ERC1400 – 证券型Token
该Token提案主打监管功能,目的是方便用户以合法合规方式在以太坊网络发行证券
标准说明
ERC1410 (等同ERC1411)将 ERC20/ERC777 中不存在解释属性的余额,附加额外的信息,从而划分成不同的部分,就可以做一些操作上的限制。
而 ERC1400 (等同ERC1411)是对 ERC1410 标准的继承和改进。
无论是 ERC20 还是 ERC777,每个单位的 Token 都是相同的,并无附加属性,属于 fungible token(同质化代币/可互换 Token)。ERC721标准的 Token,每个 Token 均有不同的ID,不同ID可以有不同的解释,属于 no-fungible token(非同质化 Token,不可互换 Token)。
ERC1410标准的 Token 属于Partially-Fungible Token (部分可互换 Token ),将 ERC20/ERC777 中不存在解释属性的余额,附加额外的信息,从而划分成不同的部分,就可以做一些操作上的限制(例如:某些操作只限定于指定 tranche 的 Token,某些操作优先消耗指定tranche的 Token)。
ERC1400 则是继承 ERC1410 标准,增加了证券相关业务会使用到的函数:证券增发,相关法律文件存储等。
先前一些证券型 Token 的合约大多是在 ERC20 标准的基础上,通过维护一个或多个以太坊地址集合,对这部分地址做出了划分:是否通过kyc,是否处于锁定期等,来进行转账上的限制。这些都是在地址层面做出不同的解释。而 ERC1400 对 Token 本身做了不同解释,以适用于更复杂的证券相关业务场景。
ERC20 与 ERC1400 的区别
ERC20标准: 每个单位的Token都是相同的,并无附加属性,可互换,属于fungible token。在以太坊地址层面上做监管,来限制转账。
ERC1400标准: 对余额附加额外的信息,从而划分成不同的分片,部分可互换,属于Partially-Fungible Token。对Token本身做了不同解释,可以应用于更复杂的证券业务场景。
ERC1400继承自ERC1410,接口兼容ERC20/ERC777/ERC1066
实现原理
将Token持有人的余额分离成多个分片(tranche),并由 bytes32 _tranche 键来建立索引,该键可以同链上或链下的元数据相关联。
必须实现的功能
- 随交易发送可以附带描述数据,以供某些业务场景使用 (bytes _data,bytes _operatorData,记录在event中)
- 证券增发(mint),相关法律文件存储(setDocument)
- 必须有一个标准的接口来查询一笔转账交易是否成功,失败的话则返回原因(交易函数带返回值,且可监听SentTranche事件)。
- 必须发布用于发行(Minted)和赎回(Burnt)的标准事件(合约owner才能调)。
- 必须能将一些数据附加到代币持有者余额的子集上,例如特殊股东权利或是转账限制的数据。(在struct Tranche中增加字段,或者通过tranche到链上链下找相关联的元数据)
- 可能需要将签名数据传递到转账交易中,以便于在链上验证。(bytes _data,bytes _operatorData,记录在event中)
- 必须能够强制转账以应对法律诉讼或资金回收(ForceSendTranche 合约owner才能调)。
- 必须能根据离线数据,链上数据和转账的参数在转账时修改元数据(getDefaultTranches)。
- 设置一些转账限制,如黑名单(canSend 在_sendTranche函数内对_from和_to做判断)
- 应该兼容ERC20和ERC777标准。
角色分类
- owner: address类型,合约发布者
- _owner: address类型,投资者,分片持有人
- _operator: address类型,由_owner指定的操作者,可以操作_owner拥有的指定余额分片
合约事件
-
发行时
event Minted(address indexed owner, bytes32 tranche, uint256 amount, bytes data);
-
销毁时
event Burnt(address indexed owner, bytes32 tranche, uint256 amount, bytes data);
-
转账,发行或者销毁时
event SentTranche(address indexed operator, address indexed from, address indexed to, bytes32 fromTranche, bytes32 toTranche, uint256 amount, bytes data, bytes operatorData);
-
给指定的操作者授权操作所有分片时
event AuthorizedOperator(address indexed operator, address indexed owner);
-
给指定的操作者授权操作指定分片时
event AuthorizedOperatorTranche(bytes32 indexed tranche, address indexed operator, address indexed owner);
-
取消指定的操作者操作所有分片的权限时
event RevokedOperator(address indexed operator, address indexed owner);
-
取消指定的操作者操作指定分片的权限时
event RevokedOperatorTranche(bytes32 indexed tranche, address indexed operator, address indexed owner);
状态码
兼容ERC1066标准为智能合约调用提供的一组通用的状态码
- 0x00 Failure
- 0x01 Success
- 0x10 Disallowed
- 0x20 Not Found
合约函数
兼容ERC777-地址层面
-
总余额
function balanceOf(address _owner) external view returns (uint256)
-
批准权限(授权所有分片)
function authorizeOperator(address _operator) public
function revokeOperator(address _operator) public
function isOperatorFor(address _operator, address _owner) public view returns (bool)
兼容ERC20
- function transfer(address to, uint256 value) public returns (bool);
- event Transfer(address indexed from, address indexed to, uint256 value);
- 实现方案: 遍历getDefaultTranches函数返回的tranches,直到指定数量的代币成功转账
继承ERC1410-分片层面
-
查询拥有的分片信息
function trancheByIndex(address _owner, uint256 _index) external view returns (bytes32)
function tranchesOf(address _owner) external view returns (uint256) //返回拥有的分片数量
function balanceOfTranche(bytes32 _tranche, address _owner) external view returns (uint256)
-
按分片转账
function _sendTranche(address _from, address _to, uint256 _amount, bytes32 _tranche, bytes _data, bytes _operatorData) internal returns (byte, bytes32)
function sendTranche(bytes32 _tranche, address _to, uint256 _amount, bytes _data) external returns (byte, bytes32)
function operatorSendTranche(bytes32 _tranche, address _from, address _to, uint256 _amount, bytes _data, bytes _operatorData) external returns (byte, bytes32)
function ForceSendTranche(bytes32 _tranche, address _from, address _to, uint256 _amount, bytes _data, bytes _operatorData) external returns (byte, bytes32)
-
批准权限(授权某个分片)
function authorizeOperatorTranche(bytes32 _tranche, address _operator) public
function revokeOperatorTranche(bytes32 _tranche, address _operator) public
function isOperatorForTranche(bytes32 _tranche, address _operator, address _owner) public view returns (bool)
-
增发
function mint(bytes32 _tranche, address _owner, uint256 _amount, bytes _data) public returns (byte reason)
-
销毁
function burn(bytes32 _tranche, address _owner, uint256 _amount, bytes _data) public returns (byte reason)
额外功能
-
Document Management 法律文件存储
function getDocument(bytes32 _name) external view returns (string, bytes32);
function setDocument(bytes32 _name, string _uri, bytes32 _documentHash) external; -
Transfer Validity 转账有效性验证
function canSend(address _from, address _to, bytes32 _tranche, uint256 _amount, bytes _data) external view returns (byte, bytes32, bytes32);
-
Default Tranche Management 按顺序返回持有的所有tranches
function getDefaultTranches(address _owner) external view returns (bytes32[]);
function setDefaultTranche(bytes32[] _tranches) external;