ERC-6909: Minimal Multi-Token Interface
A minimal specification for managing multiple tokens by their id in a single contract.
Abstract
The following specifies a multi-token contract as a simplified alternative to the ERC-1155 Multi-Token Standard. In contrast to ERC-1155, callbacks and batching have been removed from the interface and the permission system is a hybrid operator-approval scheme for granular and scalable permissions. Functionally, the interface has been reduced to the bare minimum required to manage multiple tokens under the same contract.
Motivation
The ERC-1155 standard includes unnecessary features such as requiring recipient accounts with code to implement callbacks returning specific values and batch-calls in the specification. In addition, the single operator permission scheme grants unlimited allowance on every token ID in the contract. Backwards compatibility is deliberately removed only where necessary. Additional features such as batch calls, increase and decrease allowance methods, and other user experience improvements are deliberately omitted in the specification to minimize the required external interface.
According to ERC-1155, callbacks are required for each transfer and batch transfer to contract accounts. This requires potentially unnecessary external calls to the recipient when the recipient account is a contract account. While this behavior may be desirable in some cases, there is no option to opt-out of this behavior, as is the case for ERC-721 having both transferFrom
and safeTransferFrom
. In addition to runtime performance of the token contract itself, it also impacts the runtime performance and codesize of recipient contract accounts, requiring multiple callback functions and return values to receive the tokens.
Batching transfers, while useful, are excluded from this standard to allow for opinionated batch transfer operations on different implementations. For example, a different ABI encoding may provide different benefits in different environments such as calldata size optimization for rollups with calldata storage commitments or runtime performance for environments with expensive gas fees.
A hybrid allowance-operator permission scheme enables granular yet scalable controls on token approvals. Allowances enable an external account to transfer tokens of a single token ID on a user's behalf w by their ID while operators are granted full transfer permission for all token IDs for the user.
Specification
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
Definitions
- infinite: The maximum value for a uint256 (
2 ** 256 - 1
). - caller: The caller of the current context (
msg.sender
). - spender: An account that transfers tokens on behalf of another account.
- operator: An account that has unlimited transfer permissions on all token ids for another account.
- mint: The creation of an amount of tokens. This MAY happen in a mint method or as a transfer from the zero address.
- burn: The removal an amount of tokens. This MAY happen in a burn method or as a transfer to the zero address.
Methods
balanceOf
The total amount
of a token id
that an owner
owns.
allowance
The total amount
of a token id that a spender is permitted to transfer on behalf of an owner.
isOperator
Returns true
if the spender
is approved as an operator for an owner
.
transfer
Transfers an amount
of a token id
from the caller to the receiver
.
MUST revert when the caller's balance for the token id
is insufficient.
MUST log the Transfer
event.
MUST return True.
transferFrom
Transfers an amount
of a token id
from a sender
to a receiver
by the caller.
MUST revert when the caller is neither the sender
nor an operator for the sender
and the caller's allowance for the token id
for the sender
is insufficient.
MUST revert when the sender
's balance for the token id is insufficient.
MUST log the Transfer
event.
MUST decrease the caller's allowance
by the same amount
of the sender
's balance decrease if the caller is not an operator for the sender
and the caller's allowance
is not infinite.
SHOULD NOT decrease the caller's allowance
for the token id
for the sender
if the allowance
is infinite.
SHOULD NOT decrease the caller's allowance
for the token id
for the sender
if the caller is an operator or the sender
.
MUST return True.
approve
Approves an amount
of a token id
that a spender
is permitted to transfer on behalf of the caller.
MUST set the allowance
of the spender
of the token id
for the caller to the amount
.
MUST log the Approval
event.
MUST return True.
setOperator
Grants or revokes unlimited transfer permissions for a spender
for any token id
on behalf of the caller.
MUST set the operator status to the approved
value.
MUST log the OperatorSet
event.
MUST return True.
Events
Transfer
The caller
initiates a transfer of an amount
of a token id
from a sender
to a receiver
.
MUST be logged when an amount
of a token id
is transferred from one account to another.
MUST be logged with the sender
address as the zero address when an amount
of a token id
is minted.
MUST be logged with the receiver
address as the zero address when an amount
of a token id
is burned.
OperatorSet
The owner
has set the approved
status to a spender
.
MUST be logged when the operator status is set.
MAY be logged when the operator status is set to the same status it was before the current call.
Approval
The owner
has approved a spender
to transfer an amount
of a token id
to be transferred on the owner's behalf.
MUST be logged when the allowance
is set by an owner
.
Interface ID
The interface ID is 0x0f632fb3
.
Metadata Extension
Methods
name
The name
of the contract.
symbol
The ticker symbol
of the contract.
decimals
The amount
of decimals for a token id
.
Content URI Extension
Methods
contractURI
The URI
for a token id
.
tokenURI
The URI
for a token id
.
MAY revert if the token id
does not exist.
MUST replace occurrences of {id}
in the returned URI string by the client.
Metadata Structure
Contract URI
JSON Schema:
JSON Example (Minimal):
Token URI
MUST replace occurrences of {id}
in the returned URI string by the client.
JSON Schema:
JSON Example (Minimal):
Token Supply Extension
Methods
totalSupply
The totalSupply
for a token id
.
Rationale
Granular Approvals
While the "operator model" from the ERC-1155 standard allows an account to set another account as an operator, giving full permissions to transfer any amount of any token id on behalf of the owner, this may not always be the desired permission scheme. The "allowance model" from ERC-20 allows an account to set an explicit amount of the token that another account can spend on the owner's behalf. This standard requires both be implemented, with the only modification being to the "allowance model" where the token id must be specified as well. This allows an account to grant specific approvals to specific token ids, infinite approvals to specific token ids, or infinite approvals to all token ids.
Removal of Batching
While batching operations is useful, its place should not be in the standard itself, but rather on a case-by-case basis. This allows for different tradeoffs to be made in terms of calldata layout, which may be especially useful for specific applications such as roll-ups that commit calldata to global storage.
Removal of Required Callbacks
Requiring callbacks unnecessarily encumbers implementors that either have no particular use case for callbacks or prefer a bespoke callback mechanism. Minimization of such requirements saves contract size, gas efficiency and complexity.
Removal of "Safe" Naming
The safeTransfer
and safeTransferFrom
naming conventions are misleading, especially in the context of the ERC-1155 and ERC-721 standards, as they require external calls to receiver accounts with code, passing the execution flow to an arbitrary contract, provided the receiver contract returns a specific value. The combination of removing mandatory callbacks and removing the word "safe" from all method names improves the safety of the control flow by default.
Backwards Compatibility
This is not backwards compatible with ERC-1155 as some methods are removed. However, wrappers can be implemented for the ERC-20, ERC-721, and ERC-1155 standards.
Reference Implementation
Security Considerations
Approvals and Operators
The specification includes two token transfer permission systems, the "allowance" and "operator" models. There are two security considerations in regards to delegating permission to transfer.
The first consideration is consistent with all delegated permission models. Any account with an allowance may transfer the full allowance for any reason at any time until the allowance is revoked. Any account with operator permissions may transfer any amount of any token id on behalf of the owner until the operator permission is revoked.
The second consideration is unique to systems with both delegated permission models. If an account has both operator permissions and an insufficient allowance for a given transfer, performing the allowance check before the operator check would result in a revert while performing the operator check before the allowance check would not. The specification intentionally leaves this unconstrained for cases where implementors may track allowances despite the operator status. Nonetheless, this is a notable consideration.
Copyright
Copyright and related rights waived via CC0.