Forkchoice Ethereum Mainnet

Address Contract Verified

Address 0xE5f24791E273Cb96A1f8E5B67Bc2397F0AD9B8B4
Balance 0 ETH
Nonce 1
Code Size 6046 bytes
Indexed Transactions 0 (1 on-chain, 1.2% indexed)
External Etherscan · Sourcify

Contract Bytecode

6046 bytes
0x608060405234801561001057600080fd5b506004361061018e5760003560e01c80635c8177a2116100de578063b43612e311610097578063c7ed69cd11610071578063c7ed69cd1461033e578063dc2c256f14610365578063ea0593e414610378578063efdf0bb01461039f57600080fd5b8063b43612e314610319578063b80eacc214610322578063c04637111461033557600080fd5b80635c8177a2146102a957806370a08231146102b85780637496cbb2146102d85780637acb7757146102eb5780637bc6729b146102fe578063b3ab15fb1461030657600080fd5b8063252408101161014b578063402914f511610125578063402914f5146102715780634ae4ab92146102845780635668a7341461028d578063570ca7351461029657600080fd5b806325240810146102385780632e17de781461024b5780632ff3e04e1461025e57600080fd5b80631112b18314610193578063128fced1146101af57806312d43a51146101cf57806318160ddd146101fa5780631e83409a14610203578063233e4daa14610218575b600080fd5b61019c60055481565b6040519081526020015b60405180910390f35b61019c6101bd3660046115ed565b600b6020526000908152604090205481565b6000546101e2906001600160a01b031681565b6040516001600160a01b0390911681526020016101a6565b61019c60085481565b6102166102113660046115ed565b6103b2565b005b61019c6102263660046115ed565b600a6020526000908152604090205481565b6001546101e2906001600160a01b031681565b61021661025936600461160f565b61061d565b61021661026c36600461160f565b61089f565b61019c61027f3660046115ed565b610af7565b61019c60075481565b61019c60045481565b6002546101e2906001600160a01b031681565b61019c670de0b6b3a764000081565b61019c6102c63660046115ed565b60096020526000908152604090205481565b6102166102e636600461160f565b610c38565b6102166102f9366004611628565b610e50565b610216611126565b6102166103143660046115ed565b611199565b61019c60035481565b61021661033036600461160f565b6111e5565b61019c60065481565b6101e27f000000000000000000000000ad038eb671c44b853887a7e32528fab35dc5d71081565b610216610373366004611654565b6113ea565b6101e27f000000000000000000000000865377367054516e17014ccded1e7d814edc9ce481565b6102166103ad3660046115ed565b611585565b336000600654426103c391906116a6565b9050801561047f5760006005541180156103df57506000600854115b1561047a57600854600554600454600090670de0b6b3a7640000906104059085906116bf565b61040f91906116d6565b905060008183116104205782610422565b815b905060006301e13380670de0b6b3a764000061043e84896116bf565b61044891906116bf565b61045291906116d6565b905061045e85826116d6565b6007600082825461046f91906116f8565b909155505050505050505b426006555b6001600160a01b0382166000908152600a60205260408120546007546104a591906116a6565b6001600160a01b0384166000908152600960205260408120549192506104cb83836116bf565b6007546001600160a01b0387166000908152600a602052604090205590506104fb670de0b6b3a7640000826116d6565b6001600160a01b0386166000908152600b6020526040812080549091906105239084906116f8565b9091555050336000908152600b6020526040908190205490516340c10f1960e01b81526001600160a01b038881166004830152602482018390527f000000000000000000000000ad038eb671c44b853887a7e32528fab35dc5d71016906340c10f1990604401600060405180830381600087803b1580156105a357600080fd5b505af11580156105b7573d6000803e3d6000fd5b5050336000818152600b602052604080822091909155516001600160a01b038b1693509091507f70eb43c4a8ae8c40502dcf22436c509c28d6ff421cf07c491be56984bd9870689061060c9085815260200190565b60405180910390a350505050505050565b3360006006544261062e91906116a6565b905080156106ea57600060055411801561064a57506000600854115b156106e557600854600554600454600090670de0b6b3a7640000906106709085906116bf565b61067a91906116d6565b9050600081831161068b578261068d565b815b905060006301e13380670de0b6b3a76400006106a984896116bf565b6106b391906116bf565b6106bd91906116d6565b90506106c985826116d6565b600760008282546106da91906116f8565b909155505050505050505b426006555b6001600160a01b0382166000908152600a602052604081205460075461071091906116a6565b6001600160a01b03841660009081526009602052604081205491925061073683836116bf565b6007546001600160a01b0387166000908152600a60205260409020559050610766670de0b6b3a7640000826116d6565b6001600160a01b0386166000908152600b60205260408120805490919061078e9084906116f8565b909155505033600090815260096020526040812080548892906107b29084906116a6565b9250508190555085600860008282546107cb91906116a6565b909155505060405163a9059cbb60e01b8152336004820152602481018790527f000000000000000000000000865377367054516e17014ccded1e7d814edc9ce46001600160a01b03169063a9059cbb906044016020604051808303816000875af115801561083d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610861919061170b565b5060405186815233907f85082129d87b2fe11527cb1b3b7a520aeb5aa6913f88a3d8757fe40d1db02fdd9060200160405180910390a2505050505050565b6002546001600160a01b031633146108ee5760405162461bcd60e51b815260206004820152600d60248201526c27a7262c9027a822a920aa27a960991b60448201526064015b60405180910390fd5b336000600654426108ff91906116a6565b905080156109bb57600060055411801561091b57506000600854115b156109b657600854600554600454600090670de0b6b3a7640000906109419085906116bf565b61094b91906116d6565b9050600081831161095c578261095e565b815b905060006301e13380670de0b6b3a764000061097a84896116bf565b61098491906116bf565b61098e91906116d6565b905061099a85826116d6565b600760008282546109ab91906116f8565b909155505050505050505b426006555b6001600160a01b0382166000908152600a60205260408120546007546109e191906116a6565b6001600160a01b038416600090815260096020526040812054919250610a0783836116bf565b6007546001600160a01b0387166000908152600a60205260409020559050610a37670de0b6b3a7640000826116d6565b6001600160a01b0386166000908152600b602052604081208054909190610a5f9084906116f8565b9091555050600354861115610ab65760405162461bcd60e51b815260206004820152601760248201527f524557415244204255444745542041424f5645204d415800000000000000000060448201526064016108e5565b60058690556040518681527fe9b8cf04d04098f4f772ee11940e4d3013e01f0b28e36bd2952b27bf4dcf3f84906020015b60405180910390a1505050505050565b6008546005546007546006546000939291908490610b1590426116a6565b90506000670de0b6b3a764000085600454610b3091906116bf565b610b3a91906116d6565b90506000818511610b4b5784610b4d565b815b905060006301e13380670de0b6b3a7640000610b6984876116bf565b610b7391906116bf565b610b7d91906116d6565b905060008711610b8d5784610ba1565b610b9787826116d6565b610ba190866116f8565b6001600160a01b038a166000908152600a602052604081205491965090610bc890876116a6565b6001600160a01b038b16600090815260096020526040812054919250670de0b6b3a7640000610bf784846116bf565b610c0191906116d6565b6001600160a01b038d166000908152600b6020526040902054909150610c289082906116f8565b9c9b505050505050505050505050565b6000546001600160a01b03163314610c625760405162461bcd60e51b81526004016108e59061172d565b33600060065442610c7391906116a6565b90508015610d2f576000600554118015610c8f57506000600854115b15610d2a57600854600554600454600090670de0b6b3a764000090610cb59085906116bf565b610cbf91906116d6565b90506000818311610cd05782610cd2565b815b905060006301e13380670de0b6b3a7640000610cee84896116bf565b610cf891906116bf565b610d0291906116d6565b9050610d0e85826116d6565b60076000828254610d1f91906116f8565b909155505050505050505b426006555b6001600160a01b0382166000908152600a6020526040812054600754610d5591906116a6565b6001600160a01b038416600090815260096020526040812054919250610d7b83836116bf565b6007546001600160a01b0387166000908152600a60205260409020559050610dab670de0b6b3a7640000826116d6565b6001600160a01b0386166000908152600b602052604081208054909190610dd39084906116f8565b90915550506003869055600554861015610e205760058690556040518681527fe9b8cf04d04098f4f772ee11940e4d3013e01f0b28e36bd2952b27bf4dcf3f849060200160405180910390a15b6040518681527fcdfb72d695c0be67131e063cb64f862be63e79b490d5e30c1942bf6c6f93785c90602001610ae7565b80600060065442610e6191906116a6565b90508015610f1d576000600554118015610e7d57506000600854115b15610f1857600854600554600454600090670de0b6b3a764000090610ea39085906116bf565b610ead91906116d6565b90506000818311610ebe5782610ec0565b815b905060006301e13380670de0b6b3a7640000610edc84896116bf565b610ee691906116bf565b610ef091906116d6565b9050610efc85826116d6565b60076000828254610f0d91906116f8565b909155505050505050505b426006555b6001600160a01b0382166000908152600a6020526040812054600754610f4391906116a6565b6001600160a01b038416600090815260096020526040812054919250610f6983836116bf565b6007546001600160a01b0387166000908152600a60205260409020559050610f99670de0b6b3a7640000826116d6565b6001600160a01b0386166000908152600b602052604081208054909190610fc19084906116f8565b90915550506001600160a01b03861661100b5760405162461bcd60e51b815260206004820152600c60248201526b5a65726f206164647265737360a01b60448201526064016108e5565b6001600160a01b038616600090815260096020526040812080548992906110339084906116f8565b92505081905550866008600082825461104c91906116f8565b90915550506040516323b872dd60e01b8152336004820152306024820152604481018890527f000000000000000000000000865377367054516e17014ccded1e7d814edc9ce46001600160a01b0316906323b872dd906064016020604051808303816000875af11580156110c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e8919061170b565b506040518781526001600160a01b0387169033907f99039fcf0a98f484616c5196ee8b2ecfa971babf0b519848289ea4db381f85f79060200161060c565b6001546001600160a01b031633146111725760405162461bcd60e51b815260206004820152600f60248201526e27b7363c903832b73234b733a3b7bb60891b60448201526064016108e5565b60018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6000546001600160a01b031633146111c35760405162461bcd60e51b81526004016108e59061172d565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b0316331461120f5760405162461bcd60e51b81526004016108e59061172d565b3360006006544261122091906116a6565b905080156112dc57600060055411801561123c57506000600854115b156112d757600854600554600454600090670de0b6b3a7640000906112629085906116bf565b61126c91906116d6565b9050600081831161127d578261127f565b815b905060006301e13380670de0b6b3a764000061129b84896116bf565b6112a591906116bf565b6112af91906116d6565b90506112bb85826116d6565b600760008282546112cc91906116f8565b909155505050505050505b426006555b6001600160a01b0382166000908152600a602052604081205460075461130291906116a6565b6001600160a01b03841660009081526009602052604081205491925061132883836116bf565b6007546001600160a01b0387166000908152600a60205260409020559050611358670de0b6b3a7640000826116d6565b6001600160a01b0386166000908152600b6020526040812080549091906113809084906116f8565b9091555061139e9050670de0b6b3a76400006509184e72a0006116bf565b6113aa906000196116d6565b86106113b557600080fd5b60048690556040518681527f8ff94cc2cb51561da57da775575472199bbc35bc13dbd2ccd05b40267ab9f80790602001610ae7565b6000546001600160a01b031633146114145760405162461bcd60e51b81526004016108e59061172d565b7f000000000000000000000000865377367054516e17014ccded1e7d814edc9ce46001600160a01b0316836001600160a01b03160361150c576008546040516370a0823160e01b81523060048201528391906001600160a01b038616906370a0823190602401602060405180830381865afa158015611497573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114bb919061174f565b6114c591906116a6565b101561150c5760405162461bcd60e51b815260206004820152601660248201527543414e4e4f54205357454550205553455220444f4c4160501b60448201526064016108e5565b60405163a9059cbb60e01b81526001600160a01b0382811660048301526024820184905284169063a9059cbb906044016020604051808303816000875af115801561155b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061157f919061170b565b50505050565b6000546001600160a01b031633146115af5760405162461bcd60e51b81526004016108e59061172d565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b80356001600160a01b03811681146115e857600080fd5b919050565b6000602082840312156115ff57600080fd5b611608826115d1565b9392505050565b60006020828403121561162157600080fd5b5035919050565b6000806040838503121561163b57600080fd5b8235915061164b602084016115d1565b90509250929050565b60008060006060848603121561166957600080fd5b611672846115d1565b925060208401359150611687604085016115d1565b90509250925092565b634e487b7160e01b600052601160045260246000fd5b818103818111156116b9576116b9611690565b92915050565b80820281158282048414176116b9576116b9611690565b6000826116f357634e487b7160e01b600052601260045260246000fd5b500490565b808201808211156116b9576116b9611690565b60006020828403121561171d57600080fd5b8151801515811461160857600080fd5b60208082526008908201526727a7262c9023a7ab60c11b604082015260600190565b60006020828403121561176157600080fd5b505191905056fea2646970667358221220645eb694b13572e4c491a3bbbf7bbfbbdd3348e50a847da54ce126d22d9252d964736f6c63430008150033

