Alert Source Discuss
🚧 Stagnant Standards Track: ERC

ERC-884: DGCL Token

Authors Dave Sag <davesag@gmail.com>
Created 2018-02-14

兼容特拉华州通用公司法 (DGCL) 的股份代币

参考: proposing-an-eip-for-DGCL-tokens

简单总结

一种与 ERC-20 兼容的代币,该代币符合 特拉华州参议院,第149届大会,参议院第69号法案:修订特拉华州法典第8章关于通用公司法的法案,以下简称“该法案”。

摘要

最近修订的“特拉华州法典第8章关于通用公司法的规定”现在明确允许使用区块链来维护公司股份登记册。这意味着现在可以创建一个可交易的 ERC-20 代币,其中每个代币代表特拉华州公司发行的股份。此类代币必须符合以下原则,并高于 ERC-20 标准。

  1. 代币所有者必须验证其身份。
  2. 代币合约必须提供 公司股票分类账 的以下三个功能(参考:该法案第224条):

    1. 报告:

      它必须使公司能够编制该法案第219和220条中规定的股东名单。

    2. 它必须记录该法案第156、159、217(a)和218条中规定的信息:

      • 部分支付股份
      • 已付总额
      • 待付总额
    3. 根据该法案第159条进行的股份转让:

      它必须记录《第6条》第一部分第8条管辖的股份转让。

  3. 每个代币必须对应于单股股票,每股股份都将全额支付,因此无需记录有关部分支付股份的信息,也没有部分代币。

  4. 必须有一种机制,允许丢失了私钥或以其他方式失去对其代币访问权限的股东将其地址取消,并将代币重新发行到新地址。

动机

  1. 特拉华州通用公司法要求特拉华州公司发行的股份必须记录在股份登记册中。
  2. 股份登记册可以由符合特拉华州通用公司法的 ERC-20 代币合约表示。
  3. 该标准可以涵盖任何特拉华州公司(无论是私营还是上市公司)发行的股权。

通过使用与 DGCL 兼容的代币,公司可以通过首次公开募股筹集资金,符合特拉华州公司法,但无需传统证券交易所的参与。

目前没有符合 DGCL 规则的代币标准。ERC-20 代币不支持通用公司法要求的 KYC/AML 规则,并且不提供导出股东名单的工具。

ERC-721怎么样?

拟议的标准可以轻松用于增强 ERC-721,从而增加将代币与股份证明等资产相关联的功能。

虽然 ERC-721 代币提案允许将一些元数据与以太坊地址相关联,但其用途与该法案_并非完全一致_,并且目前的形式不能完全与 ERC-20 兼容。

规范

ERC-20 代币提供以下基本功能:

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);
}

这将按如下方式扩展:

/**
 * 一种与 `ERC20` 兼容的代币,该代币符合特拉华州参议院,
 * 第149届大会,参议院第69号法案:修订特拉华州法典第8章
 * 关于通用公司法的法案。
 *
 * 实施细节。
 *
 * 此代币标准的实现应提供以下内容:
 *
 * `name` - 供钱包和交易所使用。
 * `symbol` - 供钱包和交易所使用。
 *
 * 该实现必须注意不要允许未经授权访问
 * 股份转让功能。
 *
 * 除了上述内容外,还必须定义以下可选的 `ERC20` 函数。
 *
 * `decimals` - 必须返回 `0`,因为每个代币代表单股,并且股份不可分割。
 *
 * @dev 参考 https://github.com/ethereum/EIPs/pull/884
 */
