---
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: Stagnant
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](../LICENSE.md).

[ERC-20]: ./eip-20.md
[EIP-1066]: ./eip-1066.md
[EIP-1996]: ./eip-1996.md
