ERC-7656 Contract Linking Service Factory (Generalized Contract-Linked Services)
Final · Accounts & wallets · created 2024-03-15
A shared factory standard that deploys, at a precomputable address, a "linked service" that adds functionality to an existing contract such as an NFT or smart account without changing its original code.
Why it is needed
A deployed contract cannot have its code changed. So to add new features to an NFT or smart account already in use, one has until now had to rely on approaches such as token-bound accounts. Existing standards, however, have two limitations. First, they effectively force the deployed contract to implement a specific interface so that it acts as an "account" that handles assets and executes transactions. Second, the link target is limited to NFTs, so there was no standardized way to attach features such as social recovery or permission management to non-NFT contracts such as ERC-4337 smart accounts. This standard defines a general-purpose factory that deploys services linked to any contract, allowing functionality to be extended without modifying the original contract while preserving the ownership relationship.
What to implement
function linkedData() external view returns (uint256 chainId, bytes12 mode, address linkedContract, uint256 linkedId): The linked service returns the chain ID, mode, linked contract, and link ID embedded in its own bytecode.
In depth
IERC7656Factory: create and compute
The factory provides two functions. create(implementation, salt, chainId, mode, linkedContract, linkedId) deploys a proxy pointing to the implementation, returns its address, emits a Created event, and reverts with a CreationFailed error on failure. compute is a view function that calculates, without deploying, the address that would be deployed with the same arguments. Every ERC7656Factory implementation MUST support the IERC7656Factory interface ID 0x9e23230a. The reference implementation's bytecode is deployed on Ethereum mainnet at 0x76565d90eeB1ce12D05d55D142510dBA634a128F, and it is planned to be deployed at the same address on other major mainnets and some testnets later.
The mode parameter: two linking modes
mode is a bytes12 selector that determines how the link target is interpreted. LINKED_ID (0x000000000000000000000000) is used when linking to a contract that needs a token or entity ID, such as an NFT, and guarantees compatibility with existing token-bound account systems. NO_LINKED_ID (0x000000000000000000000001) is for contracts that need no ID, such as ERC-4337 accounts. In this case linkedId remains in the interface for consistency, but it SHOULD be left as 0 unless the service needs it to carry other data. The reason for using 12 bytes instead of a boolean is room for future extension. The original text gives two examples: a service that requires an ERC-1155 token balance of at least 1000 uses the least significant byte 0x02 as the base mode and stores the minimum balance in the remaining bytes, and a service that stores a required ERC-20 balance in linkedId.
Deployed bytecode structure: 183 bytes
Every linked service MUST be deployed as an ERC-1167 minimal proxy, with immutable constant data appended after the bytecode. The structure is a 10-byte ERC-1167 header, a 20-byte implementation address, a 15-byte ERC-1167 footer, followed by a 32-byte salt, a 32-byte chainId, a 12-byte mode, a 20-byte linkedContract, and a 32-byte linkedId, for 183 bytes in total. Because the linking data is embedded in the code itself rather than in storage, a service has its own linking information that does not change after deployment.
Benefits of the deterministic address design
Attaching the linking data to the bytecode instead of storage guarantees three things. First, the address of a linked service can be computed off-chain in advance. Second, the factory stores no state, which reduces gas costs. Third, a service can be deployed at the time it is needed, or the address of a service that has not yet been deployed can be referenced ahead of time. The standard also does not force any particular interface or behavior on the implementation details of a linked service, so developers are free to build specialized services while keeping a consistent deployment and ownership model.
IERC7656Service and reading linkedData
A linked service SHOULD implement the IERC7656Service interface (ID 0x7e110a1d). linkedData() returns chainId, mode, linkedContract, and linkedId. The original text's example implementation uses extcodecopy to read the last 0x60 bytes of the service code and restore these values, separating mode from the first 12 bytes of the word that was read and the address from the rest. In the same example, owner() returns address(0) if chainId differs from the current chain, and otherwise returns the result of ownerOf on the linked ERC-721 token as the owner.
Three recommended implementation patterns
Three patterns are recommended when implementing a service (SHOULD). First, ownership verification: include a mechanism that checks whether an action is authorized by the current owner of the linked contract or token. Second, mode-specific logic: handle the NFT-linking scenario and the account-linking scenario separately according to the mode value. Third, cross-chain awareness: check that the action is executed on the chain specified in the chainId parameter, to prevent cross-chain replay attacks.
Backwards compatibility and standard status
Using LINKED_ID mode (0x000000000000000000000000) is compatible with existing token-bound accounts, so existing applications and infrastructure that support them continue to work without modification. Contracts that use NO_LINKED_ID mode (0x000000000000000000000001) may need a separate interface, but the core factory mechanism stays the same. This proposal is a standard that has been finalized with Final status.
Things to watch out for
- Ownership cycles: If a smart wallet linked to an NFT comes to hold that same NFT, an ownership cycle arises and the assets may become inaccessible. Implementers must provide safeguards that prevent or detect cycles.
- Last-minute permission change scams before a sale: A malicious seller can change or revoke service permissions just before a sale is finalized. NFT marketplaces that integrate with ERC-7656 services in particular can implement locking mechanisms that prevent last-minute changes.
- Malicious implementations: A registry cannot enforce legitimate ownership when a service is linked. Users must review or audit the implementation before deployment, and integrating frontends must display a warning when interacting with an unverified implementation.
- Upgrade risk: An upgradeable linked service carries the risk of unexpected changes or asset drain. If an upgrade is needed, a secure upgrade mechanism with a timelock or multisig governance must be implemented.
- Reentrancy and cross-contract attacks: A linked service that interacts with assets or external protocols can be vulnerable to reentrancy attacks. It should follow the checks-effects-interactions pattern and consider a reentrancy guard.