# MEP-04: Reward Token Contract
**Created**: 2023-04-19
## Simple Summary
Specification of the token contract which will encapsulate reward tokens for device owners. The reward token should be considered as a fungible asset.
## Abstract
MEP-04 describes the layout of a reward token contract which extends the ERC20 standard. In addition to the fungible token contract, it needs to track the so called "fuel tank" of the sensor.
The "fuel tank" is a coefficient built with the ratio between the current balance of the address and the total amount of tokens that the address has ever earned. This coefficient is appplied to the earned rewards.
`fuel_tank[address] = min(current_balance[address] / total_balance[address], 1)`
Example:
Lets imagine that Joel managed to earn a reward of 100CC (CC estands for Custom Currency)
Since he is keeping all his rewards on his account, the fuel tank coefficient is 1
```
Block 1:
reward(0xabcd, 100)
fuel_tank[0xabcd] = 100 / 100 = 1
```
Joel managed to earn 200CC, which brings his total rewards to 300CC and he keep them on his account. The fuel tank coefficient remains 1.
```
Block 5:
reward(0xabcd, 200)
fuel_tank[0xabcd] = 300 / 300 = 1
```
Now Joel decides to transfer 30CC to a friend. since he reduced the amount of CC on his account, then the fueltank coefficient is reduced from 1 to 0.9
```
Block 10:
transferFromSensor(0xabcd, 0xefaa, 30)
fuel_tank[0xabcd] = 270 / 300 = 0.9
```
Because of this transfer, Joel have reduced his capabilities to get rewards, he decided to purchase CC on the cryptomarket and add it to his sensor address to bring back the fuel coefficient to 1.
```
Block 20:
transfer(0xabcd, 100)
fuel_tank[0xabcd] = min(370 / 300, 1) = 1
```
Joel added 100CC to his sensor address which brings the fueltank to 1. It is important to notice that the fueltank will never be higher than 1.
The MEP-05 defines a set of 3 pool allocations. Each pool has a given amount tokens allocated. At the phase of rewarding, each reward is given from a pool based on a rewarding criteria. The addresses in the same pool compete against each other for the reward amount. The less rewards in the pool, the more the reward amount goes to the addresses in the same pool.
## Motivation
In order to give rewards based on the user's data collection, there needs to be a token that brings up value to the actions.
This proposal specifies a token standard, extending the well-known ERC20 token with sensor specific data.
MEP-04 introduces the concept of a `fuel_tank` which acts as a reward coefficient based on the balance of the sensor's address. The goal is to create incentive for the sensor owner not to liquidate the tokens after rewarding.
## Terminology
- Fuel tank - coefficient of "mining power"; calculated as the ratio between the address' current balance and total accumulated balance
- Pool - allocation of tokens from which particular rewards will be distributed
- Reward Cycle - period delimitated by start and end block in which users can submit data to get rewards; a cycle can be one day, one week, one month, etc.
## Specification
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.
Every MEP-04 compliant contract must implement the `ERC20` interface:
```solidity=
pragma solidity ^0.4.20;
/// @title MEP-04 Reward Token Contract
interface IMEP04 /* is IERC20 */ {
/// @notice Gets fired when a reward gets issued
event IssueReward(address indexed _sensorAddress, uint256 _amount);
/// @notice Gets fired when the sensor owner transfers tokens
/// from the sensor to a beneficiary
event TransferFromSensor(address indexed _sensorAddress, address indexed _to, uint256 _amount);
/// @notice Returns the fuel tank of a given sensor.
/// @dev The fuel tank is the ratio of the current balance and
/// total aggregated balance from the rewards.
///
/// @param _tokenId The ID of the sensor NFT on MEP-02
/// @return Fuel tank in decimals
function fuelTankOf(uint256 _tokenId) external view returns (uint256);
/// @notice Transfers tokens from the sensor to a different address.
/// @dev This method does a simple transfer from the sensor's address
/// to a beneficiary address; calls to this method affect
/// the fuel tank
///
/// @param _tokenId The ID of the sensor NFT on MEP-02
/// @param _to The beneficiary address
/// @param _amount The amount of tokens to be sent
/// @return Returns if the method succeeded
function transferFromSensor(uint256 _tokenId, address _to, uint256 _amount) external returns (bool);
/// @notice Transfers tokens to the sensor's address.
/// @dev This method gets called by the MEP-05 contract implementation;
/// calls to this method affect the fuel tank
///
/// @param _tokenId The ID of the sensor NFT on MEP-02
/// @return Fuel tank in decimals
function reward(uint256 _tokenId, uint256 _amount) external;
}
interface IERC20 {
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
function totalSupply() external view returns (uint256);
function balanceOf(address _account) external view returns (uint256);
function transfer(address _to, uint256 _amount) external returns (bool);
function allowance(address _owner, address _spender) external view returns (uint256);
function approve(address _spender, uint256 _amount) external returns (bool);
function transferFrom(address _from, address _to, uint256 _amount) external returns (bool);
}
```
## Rationale
The sensor's fuel tank coefficient can never be greater than 1.
The fuel tank top up happens with the `reward` method. Once the reward payouts happen (defined by MEP-05), the `current_balance` and `total_balance` of the address jump which increases the fuel tank capacity.
Once a `transferFromSensor` has been called the `current_balance` decreases which lowers the fuel tank. In order to increase the fuel tank, the caller needs to `transfer` tokens to the sensor address in order to restore the fuel tank.
### Pools
With each contract deployed, there exists a pool allocation of 3 pools. Each pool has N tokens supplied for a reward cycle.
In one reward cycle the reward entries compete in a pool which is selected with the calculation formula.
Example:
3 pools with 1000 tokens
One cycle could have the following reward distribution:
- 5 entries in pool 1
- 10 entries in pool 2
- 7 entries in pool 3
Each pool is independant and rewards in one pool don't affect the rewarded amount in another pool.
### Reward Formula
The reward formula calculates the data efficiency of each sensor and also the pool where it is selected.
For each cycle, the `totalContribution` needs to be calculated. The `totalContribution` is the sum of all data efficiences * fuel tanks * sensor validity.
`totalContribution = sum(dataEfficiency * fuelTank * isValid)`
Afterwards, the `payout` method needs to calculate each reward inside of the pools with the amount of tokens based on the following formula:
`reward[address] = dataEfficiency[sensor] * fuelTank[address] * isValid[sensor] / totalContribution`