[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