contract ERC884 is ERC20 {

    /**
     * 当验证的地址和关联的身份哈希添加到合约时,会发出此事件。
     * @param addr 添加的地址。
     * @param hash 与该地址关联的身份哈希。
     * @param sender 导致添加该地址的地址。
     */
    event VerifiedAddressAdded(
        address indexed addr,
        bytes32 hash,
        address indexed sender
    );

    /**
     * 从合约中删除经过验证的地址和关联的身份哈希时,会发出此事件。
     * @param addr 删除的地址。
     * @param sender 导致删除该地址的地址。
     */
    event VerifiedAddressRemoved(address indexed addr, address indexed sender);

    /**
     * 当与经过验证的地址关联的身份哈希更新时,会发出此事件。
     * @param addr 其哈希已更新的地址。
     * @param oldHash 与该地址关联的身份哈希。
     * @param hash 现在与该地址关联的哈希。
     * @param sender 导致哈希更新的地址。
     */
    event VerifiedAddressUpdated(
        address indexed addr,
        bytes32 oldHash,
        bytes32 hash,
        address indexed sender
    );

    /**
     * 当地址被取消并替换为新地址时,会发出此事件。
     * 这种情况发生在股东丢失了对其原始地址的访问权限并且需要将其股份重新发行到新地址的情况下。
     * 这相当于发行替换股份证明。
     * @param original 被取代的地址。
     * @param replacement 新地址。
     * @param sender 导致地址被取代的地址。
     */
    event VerifiedAddressSuperseded(
        address indexed original,
        address indexed replacement,
        address indexed sender
    );

    /**
     * 向合约添加经过验证的地址以及关联的验证哈希。
     * 成功添加经过验证的地址后,合约必须发出`VerifiedAddressAdded(addr, hash, msg.sender)`。
     * 如果提供的地址或哈希为零,或者如果该地址已提供,则必须抛出错误。
     * @param addr 由提供的哈希表示的人员的地址。
     * @param hash 地址持有者经过验证的信息的加密哈希。
     */
    function addVerified(address addr, bytes32 hash) public;

    /**
     * 删除经过验证的地址和关联的验证哈希。 如果合约不知道该地址,则此操作不执行任何操作。
     * 如果成功删除该地址,则此函数必须发出`VerifiedAddressRemoved(addr, msg.sender)`。
     * 如果尝试删除拥有代币的 verifiedAddress,则必须抛出错误。
     * @param addr 要删除的经过验证的地址。
     */
    function removeVerified(address addr) public;

    /**
     * 更新合约已知的经过验证的地址的哈希。
     * 成功更新经过验证的地址后,合约必须发出
     * `VerifiedAddressUpdated(addr, oldHash, hash, msg.sender)`。
     * 如果哈希与已存储的值相同,则
     * 不会发出任何`VerifiedAddressUpdated`事件。
     * 如果哈希为零,或者地址未经验证,则必须抛出错误。
     * @param addr 由提供的哈希表示的人员的经过验证的地址。
     * @param hash 地址持有者更新后的经过验证的信息的新加密哈希。
     */
    function updateVerified(address addr, bytes32 hash) public;

    /**
     * 取消原始地址并将代币重新发行到替换地址。
     * 必须严格控制对此功能的访问。
     * 必须从经过验证的地址集中删除`original`地址。
     * 如果提供的`original`地址不是股东,则抛出错误。
     * 如果`replacement`地址不是经过验证的地址,则抛出错误。
     * 如果`replacement`地址已持有代币,则抛出错误。
     * 此函数必须发出`VerifiedAddressSuperseded`事件。
     * @param original 要被取代的地址。 此地址不得重复使用。
     */
    function cancelAndReissue(address original, address replacement) public;

    /**
     * `transfer`函数不得允许转移到未经验证并添加到合约的地址。
     * 如果`to`地址当前不是股东,则必须成为股东。
     * 如果转账会将`msg.sender`的余额减少到0,则必须从股东列表中删除该地址。
     */
    function transfer(address to, uint256 value) public returns (bool);

    /**
     * `transferFrom`函数不得允许转移到未经验证并添加到合约的地址。
     * 如果`to`地址当前不是股东,则必须成为股东。
     * 如果转账会将`from`的余额减少到0,则必须从股东列表中删除该地址。
     */
    function transferFrom(address from, address to, uint256 value) public returns (bool);

    /**
     * 测试提供的地址是否为合约所知。
     * @param addr 要测试的地址。
     * @return 如果合约知道该地址,则为true。
     */
    function isVerified(address addr) public view returns (bool);

    /**
     * 检查提供的地址是否为股东。
     * @param addr 要检查的地址。
     * @return 如果提供的地址拥有代币,则为true。
     */
    function isHolder(address addr) public view returns (bool);

    /**
     * 检查提供的哈希是否与给定的地址关联。
     * @param addr 要测试的地址。
     * @param hash 要测试的哈希。
     * @return 如果哈希与`addVerified`或`updateVerified`中提供的地址匹配,则为true。
     */
    function hasHash(address addr, bytes32 hash) public view returns (bool);

    /**
     * 持有代币的地址数。
     * @return 持有代币的唯一地址数。
     */
    function holderCount() public view returns (uint);

    /**
     * 通过使用`holderCount`计算代币持有者的数量
     * 您可以一次检索完整的代币持有者列表。
     * 如果`index >= holderCount()`,则必须抛出错误。
     * @param index 持有者的从零开始的索引。
     * @return 具有给定索引的代币持有者的地址。
     */
    function holderAt(uint256 index) public view returns (address);

    /**
     * 检查提供的地址是否被取代。
     * @param addr 要检查的地址。
     * @return 如果提供的地址被另一个地址取代,则为true。
     */
    function isSuperseded(address addr) public view returns (bool);

    /**
     * 获取给定被取代地址的最新地址。
     * 地址可能被多次取代,因此此函数需要
     * 跟踪地址链,直到到达最终的经过验证的地址。
     * @param addr 被取代的地址。
     * @return 最终持有股份且经过验证的地址。
     */
    function getCurrentFor(address addr) public view returns (address);
}

