Overview
This topic of discussion is an ERC token standard representing shares in a corporation, or even membership unit interests (MIUs) in an alternative asset fund. This new interface standardizes equity management for issuers, investors, transfer agents, and financial intermediaries. Creating an equity token standard requires a large industry effort. That’s why this token standard adheres to the same design principles as the Open Cap Format (OCF), an industry-approved data schema for cap tables. Now everyone can adopt the same OCF-compliant token standard for Ethereum and beyond!
Building off of ERC-3643 enables features such as:
- Transfer agent controls (account and asset freeze, account recovery, etc.)
- Compatibility with onchain identity management
- Customized compliance modules
Issuance Identifiers
To conform to OCF, mint
has been renamed to issue
and burn
has been renamed to cancel
. See here for more details on cancellation of equity issuances.
ERC-7752 brings breaking changes to ERC-3643 by emphasizing security issuances (each of which may have its own vesting conditions or other contractual requirements) rather than fungible token balances. Thus, methods like freezePartialTokens
have been removed in favor of freezeSecurity
to target a specific issuance. An additional securityId
param is required for any method that modifies an account’s equity balance. The batch interfaces have been removed by the recommendation of @wjmelements to optimize contract size since calls can be batched with Multicall.
In addition to mint
and burn
ERC-20 breaking changes, this standard introduces:
- the
shareClass
anduri
parameters to theissue
method - a
securityId
parameter tocancel
,transfer
, andtransferFrom
methods - a
shareClass
param to theapprove
,increaseAllowance
, anddecreaseAllowance
methods - corresponding changes to the event signatures
Assigning a unique securityId
to all issuances of equity tokens is necessary for the ease of understanding unique conditions of a stock grant (such as vesting), cost basis, and ease of auditing. Find more details on how the OCF handles stock transfers.
Organization Documents & Share Class Metadata
Support for storing governing documents of the stock such as a corporate charter, operating agreement, or stock plan has been introduced. A metadata JSON URI can also optionally be attached per share class and should conform to the OCF StockClass schema.
For organizations that don’t issue stock such as partnerships or LLCs, we recommend using the equity token with one share class named “membership unit interests”. Such entities should ensure that their operating agreement reflects this ownership structure.
Onchain Verifications
The concept of an on-chain identity from ERC-3643 may still be used, but this standard doesn’t force you into choosing the way described in ERC-3643. One reason for this is because on-chain identities can alternatively be attested to using the Ethereum Attestation Service. It would be beneficial to standardize the way things are attested to on-chain, so the door is open to adopt EAS for this ERC (and for other ERCs) to provide a common interface for verifiable credentials. EAS is being pushed by Coinbase and due to their sponsorship, I think EAS has a good chance of being the main standard.
Interface
library Types {
struct Security {
bytes32 id;
address holder;
bytes32 class;
bytes32 balanceSecurityId;
bytes32[] resultingSecurityIds;
uint256 amount;
uint256 issuedAt; // Block timestamp of issuance tx
string uri; // Additional metadata apart from share type metadata
bool isFrozen;
}
}
interface IToken {
/// Events
event Approval(address indexed _owner, address indexed _spender, uint256 _amount);
event Transfer(address indexed from, address indexed to, bytes32 securityId, uint256 amount, bytes32[] newIds);
event ShareClassAdded(bytes32 indexed _class, string indexed _uri);
event ShareClassUpdated(bytes32 indexed _class, string indexed _uri);
event ShareClassRemoved(bytes32 indexed _class);
event UpdatedTokenInformation(string indexed _newName, string indexed _newSymbol, uint8 _newDecimals, string _newVersion, address indexed _newOnchainID);
event IdentityRegistryAdded(address indexed _identityRegistry);
event ComplianceAdded(address indexed _compliance);
event RecoverySuccess(address indexed _lostWallet, address indexed _newWallet, address indexed _investorOnchainID);
event AddressFrozen(address indexed _userAddress, bool indexed _isFrozen, address indexed _owner);
event SecurityFrozen(address indexed _userAddress, bytes32 _securityId);
event SecurityUnfrozen(address indexed _userAddress, bytes32 _securityId);
event Paused(address _userAddress);
event Unpaused(address _userAddress);
/// Functions
function securities(bytes32 securityId) external view returns (Types.Security memory);
function getShareClasses() external view returns (bytes32[] calldata);
function addShareClass(bytes32 className, string memory metadataURI) external;
function removeShareClass(bytes32 className) external;
function getMetadataURIs() external view returns (string[] memory);
function name() external view returns (string memory);
function decimals() external view returns (uint8);
function symbol() external view returns (string memory);
function version() external view returns (string memory);
function allowance(address owner, bytes32 shareClass, address spender) external view returns (uint256);
function approve(address spender, bytes32 shareClass, uint256 amount) external returns (bool);
function increaseAllowance(address spender, bytes32 shareClass, uint256 addedValue) external returns (bool);
function decreaseAllowance(address spender, bytes32 shareClass, uint256 subtractedValue) external returns (bool);
function totalSupply() external view returns (uint256);
function totalSupply(bytes32 shareClass) external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function balanceOf(address account, bytes32 shareClass) external view returns (uint256);
function transferFrom(address from, address to, bytes32 securityId, uint256 amount) external returns (bool);
function transfer(address to, bytes32 securityId, uint256 amount) external returns (bool);
function setName(string calldata name) external;
function setSymbol(string calldata symbol) external;
function setOnchainID(address onchainID) external;
function pause() external;
function unpause() external;
function setAddressFrozen(address userAddress, bool isFrozen) external;
function freezeSecurity(address userAddress, bytes32 securityId) external;
function unfreezeSecurity(address userAddress, bytes32 securityId) external;
function setIdentityRegistry(address identityRegistry) external;
function setCompliance(address compliance) external;
function forcedTransfer(address from, address to, bytes32 securityId, uint256 amount) external returns (bool);
function issue(address to, bytes32 shareClass, uint256 amount, string memory uri, bytes calldata vestingData) external;
function cancel(address userAddress, bytes32 securityId, uint256 amount) external;
function recoveryAddress(address lostWallet, address newWallet, address _investorOnchainID) external returns (bool);
function onchainID() external view returns (address);
function identityRegistry() external view returns (IIdentityRegistry);
function compliance() external view returns (IModularCompliance);
function paused() external view returns (bool);
function isFrozen(address userAddress) external view returns (bool);
}
Comparing ERC-20 vs. ERC-7752
The Open Cap Format (OCF) method of handling stock transfers and the ERC-20 standard share some similarities, but they also differ in several key aspects.
Similarities
- Immutability and Traceability:
- ERC-20: ERC-20 tokens operate on a blockchain, where every transaction is recorded in an immutable ledger. This ensures that every transfer of tokens is permanently recorded, providing a clear history of token ownership.
- OCF: The event-driven architecture in OCF also ensures that every action (issuance, transfer, etc.) is recorded immutably. The OCF does not allow for altering past events.
- Event-Driven Nature:
- ERC-20: Token transfers in the ERC-20 standard are event-driven. Every transfer emits a
Transfer
event, which can be tracked by applications and users to monitor token movements. - OCF: Similarly, OCF uses events like
StockTransfer
to record the movement of securities. Each event is a discrete record in the history of the security.
- Standardized Format:
- ERC-20: The ERC-20 standard defines a consistent format for managing and transferring tokens.
- OCF: The OCF also defines a standardized format for recording corporate actions, including transfers.
Differences
- Asset Nature:
- ERC-20: ERC-20 is a standard for fungible tokens, where each token is identical and interchangeable with any other token. ERC-20 tokens typically represent assets like cryptocurrencies or utility tokens.
- OCF: OCF deals with securities, which are often non-fungible or semi-fungible. For example, shares of stock might come with different rights, vesting conditions, restrictions, or legends, making them distinct from one another even if they belong to the same stock class.
- Transfer Mechanism:
- ERC-20: In the ERC-20 standard, a transfer simply moves tokens from one address to another. The balance of the sender is decreased, and the balance of the recipient is increased in a single operation.
- OCF: OCF requires a more complex process for transfers. It involves creating a new issuance event for the recipient and linking the old and new securities through a transfer event. This reflects the fact that securities are not merely balances to be adjusted, but distinct legal instruments that may have unique attributes.
- Handling Partial Transfers:
- ERC-20: Partial transfers are straightforward in ERC-20, where a specified number of tokens can be transferred from one address to another, and the balance is adjusted accordingly.
- OCF: In OCF, partial transfers require creating a new security issuance for the remaining balance after the transfer. The original security is effectively split into two, with one part transferred to the new owner and the other part remaining with the original owner.
- Complexity of Events:
- ERC-20: The ERC-20 standard has relatively simple events (
Transfer
,Approval
), as it is designed to manage fungible tokens that do not have complex attributes or varying legal implications. - OCF: OCF events are more complex, reflecting the multifaceted nature of securities. For example, stock transfers may involve additional considerations like compliance with legal restrictions, tax implications, or changes in the rights associated with the stock.
- Legal and Compliance Focus:
- ERC-20: While ERC-20 tokens can represent assets with real-world value, they are often not tied to the same legal and regulatory frameworks as securities. ERC-20 tokens are primarily used for blockchain-based applications, and while they can be subject to regulation, they do not inherently carry the same legal obligations as securities.
- OCF: The OCF is specifically designed to manage and track securities, which are heavily regulated. It accounts for legal requirements, such as stock legends, compliance with securities laws, and proper documentation of transfers, making it suitable for managing equity in real companies.