Creator Token Standards gives creators the ability to define rules for how the transfer function operates for tokens following the ERC20, ERC721, and ERC1155 standards.
- Transfer Function Control:
- Creators can define rules that block or allow specific protocols using token transfer functions.
- These rules are useful in a variety of scenarios such as marketplaces, gaming platforms, or custom token transfer use cases.
- Working with Transfer Hooks:
- All major token standards (ERC20, ERC721, ERC1155) include
_beforeTokenTransfer
and _afterTokenTransfer
hooks, which allow injecting logic before and after token transfers. Important note: ERC721C is used with OpenZeppelin version 4.8.2. Therefore, the current ERC721C implementation is not compatible with v5 token contracts from OpenZeppelin. - A contract inheriting from ERC721C connects to these hooks and adds validation through an external transfer check contract (Creator Token Transfer Validator Contract).
- Configuring the CreatorTokenTransferValidator Contract:
- Used to set and enforce security rules defined by the token creator, such as blocking or allowing transfers based on the caller, from, and to addresses.
- Allows creators to dynamically adjust settings to increase or decrease the security level of their collections.
- Flexible Configuration:
- Creators can configure two key parameters for their collections:
- Transfer Security Level: Defines how strict the rules are for the collection.
- List ID: Specifies which whitelist/blacklist is applied to the collection.
- These settings can be changed at any time without the need to write new code.
The module consists of the following core contracts:
- ERC721C Contract
- Transfer Validator Contract – Creator Token Transfer Validator Contract
ERC721C: Core Contract
To use the ERC721C
contract, you simply need to inherit from it.
For a more detailed understanding, you can check out the full contract code and refer to the diagram below:
Ultimately, the token contract calls the validateTransfer method on the configured CreatorTokenTransferValidator contract with every token transfer attempt.
CreatorTokenTransferValidator Contract
This contract provides a mechanism for validating and managing transfer restrictions for collection tokens such as ERC20, ERC721, and ERC1155. It allows collection owners to configure transfer restrictions (e.g., black/white lists, transfer protection levels for tokens).
The entry point for validation is the validateTransfer(address caller, address from, address to)
function. This function is called by the token contract through transfer hooks.
The contract code is quite large, so let’s highlight the key functionality. If you want to see the full code, it’s available here.
Core Functions:
Creating and Managing Lists
The contract provides functions for creating and managing address lists (blacklists and whitelists). Creators can create new lists and add/remove addresses or contract code hashes:
createList(string name)
— creates a new list (black or white). addAccountsToBlacklist
/ removeAccountsFromBlacklist
— adds or removes addresses from the blacklist. addAccountsToWhitelist
/ removeAccountsFromWhitelist
— adds or removes addresses from the whitelist. addCodeHashesToBlacklist
— adds contract code hashes to the blacklist. addCodeHashesToWhitelist
— adds contract code hashes to the whitelist.
These functions provide flexible control over the security policies of a collection.
Collection Management
setTransferSecurityLevelOfCollection
(address collection,
uint8 level,
bool disableAuthorizationMode,
bool disableWildcardOperators
, bool enableAccountFreezingMode)
Sets transfer restrictions for the entire collection. This is the main function for managing transfer settings. We'll take a closer look at it later.
freezeAccountsForCollection
(address collection,
address[] calldata
accountsToFreeze)
Freezes the specified accounts for the collection, effectively preventing them from interacting with the tokens.
Transfer Validation
validateTransfer
(address caller,
address from,
address to)
Checks whether the transfer is allowed under the current security settings. This function is used in the token contract via the _beforeTokenTransfer
hook.
Authorization Management
addAccountsToAuthorizers
(uint120 id,
address[] calldata
accounts)
Sets token authorizers. Authorizers are specifically designated addresses (accounts or contracts) that are granted the right to approve other operators who can perform transfers bypassing the standard rules. These functions are listed below.
beforeAuthorizedTransfer
(address operator,
address token,
uint256 tokenId)
Sets an authorized operator to perform a transfer, bypassing the standard transfer checks. Important: the authorizer must later remove the authorization to avoid security issues.
afterAuthorizedTransfer
(address token,
uint256 tokenId)
Removes the authorization for the operator.
beforeAuthorizedTransferWithAmount
(address token,
uint256 tokenId,
uint256
/*amount*/)
Sets a token ID to be transferable by any operator, bypassing standard transfer validations. Again, the authorizer must remove the authorization afterward.
afterAuthorizedTransferWithAmount
(address token,
uint256 tokenId)
Removes the authorization for the token.
Technologies and Libraries Used
- OpenZeppelin Standard contracts are used, such as ERC165 for interface detection and EnumerableSet for managing lists.
- PermitC An enhanced version of permit2. This contract provides advanced permission management for ERC20, ERC721, and ERC1155 tokens, including:
- Single-use permit transfers
- Time-bound approvals
- Order ID based transfers
- Tstorish The Tstorish contract is used to manage the TSTORE opcode where supported by the EVM. It includes testing for TLOAD/TSTORE availability during contract deployment. If TSTORE is supported, it allows for more efficient storage operations. If not, it falls back to standard opcodes like SSTORE and SLOAD.
Let's take a closer look at the arguments of the function setTransferSecurityLevelOfCollection
(address
collection,
uint8 level,
bool
disableAuthorizationMode,
bool
disableWildcardOperators,
bool
enableAccountFreezingMode)
:
collection
– the address of the token contract for which the transfer policy is being set. level
– the transfer protection level, what we’ve been calling transfer restrictions. You can view the table here.
disableAuthorizationMode – disables the use of authorizers to allow individual transfers that bypass the transfer policy. disableWildcardOperators
– prevents authorizers from using wildcard operators (i.e., full bypass for specific token IDs). enableAccountFreezingMode
– enables the ability to freeze certain accounts, preventing them from sending tokens.
Thus, transfer restriction settings allow you to:
- Protect tokens from unauthorized transfers.
- Ensure that transactions go through trusted channels (like trusted forwarder contracts).
- Restrict access for smart contracts, if necessary.
- Configure a flexible security mechanism suitable for various use cases — from freely transferable tokens to bound tokens (Soulbound Tokens).