Alert Source Discuss
⚠️ Draft Standards Track: ERC

ERC-6823: Token Mapping Slot Retrieval Extension (Token 映射槽检索扩展)

Approach to enhance precision of off-chain transaction simulations by accessing mapping storage slot in ERC-20/721/1155 contracts. (通过访问 ERC-20/721/1155 合约中的映射存储槽来提高链下交易模拟精度的方案。)

Authors qdqd (@qd-qd) <qdqdqdqdqd@protonmail.com>
Created 2023-03-29
Discussion Link https://ethereum-magicians.org/t/eip-6823-token-mapping-slot-retrieval-extension/13666
Requires EIP-20, EIP-721, EIP-1155

Abstract

The aim of this proposal is to enhance the precision of off-chain simulations for transactions that involve contracts complying with the ERC-20, ERC-721, or ERC-1155 standards. (本提案旨在提高链下模拟对于涉及符合 ERC-20ERC-721ERC-1155 标准合约的交易的精确度。) To achieve this, a method is proposed for obtaining the reserved storage slot of the mapping responsible to track ownership of compliant tokens. (为了达到这个目的,我们提出了一种方法,用于获取负责追踪合规 token 所有权的映射的保留存储槽。) The proposed extension offers a standardized entry point that allows for identifying the reserved storage slot of a mapping in a compatible manner. (提议的扩展提供了一个标准化的入口点,允许以兼容的方式识别映射的保留存储槽。) This not only facilitates capturing state changes more precisely but also enables external tools and services to do so without requiring expertise in the particular implementation details. (这不仅有助于更精确地捕获状态变化,而且使外部工具和服务能够在不需要特定实现细节的专业知识的情况下做到这一点。)

Motivation

To understand the rationale behind this proposal, it’s important to remember how values and mapping are stored in the storage layout. (要理解本提案背后的原理,重要的是要记住值和映射是如何存储在存储布局中的。) This procedure is language-agnostic; it can be applied to multiple programming languages beyond Solidity, including Vyper. (此过程与语言无关;它可以应用于除 Solidity 之外的多种编程语言,包括 Vyper。)

The storage layout is a way to persistently store data in Ethereum smart contracts. (存储布局是在以太坊智能合约中持久存储数据的一种方式。) In the EVM, storage is organized as a key-value store, where each key is a 32-byte location, and each value is a 32-byte word. (在 EVM 中,存储被组织为键值存储,其中每个键是 32 字节的位置,每个值是 32 字节的字。) When you define a state variable in a contract, it is assigned to a storage location. (当你在合约中定义一个状态变量时,它会被分配到一个存储位置。) The location is determined by the variable’s position in the contract’s storage structure. (该位置由变量在合约存储结构中的位置决定。) The first variable in the contract is assigned to location 0, the second to location 1, and so on. (合约中的第一个变量被分配到位置 0,第二个变量被分配到位置 1,依此类推。) Multiple values less than 32 bytes can be grouped to fit in a single slot if possible. (如果可能,可以将多个小于 32 字节的值组合在一起以适合单个槽。)

Due to their indeterminate size, mappings utilize a specialized storage arrangement. (由于它们的不确定大小,映射使用专门的存储安排。) Instead of storing mappings “in between” state variables, they are allocated to occupy 32 bytes only, and their elements are stored in a distinct storage slot computed through a keccak-256 hash. (映射不是存储在状态变量“之间”,而是仅分配占用 32 字节,并且它们的元素存储在一个通过 keccak-256 哈希计算出的不同存储槽中。) The location of the value corresponding to a mapping key k is determined by concatenating h(k) and p and performing a keccak-256 hash. (与映射键 k 对应的值的位置通过连接 h(k)p 并执行 keccak-256 哈希来确定。) The value of p is the position of the mapping in the storage layout, which depends on the order and the nature of the variables initialized before the mapping. (p 的值是映射在存储布局中的位置,这取决于在映射之前初始化的变量的顺序和性质。) It can’t be determined in a universal way as you have to know how the implementation of the contract is done. (它不能以一种通用的方式确定,因为你必须知道合约的实现方式。)

