Appearance
Simple Summary ​
An extension to ERC-20 standard token that provides compliance with securities regulations and legal enforceability.
Abstract ​
This EIP defines a minimal set of additions to the default token standard such as ERC-20, that allows for compliance with domestic and international legal requirements. Such requirements include KYC (Know Your Customer) and AML (Anti Money Laundering) regulations, and the ability to lock tokens for an account, and restrict them from transfer due to a legal dispute. Also the ability to attach additional legal documentation, in order to set up a dual-binding relationship between the token and off-chain legal entities.
The scope of this standard is being kept as narrow as possible to avoid restricting potential use-cases of this base security token. Any additional functionality and limitations not defined in this standard may be enforced on per-project basis.
Motivation ​
There are several security token standards that have been proposed recently. Examples include ERC-1400, also ERC-1450. We have concerns about each of them, mostly because the scope of each of these EIPs contains many project-specific or market-specific details. Since many EIPs are coming from the respective backing companies, they capture many niche requirements that are excessive for a general case.
For instance, ERC-1411 uses dependency on ERC-1410 but it falls out of the "security tokens" scope. Also its dependency on ERC-777 will block the adoption for a quite period of time before ERC-777 is finalized, but the integration guidelines for existing ERC-20 workflows are not described in that EIP, yet. Another attempt to make a much simpler base standard ERC-1404 is missing a few important points, specifically it doesn't provide enough granularity to distinguish between different ERC-20 transfer functions such as transfer
and transferFrom
. It also doesn't provide a way to bind legal documentation to the issued tokens.
What we propose in this EIP is a simple and very modular solution for creating a base security token for the widest possible scope of applications, so it can be used by other issuers to build upon. The issuers should be able to add more restrictions and policies to the token, using the functions and implementation proposed below, but they must not be limited in any way while using this ERC.
Specification ​
The ERC-20 token provides the following basic features:
solidity
contract ERC20 {
function totalSupply() public view returns (uint256);
function balanceOf(address who) public view returns (uint256);
function transfer(address to, uint256 value) public returns (bool);
function allowance(address owner, address spender) public view returns (uint256);
function transferFrom(address from, address to, uint256 value) public returns (bool);
function approve(address spender, uint256 value) public returns (bool);
event Approval(address indexed owner, address indexed spender, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 value);
}
This will be extended as follows:
solidity
interface BaseSecurityToken /* is ERC-20 */ {
// Checking functions
function checkTransferAllowed (address from, address to, uint256 value) public view returns (byte);
function checkTransferFromAllowed (address from, address to, uint256 value) public view returns (byte);
function checkMintAllowed (address to, uint256 value) public view returns (byte);
function checkBurnAllowed (address from, uint256 value) public view returns (byte);
// Documentation functions
function attachDocument(bytes32 _name, string _uri, bytes32 _contentHash) external;
function lookupDocument(bytes32 _name) external view returns (string, bytes32);
}
Transfer Checking Functions ​
We introduce four new functions that should be used to check that the actions are allowed for the provided inputs. The implementation details of each function are left for the token issuer, it is the issuer's responsibility to add all necessary checks that will validate an operation in accordance with KYC/AML policies and legal requirements set for a specific token asset.
Each function must return a status code from the common set of Ethereum status codes (ESC), according to ERC-1066. Localization of these codes is out of the scope of this proposal and may be optionally solved by adopting ERC-1444 on the application level. If the operation is allowed by a checking function, the return status code must be 0x11
(Allowed) or an issuer-specific code with equivalent but more precise meaning. If the operation is not allowed by a checking function, the status must be 0x10
(Disallowed) or an issuer-specific code with equivalent but more precise meaning. Upon an internal error, the function must return the most relevant code from the general code table or an issuer-specific equivalent, example: 0xF0
(Off-Chain Failure).
For ERC-20 based tokens,
- It is required that transfer function must be overridden with logic that checks the corresponding checkTransferAllowed return status code.
- It is required that
transferFrom
function must be overridden with logic that checks the correspondingcheckTransferFromAllowed
return status code. - It is required that
approve
function must be overridden with logic that checks the correspondingcheckTransferFromAllowed
return status code. - Other functions such as
mint
andburn
must be overridden, if they exist in the token implementation, they should checkcheckMintAllowed
andcheckBurnAllowed
status codes accordingly.
For ERC-777 based tokens,
- It is required that
send
function must be overridden with logic that checks the corresponding return status codes:checkTransferAllowed
return status code, if transfer happens on behalf of the tokens owner;checkTransferFromAllowed
return status code, if transfer happens on behalf of an operator (i.e. delegated transfer).
- It is required that
burn
function must be overridden with logic that checks the correspondingcheckBurnAllowed
return status code. - Other functions, such as
mint
must be overridden, if they exist in the token implementation, e.g. if the security token is mintable.mint
function must callcheckMintAllowed
ad check it return status code.
For both cases,
- It is required for guaranteed compatibility with ERC-20 and ERC-777 wallets that each checking function returns
0x11
(Allowed) if not overridden with the issuer's custom logic. - It is required that all overridden checking functions must revert if the action is not allowed or an error occurred, according to the returned status code.
Inside checker functions the logic is allowed to use any feature available on-chain: perform calls to registry contracts with whitelists/blacklists, use built-in checking logic that is defined on the same contract, or even run off-chain queries through an oracle.
Documentation Functions ​
We also introduce two new functions that should be used for document management purposes. Function attachDocument
adds a reference pointing to an off-chain document, with specified name, URI and contents hash. The hashing algorithm is not specified within this standard, but the resulting hash must not be longer than 32 bytes. Function lookupDocument
gets the referenced document by its name.
- It is not required to use documentation functions, they are optional and provided as a part of a legal framework.
- It is required that if
attachDocument
function has been used, the document reference must have a unique name, overwriting the references under same name is not allowed. All implementations must check if the reference under the given name is already existing.
Rationale ​
This EIP targets both ERC-20 and ERC-777 based tokens, although the most emphasis is given to ERC-20 due to its widespread adoption. However, this extension is designed to be compatible with the forthcoming ERC-777 standard, as well.
All checking functions are named with prefixes check
since they return check status code, not booleans, because that is important to facilitate the debugging and tracing process. It is responsibility of the issuer to implement the logic that will handle the return codes appropriately. Some handlers will simply throw errors, other handlers would log information for future process mining. More rationale for status codes can be seen in ERC-1066.
We require two different transfer validation functions: checkTransferAllowed
and checkTransferFromAllowed
since the corresponding transfer
and transferFrom
are usually called in different contexts. Some token standards such as ERC-1450 explicitly disallow use of transfer
, while allowing only transferFrom
. There might be also different complex scenarios, where transfer
and transferFrom
should be treated differently. ERC-777 is relying on its own send
for transferring tokens, so it is reasonable to switch between checker functions based on its call context. We decided to omit the checkApprove
function since it would be used in exactly the same context as checkTransferFromAllowed
. In many cases it is required not only regulate securities transfers, but also restrict burn and mint
operations, and additional checker functions have been added for that.
The documentation functions that we propose here are a must-have tool to create dual-bindings with off-chain legal documents, a great example of this can be seen in Neufund's Employee Incentive Options Plan legal framework that implements full legal enforceability: the smart contract refers to printed ESOP Terms & Conditions Document, which itself refers back to smart contract. This is becoming a widely adopted practice even in cases where there are no legal requirements to reference the documents within the security token. However they're almost always required, and it's a good way to attach useful documentation of various types.
Backwards Compatibility ​
This EIP is fully backwards compatible as its implementation extends the functionality of ERC-20 and ERC-777 tokens.
Implementation ​
Copyright ​
Copyright and related rights waived via CC0.