HomeEIPsNewsletter
EIPsERC-2009
ERC-2009

Compliance Service

StagnantStandards Track: ERC
Created: 2019-05-09
Requires: EIP-1066
Daniel Lehrner <daniel@io.builders>
Discussions ForumOriginal Proposal LinkEdit
1 min read

The ERC-2009 proposal suggests a service for decentralized compliance checks for regulated tokens on the Ethereum network. Its goal is to provide a way to comply with legal requirements such as KYC and AML without making the token transfer centralized or requiring a second confirmation step. The proposed Compliance Service supports more than one token and could be used by law-makers to maintain compliance rules of regulated tokens in one smart contract. It also provides a standard for compliance checks that third-party developers can use to verify if token movements for a specific account are allowed and act accordingly. The proposed solution is meant to be deployed as a Solidity smart contract on the Ethereum network and includes a checkTransferAllowed function.

Video
Anyone may contribute to propose contents.
Go propose
Original

Simple Summary

This EIP proposes a service for decentralized compliance checks for regulated tokens.

Actors

Operator

An account which has been approved by a token to update the tokens accumulated.

Token

An account, normally a smart contract, which uses the Compliance Service to check if the an action can be executed or not.

Token holder

An account which is in possession of tokens and on for which the checks are made.

Abstract

A regulated token needs to comply with several legal requirements, especially KYC and AML. If the necessary checks have to be made off-chain the token transfer becomes centralized. Further the transfer in this case takes longer to complete as it can not be done in one transaction, but requires a second confirmation step. The goal of this proposal is to make this second step unnecessary by providing a service for compliance checks.

Motivation

Currently there is no proposal on how to accomplish decentralized compliance checks. ERC-1462 proposes a basic set of functions to check if transfer, mint and burn are allowed for a user, but not how those checks should be implemented. This EIP proposes a way to implement them fully on-chain while being generic enough to leave the actual implementation of the checks up to the implementers, as these may vary a lot between different tokens.

The proposed Compliance Service supports more than one token. Therefore it could be used by law-makers to maintain the compliance rules of regulated tokens in one smart contract. This smart contract could be used by all of the tokens that fall under this jurisdiction and ensure compliance with the current laws.

By having a standard for compliance checks third-party developers can use them to verify if token movements for a specific account are allowed and act accordingly.

Specification

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

Mandatory checks

The checks must be verified in their corresponding actions. The action must only be successful if the check return an Allowed status code. In any other case the functions must revert.

Status codes

If an action is allowed 0x11 (Allowed) or an issuer-specific code with equivalent but more precise meaning must be returned. If the action is not allowed the status must be 0x10 (Disallowed) or an issuer-specific code with equivalent but more precise meaning.

Functions

checkTransferAllowed

Checks if the transfer function is allowed to be executed with the given parameters.

ParameterDescription
tokenIdThe unique ID which identifies a token
fromThe address of the payer, from whom the tokens are to be taken if executed
toThe address of the payee, to whom the tokens are to be transferred if executed
valueThe amount to be transferred

checkTransferFromAllowed

Checks if the transferFrom function is allowed to be executed with the given parameters.

ParameterDescription
tokenIdThe unique ID which identifies a token
senderThe address of the sender, who initiated the transaction
fromThe address of the payer, from whom the tokens are to be taken if executed
toThe address of the payee, to whom the tokens are to be transferred if executed
valueThe amount to be transferred

checkMintAllowed

Checks if the mint function is allowed to be executed with the given parameters.

ParameterDescription
tokenIdThe unique ID which identifies a token
toThe address of the payee, to whom the tokens are to be given if executed
valueThe amount to be minted

checkBurnAllowed

Checks if the burn function is allowed to be executed with the given parameters.

ParameterDescription
tokenIdThe unique ID which identifies a token
fromThe address of the payer, from whom the tokens are to be taken if executed
valueThe amount to be burned

updateTransferAccumulated

Must be called in the same transaction as transfer or transferFrom. It must revert if the update violates any of the compliance rules. It is up to the implementer which specific logic is executed in the function.

ParameterDescription
tokenIdThe unique ID which identifies a token
fromThe address of the payer, from whom the tokens are to be taken if executed
toThe address of the payee, to whom the tokens are to be transferred if executed
valueThe amount to be transferred

updateMintAccumulated

Must be called in the same transaction as mint. It must revert if the update violates any of the compliance rules. It is up to the implementer which specific logic is executed in the function.

