Skip to main content
ERC-7730 descriptors tell wallets how to display your contract calls and typed-data signatures in plain language. For Monad, the process is the same as any EVM chain: write the descriptor, bind it to chainId 143 and your contract address, then add it to the public registry.

What is clear signing?

ERC-7730 is a JSON format for describing how a wallet should render contract calldata and EIP-712 messages. The descriptor lives outside your contract. It maps functions, message types, and fields to labels and formatters a wallet can show before a user signs. The lookup key is chainId plus contract address, so Monad contracts do not need a Monad-specific version of the standard. Without a descriptor, a wallet may only have raw calldata:
0x095ea7b3000000000000000000000000fe9c9ca3eed0fb3e6a5c0bf42ad6f1a0d1c7b2a40000000000000000000000000000000000000000000000000000000003b9aca00
With a descriptor, the same approval can be shown as fields a user can check:
Approve USDC
Spender:  Uniswap V3 Router
Amount:   1,000 USDC
Network:  Monad

Why it matters for Monad

Users should not have to trust the site that assembled a transaction. A spoofed frontend can ask for one action while submitting another, and raw calldata gives most users nothing useful to inspect. Clear signing moves the important details into the wallet prompt: the action, recipient, amount, token, deadline, or any other field that matters for the call. Adding a descriptor does not require a contract change. You publish a JSON file, validate it, and submit it to the registry used by wallets that support ERC-7730.
Monad mainnet chainId is 143 (testnet 10143). See Network Information.

Quickstart

Install uv first. The uvx command runs the erc7730 tool without a separate global install.
  1. Generate a starting descriptor from your ABI:
uvx erc7730 generate \
  --chain-id 143 \
  --address 0xYourContractOnMonad \
  --abi ./abi/YourContract.json \
  --owner "Your Protocol" \
  --url "https://yourprotocol.xyz" \
  > calldata-yourcontract.json
  1. Edit the intents and field labels so they read like English (see Editing the descriptor).
  2. Validate the descriptor:
uvx erc7730 lint calldata-yourcontract.json
  1. Preview how a wallet renders your fields at clear-signing.sourcify.dev.
  2. Open a PR to the ERC-7730 registry. CI validates it against the schema, a maintainer reviews, and once merged, supporting wallets can use it.
Open the PR from an account tied to the protocol or contract owner. Registry maintainers may ask for proof that you control the deployment.

The Monad gotcha: embed your ABI inline

The erc7730 linter and registry CI try to fetch a reference ABI from Etherscan’s multichain API. Monad is not served by that API, so you may see a warning like this:
warning: Could not fetch ABI: Fetching reference ABI for chain id 143 failed ...
Include the ABI directly under context.contract.abi. The generate command above already does this, which makes the descriptor self-contained and lets the fields validate locally. Do not remove the inline abi; with it present, the warning is expected and can be ignored.
{
  "context": {
    "contract": {
      "deployments": [
        { "chainId": 143, "address": "0xYourContractOnMonad" }
      ],
      "abi": [
        {
          "type": "function",
          "name": "approve",
          "inputs": [
            { "name": "spender", "type": "address" },
            { "name": "amount", "type": "uint256" }
          ]
        }
      ]
    }
  }
}

Editing the descriptor

generate gives you a skeleton with one entry per function. Most of the hand-editing is in two places:
  • intent: a short action label, such as Approve USDC or Wrap MON. Keep it to 30 characters or fewer; some hardware wallet screens truncate longer strings.
  • fields: the parameters you want users to review, each with a label and format.
Use the most specific formatter that fits the value:
formatRendersNotes
tokenAmount1,000 USDCApplies decimals and ticker. Set a threshold with a message like Unlimited for max approvals.
amountNative MON with tickerReads the transaction value.
addressNameA known name, otherwise a checksummed addressUse types (eoa, contract, token) and sources (local, ens).
rawA number, string, or address as-is
dateA readable date from a unix timestampSet encoding.
Field paths use three roots: #. for decoded calldata or message fields, $. for this descriptor’s own metadata, and @. for the transaction container, such as @.value.

Monad examples

These Monad descriptors are useful references when writing your own:
  • Permit2, the EIP-712 approval contract used across many dApps, at, added to the canonical Uniswap descriptor in registry PR #2611.
  • The Monad staking precompile (delegate, undelegate, claim rewards) at, in registry PR #2589.
  • Wrapped MON (wrap, unwrap, and ERC-20 calls) at.

How a wallet uses the descriptor

At a high level, a supporting wallet does this:
  1. A user starts a transaction or signs an EIP-712 message.
  2. The wallet computes the 4-byte selector (or the EIP-712 type hash).
  3. It looks up the descriptor by chainId and address.
  4. It checks that the descriptor’s context binding matches the actual target.
  5. It decodes the parameters with the ABI and resolves token and name metadata.
  6. It applies each field formatter and shows the intent with the formatted fields.
If no descriptor is found, the wallet falls back to its default signing view.

Resources