Verified Source Code Full Match

Compiler: v0.8.21+commit.d9974bed EVM: paris Optimization: Yes (200 runs)
DolaSavings.sol 206 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;

interface IERC20 {
    function transfer(address, uint) external returns (bool);
    function transferFrom(address, address, uint) external returns (bool);
    function balanceOf(address) external view returns (uint);
}

interface IDBR {
    function mint(address, uint) external;
}

/**
 * @title DolaSavings
 * @dev Smart contract for staking DOLA tokens to earn DBR rewards.
 */
contract DolaSavings {

    IDBR public immutable dbr;
    IERC20 public immutable dola;
    address public gov;
    address public pendingGov;
    address public operator;
    uint public constant mantissa = 10**18;
    uint public maxYearlyRewardBudget;
    uint public maxRewardPerDolaMantissa = 10**18; // 1 DBR per DOLA
    uint public yearlyRewardBudget; // starts at 0
    uint public lastUpdate;
    uint public rewardIndexMantissa;
    uint public totalSupply;
    
    mapping (address => uint) public balanceOf;
    mapping (address => uint) public stakerIndexMantissa;
    mapping (address => uint) public accruedRewards;
 
    /**
     * @dev Modifier to update the reward index for the whole contract as well as for a specific user.
     * Calculates rewards based on the time elapsed and the total supply staked.
     * @param user Address of the user for whom to update the index.
     */
    modifier updateIndex(address user) {
        uint deltaT = block.timestamp - lastUpdate;
        if(deltaT > 0) {
            if(yearlyRewardBudget > 0 && totalSupply > 0) {
                uint _totalSupply = totalSupply;
                uint _yearlyRewardBudget = yearlyRewardBudget;
                uint maxBudget = maxRewardPerDolaMantissa * _totalSupply / mantissa;
                uint budget = _yearlyRewardBudget > maxBudget ? maxBudget : _yearlyRewardBudget;
                uint rewardsAccrued = deltaT * budget * mantissa / 365 days;
                rewardIndexMantissa += rewardsAccrued / _totalSupply;
            }
            lastUpdate = block.timestamp;
        }

        uint deltaIndex = rewardIndexMantissa - stakerIndexMantissa[user];
        uint bal = balanceOf[user];
        uint stakerDelta = bal * deltaIndex;
        stakerIndexMantissa[user] = rewardIndexMantissa;
        accruedRewards[user] += stakerDelta / mantissa;
        _;
    }

    modifier onlyGov() {
        require(msg.sender == gov, "ONLY GOV");
        _;
    }

    modifier onlyOperator() {
        require(msg.sender == operator, "ONLY OPERATOR");
        _;
    }

    /**
     * @dev Constructor for DolaSavings.
     * @param _dbr Address of the DBR token contract.
     * @param _dola Address of the DOLA token contract.
     * @param _gov Address of governance.
     * @param _operator Address of the operator.
     */
    constructor (address _dbr, address _dola, address _gov, address _operator) {
        dbr = IDBR(_dbr);
        dola = IERC20(_dola);
        gov = _gov;
        operator = _operator;
        lastUpdate = block.timestamp;
    }

    function setOperator(address _operator) external onlyGov { operator = _operator; }
    function setPendingGov(address _gov) external onlyGov { pendingGov = _gov; }
    function acceptGov() external {
        require(msg.sender == pendingGov, "Only pendingGov");
        gov = pendingGov;
        pendingGov = address(0);
    }

    /**
     * @dev Sets the maximum yearly reward budget.
     * @param _max The maximum yearly reward budget.
     */
    function setMaxYearlyRewardBudget(uint _max) external onlyGov updateIndex(msg.sender) {
        maxYearlyRewardBudget = _max;
        if(yearlyRewardBudget > _max) {
            yearlyRewardBudget = _max;
            emit SetYearlyRewardBudget(_max);
        }
        emit SetMaxYearlyRewardBudget(_max);
    }

    /**
     * @dev Sets the maximum reward per DOLA in mantissa.
     * @param _max The maximum reward per DOLA in mantissa.
     */
    function setMaxRewardPerDolaMantissa(uint _max) external onlyGov updateIndex(msg.sender) {
        require(_max < type(uint).max / (mantissa * 10 ** 13)); //May overflow if set to max and more than 10 trillion DOLA has been deposited
        maxRewardPerDolaMantissa = _max;
        emit SetMaxRewardPerDolaMantissa(_max);
    }

    /**
     * @dev Sets the yearly reward budget.
     * @param _yearlyRewardBudget The yearly reward budget.
     */
    function setYearlyRewardBudget(uint _yearlyRewardBudget) external onlyOperator updateIndex(msg.sender) {
        require(_yearlyRewardBudget <= maxYearlyRewardBudget, "REWARD BUDGET ABOVE MAX");
        yearlyRewardBudget = _yearlyRewardBudget;
        emit SetYearlyRewardBudget(_yearlyRewardBudget);
    }

    /**
     * @dev Stakes DOLA tokens.
     * @param amount The amount of DOLA tokens to stake.
     * @param recipient The address of the recipient.
     */
    function stake(uint amount, address recipient) external updateIndex(recipient) {
        require(recipient != address(0), "Zero address");
        balanceOf[recipient] += amount;
        totalSupply += amount;
        dola.transferFrom(msg.sender, address(this), amount);
        emit Stake(msg.sender, recipient, amount);
    }

    /**
     * @dev Unstakes DOLA tokens.
     * @param amount The amount of DOLA tokens to unstake.
     */
    function unstake(uint amount) external updateIndex(msg.sender) {
        balanceOf[msg.sender] -= amount;
        totalSupply -= amount;
        dola.transfer(msg.sender, amount);
        emit Unstake(msg.sender, amount);
    }

    /**
     * @dev Calculates the claimable rewards for a user.
     * @param user The address of the user.
     * @return The amount of claimable rewards.
     */
    function claimable(address user) external view returns(uint) {
        uint _totalSupply = totalSupply;
        uint _yearlyRewardBudget = yearlyRewardBudget;
        uint _rewardIndexMantissa = rewardIndexMantissa;
        uint deltaT = block.timestamp - lastUpdate;
        uint maxBudget = maxRewardPerDolaMantissa * _totalSupply / mantissa;
        uint budget = _yearlyRewardBudget > maxBudget ? maxBudget : _yearlyRewardBudget;
        uint rewardsAccrued = deltaT * budget * mantissa / 365 days;
        _rewardIndexMantissa = _totalSupply > 0 ? _rewardIndexMantissa + rewardsAccrued / _totalSupply : _rewardIndexMantissa;
        uint deltaIndex = _rewardIndexMantissa - stakerIndexMantissa[user];
        uint bal = balanceOf[user];
        uint stakerDelta = bal * deltaIndex / mantissa;
        return (accruedRewards[user] + stakerDelta);
    }

    /**
     * @dev Claims the accrued rewards of the msg.sender and mints DBR tokens to the specified address.
     * @param to The address to receive the claimed DBR tokens.
     */
    function claim(address to) external updateIndex(msg.sender) {
        uint accrued = accruedRewards[msg.sender];
        dbr.mint(to, accrued);
        accruedRewards[msg.sender] = 0;
        emit Claim(msg.sender, to, accrued);
    }

    /**
     * @dev Transfers out any ERC20 tokens from the contract.
     * Ensures that user staked DOLA cannot be swept.
     * @param token The address of the ERC20 token to sweep.
     * @param amount The amount of tokens to sweep.
     * @param to The recipient address of the swept tokens.
     */
    function sweep(address token, uint amount, address to) external onlyGov {
        if(token == address(dola)) {
            require(IERC20(token).balanceOf(address(this)) - totalSupply >= amount, "CANNOT SWEEP USER DOLA");
        }
        IERC20(token).transfer(to, amount);
    }

    event Stake(address indexed caller, address indexed recipient, uint amount);
    event Unstake(address indexed caller, uint amount);
    event Claim(address indexed caller, address indexed recipient, uint claimed);

    event SetYearlyRewardBudget(uint newYearlyRewardBudget);
    event SetMaxRewardPerDolaMantissa(uint newMax);
    event SetMaxYearlyRewardBudget(uint newMax);
}

