Source Code
Latest 7 from a total of 7 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Shutdown | 23235468 | 186 days ago | IN | 0 FRAX | 0.0001511 | ||||
| Shutdown | 23235464 | 186 days ago | IN | 0 FRAX | 0.0001511 | ||||
| Rebalance | 23018937 | 191 days ago | IN | 0 FRAX | 0.00062776 | ||||
| Rebalance | 23018921 | 191 days ago | IN | 0 FRAX | 0.00066013 | ||||
| Rebalance | 23018260 | 191 days ago | IN | 0 FRAX | 0.00045933 | ||||
| Rebalance | 23018053 | 191 days ago | IN | 0 FRAX | 0.00041795 | ||||
| Rebalance | 22739750 | 198 days ago | IN | 0 FRAX | 0.00005795 |
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 21763472 | 220 days ago | Contract Creation | 0 FRAX |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
CurveStrategy
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {ILiquidityGauge} from "@interfaces/curve/ILiquidityGauge.sol";
import {IMinter} from "@interfaces/curve/IMinter.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "src/Strategy.sol";
/// @title CurveStrategy - Curve Protocol Integration Strategy
/// @notice A strategy implementation for interacting with Curve protocol gauges
/// @dev Extends the base Strategy contract with Curve-specific functionality
/// Key responsibilities:
/// - Syncs and tracks pending rewards from Curve gauges and Sidecar contracts
/// - Handles deposits and withdrawals through Curve liquidity gauges and Sidecar contracts
/// - Executes transactions through a gateway/module manager pattern
contract CurveStrategy is Strategy {
using SafeCast for uint256;
//////////////////////////////////////////////////////
// --- CONSTANTS & IMMUTABLES
//////////////////////////////////////////////////////
/// @notice The bytes4 ID of the Curve protocol
/// @dev Used to identify the Curve protocol in the registry
bytes4 private constant CURVE_PROTOCOL_ID = bytes4(keccak256("CURVE"));
/// @notice Error thrown when the mint fails.
error MintFailed();
/// @notice Error thrown when the checkpoint fails.
error CheckpointFailed();
//////////////////////////////////////////////////////
// --- CONSTRUCTOR
//////////////////////////////////////////////////////
/// @notice Initializes the CurveStrategy contract
/// @param _registry The address of the protocol controller registry
/// @param _locker The address of the locker contract
/// @param _gateway The address of the gateway contract
constructor(address _registry, address _locker, address _gateway)
Strategy(_registry, CURVE_PROTOCOL_ID, _locker, _gateway)
{}
//////////////////////////////////////////////////////
// --- INTERNAL FUNCTIONS
//////////////////////////////////////////////////////
/// @notice Syncs and calculates pending rewards from a Curve gauge
/// @dev Retrieves allocation targets and calculates pending rewards for each target
/// @param gauge The address of the Curve gauge to sync
/// @return pendingRewards A struct containing the total and fee subject pending rewards
function _checkpointRewards(address gauge) internal override returns (PendingRewards memory pendingRewards) {
/// On L2s, the minter is the factory.
address minter = ILiquidityGauge(gauge).factory();
address allocator = PROTOCOL_CONTROLLER.allocator(PROTOCOL_ID);
address[] memory targets = IAllocator(allocator).getAllocationTargets(gauge);
/// @dev Checkpoint the locker
require(
_executeTransaction(gauge, abi.encodeWithSignature("user_checkpoint(address)", LOCKER)), CheckpointFailed()
);
uint256 pendingRewardsAmount;
for (uint256 i = 0; i < targets.length; i++) {
address target = targets[i];
if (target == LOCKER) {
// Calculate pending rewards for the locker by comparing total earned by gauge with already minted tokens
pendingRewardsAmount =
ILiquidityGauge(gauge).integrate_fraction(LOCKER) - IMinter(minter).minted(LOCKER, gauge);
pendingRewards.feeSubjectAmount += pendingRewardsAmount.toUint128();
} else {
// For sidecar contracts, use their getPendingRewards() function
pendingRewardsAmount = ISidecar(target).getPendingRewards();
}
pendingRewards.totalAmount += pendingRewardsAmount.toUint128();
}
}
/// @notice Deposits tokens into a Curve gauge
/// @dev Executes a deposit transaction through the gateway/module manager
/// @param gauge The address of the Curve gauge to deposit into
/// @param amount The amount of tokens to deposit
function _deposit(address, address gauge, uint256 amount) internal override {
bytes memory data = abi.encodeWithSignature("deposit(uint256)", amount);
require(_executeTransaction(gauge, data), DepositFailed());
}
/// @notice Withdraws tokens from a Curve gauge
/// @dev Executes a withdraw transaction through the gateway/module manager
/// @param gauge The address of the Curve gauge to withdraw from
/// @param amount The amount of tokens to withdraw
/// @param receiver The address that will receive the withdrawn tokens
function _withdraw(address asset, address gauge, uint256 amount, address receiver) internal override {
bytes memory data = abi.encodeWithSignature("withdraw(uint256)", amount);
require(_executeTransaction(gauge, data), WithdrawFailed());
// 2. Transfer the LP tokens to receiver
data = abi.encodeWithSignature("transfer(address,uint256)", receiver, amount);
require(_executeTransaction(asset, data), TransferFailed());
}
/// @notice Harvests rewards from a Curve gauge
/// @param gauge The address of the Curve gauge to harvest from
function _harvestLocker(address gauge, bytes memory) internal override returns (uint256 rewardAmount) {
/// On L2s, the minter is the factory.
address minter = ILiquidityGauge(gauge).factory();
/// 1. Snapshot the balance before minting.
uint256 _before = IERC20(REWARD_TOKEN).balanceOf(address(LOCKER));
/// @dev Locker is deployed on mainnet.
/// @dev If the locker is the gateway, we need to mint the rewards via the gateway
/// as it means the strategy is deployed on sidechain.
if (LOCKER != GATEWAY) {
/// 2. Mint the rewards of the gauge to the locker.
IMinter(minter).mint_for(gauge, address(LOCKER));
} else {
/// 2. Mint the rewards of the gauge to the locker via the gateway.
bytes memory data = abi.encodeWithSignature("mint(address)", gauge);
require(_executeTransaction(minter, data), MintFailed());
}
/// 3. Calculate the reward amount.
rewardAmount = IERC20(REWARD_TOKEN).balanceOf(address(LOCKER)) - _before;
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IL2LiquidityGauge {
function reward_data(address arg0)
external
view
returns (
address distributor,
uint256 period_finish,
uint256 rate,
uint256 last_update,
uint256 integral
);
function reward_tokens(uint256 arg0) external view returns (address);
function is_killed() external view returns (bool);
function lp_token() external view returns (address);
}
interface ILiquidityGauge is IERC20 {
event ApplyOwnership(address admin);
event CommitOwnership(address admin);
event Deposit(address indexed provider, uint256 value);
event UpdateLiquidityLimit(
address user, uint256 original_balance, uint256 original_supply, uint256 working_balance, uint256 working_supply
);
event Withdraw(address indexed provider, uint256 value);
function add_reward(address _reward_token, address _distributor) external;
function approve(address _spender, uint256 _value) external returns (bool);
function claim_rewards() external;
function claim_rewards(address _addr) external;
function claim_rewards(address _addr, address _receiver) external;
function claimable_tokens(address addr) external returns (uint256);
function decreaseAllowance(address _spender, uint256 _subtracted_value) external returns (bool);
function deposit(uint256 _value) external;
function deposit(uint256 _value, address _addr) external;
function deposit(uint256 _value, address _addr, bool _claim_rewards) external;
function deposit_reward_token(address _reward_token, uint256 _amount) external;
function increaseAllowance(address _spender, uint256 _added_value) external returns (bool);
function initialize(address _lp_token) external;
function kick(address addr) external;
function set_killed(bool _is_killed) external;
function set_reward_distributor(address _reward_token, address _distributor) external;
function set_rewards_receiver(address _receiver) external;
function transfer(address _to, uint256 _value) external returns (bool);
function transferFrom(address _from, address _to, uint256 _value) external returns (bool);
function user_checkpoint(address addr) external returns (bool);
function withdraw(uint256 _value) external;
function withdraw(uint256 _value, bool _claim_rewards) external;
function allowance(address arg0, address arg1) external view returns (uint256);
function balanceOf(address arg0) external view returns (uint256);
function claimable_reward(address _user, address _reward_token) external view returns (uint256);
function claimed_reward(address _addr, address _token) external view returns (uint256);
function decimals() external view returns (uint256);
function factory() external view returns (address);
function future_epoch_time() external view returns (uint256);
function inflation_rate() external view returns (uint256);
function integrate_checkpoint() external view returns (uint256);
function integrate_checkpoint_of(address arg0) external view returns (uint256);
function integrate_fraction(address arg0) external view returns (uint256);
function integrate_inv_supply(uint256 arg0) external view returns (uint256);
function integrate_inv_supply_of(address arg0) external view returns (uint256);
function is_killed() external view returns (bool);
function lp_token() external view returns (address);
function name() external view returns (string memory);
function period() external view returns (int128);
function period_timestamp(uint256 arg0) external view returns (uint256);
function reward_count() external view returns (uint256);
function reward_data(address arg0)
external
view
returns (
address token,
address distributor,
uint256 period_finish,
uint256 rate,
uint256 last_update,
uint256 integral
);
function reward_integral_for(address arg0, address arg1) external view returns (uint256);
function reward_tokens(uint256 arg0) external view returns (address);
function rewards_receiver(address arg0) external view returns (address);
function symbol() external view returns (string memory);
function totalSupply() external view returns (uint256);
function working_balances(address arg0) external view returns (uint256);
function working_supply() external view returns (uint256);
function admin() external view returns (address);
}/// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.19;
interface IMinter {
function mint_for(address gauge, address account) external;
function minted(address gauge, address account) external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
/**
* @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
*/
function toUint(bool b) internal pure returns (uint256 u) {
assembly ("memory-safe") {
u := iszero(iszero(b))
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {TransientSlot} from "@openzeppelin/contracts/utils/TransientSlot.sol";
import {IERC20, IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {ISidecar} from "src/interfaces/ISidecar.sol";
import {ProtocolContext} from "src/ProtocolContext.sol";
import {IStrategy, IAllocator} from "src/interfaces/IStrategy.sol";
import {IBalanceProvider} from "src/interfaces/IBalanceProvider.sol";
/// @title Strategy - Protocol-agnostic yield strategy orchestrator
/// @notice Manages deposits/withdrawals across multiple yield sources (locker + sidecars)
/// @dev Abstract base that protocol-specific strategies inherit from. Key features:
/// - Routes funds between locker and sidecars based on allocator decisions
/// - Handles reward harvesting with transient storage for gas optimization
/// - Emergency shutdown transfers all funds back to vault
/// - Rebalancing redistributes funds when allocations change
abstract contract Strategy is IStrategy, ProtocolContext {
using SafeCast for uint256;
using SafeERC20 for IERC20;
using TransientSlot for *;
/// @dev Transient storage slot for batching reward transfers during harvest
/// @dev Gas optimization: reduces multiple ERC20 transfers to single batch transfer
bytes32 internal constant FLUSH_AMOUNT_SLOT = keccak256("strategy.flushAmount");
//////////////////////////////////////////////////////
// --- ERRORS & EVENTS
//////////////////////////////////////////////////////
/// @notice Error thrown when the caller is not the vault for the gauge
error OnlyVault();
/// @notice Error thrown when the caller is not the accountant for the strategy
error OnlyAccountant();
/// @notice Error thrown when the caller is not allowed to perform the action
error OnlyAllowed();
/// @notice Error thrown when trying to interact with a shutdown gauge
error GaugeShutdown();
/// @notice Error thrown when the deposit fails
error DepositFailed();
/// @notice Error thrown when the withdraw fails
error WithdrawFailed();
/// @notice Error thrown when the transfer fails
error TransferFailed();
/// @notice Error thrown when the approve fails
error ApproveFailed();
/// @notice Error thrown when rebalance is not needed
error RebalanceNotNeeded();
/// @notice Error thrown when the strategy is already shutdown
error AlreadyShutdown();
/// @notice Error thrown when the transfer to the accountant fails
error TransferToAccountantFailed();
/// @notice Event emitted when the strategy is shutdown
event Shutdown(address indexed gauge);
/// @notice Event emitted when the strategy is rebalanced
event Rebalance(address indexed gauge, address[] targets, uint256[] amounts);
//////////////////////////////////////////////////////
// --- MODIFIERS
//////////////////////////////////////////////////////
/// @notice Restricts functions to the vault associated with the gauge
modifier onlyVault(address gauge) {
require(PROTOCOL_CONTROLLER.vaults(gauge) == msg.sender, OnlyVault());
_;
}
/// @notice Restricts harvest flush operations to the accountant
modifier onlyAccountant() {
require(ACCOUNTANT == msg.sender, OnlyAccountant());
_;
}
/// @notice Allows authorized addresses OR anyone if gauge is shutdown
/// @dev Enables permissionless emergency withdrawals during shutdowns
modifier onlyAllowed(address gauge) {
require(
PROTOCOL_CONTROLLER.allowed(address(this), msg.sender, msg.sig) || PROTOCOL_CONTROLLER.isShutdown(gauge),
OnlyAllowed()
);
_;
}
//////////////////////////////////////////////////////
// --- CONSTRUCTOR
//////////////////////////////////////////////////////
/// @notice Initializes the strategy with registry, protocol ID, and locker and gateway
/// @param _registry The address of the protocol controller
/// @param _protocolId The identifier for the protocol this strategy interacts with
/// @param _locker The address of the locker contract
/// @param _gateway The address of the gateway contract
constructor(address _registry, bytes4 _protocolId, address _locker, address _gateway)
ProtocolContext(_protocolId, _registry, _locker, _gateway)
{}
//////////////////////////////////////////////////////
// --- EXTERNAL FUNCTIONS
//////////////////////////////////////////////////////
/// @notice Deposits LP tokens into gauge/sidecars according to allocator's distribution
/// @dev Called by vault after transferring LP tokens to targets
/// @param allocation Contains targets and amounts for deposit
/// @param policy Whether to harvest rewards during deposit
/// @return pendingRewards Rewards claimed if HARVEST policy
/// @custom:throws GaugeShutdown Prevents deposits to shutdown gauges
function deposit(IAllocator.Allocation calldata allocation, HarvestPolicy policy)
external
override
onlyVault(allocation.gauge)
returns (PendingRewards memory pendingRewards)
{
require(!PROTOCOL_CONTROLLER.isShutdown(allocation.gauge), GaugeShutdown());
// Execute deposits on each target (locker or sidecar)
for (uint256 i; i < allocation.targets.length; i++) {
if (allocation.amounts[i] > 0) {
if (allocation.targets[i] == LOCKER) {
_deposit(allocation.asset, allocation.gauge, allocation.amounts[i]);
} else {
ISidecar(allocation.targets[i]).deposit(allocation.amounts[i]);
}
}
}
pendingRewards = _harvestOrCheckpoint(allocation.gauge, policy);
}
/// @notice Withdraws LP tokens from gauge/sidecars and sends to receiver
/// @dev Skips withdrawal if gauge is shutdown (requires shutdown() instead)
/// @param allocation Contains targets and amounts for withdrawal
/// @param policy Whether to harvest rewards during withdrawal
/// @param receiver Address to receive the LP tokens
/// @return pendingRewards Rewards claimed if HARVEST policy
function withdraw(IAllocator.Allocation calldata allocation, IStrategy.HarvestPolicy policy, address receiver)
external
override
onlyVault(allocation.gauge)
returns (PendingRewards memory pendingRewards)
{
address gauge = allocation.gauge;
// For shutdown gauges, only sync rewards without withdrawing
// @dev Prevents loss of user funds by ensuring no withdrawals after shutdown
if (PROTOCOL_CONTROLLER.isShutdown(gauge)) return _harvestOrCheckpoint(gauge, policy);
// Execute withdrawals from each target
for (uint256 i; i < allocation.targets.length; i++) {
if (allocation.amounts[i] > 0) {
if (allocation.targets[i] == LOCKER) {
_withdraw(allocation.asset, gauge, allocation.amounts[i], receiver);
} else {
ISidecar(allocation.targets[i]).withdraw(allocation.amounts[i], receiver);
}
}
}
return _harvestOrCheckpoint(gauge, policy);
}
/// @notice Claims rewards from gauge and sidecars (accountant batch harvest)
/// @dev Uses transient storage to defer reward transfers for gas efficiency
/// @param gauge The gauge to harvest rewards from
/// @param extraData Protocol-specific data for claiming
/// @return pendingRewards Total rewards claimed from all sources
function harvest(address gauge, bytes memory extraData)
external
override
onlyAccountant
returns (IStrategy.PendingRewards memory pendingRewards)
{
return _harvest(gauge, extraData, true);
}
/// @notice Transfers accumulated rewards to accountant after batch harvest
/// @dev Called once after harvesting multiple gauges to save gas
function flush() public onlyAccountant {
uint256 flushAmount = _getFlushAmount();
if (flushAmount == 0) return;
_transferToAccountant(flushAmount);
_setFlushAmount(0);
}
/// @notice Emergency withdrawal of all funds back to vault
/// @dev Anyone can call if gauge is shutdown, ensuring user fund recovery
/// @param gauge The gauge to withdraw all funds from
/// @custom:throws AlreadyShutdown If already fully withdrawn
function shutdown(address gauge) public onlyAllowed(gauge) {
require(!PROTOCOL_CONTROLLER.isFullyWithdrawn(gauge), AlreadyShutdown());
address vault = PROTOCOL_CONTROLLER.vaults(gauge);
address asset = IERC4626(vault).asset();
address[] memory targets = _getAllocationTargets(gauge);
// Withdraw everything from locker and sidecars to vault
_withdrawFromAllTargets(asset, gauge, targets, vault);
// Prevent double withdrawal
PROTOCOL_CONTROLLER.markGaugeAsFullyWithdrawn(gauge);
emit Shutdown(gauge);
}
/// @notice Redistributes funds between targets when allocations change
/// @dev Withdraws all funds to strategy then re-deposits per new allocation
/// @param gauge The gauge to rebalance
/// @custom:throws RebalanceNotNeeded If only one target (nothing to rebalance)
function rebalance(address gauge) external {
require(!PROTOCOL_CONTROLLER.isShutdown(gauge), GaugeShutdown());
address allocator = PROTOCOL_CONTROLLER.allocator(PROTOCOL_ID);
IERC20 asset = IERC20(PROTOCOL_CONTROLLER.asset(gauge));
uint256 currentBalance = balanceOf(gauge);
address[] memory targets = _getAllocationTargets(gauge);
// Withdraw everything to this contract
_withdrawFromAllTargets(address(asset), gauge, targets, address(this));
// Get new allocation from allocator
IAllocator.Allocation memory allocation =
IAllocator(allocator).getRebalancedAllocation(address(asset), gauge, currentBalance);
uint256 allocationLength = allocation.targets.length;
require(allocationLength > 1, RebalanceNotNeeded());
// Re-deposit according to new allocation
for (uint256 i; i < allocationLength; i++) {
address target = allocation.targets[i];
uint256 amount = allocation.amounts[i];
asset.safeTransfer(target, amount);
if (amount > 0) {
if (target == LOCKER) {
_deposit(address(asset), gauge, amount);
} else {
ISidecar(target).deposit(amount);
}
}
}
emit Rebalance(gauge, allocation.targets, allocation.amounts);
}
/// @notice Total LP tokens managed across all targets for a gauge
/// @dev Sums balances from locker and all sidecars
/// @param gauge The gauge to check balance for
/// @return balance Combined LP token balance
function balanceOf(address gauge) public view virtual returns (uint256 balance) {
address[] memory targets = _getAllocationTargets(gauge);
uint256 length = targets.length;
for (uint256 i; i < length; i++) {
address target = targets[i];
if (target == LOCKER) {
balance += IBalanceProvider(gauge).balanceOf(target);
} else {
balance += ISidecar(target).balanceOf();
}
}
}
//////////////////////////////////////////////////////
// --- INTERNAL HELPER FUNCTIONS
//////////////////////////////////////////////////////
/// @notice Gets allocation targets for a gauge
/// @param gauge The gauge to get targets for
/// @return targets Array of target addresses
function _getAllocationTargets(address gauge) internal view returns (address[] memory targets) {
address allocator = PROTOCOL_CONTROLLER.allocator(PROTOCOL_ID);
targets = IAllocator(allocator).getAllocationTargets(gauge);
}
/// @notice Withdraws assets from all targets
/// @param asset The asset to withdraw
/// @param gauge The gauge to withdraw from
/// @param targets Array of target addresses
/// @param receiver Address to receive the withdrawn assets
function _withdrawFromAllTargets(address asset, address gauge, address[] memory targets, address receiver)
internal
{
uint256 length = targets.length;
for (uint256 i; i < length; i++) {
address target = targets[i];
uint256 balance;
if (target == LOCKER) {
balance = IBalanceProvider(gauge).balanceOf(LOCKER);
if (balance > 0) {
_withdraw(asset, gauge, balance, receiver);
}
} else {
balance = ISidecar(target).balanceOf();
if (balance > 0) {
ISidecar(target).withdraw(balance, receiver);
}
}
}
}
/// @notice Claims rewards from locker and all sidecars
/// @dev Locker rewards are fee-subject, sidecar rewards may not be
/// @param gauge The gauge to harvest from
/// @param extraData Protocol-specific harvest parameters
/// @param deferRewards If true, accumulate in transient storage for batch transfer (gas optimization)
/// @return pendingRewards Total and fee-subject reward amounts
function _harvest(address gauge, bytes memory extraData, bool deferRewards)
internal
returns (IStrategy.PendingRewards memory pendingRewards)
{
address[] memory targets = _getAllocationTargets(gauge);
uint256 pendingRewardsAmount;
uint256 length = targets.length;
for (uint256 i; i < length; i++) {
address target = targets[i];
if (target == LOCKER) {
pendingRewardsAmount = _harvestLocker(gauge, extraData);
pendingRewards.feeSubjectAmount = pendingRewardsAmount.toUint128();
if (deferRewards) {
// Batch transfers: accumulate in transient storage
uint256 currentFlushAmount = _getFlushAmount();
_setFlushAmount(currentFlushAmount + pendingRewardsAmount);
} else {
// Direct transfer for HARVEST policy
_transferToAccountant(pendingRewardsAmount);
}
} else {
pendingRewardsAmount = ISidecar(target).claim();
}
pendingRewards.totalAmount += pendingRewardsAmount.toUint128();
}
return pendingRewards;
}
/// @notice Harvests or synchronizes rewards
/// @param gauge The gauge to harvest or synchronize from
/// @param policy The harvest policy to use
/// @return pendingRewards The pending rewards after harvesting or synchronization
function _harvestOrCheckpoint(address gauge, IStrategy.HarvestPolicy policy)
internal
returns (PendingRewards memory pendingRewards)
{
pendingRewards =
policy == IStrategy.HarvestPolicy.HARVEST ? _harvest(gauge, "", false) : _checkpointRewards(gauge);
}
//////////////////////////////////////////////////////
// --- INTERNAL VIRTUAL FUNCTIONS
//////////////////////////////////////////////////////
/// @notice Gets the flush amount from transient storage
/// @return The flush amount
function _getFlushAmount() internal view virtual returns (uint256) {
return FLUSH_AMOUNT_SLOT.asUint256().tload();
}
/// @notice Sets the flush amount in transient storage
/// @param amount The amount to set
function _setFlushAmount(uint256 amount) internal virtual {
FLUSH_AMOUNT_SLOT.asUint256().tstore(amount);
}
/// @notice Flushes the reward token to the accountant
/// @dev Transfers the specified amount of reward tokens to the accountant
/// @param amount The amount of reward tokens to flush
function _transferToAccountant(uint256 amount) internal {
if (amount > 0) {
bytes memory data = abi.encodeWithSelector(IERC20.transfer.selector, ACCOUNTANT, amount);
require(_executeTransaction(address(REWARD_TOKEN), data), TransferToAccountantFailed());
}
}
/// @notice Synchronizes state of pending rewards.
/// @dev Must be implemented by derived strategies to handle protocol-specific reward collection
/// @param gauge The gauge to synchronize
/// @return Pending rewards collected during synchronization
function _checkpointRewards(address gauge) internal virtual returns (PendingRewards memory);
/// @notice Harvests rewards from the locker
/// @dev Must be implemented by derived strategies to handle protocol-specific reward collection
/// @param gauge The gauge to harvest rewards from
/// @param extraData Additional data needed for harvesting (protocol-specific)
/// @return pendingRewards The pending rewards collected during harvesting
function _harvestLocker(address gauge, bytes memory extraData) internal virtual returns (uint256 pendingRewards);
/// @notice Deposits assets into a specific target
/// @dev Must be implemented by derived strategies to handle protocol-specific deposits
/// @param asset The asset to deposit
/// @param gauge The gauge to deposit into
/// @param amount The amount to deposit
function _deposit(address asset, address gauge, uint256 amount) internal virtual;
/// @notice Withdraws assets from a specific target
/// @dev Must be implemented by derived strategies to handle protocol-specific withdrawals
/// @param asset The asset to withdraw
/// @param gauge The gauge to withdraw from
/// @param amount The amount to withdraw
/// @param receiver The address to receive the withdrawn assets
function _withdraw(address asset, address gauge, uint256 amount, address receiver) internal virtual;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/TransientSlot.sol)
// This file was procedurally generated from scripts/generate/templates/TransientSlot.js.
pragma solidity ^0.8.24;
/**
* @dev Library for reading and writing value-types to specific transient storage slots.
*
* Transient slots are often used to store temporary values that are removed after the current transaction.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* * Example reading and writing values using transient storage:
* ```solidity
* contract Lock {
* using TransientSlot for *;
*
* // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
* bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542;
*
* modifier locked() {
* require(!_LOCK_SLOT.asBoolean().tload());
*
* _LOCK_SLOT.asBoolean().tstore(true);
* _;
* _LOCK_SLOT.asBoolean().tstore(false);
* }
* }
* ```
*
* TIP: Consider using this library along with {SlotDerivation}.
*/
library TransientSlot {
/**
* @dev UDVT that represent a slot holding a address.
*/
type AddressSlot is bytes32;
/**
* @dev Cast an arbitrary slot to a AddressSlot.
*/
function asAddress(bytes32 slot) internal pure returns (AddressSlot) {
return AddressSlot.wrap(slot);
}
/**
* @dev UDVT that represent a slot holding a bool.
*/
type BooleanSlot is bytes32;
/**
* @dev Cast an arbitrary slot to a BooleanSlot.
*/
function asBoolean(bytes32 slot) internal pure returns (BooleanSlot) {
return BooleanSlot.wrap(slot);
}
/**
* @dev UDVT that represent a slot holding a bytes32.
*/
type Bytes32Slot is bytes32;
/**
* @dev Cast an arbitrary slot to a Bytes32Slot.
*/
function asBytes32(bytes32 slot) internal pure returns (Bytes32Slot) {
return Bytes32Slot.wrap(slot);
}
/**
* @dev UDVT that represent a slot holding a uint256.
*/
type Uint256Slot is bytes32;
/**
* @dev Cast an arbitrary slot to a Uint256Slot.
*/
function asUint256(bytes32 slot) internal pure returns (Uint256Slot) {
return Uint256Slot.wrap(slot);
}
/**
* @dev UDVT that represent a slot holding a int256.
*/
type Int256Slot is bytes32;
/**
* @dev Cast an arbitrary slot to a Int256Slot.
*/
function asInt256(bytes32 slot) internal pure returns (Int256Slot) {
return Int256Slot.wrap(slot);
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(AddressSlot slot) internal view returns (address value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(AddressSlot slot, address value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(BooleanSlot slot) internal view returns (bool value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(BooleanSlot slot, bool value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(Bytes32Slot slot) internal view returns (bytes32 value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(Bytes32Slot slot, bytes32 value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(Uint256Slot slot) internal view returns (uint256 value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(Uint256Slot slot, uint256 value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(Int256Slot slot) internal view returns (int256 value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(Int256Slot slot, int256 value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC4626.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";
/**
* @dev Interface of the ERC-4626 "Tokenized Vault Standard", as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*/
interface IERC4626 is IERC20, IERC20Metadata {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.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 {
/**
* @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.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
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.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
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.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
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).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
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 silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}/// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface ISidecar {
function balanceOf() external view returns (uint256);
function deposit(uint256 amount) external;
function withdraw(uint256 amount, address receiver) external;
function getPendingRewards() external returns (uint256);
function getRewardTokens() external view returns (address[] memory);
function claim() external returns (uint256);
function asset() external view returns (IERC20);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {IModuleManager} from "@interfaces/safe/IModuleManager.sol";
import {IAccountant} from "src/interfaces/IAccountant.sol";
import {IProtocolController} from "src/interfaces/IProtocolController.sol";
/// @title ProtocolContext
/// @author Stake DAO
/// @notice Base contract providing shared protocol configuration and transaction execution
/// @dev Inherited by Strategy and other protocol-specific contracts to ensure consistent configuration
contract ProtocolContext {
//////////////////////////////////////////////////////
// --- IMMUTABLES
//////////////////////////////////////////////////////
/// @notice Unique identifier for the protocol (e.g., keccak256("CURVE") for Curve)
/// @dev Used to look up protocol-specific components in ProtocolController
bytes4 public immutable PROTOCOL_ID;
/// @notice The locker contract that holds and manages protocol tokens (e.g., veCRV)
/// @dev On L2s, this may be the same as GATEWAY when no separate locker exists
address public immutable LOCKER;
/// @notice Safe multisig that owns the locker and executes privileged operations
/// @dev All protocol interactions go through this gateway for security
address public immutable GATEWAY;
/// @notice The accountant responsible for tracking rewards and user balances
/// @dev Retrieved from ProtocolController during construction
address public immutable ACCOUNTANT;
/// @notice The main reward token for this protocol (e.g., CRV for Curve)
/// @dev Retrieved from the accountant's configuration
address public immutable REWARD_TOKEN;
/// @notice Reference to the central registry for protocol components
IProtocolController public immutable PROTOCOL_CONTROLLER;
//////////////////////////////////////////////////////
// --- ERRORS
//////////////////////////////////////////////////////
/// @notice Error thrown when a required address is zero
error ZeroAddress();
/// @notice Error thrown when a protocol ID is zero
error InvalidProtocolId();
//////////////////////////////////////////////////////
// --- CONSTRUCTOR
//////////////////////////////////////////////////////
/// @notice Initializes protocol configuration that all inheriting contracts will use
/// @dev Retrieves accountant and reward token from ProtocolController for consistency
/// @param _protocolId The protocol identifier (must match registered protocol in controller)
/// @param _protocolController The protocol controller contract address
/// @param _locker The locker contract address (pass address(0) for L2s where gateway acts as locker)
/// @param _gateway The gateway contract address (Safe multisig)
/// @custom:throws ZeroAddress If protocol controller or gateway is zero
/// @custom:throws InvalidProtocolId If protocol ID is empty
constructor(bytes4 _protocolId, address _protocolController, address _locker, address _gateway) {
require(_protocolController != address(0) && _gateway != address(0), ZeroAddress());
require(_protocolId != bytes4(0), InvalidProtocolId());
GATEWAY = _gateway;
PROTOCOL_ID = _protocolId;
ACCOUNTANT = IProtocolController(_protocolController).accountant(_protocolId);
REWARD_TOKEN = IAccountant(ACCOUNTANT).REWARD_TOKEN();
PROTOCOL_CONTROLLER = IProtocolController(_protocolController);
// L2 optimization: Gateway can act as both transaction executor and token holder
if (_locker == address(0)) {
LOCKER = GATEWAY;
} else {
LOCKER = _locker;
}
}
//////////////////////////////////////////////////////
// --- INTERNAL FUNCTIONS
//////////////////////////////////////////////////////
/// @notice Executes privileged transactions through the Safe module system
/// @dev Handles two execution patterns:
/// - Mainnet: Gateway -> Locker -> Target (locker holds funds and executes)
/// - L2: Gateway acts as locker and executes directly on target
/// @param target The address of the contract to interact with
/// @param data The calldata to send to the target
/// @return success Whether the transaction executed successfully
function _executeTransaction(address target, bytes memory data) internal returns (bool success) {
if (LOCKER == GATEWAY) {
// L2 pattern: Gateway holds funds and executes directly
success = IModuleManager(GATEWAY).execTransactionFromModule(target, 0, data, IModuleManager.Operation.Call);
} else {
// Mainnet pattern: Gateway instructs locker (which holds funds) to execute
// The locker contract has the necessary approvals and balances
success = IModuleManager(GATEWAY).execTransactionFromModule(
LOCKER,
0,
abi.encodeWithSignature("execute(address,uint256,bytes)", target, 0, data),
IModuleManager.Operation.Call
);
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import "src/interfaces/IAllocator.sol";
interface IStrategy {
/// @notice The policy for harvesting rewards.
enum HarvestPolicy {
CHECKPOINT,
HARVEST
}
struct PendingRewards {
uint128 feeSubjectAmount;
uint128 totalAmount;
}
function deposit(IAllocator.Allocation calldata allocation, HarvestPolicy policy)
external
returns (PendingRewards memory pendingRewards);
function withdraw(IAllocator.Allocation calldata allocation, HarvestPolicy policy, address receiver)
external
returns (PendingRewards memory pendingRewards);
function balanceOf(address gauge) external view returns (uint256 balance);
function harvest(address gauge, bytes calldata extraData) external returns (PendingRewards memory pendingRewards);
function flush() external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
interface IBalanceProvider {
function balanceOf(address _address) external view returns (uint256);
function totalSupply() external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC-20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.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);
}// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
/**
* @title IModuleManager - An interface of contract managing Safe modules
* @notice Modules are extensions with unlimited access to a Safe that can be added to a Safe by its owners.
⚠️ WARNING: Modules are a security risk since they can execute arbitrary transactions,
so only trusted and audited modules should be added to a Safe. A malicious module can
completely takeover a Safe.
* @author @safe-global/safe-protocol
*/
interface IModuleManager {
enum Operation {
Call,
DelegateCall
}
event EnabledModule(address indexed module);
event DisabledModule(address indexed module);
event ExecutionFromModuleSuccess(address indexed module);
event ExecutionFromModuleFailure(address indexed module);
event ChangedModuleGuard(address indexed moduleGuard);
/**
* @notice Enables the module `module` for the Safe.
* @dev This can only be done via a Safe transaction.
* @param module Module to be whitelisted.
*/
function enableModule(address module) external;
/**
* @notice Disables the module `module` for the Safe.
* @dev This can only be done via a Safe transaction.
* @param prevModule Previous module in the modules linked list.
* @param module Module to be removed.
*/
function disableModule(address prevModule, address module) external;
/**
* @notice Execute `operation` (0: Call, 1: DelegateCall) to `to` with `value` (Native Token)
* @param to Destination address of module transaction.
* @param value Ether value of module transaction.
* @param data Data payload of module transaction.
* @param operation Operation type of module transaction.
* @return success Boolean flag indicating if the call succeeded.
*/
function execTransactionFromModule(
address to,
uint256 value,
bytes memory data,
Operation operation
) external returns (bool success);
/**
* @notice Execute `operation` (0: Call, 1: DelegateCall) to `to` with `value` (Native Token) and return data
* @param to Destination address of module transaction.
* @param value Ether value of module transaction.
* @param data Data payload of module transaction.
* @param operation Operation type of module transaction.
* @return success Boolean flag indicating if the call succeeded.
* @return returnData Data returned by the call.
*/
function execTransactionFromModuleReturnData(
address to,
uint256 value,
bytes memory data,
Operation operation
) external returns (bool success, bytes memory returnData);
/**
* @notice Returns if a module is enabled
* @return True if the module is enabled
*/
function isModuleEnabled(address module) external view returns (bool);
/**
* @notice Returns an array of modules.
* If all entries fit into a single page, the next pointer will be 0x1.
* If another page is present, next will be the last element of the returned array.
* @param start Start of the page. Has to be a module or start pointer (0x1 address)
* @param pageSize Maximum number of modules that should be returned. Has to be > 0
* @return array Array of modules.
* @return next Start of the next page.
*/
function getModulesPaginated(address start, uint256 pageSize) external view returns (address[] memory array, address next);
/**
* @dev Set a module guard that checks transactions initiated by the module before execution
* This can only be done via a Safe transaction.
* ⚠️ IMPORTANT: Since a module guard has full power to block Safe transaction execution initiated via a module,
* a broken module guard can cause a denial of service for the Safe modules. Make sure to carefully
* audit the module guard code and design recovery mechanisms.
* @notice Set Module Guard `moduleGuard` for the Safe. Make sure you trust the module guard.
* @param moduleGuard The address of the module guard to be used or the zero address to disable the module guard.
*/
function setModuleGuard(address moduleGuard) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import {IStrategy} from "src/interfaces/IStrategy.sol";
interface IAccountant {
function checkpoint(
address gauge,
address from,
address to,
uint128 amount,
IStrategy.PendingRewards calldata pendingRewards,
IStrategy.HarvestPolicy policy
) external;
function checkpoint(
address gauge,
address from,
address to,
uint128 amount,
IStrategy.PendingRewards calldata pendingRewards,
IStrategy.HarvestPolicy policy,
address referrer
) external;
function totalSupply(address asset) external view returns (uint128);
function balanceOf(address asset, address account) external view returns (uint128);
function claim(address[] calldata _vaults, bytes[] calldata harvestData) external;
function claim(address[] calldata _vaults, bytes[] calldata harvestData, address receiver) external;
function claim(address[] calldata _vaults, address account, bytes[] calldata harvestData) external;
function claim(address[] calldata _vaults, address account, bytes[] calldata harvestData, address receiver)
external;
function claimProtocolFees() external;
function harvest(address[] calldata _vaults, bytes[] calldata _harvestData, address _receiver) external;
function REWARD_TOKEN() external view returns (address);
}/// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
interface IProtocolController {
function vaults(address) external view returns (address);
function asset(address) external view returns (address);
function rewardReceiver(address) external view returns (address);
function allowed(address, address, bytes4 selector) external view returns (bool);
function permissionSetters(address) external view returns (bool);
function isRegistrar(address) external view returns (bool);
function strategy(bytes4 protocolId) external view returns (address);
function allocator(bytes4 protocolId) external view returns (address);
function accountant(bytes4 protocolId) external view returns (address);
function feeReceiver(bytes4 protocolId) external view returns (address);
function isShutdown(address) external view returns (bool);
function isFullyWithdrawn(address) external view returns (bool);
function registerVault(address _gauge, address _vault, address _asset, address _rewardReceiver, bytes4 _protocolId)
external;
function setValidAllocationTarget(address _gauge, address _target) external;
function removeValidAllocationTarget(address _gauge, address _target) external;
function isValidAllocationTarget(address _gauge, address _target) external view returns (bool);
function shutdown(address _gauge) external;
function markGaugeAsFullyWithdrawn(address _gauge) external;
function setPermissionSetter(address _setter, bool _allowed) external;
function setPermission(address _contract, address _caller, bytes4 _selector, bool _allowed) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
interface IAllocator {
struct Allocation {
address asset;
address gauge;
address[] targets;
uint256[] amounts;
}
function getDepositAllocation(address asset, address gauge, uint256 amount)
external
view
returns (Allocation memory);
function getWithdrawalAllocation(address asset, address gauge, uint256 amount)
external
view
returns (Allocation memory);
function getRebalancedAllocation(address asset, address gauge, uint256 amount)
external
view
returns (Allocation memory);
function getAllocationTargets(address gauge) external view returns (address[] memory);
}// 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";// 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";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.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);
}{
"remappings": [
"forge-std/=node_modules/forge-std/",
"shared/=node_modules/@stake-dao/shared/",
"layerzerolabs/oft-evm/=node_modules/@layerzerolabs/oft-evm/",
"@safe/=node_modules/@safe-global/safe-smart-account/",
"@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/",
"@interfaces/=node_modules/@stake-dao/interfaces/src/interfaces/",
"@address-book/=node_modules/@stake-dao/address-book/",
"@layerzerolabs/=node_modules/@layerzerolabs/",
"@safe-global/=node_modules/@safe-global/",
"@solady/=node_modules/@solady/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_registry","type":"address"},{"internalType":"address","name":"_locker","type":"address"},{"internalType":"address","name":"_gateway","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyShutdown","type":"error"},{"inputs":[],"name":"ApproveFailed","type":"error"},{"inputs":[],"name":"CheckpointFailed","type":"error"},{"inputs":[],"name":"DepositFailed","type":"error"},{"inputs":[],"name":"GaugeShutdown","type":"error"},{"inputs":[],"name":"InvalidProtocolId","type":"error"},{"inputs":[],"name":"MintFailed","type":"error"},{"inputs":[],"name":"OnlyAccountant","type":"error"},{"inputs":[],"name":"OnlyAllowed","type":"error"},{"inputs":[],"name":"OnlyVault","type":"error"},{"inputs":[],"name":"RebalanceNotNeeded","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"TransferToAccountantFailed","type":"error"},{"inputs":[],"name":"WithdrawFailed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"gauge","type":"address"},{"indexed":false,"internalType":"address[]","name":"targets","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"Rebalance","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"gauge","type":"address"}],"name":"Shutdown","type":"event"},{"inputs":[],"name":"ACCOUNTANT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GATEWAY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LOCKER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROTOCOL_CONTROLLER","outputs":[{"internalType":"contract IProtocolController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROTOCOL_ID","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARD_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"gauge","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"gauge","type":"address"},{"internalType":"address[]","name":"targets","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"internalType":"struct IAllocator.Allocation","name":"allocation","type":"tuple"},{"internalType":"enum IStrategy.HarvestPolicy","name":"policy","type":"uint8"}],"name":"deposit","outputs":[{"components":[{"internalType":"uint128","name":"feeSubjectAmount","type":"uint128"},{"internalType":"uint128","name":"totalAmount","type":"uint128"}],"internalType":"struct IStrategy.PendingRewards","name":"pendingRewards","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"flush","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"gauge","type":"address"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"harvest","outputs":[{"components":[{"internalType":"uint128","name":"feeSubjectAmount","type":"uint128"},{"internalType":"uint128","name":"totalAmount","type":"uint128"}],"internalType":"struct IStrategy.PendingRewards","name":"pendingRewards","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"gauge","type":"address"}],"name":"rebalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"gauge","type":"address"}],"name":"shutdown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"gauge","type":"address"},{"internalType":"address[]","name":"targets","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"internalType":"struct IAllocator.Allocation","name":"allocation","type":"tuple"},{"internalType":"enum IStrategy.HarvestPolicy","name":"policy","type":"uint8"},{"internalType":"address","name":"receiver","type":"address"}],"name":"withdraw","outputs":[{"components":[{"internalType":"uint128","name":"feeSubjectAmount","type":"uint128"},{"internalType":"uint128","name":"totalAmount","type":"uint128"}],"internalType":"struct IStrategy.PendingRewards","name":"pendingRewards","type":"tuple"}],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
610140604052348015610010575f5ffd5b50604051612f7e380380612f7e83398101604081905261002f9161020f565b827fc715e3736a8cb018f630cb9a1df908ad1629e9c2da4cd190b2dc83d6687ba1698383828483836001600160a01b0383161580159061007757506001600160a01b03811615155b6100945760405163d92e233d60e01b815260040160405180910390fd5b6001600160e01b031984166100bc576040516355e7c3d960e11b815260040160405180910390fd5b6001600160a01b0381811660c0526001600160e01b03198516608081905260405163669cc2c960e11b815260048101919091529084169063cd39859290602401602060405180830381865afa158015610117573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061013b919061024f565b6001600160a01b031660e0819052604080516399248ea760e01b815290516399248ea7916004808201926020929091908290030181865afa158015610182573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101a6919061024f565b6001600160a01b03908116610100528381166101205282166101d65760c0516001600160a01b031660a0526101e4565b6001600160a01b03821660a0525b505050505050505050505061026f565b80516001600160a01b038116811461020a575f5ffd5b919050565b5f5f5f60608486031215610221575f5ffd5b61022a846101f4565b9250610238602085016101f4565b9150610246604085016101f4565b90509250925092565b5f6020828403121561025f575f5ffd5b610268826101f4565b9392505050565b60805160a05160c05160e0516101005161012051612b956103e95f395f818161021d015281816102e4015281816103800152818161062d015281816106f50152818161078a01528181610a7101528181610b3601528181611015015281816110ab01528181611150015281816111f8015281816112ff0152818161149c0152611da001525f818161026b015281816118fa0152818161226c015261245f01525f818161024401528181610d8701528181610f8c015261189401525f81816101ba01528181611afd01528181611b6b01528181611bef01526122d901525f818160d4015281816104860152818161093101528181610c0501528181610e49015281816115a6015281816115f4015281816119b701528181611b2701528181611c1e01528181611e8501528181611f2d01528181611f7b0152818161200b0152818161223f015281816123030152818161234f015261243501525f8181610152015281816106cc015281816114680152611d6c0152612b955ff3fe608060405234801561000f575f5ffd5b50600436106100cb575f3560e01c80636b9f96ea116100885780637aaf53e6116100635780637aaf53e6146102185780638b9d29401461023f57806399248ea714610266578063cce2f3fb1461028d575f5ffd5b80636b9f96ea146101dc57806370a08231146101e45780637399bfe814610205575f5ffd5b806308ecd9a6146100cf5780630c96a583146101135780630db41f311461014d57806321c281911461018d5780632d8e2142146101a2578063338c5371146101b5575b5f5ffd5b6100f67f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b61012661012136600461253d565b6102a0565b6040805182516001600160801b03908116825260209384015116928101929092520161010a565b6101747f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160e01b0319909116815260200161010a565b6101a061019b36600461259c565b61060e565b005b6101266101b03660046125b7565b610a2d565b6100f67f000000000000000000000000000000000000000000000000000000000000000081565b6101a0610d85565b6101f76101f236600461259c565b610e10565b60405190815260200161010a565b610126610213366004612683565b610f77565b6100f67f000000000000000000000000000000000000000000000000000000000000000081565b6100f67f000000000000000000000000000000000000000000000000000000000000000081565b6100f67f000000000000000000000000000000000000000000000000000000000000000081565b6101a061029b36600461259c565b610fe8565b604080518082019091525f80825260208201526102c3604084016020850161259c565b604051632988bb9f60e21b81526001600160a01b03828116600483015233917f00000000000000000000000000000000000000000000000000000000000000009091169063a622ee7c90602401602060405180830381865afa15801561032b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061034f919061272a565b6001600160a01b03161461037657604051638d1af8bd60e01b815260040160405180910390fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016634bc5d7356103b5604087016020880161259c565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156103f7573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061041b9190612745565b15610439576040516301970f6d60e71b815260040160405180910390fd5b5f5b6104486040860186612764565b90508110156105ec575f61045f6060870187612764565b8381811061046f5761046f6127b1565b9050602002013511156105e4576001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166104b36040870187612764565b838181106104c3576104c36127b1565b90506020020160208101906104d8919061259c565b6001600160a01b0316036105345761052f6104f6602087018761259c565b610506604088016020890161259c565b6105136060890189612764565b85818110610523576105236127b1565b90506020020135611390565b6105e4565b6105416040860186612764565b82818110610551576105516127b1565b9050602002016020810190610566919061259c565b6001600160a01b031663b6b55f256105816060880188612764565b84818110610591576105916127b1565b905060200201356040518263ffffffff1660e01b81526004016105b691815260200190565b5f604051808303815f87803b1580156105cd575f5ffd5b505af11580156105df573d5f5f3e3d5ffd5b505050505b60010161043b565b50610606610600604086016020870161259c565b846113fd565b949350505050565b604051634bc5d73560e01b81526001600160a01b0382811660048301527f00000000000000000000000000000000000000000000000000000000000000001690634bc5d73590602401602060405180830381865afa158015610672573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106969190612745565b156106b4576040516301970f6d60e71b815260040160405180910390fd5b60405163ef64d76360e01b81526001600160e01b03197f00000000000000000000000000000000000000000000000000000000000000001660048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063ef64d76390602401602060405180830381865afa158015610742573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610766919061272a565b604051634e2333d160e11b81526001600160a01b0384811660048301529192505f917f00000000000000000000000000000000000000000000000000000000000000001690639c4667a290602401602060405180830381865afa1580156107cf573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107f3919061272a565b90505f6107ff84610e10565b90505f61080b85611450565b90506108198386833061157a565b604051632f3c319f60e01b81526001600160a01b0384811660048301528681166024830152604482018490525f9190861690632f3c319f906064015f60405180830381865afa15801561086e573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610895919081019061285b565b604081015151909150600181116108bf57604051635121f34360e01b815260040160405180910390fd5b5f5b818110156109d8575f836040015182815181106108e0576108e06127b1565b602002602001015190505f84606001518381518110610901576109016127b1565b6020026020010151905061092982828a6001600160a01b03166117549092919063ffffffff16565b80156109ce577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03160361097857610973888b83611390565b6109ce565b60405163b6b55f2560e01b8152600481018290526001600160a01b0383169063b6b55f25906024015f604051808303815f87803b1580156109b7575f5ffd5b505af11580156109c9573d5f5f3e3d5ffd5b505050505b50506001016108c1565b50866001600160a01b03167f7999601d1a757a3c60f7cc686ee486ef059e7aa194251eb545a340f5fbba330e83604001518460600151604051610a1c929190612973565b60405180910390a250505050505050565b604080518082019091525f8082526020820152610a50604085016020860161259c565b604051632988bb9f60e21b81526001600160a01b03828116600483015233917f00000000000000000000000000000000000000000000000000000000000000009091169063a622ee7c90602401602060405180830381865afa158015610ab8573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610adc919061272a565b6001600160a01b031614610b0357604051638d1af8bd60e01b815260040160405180910390fd5b5f610b14604087016020880161259c565b604051634bc5d73560e01b81526001600160a01b0380831660048301529192507f000000000000000000000000000000000000000000000000000000000000000090911690634bc5d73590602401602060405180830381865afa158015610b7d573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ba19190612745565b15610bb857610bb081866113fd565b925050610d7d565b5f5b610bc76040880188612764565b9050811015610d6e575f610bde6060890189612764565b83818110610bee57610bee6127b1565b905060200201351115610d66576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016610c326040890189612764565b83818110610c4257610c426127b1565b9050602002016020810190610c57919061259c565b6001600160a01b031603610ca557610ca0610c75602089018961259c565b83610c8360608b018b612764565b85818110610c9357610c936127b1565b90506020020135886117ab565b610d66565b610cb26040880188612764565b82818110610cc257610cc26127b1565b9050602002016020810190610cd7919061259c565b6001600160a01b031662f714ce610cf160608a018a612764565b84818110610d0157610d016127b1565b90506020020135876040518363ffffffff1660e01b8152600401610d389291909182526001600160a01b0316602082015260400190565b5f604051808303815f87803b158015610d4f575f5ffd5b505af1158015610d61573d5f5f3e3d5ffd5b505050505b600101610bba565b50610d7981866113fd565b9250505b509392505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163314610dce5760405163baf4cbdd60e01b815260040160405180910390fd5b7f56d95056ce1c07cd2be5f6ba7c1032b2ced7959a89d4000fbfdb5b75562325485c5f819003610dfb5750565b610e0481611888565b610e0d5f611940565b50565b5f5f610e1b83611450565b80519091505f5b81811015610f6f575f838281518110610e3d57610e3d6127b1565b602002602001015190507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031603610ef9576040516370a0823160e01b81526001600160a01b0382811660048301528716906370a0823190602401602060405180830381865afa158015610ec4573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ee891906129fc565b610ef29086612a27565b9450610f66565b806001600160a01b031663722713f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f35573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f5991906129fc565b610f639086612a27565b94505b50600101610e22565b505050919050565b604080518082019091525f80825260208201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163314610fd35760405163baf4cbdd60e01b815260040160405180910390fd5b610fdf8383600161196a565b90505b92915050565b6040516217798b60e61b81523060048201523360248201525f356001600160e01b031916604482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906305de62c090606401602060405180830381865afa158015611062573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110869190612745565b806111145750604051634bc5d73560e01b81526001600160a01b0382811660048301527f00000000000000000000000000000000000000000000000000000000000000001690634bc5d73590602401602060405180830381865afa1580156110f0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111149190612745565b61113157604051634eaf9b5d60e11b815260040160405180910390fd5b604051631c5543cd60e21b81526001600160a01b0383811660048301527f000000000000000000000000000000000000000000000000000000000000000016906371550f3490602401602060405180830381865afa158015611195573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111b99190612745565b156111d7576040516365eca15b60e11b815260040160405180910390fd5b604051632988bb9f60e21b81526001600160a01b0383811660048301525f917f00000000000000000000000000000000000000000000000000000000000000009091169063a622ee7c90602401602060405180830381865afa15801561123f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611263919061272a565b90505f816001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112a2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112c6919061272a565b90505f6112d285611450565b90506112e08286838661157a565b6040516303f506e960e01b81526001600160a01b0386811660048301527f000000000000000000000000000000000000000000000000000000000000000016906303f506e9906024015f604051808303815f87803b158015611340575f5ffd5b505af1158015611352573d5f5f3e3d5ffd5b50506040516001600160a01b03881692507f28b4c24cb1012c094cd2f59f98e89d791973295f8fda6eaa118022d6d318960a91505f90a25050505050565b5f816040516024016113a491815260200190565b60408051601f198184030181529190526020810180516001600160e01b031663b6b55f2560e01b17905290506113da8382611afa565b6113f7576040516379cacff160e01b815260040160405180910390fd5b50505050565b604080518082019091525f8082526020820152600182600181111561142457611424612a3a565b146114375761143283611ce0565b610fdf565b610fdf8360405180602001604052805f8152505f61196a565b60405163ef64d76360e01b81526001600160e01b03197f00000000000000000000000000000000000000000000000000000000000000001660048201526060905f906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ef64d76390602401602060405180830381865afa1580156114e1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611505919061272a565b60405163db8c1be960e01b81526001600160a01b0385811660048301529192509082169063db8c1be9906024015f60405180830381865afa15801561154c573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526115739190810190612a4e565b9392505050565b81515f5b8181101561174c575f848281518110611599576115996127b1565b602002602001015190505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03160361167e576040516370a0823160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301528816906370a0823190602401602060405180830381865afa158015611641573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061166591906129fc565b9050801561167957611679888883886117ab565b611742565b816001600160a01b031663722713f76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116ba573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116de91906129fc565b9050801561174257604051627b8a6760e11b8152600481018290526001600160a01b03868116602483015283169062f714ce906044015f604051808303815f87803b15801561172b575f5ffd5b505af115801561173d573d5f5f3e3d5ffd5b505050505b505060010161157e565b505050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526117a690849061214e565b505050565b5f826040516024016117bf91815260200190565b60408051601f198184030181529190526020810180516001600160e01b0316632e1a7d4d60e01b17905290506117f58482611afa565b61181257604051631d42c86760e21b815260040160405180910390fd5b6040516001600160a01b03831660248201526044810184905260640160408051601f198184030181529190526020810180516001600160e01b031663a9059cbb60e01b17905290506118648582611afa565b611881576040516312171d8360e31b815260040160405180910390fd5b5050505050565b8015610e0d57604080517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261191f7f000000000000000000000000000000000000000000000000000000000000000082611afa565b61193c576040516304fc2be760e01b815260040160405180910390fd5b5050565b610e0d7f56d95056ce1c07cd2be5f6ba7c1032b2ced7959a89d4000fbfdb5b7556232548826121bf565b604080518082019091525f80825260208201525f61198785611450565b80519091505f90815b81811015611aef575f8482815181106119ab576119ab6127b1565b602002602001015190507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031603611a5c576119f889896121c6565b9350611a03846124dd565b6001600160801b031686528615611a4e577f56d95056ce1c07cd2be5f6ba7c1032b2ced7959a89d4000fbfdb5b75562325485c611a48611a438683612a27565b611940565b50611ac0565b611a5784611888565b611ac0565b806001600160a01b0316634e71d92d6040518163ffffffff1660e01b81526004016020604051808303815f875af1158015611a99573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611abd91906129fc565b93505b611ac9846124dd565b86602001818151611ada9190612a80565b6001600160801b031690525050600101611990565b505050509392505050565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603611bed5760405163468721a760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063468721a790611ba69086905f9087908290600401612acd565b6020604051808303815f875af1158015611bc2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611be69190612745565b9050610fe2565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663468721a77f00000000000000000000000000000000000000000000000000000000000000005f865f87604051602401611c5393929190612b20565b60408051601f198184030181529181526020820180516001600160e01b0316635b0e93fb60e11b1790525160e085901b6001600160e01b0319168152611ca0939291905f90600401612acd565b6020604051808303815f875af1158015611cbc573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fdf9190612745565b604080518082019091525f80825260208201525f826001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d30573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d54919061272a565b60405163ef64d76360e01b81526001600160e01b03197f00000000000000000000000000000000000000000000000000000000000000001660048201529091505f906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ef64d76390602401602060405180830381865afa158015611de5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e09919061272a565b60405163db8c1be960e01b81526001600160a01b0386811660048301529192505f9183169063db8c1be9906024015f60405180830381865afa158015611e51573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611e789190810190612a4e565b6040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166024820152909150611ee590869060440160408051601f198184030181529190526020810180516001600160e01b0316634b82009360e01b179052611afa565b611f0257604051630d027b0960e41b815260040160405180910390fd5b5f805b8251811015612144575f838281518110611f2157611f216127b1565b602002602001015190507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036120b1576040516308b752bb60e41b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301528981166024830152871690638b752bb090604401602060405180830381865afa158015611fd0573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ff491906129fc565b604051630940070760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301528a1690630940070790602401602060405180830381865afa158015612058573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061207c91906129fc565b6120869190612b4c565b9250612091836124dd565b875188906120a0908390612a80565b6001600160801b0316905250612115565b806001600160a01b031663d9621f9e6040518163ffffffff1660e01b81526004016020604051808303815f875af11580156120ee573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061211291906129fc565b92505b61211e836124dd565b8760200181815161212f9190612a80565b6001600160801b031690525050600101611f05565b5050505050919050565b5f5f60205f8451602086015f885af18061216d576040513d5f823e3d81fd5b50505f513d91508115612184578060011415612191565b6001600160a01b0384163b155b156113f757604051635274afe760e01b81526001600160a01b03851660048201526024015b60405180910390fd5b80825d5050565b5f5f836001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015612204573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612228919061272a565b6040516370a0823160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529192505f917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156122b1573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122d591906129fc565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316146123b3576040516327f18ae360e01b81526001600160a01b0386811660048301527f0000000000000000000000000000000000000000000000000000000000000000811660248301528316906327f18ae3906044015f604051808303815f87803b158015612398575f5ffd5b505af11580156123aa573d5f5f3e3d5ffd5b5050505061241e565b6040516001600160a01b03861660248201525f9060440160408051601f198184030181529190526020810180516001600160e01b03166335313c2160e11b17905290506124008382611afa565b61241c5760405162ec6f7b60e31b815260040160405180910390fd5b505b6040516370a0823160e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282917f0000000000000000000000000000000000000000000000000000000000000000909116906370a0823190602401602060405180830381865afa1580156124a6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124ca91906129fc565b6124d49190612b4c565b95945050505050565b5f6001600160801b03821115612510576040516306dfcc6560e41b815260806004820152602481018390526044016121b6565b5090565b5f60808284031215612524575f5ffd5b50919050565b803560028110612538575f5ffd5b919050565b5f5f6040838503121561254e575f5ffd5b823567ffffffffffffffff811115612564575f5ffd5b61257085828601612514565b92505061257f6020840161252a565b90509250929050565b6001600160a01b0381168114610e0d575f5ffd5b5f602082840312156125ac575f5ffd5b813561157381612588565b5f5f5f606084860312156125c9575f5ffd5b833567ffffffffffffffff8111156125df575f5ffd5b6125eb86828701612514565b9350506125fa6020850161252a565b9150604084013561260a81612588565b809150509250925092565b634e487b7160e01b5f52604160045260245ffd5b6040516080810167ffffffffffffffff8111828210171561264c5761264c612615565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561267b5761267b612615565b604052919050565b5f5f60408385031215612694575f5ffd5b823561269f81612588565b9150602083013567ffffffffffffffff8111156126ba575f5ffd5b8301601f810185136126ca575f5ffd5b803567ffffffffffffffff8111156126e4576126e4612615565b6126f7601f8201601f1916602001612652565b81815286602083850101111561270b575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b5f6020828403121561273a575f5ffd5b815161157381612588565b5f60208284031215612755575f5ffd5b81518015158114611573575f5ffd5b5f5f8335601e19843603018112612779575f5ffd5b83018035915067ffffffffffffffff821115612793575f5ffd5b6020019150600581901b36038213156127aa575f5ffd5b9250929050565b634e487b7160e01b5f52603260045260245ffd5b5f67ffffffffffffffff8211156127de576127de612615565b5060051b60200190565b5f82601f8301126127f7575f5ffd5b815161280a612805826127c5565b612652565b8082825260208201915060208360051b86010192508583111561282b575f5ffd5b602085015b8381101561285157805161284381612588565b835260209283019201612830565b5095945050505050565b5f6020828403121561286b575f5ffd5b815167ffffffffffffffff811115612881575f5ffd5b820160808185031215612892575f5ffd5b61289a612629565b81516128a581612588565b815260208201516128b581612588565b6020820152604082015167ffffffffffffffff8111156128d3575f5ffd5b6128df868285016127e8565b604083015250606082015167ffffffffffffffff8111156128fe575f5ffd5b80830192505084601f830112612912575f5ffd5b8151612920612805826127c5565b8082825260208201915060208360051b860101925087831115612941575f5ffd5b6020850194505b82851015612963578451825260209485019490910190612948565b6060840152509095945050505050565b604080825283519082018190525f9060208501906060840190835b818110156129b55783516001600160a01b031683526020938401939092019160010161298e565b5050838103602080860191909152855180835291810192508501905f5b818110156129f05782518452602093840193909201916001016129d2565b50919695505050505050565b5f60208284031215612a0c575f5ffd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b80820180821115610fe257610fe2612a13565b634e487b7160e01b5f52602160045260245ffd5b5f60208284031215612a5e575f5ffd5b815167ffffffffffffffff811115612a74575f5ffd5b610606848285016127e8565b6001600160801b038181168382160190811115610fe257610fe2612a13565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b60018060a01b0385168152836020820152608060408201525f612af36080830185612a9f565b905060028310612b1157634e487b7160e01b5f52602160045260245ffd5b82606083015295945050505050565b6001600160a01b038416815260ff831660208201526060604082018190525f906124d490830184612a9f565b81810381811115610fe257610fe2612a1356fea26469706673582212200fdd167c963618d7c22102d739b30a1bdbf4c331c530546cc4d55140981e5da564736f6c634300081c00330000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6
Deployed Bytecode
0x608060405234801561000f575f5ffd5b50600436106100cb575f3560e01c80636b9f96ea116100885780637aaf53e6116100635780637aaf53e6146102185780638b9d29401461023f57806399248ea714610266578063cce2f3fb1461028d575f5ffd5b80636b9f96ea146101dc57806370a08231146101e45780637399bfe814610205575f5ffd5b806308ecd9a6146100cf5780630c96a583146101135780630db41f311461014d57806321c281911461018d5780632d8e2142146101a2578063338c5371146101b5575b5f5ffd5b6100f67f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b681565b6040516001600160a01b0390911681526020015b60405180910390f35b61012661012136600461253d565b6102a0565b6040805182516001600160801b03908116825260209384015116928101929092520161010a565b6101747fc715e3730000000000000000000000000000000000000000000000000000000081565b6040516001600160e01b0319909116815260200161010a565b6101a061019b36600461259c565b61060e565b005b6101266101b03660046125b7565b610a2d565b6100f67f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b681565b6101a0610d85565b6101f76101f236600461259c565b610e10565b60405190815260200161010a565b610126610213366004612683565b610f77565b6100f67f0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a8081565b6100f67f000000000000000000000000a7d6dd95a06d95b65edf32b94ed46996e151c06f81565b6100f67f000000000000000000000000331b9182088e2a7d6d3fe4742aba1fb231aecc5681565b6101a061029b36600461259c565b610fe8565b604080518082019091525f80825260208201526102c3604084016020850161259c565b604051632988bb9f60e21b81526001600160a01b03828116600483015233917f0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a809091169063a622ee7c90602401602060405180830381865afa15801561032b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061034f919061272a565b6001600160a01b03161461037657604051638d1af8bd60e01b815260040160405180910390fd5b6001600160a01b037f0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a8016634bc5d7356103b5604087016020880161259c565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156103f7573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061041b9190612745565b15610439576040516301970f6d60e71b815260040160405180910390fd5b5f5b6104486040860186612764565b90508110156105ec575f61045f6060870187612764565b8381811061046f5761046f6127b1565b9050602002013511156105e4576001600160a01b037f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6166104b36040870187612764565b838181106104c3576104c36127b1565b90506020020160208101906104d8919061259c565b6001600160a01b0316036105345761052f6104f6602087018761259c565b610506604088016020890161259c565b6105136060890189612764565b85818110610523576105236127b1565b90506020020135611390565b6105e4565b6105416040860186612764565b82818110610551576105516127b1565b9050602002016020810190610566919061259c565b6001600160a01b031663b6b55f256105816060880188612764565b84818110610591576105916127b1565b905060200201356040518263ffffffff1660e01b81526004016105b691815260200190565b5f604051808303815f87803b1580156105cd575f5ffd5b505af11580156105df573d5f5f3e3d5ffd5b505050505b60010161043b565b50610606610600604086016020870161259c565b846113fd565b949350505050565b604051634bc5d73560e01b81526001600160a01b0382811660048301527f0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a801690634bc5d73590602401602060405180830381865afa158015610672573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106969190612745565b156106b4576040516301970f6d60e71b815260040160405180910390fd5b60405163ef64d76360e01b81526001600160e01b03197fc715e373000000000000000000000000000000000000000000000000000000001660048201525f907f0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a806001600160a01b03169063ef64d76390602401602060405180830381865afa158015610742573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610766919061272a565b604051634e2333d160e11b81526001600160a01b0384811660048301529192505f917f0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a801690639c4667a290602401602060405180830381865afa1580156107cf573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107f3919061272a565b90505f6107ff84610e10565b90505f61080b85611450565b90506108198386833061157a565b604051632f3c319f60e01b81526001600160a01b0384811660048301528681166024830152604482018490525f9190861690632f3c319f906064015f60405180830381865afa15801561086e573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610895919081019061285b565b604081015151909150600181116108bf57604051635121f34360e01b815260040160405180910390fd5b5f5b818110156109d8575f836040015182815181106108e0576108e06127b1565b602002602001015190505f84606001518381518110610901576109016127b1565b6020026020010151905061092982828a6001600160a01b03166117549092919063ffffffff16565b80156109ce577f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b0316826001600160a01b03160361097857610973888b83611390565b6109ce565b60405163b6b55f2560e01b8152600481018290526001600160a01b0383169063b6b55f25906024015f604051808303815f87803b1580156109b7575f5ffd5b505af11580156109c9573d5f5f3e3d5ffd5b505050505b50506001016108c1565b50866001600160a01b03167f7999601d1a757a3c60f7cc686ee486ef059e7aa194251eb545a340f5fbba330e83604001518460600151604051610a1c929190612973565b60405180910390a250505050505050565b604080518082019091525f8082526020820152610a50604085016020860161259c565b604051632988bb9f60e21b81526001600160a01b03828116600483015233917f0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a809091169063a622ee7c90602401602060405180830381865afa158015610ab8573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610adc919061272a565b6001600160a01b031614610b0357604051638d1af8bd60e01b815260040160405180910390fd5b5f610b14604087016020880161259c565b604051634bc5d73560e01b81526001600160a01b0380831660048301529192507f0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a8090911690634bc5d73590602401602060405180830381865afa158015610b7d573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ba19190612745565b15610bb857610bb081866113fd565b925050610d7d565b5f5b610bc76040880188612764565b9050811015610d6e575f610bde6060890189612764565b83818110610bee57610bee6127b1565b905060200201351115610d66576001600160a01b037f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b616610c326040890189612764565b83818110610c4257610c426127b1565b9050602002016020810190610c57919061259c565b6001600160a01b031603610ca557610ca0610c75602089018961259c565b83610c8360608b018b612764565b85818110610c9357610c936127b1565b90506020020135886117ab565b610d66565b610cb26040880188612764565b82818110610cc257610cc26127b1565b9050602002016020810190610cd7919061259c565b6001600160a01b031662f714ce610cf160608a018a612764565b84818110610d0157610d016127b1565b90506020020135876040518363ffffffff1660e01b8152600401610d389291909182526001600160a01b0316602082015260400190565b5f604051808303815f87803b158015610d4f575f5ffd5b505af1158015610d61573d5f5f3e3d5ffd5b505050505b600101610bba565b50610d7981866113fd565b9250505b509392505050565b7f000000000000000000000000a7d6dd95a06d95b65edf32b94ed46996e151c06f6001600160a01b03163314610dce5760405163baf4cbdd60e01b815260040160405180910390fd5b7f56d95056ce1c07cd2be5f6ba7c1032b2ced7959a89d4000fbfdb5b75562325485c5f819003610dfb5750565b610e0481611888565b610e0d5f611940565b50565b5f5f610e1b83611450565b80519091505f5b81811015610f6f575f838281518110610e3d57610e3d6127b1565b602002602001015190507f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b0316816001600160a01b031603610ef9576040516370a0823160e01b81526001600160a01b0382811660048301528716906370a0823190602401602060405180830381865afa158015610ec4573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ee891906129fc565b610ef29086612a27565b9450610f66565b806001600160a01b031663722713f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f35573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f5991906129fc565b610f639086612a27565b94505b50600101610e22565b505050919050565b604080518082019091525f80825260208201527f000000000000000000000000a7d6dd95a06d95b65edf32b94ed46996e151c06f6001600160a01b03163314610fd35760405163baf4cbdd60e01b815260040160405180910390fd5b610fdf8383600161196a565b90505b92915050565b6040516217798b60e61b81523060048201523360248201525f356001600160e01b031916604482015281907f0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a806001600160a01b0316906305de62c090606401602060405180830381865afa158015611062573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110869190612745565b806111145750604051634bc5d73560e01b81526001600160a01b0382811660048301527f0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a801690634bc5d73590602401602060405180830381865afa1580156110f0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111149190612745565b61113157604051634eaf9b5d60e11b815260040160405180910390fd5b604051631c5543cd60e21b81526001600160a01b0383811660048301527f0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a8016906371550f3490602401602060405180830381865afa158015611195573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111b99190612745565b156111d7576040516365eca15b60e11b815260040160405180910390fd5b604051632988bb9f60e21b81526001600160a01b0383811660048301525f917f0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a809091169063a622ee7c90602401602060405180830381865afa15801561123f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611263919061272a565b90505f816001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112a2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112c6919061272a565b90505f6112d285611450565b90506112e08286838661157a565b6040516303f506e960e01b81526001600160a01b0386811660048301527f0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a8016906303f506e9906024015f604051808303815f87803b158015611340575f5ffd5b505af1158015611352573d5f5f3e3d5ffd5b50506040516001600160a01b03881692507f28b4c24cb1012c094cd2f59f98e89d791973295f8fda6eaa118022d6d318960a91505f90a25050505050565b5f816040516024016113a491815260200190565b60408051601f198184030181529190526020810180516001600160e01b031663b6b55f2560e01b17905290506113da8382611afa565b6113f7576040516379cacff160e01b815260040160405180910390fd5b50505050565b604080518082019091525f8082526020820152600182600181111561142457611424612a3a565b146114375761143283611ce0565b610fdf565b610fdf8360405180602001604052805f8152505f61196a565b60405163ef64d76360e01b81526001600160e01b03197fc715e373000000000000000000000000000000000000000000000000000000001660048201526060905f906001600160a01b037f0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a80169063ef64d76390602401602060405180830381865afa1580156114e1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611505919061272a565b60405163db8c1be960e01b81526001600160a01b0385811660048301529192509082169063db8c1be9906024015f60405180830381865afa15801561154c573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526115739190810190612a4e565b9392505050565b81515f5b8181101561174c575f848281518110611599576115996127b1565b602002602001015190505f7f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b0316826001600160a01b03160361167e576040516370a0823160e01b81526001600160a01b037f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6811660048301528816906370a0823190602401602060405180830381865afa158015611641573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061166591906129fc565b9050801561167957611679888883886117ab565b611742565b816001600160a01b031663722713f76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116ba573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116de91906129fc565b9050801561174257604051627b8a6760e11b8152600481018290526001600160a01b03868116602483015283169062f714ce906044015f604051808303815f87803b15801561172b575f5ffd5b505af115801561173d573d5f5f3e3d5ffd5b505050505b505060010161157e565b505050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526117a690849061214e565b505050565b5f826040516024016117bf91815260200190565b60408051601f198184030181529190526020810180516001600160e01b0316632e1a7d4d60e01b17905290506117f58482611afa565b61181257604051631d42c86760e21b815260040160405180910390fd5b6040516001600160a01b03831660248201526044810184905260640160408051601f198184030181529190526020810180516001600160e01b031663a9059cbb60e01b17905290506118648582611afa565b611881576040516312171d8360e31b815260040160405180910390fd5b5050505050565b8015610e0d57604080517f000000000000000000000000a7d6dd95a06d95b65edf32b94ed46996e151c06f6001600160a01b0316602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261191f7f000000000000000000000000331b9182088e2a7d6d3fe4742aba1fb231aecc5682611afa565b61193c576040516304fc2be760e01b815260040160405180910390fd5b5050565b610e0d7f56d95056ce1c07cd2be5f6ba7c1032b2ced7959a89d4000fbfdb5b7556232548826121bf565b604080518082019091525f80825260208201525f61198785611450565b80519091505f90815b81811015611aef575f8482815181106119ab576119ab6127b1565b602002602001015190507f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b0316816001600160a01b031603611a5c576119f889896121c6565b9350611a03846124dd565b6001600160801b031686528615611a4e577f56d95056ce1c07cd2be5f6ba7c1032b2ced7959a89d4000fbfdb5b75562325485c611a48611a438683612a27565b611940565b50611ac0565b611a5784611888565b611ac0565b806001600160a01b0316634e71d92d6040518163ffffffff1660e01b81526004016020604051808303815f875af1158015611a99573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611abd91906129fc565b93505b611ac9846124dd565b86602001818151611ada9190612a80565b6001600160801b031690525050600101611990565b505050509392505050565b5f7f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b03167f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b031603611bed5760405163468721a760e01b81526001600160a01b037f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6169063468721a790611ba69086905f9087908290600401612acd565b6020604051808303815f875af1158015611bc2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611be69190612745565b9050610fe2565b7f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b031663468721a77f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b65f865f87604051602401611c5393929190612b20565b60408051601f198184030181529181526020820180516001600160e01b0316635b0e93fb60e11b1790525160e085901b6001600160e01b0319168152611ca0939291905f90600401612acd565b6020604051808303815f875af1158015611cbc573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fdf9190612745565b604080518082019091525f80825260208201525f826001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d30573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d54919061272a565b60405163ef64d76360e01b81526001600160e01b03197fc715e373000000000000000000000000000000000000000000000000000000001660048201529091505f906001600160a01b037f0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a80169063ef64d76390602401602060405180830381865afa158015611de5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e09919061272a565b60405163db8c1be960e01b81526001600160a01b0386811660048301529192505f9183169063db8c1be9906024015f60405180830381865afa158015611e51573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611e789190810190612a4e565b6040516001600160a01b037f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6166024820152909150611ee590869060440160408051601f198184030181529190526020810180516001600160e01b0316634b82009360e01b179052611afa565b611f0257604051630d027b0960e41b815260040160405180910390fd5b5f805b8251811015612144575f838281518110611f2157611f216127b1565b602002602001015190507f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b0316816001600160a01b0316036120b1576040516308b752bb60e41b81526001600160a01b037f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6811660048301528981166024830152871690638b752bb090604401602060405180830381865afa158015611fd0573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ff491906129fc565b604051630940070760e01b81526001600160a01b037f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6811660048301528a1690630940070790602401602060405180830381865afa158015612058573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061207c91906129fc565b6120869190612b4c565b9250612091836124dd565b875188906120a0908390612a80565b6001600160801b0316905250612115565b806001600160a01b031663d9621f9e6040518163ffffffff1660e01b81526004016020604051808303815f875af11580156120ee573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061211291906129fc565b92505b61211e836124dd565b8760200181815161212f9190612a80565b6001600160801b031690525050600101611f05565b5050505050919050565b5f5f60205f8451602086015f885af18061216d576040513d5f823e3d81fd5b50505f513d91508115612184578060011415612191565b6001600160a01b0384163b155b156113f757604051635274afe760e01b81526001600160a01b03851660048201526024015b60405180910390fd5b80825d5050565b5f5f836001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015612204573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612228919061272a565b6040516370a0823160e01b81526001600160a01b037f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6811660048301529192505f917f000000000000000000000000331b9182088e2a7d6d3fe4742aba1fb231aecc5616906370a0823190602401602060405180830381865afa1580156122b1573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122d591906129fc565b90507f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b03167f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b0316146123b3576040516327f18ae360e01b81526001600160a01b0386811660048301527f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6811660248301528316906327f18ae3906044015f604051808303815f87803b158015612398575f5ffd5b505af11580156123aa573d5f5f3e3d5ffd5b5050505061241e565b6040516001600160a01b03861660248201525f9060440160408051601f198184030181529190526020810180516001600160e01b03166335313c2160e11b17905290506124008382611afa565b61241c5760405162ec6f7b60e31b815260040160405180910390fd5b505b6040516370a0823160e01b81526001600160a01b037f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b68116600483015282917f000000000000000000000000331b9182088e2a7d6d3fe4742aba1fb231aecc56909116906370a0823190602401602060405180830381865afa1580156124a6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124ca91906129fc565b6124d49190612b4c565b95945050505050565b5f6001600160801b03821115612510576040516306dfcc6560e41b815260806004820152602481018390526044016121b6565b5090565b5f60808284031215612524575f5ffd5b50919050565b803560028110612538575f5ffd5b919050565b5f5f6040838503121561254e575f5ffd5b823567ffffffffffffffff811115612564575f5ffd5b61257085828601612514565b92505061257f6020840161252a565b90509250929050565b6001600160a01b0381168114610e0d575f5ffd5b5f602082840312156125ac575f5ffd5b813561157381612588565b5f5f5f606084860312156125c9575f5ffd5b833567ffffffffffffffff8111156125df575f5ffd5b6125eb86828701612514565b9350506125fa6020850161252a565b9150604084013561260a81612588565b809150509250925092565b634e487b7160e01b5f52604160045260245ffd5b6040516080810167ffffffffffffffff8111828210171561264c5761264c612615565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561267b5761267b612615565b604052919050565b5f5f60408385031215612694575f5ffd5b823561269f81612588565b9150602083013567ffffffffffffffff8111156126ba575f5ffd5b8301601f810185136126ca575f5ffd5b803567ffffffffffffffff8111156126e4576126e4612615565b6126f7601f8201601f1916602001612652565b81815286602083850101111561270b575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b5f6020828403121561273a575f5ffd5b815161157381612588565b5f60208284031215612755575f5ffd5b81518015158114611573575f5ffd5b5f5f8335601e19843603018112612779575f5ffd5b83018035915067ffffffffffffffff821115612793575f5ffd5b6020019150600581901b36038213156127aa575f5ffd5b9250929050565b634e487b7160e01b5f52603260045260245ffd5b5f67ffffffffffffffff8211156127de576127de612615565b5060051b60200190565b5f82601f8301126127f7575f5ffd5b815161280a612805826127c5565b612652565b8082825260208201915060208360051b86010192508583111561282b575f5ffd5b602085015b8381101561285157805161284381612588565b835260209283019201612830565b5095945050505050565b5f6020828403121561286b575f5ffd5b815167ffffffffffffffff811115612881575f5ffd5b820160808185031215612892575f5ffd5b61289a612629565b81516128a581612588565b815260208201516128b581612588565b6020820152604082015167ffffffffffffffff8111156128d3575f5ffd5b6128df868285016127e8565b604083015250606082015167ffffffffffffffff8111156128fe575f5ffd5b80830192505084601f830112612912575f5ffd5b8151612920612805826127c5565b8082825260208201915060208360051b860101925087831115612941575f5ffd5b6020850194505b82851015612963578451825260209485019490910190612948565b6060840152509095945050505050565b604080825283519082018190525f9060208501906060840190835b818110156129b55783516001600160a01b031683526020938401939092019160010161298e565b5050838103602080860191909152855180835291810192508501905f5b818110156129f05782518452602093840193909201916001016129d2565b50919695505050505050565b5f60208284031215612a0c575f5ffd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b80820180821115610fe257610fe2612a13565b634e487b7160e01b5f52602160045260245ffd5b5f60208284031215612a5e575f5ffd5b815167ffffffffffffffff811115612a74575f5ffd5b610606848285016127e8565b6001600160801b038181168382160190811115610fe257610fe2612a13565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b60018060a01b0385168152836020820152608060408201525f612af36080830185612a9f565b905060028310612b1157634e487b7160e01b5f52602160045260245ffd5b82606083015295945050505050565b6001600160a01b038416815260ff831660208201526060604082018190525f906124d490830184612a9f565b81810381811115610fe257610fe2612a1356fea26469706673582212200fdd167c963618d7c22102d739b30a1bdbf4c331c530546cc4d55140981e5da564736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6
-----Decoded View---------------
Arg [0] : _registry (address): 0x4D4c2C4777625e97be1985682fAE5A53f5C44A80
Arg [1] : _locker (address): 0x0000000000000000000000000000000000000000
Arg [2] : _gateway (address): 0x52f541764E6e90eeBc5c21Ff570De0e2D63766B6
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a80
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [2] : 00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in FRAX
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.