Alert Source Discuss
🚧 Stagnant Standards Track: ERC

ERC-1592: 地址和符合 ERC20 标准的转账规则

Authors Cyril Lapinte <cyril.lapinte@mtpelerin.com>, Laurent Aapro <laurent.aapro@mtpelerin.com>
Created 2018-11-09
Discussion Link https://github.com/ethereum/EIPs/issues/1597

简单概括

我们提出了一个标准和一个接口来定义转账规则,在 ERC20 代币的背景下,甚至可能超出这个范围。

一个规则可以基于发送者、接收者和金额进行操作,并根据任何所需的业务逻辑触发(并拒绝转账)。

为了方便规则的重用和组合,我们还为规则引擎提出了一个接口和基础实现。

摘要

本标准提案应解决以下挑战:

  • 实现规则与交互平台(如交易所、去中心化钱包和 DApp)的集成。
  • 外部化代码和存储,全面提高可重用性、gas 成本和合约的内存占用。
  • 突出合约行为及其演变,以便简化用户与此类合约的交互。

如果这些挑战得到解决,该提案将为转账规则提供统一的基础,并有望满足其他 EIP 的转账限制需求,例如 EIP-902, EIP-1066EIP-1175

本文档提出了 转账规则 标准的规范以及规则和规则引擎的接口,该引擎旨在被代币继承,但在作者看来,它可能具有更广泛的范围。

本文档的最后一节通过一个规则模板和指向规则实现的链接来说明该提案。

动机

ERC20 被设计为一个标准接口,允许以太坊上的任何代币被其他应用程序处理:从钱包到去中心化交易所。这非常强大,但代币化行业的未来发展带来了新的挑战。例如,已经很难确切知道 ERC20 转账失败的原因,当许多代币将自己的转账规则添加到组合中时,将会变得更加困难;我们建议,在发送交易之前,应该很容易确定转账是否有效,以及原因(除非在此期间条件发生变化)。另一方面,如果规则发生变化,也应该很容易检测到,以便交互方知道它必须调整其预期或模型。

规范

我们在下面定义了一个规则的接口。规则旨在尽可能简单,以限制 gas 支出,因为该逻辑将在每次转账时执行。保持规则简单和简短的另一个原因是,尽可能追求原子性,以便于被拒绝转账的组合和解释。通过了解触发了哪个规则,我们可以清楚地了解拒绝的原因。

我们提出的引擎在每次转账时都会执行其所有者定义的所有规则,并且很容易单独添加和删除规则,尽管我们选择使用相当原始的规则更新方法,以节省部署成本,在代币智能合约方面,部署成本通常很紧张。

规则作为单独的智能合约部署在区块链上,并由它们所附加的规则引擎调用。但是任何第三方,例如交易所为客户准备提现,都可以非常廉价地查询代币的规则引擎,或者直接查询单个规则,以在执行之前验证转账的有效性,从而永远不会收到被拒绝的交易。

规则接口

IRule 接口应提供一种验证地址或转账是否有效的方法。

如果这两种方法中的任何一种不适用,则可以简单地使其有条不紊地返回 true。 如果 isTransferValid 的任何参数不需要,则应使用 /* */ 注释掉其名称。

pragma solidity ^0.4.25;

interface IRule {
  function isAddressValid(address _address) external view returns (bool);
  function isTransferValid(address _from, address _to, uint256 _amount)
    external view returns (bool);
}

WithRules 接口

WithRules 接口描述了规则与规则引擎的集成。 如果开发人员的代码仅处理一个规则,或者不希望更新规则,则可以选择不实现此接口。

必须仔细考虑规则的排序。 应首先放置验证成本较低或更有可能中断的规则,以降低全局 gas 支出,然后业务逻辑应指导规则的排序。这就是为什么给定上下文的规则应作为一个整体而不是单独定义的原因。

pragma solidity ^0.4.25;

import "./IRule.sol";

interface IWithRules {
  function ruleLength() public view returns (uint256);
  function rule(uint256 _ruleId) public view returns (IRule);
  function validateAddress(address _address) public view returns (bool);
  function validateTransfer(address _from, address _to, uint256 _amount)
    public view returns (bool);

  function defineRules(IRule[] _rules) public;

  event RulesDefined(uint256 count);
}

WithRules 实现

我们还提出了规则引擎的简单实现,可在此处获得 here。它已被保持在最低限度,既可以节省每次转账的 gas 成本,又可以降低派生智能合约的部署成本开销。

除了实现上面的接口之外,该引擎还定义了两个修饰符(whenAddressRulesAreValidwhenTransferRulesAreValid),可以在整个代币合约中使用它们来限制 transfer()transferFrom 和任何其他需要遵守简单白名单或复杂转账规则的函数。

集成

在代币中使用规则就像让代币从 WithRules 继承一样简单,然后根据 IRule 接口编写规则并单独部署每个规则。然后,代币所有者可以使用 defineRules() 在单个交易中按选择的顺序附加所有规则。

下面是规则的模板。

import "../interface/IRule.sol";

contract TemplateRule is IRule {
  
  // state vars for business logic
  // 用于业务逻辑的状态变量

  constructor(/* arguments for init */) public {

    // initializations
    // 初始化

  }

  function isAddressValid(address _from) public view returns (bool) {
    boolean isValid;

    // business logic 
    // 业务逻辑

    return isValid;
  }

  function isTransferValid(
    address _from,
    address _to,
    uint256 _amount)
    public view returns (bool)
  {
    boolean isValid;

    // business logic 
    // 业务逻辑

    return isValid;
  }
}

** 备注 ** MPS(Mt Pelerin 的股份)代币是该标准的当前实时实现。 可以使用不同的权衡来编写其他实现:从节省 gas 到提高安全性。

规则实现示例

  • YesNo rule: 用于演示规则和规则引擎的简单规则。

  • Freeze rule: 此规则允许阻止代币转移到或从选定的地址。一个智能黑名单。

  • Lock rule: 定义一个全局转账策略,在一段时间内阻止发送或接收代币。代币管理员可以向某些地址授予例外。一个智能白名单。

  • User Kyc Rule: 依赖于现有白名单以断言转账和地址有效性的规则示例。这是一个完全外部化其任务的规则的一个很好的例子。

示例实现位于

历史

与此标准相关的历史链接:

  • Mt Pelerin 发行的第一个受监管的代币化股份(MPS 代币)使用的是该提案的早期版本:https://www.mtpelerin.com/blog/world-first-tokenized-shares 在代币发行期间和代币销售期间,规则引擎多次更新,以匹配不断变化的业务和法律要求,展示了规则引擎的稳健性和灵活性。

版权

版权和相关权利通过 CC0 放弃。 此存储库之外的外部引用将具有其自己的特定版权。

Citation

Please cite this document as:

Cyril Lapinte <cyril.lapinte@mtpelerin.com>, Laurent Aapro <laurent.aapro@mtpelerin.com>, "ERC-1592: 地址和符合 ERC20 标准的转账规则 [DRAFT]," Ethereum Improvement Proposals, no. 1592, November 2018. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-1592.