Forkchoice Ethereum Mainnet

Address Contract Verified

Address 0x141E4A7eFe8addb63D4a51B30A9a8656CE0678f5
Balance 0 ETH
Nonce 1
Code Size 6029 bytes
Indexed Transactions 0 (1 on-chain, 1.3% indexed)
External Etherscan · Sourcify

Contract Bytecode

6029 bytes
0x608060405234801561000f575f80fd5b5060043610610115575f3560e01c806380f55605116100ad578063b69ef8a81161007d578063c6def07611610063578063c6def076146102b0578063f1068454146102d7578063fc0c546a146102fe575f80fd5b8063b69ef8a814610287578063c40768761461029d575f80fd5b806380f55605146101fc578063923c1d611461021b578063a262f5f814610242578063a7cd52cb14610255575f80fd5b8063485cc955116100e8578063485cc955146101935780634e71d92d146101a657806366666aa9146101ae5780636a4874a1146101d5575f80fd5b806312c93f591461011957806317d4bcb21461012357806327c45be21461013657806338af3eed14610149575b5f80fd5b61012161031e565b005b6101216101313660046115d4565b610485565b6101216101443660046115d4565b61055e565b6002546101699073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101216101a13660046115ef565b610628565b6101216107d0565b6101697f000000000000000000000000f1d547f657a05a4a081f899070a5585eb9f326b281565b6101697f000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd5281565b5f546101699073ffffffffffffffffffffffffffffffffffffffff1681565b6101697f0000000000000000000000004e3fbd56cd56c3e72c1403e103b45db9da5b9d2b81565b6101216102503660046115d4565b61082c565b6102776102633660046115d4565b60036020525f908152604090205460ff1681565b604051901515815260200161018a565b61028f610edd565b60405190815260200161018a565b6101216102ab366004611626565b611028565b6101697f000000000000000000000000f403c135812408bfbe8713b5a23a04b3d48aae3181565b61028f7f000000000000000000000000000000000000000000000000000000000000018e81565b6001546101699073ffffffffffffffffffffffffffffffffffffffff1681565b6001546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa15801561038a573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103ae9190611650565b9050805f036103ba5750565b6040517f43a0d0660000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000018e600482015260248101829052600160448201527f000000000000000000000000f403c135812408bfbe8713b5a23a04b3d48aae3173ffffffffffffffffffffffffffffffffffffffff16906343a0d066906064015f604051808303815f87803b15801561046c575f80fd5b505af115801561047e573d5f803e3d5ffd5b5050505050565b60025473ffffffffffffffffffffffffffffffffffffffff1633146104d6576040517f5e5a974900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f8181526003602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811790915591519182527fa8c68afffac3bb44579becca67bdab8c093d0b3a192fe11f29f28622ad1ea87a91015b60405180910390a250565b60025473ffffffffffffffffffffffffffffffffffffffff1633146105af576040517f5e5a974900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f81815260036020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055519182527fa8c68afffac3bb44579becca67bdab8c093d0b3a192fe11f29f28622ad1ea87a9101610553565b5f5473ffffffffffffffffffffffffffffffffffffffff1615610677576040517f0dc149f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8054337fffffffffffffffffffffffff0000000000000000000000000000000000000000918216179091556001805490911673ffffffffffffffffffffffffffffffffffffffff8481169182179092556040517f095ea7b30000000000000000000000000000000000000000000000000000000081527f000000000000000000000000f403c135812408bfbe8713b5a23a04b3d48aae3190921660048301527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60248301529063095ea7b3906044016020604051808303815f875af1158015610763573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107879190611667565b50600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905550565b60025473ffffffffffffffffffffffffffffffffffffffff163314610821576040517f5e5a974900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61082a3361082c565b565b60025473ffffffffffffffffffffffffffffffffffffffff1633148015906108635750335f9081526003602052604090205460ff16155b1561089a576040517f1efc249000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f7050ccd9000000000000000000000000000000000000000000000000000000008152306004820152600160248201527f000000000000000000000000f1d547f657a05a4a081f899070a5585eb9f326b273ffffffffffffffffffffffffffffffffffffffff1690637050ccd9906044016020604051808303815f875af115801561092a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061094e9190611667565b506040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f907f000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd5273ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156109d9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109fd9190611650565b90508015610a4657610a4673ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000d533a949740bb3306d119cc777fa900ba034cd521683836112f4565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f907f0000000000000000000000004e3fbd56cd56c3e72c1403e103b45db9da5b9d2b73ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610ad0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610af49190611650565b90508015610b3d57610b3d73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004e3fbd56cd56c3e72c1403e103b45db9da5b9d2b1684836112f4565b5f7f000000000000000000000000f1d547f657a05a4a081f899070a5585eb9f326b273ffffffffffffffffffffffffffffffffffffffff1663d55a23f46040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ba7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bcb9190611650565b9050805f03610bda5750505050565b5f5b8181101561047e576040517f40c35446000000000000000000000000000000000000000000000000000000008152600481018290525f907f000000000000000000000000f1d547f657a05a4a081f899070a5585eb9f326b273ffffffffffffffffffffffffffffffffffffffff16906340c3544690602401602060405180830381865afa158015610c6f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c939190611686565b90505f60977f000000000000000000000000000000000000000000000000000000000000018e10610d9f578173ffffffffffffffffffffffffffffffffffffffff1663f7c618c16040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d07573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d2b9190611686565b73ffffffffffffffffffffffffffffffffffffffff1663fc0c546a6040518163ffffffff1660e01b81526004016020604051808303815f875af1158015610d74573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d989190611686565b9050610e0f565b8173ffffffffffffffffffffffffffffffffffffffff1663f7c618c16040518163ffffffff1660e01b8152600401602060405180830381865afa158015610de8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e0c9190611686565b90505b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9073ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015610e79573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e9d9190611650565b90508015610ec657610ec673ffffffffffffffffffffffffffffffffffffffff831689836112f4565b50505080610ed3906116ce565b9050610bdc565b50565b6001546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610f49573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f6d9190611650565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000f1d547f657a05a4a081f899070a5585eb9f326b273ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610ff5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110199190611650565b6110239190611705565b905090565b5f5473ffffffffffffffffffffffffffffffffffffffff163314611078576040517f9e0125a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9173ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156110e4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111089190611650565b905081811061113a576001546111359073ffffffffffffffffffffffffffffffffffffffff1684846112f4565b505050565b5f6111458284611718565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529091505f9073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000f1d547f657a05a4a081f899070a5585eb9f326b216906370a0823190602401602060405180830381865afa1580156111d2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111f69190611650565b905080156112d4575f82821161120c578161120e565b825b905061121a8184611718565b6040517fc32e7202000000000000000000000000000000000000000000000000000000008152600481018390525f60248201529093507f000000000000000000000000f1d547f657a05a4a081f899070a5585eb9f326b273ffffffffffffffffffffffffffffffffffffffff169063c32e7202906044016020604051808303815f875af11580156112ad573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112d19190611667565b50505b60015461047e9073ffffffffffffffffffffffffffffffffffffffff1686865b6040805173ffffffffffffffffffffffffffffffffffffffff848116602483015260448083018590528351808403909101815260649092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052611135918591905f9061138c90841683611404565b905080515f141580156113b05750808060200190518101906113ae9190611667565b155b15611135576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024015b60405180910390fd5b606061141183835f61141a565b90505b92915050565b60608147101561145f576040517fcf479181000000000000000000000000000000000000000000000000000000008152476004820152602481018390526044016113fb565b5f808573ffffffffffffffffffffffffffffffffffffffff168486604051611487919061172b565b5f6040518083038185875af1925050503d805f81146114c1576040519150601f19603f3d011682016040523d82523d5f602084013e6114c6565b606091505b50915091506114d68683836114e2565b925050505b9392505050565b6060826114f7576114f282611571565b6114db565b815115801561151b575073ffffffffffffffffffffffffffffffffffffffff84163b155b1561156a576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016113fb565b50806114db565b8051156115815780518082602001fd5b6040517fd6bda27500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81168114610eda575f80fd5b5f602082840312156115e4575f80fd5b81356114db816115b3565b5f8060408385031215611600575f80fd5b823561160b816115b3565b9150602083013561161b816115b3565b809150509250929050565b5f8060408385031215611637575f80fd5b8235611642816115b3565b946020939093013593505050565b5f60208284031215611660575f80fd5b5051919050565b5f60208284031215611677575f80fd5b815180151581146114db575f80fd5b5f60208284031215611696575f80fd5b81516114db816115b3565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036116fe576116fe6116a1565b5060010190565b80820180821115611414576114146116a1565b81810381811115611414576114146116a1565b5f82515f5b8181101561174a5760208186018101518583015201611730565b505f92019182525091905056fea264697066735822122003ef5ea89b6ed2d4bf5a0537d84b28b85e87574c154f47f42ea67870c26d9c4064736f6c63430008140033