证券交易委员会要求

美国证券交易委员会 (SEC) 对如何运行众筹以及必须向公众提供哪些信息有其他要求。 但是,这些信息超出了本标准的范围,尽管该标准确实支持这些要求。

例如:美国证券交易委员会要求众筹的网站以美元显示筹集的资金额。为了支持这一点,铸造这些代币的众筹合约必须维护美元到 ETH 的转换率(通过 Oracle 或其他机制),并且必须记录铸造时使用的转换率。

此外,根据筹集资金的类型,美国证券交易委员会(或其他法定机构)可以对允许的股东数量施加限制。为了支持这一点,该标准提供了 holderCountisHolder 函数,众筹可以调用这些函数来检查是否超过了限制。

使用身份 hash

为了符合该法案,众筹的实施者必须能够生成一份最新的所有股东姓名和地址列表。出于隐私和经济原因,不希望在公共区块链中包含这些详细信息。强烈建议不要在区块链上存储任意字符串数据。

实施者应维护一个链下私有数据库,记录所有者的姓名、居住地址和以太坊地址。然后,实施者必须能够提取任何地址的姓名和地址,并对姓名+地址数据进行哈希处理,并将该哈希与使用 hasHash 函数记录在合约中的哈希进行比较。此系统的具体细节留给实施者。

还希望实施者提供一个 REST API 端点,其格式如下

GET https://<host>/<pathPrefix>/:ethereumAddress -> [true|false]

为了使第三方审核员能够验证给定的以太坊地址是否被实施者识别为经过验证的地址。

实施者如何验证一个人的身份取决于他们,并且超出了本标准的范围。

处理失去对其地址访问权限的用户

传统的股份登记册通常由转移代理人管理,该代理人被授权准确地维护登记册并处理股东查询。一个常见的请求是在股东丢失或销毁其原始股票证明的情况下重新发行股票证明。

代币实施者可以通过 cancelAndReissue 函数来处理这种情况,该函数必须执行各种更改,以确保旧地址现在指向新地址,并且已取消的地址不会被重复使用。

权限管理

不希望任何人都可以添加、删除、更新或取代经过验证的地址。如何控制对这些功能的访问超出了本标准的范围。

理由

拟议的标准提供了对现有 ERC-20 标准的尽可能小的扩展,以符合该法案的要求。 我们没有为 addVerifiedremoveVerifiedupdateVerified 等状态更改函数的成功或不成功完成返回一个 bool 值,而是选择要求实现 抛出 错误(最好使用 即将发布的 require(condition, 'fail message') 语法)。

向后兼容性

拟议的标准旨在保持与 ERC-20 代币的兼容性,但有以下规定:

  1. decimals 函数必须返回 0,因为代币不得可分割,
  2. transfertransferFrom 函数必须不允许转账到未经验证的地址,并且必须维护股东列表。
  3. 将其剩余代币转让出去的股东必须从股东列表中删除。

规定 1 不会破坏与现代钱包或交易所的兼容性,因为如果可用,它们似乎都使用该信息。

如果尝试将代币转移到未经验证的地址,规定 2 将导致转账失败。这在设计中是隐含的,并且鼓励实施者向市场参与者明确这一点。 我们意识到这将使该标准对某些交易所不合口味,但美国证券交易委员会 (SEC) 要求公司股东提供经过验证的姓名和地址。

规定 3 是一个实施细节。

测试用例和参考实现

测试用例和参考实现可在 github.com/davesag/ERC884-reference-implementation 找到。

版权

版权和相关权利通过 CC0 放弃。

Citation

Please cite this document as:

Dave Sag <davesag@gmail.com>, "ERC-884: DGCL Token [DRAFT]," Ethereum Improvement Proposals, no. 884, February 2018. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-884.