forked from ethereum/EIPs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
EIP-2021: Payoutable Token (ethereum#2021)
- Loading branch information
1 parent
2662a6c
commit 1c88f34
Showing
1 changed file
with
290 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,290 @@ | ||
--- | ||
eip: 2021 | ||
title: Payoutable Token | ||
author: Fernando Paris <fer@io.builders>, Julio Faura <julio@adhara.io>, Daniel Lehrner <daniel@io.builders> | ||
discussions-to: https://github.com/ethereum/EIPs/issues/2106 | ||
status: Draft | ||
type: Standards Track | ||
category: ERC | ||
created: 2019-05-10 | ||
requires: 20, 1066, 1996 | ||
--- | ||
|
||
## Simple Summary | ||
An extension to the [ERC-20] standard token that allows Token wallet owners to request payout from their wallet, by calling the smart contract and attaching a payout instruction string. | ||
|
||
## Actors | ||
|
||
#### Token Wallet Owners | ||
The person or company who owns the wallet, and will order payout. | ||
|
||
#### Token contract owner / agent | ||
The entity, company responsible/owner of the token contract, and token issuing/minting. This actor is in charge of trying to fulfill all payout request(s), reading the payout instruction(s), and correlate the payout details. | ||
|
||
#### Orderer | ||
An actor who is enabled to initiate payout orders on behalf of a token wallet owner. | ||
|
||
## Abstract | ||
Token wallet owners (or approved addresses) can order payout requests through blockchain. This is done by calling the ```orderPayoutFrom``` or ```orderPayoutFrom``` methods, which initiate the workflow for the token contract operator to either honor or reject the payout request. In this case, payout instructions are provided when submitting the request, which are used by the operator to determine the destination of the funds. | ||
|
||
In general, it is not advisable to place explicit routing instructions for the payouts on a verbatim basis on the blockchain, and it is advised to use a private communication alternatives, such as private channels, encrypted storage or similar, to do so (external to the blockchain ledger). Another (less desirable) possibility is to place these instructions on the instructions field in encrypted form. | ||
|
||
## Motivation | ||
Nowadays most of the token payout requests, need a previous centralized transaction, to be able to define the payout destination to be able to execute the payout (burn transaction). | ||
In the aim of trying to bring all the needed steps into decentralization, exposing all the needed steps of token lifecycle and payment transactions, a payout request can allow wallet owner to initiate the payout order via blockchain. | ||
Key benefits: | ||
|
||
* Payout, burning traceability is enhanced bringing the initiation into the ledger. All payment, payout statuses can be stored on chain. | ||
* Almost all money/token lifecycle is covered via a decentralized approach, complemented with private communications which is common use in the ecosystem. | ||
|
||
In this case, the following movement of tokens are done as the process progresses: | ||
|
||
* Upon launch of the payout request, the appropriate amount of funds are placed on a hold with a predefined notary defined by the platform, and the payout is placed into a ```Ordered``` state | ||
* The operator then can put the payout request ```InProcess```, which prevents the _orderer_ of the payout from being able to cancel the payout request | ||
* After checking the payout is actually possible the operator then executes the hold, which moves the funds to a suspense wallet and places the payout into the ```FundsInSuspense``` state | ||
* The operator then moves the funds offchain (usually from the omnibus account) to the appropriate destination account, then burning the tokens from the suspense wallet and rendering the payout into the ```Executed``` state | ||
* Either before or after placing the request ```InProcess```, the operator can also reject the payout, which returns the funds to the payer and eliminates the hold. The resulting end state of the payout is ```Rejected``` | ||
* When the payout is ```Ordered``` and before the operator places it into the ```InProcess``` state, the orderer of the payout can also cancel it, which frees up the hold and puts the payout into the final ```Cancelled``` state | ||
|
||
## Specification | ||
|
||
```solidity | ||
interface IPayoutable /* is ERC-20 */ { | ||
enum PayoutStatusCode { | ||
Nonexistent, | ||
Ordered, | ||
InProcess, | ||
FundsInSuspense, | ||
Executed, | ||
Rejected, | ||
Cancelled | ||
} | ||
function authorizePayoutOperator(address orderer) external returns (bool); | ||
function revokePayoutOperator(address orderer) external returns (bool); | ||
function orderPayout(string calldata operationId, uint256 value, string calldata instructions) external returns (bool); | ||
function orderPayoutFrom(string calldata operationId, address walletToBePaidOut, uint256 value, string calldata instructions) external returns (bool); | ||
function cancelPayout(string calldata operationId) external returns (bool); | ||
function processPayout(string calldata operationId) external returns (bool); | ||
function putFundsInSuspenseInPayout(string calldata operationId) external returns (bool); | ||
function executePayout(string calldata operationId) external returns (bool); | ||
function rejectPayout(string calldata operationId, string calldata reason) external returns (bool); | ||
function isPayoutOperatorFor(address walletToDebit, address orderer) external view returns (bool); | ||
function retrievePayoutData(string calldata operationId) external view returns (address walletToDebit, uint256 value, string memory instructions, PayoutStatusCode status); | ||
event PayoutOrdered(address indexed orderer, string indexed operationId, address indexed walletToDebit, uint256 value, string instructions); | ||
event PayoutInProcess(address indexed orderer, string indexed operationId); | ||
event PayoutFundsInSuspense(address indexed orderer, string indexed operationId); | ||
event PayoutExecuted(address indexed orderer, string indexed operationId); | ||
event PayoutRejected(address indexed orderer, string indexed operationId, string reason); | ||
event PayoutCancelled(address indexed orderer, string indexed operationId); | ||
event PayoutOperatorAuthorized(address indexed walletToBePaidOut, address indexed orderer); | ||
event PayoutOperatorRevoked(address indexed walletToBePaidOut, address indexed orderer); | ||
} | ||
``` | ||
|
||
### Functions | ||
|
||
#### authorizePayoutOperator | ||
|
||
Wallet owner, allows a given address to be payout orderer. | ||
|
||
| Parameter | Description | | ||
| ---------|-------------| | ||
| orderer | The address of the orderer. | | ||
|
||
#### revokePayoutOperator | ||
|
||
Wallet owner, Revokes a given address to be payout orderer. | ||
|
||
| Parameter | Description | | ||
| ---------|-------------| | ||
| orderer | The address of the orderer. | | ||
|
||
#### orderPayout | ||
|
||
Creates a payout request, that will be processed by the token operator. The function must revert if the operation ID has been used before. | ||
|
||
| Parameter | Description | | ||
| ---------|-------------| | ||
| operationId | The unique ID to identify the request | | ||
| value | The amount to be paid out. | | ||
| instruction | A string including the payment instruction. | | ||
|
||
#### orderPayoutFrom | ||
|
||
Creates a payout request, on behalf of a wallet owner, that will be processed by the token operator. The function must revert if the operation ID has been used before. | ||
|
||
| Parameter | Description | | ||
| ---------|-------------| | ||
| operationId |The unique ID to identify the request | | ||
| walletToBePaidOut | The wallet to be paid out on behalf. | | ||
| value | The amount to be paid out. | | ||
| instruction | A string including the payment instruction. | | ||
|
||
#### cancelPayout | ||
|
||
Cancels a payout request. | ||
|
||
| Parameter | Description | | ||
| ---------|-------------| | ||
| operationId | The unique ID to identify the request that is going to be cancelled. This can only be done by token holder, or the payout initiator/orderer. | | ||
| reason | The specific reason that explains why the payout request was rejected. [EIP-1066] codes can be used. | | ||
|
||
|
||
#### processPayout | ||
|
||
Marks a payout request as on process. After the status is on process, order cannot be cancelled. | ||
|
||
| Parameter | Description | | ||
| ---------|-------------| | ||
| operationId | The unique ID to identify that the request is in process. | | ||
|
||
#### putFundsInSuspenseInPayout | ||
|
||
Put a given payout in suspense. Can only be done if it is in process. | ||
|
||
| Parameter | Description | | ||
| ---------|-------------| | ||
| operationId | The unique ID to identify that the request is in process. | | ||
|
||
#### executePayout | ||
|
||
Burn the amount of tokens and marks a payout request as executed. | ||
|
||
| Parameter | Description | | ||
| ---------|-------------| | ||
| operationId | The unique ID to identify the request that has been executed. | | ||
|
||
#### rejectPayout | ||
|
||
Rejects a given operation with a reason. | ||
|
||
| Parameter | Description | | ||
| ---------|-------------| | ||
| operationId | The unique ID to identify the request that has been executed. | | ||
| reason | The specific reason that explains why the payout request was rejected. [EIP-1066] codes can be used | | ||
|
||
#### isApprovedToOrderPayout | ||
|
||
Checks that given player is allowed to order payout requests, for a given wallet. | ||
|
||
| Parameter | Description | | ||
| ---------|-------------| | ||
| walletToBePaidOut | The wallet to be paid out, and checked for approval permission. | | ||
| orderer | The address of the orderer, to be checked for approval permission. | | ||
|
||
#### retrievePayoutData | ||
|
||
Retrieves all the payout request data. Only operator, tokenHolder, and orderer can get the given operation data. | ||
|
||
| Parameter | Description | | ||
| ---------|-------------| | ||
| orderer | The address of the orderer, to correlate the right data. | | ||
| operationId | The unique ID to identify the payout order. | | ||
|
||
### Events | ||
|
||
#### Payout Ordered | ||
|
||
Emitted when an token wallet owner orders a payout request. | ||
|
||
| Parameter | Description | | ||
| ---------|-------------| | ||
| operationId | The unique ID to identify the request | | ||
| walletToBePaidOut | The wallet that is requested to be paid out | | ||
| value | The amount to be funded. | | ||
| instruction | A string including the payment instruction. | | ||
|
||
#### PayoutFundsInSuspense | ||
|
||
Emitted when an operator puts fund in suspense. | ||
|
||
| Parameter | Description | | ||
| ---------|-------------| | ||
| orderer | The address of the payout request orderer. | | ||
| operationId | The unique ID to identify the payout. | | ||
|
||
#### PayoutInProcess | ||
|
||
Emitted when an operator accepts a payout request, and the operation is in process. | ||
|
||
| Parameter | Description | | ||
| ---------|-------------| | ||
| orderer | The address of the payout request orderer. | | ||
| operationId | The unique ID to identify the payout. | | ||
|
||
#### PayoutExecuted | ||
|
||
Emitted when an operator has executed a payout request. | ||
|
||
| Parameter | Description | | ||
| ---------|-------------| | ||
| orderer | The address of the payout request orderer. | | ||
| operationId | The unique ID to identify the payout. | | ||
|
||
#### PayoutRejected | ||
|
||
Emitted when an operator has rejected a payout request. | ||
|
||
| Parameter | Description | | ||
| ---------|-------------| | ||
| orderer | The address of the payout request orderer. | | ||
| operationId | The unique ID to identify the payout. | | ||
| reason | The specific reason that explains why the payout request was rejected. [EIP-1066] codes can be used | | ||
|
||
#### PayoutCancelled | ||
|
||
Emitted when a token holder, orderer, has cancelled a payout request. This can only be done if the operator hasn't put the payout order in process. | ||
|
||
| Parameter | Description | | ||
| ---------|-------------| | ||
| orderer | The address of the payout request orderer. | | ||
| operationId | The unique ID per payout issuer to identify the payout. | | ||
|
||
#### PayoutOperatorAuthorized | ||
|
||
Emitted when a given player, operator, company or a given persona, has been approved to start payout request for a given token holder. | ||
|
||
| Parameter | Description | | ||
| ---------|-------------| | ||
| walletToBePaidOut | The wallet that the player is allowed to start payout requests | | ||
| orderer |The address that allows the the player to start requests. | | ||
|
||
#### PayoutOperatorRevoked | ||
|
||
Emitted when a given player has been revoked initiate payout requests. | ||
|
||
| Parameter | Description | | ||
| ---------|-------------| | ||
| walletToBePaidOut | The wallet that the player is allowed to start payout requests | | ||
| orderer |The address that allows the the player to start requests. | | ||
|
||
## Rationale | ||
This standards provides a functionality to allow token holders to start payout requests in a decentralized way. | ||
|
||
It's important to highlight that the token operator, need to process all payout request, updating the payout status based on the linked payment that will be done. | ||
|
||
Payout instruction format is open. ISO payment standard like is a good start point. | ||
|
||
This EIP uses [EIP-1996] to hold the money after a payout is ordered. The token contract owner or agent, whose implementation is not part of this proposal, acts as a predefined notary to decide if the payout is executed or not. | ||
|
||
The `operationId` is a string and not something more gas efficient to allow easy traceability of the hold and allow human readable ids. It is up to the implementer if the string should be stored on-chain or only its hash, as it is enough to identify a hold. | ||
|
||
The `operationId` is a competitive resource. It is recommended, but not required, that the hold issuers used a unique prefix to avoid collisions. | ||
|
||
## Backwards Compatibility | ||
This EIP is fully backwards compatible as its implementation extends the functionality of [ERC-20] and [ERC-1996]. | ||
|
||
## Implementation | ||
The GitHub repository [IoBuilders/payoutable-token](https://github.com/IoBuilders/payoutable-token) contains the reference implementation. | ||
|
||
## Contributors | ||
This proposal has been collaboratively implemented by [adhara.io](https://adhara.io/) and [io.builders](https://io.builders/). | ||
|
||
## Copyright | ||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). | ||
|
||
[ERC-20]: https://eips.ethereum.org/EIPS/eip-20 | ||
[EIP-1066]: https://eips.ethereum.org/EIPS/eip-1066 | ||
[EIP-1996]: https://eips.ethereum.org/EIPS/eip-1996 |