Verified Source Code Full Match

Compiler: v0.8.20+commit.a1b79de6 EVM: shanghai Optimization: Yes (10000 runs)
IRewardPool.sol 25 lines
pragma solidity ^0.8.13;

interface IRewardPool {
    function withdraw(uint256 amount, bool claim) external returns (bool);

    function withdrawAndUnwrap(
        uint256 amount,
        bool claim
    ) external returns (bool);

    function getReward(
        address account,
        bool claimExtras
    ) external returns (bool);

    function getReward() external returns (bool);

    function balanceOf(address account) external view returns (uint256);

    function extraRewardsLength() external view returns (uint);

    function rewardToken() external view returns (address);

    function extraRewards(uint256 index) external view returns (address);
}
IConvexBooster.sol 9 lines
pragma solidity ^0.8.13;

interface IConvexBooster {
    function withdraw(uint256 pid, uint256 _amount) external;

    function deposit(uint256 pid, uint256 amount, bool stake) external;

    function earmarkRewards(uint256 pid) external;
}
ConvexEscrowV2.sol 188 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import {IRewardPool} from "src/interfaces/IRewardPool.sol";
import {IConvexBooster} from "src/interfaces/IConvexBooster.sol";
import {IVirtualBalanceRewardPool} from "src/interfaces/IVirtualBalanceRewardPool.sol";

