From 9475fc87a982dc4e19ae28394f02458e5d20f8b5 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Wed, 22 Oct 2025 11:03:05 +0200 Subject: [PATCH 01/12] Document ABI sourcing guidance for ERC-7730 --- ERCS/erc-7730.md | 62 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/ERCS/erc-7730.md b/ERCS/erc-7730.md index 9fadb6e70eb..0649512df97 100644 --- a/ERCS/erc-7730.md +++ b/ERCS/erc-7730.md @@ -2,7 +2,7 @@ eip: 7730 title: Structured Data Clear Signing Format description: JSON format describing how to clear-sign smart contract calls and typed messages. -author: Laurent Castillo (@lcastillo-ledger), Derek Rein (@arein), Pierre Aoun (@paoun-ledger), Arik Galansky (@arikg) +author: Laurent Castillo (@lcastillo-ledger), Derek Rein (@arein), Pierre Aoun (@paoun-ledger), Arik Galansky (@arikg), Bartosz Rozwarski (@llbartekll) discussions-to: https://ethereum-magicians.org/t/eip-7730-proposal-for-a-clear-signing-standard-format-for-wallets/20403 status: Draft type: Standards Track @@ -49,7 +49,18 @@ The following is an example of how to clear sign a `transfer` function call on a "context": { "$id": "Example ERC-20", "contract" : { - "abi": "https://api.example.io/api?module=contract&action=getabi&address=0xdac17f958d2ee523a2206206994597c13d831ec7", + "abi": [ + { + "type": "function", + "name": "transfer", + "stateMutability": "nonpayable", + "inputs": [ + { "name": "_to", "type": "address" }, + { "name": "_value", "type": "uint256" } + ], + "outputs": [] + } + ], "deployments": [ { "chainId": 1, @@ -479,13 +490,46 @@ The `contract` sub-key is used to introduce an EVM smart contract binding contex **`contract.abi`** -Either an URL of the reference ABI (served in json representation), or the ABI itself as a json array. +A JSON array of ABI entries embedded in the descriptor. A wallet MUST verify that the ABI is applicable to the contract being called. All paths described in the ERC-7730 starting with the `#.` root node (typically used to describe a single parameter of the contract call) use selector names coming from this ABI. -A wallet MUST verify that the ABI is applicable to the contract being called. +**ABI sourcing** -All paths described in the ERC-7730 starting with the `#.` root node (typically used to describe a single parameter of the contract call) are using selectors names coming from the parameter names of the ABI referenced. +- When present, `context.contract.abi` MUST be a JSON array embedded in the descriptor; it MAY be minimal but MUST include full type information (including tuple `components`) for every formatted function. +- If `context.contract.abi` is absent or omits a referenced function, wallets MAY fall back to `context.contract.abiSource.uris`. +- At least one of `context.contract.abi` or `context.contract.abiSource.uris` MUST be present; providing `context.contract.abi` is RECOMMENDED. +- `context.contract.abiSource.uris` MUST be a priority-ordered list that SHOULD prefer relative paths resolved against the descriptor URL; absolute URIs MUST use `https`, `ipfs`, or `ar` schemes. -The `contract.abi` key is mandatory for a smart contract ERC-7730 file. +**Wallet behavior** +- Wallets SHOULD prefer `context.contract.abi` when it satisfies rendering requirements. +- Wallets MAY dereference `context.contract.abiSource.uris` sequentially until a usable ABI is obtained. +- Wallets MAY cache resolved ABIs per descriptor origin. + +```json +{ + "context": { + "contract": { + "abi": [ + { + "type": "function", + "name": "transfer", + "stateMutability": "nonpayable", + "inputs": [ + { "name": "recipient", "type": "address" }, + { "name": "amount", "type": "uint256" } + ], + "outputs": [] + } + ], + "abiSource": { + "uris": [ + "./abis/MyContract.json", + "ipfs://bafybeigdyrztfqexample" + ] + } + } + } +} +``` **`contract.deployments`** @@ -786,9 +830,9 @@ This snippet defines a common formatter for an amount to send that can be used b The `formats` key is an object containing the actual information used to format the structured data. It is a json object in which each sub-key is a specific function call (for contracts) or a specific message type (for EIP-712) being described. The values are each a *structured data format specification*. For contracts, the key names MUST be one of those three forms: -* A 4-bytes selector of the function being described, in hex string notation: the corresponding function MUST be in the abi specified in `context.abi`. -* The function signature used to compute the selector, i.e. without parameter names and without spaces (refer to Solidity documentation): the corresponding function MUST be in the abi specified in `context.abi`. -* A full solidity signature, including parameter names: the corresponding function MUST be in the abi specified in `context.abi` and the parameters names MUST match those in the ABI. +* A 4-bytes selector of the function being described, in hex string notation: the corresponding function MUST be in the abi specified in `context.contract.abi`. +* The function signature used to compute the selector, i.e. without parameter names and without spaces (refer to Solidity documentation): the corresponding function MUST be in the abi specified in `context.contract.abi`. +* A full solidity signature, including parameter names: the corresponding function MUST be in the abi specified in `context.contract.abi` and the parameters names MUST match those in the ABI. For EIP-712, the key names MUST be one of the primary type names included in `context.eip712.schemas`. From ba6ae321c2febf577abfc3b85138f2d49bd6f9f4 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Tue, 28 Oct 2025 11:00:41 +0100 Subject: [PATCH 02/12] Make display formats the single source of contract typing --- ERCS/erc-7730.md | 259 +++++++++++++++++++++++------------------------ 1 file changed, 126 insertions(+), 133 deletions(-) diff --git a/ERCS/erc-7730.md b/ERCS/erc-7730.md index 0649512df97..a253c880d77 100644 --- a/ERCS/erc-7730.md +++ b/ERCS/erc-7730.md @@ -49,18 +49,6 @@ The following is an example of how to clear sign a `transfer` function call on a "context": { "$id": "Example ERC-20", "contract" : { - "abi": [ - { - "type": "function", - "name": "transfer", - "stateMutability": "nonpayable", - "inputs": [ - { "name": "_to", "type": "address" }, - { "name": "_value", "type": "uint256" } - ], - "outputs": [] - } - ], "deployments": [ { "chainId": 1, @@ -89,26 +77,21 @@ The following is an example of how to clear sign a `transfer` function call on a "display": { "formats": { - "transfer(address _to,uint256 _value)": { + "transfer(address to,uint256 value)": { "intent": "Send", - "interpolatedIntent": "Send {_value} to {_to}", + "interpolatedIntent": "Send {value} to {to}", "fields": [ { - "path": "_to", - "label": "To", - "format": "addressOrName" + "path": "value", + "label": "Amount", + "format": "tokenAmount" }, { - "path": "_value", - "label": "Amount", - "format": "tokenAmount", - "params": { - "tokenPath": "@.to" - } + "path": "to", + "label": "To", + "format": "addressName" } - ], - "required": ["_to", "_value"], - "excluded": [] + ] } } } @@ -119,7 +102,7 @@ The `$schema` key refers to the latest version of this specification json schema The `context` key is used to provide binding context information for this file. It can be seen as a set of *constraints* on the structured data being reviewed, indicating whether the ERC-7730 file is valid for this data. A wallet MUST ensure these constraints are met before ERC-7730 formatting information is applied to the data being signed. -In this example, the context section indicates that the ERC-7730 file should only be applied to the Example smart contract whose deployment addresses are provided and only if they match the reference ABI. Note that the ABI is used to define unique *path* references to fields being formatted in the `display.formats` section, so the ABI is mandatory for all contracts clear-signed. +In this example, the context section indicates that the ERC-7730 file should only be applied to the Example smart contract whose deployment addresses are provided. Once the contract is matched, wallets use the `display.formats` entry itself to derive the function selector, parameter layout, and user-facing labels. The `metadata` section contains constants that can be trusted when the ERC-7730 file is applicable for the given context. This section is typically used to: * Provide displayable information about the recipient of the contract call / message @@ -130,13 +113,13 @@ In this example, the metadata section contains only the recipient information, i Finally, the `display` section contains the definitions of how to format each field of targeted contract calls under the `formats` key. -In this example, the function being described is identified by its solidity signature `transfer(address _to,uint256 _value)`. This is the signature used to compute the function selector `0xa9059cbb` (using the solidity signature guarantees unicity in the context of the contract). +In this example, the function being described is identified by its human-readable ABI fragment `transfer(address to,uint256 value)`. Wallets strip the parameter names to compute the type-only signature `transfer(address,uint256)`, hash it, and match the resulting selector `0xa9059cbb` against the calldata. * The `intent` key contains a human-readable string that wallets SHOULD display to explain to the user the intent of the function call. * The `fields` key contains all the parameters that CAN be displayed, and the way to format them * The `required` key indicates which parameters wallets SHOULD display. * The `excluded` key indicates which parameters are intentionally left out (none in this example). -In this example, the `_to` parameter and the `_value` SHOULD both be displayed, one as an address replaceable by a trusted name (ENS or others), the other as an amount formatted using metadata of the target ERC-20 contract. +In this example, the `to` parameter and the `value` parameter SHOULD both be displayed, one as an address replaceable by a trusted name (ENS or others), the other as an amount formatted using metadata of the target ERC-20 contract. ### Common concepts @@ -161,7 +144,7 @@ Displaying structured data is often done by wallets to review its content before Current specification covers EVM smart contract calldata: * Defined in Solidity -* The schema is the ABI (expected in json format when linked to) +* The schema is derived from the matched `display.formats` function fragment * The container structure is an EVM Transaction serialized in RLP encoding It also supports EIP-712 messages @@ -170,7 +153,7 @@ It also supports EIP-712 messages * An EIP-712 message is self-contained, the signature is applied to the hashed message itself. -The *schema* is referenced and bound to this file under the `context` key. In turn, it enables using *path* strings to target specific fields in the `display` section to describe what formatting should be applied to these fields before display. +The *schema* is defined by the binding context together with the selected display entry. For contracts, the matched `display.formats` key provides the full function signature (types and parameter names); for EIP-712 messages, the schema is still supplied through the message definitions collected under `context.eip712`. In turn, the schema enables using *path* strings to target specific fields in the `display` section to describe what formatting should be applied before display. Formats are dependent on and defined for the underlying *types* on the structured data. The [Reference](#reference) section covers formats and types supported by this current version of the specification. @@ -189,7 +172,7 @@ In addition, additional *roots* are introduced to support description of paths o | Root node identifier | Refers to | Value location | |----------------------|---------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------| -| # | Path applies to the structured data *schema* (ABI path for contracts, path in the message types itself for EIP-712) | Values can be found in the serialized representation of the structured data | +| # | Path applies to the structured data *schema* (decoded function parameters for contracts, path in the message types itself for EIP-712) | Values can be found in the serialized representation of the structured data | | $ | Path applies to the current file describing the structured data formatting, after merging with includes | Values can be found in the merged file itself | | @ | Path applies to the container of the structured data to be signed | Values can be found in the serialized container to sign, and are uniquely defined per container in the [Reference](#reference) section | @@ -200,10 +183,10 @@ For paths referring to structured data fields, if a field has a variable length *Examples* References to values in the serialized structured data -* `#.params.amountIn` or `params.amountIn` refers to parameter `amountIn` in top-level structure `params` as defined in the ABI -* `#.data.path.[0].path.[-1].to` or `data.path.[0].path.[-1].to` refers to the field `to` taken from last member of `path` array, itself taken from first member of enclosing `path` array, itself part of top level `data` structure. -* `#.params.path.[:20]` or `#.params.path.[0:20]` refers to the first 20 bytes of the `path` byte array -* `#.params.path.[-20:]` refers to the last 20 bytes of the `path` byte array +* `#.` or relative `value` refers to the decoded argument named `value` from the matched function fragment +* `#.order.price` refers to the `price` field inside the `order` tuple argument +* `#.recipients.[0]` refers to the first entry of the `recipients` dynamic array +* `#.order.path.[0:20]` refers to the first 20 bytes of a `path` byte array nested inside the `order` tuple * `#.details.[]` refers to the array with the Permit Details of a PermitBatch message References to values in the format specification file @@ -226,7 +209,7 @@ The `interpolatedIntent` makes transaction intents significantly shorter and eas **Interpolation Syntax** Values are interpolated using curly braces containing a path reference: `{path}`. The path MUST follow the [path reference rules](#path-references) and can reference: -- Structured data fields (e.g., `{_to}`, `{params.amountIn}`) +- Structured data fields (e.g., `{to}`, `{order.amount}`) - Container values (e.g., `{@.value}`, `{@.from}`) - Metadata constants (e.g., `{$.metadata.constants.nativeAssetAddress}`) @@ -249,10 +232,10 @@ To include literal curly braces in the intent text, escape them by doubling: `{{ ```json { "intent": "Send", - "interpolatedIntent": "Send {_value} to {_to}", + "interpolatedIntent": "Send {value} to {to}", "fields": [ - {"path": "_to", "format": "addressName"}, - {"path": "_value", "format": "tokenAmount", "params": {"tokenPath": "@.to"}} + {"path": "to", "format": "addressName"}, + {"path": "value", "format": "tokenAmount", "params": {"tokenPath": "@.to"}} ] } ``` @@ -317,7 +300,7 @@ Combined display: **"Approve Uniswap Router to spend 1000 USDC and Swap 1000 USD [ { "function": "approve", - "interpolatedIntent": "Approve {_spender} to spend {_value}" + "interpolatedIntent": "Approve {spender} to spend {value}" }, { "function": "exactInputSingle", @@ -332,7 +315,7 @@ Combined display: **"Approve Uniswap V3 Router to spend 5000 DAI and Swap 5000 D [ { "function": "approve", - "interpolatedIntent": "Approve {_spender} to spend {_value}" + "interpolatedIntent": "Approve {spender} to spend {value}" }, { "function": "swapExactTokensForETH", @@ -378,38 +361,18 @@ Special care must be taken when merging [field format specifications](#field-for This file defines a generic ERC-20 interface for a single `approve` function: ```json { - "context": { - "contract": { - "abi": [ - { - "inputs": [ - { - "name": "_spender", - "type": "address" - }, - { - "name": "_value", - "type": "uint256" - } - ], - "name": "approve", - "type": "function" - } - ] - } - }, "display": { "formats": { - "approve(address _spender,uint256 _value)": { + "approve(address spender,uint256 value)": { "intent": "Approve", "fields": [ { - "path": "_spender", + "path": "spender", "label": "Spender", - "format": "addressOrName" + "format": "addressName" }, { - "path": "_value", + "path": "value", "label": "Amount", "format": "tokenAmount", "params": { @@ -419,7 +382,7 @@ This file defines a generic ERC-20 interface for a single `approve` function: } } ], - "required": ["_spender", "_value"] + "required": ["spender", "value"] } } } @@ -460,10 +423,10 @@ The following file would include this generic interface and bind it to the speci "display": { "formats": { - "approve(address _spender,uint256 _value)": { + "approve(address spender,uint256 value)": { "fields": [ { - "path": "_value", + "path": "value", "params" : { "threshold": "0xFFFFFFFFFFFFFFFFFF" } @@ -474,7 +437,7 @@ The following file would include this generic interface and bind it to the speci } } ``` -Note that the keys under `context.contract` would be merged together to construct a full contract binding object. The field formatter `_value` parameter `threshold` is overridden with value `0xFFFFFFFFFFFFFFFFFF`. +Note that the keys under `context.contract` would be merged together to construct a full contract binding object. The field formatter `value` parameter `threshold` is overridden with value `0xFFFFFFFFFFFFFFFFFF`. ### `Context` section @@ -488,49 +451,6 @@ All context support an `$id` sub-key as an internal identifier (only relevant to The `contract` sub-key is used to introduce an EVM smart contract binding context, with the following constraints expressed as sub-keys of `contract`. -**`contract.abi`** - -A JSON array of ABI entries embedded in the descriptor. A wallet MUST verify that the ABI is applicable to the contract being called. All paths described in the ERC-7730 starting with the `#.` root node (typically used to describe a single parameter of the contract call) use selector names coming from this ABI. - -**ABI sourcing** - -- When present, `context.contract.abi` MUST be a JSON array embedded in the descriptor; it MAY be minimal but MUST include full type information (including tuple `components`) for every formatted function. -- If `context.contract.abi` is absent or omits a referenced function, wallets MAY fall back to `context.contract.abiSource.uris`. -- At least one of `context.contract.abi` or `context.contract.abiSource.uris` MUST be present; providing `context.contract.abi` is RECOMMENDED. -- `context.contract.abiSource.uris` MUST be a priority-ordered list that SHOULD prefer relative paths resolved against the descriptor URL; absolute URIs MUST use `https`, `ipfs`, or `ar` schemes. - -**Wallet behavior** -- Wallets SHOULD prefer `context.contract.abi` when it satisfies rendering requirements. -- Wallets MAY dereference `context.contract.abiSource.uris` sequentially until a usable ABI is obtained. -- Wallets MAY cache resolved ABIs per descriptor origin. - -```json -{ - "context": { - "contract": { - "abi": [ - { - "type": "function", - "name": "transfer", - "stateMutability": "nonpayable", - "inputs": [ - { "name": "recipient", "type": "address" }, - { "name": "amount", "type": "uint256" } - ], - "outputs": [] - } - ], - "abiSource": { - "uris": [ - "./abis/MyContract.json", - "ipfs://bafybeigdyrztfqexample" - ] - } - } - } -} -``` - **`contract.deployments`** An array of deployments options. Wallets MUST verify that the target chain and contract address of the containing transaction MUST match one of these deployment options. @@ -825,17 +745,94 @@ Definitions don't usually include the `path` or `value` key of a [*field format ``` This snippet defines a common formatter for an amount to send that can be used by a simple reference to the path `$.display.definitions.sendAmount`. -**`metadata.formats`** +**`display.formats`** The `formats` key is an object containing the actual information used to format the structured data. It is a json object in which each sub-key is a specific function call (for contracts) or a specific message type (for EIP-712) being described. The values are each a *structured data format specification*. -For contracts, the key names MUST be one of those three forms: -* A 4-bytes selector of the function being described, in hex string notation: the corresponding function MUST be in the abi specified in `context.contract.abi`. -* The function signature used to compute the selector, i.e. without parameter names and without spaces (refer to Solidity documentation): the corresponding function MUST be in the abi specified in `context.contract.abi`. -* A full solidity signature, including parameter names: the corresponding function MUST be in the abi specified in `context.contract.abi` and the parameters names MUST match those in the ABI. +For contract calldata, this specification only covers functions. Each key MUST be a human-readable ABI function fragment that includes parameter names, for example `transfer(address to,uint256 value)` or `submitOrder((address token,uint256 amount) order,bytes32 salt)`. + +- Keys MUST use canonical Solidity type names: `uint256`, `bytes32`, `address`, `bool`, tuple syntax `(…)`, dynamic arrays `type[]`, and fixed arrays `type[N]`. Aliases (e.g., `uint`) are NOT permitted, commas MUST NOT be followed by spaces, and there MUST be exactly one space between each type and its parameter name. +- Parameter names in the fragment MUST match the names used throughout the formatting specification; wallets derive all display paths from these names. +- Overloaded functions are distinguished solely by their type signatures. Parameter names do not affect selector matching. For EIP-712, the key names MUST be one of the primary type names included in `context.eip712.schemas`. +**Selector matching (contracts)** + +Wallets MUST match calldata to a `display.formats` entry using the following procedure: +1. Parse the key and drop parameter names to obtain the canonical type-only signature (e.g., `transfer(address,uint256)`). +2. Compute `keccak256()[:4]`. +3. Compare the resulting selector to the transaction calldata selector; a match selects the corresponding format specification. + +If multiple keys share the same type-only signature, wallets MUST treat this as an invalid descriptor. + +**Decoding and parameter names** + +Once a format entry is selected, wallets MUST decode calldata arguments using the canonical type vector derived from the key. Parameter names, `fields[].path` entries, and `{placeholders}` in `interpolatedIntent` MUST all use the names from the key (e.g., `value`, `order.amount`, `recipients[0]`). + +Paths are relative to the matched function parameters unless prefixed by another root node; for example, `to`, `order.price`, and `recipients[0]` point to decoded arguments, while `@.value` references the transaction container. + +Placeholders in strings MUST use `{}` with the same path semantics. + +**Unknown selectors** + +If no key matches the calldata selector, wallets SHOULD display a safe fallback (for example, "Unknown function" alongside raw arguments) and MUST NOT attempt to apply any unrelated format specifications. + +*Minimal contract examples* + +```json +{ + "display": { + "formats": { + "transfer(address to,uint256 value)": { + "intent": "Send", + "interpolatedIntent": "Send {value} to {to}", + "fields": [ + { "path": "value", "label": "Amount", "format": "tokenAmount" }, + { "path": "to", "label": "To", "format": "addressName" } + ] + } + } + } +} +``` + +```json +{ + "display": { + "formats": { + "submitOrder((address token,uint256 amount,uint256 price) order,bytes32 salt)": { + "intent": "Place order", + "interpolatedIntent": "Buy {order.amount} @ {order.price}", + "fields": [ + { "path": "order.token", "label": "Token", "format": "addressName" }, + { "path": "order.amount", "label": "Amount", "format": "number" }, + { "path": "order.price", "label": "Price", "format": "number" }, + { "path": "salt", "label": "Salt", "format": "bytes32" } + ] + } + } + } +} +``` + +```json +{ + "display": { + "formats": { + "airdrop(address[] recipients,uint256[3] values)": { + "intent": "Airdrop", + "interpolatedIntent": "Airdrop to {recipients[0]} (+{recipients.length} total)", + "fields": [ + { "path": "recipients[0]", "label": "First recipient", "format": "addressName" }, + { "path": "values[0]", "label": "Tier 1", "format": "tokenAmount" } + ] + } + } + } +} +``` + #### Structured data format specification A *Structured data format specification* is used to describe how to format all the fields of a single function or EIP-712 message. It is contained in a single json object under each sub-keys of `display.formats`. @@ -931,7 +928,7 @@ contract MyContract { } // Function declaration - function myFunction(address _address, uint256 _amount, MyParamType memory _param) public { + function myFunction(address account, uint256 amount, MyParamType memory param) public { // Function logic here } } @@ -942,20 +939,20 @@ The following ERC-7730 shows examples for the three kinds of `fields` options { "display": { "formats": { - "myFunction(address _address,uint256 _amount,MyParamType _param)" : { + "myFunction(address account,uint256 amount,MyParamType param)" : { "fields": [ { - "path": "_address", + "path": "account", "$ref": "$.display.definitions.sendTo", "params": { "type": "eoa" } }, { - "path": "_amount", + "path": "amount", "label": "Number of items", "format": "raw" }, { - "path": "_param", + "path": "param", "fields": [ { "path": "name", "$ref": "$.display.definitions.itemName" }, { "path": "value", "$ref": "$.display.definitions.itemReference" } @@ -967,19 +964,19 @@ The following ERC-7730 shows examples for the three kinds of `fields` options } } ``` -* The `_address` field is an example of an internal reference (reference not included in the example), overriding the reference `type` parameter with another value. -* The `_amount` field shows an example of a simple formatter, displaying an int in its natural representation with a label. -* The `_param` field shows an example of defining formatters with a recursive structure, ending up defining two embedded formatters for paths `#._param.name` and `#._param.value` +* The `account` field is an example of an internal reference (reference not included in the example), overriding the reference `type` parameter with another value. +* The `amount` field shows an example of a simple formatter, displaying an int in its natural representation with a label. +* The `param` field shows an example of defining formatters with a recursive structure, ending up defining two embedded formatters for paths `#.param.name` and `#.param.value` Note that the recursive definition is equivalent to the following definition, which is the preferred form: ```json { "display": { "formats": { - "myFunction(address _address,uint256 _amount,MyParamType _param)" : { + "myFunction(address account,uint256 amount,MyParamType param)" : { "fields": [ - { "path":"_param.name", "$ref": "$.display.definitions.itemName" }, - { "path":"_param.value", "$ref": "$.display.definitions.itemReference" } + { "path":"param.name", "$ref": "$.display.definitions.itemName" }, + { "path":"param.value", "$ref": "$.display.definitions.itemReference" } ] } } @@ -1414,10 +1411,6 @@ All display strings in ERC-7730 files—including intents, labels, field names, Future versions of this specification may consider standardized internationalization support once the base standard achieves wider adoption and the ecosystem can better assess the need for multilingual support. -### Why is the ABI still necessary? - -The full signature of a function call does not contain information about the types of complex parameters that might be used in the function call, only their names, while the ABI does carry this information. This is why the ABI is the reference and the function signature MUST match it. The full form of the function call is allowed in order to simplify writing and reading the ERC-7730 file. - ### Extensibility to other Structured Data formats In the future, this specification could be extended to structured data like Meta Transaction in [EIP-2771](./eip-2771.md), User Operations in [EIP-4337](./eip-4337.md), and batch transaction payloads in [EIP-5792](./eip-5792.md). From c4a683ac7e521564a49a1a9a2bbccc82e6ec246d Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Tue, 28 Oct 2025 11:17:45 +0100 Subject: [PATCH 03/12] Add Kaan Uzdogan as ERC-7730 contributor --- ERCS/erc-7730.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ERCS/erc-7730.md b/ERCS/erc-7730.md index a253c880d77..3e1b6fef930 100644 --- a/ERCS/erc-7730.md +++ b/ERCS/erc-7730.md @@ -2,7 +2,7 @@ eip: 7730 title: Structured Data Clear Signing Format description: JSON format describing how to clear-sign smart contract calls and typed messages. -author: Laurent Castillo (@lcastillo-ledger), Derek Rein (@arein), Pierre Aoun (@paoun-ledger), Arik Galansky (@arikg), Bartosz Rozwarski (@llbartekll) +author: Laurent Castillo (@lcastillo-ledger), Derek Rein (@arein), Pierre Aoun (@paoun-ledger), Arik Galansky (@arikg), Bartosz Rozwarski (@llbartekll), Kaan Uzdogan (@kuzdogan) discussions-to: https://ethereum-magicians.org/t/eip-7730-proposal-for-a-clear-signing-standard-format-for-wallets/20403 status: Draft type: Standards Track From 8d4f9f2c84b02fdf1ded1b46a13a560916460376 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Thu, 30 Oct 2025 15:06:05 +0100 Subject: [PATCH 04/12] Update ERCS/erc-7730.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kaan Uzdoğan --- ERCS/erc-7730.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ERCS/erc-7730.md b/ERCS/erc-7730.md index 3e1b6fef930..0662292d91d 100644 --- a/ERCS/erc-7730.md +++ b/ERCS/erc-7730.md @@ -144,7 +144,7 @@ Displaying structured data is often done by wallets to review its content before Current specification covers EVM smart contract calldata: * Defined in Solidity -* The schema is derived from the matched `display.formats` function fragment +* The schema is the ABI (derived from the matched `display.formats` function fragment) * The container structure is an EVM Transaction serialized in RLP encoding It also supports EIP-712 messages From ffa8dd791f50a4e0a2d752a65fb947bf389b8002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Thu, 30 Oct 2025 15:42:21 +0100 Subject: [PATCH 05/12] Remove the abi from ERC7730 json schema and examples --- assets/erc-7730/erc7730-v1.schema.json | 95 +------------------------- assets/erc-7730/example-erc20.json | 20 ------ assets/erc-7730/example-main.json | 1 - 3 files changed, 1 insertion(+), 115 deletions(-) diff --git a/assets/erc-7730/erc7730-v1.schema.json b/assets/erc-7730/erc7730-v1.schema.json index a9c8444dc10..dd6e83cc4ce 100644 --- a/assets/erc-7730/erc7730-v1.schema.json +++ b/assets/erc-7730/erc7730-v1.schema.json @@ -66,19 +66,6 @@ "description": "The contract binding context is a set constraints that are used to bind the ERC7730 file to a specific smart contract.", "properties": { - "abi": { - "oneOf": [ - { - "$ref": "#/$definitions/abi-json-schema" - }, - { - "title": "An ABI url", - "description": "URL of an ABI bound to this file.", - "type": "string", - "format": "uri-reference" - } - ] - }, "deployments": { "$ref": "#/$context/deployments" }, @@ -362,7 +349,7 @@ "formats": { "title": "List of field formats", - "description": "The list includes formatting info for each field of a structure. This list is indexed by a key identifying uniquely the message's type in the abi. For smartcontracts, it is the selector of the function or its signature; and for EIP712 messages it is the primaryType of the message.", + "description": "The list includes formatting info for each field of a structure. This list is indexed by the full function signature with parameter names.", "type": "object", "additionalProperties": { @@ -965,86 +952,6 @@ "types", "primaryType" ] - }, - - "abi-json-schema": { - "title": "An EVM ABI", - "type": "array", - "description": "JSON schema for the json representation of a solidity ABI", - "items": { - "type": "object", - "properties": { - "inputs": { - "type": "array", - "description": "an array of object with input parameters", - "items": { - "$ref": "#/$definitions/abi-parameter" - } - }, - "name": { - "type": "string", - "description": "the name of the function" - }, - "outputs": { - "type": "array", - "description": "an array of object with output parameters", - "items": { - "$ref": "#/$definitions/abi-parameter" - } - }, - "stateMutability": { - "type": "string", - "enum": [ - "pure", - "view", - "nonpayable", - "payable" - ] - }, - "type": { - "type": "string", - "description": "the type of object being described", - "enum": [ - "function", - "constructor", - "receive", - "fallback" - ] - } - }, - "required": [ - "inputs", - "type" - ] - } - }, - - "abi-parameter": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Name of the parameter, used in the selector computation" - }, - "type": { - "type": "string", - "description": "the canonical type of the parameter" - }, - "internalType": { - "type": "string", - "description": "fully qualified type name in solidity source code" - }, - "components": { - "type": "array", - "items": { - "$ref": "#/$definitions/abi-parameter" - } - } - }, - "required": [ - "name", - "type" - ] } } } diff --git a/assets/erc-7730/example-erc20.json b/assets/erc-7730/example-erc20.json index 681ad381f28..133cffec925 100644 --- a/assets/erc-7730/example-erc20.json +++ b/assets/erc-7730/example-erc20.json @@ -1,24 +1,4 @@ { - "context": { - "contract": { - "abi": [ - { - "inputs": [ - { - "name": "_spender", - "type": "address" - }, - { - "name": "_value", - "type": "uint256" - } - ], - "name": "approve", - "type": "function" - } - ] - } - }, "display": { "formats": { "approve(address _spender,uint256 _value)": { diff --git a/assets/erc-7730/example-main.json b/assets/erc-7730/example-main.json index 5a658779533..6fc3c03c272 100644 --- a/assets/erc-7730/example-main.json +++ b/assets/erc-7730/example-main.json @@ -4,7 +4,6 @@ "context": { "$id": "Example ERC-20", "contract" : { - "abi": "https://api.example.io/api?module=contract&action=getabi&address=0xdac17f958d2ee523a2206206994597c13d831ec7", "deployments": [ { "chainId": 1, From d4a48fc5174f00f90ebfd405bf27780edb7f4538 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Fri, 31 Oct 2025 08:52:39 +0100 Subject: [PATCH 06/12] savepoint --- ERCS/erc-7730.md | 49 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/ERCS/erc-7730.md b/ERCS/erc-7730.md index 0662292d91d..04e9cede1cc 100644 --- a/ERCS/erc-7730.md +++ b/ERCS/erc-7730.md @@ -91,7 +91,9 @@ The following is an example of how to clear sign a `transfer` function call on a "label": "To", "format": "addressName" } - ] + ], + "required": ["to", "value"], + "excluded": [] } } } @@ -183,11 +185,12 @@ For paths referring to structured data fields, if a field has a variable length *Examples* References to values in the serialized structured data -* `#.` or relative `value` refers to the decoded argument named `value` from the matched function fragment -* `#.order.price` refers to the `price` field inside the `order` tuple argument -* `#.recipients.[0]` refers to the first entry of the `recipients` dynamic array -* `#.order.path.[0:20]` refers to the first 20 bytes of a `path` byte array nested inside the `order` tuple +* `#.params.amountIn` or `params.amountIn` refers to parameter `amountIn` in the top-level structure `params` as defined by the message schema. +* `#.data.path.[0].path.[-1].to` or `data.path.[0].path.[-1].to` refers to the field `to` taken from last member of `path` array, itself taken from first member of enclosing `path` array, itself part of top level `data` structure. +* `#.params.path.[:20]` or `#.params.path.[0:20]` refers to the first 20 bytes of the `path` byte array +* `#.params.path.[-20:]` refers to the last 20 bytes of the `path` byte array * `#.details.[]` refers to the array with the Permit Details of a PermitBatch message +* For contract calls (functions only), use argument paths, e.g. `value` or the absolute form `#.function.transfer.value`. References to values in the format specification file * `$.metadata.enums.interestRateMode` refers to the values of an enum defined in the specification file (typically to convert an integer into a displayed string) @@ -209,7 +212,7 @@ The `interpolatedIntent` makes transaction intents significantly shorter and eas **Interpolation Syntax** Values are interpolated using curly braces containing a path reference: `{path}`. The path MUST follow the [path reference rules](#path-references) and can reference: -- Structured data fields (e.g., `{to}`, `{order.amount}`) +- Structured data fields (e.g., `{_to}`, `{params.amountIn}`) - Container values (e.g., `{@.value}`, `{@.from}`) - Metadata constants (e.g., `{$.metadata.constants.nativeAssetAddress}`) @@ -382,7 +385,7 @@ This file defines a generic ERC-20 interface for a single `approve` function: } } ], - "required": ["spender", "value"] + "required": ["_spender", "_value"] } } } @@ -423,10 +426,10 @@ The following file would include this generic interface and bind it to the speci "display": { "formats": { - "approve(address spender,uint256 value)": { + "approve(address _spender,uint256 _value)": { "fields": [ { - "path": "value", + "path": "_value", "params" : { "threshold": "0xFFFFFFFFFFFFFFFFFF" } @@ -437,7 +440,7 @@ The following file would include this generic interface and bind it to the speci } } ``` -Note that the keys under `context.contract` would be merged together to construct a full contract binding object. The field formatter `value` parameter `threshold` is overridden with value `0xFFFFFFFFFFFFFFFFFF`. +Note that the keys under `context.contract` would be merged together to construct a full contract binding object. The field formatter `_value` parameter `threshold` is overridden with value `0xFFFFFFFFFFFFFFFFFF`. ### `Context` section @@ -893,8 +896,8 @@ Interpolated paths MUST reference fields that have corresponding format specific "interpolatedIntent": "Approve {spender} to spend up to {amount} on your behalf until {deadline}", "fields": [ {"path": "spender", "label": "Spender", "format": "addressName"}, - {"path": "amount", "label": "Amount", "format": "tokenAmount", "params": {"tokenPath": "@.to"}}, - {"path": "deadline", "label": "Deadline", "format": "date", "params": {"encoding": "timestamp"}} + {"path": "amount", "label": "Amount", "format": "tokenAmount"}, + {"path": "deadline", "label": "Deadline", "format": "date"} ] } ``` @@ -928,7 +931,7 @@ contract MyContract { } // Function declaration - function myFunction(address account, uint256 amount, MyParamType memory param) public { + function myFunction(address _address, uint256 _amount, MyParamType memory _param) public { // Function logic here } } @@ -939,20 +942,20 @@ The following ERC-7730 shows examples for the three kinds of `fields` options { "display": { "formats": { - "myFunction(address account,uint256 amount,MyParamType param)" : { + "myFunction(address _address,uint256 _amount,MyParamType _param)" : { "fields": [ { - "path": "account", + "path": "_address", "$ref": "$.display.definitions.sendTo", "params": { "type": "eoa" } }, { - "path": "amount", + "path": "_amount", "label": "Number of items", "format": "raw" }, { - "path": "param", + "path": "_param", "fields": [ { "path": "name", "$ref": "$.display.definitions.itemName" }, { "path": "value", "$ref": "$.display.definitions.itemReference" } @@ -964,19 +967,19 @@ The following ERC-7730 shows examples for the three kinds of `fields` options } } ``` -* The `account` field is an example of an internal reference (reference not included in the example), overriding the reference `type` parameter with another value. -* The `amount` field shows an example of a simple formatter, displaying an int in its natural representation with a label. -* The `param` field shows an example of defining formatters with a recursive structure, ending up defining two embedded formatters for paths `#.param.name` and `#.param.value` +* The `_address` field is an example of an internal reference (reference not included in the example), overriding the reference `type` parameter with another value. +* The `_amount` field shows an example of a simple formatter, displaying an int in its natural representation with a label. +* The `_param` field shows an example of defining formatters with a recursive structure, ending up defining two embedded formatters for paths `#._param.name` and `#._param.value` Note that the recursive definition is equivalent to the following definition, which is the preferred form: ```json { "display": { "formats": { - "myFunction(address account,uint256 amount,MyParamType param)" : { + "myFunction(address _address,uint256 _amount,MyParamType _param)" : { "fields": [ - { "path":"param.name", "$ref": "$.display.definitions.itemName" }, - { "path":"param.value", "$ref": "$.display.definitions.itemReference" } + { "path":"_param.name", "$ref": "$.display.definitions.itemName" }, + { "path":"_param.value", "$ref": "$.display.definitions.itemReference" } ] } } From 683c505e6acd9350fcf3a31ee05d720f3932165b Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Fri, 31 Oct 2025 09:06:13 +0100 Subject: [PATCH 07/12] savepoint --- ERCS/erc-7730.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/ERCS/erc-7730.md b/ERCS/erc-7730.md index 04e9cede1cc..2a46ea4d894 100644 --- a/ERCS/erc-7730.md +++ b/ERCS/erc-7730.md @@ -89,7 +89,10 @@ The following is an example of how to clear sign a `transfer` function call on a { "path": "to", "label": "To", - "format": "addressName" + "format": "addressName", + "params": { + "tokenPath": "@.to" + } } ], "required": ["to", "value"], @@ -235,10 +238,10 @@ To include literal curly braces in the intent text, escape them by doubling: `{{ ```json { "intent": "Send", - "interpolatedIntent": "Send {value} to {to}", + "interpolatedIntent": "Send {_value} to {_to}", "fields": [ - {"path": "to", "format": "addressName"}, - {"path": "value", "format": "tokenAmount", "params": {"tokenPath": "@.to"}} + {"path": "_to", "format": "addressName"}, + {"path": "_value", "format": "tokenAmount", "params": {"tokenPath": "@.to"}} ] } ``` @@ -303,7 +306,7 @@ Combined display: **"Approve Uniswap Router to spend 1000 USDC and Swap 1000 USD [ { "function": "approve", - "interpolatedIntent": "Approve {spender} to spend {value}" + "interpolatedIntent": "Approve {_spender} to spend {_value}" }, { "function": "exactInputSingle", @@ -318,7 +321,7 @@ Combined display: **"Approve Uniswap V3 Router to spend 5000 DAI and Swap 5000 D [ { "function": "approve", - "interpolatedIntent": "Approve {spender} to spend {value}" + "interpolatedIntent": "Approve {_spender} to spend {_value}" }, { "function": "swapExactTokensForETH", From bac3e00cb47b31020518f904a49b24ebc42171c9 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Fri, 31 Oct 2025 09:18:39 +0100 Subject: [PATCH 08/12] Restore token formatting guidance and update contract paths --- ERCS/erc-7730.md | 12 ++++++------ assets/erc-7730/example-erc20.json | 18 ++++++++---------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/ERCS/erc-7730.md b/ERCS/erc-7730.md index 2a46ea4d894..29e31839e43 100644 --- a/ERCS/erc-7730.md +++ b/ERCS/erc-7730.md @@ -84,15 +84,15 @@ The following is an example of how to clear sign a `transfer` function call on a { "path": "value", "label": "Amount", - "format": "tokenAmount" + "format": "tokenAmount", + "params": { + "tokenPath": "@.to" + } }, { "path": "to", "label": "To", - "format": "addressName", - "params": { - "tokenPath": "@.to" - } + "format": "addressName" } ], "required": ["to", "value"], @@ -193,7 +193,7 @@ References to values in the serialized structured data * `#.params.path.[:20]` or `#.params.path.[0:20]` refers to the first 20 bytes of the `path` byte array * `#.params.path.[-20:]` refers to the last 20 bytes of the `path` byte array * `#.details.[]` refers to the array with the Permit Details of a PermitBatch message -* For contract calls (functions only), use argument paths, e.g. `value` or the absolute form `#.function.transfer.value`. +* For contract calls (functions only), use decoded argument paths such as `value` or `#.order.price`. References to values in the format specification file * `$.metadata.enums.interestRateMode` refers to the values of an enum defined in the specification file (typically to convert an integer into a displayed string) diff --git a/assets/erc-7730/example-erc20.json b/assets/erc-7730/example-erc20.json index 133cffec925..b6f560dc8f9 100644 --- a/assets/erc-7730/example-erc20.json +++ b/assets/erc-7730/example-erc20.json @@ -1,28 +1,26 @@ { "display": { "formats": { - "approve(address _spender,uint256 _value)": { + "approve(address spender,uint256 value)": { "intent": "Approve", - "interpolatedIntent": "Approve {_spender} to spend {_value}", + "interpolatedIntent": "Approve {spender} to spend {value}", "fields": [ { - "path": "_spender", + "path": "spender", "label": "Spender", - "format": "addressOrName" + "format": "addressName" }, { - "path": "_value", + "path": "value", "label": "Amount", "format": "tokenAmount", "params": { - "tokenPath": "@.to", - "threshold": "0x8000000000000000000000000000000000000000000000000000000000000000", - "thresholdLabel": "Unlimited" + "tokenPath": "@.to" } } ], - "required": ["_spender", "_value"] + "required": ["spender", "value"] } } } -} \ No newline at end of file +} From 5323ead414a255bd855ec3fecb11f6c8108fceb1 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Fri, 31 Oct 2025 09:29:41 +0100 Subject: [PATCH 09/12] Align examples with underscore-free parameter naming --- ERCS/erc-7730.md | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/ERCS/erc-7730.md b/ERCS/erc-7730.md index 29e31839e43..c2b3d07ec4c 100644 --- a/ERCS/erc-7730.md +++ b/ERCS/erc-7730.md @@ -215,7 +215,7 @@ The `interpolatedIntent` makes transaction intents significantly shorter and eas **Interpolation Syntax** Values are interpolated using curly braces containing a path reference: `{path}`. The path MUST follow the [path reference rules](#path-references) and can reference: -- Structured data fields (e.g., `{_to}`, `{params.amountIn}`) +- Structured data fields (e.g., `{to}`, `{params.amountIn}`) - Container values (e.g., `{@.value}`, `{@.from}`) - Metadata constants (e.g., `{$.metadata.constants.nativeAssetAddress}`) @@ -238,10 +238,10 @@ To include literal curly braces in the intent text, escape them by doubling: `{{ ```json { "intent": "Send", - "interpolatedIntent": "Send {_value} to {_to}", + "interpolatedIntent": "Send {value} to {to}", "fields": [ - {"path": "_to", "format": "addressName"}, - {"path": "_value", "format": "tokenAmount", "params": {"tokenPath": "@.to"}} + {"path": "to", "format": "addressName"}, + {"path": "value", "format": "tokenAmount", "params": {"tokenPath": "@.to"}} ] } ``` @@ -306,7 +306,7 @@ Combined display: **"Approve Uniswap Router to spend 1000 USDC and Swap 1000 USD [ { "function": "approve", - "interpolatedIntent": "Approve {_spender} to spend {_value}" + "interpolatedIntent": "Approve {spender} to spend {value}" }, { "function": "exactInputSingle", @@ -321,7 +321,7 @@ Combined display: **"Approve Uniswap V3 Router to spend 5000 DAI and Swap 5000 D [ { "function": "approve", - "interpolatedIntent": "Approve {_spender} to spend {_value}" + "interpolatedIntent": "Approve {spender} to spend {value}" }, { "function": "swapExactTokensForETH", @@ -388,7 +388,7 @@ This file defines a generic ERC-20 interface for a single `approve` function: } } ], - "required": ["_spender", "_value"] + "required": ["spender", "value"] } } } @@ -429,10 +429,10 @@ The following file would include this generic interface and bind it to the speci "display": { "formats": { - "approve(address _spender,uint256 _value)": { + "approve(address spender,uint256 value)": { "fields": [ { - "path": "_value", + "path": "value", "params" : { "threshold": "0xFFFFFFFFFFFFFFFFFF" } @@ -443,7 +443,7 @@ The following file would include this generic interface and bind it to the speci } } ``` -Note that the keys under `context.contract` would be merged together to construct a full contract binding object. The field formatter `_value` parameter `threshold` is overridden with value `0xFFFFFFFFFFFFFFFFFF`. +Note that the keys under `context.contract` would be merged together to construct a full contract binding object. The field formatter `value` parameter `threshold` is overridden with value `0xFFFFFFFFFFFFFFFFFF`. ### `Context` section @@ -934,7 +934,7 @@ contract MyContract { } // Function declaration - function myFunction(address _address, uint256 _amount, MyParamType memory _param) public { + function myFunction(address account, uint256 amount, MyParamType memory param) public { // Function logic here } } @@ -945,20 +945,20 @@ The following ERC-7730 shows examples for the three kinds of `fields` options { "display": { "formats": { - "myFunction(address _address,uint256 _amount,MyParamType _param)" : { + "myFunction(address account,uint256 amount,MyParamType param)" : { "fields": [ { - "path": "_address", + "path": "account", "$ref": "$.display.definitions.sendTo", "params": { "type": "eoa" } }, { - "path": "_amount", + "path": "amount", "label": "Number of items", "format": "raw" }, { - "path": "_param", + "path": "param", "fields": [ { "path": "name", "$ref": "$.display.definitions.itemName" }, { "path": "value", "$ref": "$.display.definitions.itemReference" } @@ -970,19 +970,19 @@ The following ERC-7730 shows examples for the three kinds of `fields` options } } ``` -* The `_address` field is an example of an internal reference (reference not included in the example), overriding the reference `type` parameter with another value. -* The `_amount` field shows an example of a simple formatter, displaying an int in its natural representation with a label. -* The `_param` field shows an example of defining formatters with a recursive structure, ending up defining two embedded formatters for paths `#._param.name` and `#._param.value` +* The `account` field is an example of an internal reference (reference not included in the example), overriding the reference `type` parameter with another value. +* The `amount` field shows an example of a simple formatter, displaying an int in its natural representation with a label. +* The `param` field shows an example of defining formatters with a recursive structure, ending up defining two embedded formatters for paths `#.param.name` and `#.param.value` Note that the recursive definition is equivalent to the following definition, which is the preferred form: ```json { "display": { "formats": { - "myFunction(address _address,uint256 _amount,MyParamType _param)" : { + "myFunction(address account,uint256 amount,MyParamType param)" : { "fields": [ - { "path":"_param.name", "$ref": "$.display.definitions.itemName" }, - { "path":"_param.value", "$ref": "$.display.definitions.itemReference" } + { "path":"param.name", "$ref": "$.display.definitions.itemName" }, + { "path":"param.value", "$ref": "$.display.definitions.itemReference" } ] } } From 94fb7f1a550fc9d151a4a22cb05e19b7d41c85ff Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Wed, 5 Nov 2025 08:35:45 +0100 Subject: [PATCH 10/12] mention abi deprecation --- ERCS/erc-7730.md | 4 ++++ assets/erc-7730/erc7730-v1.schema.json | 3 +++ 2 files changed, 7 insertions(+) diff --git a/ERCS/erc-7730.md b/ERCS/erc-7730.md index c2b3d07ec4c..173c6d00dad 100644 --- a/ERCS/erc-7730.md +++ b/ERCS/erc-7730.md @@ -465,6 +465,10 @@ A deployment option is an object with: * `chainId`: an [EIP-155 identifier](./eip-155.md) of the chain the described contract is deployed on. * `address`: the address of the deployed contract on specified `chainId` chain. +**`contract.abi`** *(deprecated)* + +Legacy ABI attachment kept for backward compatibility. Authors SHOULD prefer `display.formats` and avoid relying on this key, as it will be removed in a future revision. + --- *The following constraints for contracts are considered draft* diff --git a/assets/erc-7730/erc7730-v1.schema.json b/assets/erc-7730/erc7730-v1.schema.json index dd6e83cc4ce..4a3e2b8ce1e 100644 --- a/assets/erc-7730/erc7730-v1.schema.json +++ b/assets/erc-7730/erc7730-v1.schema.json @@ -66,6 +66,9 @@ "description": "The contract binding context is a set constraints that are used to bind the ERC7730 file to a specific smart contract.", "properties": { + "abi": { + "description": "[Deprecated] ABI definition bound to this file. Continue providing it for backward compatibility only; new specs should rely on display formats." + }, "deployments": { "$ref": "#/$context/deployments" }, From 42a0ab6ba38afca77482d405cad0366b049f5861 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Wed, 5 Nov 2025 08:48:47 +0100 Subject: [PATCH 11/12] Validate format keys as function signatures --- assets/erc-7730/erc7730-v1.schema.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/assets/erc-7730/erc7730-v1.schema.json b/assets/erc-7730/erc7730-v1.schema.json index 4a3e2b8ce1e..4cbf2fd8524 100644 --- a/assets/erc-7730/erc7730-v1.schema.json +++ b/assets/erc-7730/erc7730-v1.schema.json @@ -354,6 +354,9 @@ "title": "List of field formats", "description": "The list includes formatting info for each field of a structure. This list is indexed by the full function signature with parameter names.", "type": "object", + "propertyNames": { + "pattern": "^[A-Za-z_][A-Za-z0-9_]*\\(\\s*(?:(?:(?:tuple(?:\\s*\\((?:[^()]|\\([^()]*\\))*\\))?|[A-Za-z0-9_]+)(?:\\[[0-9]*\\])*(?:\\s+(?:memory|calldata|storage))?\\s+[A-Za-z_][A-Za-z0-9_]*)(?:\\s*,\\s*(?:(?:tuple(?:\\s*\\((?:[^()]|\\([^()]*\\))*\\))?|[A-Za-z0-9_]+)(?:\\[[0-9]*\\])*(?:\\s+(?:memory|calldata|storage))?\\s+[A-Za-z_][A-Za-z0-9_]*))*\\s*)?\\)$" + }, "additionalProperties": { "title": "A structured data format specification", From 8a4f78dfb5183bd5101c3d40cc32a374a2d5f9fb Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Wed, 5 Nov 2025 08:52:22 +0100 Subject: [PATCH 12/12] Enforce format key syntax and clarify schema indexing --- assets/erc-7730/erc7730-v1.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/erc-7730/erc7730-v1.schema.json b/assets/erc-7730/erc7730-v1.schema.json index 4cbf2fd8524..598a20540aa 100644 --- a/assets/erc-7730/erc7730-v1.schema.json +++ b/assets/erc-7730/erc7730-v1.schema.json @@ -352,7 +352,7 @@ "formats": { "title": "List of field formats", - "description": "The list includes formatting info for each field of a structure. This list is indexed by the full function signature with parameter names.", + "description": "The list includes formatting info for each field of a structure. For contract bindings, entries are keyed by the full function signature with parameter names; for EIP712 bindings, entries are keyed by the message primary type.", "type": "object", "propertyNames": { "pattern": "^[A-Za-z_][A-Za-z0-9_]*\\(\\s*(?:(?:(?:tuple(?:\\s*\\((?:[^()]|\\([^()]*\\))*\\))?|[A-Za-z0-9_]+)(?:\\[[0-9]*\\])*(?:\\s+(?:memory|calldata|storage))?\\s+[A-Za-z_][A-Za-z0-9_]*)(?:\\s*,\\s*(?:(?:tuple(?:\\s*\\((?:[^()]|\\([^()]*\\))*\\))?|[A-Za-z0-9_]+)(?:\\[[0-9]*\\])*(?:\\s+(?:memory|calldata|storage))?\\s+[A-Za-z_][A-Za-z0-9_]*))*\\s*)?\\)$"