Abstract
This proposal introduces a variation of ERC6551 that extends to all types of contracts linked to non-fungible tokens (NFTs). This generalization allows NFTs not only to own assets and interact with applications as accounts but also to be linked with any contract, enhancing their utility without necessitating modifications to existing smart contracts or infrastructure.
For reference:
- https://eips.ethereum.org/EIPS/eip-6551
- https://ethereum-magicians.org/t/erc-6551-non-fungible-token-bound-accounts/13030
Motivation
Our initial approach involved proposing an expansion of ERC6551 to encompass a broader scope of token-bound contracts beyond accounts. The goal was to enable any deployed token-bound contract to potentially represent more than just an account, with the actual functionality determined by checking the contractās interface. Unfortunately, this suggestion was not adopted due to concerns about complicating the trust model built into ERC6551, where projects rely on emitted events to understand the nature of the contract without additional verification steps. Our proposed change, while introducing versatility, would have necessitated interface checks by developers, introducing a layer of friction and potentially leading to non-account contracts being banned as spam by Token Bound Account (TBA) indexes.
Reflecting on this feedback and considering the vast potential applications, we have crafted this new proposal. It aims to transcend the limitations of having NFTs solely function as accounts, thus unlocking a myriad array of interactions and functionalities. By proposing a separate but complementary standard, we seek to preserve the integrity and trust model of ERC6551 while offering a framework for NFTs to engage with diverse contracts. This approach not only enriches the ecosystem but also aligns with the evolving complexity of digital and real-world assets that NFTs aim to represent.
Of course, if ERC6551 evolves in a more general way, weād be happy to dismiss this proposal.
Specification (updated on March 23 to latest version)
The interface IERC7656Registry
is defined as follows (the number is temporary, waiting for an EIP editor to assign it):
interface IERC7656Registry {
/**
* @notice The registry MUST emit the Created event upon successful contract creation.
* @param contractAddress The address of the created contract
* @param implementation The address of the implementation contract
* @param salt The salt to use for the create2 operation
* @param chainId The chain id of the chain where the contract is being created
* @param tokenContract The address of the token contract
* @param tokenId The id of the token
*/
event Created(
address contractAddress,
address indexed implementation,
bytes32 salt,
uint256 chainId,
address indexed tokenContract,
uint256 indexed tokenId
);
/**
* The registry MUST revert with CreationFailed error if the create2 operation fails.
*/
error CreationFailed();
/**
* @notice Creates a token linked account for a non-fungible token.
* If account has already been created, returns the account address without calling create2.
* @param implementation The address of the implementation contract
* @param salt The salt to use for the create2 operation
* @param chainId The chain id of the chain where the account is being created
* @param tokenContract The address of the token contract
* @param tokenId The id of the token
* Emits Created event.
* @return account The address of the token linked account
*/
function create(
address implementation,
bytes32 salt,
uint256 chainId,
address tokenContract,
uint256 tokenId
) external returns (address account);
/**
* @notice Returns the computed token linked account address for a non-fungible token.
* @param implementation The address of the implementation contract
* @param salt The salt to use for the create2 operation
* @param chainId The chain id of the chain where the account is being created
* @param tokenContract The address of the token contract
* @param tokenId The id of the token
* @return account The address of the token linked account
*/
function compute(
address implementation,
bytes32 salt,
uint256 chainId,
address tokenContract,
uint256 tokenId
) external view returns (address account);
}
Any contract developed using the ERC76xxRegistry
SHOULD implement the IERC76xxContract
interface:
interface IERC7656Contract {
/**
* @notice Returns the token linked to the contract
* @return chainId The chainId of the token
* @return tokenContract The address of the token contract
* @return tokenId The tokenId of the token
*/
function token() external view returns (uint256 chainId, address tokenContract, uint256 tokenId);
}
or the IERC6551Account
interface or both.
Here an implementation for a contract implementing IERC7656Contract
.
contract ERC7656Contract is IERC7656Contract {
function token() public view virtual returns (uint256, address, uint256) {
bytes memory footer = new bytes(0x60);
assembly {
extcodecopy(address(), add(footer, 0x20), 0x4d, 0x60)
}
return abi.decode(footer, (uint256, address, uint256));
}
}