Transfer Security
Creator Token Standard contracts implement transfer security through the use of Transfer Security Levels and Lists giving creators full control over how their creations are distributed and used.
Transfer Security Levels
A collection's Transfer Security Level determines what restrictions are applied to transfers made by token owners. There
are nine unique security levels with the default Recommended level being functionally equivalent to level 3 while
optimizing contract initialization gas costs by leaving the storage slot as a zero value.
| Level | List Type | OTC | Smart Contract Receivers |
|---|---|---|---|
| Recommended | Whitelist | Allowed | Allowed |
| 1 | None | Allowed | Allowed |
| 2 | Blacklist | Allowed | Allowed |
| 3 | Whitelist | Allowed | Allowed |
| 4 | Whitelist | Blocked | Allowed |
| 5 | Whitelist | Allowed | Blocked Using Code Length Check |
| 6 | Whitelist | Allowed | Blocked Using EOA Signature Verification |
| 7 | Whitelist | Blocked | Blocked Using Code Length Check |
| 8 | Whitelist | Blocked | Blocked Using EOA Signature Verification |
| 9 | None | Blocked | Blocked by restricting transfer |
Transfer security settings are applied by a Transfer Validator contract. Limit Break provides a default transfer validator for use
by collections. Creators may implement their own transfer validator however it is highly recommended to use the default for user
experience and gas efficiency as it provides a single EOA Registry for all collections using Creator Token Standards and will
minimize user friction on collections that apply security levels 6 or 8.
Creators can manage their security settings at https://developers.freenft.com, with direct calls to their token contract (see Token Contract Functions) or direct calls to the transfer validator (see Transfer Contract Functions).
List Type
List types may be None, Blacklist or Whitelist and apply to the over-the-counter (OTC) transfer setting.
- None is only applied to security level
1. There are no filter lists applied to the transfer. - Blacklist is only applied to security level
2. If the transaction caller's codehash or contract address has been added to the list the transaction will not be allowed. This type of list is easily bypassed by users that deploy the same contracts to new addresses or make small changes to the contract code to get a new codehash without significantly changing the contract logic. - Whitelist is applied to all other security levels. If the transaction caller's codehash or contract address has not been added to the list the transaction will not be allowed. This type of list allows a creator to specify exactly which contracts are allowed to transact items in the collection.
Lists
Lists contain contract addresses and codehashes curated by a list owner and are stored in the Transfer Validator that is utilized by the collection. Lists may be shared between collections. A list will be enforced during a token transfer transaction based on the security level set for the collection.
OTC
OTC may be set to Allowed or Blocked based on the security level selected. If OTC is Allowed then a token owner may transfer their
tokens to another address without the transfer routing through another smart contract. If OTC is Blocked then a token owner's transfer must
be routed through a smart contract.
Smart Contract Receivers
Smart Contract Receivers may be set to Allowed or Blocked with the blocked state enforcement set to Code Length Check or
EOA Signature Verification. If smart contract receivers are Allowed then a token may be transferred to a smart contract.
If smart contract receivers are Blocked then the transfer validator will check that the receiver is an EOA using contract code
length or by requiring the receiver send a signed message to the EOA Registry to prove that their is a private key for the address.
Code length checks may be bypassed by executing transactions from a smart contract's constructor code. EOA signature verification requires additional steps and a transaction by the receiver.
Authorizers
The Creator Token Transfer Validator now includes a new validation procedure, utilizing approved authorizers to review and approve transfers. Authorizers will provide a signature enabling transfers if the transaction meets certain criteria such as paying royalties, multi-hop transfers, or utilizing a limited smart contract system for gaming restraints.
Account Freezing
As a method of last resort, creators can freeze an account to prevent all transfers from the address. This is intended to prevent malicious actors from circumventing any transfer rules the validators have set via unintended routes or exploits.
Mechanisms By Which Royalties Can Be Evaded (By Security Level)
| Level | Blocked Exchange | Pop-Up Exchange | OTC / Escrow | Wrapper Contracts | Trading Multi-Sig Wallets | Centralized Exchange w/EOA |
|---|---|---|---|---|---|---|
| 1 | Yes | Yes | Yes | Yes | Yes | Yes |
| 2 | No | Yes | Yes | Yes | Yes | Yes |
| 3 | No | No | Yes | Yes | Yes | Yes |
| 4 | No | No | No | Yes | Yes | Yes |
| 5 | No | No | Yes | Limited | No | Yes |
| 6 | No | No | Yes | No | No | Yes |
| 7 | No | No | No | Limited | No | Limited |
| 8 | No | No | No | No | No | Limited |
| 9 | No | No | No | No | No | No |
Transfer Security Functions
Transfer security functions are located in two places for a token contract - the token contract itself and the transfer validator contract that the token contract has set as its transfer validator.
Token Contract Functions
The functions in this section are implemented in the token contract.
setTransferValidator
Callable by the token contract owner or any account that is assigned the default admin role to set the transfer validator to a new address.
function setTransferValidator(address transferValidator_) public;
Transfer Validator Functions
The functions in this section are implemented in the transfer validator used by the token contract.
createList
Callable by any user to create a new list.
function createList(string calldata name) public returns (uint120);
createListCopy
Callable by any user to create a new list copied from an existing list.
function createListCopy(string calldata name, uint120 sourceListId) external returns (uint120);
reassignOwnershipOfList
Callable by the owner of a list to transfer ownership of the list to a new owner.
function reassignOwnershipOfList(uint120 id, address newOwner) public;
renounceOwnershipOfList
Callable by the owner of a list to renounce ownership of the list and prevent further changes.
function renounceOwnershipOfList(uint120 id) public;
addAccountsToBlacklist
Callable by the owner of a list to add the specified accounts to the list's blacklist.
function addAccountsToBlacklist(
uint120 id,
address[] calldata accounts
) external;
addAccountsToWhitelist
Callable by the owner of a list to add the specified accounts to the list's whitelist.
function addAccountsToWhitelist(
uint120 id,
address[] calldata accounts
) external;
addCodeHashesToBlacklist
Callable by the owner of a list to add the specified code hashes to the list's blacklist.
function addCodeHashesToBlacklist(
uint120 id,
bytes32[] calldata codehashes
) external;
addCodeHashesToWhitelist
Callable by the owner of a list to add the specified code hashes to the list's whitelist.
function addCodeHashesToWhitelist(
uint120 id,
bytes32[] calldata codehashes
) external;
addAccountsToAuthorizers
Callable by the owner of a list to add the specified authorizers to the list's approved authorizer addresses.
function addAccountsToAuthorizers(
uint120 id,
address[] calldata accounts
) external
removeAccountsFromBlacklist
Callable by the owner of a list to remove the specified accounts from the list's blacklist.
function removeAccountsFromBlacklist(
uint120 id,
address[] calldata accounts
) external;
removeAccountsFromWhitelist
Callable by the owner of a list to remove the specified accounts from the list's whitelist.
function removeAccountsFromWhitelist(
uint120 id,
address[] calldata accounts
) external;
removeCodeHashesFromBlacklist
Callable by the owner of a list to remove the specified code hashes from the list's blacklist.
function removeCodeHashesFromBlacklist(
uint120 id,
bytes32[] calldata codehashes
) external;
removeCodeHashesFromWhitelist
Callable by the owner of a list to remove the specified code hashes from the list's whitelist.
function removeCodeHashesFromWhitelist(
uint120 id,
bytes32[] calldata codehashes
) external;
removeAccountsFromAuthorizers
Callable by the owner of a list to remove the specified authorizers from the list's approved authorizer addresses.
function removeAccountsFromAuthorizers(
uint120 id,
address[] calldata accounts
) external
setTransferSecurityLevelOfCollection
Callable by the token contract, owner of the token contract or any account that has been assigned the default admin role for the token contract to set the token's transfer security level. The caller can also define authorizers, set if authorizers can enable wildcard allowances and enable freezing of accounts.
function setTransferSecurityLevelOfCollection(
address collection,
TransferSecurityLevels level,
bool enableAuthorizationMode,
bool authorizersCanSetWildcardOperators,
bool enableAccountFreezingMode
) external;
applyListToCollection
Callable by the token contract, owner of the token contract or any account that has been assigned the default admin role for the token contract to set the list to use when applying whitelist/blacklist transfer restrictions.
function applyListToCollection(address collection, uint120 id) public;
freezeAccountsForCollection
Callable by the token contract, owner of the token contract or any account that has been assigned the default admin role for the token contract to freeze transferability for a specific set of addresses.
function freezeAccountsForCollection(address collection, address[] calldata accountsToFreeze) public;
unfreezeAccountsForCollection
Callable by the token contract, owner of the token contract or any account that has been assigned the default admin role for the token contract to remove transfer restrictions from a specific set of addresses.
function unfreezeAccountsForCollection(address collection, address[] calldata accountsToUnfreeze) public;
