---
title: Manual Implementation
category: how-to
---

# How to write metadata manually

Craft ERC-7730 metadata files manually for complex contracts and EIP-712 messages when the builder tool is not enough.

## When to use manual implementation

Use manual implementation when:



Use the JSON Builder instead when:



## Prerequisites

- Contract ABI or EIP-712 schema for every interaction you plan to support
- Chain IDs and contract addresses
- A list of user-facing fields each signer must display

## What you will build

A JSON metadata file that transforms raw calldata into a readable display. For example:

RAW TRANSACTION

0x23b872dd000000000000000000000000...\

000000000000000000000000a0b86991...\

000000000000000000000000000001f4

WITH YOUR METADATA

Send\

Recipient: alice.eth\

Amount: 500 USDT

## Write the metadata file

### Step 1: Define the context

The `context` section binds the metadata to one or more contract deployments. For this walkthrough, we use Tether (USDT) deployed on three chains.

```json
{
  "$schema": "https://eips.ethereum.org/assets/eip-7730/erc7730-v1.schema.json",
  "context": {
    "$id": "Tether USD",
    "contract": {
      "abi": "https://api.etherscan.io/api?module=contract&action=getabi&address=0xdac17f958d2ee523a2206206994597c13d831ec7",
      "deployments": [
        { "chainId": 1,     "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7" },
        { "chainId": 137,   "address": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F" },
        { "chainId": 42161, "address": "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9" }
      ]
    }
  }
}
```

> **Note:** Working with EIP-712? Replace the <code>contract</code> block with an <code>eip712</code> definition. See the <Link href="/docs/clear-signing/reference/specifications#context-section" className="text-orange-400 hover:text-orange-300">Context section reference</Link> for the full schema including <code>addressMatcher</code> and <code>factory</code> options for proxy patterns.

### Step 2: Add protocol metadata

The `metadata` section introduces the protocol to users and stores reusable values such as token definitions and enums.

```json
"metadata": {
  "owner": "Tether",
  "info": {
    "legalName": "Tether Limited",
    "url": "https://tether.to/",
    "deploymentDate": "2017-11-28T12:41:21Z"
  },
  "token": {
    "ticker": "USDT",
    "name": "Tether USD",
    "decimals": 6
  }
}
```

> **Note:** The <code>metadata</code> section also supports <code>enums</code> (value-to-label mappings) and <code>constants</code> (reusable values). See the <Link href="/docs/clear-signing/reference/specifications#metadata-section" className="text-orange-400 hover:text-orange-300">Metadata section reference</Link>.

### Step 3: Define the display rules

The `display.formats` section maps contract function parameters to the labels and formats shown on the signer.

```json
"display": {
  "formats": {
    "transfer(address,uint256)": {
      "intent": "Send",
      "fields": [
        { "path": "_to",    "label": "Recipient", "format": "addressOrName" },
        {
          "path": "_value",
          "label": "Amount",
          "format": "tokenAmount",
          "params": { "tokenPath": "@.to" }
        }
      ],
      "required": ["_to", "_value"],
      "excluded": []
    }
  }
}
```

You can key each entry in `display.formats` by Solidity declaration, canonical signature, or raw selector—use whichever form your tooling already produces:

```json
"transfer(address _to,uint256 _value)": { },   // Solidity declaration
"transfer(address,uint256)": { },              // Canonical signature
"0xa9059cbb": { }                             // 4-byte selector
```

> **Warning:** Every function parameter must be listed in either <code>fields</code> or <code>excluded</code>. Validation fails if any parameter is left unaccounted for.

> **Note:** For the full list of format types, path syntax, array helpers, and advanced patterns, see the <Link href="/docs/clear-signing/reference/specifications#format-types" className="text-orange-400 hover:text-orange-300">Format types reference</Link> and <Link href="/docs/clear-signing/reference/specifications#path-system" className="text-orange-400 hover:text-orange-300">Path system guide</Link>.

### Step 4: Reuse definitions with includes (optional)

To share display logic across multiple files, extract common snippets into a helper file and reference it with `includes`:

```json
{
  "$schema": "https://eips.ethereum.org/assets/eip-7730/erc7730-v1.schema.json",
  "includes": "common-swap.json",
  "context": {
    "contract": {
      "deployments": [{ "chainId": 324, "address": "0x6fd4383cB451173D5f9304F041C7BCBf27d561fF" }]
    }
  }
}
```

Shared definitions live under `display.definitions` in the included file:

