Manual Implementation
Craft ERC-7730 metadata files manually for complex contracts and EIP-712 messages when the builder tool is not enough.
What You’ll Build
A JSON metadata file that transforms this:
0x23b872dd000000000000000000000000…
000000000000000000000000a0b86991…
000000000000000000000000000001f4
Protocol: Uniswap V3
Min. received: 1,245 USDC

Your metadata enables users to verify exactly what they’re signing
When Manual Creation Fits
- • You want one JSON to cover multiple deployments or contract variants
- • You need EIP-712 or other structured messages
- • Your display logic relies on nested paths, byte slices, or conditional rules
- • You plan to reuse enums, constants, or includes across contracts
- • You target a single contract deployment
- • Function signatures decode cleanly (no nested tuples or calldata slicing)
- • Parameter formatting is minimal
- • You just need a quick start (< 10 minutes)
- • No custom logic needed
Prerequisites
- Contract ABI or EIP-712 schema for every interaction you plan to support
- Chain IDs and contract addresses the participating wallets should recognise
- A clear list of user-facing fields each signing device must display
Workflow at a Glance
- Map the context to every contract address or typed-data schema you need to support.
- Add metadata that introduces the protocol and stores shared values (tokens, enums, constants).
- Configure the display rules so calldata becomes readable labels and amounts for signers.
- Run local validation, then package and submit the finished JSON to the registry.
Step 1: Define the Context
Describe the contracts or typed data the metadata covers. For this walkthrough we use Tether (USDT) deployments on Ethereum, Polygon, and Arbitrum.
{
"$schema": "https://github.com/LedgerHQ/clear-signing-erc7730-registry/blob/master/specs/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" }
]
}
}
}
Working with EIP-712? Swap the contract
block for an eip712
definition; see the Context section reference for the full schema.
Step 2: Add Protocol Metadata
This section introduces the protocol to users and holds reusable values for future steps.
"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
}
}
Need enums, constants, or shared definitions? Jump to the Metadata section reference for every available key.
Step 3: Design the Display Rules
Map contract parameters to clear labels so signers immediately understand the action they approve.
"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 declaration, canonical signature, or raw selector—choose the form your tooling already emits:
"transfer(address _to,uint256 _value)": { }, // Solidity declaration
"transfer(address,uint256)": { }, // Canonical signature
"0xa9059cbb": { } // Function selector
Every function parameter must be shown or added to excluded
. Validation fails if a field is left unaccounted for.
Browse the full list of format types, path syntax, array helpers, and advanced patterns in the Format reference and Path system guide.
Need to reuse the same display logic across multiple contracts? Extract shared snippets into a helper file and include it:
{
"$schema": "../../specs/erc7730-v1.schema.json",
"includes": "common-swap.json",
"context": {
"contract": {
"deployments": [{ "chainId": 324, "address": "0x6fd4383cB451173D5f9304F041C7BCBf27d561fF" }]
}
}
}
Included files can expose reusable snippets under display.definitions
:
{
"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" }
]
}
}
}
}
If the including file redeclares the same key, its version wins. Use this to override only the pieces that differ per chain.
Step 4: Validate and Iterate
- Use the Validate & Submit guide to run schema checks and complete the registry submission workflow.
- Expand coverage by adding more functions to
display.formats
or additional deployments tocontext
. - When you need advanced features such as shared includes, enums, or domain separators, jump into the specification so the manual file stays lean and maintainable.
Final JSON
Combine the sections above into your final .json
file:
{
"$schema": "https://github.com/LedgerHQ/clear-signing-erc7730-registry/blob/master/specs/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
{
"$schema": "https://github.com/LedgerHQ/clear-signing-erc7730-registry/blob/master/specs/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": []
}
}
}
}
Go Deeper
- Study the full Context reference when supporting factories, matchers, or typed data.
- Reuse enums, constants, and includes with the Metadata reference and Display reference.
- Explore real-world patterns in the public registry for inspiration.