ERC-2009: 合规性服务
Authors | Daniel Lehrner <daniel@io.builders> |
---|---|
Created | 2019-05-09 |
Discussion Link | https://github.com/ethereum/EIPs/issues/2022 |
Requires | EIP-1066 |
简单概要
本EIP提出了一个用于受监管代币的去中心化合规性检查服务。
参与者
操作员
一个已被代币批准更新代币累计值的帐户。
代币
一个帐户,通常是一个智能合约,它使用Compliance Service
来检查某个操作是否可以执行。
代币持有者
一个拥有代币并对其进行检查的帐户。
摘要
受监管的代币需要符合若干法律规定,特别是KYC和AML。如果必要的检查必须在链下进行,则代币转移将变得中心化。此外,在这种情况下,转移需要更长的时间才能完成,因为它不能在一个交易中完成,而是需要第二个确认步骤。本提案的目标是通过提供合规性检查服务来使第二个步骤变得不必要。
动机
目前还没有关于如何完成去中心化合规性检查的提案。ERC-1462提出了一个基本的功能集,用于检查用户是否允许transfer
、mint
和burn
,但没有说明如何实现这些检查。本EIP提出了一种完全在链上实现它们的方法,同时足够通用,可以将检查的实际实现留给实现者,因为这些检查在不同的代币之间可能会有很大差异。
拟议的Compliance Service
支持多个代币。因此,它可以被立法者用来在一个智能合约中维护受监管代币的合规性规则。所有属于该管辖范围的代币都可以使用这个智能合约,并确保符合现行法律。
通过制定合规性检查标准,第三方开发人员可以使用它们来验证特定帐户的代币移动是否被允许,并采取相应的行动。
规范
interface CompliantService {
function checkTransferAllowed(bytes32 tokenId, address from, address to, uint256 value) external view returns (byte);
function checkTransferFromAllowed(bytes32 tokenId, address sender, address from, address to, uint256 value) external view returns (byte);
function checkMintAllowed(bytes32 tokenId, address to, uint256 value) external view returns (byte);
function checkBurnAllowed(bytes32 tokenId, address from, uint256 value) external view returns (byte);
function updateTransferAccumulated(bytes32 tokenId, address from, address to, uint256 value) external;
function updateMintAccumulated(bytes32 tokenId, address to, uint256 value) external;
function updateBurnAccumulated(bytes32 tokenId, address from, uint256 value) external;
function addToken(bytes32 tokenId, address token) external;
function replaceToken(bytes32 tokenId, address token) external;
function removeToken(bytes32 tokenId) external;
function isToken(address token) external view returns (bool);
function getTokenId(address token) external view returns (bytes32);
function authorizeAccumulatedOperator(address operator) external returns (bool);
function revokeAccumulatedOperator(address operator) external returns (bool);
function isAccumulatedOperatorFor(address operator, bytes32 tokenId) external view returns (bool);
event TokenAdded(bytes32 indexed tokenId, address indexed token);
event TokenReplaced(bytes32 indexed tokenId, address indexed previousAddress, address indexed newAddress);
event TokenRemoved(bytes32 indexed tokenId);
event AuthorizedAccumulatedOperator(address indexed operator, bytes32 indexed tokenId);
event RevokedAccumulatedOperator(address indexed operator, bytes32 indexed tokenId);
}
强制检查
这些检查必须在其相应的操作中进行验证。只有当检查返回Allowed
状态代码时,该操作才能成功。在任何其他情况下,函数必须恢复。
状态代码
如果允许执行某个操作,则必须返回0x11
(允许)或具有等效但更精确含义的发行者特定代码。如果该操作不被允许,则状态必须为0x10
(不允许)或具有等效但更精确含义的发行者特定代码。
函数
checkTransferAllowed
检查是否允许使用给定的参数执行transfer
函数。
参数 | 描述 |
---|---|
tokenId | 唯一标识代币的ID |
from | 付款人的地址,如果执行,将从此地址取出代币 |
to | 收款人的地址,如果执行,代币将被转移到此地址 |
value | 要转移的金额 |
checkTransferFromAllowed
检查是否允许使用给定的参数执行transferFrom
函数。
参数 | 描述 |
---|---|
tokenId | 唯一标识代币的ID |
sender | 发起交易的发件人地址 |
from | 付款人的地址,如果执行,将从此地址取出代币 |
to | 收款人的地址,如果执行,代币将被转移到此地址 |
value | 要转移的金额 |
checkMintAllowed
检查是否允许使用给定的参数执行mint
函数。
参数 | 描述 |
---|---|
tokenId | 唯一标识代币的ID |
to | 收款人的地址,如果执行,代币将被赋予此地址 |
value | 要铸造的数量 |
checkBurnAllowed
检查是否允许使用给定的参数执行burn
函数。
参数 | 描述 |
---|---|
tokenId | 唯一标识代币的ID |
from | 付款人的地址,如果执行,将从此地址取出代币 |
value | 要销毁的数量 |
updateTransferAccumulated
必须与transfer
或transferFrom
在同一交易中调用。如果更新违反任何合规性规则,则必须恢复。具体在函数中执行哪些逻辑由实现者决定。
参数 | 描述 |
---|---|
tokenId | 唯一标识代币的ID |
from | 付款人的地址,如果执行,将从此地址取出代币 |
to | 收款人的地址,如果执行,代币将被转移到此地址 |
value | 要转移的金额 |
updateMintAccumulated
必须与mint
在同一交易中调用。如果更新违反任何合规性规则,则必须恢复。具体在函数中执行哪些逻辑由实现者决定。
参数 | 描述 |
---|---|
tokenId | 唯一标识代币的ID |
to | 收款人的地址,如果执行,代币将被赋予此地址 |
value | 要铸造的数量 |
updateBurnAccumulated
必须与burn
在同一交易中调用。如果更新违反任何合规性规则,则必须恢复。具体在函数中执行哪些逻辑由实现者决定。
参数 | 描述 |
---|---|
tokenId | 唯一标识代币的ID |
from | 付款人的地址,如果执行,将从此地址取出代币 |
value | 要销毁的数量 |
addToken
将代币添加到服务中,允许该代币调用函数来更新累计值。如果使用了现有的代币ID,则函数必须恢复。添加代币是否应该受到限制由实现者决定。
参数 | 描述 |
---|---|
tokenId | 唯一标识代币的ID |
token | 将从中调用更新函数的地址 |
replaceToken
用另一个地址替换已添加代币的地址。替换代币是否应该受到限制由实现者决定,但代币应该能够替换自己的地址。
参数 | 描述 |
---|---|
tokenId | 唯一标识代币的ID |
token | 将从中调用更新函数的地址 |
removeToken
从服务中删除代币,这会禁止该代币调用函数来更新累计值。删除代币是否应该受到限制由实现者决定。
参数 | 描述 |
---|---|
tokenId | 唯一标识代币的ID |
isToken
如果该地址已添加到服务中,则返回true
,否则返回false
。
参数 | 描述 |
---|---|
token | 应检查的地址 |
getTokenId
返回代币的代币ID。如果该代币尚未添加到服务中,则必须返回“0”。
参数 | 描述 |
---|---|
token | 应返回代币ID的地址 |
authorizeAccumulatedOperator
批准一个操作员代表msg.sender
的代币ID更新累计值。
参数 | 描述 |
---|---|
operator | 要批准为累计更新操作员的地址 |
revokeAccumulatedOperator
撤销代表msg.sender
的代币ID更新累计值的批准。
参数 | 描述 |
---|---|
operator | 要撤销作为累计更新操作员的地址 |
isAccumulatedOperatorFor
检索操作员是否被批准代表tokenId
创建持有。
参数 | 描述 |
---|---|
operator | 作为更新累计值的操作员的地址 |
tokenId | 唯一标识代币的ID |
事件
TokenAdded
必须在添加代币后发出。
参数 | 描述 |
---|---|
tokenId | 唯一标识代币的ID |
token | 将从中调用更新函数的地址 |
TokenReplaced
必须在替换代币地址后发出。
参数 | 描述 |
---|---|
tokenId | 唯一标识代币的ID |
previousAddress | 以前使用的地址 |
newAddress | 从现在开始将使用的地址 |
TokenRemoved
必须在删除代币后发出。
参数 | 描述 |
---|---|
tokenId | 唯一标识代币的ID |
AuthorizedAccumulatedOperator
当操作员被批准代表代币更新累计值时发出。
参数 | 描述 |
---|---|
operator | 作为更新累计值的操作员的地址 |
tokenId | 可能代表其进行累计更新的代币ID |
RevokedHoldOperator
当操作员被撤销代表代币更新累计值时发出。
参数 | 描述 |
---|---|
operator | 作为更新累计值的操作员的地址 |
tokenId | 可能代表其进行累计更新的代币ID |
理由
选择使用代币ID而不是地址是为了让代币能够更新其智能合约并保留所有相关的累计值。如果使用地址,则在智能合约更新后需要完成迁移过程。
更新累计值后不会发出任何事件,因为这些事件始终与代币的transfer
、mint
或burn
相关联,后者已经发出其自身的事件。
虽然没有要求,但函数checkTransferAllowed
、checkTransferFromAllowed
、checkMintAllowed
和checkBurnAllowed
的命名是从ERC-1462采用的。
虽然没有要求,但函数authorizeAccumulatedOperator
、revokeAccumulatedOperator
和isAccumulatedOperatorFor
的命名遵循ERC-777的命名约定。
本地化不是本EIP的一部分,但ERC-1066和ERC-1444可以一起使用来实现它。
向后兼容性
由于EIP未使用任何现有的EIP,因此无需考虑任何向后兼容性。
实现
GitHub仓库IoBuilders/compliance-service包含正在进行中的实现。
贡献者
本提案由adhara.io和io.builders合作实施。
版权
版权及相关权利通过CC0放弃。
Citation
Please cite this document as:
Daniel Lehrner <daniel@io.builders>, "ERC-2009: 合规性服务 [DRAFT]," Ethereum Improvement Proposals, no. 2009, May 2019. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-2009.