```json
{
  "display": {
    "definitions": {
      "sendAmount": {
        "label": "Amount to Send",
        "format": "tokenAmount",
        "params": { "tokenPath": "desc.srcToken" }
      }
    },
    "formats": {
      "swap(...)": {
        "intent": "Swap",
        "fields": [
          { "path": "desc.amount", "$ref": "$.display.definitions.sendAmount" }
        ]
      }
    }
  }
}
```

When the including file redeclares the same key, its version takes precedence. Use this to override only the fields that differ per chain while keeping shared logic in one place.

### Step 5: Validate and submit

Run the ERC-7730 validator on your completed file and then follow the [Validate & Submit guide](./validate-submit) to open a pull request to the registry.

## Final JSON

The complete file combining all sections above:

```json
{
  "$schema": "https://eips.ethereum.org/assets/eip-7730/erc7730-v1.schema.json",
  "context": {
    "$id": "Tether USD",
    "contract": {
      "abi": "https://api.etherscan.io/api?module=contract&action=getabi&address=0xdac17f958d2ee523a2206206994597c13d831ec7",
      "deployments": [
        { "chainId": 1,     "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7" },
        { "chainId": 137,   "address": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F" },
        { "chainId": 42161, "address": "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9" }
      ]
    }
  },
  "metadata": {
    "owner": "Tether",
    "info": {
      "legalName": "Tether Limited",
      "url": "https://tether.to/",
      "deploymentDate": "2017-11-28T12:41:21Z"
    },
    "token": {
      "ticker": "USDT",
      "name": "Tether USD",
      "decimals": 6
    }
  },
  "display": {
    "formats": {
      "transfer(address,uint256)": {
        "intent": "Send",
        "fields": [
          { "path": "_to",    "label": "Recipient", "format": "addressOrName" },
          {
            "path": "_value",
            "label": "Amount",
            "format": "tokenAmount",
            "params": { "tokenPath": "@.to" }
          }
        ],
        "required": ["_to", "_value"],
        "excluded": []
      }
    }
  }
}
```

## Complete examples

### Tether USDT

```json
{
  "$schema": "https://eips.ethereum.org/assets/eip-7730/erc7730-v1.schema.json",
  "context": {
    "contract": {
      "abi": "https://api.etherscan.io/api?module=contract&action=getabi&address=0xdac17f958d2ee523a2206206994597c13d831ec7",
      "deployments": [
        { "chainId": 1,     "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7" },
        { "chainId": 137,   "address": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F" },
        { "chainId": 42161, "address": "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9" }
      ]
    }
  },
  "metadata": {
    "owner": "Tether",
    "info": {
      "legalName": "Tether Limited",
      "url": "https://tether.to/",
      "deploymentDate": "2017-11-28T12:41:21Z"
    }
  },
  "display": {
    "formats": {
      "transfer(address,uint256)": {
        "intent": "Send",
        "fields": [
          { "path": "_to",    "label": "To",     "format": "addressOrName" },
          { "path": "_value", "label": "Amount", "format": "tokenAmount", "params": { "tokenPath": "@.to" } }
        ],
        "required": ["_to", "_value"],
        "excluded": []
      }
    }
  }
}
```

### 1inch Order (EIP-712)

```json
{
  "$schema": "https://eips.ethereum.org/assets/eip-7730/erc7730-v1.schema.json",
  "context": {
    "eip712": {
      "deployments": [
        { "chainId": 1,   "address": "0x119c71d3bbac22029622cbaec24854d3d32d2828" },
        { "chainId": 10,  "address": "0x11431a89893025d2a48dca4eddc396f8c8117187" },
        { "chainId": 56,  "address": "0x1e38eff998df9d3669e32f4ff400031385bf6362" },
        { "chainId": 137, "address": "0x94bc2a1c732bcad7343b25af48385fe76e08734f" },
        { "chainId": 42161, "address": "0x7f069df72b7a39bce9806e3afaf579e54d8cf2b9" }
      ],
      "domain": { "name": "Permit2" },
      "schemas": [{
        "primaryType": "OrderStructure",
        "types": {
          "EIP712Domain": [
            { "name": "name",              "type": "string" },
            { "name": "version",           "type": "string" },
            { "name": "chainId",           "type": "uint256" },
            { "name": "verifyingContract", "type": "address" }
          ],
          "OrderStructure": [
            { "name": "salt",         "type": "uint256" },
            { "name": "maker",        "type": "address" },
            { "name": "receiver",     "type": "address" },
            { "name": "makerAsset",   "type": "address" },
            { "name": "takerAsset",   "type": "address" },
            { "name": "makingAmount", "type": "uint256" },
            { "name": "takingAmount", "type": "uint256" },
            { "name": "makerTraits",  "type": "uint256" }
          ]
        }
      }]
    }
  },
  "metadata": {
    "owner": "1inch Limit Order Protocol"
  },
  "display": {
    "formats": {
      "OrderStructure": {
        "intent": "1inch Order",
        "fields": [
          { "path": "maker",         "label": "From",             "format": "raw" },
          { "path": "makingAmount",  "label": "Send",             "format": "tokenAmount", "params": { "tokenPath": "makerAsset" } },
          { "path": "takingAmount",  "label": "Receive minimum",  "format": "tokenAmount", "params": { "tokenPath": "takerAsset" } },
          { "path": "receiver",      "label": "To",               "format": "raw" }
        ],
        "excluded": ["salt", "makerTraits"],
        "required": ["maker", "makingAmount", "takingAmount", "receiver"]
      }
    }
  }
}
```