Due to the nature of the mapping type, it is challenging to simulate transactions that involve smart contracts because the storage layout for different contracts is unique to their specific implementation, etched by their variable requirements and the order of their declaration. (由于映射类型的性质,模拟涉及智能合约的交易具有挑战性,因为不同合约的存储布局对于其特定实现是唯一的,受到其变量要求和声明顺序的影响。) Since the storage location of a value in a mapping variable depends on this implementation-sensitive storage slot, we cannot guarantee similarity on the off-chain simulation version that an on-chain attempted interaction will result in. (由于映射变量中值的存储位置取决于这种对实现敏感的存储槽,因此我们无法保证链下模拟版本与链上尝试交互的结果相似。)

This hurdle prevents external platforms and tools from capturing/validating changes made to the contract’s state with certainty. (这个障碍阻止了外部平台和工具确定地捕获/验证对合约状态所做的更改。)

That’s why transaction simulation relies heavily on events. (这就是为什么交易模拟严重依赖于事件。) However, this approach has limitations, and events should only be informative and not relied upon as the single source of truth. (然而,这种方法有局限性,事件应该只是提供信息,而不应该作为唯一的真实来源。) The state is and must be the only source of truth. (状态是并且必须是唯一的真实来源。) Furthermore, it is impossible to know the shape of the storage deterministically and universally, which prevents us from verifying the source of truth that is storage, forcing us to rely on information emitted from the application layer. (此外,不可能确定地和普遍地知道存储的形状,这阻止我们验证作为真实来源的存储,迫使我们依赖于从应用层发出的信息。)

Specification

The keywords “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119 and RFC 8174. (本文档中的关键词 “MUST”、”MUST NOT”、”REQUIRED”、”SHALL”、”SHALL NOT”、”SHOULD”、”SHOULD NOT”、”RECOMMENDED”、”NOT RECOMMENDED”、”MAY” 和 “OPTIONAL” 按照 RFC 2119 和 RFC 8174 中的描述进行解释。)

The proposal suggests an extension to the ERC-20/ERC-721/ERC-1155 standards that allows retrieving the reserved storage slot for the mapping type in any compliant smart-contract implementation in a deterministic manner. (该提案建议对 ERC-20/ERC-721/ERC-1155 标准进行扩展,允许以确定性的方式检索任何符合标准的智能合约实现中映射类型的保留存储槽。) This method eliminates the reliance on events and enhances the precision of the data access from storage. (这种方法消除了对事件的依赖,并提高了从存储访问数据的精确性。) The proposed extension therefore enables accurate off-chain simulations. (因此,所提议的扩展实现了精确的链下模拟。) The outcome is greater transparency and predictability at no extra cost for the caller, and a negigleable increase in the deployment cost of the contract. (结果是更高的透明度和可预测性,而不会给调用者带来额外的成本,并且合约的部署成本略有增加。)

The proposed extension is a single function that returns the reserved storage slot for the mapping type in any ERC-20/ERC-721/ERC-1155 compliant smart-contract implementation. (提议的扩展是一个单一函数,它返回任何符合 ERC-20/ERC-721/ERC-1155 的智能合约实现中映射类型的保留存储槽。) The function is named getTokenLocationRoot and is declared as follows: (该函数被命名为 getTokenLocationRoot,并声明如下:)

abstract contract ERC20Extension is ERC20 {
    function getTokenLocationRoot() external pure virtual returns (bytes32 slot) {
        assembly {
            slot := <mapping_name>.slot
        }
    }
}

abstract contract ERC721Extension is ERC721 {
    function getTokenLocationRoot() external pure virtual returns (bytes32 slot) {
        assembly {
            slot := <mapping_name>.slot
        }
    }
}

abstract contract ERC1155Extension is ERC1155 {
    function getTokenLocationRoot() external pure virtual returns (bytes32 slot) {
        assembly {
            slot := <mapping_name>.slot
        }
    }
}

