Alert Source Discuss
🚧 Stagnant Standards Track: ERC

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来检查某个操作是否可以执行。

代币持有者

一个拥有代币并对其进行检查的帐户。

摘要

受监管的代币需要符合若干法律规定,特别是KYCAML。如果必要的检查必须在链下进行,则代币转移将变得中心化。此外,在这种情况下,转移需要更长的时间才能完成,因为它不能在一个交易中完成,而是需要第二个确认步骤。本提案的目标是通过提供合规性检查服务来使第二个步骤变得不必要。

动机

目前还没有关于如何完成去中心化合规性检查的提案。ERC-1462提出了一个基本的功能集,用于检查用户是否允许transfermintburn,但没有说明如何实现这些检查。本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

必须与transfertransferFrom在同一交易中调用。如果更新违反任何合规性规则,则必须恢复。具体在函数中执行哪些逻辑由实现者决定。

参数 描述
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而不是地址是为了让代币能够更新其智能合约并保留所有相关的累计值。如果使用地址,则在智能合约更新后需要完成迁移过程。

更新累计值后不会发出任何事件,因为这些事件始终与代币的transfermintburn相关联,后者已经发出其自身的事件。

虽然没有要求,但函数checkTransferAllowedcheckTransferFromAllowedcheckMintAllowedcheckBurnAllowed的命名是从ERC-1462采用的。

虽然没有要求,但函数authorizeAccumulatedOperatorrevokeAccumulatedOperatorisAccumulatedOperatorFor的命名遵循ERC-777的命名约定。

本地化不是本EIP的一部分,但ERC-1066ERC-1444可以一起使用来实现它。

向后兼容性

由于EIP未使用任何现有的EIP,因此无需考虑任何向后兼容性。

实现

GitHub仓库IoBuilders/compliance-service包含正在进行中的实现。

贡献者

本提案由adhara.ioio.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.