Read Contract

accruedRewards 0x128fced1 → uint256
balanceOf 0x70a08231 → uint256
claimable 0x402914f5 → uint256
dbr 0xc7ed69cd → address
dola 0xea0593e4 → address
gov 0x12d43a51 → address
lastUpdate 0xc0463711 → uint256
mantissa 0x5c8177a2 → uint256
maxRewardPerDolaMantissa 0x5668a734 → uint256
maxYearlyRewardBudget 0xb43612e3 → uint256
operator 0x570ca735 → address
pendingGov 0x25240810 → address
rewardIndexMantissa 0x4ae4ab92 → uint256
stakerIndexMantissa 0x233e4daa → uint256
totalSupply 0x18160ddd → uint256
yearlyRewardBudget 0x1112b183 → uint256

Write Contract 10 functions

These functions modify contract state and require a wallet transaction to execute.

acceptGov 0x7bc6729b
No parameters
claim 0x1e83409a
address to
setMaxRewardPerDolaMantissa 0xb80eacc2
uint256 _max
setMaxYearlyRewardBudget 0x7496cbb2
uint256 _max
setOperator 0xb3ab15fb
address _operator
setPendingGov 0xefdf0bb0
address _gov
setYearlyRewardBudget 0x2ff3e04e
uint256 _yearlyRewardBudget
stake 0x7acb7757
uint256 amount
address recipient
sweep 0xdc2c256f
address token
uint256 amount
address to
unstake 0x2e17de78
uint256 amount

Recent Transactions

This address has 1 on-chain transactions, but only 1.2% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →