mirror of https://github.com/status-im/EIPs.git
draft EIP for a DGCL compliant Token standard. (#884)
* initial submission of draft EIP for consideration * EIP-884 correct spelling and add section on permissions management * EIP-884 added oldHash * EIP-884 changed getHash to hasHash and cleaned up grammar and spelling * EIP-884 updates to wording * EIR-884 added clarification on Delaware GCL vs Reg A+ * EIR-884 tweaks so the proposed code actually compiles * EIP-884 simplified ownerAt and added requirement that a verified address that owns tokens can not be removed * EIP-884 added link to reference implementation * EIP-884 added notes on ERC721 * EIP-884 renamed document, removed references to Reg A+, and updated interface to include stock cancellation and reissuance. * EIP-884 updated some documentation in the proposed interface * EIP-884 added isHolder function to proposed interface * EIP-884 moved to new frontmatter format * EIP-884 removed 'requires' from metadata * EIP-884 renamed file to match others
This commit is contained in:
parent
a5a6600bcb
commit
baf0e7a6ee
|
@ -0,0 +1,322 @@
|
|||
---
|
||||
eip: 884
|
||||
title: 'DGCL Token'
|
||||
author: 'Dave Sag <davesag@gmail.com>'
|
||||
type: Standard Track
|
||||
category: ERC
|
||||
status: Draft
|
||||
created: 2018-02-14
|
||||
---
|
||||
|
||||
# Delaware General Corporations Law (DGCL) compatible stock Token
|
||||
|
||||
Ref: [proposing-an-eip-for-DGCL-Tokens](http://forum.ethereum.org/discussion/17200/proposing-an-eip-for-regulation-a-Tokens)
|
||||
|
||||
## Simple Summary
|
||||
|
||||
An `ERC20` compatible Token that conforms to [Delaware State Senate, 149th General Assembly, Senate Bill No. 69: An act to Amend Title 8 of the Delaware Code Relating to the General Corporation Law](https://legis.delaware.gov/json/BillDetail/GenerateHtmlDocument?legislationId=25730&legislationTypeId=1&docTypeId=2&legislationName=SB69), henceforth referred to as 'The Act'.
|
||||
|
||||
## Abstract
|
||||
|
||||
The recently amended 'Title 8 of the Delaware Code Relating to the General Corporation Law' now explicitly allows for the use of blockchains to maintain corporate stock ledgers. This means it is now possible to create a tradable `ERC20` Token where each Token represents a Share issued by a Delaware corporation. Such a Token must conform to the following principles over and above the `ERC20` standard.
|
||||
|
||||
1. Token owners must have their identity verified.
|
||||
2. The Token contract must provide the following 3 functions of a `Corporations Stock ledger` (Ref: Section 224 of The Act):
|
||||
|
||||
1. Reporting:
|
||||
|
||||
It must enable the corporation to prepare the list of stockholders specified in Sections 219 and 220 of The Act.
|
||||
|
||||
2. It must record the information specified in Sections 156, 159, 217(a) and 218 of The Act:
|
||||
|
||||
- Partly paid shares
|
||||
- Total amount paid
|
||||
- Total amount to be paid
|
||||
|
||||
3. Transfers of stock as per section 159 of The Act:
|
||||
|
||||
It must record transfers of stock as governed by Article 8 of subtitle I of Title 6.
|
||||
|
||||
3. Each Token MUST correspond to a single share, each of which would be paid for in full, so there is no need to record information concerning partly paid shares, and there are no partial Tokens.
|
||||
|
||||
4. There must be a mechanism to allow a stockholder who has lost their private key, or otherwise lost access to their Tokens to have their address `cancelled` and the Tokens re-issued to a new address.
|
||||
|
||||
## Motivation
|
||||
|
||||
1. Delaware General Corporation Law requires that stock issued by a Delaware corporation be recorded in a stock ledger.
|
||||
2. The stock ledger can be represented by an ERC20 Token contract that is compliant with Delaware General Corporation Law.
|
||||
3. This standard can cover equity issued by any Delaware corporation, whether private or public.
|
||||
|
||||
By using a `DGCL` compatible Token, a firm may be able to raise funds via IPO, conforming to Delaware Corporations Law, but bypassing the need for involvement of a traditional Stock Exchange.
|
||||
|
||||
The are currently no Token standards that conform to the `DGCL` rules. `ERC20` Tokens do not support KYC/AML rules required by the General Corporation Law, and do not provide facilities for the exporting of lists of stockholders.
|
||||
|
||||
### What about ERC721?
|
||||
|
||||
The proposed standard could easily be used to enhance ERC721, adding features for associating tokens with assets such as share certificates.
|
||||
|
||||
While the `ERC721` Token proposal allows for some association of metadata with an Ethereum address, its uses are _not completely aligned_ with The Act, and it is not, in its current form, fully `ERC20` compatible.
|
||||
|
||||
## Specification
|
||||
|
||||
The `ERC20` Token provides the following basic features:
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
This will be extended as follows:
|
||||
|
||||
/**
|
||||
* An `ERC20` compatible Token that conforms to Delaware State Senate,
|
||||
* 149th General Assembly, Senate Bill No. 69: An act to Amend Title 8
|
||||
* of the Delaware Code Relating to the General Corporation Law.
|
||||
*
|
||||
* Implementation Details.
|
||||
*
|
||||
* An implementation of this Token standard SHOULD provide the following:
|
||||
*
|
||||
* `name` - for use by wallets and exchanges.
|
||||
* `symbol` - for use by wallets and exchanges.
|
||||
*
|
||||
* The implementation MUST take care not to allow unauthorised access to stock
|
||||
* transfer functions.
|
||||
*
|
||||
* In addition to the above the following optional `ERC20` function MUST be defined.
|
||||
*
|
||||
* `decimals` — MUST return `0` as each Token represents a single Share and Shares are non-divisible.
|
||||
*
|
||||
* @dev Ref https://github.com/ethereum/EIPs/pull/884
|
||||
*/
|
||||
contract ERC884 is ERC20 {
|
||||
|
||||
/**
|
||||
* This event is emitted when a verified address and associated identity hash are
|
||||
* added to the contract.
|
||||
* @param addr The address that was added.
|
||||
* @param hash The identity hash associated with the address.
|
||||
* @param sender The address that caused the address to be added.
|
||||
*/
|
||||
event VerifiedAddressAdded(
|
||||
address indexed addr,
|
||||
bytes32 hash,
|
||||
address indexed sender
|
||||
);
|
||||
|
||||
/**
|
||||
* This event is emitted when a verified address its associated identity hash are
|
||||
* removed from the contract.
|
||||
* @param addr The address that was removed.
|
||||
* @param sender The address that caused the address to be removed.
|
||||
*/
|
||||
event VerifiedAddressRemoved(address indexed addr, address indexed sender);
|
||||
|
||||
/**
|
||||
* This event is emitted when the identity hash associated with a verified address is updated.
|
||||
* @param addr The address whose hash was updated.
|
||||
* @param oldHash The identity hash that was associated with the address.
|
||||
* @param hash The hash now associated with the address.
|
||||
* @param sender The address that caused the hash to be updated.
|
||||
*/
|
||||
event VerifiedAddressUpdated(
|
||||
address indexed addr,
|
||||
bytes32 oldHash,
|
||||
bytes32 hash,
|
||||
address indexed sender
|
||||
);
|
||||
|
||||
/**
|
||||
* This event is emitted when an address is cancelled and replaced with
|
||||
* a new address. This happens in the case where a stockholder has
|
||||
* lost access to their original address and needs to have their stock
|
||||
* reissued to a new address. This is the equivalent of issuing replacement
|
||||
* stock certificates.
|
||||
* @param original The address being superseded.
|
||||
* @param replacement The new address.
|
||||
* @param sender The address that caused the address to be superseded.
|
||||
*/
|
||||
event VerifiedAddressSuperseded(
|
||||
address indexed original,
|
||||
address indexed replacement,
|
||||
address indexed sender
|
||||
);
|
||||
|
||||
/**
|
||||
* Add a verified address, along with an associated verification hash to the contract.
|
||||
* Upon successful addition of a verified address the contract must emit
|
||||
* `VerifiedAddressAdded(addr, hash, msg.sender)`.
|
||||
* It MUST throw if the supplied address or hash are zero, or if the address has already been supplied.
|
||||
* @param addr The address of the person represented by the supplied hash.
|
||||
* @param hash A cryptographic hash of the address holder's verified information.
|
||||
*/
|
||||
function addVerified(address addr, bytes32 hash) public;
|
||||
|
||||
/**
|
||||
* Remove a verified address, and the associated verification hash. If the address is
|
||||
* unknown to the contract then this does nothing. If the address is successfully removed this
|
||||
* function must emit `VerifiedAddressRemoved(addr, msg.sender)`.
|
||||
* It MUST throw if an attempt is made to remove a verifiedAddress that owns Tokens.
|
||||
* @param addr The verified address to be removed.
|
||||
*/
|
||||
function removeVerified(address addr) public;
|
||||
|
||||
/**
|
||||
* Update the hash for a verified address known to the contract.
|
||||
* Upon successful update of a verified address the contract must emit
|
||||
* `VerifiedAddressUpdated(addr, oldHash, hash, msg.sender)`.
|
||||
* If the hash is the same as the value already stored then
|
||||
* no `VerifiedAddressUpdated` event is to be emitted.
|
||||
* It MUST throw if the hash is zero, or if the address is unverified.
|
||||
* @param addr The verified address of the person represented by the supplied hash.
|
||||
* @param hash A new cryptographic hash of the address holder's updated verified information.
|
||||
*/
|
||||
function updateVerified(address addr, bytes32 hash) public;
|
||||
|
||||
/**
|
||||
* Cancel the original address and reissue the Tokens to the replacement address.
|
||||
* Access to this function MUST be strictly controlled.
|
||||
* The `original` address MUST be removed from the set of verified addresses.
|
||||
* Throw if the `original` address supplied is not a stockholder.
|
||||
* Throw if the `replacement` address is not a verified address.
|
||||
* Throw if the `replacement` address already holds Tokens.
|
||||
* This function MUST emit the `VerifiedAddressSuperseded` event.
|
||||
* @param original The address to be superseded. This address MUST NOT be reused.
|
||||
*/
|
||||
function cancelAndReissue(address original, address replacement) public;
|
||||
|
||||
/**
|
||||
* The `transfer` function MUST NOT allow transfers to addresses that
|
||||
* have not been verified and added to the contract.
|
||||
* If the `to` address is not currently a stockholder then it MUST become one.
|
||||
* If the transfer will reduce `msg.sender`'s balance to 0 then that address
|
||||
* MUST be removed from the list of stockholders.
|
||||
*/
|
||||
function transfer(address to, uint256 value) public returns (bool);
|
||||
|
||||
/**
|
||||
* The `transferFrom` function MUST NOT allow transfers to addresses that
|
||||
* have not been verified and added to the contract.
|
||||
* If the `to` address is not currently a stockholder then it MUST become one.
|
||||
* If the transfer will reduce `from`'s balance to 0 then that address
|
||||
* MUST be removed from the list of stockholders.
|
||||
*/
|
||||
function transferFrom(address from, address to, uint256 value) public returns (bool);
|
||||
|
||||
/**
|
||||
* Tests that the supplied address is known to the contract.
|
||||
* @param addr The address to test.
|
||||
* @return true if the address is known to the contract.
|
||||
*/
|
||||
function isVerified(address addr) public view returns (bool);
|
||||
|
||||
/**
|
||||
* Checks to see if the supplied address is a stock holder.
|
||||
* @param addr The address to check.
|
||||
* @return true if the supplied address owns a token.
|
||||
*/
|
||||
function isHolder(address addr) public view returns (bool);
|
||||
|
||||
/**
|
||||
* Checks that the supplied hash is associated with the given address.
|
||||
* @param addr The address to test.
|
||||
* @param hash The hash to test.
|
||||
* @return true if the hash matches the one supplied with the address in `addVerified`, or `updateVerified`.
|
||||
*/
|
||||
function hasHash(address addr, bytes32 hash) public view returns (bool);
|
||||
|
||||
/**
|
||||
* The number of addresses that hold tokens.
|
||||
* @return the number of unique addresses that hold tokens.
|
||||
*/
|
||||
function holderCount() public view returns (uint);
|
||||
|
||||
/**
|
||||
* By counting the number of Token holders using `holderCount`
|
||||
* you can retrieve the complete list of Token holders, one at a time.
|
||||
* It MUST throw if `index >= holderCount()`.
|
||||
* @param index The zero-based index of the holder.
|
||||
* @return the address of the Token holder with the given index.
|
||||
*/
|
||||
function holderAt(uint256 index) public view returns (address);
|
||||
|
||||
/**
|
||||
* Checks to see if the supplied address was superseded.
|
||||
* @param addr The address to check.
|
||||
* @return true if the supplied address was superseded by another address.
|
||||
*/
|
||||
function isSuperseded(address addr) public view returns (bool);
|
||||
|
||||
/**
|
||||
* Gets the most recent address given a superseded one.
|
||||
* Addresses may be superseded multiple times, so this function needs to
|
||||
* follow the chain of addresses until it reaches the final, verified address.
|
||||
* @param addr The superseded address.
|
||||
* @return the verified address that ultimately holds the stock.
|
||||
*/
|
||||
function getCurrentFor(address addr) public view returns (address);
|
||||
}
|
||||
|
||||
### SEC Requirements
|
||||
|
||||
The SEC has additional requirements as to how a Crowdsale ought to be run and what information must be made available to the general public. This information is however out of scope from this standard, though the standard does support the requirements.
|
||||
|
||||
For example: The SEC requires a Crowdsale's website display the amount of money raised in USD. To support this a Crowdsale contract minting these Tokens must maintain a USD to ETH conversion rate (via Oracle or some other mechanism) and must record the conversion rate used at time of minting.
|
||||
|
||||
Also, depending on the type of raise, the SEC (or other statutory body) can apply limits to the number of shareholders allowed. To support this the standard provides the `holderCount` and `isHolder` functions which a crowdsale can invoke to check that limits have not been exceeded.
|
||||
|
||||
### Use of the Identity `hash` value.
|
||||
|
||||
Implementers of a Crowdsale, in order to comply with The Act, must be able to produce an up-to-date list of the names and addresses of all stockholders. It is not desirable to include those details in a public blockchain, both for reasons of privacy, and also for reasons of economy. Storing arbitrary string data on the blockchain is strongly discouraged.
|
||||
|
||||
Implementers should maintain an off-chain private database that records the owner's name, residential address, and Ethereum address. The implementer must then be able to extract the name and address for any address, and hash the name + address data and compare that hash to the hash recorded in the contract using the `hasHash` function. The specific details of this system are left to the implementer.
|
||||
|
||||
It is also desirable that the implementers offer a REST API endpoint along the lines of
|
||||
|
||||
GET https://<host>/<pathPrefix>/:ethereumAddress -> [true|false]
|
||||
|
||||
to enable 3rd party auditors to verify that a given Ethereum address is known to the implementers as a verified address.
|
||||
|
||||
How the implementers verify a person's identity is up to them and beyond the scope of this standard.
|
||||
|
||||
### Handling users who have lost access to their addresses
|
||||
|
||||
A traditional stock register is typically managed by a Transfer Agent who is authorised to maintain the ledger accurately, and to handle stockholder enquiries. A common request is for stock certificates to be reissued in the case where the stockholder has lost or destroyed their original.
|
||||
|
||||
Token implementers can handle that via the `cancelAndReissue` function, which must perform the various changes to ensure that the old address now points to the new one, and that cancelled addresses are not then reused.
|
||||
|
||||
### Permissions management
|
||||
|
||||
It is not desirable that anyone can add, remove, update, or supersede verified addresses. How access to these functions is controlled is outside of the scope of this standard.
|
||||
|
||||
## Rationale
|
||||
|
||||
The proposed standard offers an as minimal as possible extension over the existing `ERC20` standard in order to conform to the requirements of The Act. Rather than return a `bool` for successful or unsuccessful completion of state-changing functions such as `addVerified`, `removeVerified`, and `updateVerified`, we have opted to require that implementations `throw` (preferably by using the [forthcoming `require(condition, 'fail message')` syntax](https://github.com/ethereum/solidity/issues/1686#issuecomment-328181514).)
|
||||
|
||||
## Backwards Compatibility
|
||||
|
||||
The proposed standard is designed to maintain compatibility with ERC20 Tokens with the following provisos.
|
||||
|
||||
1. The `decimals` function MUST return `0` as the Tokens MUST NOT be divisible,
|
||||
2. The `transfer` and `transferFrom` functions MUST NOT allow transfers to non-verified addresses, and MUST maintain a list of stockholders.
|
||||
3. Stockholders who transfer away their remaining Tokens must be pruned from the list of stockholders.
|
||||
|
||||
Proviso 1 will not break compatibility with modern wallets or exchanges as they all appear to use that information if available.
|
||||
|
||||
Proviso 2 will cause transfers to fail if an attempt is made to transfer Tokens to a non-verified address. This is implicit in the design and implementers are encouraged to make this abundantly clear to market participants. We appreciate that this will make the standard unpalatable to some exchanges, but it is an SEC requirement that stockholders of a corporation provide verified names and addresses.
|
||||
|
||||
Proviso 3 is an implementation detail.
|
||||
|
||||
## Test Cases and Reference Implementation
|
||||
|
||||
Test cases and a reference implementation are available at [github.com/davesag/ERC884-reference-implementation](https://github.com/davesag/ERC884-reference-implementation).
|
||||
|
||||
## Copyright
|
||||
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
Loading…
Reference in New Issue