Contrat
Contrat
0xa756f74dae…077649c15b
0xa756f74dae1b9077befff7ac966a46077649c15b
Solde WTG
17.498718 WTG
≈ 311,63 FCFA (@ 17,81 FCFA/WTG)
Avoirs en tokens
0 token
≈ 0,00 FCFA
Plus d'infos
Transactions envoyées1
Dernière activitéil y a 35 s
Première activitéil y a 18 h
Financé par
—
Code du contrat
✓ VérifiéRewardDistributor · Solidity v0.8.20+commit.a1b79de6 · optimiseur activé (200 runs) · licence MIT
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import { Ownable2Step, Ownable } from "@openzeppelin/contracts/access/Ownable2Step.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
interface IStakeManagerRewards {
function distributeRewards() external payable;
}
/// @title RewardDistributor — QBFT block-reward beneficiary & fee settlement sink
/// @notice This is the `miningbeneficiary` configured in the QBFT genesis: every
/// block the protocol credits it the `blockreward` (the 1.5–2%/yr WTG
/// inflation). It also receives the validator-share of network/app fees.
///
/// Two native inflows are distinguished:
/// • block reward + already-burned fee remainder → arrive via receive(),
/// forwarded 100% to validators (burning inflation would be wrong).
/// • raw transaction fees → arrive via {depositFees}, which marks them
/// so that 20% is burned at settlement (the protocol burn policy).
///
/// At settlement, 20% of the *fee* bucket is burned to 0x…dEaD and the
/// remainder (block reward + 80% fees) is pushed to the StakeManager for
/// pro-rata distribution across the active validator set and delegators.
contract RewardDistributor is Ownable2Step, ReentrancyGuard {
address public constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD;
uint16 public constant BPS = 10_000;
IStakeManagerRewards public stakeManager;
/// @notice Burn rate applied to the fee bucket at settlement (2000 = 20%).
uint16 public feeBurnBps = 2_000;
/// @notice Native WTG received as raw fees and pending settlement.
uint256 public feePending;
uint256 public totalBlockRewards;
uint256 public totalFeesIn;
uint256 public totalBurned;
uint256 public totalDistributed;
event BlockRewardReceived(uint256 amount);
event FeesReceived(address indexed from, uint256 amount);
event Settled(uint256 burned, uint256 distributed);
event FeeBurnBpsUpdated(uint16 oldBps, uint16 newBps);
event StakeManagerUpdated(address indexed stakeManager);
error ZeroAddress();
error InvalidBps();
error NothingToSettle();
constructor(address stakeManager_, address owner_) Ownable(owner_) {
if (stakeManager_ == address(0)) revert ZeroAddress();
stakeManager = IStakeManagerRewards(stakeManager_);
}
/// @notice Intake for raw transaction fees subject to the 20% burn.
/// Called by the protocol fee router / relayer and by modules that
/// forward gas fees here.
function depositFees() external payable {
if (msg.value == 0) return;
feePending += msg.value;
totalFeesIn += msg.value;
emit FeesReceived(msg.sender, msg.value);
}
/// @notice Settle: burn 20% of the fee bucket, distribute everything else
/// (block reward + 80% fees) to validators/delegators.
function settle() external nonReentrant {
uint256 bal = address(this).balance;
if (bal == 0) revert NothingToSettle();
uint256 burnAmount = (feePending * feeBurnBps) / BPS;
feePending = 0;
if (burnAmount > bal) burnAmount = bal; // safety
uint256 distributable = bal - burnAmount;
if (burnAmount > 0) {
totalBurned += burnAmount;
(bool burned, ) = BURN_ADDRESS.call{ value: burnAmount }("");
require(burned, "RewardDistributor: burn failed");
}
if (distributable > 0) {
totalDistributed += distributable;
stakeManager.distributeRewards{ value: distributable }();
}
emit Settled(burnAmount, distributable);
}
// ----- governance -----
function setFeeBurnBps(uint16 newBps) external onlyOwner {
if (newBps > BPS) revert InvalidBps();
emit FeeBurnBpsUpdated(feeBurnBps, newBps);
feeBurnBps = newBps;
}
function setStakeManager(address sm) external onlyOwner {
if (sm == address(0)) revert ZeroAddress();
stakeManager = IStakeManagerRewards(sm);
emit StakeManagerUpdated(sm);
}
/// @dev QBFT block reward (coinbase credit) and forwarded fee remainders land here.
receive() external payable {
totalBlockRewards += msg.value;
emit BlockRewardReceived(msg.value);
}
}
[
{
"type": "constructor",
"inputs": [
{
"name": "stakeManager_",
"type": "address",
"internalType": "address"
},
{
"name": "owner_",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "nonpayable"
},
{
"type": "receive",
"stateMutability": "payable"
},
{
"type": "function",
"name": "BPS",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint16",
"internalType": "uint16"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "BURN_ADDRESS",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "acceptOwnership",
"inputs": [],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "depositFees",
"inputs": [],
"outputs": [],
"stateMutability": "payable"
},
{
"type": "function",
"name": "feeBurnBps",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint16",
"internalType": "uint16"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "feePending",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "owner",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "pendingOwner",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "renounceOwnership",
"inputs": [],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "setFeeBurnBps",
"inputs": [
{
"name": "newBps",
"type": "uint16",
"internalType": "uint16"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "setStakeManager",
"inputs": [
{
"name": "sm",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "settle",
"inputs": [],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "stakeManager",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "contract IStakeManagerRewards"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "totalBlockRewards",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "totalBurned",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "totalDistributed",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "totalFeesIn",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "transferOwnership",
"inputs": [
{
"name": "newOwner",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "event",
"name": "BlockRewardReceived",
"inputs": [
{
"name": "amount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"type": "event",
"name": "FeeBurnBpsUpdated",
"inputs": [
{
"name": "oldBps",
"type": "uint16",
"indexed": false,
"internalType": "uint16"
},
{
"name": "newBps",
"type": "uint16",
"indexed": false,
"internalType": "uint16"
}
],
"anonymous": false
},
{
"type": "event",
"name": "FeesReceived",
"inputs": [
{
"name": "from",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "amount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"type": "event",
"name": "OwnershipTransferStarted",
"inputs": [
{
"name": "previousOwner",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "newOwner",
"type": "address",
"indexed": true,
"internalType": "address"
}
],
"anonymous": false
},
{
"type": "event",
"name": "OwnershipTransferred",
"inputs": [
{
"name": "previousOwner",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "newOwner",
"type": "address",
"indexed": true,
"internalType": "address"
}
],
"anonymous": false
},
{
"type": "event",
"name": "Settled",
"inputs": [
{
"name": "burned",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "distributed",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"type": "event",
"name": "StakeManagerUpdated",
"inputs": [
{
"name": "stakeManager",
"type": "address",
"indexed": true,
"internalType": "address"
}
],
"anonymous": false
},
{
"type": "error",
"name": "InvalidBps",
"inputs": []
},
{
"type": "error",
"name": "NothingToSettle",
"inputs": []
},
{
"type": "error",
"name": "OwnableInvalidOwner",
"inputs": [
{
"name": "owner",
"type": "address",
"internalType": "address"
}
]
},
{
"type": "error",
"name": "OwnableUnauthorizedAccount",
"inputs": [
{
"name": "account",
"type": "address",
"internalType": "address"
}
]
},
{
"type": "error",
"name": "ReentrancyGuardReentrantCall",
"inputs": []
},
{
"type": "error",
"name": "ZeroAddress",
"inputs": []
}
]
0x604060808152600480361015610055575b50361561001b575f80fd5b60207f7181dcb6fe2d63f99c1a50bcadf653f97125398dafe17be204de3d681a5a6f469161004b346005546107af565b60055551348152a1005b5f90813560e01c9081630e7c67fc1461070157816311da60b4146104b35781631d5514f71461048d5781631ee56788146103ef578163249d39e9146103d257816326741e7d146103bb578163715018a6146103535781637542ff951461032a57816379ba50971461029e57816379cb75431461027f5781638da5cb5b14610257578163be8dd9be14610238578163c872df9514610219578163d89135cd146101fa578163e30c3978146101d1578163efca2eed146101b2578163f2fde38b14610143575063fccc28130361001057903461013f578160031936011261013f576020905161dead8152f35b5080fd5b90503461013f57602036600319011261013f57356001600160a01b03818116918290036101ae57610172610784565b600180546001600160a01b031916831790558254167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227008380a380f35b8280fd5b82843461013f578160031936011261013f576020906008549051908152f35b82843461013f578160031936011261013f5760015490516001600160a01b039091168152602090f35b82843461013f578160031936011261013f576020906007549051908152f35b82843461013f578160031936011261013f576020906006549051908152f35b82843461013f578160031936011261013f576020906005549051908152f35b82843461013f578160031936011261013f57905490516001600160a01b039091168152602090f35b839150346101ae57826003193601126101ae5760209250549051908152f35b905082346101ae57826003193601126101ae57600154916001600160a01b039133838516036103135750506bffffffffffffffffffffffff60a01b8092166001555f549133908316175f553391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a380f35b60249250519063118cdaa760e01b82523390820152fd5b82843461013f578160031936011261013f5760035490516001600160a01b039091168152602090f35b82346103b857806003193601126103b85761036c610784565b600180546001600160a01b03199081169091555f80549182168155906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b80fd5b82806003193601126103b8576103cf6107d0565b80f35b82843461013f578160031936011261013f57602090516127108152f35b905082346101ae5760203660031901126101ae5781359061ffff808316938484036104895761041c610784565b612710851161047b5750907fed9a829a2cfdde32a9397899dd9501ee46a6c93262182c040753e5f42d1ba05791600354948251918660a01c1682526020820152a161ffff60a01b1990911660a09190911b61ffff60a01b161760035580f35b825163c6cc5d7f60e01b8152fd5b8580fd5b82843461013f578160031936011261013f5760209061ffff60035460a01c169051908152f35b82843461013f578160031936011261013f5760028054146106f257600280554780156106e257835461ffff60035460a01c16908181029181830414901517156106cf576127109004908385558082116106c7575b818103908082116106b4578290816105df575b03610557575b7ff5b268a3ff315cc44ccceeef86259c9e8eef81ceecb14001543809115380dd6293945082519182526020820152a1600160025580f35b610563816008546107af565b6008556003546001600160a01b0316803b156105db57848291878651809481936306f4a2cd60e41b83525af180156105d1576105a0575b50610520565b67ffffffffffffffff81959295116105be578352929350838561059a565b634e487b7160e01b825260418652602482fd5b84513d87823e3d90fd5b8480fd5b906105ec906007546107af565b600755848080808661dead5af13d156106af5767ffffffffffffffff3d81811161069c57865191601f8201601f19908116603f011683019081118382101761068957875281528660203d92013e5b1561064657829061051a565b835162461bcd60e51b8152602081880152601e60248201527f5265776172644469737472696275746f723a206275726e206661696c656400006044820152606490fd5b634e487b7160e01b895260418a52602489fd5b634e487b7160e01b885260418952602488fd5b61063a565b634e487b7160e01b855260118652602485fd5b905080610507565b634e487b7160e01b845260118552602484fd5b8151630c30209d60e31b81528490fd5b51633ee5aeb560e01b81529050fd5b839150346101ae5760203660031901126101ae5780356001600160a01b038116929083900361078057610732610784565b8215610773575050600380546001600160a01b031916821790557f18c7cdf94f8233bc399bdc8cb14514437756e7e9c583510d72b3a337f33b14a78280a280f35b5163d92e233d60e01b8152fd5b8380fd5b5f546001600160a01b0316330361079757565b60405163118cdaa760e01b8152336004820152602490fd5b919082018092116107bc57565b634e487b7160e01b5f52601160045260245ffd5b3415610822576107e2346004546107af565b6004556107f1346006546107af565b6006556040513481527f2ccfc58c2cef4ee590b5f16be0548cc54afc12e1c66a67b362b7d640fd16bb2d60203392a2565b56fea264697066735822122001790f8388c1f3f30c77e77a841b455a3566ba0575c4e76935ff011424268eb764736f6c63430008140033
Aucun transfert de token.