编译器
0.8.11+commit.d7f03943
文件 1 的 6:Address.sol
pragma solidity ^0.8.0;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 6:BoosterHelper.sol
pragma solidity 0.8.11;
import { IERC20 } from "@openzeppelin/contracts-0.8/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts-0.8/token/ERC20/utils/SafeERC20.sol";
import { IBooster } from "../interfaces/IBooster.sol";
import { IRewardStaking } from "../interfaces/IRewardStaking.sol";
interface IBaseRewardPool {
function lastTimeRewardApplicable() external view returns (uint256);
function periodFinish() external view returns (uint256);
function queuedRewards() external view returns (uint256);
function extraRewards(uint256) external view returns (address);
function extraRewardsLength() external view returns (uint256);
}
contract BoosterHelper {
using SafeERC20 for IERC20;
struct PoolInfo {
uint256 pid;
address lptoken;
address token;
address gauge;
address crvRewards;
address stash;
bool shutdown;
}
IBooster public immutable booster;
address public immutable crv;
constructor(address _booster, address _crv) {
booster = IBooster(_booster);
crv = _crv;
}
function earmarkRewards(uint256[] memory _pids) external returns (uint256) {
uint256 len = _pids.length;
require(len > 0, "!pids");
for (uint256 i = 0; i < len; i++) {
require(booster.earmarkRewards(_pids[i]), "!earmark reward");
}
uint256 crvBal = IERC20(crv).balanceOf(address(this));
IERC20(crv).safeTransfer(msg.sender, crvBal);
return crvBal;
}
function processIdleRewards(uint256[] memory _pids) external {
uint256 len = _pids.length;
require(len > 0, "!pids");
for (uint256 i = 0; i < len; i++) {
IBooster.PoolInfo memory poolInfo = booster.poolInfo(_pids[i]);
IRewardStaking baseRewardPool = IRewardStaking(poolInfo.crvRewards);
baseRewardPool.processIdleRewards();
}
}
function processIdleRewardsByAddress(address[] memory _pools) external {
uint256 len = _pools.length;
require(len > 0, "!pools");
for (uint256 i = 0; i < len; i++) {
IRewardStaking baseRewardPool = IRewardStaking(_pools[i]);
baseRewardPool.processIdleRewards();
}
}
function getExpiredPools(uint256 start, uint256 daysToExpiration) external view returns (PoolInfo[] memory) {
uint256 end = booster.poolLength();
PoolInfo[] memory pids = new PoolInfo[](end - start);
uint256 idx = 0;
for (uint256 i = start; i < end; i++) {
IBooster.PoolInfo memory poolInfo = booster.poolInfo(i);
if (_isExpiredWithoutQueuedRewards(poolInfo, daysToExpiration)) {
pids[idx++] = PoolInfo({
pid: i,
lptoken: poolInfo.lptoken,
token: poolInfo.token,
gauge: poolInfo.gauge,
crvRewards: poolInfo.crvRewards,
stash: poolInfo.stash,
shutdown: poolInfo.shutdown
});
}
}
return _sliceArray(pids, idx);
}
function getIdlePoolIds(uint256 start) external view returns (uint256[] memory) {
uint256 end = booster.poolLength();
uint256[] memory pids = new uint256[](end - start);
uint256 idx = 0;
for (uint256 i = start; i < end; i++) {
if (_isExpiredWithQueuedRewards(i)) {
pids[idx++] = i;
}
}
return _sliceArray(pids, idx);
}
function getIdleBaseAndVirtualPools(uint256 start) external view returns (address[] memory) {
uint256 end = booster.poolLength();
address[] memory idlePools = new address[]((end - start) * 2);
uint256 idx = 0;
for (uint256 i = start; i < end; i++) {
IBooster.PoolInfo memory poolInfo = booster.poolInfo(i);
address[] memory virtualRewardPools = _getVirtualRewardPools(poolInfo.crvRewards);
uint256 virtualRewardPoolsLength = virtualRewardPools.length;
for (uint256 j = 0; j < virtualRewardPoolsLength; j++) {
address virtualRewardPool = virtualRewardPools[j];
if (_isExpiredWithQueuedRewards(virtualRewardPool)) {
idlePools[idx++] = virtualRewardPool;
}
}
if (_isExpiredWithQueuedRewards(poolInfo.crvRewards)) {
idlePools[idx++] = poolInfo.crvRewards;
}
}
return _sliceArray(idlePools, idx);
}
function _isExpiredWithoutQueuedRewards(IBooster.PoolInfo memory poolInfo, uint256 daysToExpiration)
internal
view
returns (bool)
{
if (poolInfo.shutdown) return false;
IBaseRewardPool baseRewardPool = IBaseRewardPool(poolInfo.crvRewards);
if (baseRewardPool.queuedRewards() > 0) return false;
uint256 periodFinish = baseRewardPool.periodFinish();
if (block.timestamp > periodFinish) return true;
uint256 lastTimeRewardApplicable = baseRewardPool.lastTimeRewardApplicable();
uint256 daysToNextEarmark = (periodFinish - lastTimeRewardApplicable) / 86400;
return daysToNextEarmark <= daysToExpiration;
}
function _isExpiredWithQueuedRewards(uint256 pid) internal view returns (bool) {
IBooster.PoolInfo memory poolInfo = booster.poolInfo(pid);
if (poolInfo.shutdown) return false;
return _isExpiredWithQueuedRewards(poolInfo.crvRewards);
}
function _isExpiredWithQueuedRewards(address crvRewards) internal view returns (bool) {
IBaseRewardPool baseRewardPool = IBaseRewardPool(crvRewards);
if (baseRewardPool.queuedRewards() == 0) return false;
return (block.timestamp > baseRewardPool.periodFinish());
}
function _getVirtualRewardPools(address crvRewards) internal view returns (address[] memory) {
IBaseRewardPool baseRewardPool = IBaseRewardPool(crvRewards);
uint256 extraRewardsLength = baseRewardPool.extraRewardsLength();
address[] memory virtualBalanceRewardPools = new address[](extraRewardsLength);
for (uint256 i = 0; i < extraRewardsLength; i++) {
virtualBalanceRewardPools[i] = baseRewardPool.extraRewards(i);
}
return virtualBalanceRewardPools;
}
function _sliceArray(PoolInfo[] memory _arr, uint256 length) internal pure returns (PoolInfo[] memory) {
PoolInfo[] memory arr = new PoolInfo[](length);
for (uint256 i = 0; i < length; i++) {
arr[i] = _arr[i];
}
return arr;
}
function _sliceArray(uint256[] memory _arr, uint256 length) internal pure returns (uint256[] memory) {
uint256[] memory arr = new uint256[](length);
for (uint256 i = 0; i < length; i++) {
arr[i] = _arr[i];
}
return arr;
}
function _sliceArray(address[] memory _arr, uint256 length) internal pure returns (address[] memory) {
address[] memory arr = new address[](length);
for (uint256 i = 0; i < length; i++) {
arr[i] = _arr[i];
}
return arr;
}
}
文件 3 的 6:IBooster.sol
pragma solidity 0.8.11;
interface IBooster {
struct FeeDistro {
address distro;
address rewards;
bool active;
}
function feeTokens(address _token) external returns (FeeDistro memory);
function earmarkFees(address _feeToken) external returns (bool);
struct PoolInfo {
address lptoken;
address token;
address gauge;
address crvRewards;
address stash;
bool shutdown;
}
function earmarkRewards(uint256 _pid) external returns (bool);
function poolLength() external view returns (uint256);
function lockRewards() external view returns (address);
function poolInfo(uint256 _pid) external view returns (PoolInfo memory poolInfo);
function distributeL2Fees(uint256 _amount) external;
function lockIncentive() external view returns (uint256);
function stakerIncentive() external view returns (uint256);
function earmarkIncentive() external view returns (uint256);
function platformFee() external view returns (uint256);
function FEE_DENOMINATOR() external view returns (uint256);
function voteGaugeWeight(address[] calldata _gauge, uint256[] calldata _weight) external returns (bool);
}
文件 4 的 6:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 5 的 6:IRewardStaking.sol
pragma solidity 0.8.11;
interface IRewardStaking {
function getReward(address _account, bool _claimExtras) external;
function getReward(address _account) external;
function getReward(address _account, address _token) external;
function stakeFor(address, uint256) external;
function processIdleRewards() external;
}
文件 6 的 6:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
{
"compilationTarget": {
"contracts/peripheral/BoosterHelper.sol": "BoosterHelper"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 800
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_booster","type":"address"},{"internalType":"address","name":"_crv","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"booster","outputs":[{"internalType":"contract IBooster","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"crv","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_pids","type":"uint256[]"}],"name":"earmarkRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"daysToExpiration","type":"uint256"}],"name":"getExpiredPools","outputs":[{"components":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"address","name":"lptoken","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"gauge","type":"address"},{"internalType":"address","name":"crvRewards","type":"address"},{"internalType":"address","name":"stash","type":"address"},{"internalType":"bool","name":"shutdown","type":"bool"}],"internalType":"struct BoosterHelper.PoolInfo[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"start","type":"uint256"}],"name":"getIdleBaseAndVirtualPools","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"start","type":"uint256"}],"name":"getIdlePoolIds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_pids","type":"uint256[]"}],"name":"processIdleRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_pools","type":"address[]"}],"name":"processIdleRewardsByAddress","outputs":[],"stateMutability":"nonpayable","type":"function"}]