For these contracts, off-chain callers can use the getTokenLocationRoot() function to find the reserved storage slot for the mapping type. (对于这些合约,链下调用者可以使用 getTokenLocationRoot() 函数来查找映射类型的保留存储槽。) This function returns the reserved storage slot for the mapping type in the contract. (此函数返回合约中映射类型的保留存储槽。) This location is used to calculate where all the values of the mapping will be stored. (此位置用于计算映射的所有值将存储在哪里。) Knowing this value makes it possible to determine precisely where each value of the mapping will be stored, regardless of the contract’s implementation. (知道这个值使得确定映射的每个值将存储在哪里成为可能,而不管合约的实现如何。) The caller can use this slot to calculate the storage slot for a specific token ID and compare the value to the expected one to verify the action stated by the event. (调用者可以使用此槽来计算特定 token ID 的存储槽,并将该值与预期值进行比较,以验证事件声明的操作。) In the case of a ERC-721 mint, the caller can compare the value of the storage slot to the address of the token’s owner. (在 ERC-721 铸造的情况下,调用者可以将存储槽的值与 token 所有者的地址进行比较。) In the case of a ERC-20 transfer, the caller can compare the value of the storage slot to the address of the token’s new owner. (在 ERC-20 转账的情况下,调用者可以将存储槽的值与 token 新所有者的地址进行比较。) In the case of a ERC-1155 burn, the caller can compare the value of the storage slot to the zero address. (在 ERC-1155 销毁的情况下,调用者可以将存储槽的值与零地址进行比较。) The off-chain comparison can be performed with any of the many tools available. (链下比较可以使用许多可用的工具中的任何一个来执行。) In addition, it could perhaps allow storage to be proven atomically by not proving the entire state but only a location – to track ownership of a specific token, for example.(此外,它可能允许通过不证明整个状态而只证明一个位置来原子地证明存储——例如,跟踪特定 token 的所有权。)

The name of the function is intentionally generic to allow the same implementation for all the different token standards. (该函数的名称是有意通用的,以允许所有不同 token 标准的相同实现。) Once implemented universally, the selector derived from the signature of this function will be a single, universal entry point that can be used to directly read the slots in the storage responsible of the ownership, of any token contract. (一旦被普遍实现,从该函数签名派生的 selector 将是一个单一的、通用的入口点,它可以用来直接读取负责任何 token 合约所有权的存储中的槽。) This will make off-chain simulations significantly more accurate, and the events will be used for informational purposes only. (这将使链下模拟更加准确,并且事件将仅用于提供信息。)

Contract implementers MUST implement the getTokenLocationRoot() function in their contracts. (合约实现者必须在其合约中实现 getTokenLocationRoot() 函数。) The function MUST return the reserved storage slot for the mapping type in the contract. (该函数必须返回合约中映射类型的保留存储槽。) The function SHOULD be declared as external pure. (该函数应该声明为 external pure。)

Rationale

The idea behind the implementation was to find an elegant and concise way that avoided any breaking changes with the current standard. (该实现背后的想法是找到一种优雅而简洁的方式,避免对当前标准进行任何破坏性更改。) Moreover, since gas consumption is crucial, it was inconceivable to find an implementation that would cost gas to the final user. (此外,由于 gas 消耗至关重要,因此不可能找到一种会给最终用户带来 gas 成本的实现。) In this case, the addition of a function increases the deployment cost of the contract in a minimal way, but its use is totally free for the external actors. (在这种情况下,添加一个函数以最小的方式增加了合约的部署成本,但它的使用对于外部参与者来说是完全免费的。)

The implementation is minimalist in order to be as flexible as possible while being directly compatible with the main programming languages used today to develop smart-contracts for the EVM. (该实现是极简主义的,以便尽可能地灵活,同时与当今用于为 EVM 开发智能合约的主要编程语言直接兼容。)

Backwards Compatibility

No backward compatibility issues have been found. (未发现向后兼容性问题。)

Reference Implementation

abstract contract ERC20Extension is ERC20 {
    function getTokenLocationRoot() external pure virtual returns (bytes32 slot) {
        assembly {
            slot := <mapping_name>.slot
        }
    }
}

abstract contract ERC721Extension is ERC721 {
    function getTokenLocationRoot() external pure virtual returns (bytes32 slot) {
        assembly {
            slot := <mapping_name>.slot
        }
    }
}

abstract contract ERC1155Extension is ERC1155 {
    function getTokenLocationRoot() external pure virtual returns (bytes32 slot) {
        assembly {
            slot := <mapping_name>.slot
        }
    }
}

Security Considerations

No security issues are raised by the implementation of this extension. (此扩展的实现不会引发任何安全问题。)

Copyright and related rights waived via CC0.

Citation

Please cite this document as:

qdqd (@qd-qd) <qdqdqdqdqd@protonmail.com>, "ERC-6823: Token Mapping Slot Retrieval Extension (Token 映射槽检索扩展) [DRAFT]," Ethereum Improvement Proposals, no. 6823, March 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-6823.