The Cosmos Inscriptions Specification

The Cosmos Inscriptions Specification details a way to inscribe arbitrary data onto a Cosmos SDK blockchain. Inscribing data onto the chain ensures it will live on for as long as the chain is running.

The design takes inspiration from the rather clever ordinals implementation on bitcoin, which uses data pushes within unexecuted taproot conditionals, called “envelopes.” This “backdoor” approach enables users to write data directly to the bitcoin blockchain.

The Cosmos SDK differs in a big way from other blockchain implementations in that messages are validated, and rarely do you find any part of a transaction that isn’t strictly controlled by some definition. This is generally good and avoids a lot of mistakes, however, it also makes it harder to put arbitrary data in a transaction.

One of the fields that are somewhat suited for inscriptions is the “memo” field. The memo field is used in transfers to centralized exchanges as well with IBC-Hooks. The memo field is very limited though, with a maximum length of 512 characters on Cosmos Hub. There was an attempt on the Cosmos Hub forum to increase the size of the field, but it doesn’t seem a proposal was put to a vote on this.

There is another section of a transaction that allows arbitrary data to be added as long as you conform to the message type built into the chain. This section is non_critical_extension_options (NCXO).

From the SDK documentation:

extension_options are arbitrary options that can be added by chains when the default options are not sufficient. If any of these are present and can’t be handled, they will be ignored

The final part of the description is key: “If any of these are present and can’t be handled, they will be ignored.” This leaves a path for adding content that is not validated past the protocol buffer type. As long as you use a type known to the chain, it can be used. An example is the sending of tokens below using the /cosmos.bank.v1beta1.MsgSend type:

In this example, the field names are validated, but the content of the fields are not. This is expected as this specific option isn’t handled and thus ignored. Indeed, none of the tests we attempted generated errors. One of the caveats of this approach, however, is that SIGN_MODE_DIRECT is required, which means this will not work with Ledger devices.

MsgSend is not really well suited for what we want to achieve. Initially, Asteroid Protocol used /cosmos.authz.v1beta1.MsgRevoke instead. After the successful launch of Asteroid Protocol, though, Cosmos Hub's Gaia v15.1.0 upgrade added official support for Asteroids. Specifically, the Gaia v15.1.0 upgrade ensured the “non_critical_extension_options” portion could always be used for posting on-chain data.

The new metaprotocol module added support for an ExtensionData message type with following format:

{
  "@type": "/gaia.metaprotocols.ExtensionData",
  "protocol_id": "asteroid:inscription",
  "protocol_version": "v1",
  "data": "<base64 encoded bytes>"
}

Asteroid transactions then add an inscription protobuf message in the data field of the ExtensionData message as follows:

{
  "parent_type": "/cosmos.bank.Account",
  "parent_identifier": "cosmos1m9l358xunhhwds0568za49mzhvuxx9uxre5tud",
  "metadata": "<json bytes>",
  "content": "<bytes>",
}

Note that these changes deprecated the old method for inscribing transaction data via a MsgRevoke message. After the upgrade, which went live with Block 19639600, all transactions that use the legacy format are invalid. Anyone using the legacy format should immediately migrate to the new format.

Any Asteroid tools or frontends are encouraged to use the Asteroid Protocol SDK (online at https://www.npmjs.com/package/@asteroid-protocol/sdk). This abstracts away the transaction creation logic and ensures you won’t need to manually upgrade your message formats.

With a bit of creativity, this structure means we can:

  1. Identity the type of content stored in this transaction

  2. Provide metadata for the content stored

  3. Store arbitrary data in base64

That gives us:

{
  "@type": "/gaia.metaprotocols.ExtensionData",
  "granter": "{\"name\": \"My inscribed image\"}",
  "grantee": "IHNobGRrIGxoc..gbDtkaGE=",
  "msg_type_url": "image/png"
}

With each field is defined as follows:

We use the @type here as no-op, and it is ignored by the chain when part of non_critical_extension_options. In any case, the content is invalid and the chain would reject the message if it was ever implemented as part of non_critical_extension_options since Asteroids rely on the content not being validated.

Note that Asteroids rely on public RPC nodes for submitting transactions and indexing inscriptions and tokens. If those nodes go offline, transactions could fail and/or be delayed. In the event of a delay, Asteroid indexers could temporarily report stale/inaccurate information. Use caution when interacting with Asteroids during periods of network congestion and/or offline RPC nodes.

1.1 How to create your first Asteroid inscription using the Cosmos Inscriptions Specification on Asteroid Protocol

Prerequisites:

  • A nominal amount of $ATOM on Cosmos Hub (ATOM is available on leading exchanges including Binance and Coinbase) as well as decentralized exchanges including Astroport

  • The file you’d like to inscribe in any format supported by browsers (i.e. .txt, .html, .jpg, .png)

Steps:

  1. Visit asteroidprotocol.io and connect your Keplr wallet

  2. Click “Create” under “Inscriptions” in the navigation pane

  3. Click “Select file” to choose the file you’d like to inscribe (up to a maximum of ~550kb)

  4. Enter a name and description for your inscription

  5. Click the “Inscribe” button and approve the transaction in your wallet

  6. That’s it! Your inscription should soon appear on asteroidprotocol.io. Simply navigate to Wallet → Inscriptions to see it

Last updated