// StakingWrapper interface for pools with pid 151+
interface IStakingWrapper {
    function token() external returns (address);
}

contract ConvexEscrowV2 {
    using SafeERC20 for IERC20;

    error AlreadyInitialized();
    error OnlyMarket();
    error OnlyBeneficiary();
    error OnlyBeneficiaryOrAllowlist();

    uint256 public immutable pid;

    IRewardPool public immutable rewardPool;
    IConvexBooster public immutable booster;
    IERC20 public immutable cvx;
    IERC20 public immutable crv;

    address public market;
    IERC20 public token;
    address public beneficiary;

    mapping(address => bool) public allowlist;

    modifier onlyBeneficiary() {
        if (msg.sender != beneficiary) revert OnlyBeneficiary();
        _;
    }

    modifier onlyBeneficiaryOrAllowlist() {
        if (msg.sender != beneficiary && !allowlist[msg.sender])
            revert OnlyBeneficiaryOrAllowlist();
        _;
    }

    event AllowClaim(address indexed allowedAddress, bool allowed);

    constructor(
        address _rewardPool,
        address _booster,
        address _cvx,
        address _crv,
        uint256 _pid
    ) {
        rewardPool = IRewardPool(_rewardPool);
        booster = IConvexBooster(_booster);
        cvx = IERC20(_cvx);
        crv = IERC20(_crv);
        pid = _pid;
    }

    /**
    @notice Initialize escrow with a token
    @dev Must be called right after proxy is created.
    @param _token The IERC20 token representing the governance token
    @param _beneficiary The beneficiary who the token is staked on behalf
    */
    function initialize(IERC20 _token, address _beneficiary) public {
        if (market != address(0)) revert AlreadyInitialized();
        market = msg.sender;
        token = _token;
        token.approve(address(booster), type(uint).max);
        beneficiary = _beneficiary;
    }

    /**
    @notice Withdraws the wrapped token from the reward pool and transfers the associated ERC20 token to a recipient.
    @dev Will first try to pay from the escrow balance, if not enough or any, will try to pay the missing amount withdrawing from Convex
    @param recipient The address to receive payment from the escrow
    @param amount The amount of ERC20 token to be transferred.
    */
    function pay(address recipient, uint amount) public {
        if (msg.sender != market) revert OnlyMarket();
        uint256 tokenBal = token.balanceOf(address(this));

        if (tokenBal >= amount) {
            token.safeTransfer(recipient, amount);
            return;
        }

        uint256 missingAmount = amount - tokenBal;
        uint256 convexBalance = rewardPool.balanceOf(address(this));
        if (convexBalance > 0) {
            uint256 withdrawAmount = convexBalance > missingAmount
                ? missingAmount
                : convexBalance;
            missingAmount -= withdrawAmount;
            rewardPool.withdrawAndUnwrap(withdrawAmount, false);
        }

        token.safeTransfer(recipient, amount);
    }

    /**
    @notice Get the token balance of the escrow
    @return Uint representing the token balance of the escrow
    */
    function balance() public view returns (uint) {
        return
            rewardPool.balanceOf(address(this)) +
            token.balanceOf(address(this));
    }

    /**
    @notice Function called by market on deposit. Stakes deposited collateral into Convex reward pool
    @dev This function should remain callable by anyone to handle direct inbound transfers.
    */
    function onDeposit() public {
        uint256 tokenBal = token.balanceOf(address(this));
        if (tokenBal == 0) return;
        booster.deposit(pid, tokenBal, true);
    }

    /**
    @notice Claims reward tokens to the specified address. Only callable by beneficiary and allowlisted addresses
    @param to Address to send claimed rewards to
    */
    function claimTo(address to) public onlyBeneficiaryOrAllowlist {
        //Claim rewards
        rewardPool.getReward(address(this), true);
        //Send crv balance
        uint256 crvBal = crv.balanceOf(address(this));
        if (crvBal != 0) crv.safeTransfer(to, crvBal);
        //Send cvx balance
        uint256 cvxBal = cvx.balanceOf(address(this));
        if (cvxBal != 0) cvx.safeTransfer(to, cvxBal);

        //Send contract balance of extra rewards
        uint256 rewardLength = rewardPool.extraRewardsLength();
        if (rewardLength == 0) return;
        for (uint rewardIndex; rewardIndex < rewardLength; ++rewardIndex) {
            IVirtualBalanceRewardPool virtualReward = IVirtualBalanceRewardPool(
                rewardPool.extraRewards(rewardIndex)
            );
            IERC20 rewardToken;
            if (pid >= 151) {
                rewardToken = IERC20(
                    IStakingWrapper(address(virtualReward.rewardToken()))
                        .token()
                );
            } else {
                rewardToken = virtualReward.rewardToken();
            }

            uint rewardBal = rewardToken.balanceOf(address(this));
            if (rewardBal > 0) {
                //Use safe transfer in case bad reward token is added
                rewardToken.safeTransfer(to, rewardBal);
            }
        }
    }

    /**
    @notice Claims reward tokens to the message sender. Only callable by beneficiary and allowlisted addresses
    */
    function claim() external onlyBeneficiary {
        claimTo(msg.sender);
    }

    /**
    @notice Allow address to claim on behalf of the beneficiary to any address
    @param allowee Address that are allowed to claim on behalf of the beneficiary
    @dev Can be used to build contracts for auto-compounding cvxCrv, auto-buying DBR or auto-repaying loans
    */
    function allowClaimOnBehalf(address allowee) external onlyBeneficiary {
        allowlist[allowee] = true;
        emit AllowClaim(allowee, true);
    }

    /**
    @notice Disallow address to claim on behalf of the beneficiary to any address
    @param allowee Address that are disallowed to claim on behalf of the beneficiary
    */
    function disallowClaimOnBehalf(address allowee) external onlyBeneficiary {
        allowlist[allowee] = false;
        emit AllowClaim(allowee, false);
    }
}
SafeERC20.sol 173 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
import {Address} from "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data);
        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
    }
}
IVirtualBalanceRewardPool.sol 13 lines
pragma solidity ^0.8.13;