### Uniswap V3 Router

```json
{
  "$schema": "https://eips.ethereum.org/assets/eip-7730/erc7730-v1.schema.json",
  "context": {
    "contract": {
      "abi": [...],
      "deployments": [
        { "chainId": 1, "address": "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45" }
      ]
    }
  },
  "display": {
    "formats": {
      "exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))": {
        "intent": "Swap tokens",
        "fields": [
          { "path": "params.tokenIn",           "label": "From",         "format": "token" },
          { "path": "params.amountIn",          "label": "Amount",       "format": "tokenAmount" },
          { "path": "params.tokenOut",          "label": "To",           "format": "token" },
          { "path": "params.amountOutMinimum",  "label": "Min received", "format": "tokenAmount" }
        ]
      }
    }
  }
}
```

### Permit2

```json
{
  "$schema": "https://eips.ethereum.org/assets/eip-7730/erc7730-v1.schema.json",
  "context": {
    "eip712": {
      "deployments": [
        { "chainId": 1, "address": "0x000000000022D473030F116dDEE9F6B43aC78BA3" }
      ],
      "domain": { "name": "Permit2", "version": "1" },
      "schemas": [{
        "primaryType": "PermitSingle",
        "types": {
          "PermitSingle": [
            { "name": "details",     "type": "PermitDetails" },
            { "name": "spender",     "type": "address" },
            { "name": "sigDeadline", "type": "uint256" }
          ]
        }
      }]
    }
  },
  "display": {
    "formats": {
      "PermitSingle": {
        "intent": "Approve spending",
        "fields": [
          { "path": "details.token",  "label": "Token",   "format": "token" },
          { "path": "details.amount", "label": "Amount",  "format": "tokenAmount" },
          { "path": "spender",        "label": "Spender", "format": "addressOrName" }
        ]
      }
    }
  }
}
```

## Troubleshooting

Validation fails with "unaccounted parameter"

Every parameter in the function signature must appear in either fields or excluded. Check the error message for the parameter name, then either add it to fields with an appropriate format, or add it to the excluded array.

The function signature in my display key does not match

The key in display.formats must exactly match the function's canonical signature, Solidity declaration, or 4-byte selector. Common mistakes:



Path expression returns nothing or fails validation

Check the path root identifier:



See the [Path system reference](../reference/specifications#path-system) for full syntax.

ABI URL returns an error during validation

If the ABI URL is not reachable or returns an error during validation, embed the ABI directly in the file as a JSON array instead of a URL string. You can copy the ABI from Etherscan's contract page under the Contract tab.

Your metadata file is complete. Validate it with the CLI tool and open a pull request to the registry.

## Go deeper

- Study the full [Context reference](../reference/specifications#context-section) for factories, matchers, and typed data options
- Reuse enums, constants, and includes using the [Metadata reference](../reference/specifications#metadata-section) and [Display reference](../reference/specifications#display-section)
- Browse real-world patterns in the [public registry](https://github.com/LedgerHQ/clear-signing-erc7730-registry)

## Next steps

[<div className="font-semibold mb-2">Validate & Submit →</div>
<div className="text-sm text-gray-400">Test your metadata file and submit it to the registry</div>](./validate-submit)

[<div className="font-semibold mb-2">Browse examples →</div>
<div className="text-sm text-gray-400">See implementations from major protocols in the public registry</div>](https://github.com/LedgerHQ/clear-signing-erc7730-registry/tree/master/registry)
