# MEP-05: Reward Calculation Contract **Created**: 2023-04-19 ## Simple Summary Specification for the reward calculation formula. Based on this one, a application creator can specify custom rules for rewarding sensor owners that submit data to the platform. ## Abstract ## Motivation ## Terminology - Reward Pools - 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. - Daily Amount ## 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-05 compliant contract must implement the following interface: ```solidity= pragma solidity ^0.4.20; /// @title MEP-05 Reward Calculation Contract interface IMEP05 { event RegisterReward(uint256 indexed tokenId, uint256 dataEfficiency, uint256 pool); event Payout(uint256 startBlock, uint256 endBlock, uint256 numberOfRewards); /// @notice Registers a reward entry for a single sensor. /// @dev This method should store the tokenId from MEP-02, /// it's data efficiency and the pool selected; afterwards /// when the payout of a cycle is done, the method needs /// to calculate the total contributions /// /// @param _tokenId The tokenId of the sensor /// @param _dataEfficiency The address of the sensor /// @param _pool The address of the sensor /// @return Fuel tank in decimals function registerReward(uint256 _tokenId, uint256 _dataEfficiency, uint256 _pool) external; function payout(uint256 _startBlock, uint256 _endBlock) external; } ``` ## Rationale ### Contract dependencies In order for MEP05 to issue rewards, check fuel tank and device validity, it needs a link to: - MEP02 - checking the validity of the sensor using `isValid` - MEP04 - calling the `reward` method and getting the sensor's fuel tank In practice, this is mostly done inside the constructor: ```solidity constructor(address provisioningContract, address rewardTokenContract) ``` In order to authorize an external entity (EOA) to call the `payout` method, there needs to be an authorized account with a `onlyPayout` modifier. This can go also inside of the constructor, so that we have: ```solidity= public address authorizedAddress; modifier onlyPayout() { require(msg.sender == authorizedAddress); _; } constructor(address provisioningContract, address rewardTokenContract, address payoutAddress) { this.authorizedAddress = payoutAddress; } function payout(uint256 startBlock, uint256 endBlock) external onlyPayout {...}; ``` ### 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`