Address Contract Verified
Address
0x141E4A7eFe8addb63D4a51B30A9a8656CE0678f5
Balance
0 ETH
Nonce
1
Code Size
6029 bytes
Creator
0xcfaD496f...a781 at tx 0x78d0e9df...0f22ea
Indexed Transactions
0 (1 on-chain, 1.3% indexed)
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 →