ERC-6066 NFT signature validation standard (Signature Validation Method for NFTs)
Final · Signatures & auth · created 2022-11-29
Defines a standard function that lets an NFT itself, rather than a regular account or a smart contract, be the subject of a signature, and lets anyone check whether that signature is valid.
Why it is needed
On Ethereum, signatures made by an externally owned account (EOA) can be verified with ecrecover(), and signatures made by a smart contract can be verified with ERC-1271, but there was no standard way to verify a signature made by an NFT. For example, suppose a DAO represents roles such as CEO and COO as NFT badges and replaces the holders by election every quarter. An agreement or approval signed by the sitting COO is then tied to that person's personal account at the time, not to the 'COO role'. When the person changes, past signatures do not move along with the role. Workarounds exist, such as using the DAO's multisig wallet or installing a contract as COO, but they make it hard to divide responsibility finely or add unnecessary complexity. This standard solves the problem by tying signatures to a transferable NFT.
In depth
Requirements for the isValidSignature function
The function takes tokenId (the token ID of the signing NFT), hash (the hash of the data being signed), and data (optional arbitrary data that can help verification). If the signature is valid, it MUST return the bytes4 magic value 0x12edb34f, it MUST NOT modify state (STATICCALL for solc below 0.5, the view modifier for 0.5 and above), and it MUST allow external calls. During verification it may call arbitrary other methods to check the signature.
Implementation obligations and calling obligations
A contract compatible with ERC-721 or ERC-1155 that wants to give token holders the ability to sign with an NFT MAY implement this function. On the other hand, a compatible caller that wants to support contract signatures MUST call this method when the signer is an NFT (ERC-721 or ERC-1155) holder. In other words, implementation is optional, but calling is mandatory for verifiers that claim support.
Why signature creation is not standardized
This proposal deliberately does not standardize how signatures are created. The reason is the same as why ERC-1271 does not force a signing method on smart contracts: fixing the creation method would reduce flexibility. For the verification method, it draws on the contract signature approach of Gnosis Safe, which is simple and well tested. The bytes calldata data parameter is optional and is used when verification needs additional data. It follows ERC-5750 for future extension.
A consent flag, not a cryptographic signature
This standard does not verify cryptographically generated signatures, so it is not compatible with existing signature verification work. Here a signature is nothing more than a boolean flag indicating consent. This design is consistent with the contract signature implementation of Gnosis Safe.
Structure of the reference implementation
The reference implementation keeps mapping(uint256 => mapping(bytes32 => bool)) storage in an ERC-721 contract and protects the sign(tokenId, hash) function with the onlyTokenOwner modifier so that only the owner of that NFT can register a signature. isValidSignature returns MAGICVALUE (0x12edb34f) if the stored value is true and BADVALUE (0xffffffff) otherwise, and the data parameter is not used in this example. It also declares ERC-165 support through supportsInterface, and the magic value equals type(IERC6066).interfaceId.
Things to watch out for
- Revocability of signatures: The property that contract-based signatures can be revoked carries over to this standard as it is. Both developers and users must take this into account.