ParameterDescription
tokenIdThe unique ID which identifies a token
toThe address of the payee, to whom the tokens are to be given if executed
valueThe amount to be minted

updateBurnAccumulated

Must be called in the same transaction as burn. It must revert if the update violates any of the compliance rules. It is up to the implementer which specific logic is executed in the function.

ParameterDescription
tokenIdThe unique ID which identifies a token
fromThe address of the payer, from whom the tokens are to be taken if executed
valueThe amount to be minted

addToken

Adds a token to the service, which allows the token to call the functions to update the accumulated. If an existing token id is used the function must revert. It is up to the implementer if adding a token should be restricted or not.

ParameterDescription
tokenIdThe unique ID which identifies a token
tokenThe address from which the update functions will be called

replaceToken

Replaces the address of a added token with another one. It is up to the implementer if replacing a token should be restricted or not, but a token should be able to replace its own address.

ParameterDescription
tokenIdThe unique ID which identifies a token
tokenThe address from which the update functions will be called

removeToken

Removes a token from the service, which disallows the token to call the functions to update the accumulated. It is up to the implementer if removing a token should be restricted or not.

ParameterDescription
tokenIdThe unique ID which identifies a token

isToken

Returns true if the address has been added to the service, false if not.

ParameterDescription
tokenThe address which should be checked

getTokenId

Returns the token id of a token. If the token has not been added to the service, '0' must be returned.

ParameterDescription
tokenThe address which token id should be returned

authorizeAccumulatedOperator

Approves an operator to update accumulated on behalf of the token id of msg.sender.

ParameterDescription
operatorThe address to be approved as operator of accumulated updates

revokeAccumulatedOperator

Revokes the approval to update accumulated on behalf the token id the token id ofof msg.sender.

ParameterDescription
operatorThe address to be revoked as operator of accumulated updates

isAccumulatedOperatorFor

Retrieves if an operator is approved to create holds on behalf of tokenId.

ParameterDescription
operatorThe address which is operator of updating the accumulated
tokenIdThe unique ID which identifies a token

Events

TokenAdded

Must be emitted after a token has been added.

ParameterDescription
tokenIdThe unique ID which identifies a token
tokenThe address from which the update functions will be called

TokenReplaced

Must be emitted after the address of a token has been replaced.

ParameterDescription
tokenIdThe unique ID which identifies a token
previousAddressThe previous address which was used before
newAddressThe address which will be used from now on

TokenRemoved

Must be emitted after the a token has been removed.

ParameterDescription
tokenIdThe unique ID which identifies a token

AuthorizedAccumulatedOperator

Emitted when an operator has been approved to update the accumulated on behalf of a token.

ParameterDescription
operatorThe address which is operator of updating the accumulated
tokenIdToken id on which behalf updates of the accumulated will potentially be made

RevokedHoldOperator

Emitted when an operator has been revoked from updating the accumulated on behalf of a token.

ParameterDescription
operatorThe address which was operator of updating the accumulated
tokenIdToken id on which behalf updates of the accumulated could be made

Rationale

The usage of a token id instead of the address has been chosen to give tokens the possibility to update their smart contracts and keeping all their associated accumulated. If the address would be used, a migration process would needed to be done after a smart contract update.

No event is emitted after updating the accumulated as those are always associated with a transfer, mint or burn of a token which already emits an event of itself.

While not requiring it, the naming of the functions checkTransferAllowed, checkTransferFromAllowed, checkMintAllowed and checkBurnAllowed was adopted from ERC-1462.

While not requiring it, the naming of the functions authorizeAccumulatedOperator, revokeAccumulatedOperator and isAccumulatedOperatorFor follows the naming convention of ERC-777.

Localization is not part of this EIP, but ERC-1066 and ERC-1444 can be used together to achieve it.

Backwards Compatibility

As the EIP is not using any existing EIP there are no backwards compatibilities to take into consideration.

Implementation

The GitHub repository IoBuilders/compliance-service contains the work in progress implementation.

Contributors

This proposal has been collaboratively implemented by adhara.io and io.builders.

Copyright and related rights waived via CC0.

Further reading
Anyone may contribute to propose contents.
Go propose
Adopted by projects
Anyone may contribute to propose contents.
Go propose

Not miss a beat of EIPs' update?

Subscribe EIPs Fun to receive the latest updates of EIPs Good for Buidlers to follow up.

View all
Serve Ethereum Builders, Scale the Community.
Resources
GitHub
Supported by