import "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";

interface IVirtualBalanceRewardPool {
    function virtualBalance() external view returns (uint256);

    function queueNewRewards(uint256 _rewards) external;

    function operator() external view returns (address);

    function rewardToken() external view returns (IERC20);
}
IERC20.sol 79 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}
IERC1363.sol 86 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1363.sol)

pragma solidity ^0.8.20;

import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}
Address.sol 151 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)

pragma solidity ^0.8.20;

import {Errors} from "./Errors.sol";

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert Errors.InsufficientBalance(address(this).balance, amount);
        }

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert Errors.FailedCall();
        }
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {Errors.FailedCall} error.
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
     * of an unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {Errors.FailedCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
     */
    function _revert(bytes memory returndata) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert Errors.FailedCall();
        }
    }
}
IERC20.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../token/ERC20/IERC20.sol";
IERC165.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../utils/introspection/IERC165.sol";
Errors.sol 26 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

/**
 * @dev Collection of common custom errors used in multiple contracts
 *
 * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
 * It is recommended to avoid relying on the error API for critical functionality.
 */
library Errors {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error InsufficientBalance(uint256 balance, uint256 needed);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedCall();

    /**
     * @dev The deployment failed.
     */
    error FailedDeployment();
}
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

Read Contract

allowlist 0xa7cd52cb → bool
balance 0xb69ef8a8 → uint256
beneficiary 0x38af3eed → address
booster 0xc6def076 → address
crv 0x6a4874a1 → address
cvx 0x923c1d61 → address
market 0x80f55605 → address
pid 0xf1068454 → uint256
rewardPool 0x66666aa9 → address
token 0xfc0c546a → address

Write Contract 7 functions

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

allowClaimOnBehalf 0x17d4bcb2
address allowee
claim 0x4e71d92d
No parameters
claimTo 0xa262f5f8
address to
disallowClaimOnBehalf 0x27c45be2
address allowee
initialize 0x485cc955
address _token
address _beneficiary
onDeposit 0x12c93f59
No parameters
pay 0xc4076876
address recipient
uint256 amount

Recent Transactions

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