[EIP-6551](https://eips.ethereum.org/EIPS/eip-6551) [EIP-721](https://eips.ethereum.org/EIPS/eip-721) [EIP-1167](https://eips.ethereum.org/EIPS/eip-1167) [EIP-165](https://eips.ethereum.org/EIPS/eip-165) [EIP-1271](https://eips.ethereum.org/EIPS/eip-1271) --- - **What** The EIP-6551 proposes a new standard (ERC) that allows Ethereum accounts to be assigned to all non-fungible tokens (NFTs) - token bound accounts (TBAs). These TBAs allows NFTs to own other assets and perform on-chain operations. These standard is composable and compatible with all existing smart contract standards and infrastructure. # Specification ## Singleton Registry - The **Registry** is a single point of entry for the creation of **TBAs** - The **Registry** has two functions: - `createAccount` : creates the **TBA** for an NFT given an **Account Implementation** address - `account` : computes the **TBA** address for an NFT given an **Account Implementation** address - The **Registry** deploys the **TBA** as a [ERC-1167: **Minimal Proxy Contract**](ERC-1167%20Minimal%20Proxy%20Contract.md) with immutable constant data appended to the bytecode. - The deployed bytecode for all **TBAs** has the following structure ``` ERC-1167 Header (10 bytes) <implementation (address)> (20 bytes) ERC-1167 Footer (15 bytes) <salt (uint256)> (32 bytes) <chainId (uint256)> (32 bytes) <tokenContract (address)> (32 bytes) <tokenId (uint256)> (32 bytes) ``` - The **Registry** contract is permissionless, immutable and has no owner - The **Registry** is deployed at address (TBD) using [Nick’s Factory](Nick’s%20Factory%20A%20Keyless%20Execution%20Deployment%20Method.md) and with [salt](Cryptography%20Salt%20-%20A%20set%20of%20random%20data%20used%20to%20increase%20entropy%20in%20a%20crypto%20function.md) (TBD) - The **Registry** deploys all **TBAs** using the CREATE2 opcode (this allows for each account address to be deterministic) - The address for each **TBA** is derived from the **Account Implementation** address, **Non-Fungible Token Contract** address, token ID, [EIP-155](EIP-155%20Simple%20Relay%20Account%20Protection.md) chain ID, and [salt](Cryptography%20Salt%20-%20A%20set%20of%20random%20data%20used%20to%20increase%20entropy%20in%20a%20crypto%20function.md). ### Registry Interface ```solidity interface IERC6551Registry { /** * @dev The registry SHALL emit the AccountCreated event upon successful account creation */ event AccountCreated( address account, address indexed implementation, uint256 chainId, address indexed tokenContract, uint256 indexed tokenId, uint256 salt ); /** * @dev Creates a token bound account for a non-fungible token. * * If account has already been created, returns the account address without calling create2. * * If initData is not empty and account has not yet been created, calls account with * provided initData after creation. * * Emits AccountCreated event. * * @return the address of the account */ function createAccount( address implementation, uint256 chainId, address tokenContract, uint256 tokenId, uint256 salt, bytes calldata initData ) external returns (address); /** * @dev Returns the computed token bound account address for a non-fungible token * * @return The computed address of the token bound account */ function account( address implementation, uint256 chainId, address tokenContract, uint256 tokenId, uint256 salt ) external view returns (address); } ``` ## Token Bound Account - The **Account**, created by the **Registry** merely serves to record state changes - All execution is delegated to the **Account Implementation** (or otherwise a contract that implements the `IERC6551Account` interface) - All **Account** implementation must implement [**ERC-165: Standard Interface Detection**](ERC-165%20Standard%20Interface%20Detection.md) and [ERC-1271: **Standard Signature Validation for Contracts**](ERC-1271%20Standard%20Signature%20Validation%20for%20Contracts.md) - All **TBAs** must implement a execution interface allowing valid signers to execute operations on behalf of the account - To support an execution interface it must be signaled by the account using [**ERC-165: Standard Interface Detection**](ERC-165%20Standard%20Interface%20Detection.md) ### Account Interface ```solidity /// @dev the ERC-165 identifier for this interface is `0x6faff5f1` interface IERC6551Account { /** * @dev Allows the account to receive Ether * * Accounts MUST implement a `receive` function. * * Accounts MAY perform arbitrary logic to restrict conditions * under which Ether can be received. */ receive() external payable; /** * @dev Returns the identifier of the non-fungible token which owns the account * * The return value of this function MUST be constant - it MUST NOT change * over time * * @return chainId The EIP-155 ID of the chain the token exists on * @return tokenContract The contract address of the token * @return tokenId The ID of the token */ function token() external view returns ( uint256 chainId, address tokenContract, uint256 tokenId ); /** * @dev Returns a value that SHOULD be modified each time the account changes state * * @return The current account state */ function state() external view returns (uint256); /** * @dev Returns a magic value indicating whether a given signer is authorized to act on behalf of the account * * MUST return the bytes4 magic value 0x523e3260 if the given signer is valid * * By default, the holder of the non-fungible token the account is bound to MUST be considered a valid * signer * * Accounts MAY implement additional authorization logic which invalidates the holder as a * signer or grants signing permissions to other non-holder accounts * * @param signer The address to check signing authorization for * @param context Additional data used to determine whether the signer is valid * @return magicValue Magic value indicating whether the signer is valid */ function isValidSigner(address signer, bytes calldata context) external view returns (bytes4 magicValue); } ``` ### Execution Interface ```solidity /// @dev the ERC-165 identifier for this interface is `0x74420f4c` interface IERC6551Executable { /** * @dev Executes a low-level operation if the caller is a valid signer on the account * * Reverts and bubbles up error if operation fails * * @param to The target address of the operation * @param value The Ether value to be sent to the target * @param data The encoded operation calldata * @param operation A value indicating the type of operation to perform * * Accounts implementing this interface MUST accept the following operation parameter values: * - 0 = CALL * - 1 = DELEGATECALL * - 2 = CREATE * - 3 = CREATE2 * * Accounts implementing this interface MAY support additional operations or restrict a signer's * ability to execute certain operations * * @return The result of the operation */ function execute( address to, uint256 value, bytes calldata data, uint256 operation ) external payable returns (bytes memory); } ``` # Rationale - Counterfactual Accounts: **TBAs** are created with [CREATE2](EIP-1014%20-%20Skinny%20CREATE2.md) which enables them to exist in a counterfactual state, allowing them to receive assets prior to contract creation - Trustless deployments: With an immutable, ownerless **Registry**, making so that the only trusted contract is the **Account Implementation** - Cross-chain Compatibility: By including `chainId` as a parameter to `createAccount`, it allows accounts to be deployed at the same address in different chains