ERC-6809 Key-Bound NFT standard (Non-Fungible Key Bound Token)

Final · NFTs & multi-token · created 2023-03-31

An ERC-721 extension that builds optional security features into the NFT itself. An NFT can be moved only when two separate key wallets authorize the transfer and approval, so assets stay safe even if the holding wallet is compromised.

Why it is needed

With self-custody assets, all responsibility rests with the individual. If a seed phrase or private key leaks, no one can recover the NFTs in the wallet. According to the original text, more than 46,000 crypto scam reports were filed with the US Federal Trade Commission from January 2021 to March 2022, and consumer losses exceeded 1 billion dollars. Existing security measures also have limits. Centralized services require account creation and submission of personal information and may be subject to regional restrictions, while decentralized options such as hardware wallets come with logistical problems such as purchase and shipping. This standard takes a different approach by building security into the token itself rather than the wallet. With the security feature turned on, individual assets stay protected even if the seed phrase is exposed, and with it turned off, the token behaves exactly like a regular ERC-721.

What to implement

In depth

The three-wallet scheme and addBindings

addBindings(_keyWallet1, _keyWallet2) binds two key wallets to the sending account at once and must emit an AccountSecured event. It SHOULD revert if the caller is not a holder, if security is already set, if the two key wallets are the same, if a key wallet equals the caller itself, if either of them is the zero address (0x0), or if one is already a key wallet of another holding account. The original text explains that the two wallets are registered together to reduce fees, prevent mistakes, and avoid situations where safeFallback misbehaves. If addBindings is never called, the token keeps the same default behavior as a regular ERC-721.

How allowTransfer conditions are interpreted

allowTransfer(_tokenId, _time, _to, _anyToken) is called from a key wallet and runs before transferFrom or safeTransferFrom. If _tokenId is 0 there is no token restriction, if _time is 0 there is no time restriction, and if _to is the zero address there is no recipient restriction. If _anyToken is true, any token can be sent at any time to anyone, regardless of the other parameters. It must emit an AccountEnabledTransfer event, and it SHOULD revert if the caller is not a key wallet of the holder or if the owner of _tokenId differs from that holder.

allowApproval and decrementing the transfer count

allowApproval(_time, _numberOfTransfers) is called from a key wallet and runs before approve or setApprovalForAll. It lets the holder make approvals for _time and limits the number of transfers the approved party can make to _numberOfTransfers (0 means unlimited within the permitted limit). After that, each time transferFrom is called, the contract decrements the remaining count, and when it reaches 0 it sets setApprovalForAll to false to revoke the approval. approve and setApprovalForAll SHOULD revert if the secure account has not called allowApproval or if the configured _time has passed.

safeFallback: when the holding wallet is compromised

When safeFallback is called from a key wallet, all tokens in the holding account must move to the other key wallet, and a SafeFallbackActivated event must be emitted. It SHOULD revert if the caller is not a key wallet. The key point is that tokens go to the opposite key wallet rather than the caller. If they went to the calling wallet, an attacker who took over one key wallet could call safeFallback and take everything. Average gas in testing is 72,221, which varies with the number of NFTs held.

resetBindings: when a key wallet is compromised

When resetBindings is called from a key wallet, the key wallet settings of the holding account are cleared and an AccountResetBinding event must be emitted. After that, tokens behave like a regular ERC-721, and the holding wallet can register new key wallets by calling addBindings again. The reason only key wallets, not the holding wallet, can call this function is that if the holding wallet could, an attacker who took over the holding wallet could immediately disable the security and take the assets. The original text explains that if two of the three wallets are compromised at the same time there is no way to stop it, but a compromise of up to one wallet leaves a chance to recover.

ERC-721 compatibility and return value handling

This standard inherits every property of ERC-721, so it works unchanged in dApps that already use non-fungible tokens, and existing tokens and wallets are not affected. transferFrom and safeTransferFrom SHOULD revert if the caller is neither the owner nor an approved account, if _from is not the owner, or if the security account has not permitted the transfer of that _tokenId through allowTransfer. The specification states that callers must handle a false value of returns (bool success) and must not assume that false is never returned. allowTransfer and allowApproval return a bool on success and revert on failure for consistency with ERC-721.

Things to watch out for

Original ERC · ← ERCs