Source Code
Latest 25 from a total of 31 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Rebalance | 31184208 | 2 days ago | IN | 0 FRAX | 0.00001581 | ||||
| Rebalance | 31165306 | 2 days ago | IN | 0 FRAX | 0.0000038 | ||||
| Rebalance | 31140376 | 3 days ago | IN | 0 FRAX | 0.00001415 | ||||
| Rebalance | 31122063 | 3 days ago | IN | 0 FRAX | 0.00000559 | ||||
| Rebalance | 31087614 | 4 days ago | IN | 0 FRAX | 0.00001023 | ||||
| Rebalance | 30472938 | 18 days ago | IN | 0 FRAX | 0.00000383 | ||||
| Rebalance | 29283995 | 46 days ago | IN | 0 FRAX | 0.00001385 | ||||
| Rebalance | 29282926 | 46 days ago | IN | 0 FRAX | 0.00001354 | ||||
| Rebalance | 29262882 | 46 days ago | IN | 0 FRAX | 0.00001626 | ||||
| Rebalance | 29262520 | 46 days ago | IN | 0 FRAX | 0.00001488 | ||||
| Rebalance | 29001326 | 52 days ago | IN | 0 FRAX | 0.00000318 | ||||
| Rebalance | 29001235 | 52 days ago | IN | 0 FRAX | 0.00000331 | ||||
| Rebalance | 28571311 | 62 days ago | IN | 0 FRAX | 0.00000778 | ||||
| Rebalance | 27252983 | 93 days ago | IN | 0 FRAX | 0.0001597 | ||||
| Rebalance | 26313824 | 114 days ago | IN | 0 FRAX | 0.00006355 | ||||
| Rebalance | 25462704 | 134 days ago | IN | 0 FRAX | 0.00001593 | ||||
| Rebalance | 25392539 | 136 days ago | IN | 0 FRAX | 0.00006621 | ||||
| Rebalance | 25392530 | 136 days ago | IN | 0 FRAX | 0.00007102 | ||||
| Rebalance | 25378639 | 136 days ago | IN | 0 FRAX | 0.00001122 | ||||
| Rebalance | 25338889 | 137 days ago | IN | 0 FRAX | 0.00001364 | ||||
| Rebalance | 25308343 | 138 days ago | IN | 0 FRAX | 0.00012401 | ||||
| Rebalance | 25291137 | 138 days ago | IN | 0 FRAX | 0.00001182 | ||||
| Rebalance | 25129188 | 142 days ago | IN | 0 FRAX | 0.00001824 | ||||
| Rebalance | 25096292 | 143 days ago | IN | 0 FRAX | 0.00011891 | ||||
| Rebalance | 25095675 | 143 days ago | IN | 0 FRAX | 0.00010951 |
Advanced mode: Intended for advanced users or developers and will display all Internal Transactions including zero value transfers.
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | ||||
|---|---|---|---|---|---|---|---|
| 31279498 | 22 mins ago | 0 FRAX | |||||
| 31279498 | 22 mins ago | 0 FRAX | |||||
| 31279498 | 22 mins ago | 0 FRAX | |||||
| 31279498 | 22 mins ago | 0 FRAX | |||||
| 31279498 | 22 mins ago | 0 FRAX | |||||
| 31279498 | 22 mins ago | 0 FRAX | |||||
| 31279498 | 22 mins ago | 0 FRAX | |||||
| 31279498 | 22 mins ago | 0 FRAX | |||||
| 31279498 | 22 mins ago | 0 FRAX | |||||
| 31279498 | 22 mins ago | 0 FRAX | |||||
| 31279498 | 22 mins ago | 0 FRAX | |||||
| 31279498 | 22 mins ago | 0 FRAX | |||||
| 31279498 | 22 mins ago | 0 FRAX | |||||
| 31279498 | 22 mins ago | 0 FRAX | |||||
| 31279498 | 22 mins ago | 0 FRAX | |||||
| 31279498 | 22 mins ago | 0 FRAX | |||||
| 31279498 | 22 mins ago | 0 FRAX | |||||
| 31279498 | 22 mins ago | 0 FRAX | |||||
| 31279498 | 22 mins ago | 0 FRAX | |||||
| 31277739 | 1 hr ago | 0 FRAX | |||||
| 31277739 | 1 hr ago | 0 FRAX | |||||
| 31277739 | 1 hr ago | 0 FRAX | |||||
| 31277739 | 1 hr ago | 0 FRAX | |||||
| 31277739 | 1 hr ago | 0 FRAX | |||||
| 31277739 | 1 hr ago | 0 FRAX |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
CurveStrategyL2
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";
import {IRewardVault} from "src/interfaces/IRewardVault.sol";
import {IRewardReceiver} from "src/interfaces/IRewardReceiver.sol";
import {IFactory} from "src/interfaces/IFactory.sol";
/// @title CurveStrategyL2.
/// @author Stake DAO
/// @custom:github @stake-dao
/// @custom:contact [email protected]
/// @notice CurveStrategyL2 is a specialized implementation for interacting with Curve protocol gauges on Layer 2 networks.
///
/// Key differences from mainnet CurveStrategy:
/// - No MINTER immutable - uses gauge.factory() as the minter
/// - Includes extra rewards claiming functionality via claim_rewards()
contract CurveStrategyL2 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();
/// @notice Error thrown when the extra rewards claim fails.
error ClaimExtraRewards();
//////////////////////////////////////////////////////
// --- 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;
}
/// @notice Override base _harvest to trigger reward distribution after all claims
/// @dev This ensures both gauge and sidecar rewards are distributed together on L2s
function _harvest(address gauge, bytes memory extraData, bool deferRewards)
internal
override
returns (IStrategy.PendingRewards memory pendingRewards)
{
// Sync reward tokens if new ones were added to the gauge
_syncRewardTokensIfNeeded(gauge);
// Call parent harvest which handles both locker and sidecar claims
pendingRewards = super._harvest(gauge, extraData, deferRewards);
/// Claim extra rewards from the gauge on Locker side.
_claimExtraRewards(gauge);
return pendingRewards;
}
/// @notice Claims extra rewards from a Curve gauge
/// @dev This function is called after the main rewards have been claimed
function _claimExtraRewards(address gauge) internal {
/// 1. Get the reward receiver address.
address rewardReceiver = PROTOCOL_CONTROLLER.rewardReceiver(gauge);
/// 2. Claim extra rewards from the gauge to the reward receiver.
bytes memory data =
abi.encodeWithSignature("claim_rewards(address,address)", address(LOCKER), address(rewardReceiver));
require(_executeTransaction(gauge, data), ClaimExtraRewards());
address rewardVault = PROTOCOL_CONTROLLER.vault(gauge);
address[] memory rewardTokens = IRewardVault(rewardVault).getRewardTokens();
if (rewardTokens.length == 0) {
return;
}
/// 4. Trigger distribute in the reward receiver.
IRewardReceiver(rewardReceiver).distributeRewards();
}
/// @notice Syncs reward tokens with the factory if needed
/// @dev Calls the factory to check and add any new reward tokens from the gauge
function _syncRewardTokensIfNeeded(address gauge) internal {
address factoryAddress = PROTOCOL_CONTROLLER.factory(PROTOCOL_ID);
// Only sync if factory is set
if (factoryAddress != address(0)) {
IFactory(factoryAddress).syncRewardTokens(gauge);
}
}
}// 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.
/// @author Stake DAO
/// @custom:github @stake-dao
/// @custom:contact [email protected]
/// @notice Strategy is a protocol-agnostic yield strategy orchestrator that manages deposits and withdrawals
/// across multiple yield sources (locker and sidecars). It routes funds based on allocator decisions,
/// handles reward harvesting with transient storage for gas optimization, supports emergency shutdown
/// to transfer all funds back to vaults, and enables rebalancing 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 the protocol controller
error OnlyProtocolController();
/// @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 Error thrown when deposits are attempted while protocol is paused
error DepositsPaused();
/// @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.vault(gauge) == msg.sender, OnlyVault());
_;
}
/// @notice Restricts functions to the protocol controller
modifier onlyProtocolController() {
require(msg.sender == address(PROTOCOL_CONTROLLER), OnlyProtocolController());
_;
}
/// @notice Restricts harvest flush operations to the accountant
modifier onlyAccountant() {
require(ACCOUNTANT == msg.sender, OnlyAccountant());
_;
}
//////////////////////////////////////////////////////
// --- 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
/// @custom:throws DepositsPaused Prevents deposits when protocol is paused
function deposit(IAllocator.Allocation calldata allocation, HarvestPolicy policy)
external
override
onlyVault(allocation.gauge)
returns (PendingRewards memory pendingRewards)
{
require(!PROTOCOL_CONTROLLER.isShutdown(allocation.gauge), GaugeShutdown());
require(!PROTOCOL_CONTROLLER.isPaused(PROTOCOL_ID), DepositsPaused());
// 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 onlyProtocolController {
address vault = PROTOCOL_CONTROLLER.vault(gauge);
address asset = IERC4626(vault).asset();
address[] memory targets = _getAllocationTargets(gauge);
// Withdraw everything from locker and sidecars to vault
_withdrawFromAllTargets(asset, gauge, targets, vault);
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)
/// @custom:throws DepositsPaused Prevents rebalancing when protocol is paused
function rebalance(address gauge) external {
require(!PROTOCOL_CONTROLLER.isShutdown(gauge), GaugeShutdown());
require(!PROTOCOL_CONTROLLER.isPaused(PROTOCOL_ID), DepositsPaused());
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
virtual
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: BUSL-1.1
pragma solidity 0.8.28;
/// @title IRewardVault
/// @notice Interface for the RewardVault contract
interface IRewardVault {
function addRewardToken(address rewardsToken, address distributor) external;
function depositRewards(address _rewardsToken, uint128 _amount) external;
function deposit(uint256 assets, address receiver, address referrer) external returns (uint256 shares);
function deposit(address account, address receiver, uint256 assets, address referrer)
external
returns (uint256 shares);
function claim(address[] calldata tokens, address receiver) external returns (uint256[] memory amounts);
function claim(address account, address[] calldata tokens, address receiver)
external
returns (uint256[] memory amounts);
function getRewardsDistributor(address token) external view returns (address);
function getLastUpdateTime(address token) external view returns (uint32);
function getPeriodFinish(address token) external view returns (uint32);
function getRewardRate(address token) external view returns (uint128);
function getRewardPerTokenStored(address token) external view returns (uint128);
function getRewardPerTokenPaid(address token, address account) external view returns (uint128);
function getClaimable(address token, address account) external view returns (uint128);
function getRewardTokens() external view returns (address[] memory);
function lastTimeRewardApplicable(address token) external view returns (uint256);
function rewardPerToken(address token) external view returns (uint128);
function earned(address account, address token) external view returns (uint128);
function isRewardToken(address rewardToken) external view returns (bool);
function resumeVault() external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
interface IRewardReceiver {
function distributeRewards() external;
function distributeRewardToken(IERC20 token) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
interface IFactory {
function createVault(address gauge) external returns (address vault, address rewardReceiver);
function syncRewardTokens(address gauge) external;
}// 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
/// @custom:github @stake-dao
/// @custom:contact [email protected]
/// @notice Base contract providing shared protocol configuration and transaction execution.
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;
function shutdown(address gauge) 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 _gauges, bytes[] calldata harvestData) external;
function claim(address[] calldata _gauges, bytes[] calldata harvestData, address receiver) external;
function claim(address[] calldata _gauges, address account, bytes[] calldata harvestData, address receiver)
external;
function claimProtocolFees() external;
function harvest(address[] calldata _gauges, 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 vault(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 factory(bytes4 protocolId) external view returns (address);
function isPaused(bytes4) external view returns (bool);
function isShutdown(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 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":"ClaimExtraRewards","type":"error"},{"inputs":[],"name":"DepositFailed","type":"error"},{"inputs":[],"name":"DepositsPaused","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":"OnlyProtocolController","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
610140604052348015610010575f5ffd5b506040516132cd3803806132cd83398101604081905261002f9161020f565b827fc715e3736a8cb018f630cb9a1df908ad1629e9c2da4cd190b2dc83d6687ba1698383828483836001600160a01b0383161580159061007757506001600160a01b03811615155b6100945760405163d92e233d60e01b815260040160405180910390fd5b6001600160e01b031984166100bc576040516355e7c3d960e11b815260040160405180910390fd5b6001600160a01b0381811660c0526001600160e01b03198516608081905260405163669cc2c960e11b815260048101919091529084169063cd39859290602401602060405180830381865afa158015610117573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061013b919061024f565b6001600160a01b031660e0819052604080516399248ea760e01b815290516399248ea7916004808201926020929091908290030181865afa158015610182573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101a6919061024f565b6001600160a01b03908116610100528381166101205282166101d65760c0516001600160a01b031660a0526101e4565b6001600160a01b03821660a0525b505050505050505050505061026f565b80516001600160a01b038116811461020a575f5ffd5b919050565b5f5f5f60608486031215610221575f5ffd5b61022a846101f4565b9250610238602085016101f4565b9150610246604085016101f4565b90509250925092565b5f6020828403121561025f575f5ffd5b610268826101f4565b9392505050565b60805160a05160c05160e0516101005161012051612eba6104135f395f8181610211015281816102d80152818161037401528181610444015281816106ea01528181610788015281816108530152818161090b01528181610bf201528181610cb701528181611174015281816111d3015281816113b901528181611b5801528181611fd70152818161227f01526123a001525f818161025f01528181611857015281816125b301526127a601525f818161023801528181610f080152818161110d01526117f101525f81816101ae015281816118fc0152818161196a015281816119ee015261262001525f818160d40152818161054301528181610ab201528181610d8601528181610fca01528181611503015281816115510152818161192601528181611a1d01528181611c7d01528181611d2501528181611d7301528181611e030152818161211b015281816122f7015281816125860152818161264a01528181612696015261277c01525f818161015201528181610471015281816107b501528181610880015281816113e801528181611b8701526120040152612eba5ff3fe608060405234801561000f575f5ffd5b50600436106100cb575f3560e01c80636b9f96ea116100885780637aaf53e6116100635780637aaf53e61461020c5780638b9d29401461023357806399248ea71461025a578063cce2f3fb14610281575f5ffd5b80636b9f96ea146101d057806370a08231146101d85780637399bfe8146101f9575f5ffd5b806308ecd9a6146100cf5780630c96a583146101135780630db41f311461014d57806321c28191146101815780632d8e214214610196578063338c5371146101a9575b5f5ffd5b6100f67f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b61012661012136600461284d565b610294565b6040805182516001600160801b03908116825260209384015116928101929092520161010a565b6101747f000000000000000000000000000000000000000000000000000000000000000081565b60405161010a9190612898565b61019461018f3660046128c1565b6106cb565b005b6101266101a43660046128dc565b610bae565b6100f67f000000000000000000000000000000000000000000000000000000000000000081565b610194610f06565b6101eb6101e63660046128c1565b610f91565b60405190815260200161010a565b6101266102073660046129a8565b6110f8565b6100f67f000000000000000000000000000000000000000000000000000000000000000081565b6100f67f000000000000000000000000000000000000000000000000000000000000000081565b6100f67f000000000000000000000000000000000000000000000000000000000000000081565b61019461028f3660046128c1565b611169565b604080518082019091525f80825260208201526102b760408401602085016128c1565b60405163f815c03d60e01b81526001600160a01b03828116600483015233917f00000000000000000000000000000000000000000000000000000000000000009091169063f815c03d90602401602060405180830381865afa15801561031f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103439190612a4f565b6001600160a01b03161461036a57604051638d1af8bd60e01b815260040160405180910390fd5b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016634bc5d7356103a960408701602088016128c1565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156103eb573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061040f9190612a6a565b1561042d576040516301970f6d60e71b815260040160405180910390fd5b6040516304db2f3360e11b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906309b65e6690610499907f000000000000000000000000000000000000000000000000000000000000000090600401612898565b602060405180830381865afa1580156104b4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104d89190612a6a565b156104f65760405163deeb694360e01b815260040160405180910390fd5b5f5b6105056040860186612a89565b90508110156106a9575f61051c6060870187612a89565b8381811061052c5761052c612ad6565b9050602002013511156106a1576001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166105706040870187612a89565b8381811061058057610580612ad6565b905060200201602081019061059591906128c1565b6001600160a01b0316036105f1576105ec6105b360208701876128c1565b6105c360408801602089016128c1565b6105d06060890189612a89565b858181106105e0576105e0612ad6565b905060200201356112f4565b6106a1565b6105fe6040860186612a89565b8281811061060e5761060e612ad6565b905060200201602081019061062391906128c1565b6001600160a01b031663b6b55f2561063e6060880188612a89565b8481811061064e5761064e612ad6565b905060200201356040518263ffffffff1660e01b815260040161067391815260200190565b5f604051808303815f87803b15801561068a575f5ffd5b505af115801561069c573d5f5f3e3d5ffd5b505050505b6001016104f8565b506106c36106bd60408601602087016128c1565b84611361565b949350505050565b604051634bc5d73560e01b81526001600160a01b0382811660048301527f00000000000000000000000000000000000000000000000000000000000000001690634bc5d73590602401602060405180830381865afa15801561072f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107539190612a6a565b15610771576040516301970f6d60e71b815260040160405180910390fd5b6040516304db2f3360e11b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906309b65e66906107dd907f000000000000000000000000000000000000000000000000000000000000000090600401612898565b602060405180830381865afa1580156107f8573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061081c9190612a6a565b1561083a5760405163deeb694360e01b815260040160405180910390fd5b60405163ef64d76360e01b81525f906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ef64d763906108a8907f000000000000000000000000000000000000000000000000000000000000000090600401612898565b602060405180830381865afa1580156108c3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108e79190612a4f565b604051634e2333d160e11b81526001600160a01b0384811660048301529192505f917f00000000000000000000000000000000000000000000000000000000000000001690639c4667a290602401602060405180830381865afa158015610950573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109749190612a4f565b90505f61098084610f91565b90505f61098c856113b4565b905061099a838683306114d7565b604051632f3c319f60e01b81526001600160a01b0384811660048301528681166024830152604482018490525f9190861690632f3c319f906064015f60405180830381865afa1580156109ef573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610a169190810190612b80565b60408101515190915060018111610a4057604051635121f34360e01b815260040160405180910390fd5b5f5b81811015610b59575f83604001518281518110610a6157610a61612ad6565b602002602001015190505f84606001518381518110610a8257610a82612ad6565b60200260200101519050610aaa82828a6001600160a01b03166116b19092919063ffffffff16565b8015610b4f577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031603610af957610af4888b836112f4565b610b4f565b60405163b6b55f2560e01b8152600481018290526001600160a01b0383169063b6b55f25906024015f604051808303815f87803b158015610b38575f5ffd5b505af1158015610b4a573d5f5f3e3d5ffd5b505050505b5050600101610a42565b50866001600160a01b03167f7999601d1a757a3c60f7cc686ee486ef059e7aa194251eb545a340f5fbba330e83604001518460600151604051610b9d929190612c98565b60405180910390a250505050505050565b604080518082019091525f8082526020820152610bd160408501602086016128c1565b60405163f815c03d60e01b81526001600160a01b03828116600483015233917f00000000000000000000000000000000000000000000000000000000000000009091169063f815c03d90602401602060405180830381865afa158015610c39573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c5d9190612a4f565b6001600160a01b031614610c8457604051638d1af8bd60e01b815260040160405180910390fd5b5f610c9560408701602088016128c1565b604051634bc5d73560e01b81526001600160a01b0380831660048301529192507f000000000000000000000000000000000000000000000000000000000000000090911690634bc5d73590602401602060405180830381865afa158015610cfe573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d229190612a6a565b15610d3957610d318186611361565b925050610efe565b5f5b610d486040880188612a89565b9050811015610eef575f610d5f6060890189612a89565b83818110610d6f57610d6f612ad6565b905060200201351115610ee7576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016610db36040890189612a89565b83818110610dc357610dc3612ad6565b9050602002016020810190610dd891906128c1565b6001600160a01b031603610e2657610e21610df660208901896128c1565b83610e0460608b018b612a89565b85818110610e1457610e14612ad6565b9050602002013588611708565b610ee7565b610e336040880188612a89565b82818110610e4357610e43612ad6565b9050602002016020810190610e5891906128c1565b6001600160a01b031662f714ce610e7260608a018a612a89565b84818110610e8257610e82612ad6565b90506020020135876040518363ffffffff1660e01b8152600401610eb99291909182526001600160a01b0316602082015260400190565b5f604051808303815f87803b158015610ed0575f5ffd5b505af1158015610ee2573d5f5f3e3d5ffd5b505050505b600101610d3b565b50610efa8186611361565b9250505b509392505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163314610f4f5760405163baf4cbdd60e01b815260040160405180910390fd5b7f56d95056ce1c07cd2be5f6ba7c1032b2ced7959a89d4000fbfdb5b75562325485c5f819003610f7c5750565b610f85816117e5565b610f8e5f61189d565b50565b5f5f610f9c836113b4565b80519091505f5b818110156110f0575f838281518110610fbe57610fbe612ad6565b602002602001015190507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b03160361107a576040516370a0823160e01b81526001600160a01b0382811660048301528716906370a0823190602401602060405180830381865afa158015611045573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110699190612d21565b6110739086612d4c565b94506110e7565b806001600160a01b031663722713f76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110b6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110da9190612d21565b6110e49086612d4c565b94505b50600101610fa3565b505050919050565b604080518082019091525f80825260208201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633146111545760405163baf4cbdd60e01b815260040160405180910390fd5b611160838360016118c7565b90505b92915050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146111b2576040516311db81c560e21b815260040160405180910390fd5b60405163f815c03d60e01b81526001600160a01b0382811660048301525f917f00000000000000000000000000000000000000000000000000000000000000009091169063f815c03d90602401602060405180830381865afa15801561121a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061123e9190612a4f565b90505f816001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561127d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112a19190612a4f565b90505f6112ad846113b4565b90506112bb828583866114d7565b6040516001600160a01b038516907f28b4c24cb1012c094cd2f59f98e89d791973295f8fda6eaa118022d6d318960a905f90a250505050565b5f8160405160240161130891815260200190565b60408051601f198184030181529190526020810180516001600160e01b031663b6b55f2560e01b179052905061133e83826118f9565b61135b576040516379cacff160e01b815260040160405180910390fd5b50505050565b604080518082019091525f8082526020820152600182600181111561138857611388612d5f565b1461139b5761139683611adf565b611160565b6111608360405180602001604052805f8152505f6118c7565b60605f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ef64d7637f00000000000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b81526004016114239190612898565b602060405180830381865afa15801561143e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114629190612a4f565b60405163db8c1be960e01b81526001600160a01b0385811660048301529192509082169063db8c1be9906024015f60405180830381865afa1580156114a9573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526114d09190810190612d73565b9392505050565b81515f5b818110156116a9575f8482815181106114f6576114f6612ad6565b602002602001015190505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316036115db576040516370a0823160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301528816906370a0823190602401602060405180830381865afa15801561159e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115c29190612d21565b905080156115d6576115d688888388611708565b61169f565b816001600160a01b031663722713f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611617573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061163b9190612d21565b9050801561169f57604051627b8a6760e11b8152600481018290526001600160a01b03868116602483015283169062f714ce906044015f604051808303815f87803b158015611688575f5ffd5b505af115801561169a573d5f5f3e3d5ffd5b505050505b50506001016114db565b505050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611703908490611f46565b505050565b5f8260405160240161171c91815260200190565b60408051601f198184030181529190526020810180516001600160e01b0316632e1a7d4d60e01b179052905061175284826118f9565b61176f57604051631d42c86760e21b815260040160405180910390fd5b6040516001600160a01b03831660248201526044810184905260640160408051601f198184030181529190526020810180516001600160e01b031663a9059cbb60e01b17905290506117c185826118f9565b6117de576040516312171d8360e31b815260040160405180910390fd5b5050505050565b8015610f8e57604080517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261187c7f0000000000000000000000000000000000000000000000000000000000000000826118f9565b611899576040516304fc2be760e01b815260040160405180910390fd5b5050565b610f8e7f56d95056ce1c07cd2be5f6ba7c1032b2ced7959a89d4000fbfdb5b755623254882611fb7565b604080518082019091525f80825260208201526118e384611fbe565b6118ee8484846120ce565b90506114d08461225e565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316036119ec5760405163468721a760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063468721a7906119a59086905f9087908290600401612dd3565b6020604051808303815f875af11580156119c1573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119e59190612a6a565b9050611163565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663468721a77f00000000000000000000000000000000000000000000000000000000000000005f865f87604051602401611a5293929190612e26565b60408051601f198184030181529181526020820180516001600160e01b0316635b0e93fb60e11b1790525160e085901b6001600160e01b0319168152611a9f939291905f90600401612dd3565b6020604051808303815f875af1158015611abb573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111609190612a6a565b604080518082019091525f80825260208201525f826001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b2f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b539190612a4f565b90505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ef64d7637f00000000000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b8152600401611bc29190612898565b602060405180830381865afa158015611bdd573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c019190612a4f565b60405163db8c1be960e01b81526001600160a01b0386811660048301529192505f9183169063db8c1be9906024015f60405180830381865afa158015611c49573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611c709190810190612d73565b6040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166024820152909150611cdd90869060440160408051601f198184030181529190526020810180516001600160e01b0316634b82009360e01b1790526118f9565b611cfa57604051630d027b0960e41b815260040160405180910390fd5b5f805b8251811015611f3c575f838281518110611d1957611d19612ad6565b602002602001015190507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031603611ea9576040516308b752bb60e41b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301528981166024830152871690638b752bb090604401602060405180830381865afa158015611dc8573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611dec9190612d21565b604051630940070760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301528a1690630940070790602401602060405180830381865afa158015611e50573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e749190612d21565b611e7e9190612e52565b9250611e89836124d6565b87518890611e98908390612e65565b6001600160801b0316905250611f0d565b806001600160a01b031663d9621f9e6040518163ffffffff1660e01b81526004016020604051808303815f875af1158015611ee6573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f0a9190612d21565b92505b611f16836124d6565b87602001818151611f279190612e65565b6001600160801b031690525050600101611cfd565b5050505050919050565b5f5f60205f8451602086015f885af180611f65576040513d5f823e3d81fd5b50505f513d91508115611f7c578060011415611f89565b6001600160a01b0384163b155b1561135b57604051635274afe760e01b81526001600160a01b03851660048201526024015b60405180910390fd5b80825d5050565b60405163b389020960e01b81525f906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063b38902099061202c907f000000000000000000000000000000000000000000000000000000000000000090600401612898565b602060405180830381865afa158015612047573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061206b9190612a4f565b90506001600160a01b0381161561189957604051633bc9a43160e01b81526001600160a01b038381166004830152821690633bc9a431906024015f604051808303815f87803b1580156120bc575f5ffd5b505af11580156116a9573d5f5f3e3d5ffd5b604080518082019091525f80825260208201525f6120eb856113b4565b80519091505f90815b81811015612253575f84828151811061210f5761210f612ad6565b602002602001015190507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036121c05761215c898961250d565b9350612167846124d6565b6001600160801b0316865286156121b2577f56d95056ce1c07cd2be5f6ba7c1032b2ced7959a89d4000fbfdb5b75562325485c6121ac6121a78683612d4c565b61189d565b50612224565b6121bb846117e5565b612224565b806001600160a01b0316634e71d92d6040518163ffffffff1660e01b81526004016020604051808303815f875af11580156121fd573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122219190612d21565b93505b61222d846124d6565b8660200181815161223e9190612e65565b6001600160801b0316905250506001016120f4565b505050509392505050565b604051630339050960e51b81526001600160a01b0382811660048301525f917f000000000000000000000000000000000000000000000000000000000000000090911690636720a12090602401602060405180830381865afa1580156122c6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122ea9190612a4f565b6040516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166024830152821660448201529091505f9060640160408051601f198184030181529190526020810180516001600160e01b0316639faceb1b60e01b179052905061236283826118f9565b61237f5760405163cc5c2c2760e01b815260040160405180910390fd5b60405163f815c03d60e01b81526001600160a01b0384811660048301525f917f00000000000000000000000000000000000000000000000000000000000000009091169063f815c03d90602401602060405180830381865afa1580156123e7573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061240b9190612a4f565b90505f816001600160a01b031663c4f59f9b6040518163ffffffff1660e01b81526004015f60405180830381865afa158015612449573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526124709190810190612d73565b905080515f03612481575050505050565b836001600160a01b0316636f4a2cd06040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156124b9575f5ffd5b505af11580156124cb573d5f5f3e3d5ffd5b505050505050505050565b5f6001600160801b03821115612509576040516306dfcc6560e41b81526080600482015260248101839052604401611fae565b5090565b5f5f836001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa15801561254b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061256f9190612a4f565b6040516370a0823160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529192505f917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156125f8573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061261c9190612d21565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316146126fa576040516327f18ae360e01b81526001600160a01b0386811660048301527f0000000000000000000000000000000000000000000000000000000000000000811660248301528316906327f18ae3906044015f604051808303815f87803b1580156126df575f5ffd5b505af11580156126f1573d5f5f3e3d5ffd5b50505050612765565b6040516001600160a01b03861660248201525f9060440160408051601f198184030181529190526020810180516001600160e01b03166335313c2160e11b179052905061274783826118f9565b6127635760405162ec6f7b60e31b815260040160405180910390fd5b505b6040516370a0823160e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015282917f0000000000000000000000000000000000000000000000000000000000000000909116906370a0823190602401602060405180830381865afa1580156127ed573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128119190612d21565b61281b9190612e52565b95945050505050565b5f60808284031215612834575f5ffd5b50919050565b803560028110612848575f5ffd5b919050565b5f5f6040838503121561285e575f5ffd5b823567ffffffffffffffff811115612874575f5ffd5b61288085828601612824565b92505061288f6020840161283a565b90509250929050565b6001600160e01b031991909116815260200190565b6001600160a01b0381168114610f8e575f5ffd5b5f602082840312156128d1575f5ffd5b81356114d0816128ad565b5f5f5f606084860312156128ee575f5ffd5b833567ffffffffffffffff811115612904575f5ffd5b61291086828701612824565b93505061291f6020850161283a565b9150604084013561292f816128ad565b809150509250925092565b634e487b7160e01b5f52604160045260245ffd5b6040516080810167ffffffffffffffff811182821017156129715761297161293a565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156129a0576129a061293a565b604052919050565b5f5f604083850312156129b9575f5ffd5b82356129c4816128ad565b9150602083013567ffffffffffffffff8111156129df575f5ffd5b8301601f810185136129ef575f5ffd5b803567ffffffffffffffff811115612a0957612a0961293a565b612a1c601f8201601f1916602001612977565b818152866020838501011115612a30575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b5f60208284031215612a5f575f5ffd5b81516114d0816128ad565b5f60208284031215612a7a575f5ffd5b815180151581146114d0575f5ffd5b5f5f8335601e19843603018112612a9e575f5ffd5b83018035915067ffffffffffffffff821115612ab8575f5ffd5b6020019150600581901b3603821315612acf575f5ffd5b9250929050565b634e487b7160e01b5f52603260045260245ffd5b5f67ffffffffffffffff821115612b0357612b0361293a565b5060051b60200190565b5f82601f830112612b1c575f5ffd5b8151612b2f612b2a82612aea565b612977565b8082825260208201915060208360051b860101925085831115612b50575f5ffd5b602085015b83811015612b76578051612b68816128ad565b835260209283019201612b55565b5095945050505050565b5f60208284031215612b90575f5ffd5b815167ffffffffffffffff811115612ba6575f5ffd5b820160808185031215612bb7575f5ffd5b612bbf61294e565b8151612bca816128ad565b81526020820151612bda816128ad565b6020820152604082015167ffffffffffffffff811115612bf8575f5ffd5b612c0486828501612b0d565b604083015250606082015167ffffffffffffffff811115612c23575f5ffd5b80830192505084601f830112612c37575f5ffd5b8151612c45612b2a82612aea565b8082825260208201915060208360051b860101925087831115612c66575f5ffd5b6020850194505b82851015612c88578451825260209485019490910190612c6d565b6060840152509095945050505050565b604080825283519082018190525f9060208501906060840190835b81811015612cda5783516001600160a01b0316835260209384019390920191600101612cb3565b5050838103602080860191909152855180835291810192508501905f5b81811015612d15578251845260209384019390920191600101612cf7565b50919695505050505050565b5f60208284031215612d31575f5ffd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561116357611163612d38565b634e487b7160e01b5f52602160045260245ffd5b5f60208284031215612d83575f5ffd5b815167ffffffffffffffff811115612d99575f5ffd5b6106c384828501612b0d565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b60018060a01b0385168152836020820152608060408201525f612df96080830185612da5565b905060028310612e1757634e487b7160e01b5f52602160045260245ffd5b82606083015295945050505050565b6001600160a01b038416815260ff831660208201526060604082018190525f9061281b90830184612da5565b8181038181111561116357611163612d38565b6001600160801b03818116838216019081111561116357611163612d3856fea26469706673582212207e647b1cbd8a017c0242c5d8171da613207b8c1e46a18034346843befba907e164736f6c634300081c00330000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6
Deployed Bytecode
0x608060405234801561000f575f5ffd5b50600436106100cb575f3560e01c80636b9f96ea116100885780637aaf53e6116100635780637aaf53e61461020c5780638b9d29401461023357806399248ea71461025a578063cce2f3fb14610281575f5ffd5b80636b9f96ea146101d057806370a08231146101d85780637399bfe8146101f9575f5ffd5b806308ecd9a6146100cf5780630c96a583146101135780630db41f311461014d57806321c28191146101815780632d8e214214610196578063338c5371146101a9575b5f5ffd5b6100f67f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b681565b6040516001600160a01b0390911681526020015b60405180910390f35b61012661012136600461284d565b610294565b6040805182516001600160801b03908116825260209384015116928101929092520161010a565b6101747fc715e3730000000000000000000000000000000000000000000000000000000081565b60405161010a9190612898565b61019461018f3660046128c1565b6106cb565b005b6101266101a43660046128dc565b610bae565b6100f67f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b681565b610194610f06565b6101eb6101e63660046128c1565b610f91565b60405190815260200161010a565b6101266102073660046129a8565b6110f8565b6100f67f0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb81565b6100f67f00000000000000000000000093b4b9bd266ffa8af68e39edfa8cfe2a62011ce081565b6100f67f000000000000000000000000331b9182088e2a7d6d3fe4742aba1fb231aecc5681565b61019461028f3660046128c1565b611169565b604080518082019091525f80825260208201526102b760408401602085016128c1565b60405163f815c03d60e01b81526001600160a01b03828116600483015233917f0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb9091169063f815c03d90602401602060405180830381865afa15801561031f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103439190612a4f565b6001600160a01b03161461036a57604051638d1af8bd60e01b815260040160405180910390fd5b6001600160a01b037f0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb16634bc5d7356103a960408701602088016128c1565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156103eb573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061040f9190612a6a565b1561042d576040516301970f6d60e71b815260040160405180910390fd5b6040516304db2f3360e11b81526001600160a01b037f0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb16906309b65e6690610499907fc715e3730000000000000000000000000000000000000000000000000000000090600401612898565b602060405180830381865afa1580156104b4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104d89190612a6a565b156104f65760405163deeb694360e01b815260040160405180910390fd5b5f5b6105056040860186612a89565b90508110156106a9575f61051c6060870187612a89565b8381811061052c5761052c612ad6565b9050602002013511156106a1576001600160a01b037f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6166105706040870187612a89565b8381811061058057610580612ad6565b905060200201602081019061059591906128c1565b6001600160a01b0316036105f1576105ec6105b360208701876128c1565b6105c360408801602089016128c1565b6105d06060890189612a89565b858181106105e0576105e0612ad6565b905060200201356112f4565b6106a1565b6105fe6040860186612a89565b8281811061060e5761060e612ad6565b905060200201602081019061062391906128c1565b6001600160a01b031663b6b55f2561063e6060880188612a89565b8481811061064e5761064e612ad6565b905060200201356040518263ffffffff1660e01b815260040161067391815260200190565b5f604051808303815f87803b15801561068a575f5ffd5b505af115801561069c573d5f5f3e3d5ffd5b505050505b6001016104f8565b506106c36106bd60408601602087016128c1565b84611361565b949350505050565b604051634bc5d73560e01b81526001600160a01b0382811660048301527f0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb1690634bc5d73590602401602060405180830381865afa15801561072f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107539190612a6a565b15610771576040516301970f6d60e71b815260040160405180910390fd5b6040516304db2f3360e11b81526001600160a01b037f0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb16906309b65e66906107dd907fc715e3730000000000000000000000000000000000000000000000000000000090600401612898565b602060405180830381865afa1580156107f8573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061081c9190612a6a565b1561083a5760405163deeb694360e01b815260040160405180910390fd5b60405163ef64d76360e01b81525f906001600160a01b037f0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb169063ef64d763906108a8907fc715e3730000000000000000000000000000000000000000000000000000000090600401612898565b602060405180830381865afa1580156108c3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108e79190612a4f565b604051634e2333d160e11b81526001600160a01b0384811660048301529192505f917f0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb1690639c4667a290602401602060405180830381865afa158015610950573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109749190612a4f565b90505f61098084610f91565b90505f61098c856113b4565b905061099a838683306114d7565b604051632f3c319f60e01b81526001600160a01b0384811660048301528681166024830152604482018490525f9190861690632f3c319f906064015f60405180830381865afa1580156109ef573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610a169190810190612b80565b60408101515190915060018111610a4057604051635121f34360e01b815260040160405180910390fd5b5f5b81811015610b59575f83604001518281518110610a6157610a61612ad6565b602002602001015190505f84606001518381518110610a8257610a82612ad6565b60200260200101519050610aaa82828a6001600160a01b03166116b19092919063ffffffff16565b8015610b4f577f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b0316826001600160a01b031603610af957610af4888b836112f4565b610b4f565b60405163b6b55f2560e01b8152600481018290526001600160a01b0383169063b6b55f25906024015f604051808303815f87803b158015610b38575f5ffd5b505af1158015610b4a573d5f5f3e3d5ffd5b505050505b5050600101610a42565b50866001600160a01b03167f7999601d1a757a3c60f7cc686ee486ef059e7aa194251eb545a340f5fbba330e83604001518460600151604051610b9d929190612c98565b60405180910390a250505050505050565b604080518082019091525f8082526020820152610bd160408501602086016128c1565b60405163f815c03d60e01b81526001600160a01b03828116600483015233917f0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb9091169063f815c03d90602401602060405180830381865afa158015610c39573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c5d9190612a4f565b6001600160a01b031614610c8457604051638d1af8bd60e01b815260040160405180910390fd5b5f610c9560408701602088016128c1565b604051634bc5d73560e01b81526001600160a01b0380831660048301529192507f0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb90911690634bc5d73590602401602060405180830381865afa158015610cfe573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d229190612a6a565b15610d3957610d318186611361565b925050610efe565b5f5b610d486040880188612a89565b9050811015610eef575f610d5f6060890189612a89565b83818110610d6f57610d6f612ad6565b905060200201351115610ee7576001600160a01b037f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b616610db36040890189612a89565b83818110610dc357610dc3612ad6565b9050602002016020810190610dd891906128c1565b6001600160a01b031603610e2657610e21610df660208901896128c1565b83610e0460608b018b612a89565b85818110610e1457610e14612ad6565b9050602002013588611708565b610ee7565b610e336040880188612a89565b82818110610e4357610e43612ad6565b9050602002016020810190610e5891906128c1565b6001600160a01b031662f714ce610e7260608a018a612a89565b84818110610e8257610e82612ad6565b90506020020135876040518363ffffffff1660e01b8152600401610eb99291909182526001600160a01b0316602082015260400190565b5f604051808303815f87803b158015610ed0575f5ffd5b505af1158015610ee2573d5f5f3e3d5ffd5b505050505b600101610d3b565b50610efa8186611361565b9250505b509392505050565b7f00000000000000000000000093b4b9bd266ffa8af68e39edfa8cfe2a62011ce06001600160a01b03163314610f4f5760405163baf4cbdd60e01b815260040160405180910390fd5b7f56d95056ce1c07cd2be5f6ba7c1032b2ced7959a89d4000fbfdb5b75562325485c5f819003610f7c5750565b610f85816117e5565b610f8e5f61189d565b50565b5f5f610f9c836113b4565b80519091505f5b818110156110f0575f838281518110610fbe57610fbe612ad6565b602002602001015190507f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b0316816001600160a01b03160361107a576040516370a0823160e01b81526001600160a01b0382811660048301528716906370a0823190602401602060405180830381865afa158015611045573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110699190612d21565b6110739086612d4c565b94506110e7565b806001600160a01b031663722713f76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110b6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110da9190612d21565b6110e49086612d4c565b94505b50600101610fa3565b505050919050565b604080518082019091525f80825260208201527f00000000000000000000000093b4b9bd266ffa8af68e39edfa8cfe2a62011ce06001600160a01b031633146111545760405163baf4cbdd60e01b815260040160405180910390fd5b611160838360016118c7565b90505b92915050565b336001600160a01b037f0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb16146111b2576040516311db81c560e21b815260040160405180910390fd5b60405163f815c03d60e01b81526001600160a01b0382811660048301525f917f0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb9091169063f815c03d90602401602060405180830381865afa15801561121a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061123e9190612a4f565b90505f816001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561127d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112a19190612a4f565b90505f6112ad846113b4565b90506112bb828583866114d7565b6040516001600160a01b038516907f28b4c24cb1012c094cd2f59f98e89d791973295f8fda6eaa118022d6d318960a905f90a250505050565b5f8160405160240161130891815260200190565b60408051601f198184030181529190526020810180516001600160e01b031663b6b55f2560e01b179052905061133e83826118f9565b61135b576040516379cacff160e01b815260040160405180910390fd5b50505050565b604080518082019091525f8082526020820152600182600181111561138857611388612d5f565b1461139b5761139683611adf565b611160565b6111608360405180602001604052805f8152505f6118c7565b60605f7f0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb6001600160a01b031663ef64d7637fc715e373000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b81526004016114239190612898565b602060405180830381865afa15801561143e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114629190612a4f565b60405163db8c1be960e01b81526001600160a01b0385811660048301529192509082169063db8c1be9906024015f60405180830381865afa1580156114a9573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526114d09190810190612d73565b9392505050565b81515f5b818110156116a9575f8482815181106114f6576114f6612ad6565b602002602001015190505f7f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b0316826001600160a01b0316036115db576040516370a0823160e01b81526001600160a01b037f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6811660048301528816906370a0823190602401602060405180830381865afa15801561159e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115c29190612d21565b905080156115d6576115d688888388611708565b61169f565b816001600160a01b031663722713f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611617573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061163b9190612d21565b9050801561169f57604051627b8a6760e11b8152600481018290526001600160a01b03868116602483015283169062f714ce906044015f604051808303815f87803b158015611688575f5ffd5b505af115801561169a573d5f5f3e3d5ffd5b505050505b50506001016114db565b505050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611703908490611f46565b505050565b5f8260405160240161171c91815260200190565b60408051601f198184030181529190526020810180516001600160e01b0316632e1a7d4d60e01b179052905061175284826118f9565b61176f57604051631d42c86760e21b815260040160405180910390fd5b6040516001600160a01b03831660248201526044810184905260640160408051601f198184030181529190526020810180516001600160e01b031663a9059cbb60e01b17905290506117c185826118f9565b6117de576040516312171d8360e31b815260040160405180910390fd5b5050505050565b8015610f8e57604080517f00000000000000000000000093b4b9bd266ffa8af68e39edfa8cfe2a62011ce06001600160a01b0316602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261187c7f000000000000000000000000331b9182088e2a7d6d3fe4742aba1fb231aecc56826118f9565b611899576040516304fc2be760e01b815260040160405180910390fd5b5050565b610f8e7f56d95056ce1c07cd2be5f6ba7c1032b2ced7959a89d4000fbfdb5b755623254882611fb7565b604080518082019091525f80825260208201526118e384611fbe565b6118ee8484846120ce565b90506114d08461225e565b5f7f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b03167f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b0316036119ec5760405163468721a760e01b81526001600160a01b037f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6169063468721a7906119a59086905f9087908290600401612dd3565b6020604051808303815f875af11580156119c1573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119e59190612a6a565b9050611163565b7f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b031663468721a77f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b65f865f87604051602401611a5293929190612e26565b60408051601f198184030181529181526020820180516001600160e01b0316635b0e93fb60e11b1790525160e085901b6001600160e01b0319168152611a9f939291905f90600401612dd3565b6020604051808303815f875af1158015611abb573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111609190612a6a565b604080518082019091525f80825260208201525f826001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b2f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b539190612a4f565b90505f7f0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb6001600160a01b031663ef64d7637fc715e373000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b8152600401611bc29190612898565b602060405180830381865afa158015611bdd573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c019190612a4f565b60405163db8c1be960e01b81526001600160a01b0386811660048301529192505f9183169063db8c1be9906024015f60405180830381865afa158015611c49573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611c709190810190612d73565b6040516001600160a01b037f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6166024820152909150611cdd90869060440160408051601f198184030181529190526020810180516001600160e01b0316634b82009360e01b1790526118f9565b611cfa57604051630d027b0960e41b815260040160405180910390fd5b5f805b8251811015611f3c575f838281518110611d1957611d19612ad6565b602002602001015190507f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b0316816001600160a01b031603611ea9576040516308b752bb60e41b81526001600160a01b037f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6811660048301528981166024830152871690638b752bb090604401602060405180830381865afa158015611dc8573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611dec9190612d21565b604051630940070760e01b81526001600160a01b037f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6811660048301528a1690630940070790602401602060405180830381865afa158015611e50573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e749190612d21565b611e7e9190612e52565b9250611e89836124d6565b87518890611e98908390612e65565b6001600160801b0316905250611f0d565b806001600160a01b031663d9621f9e6040518163ffffffff1660e01b81526004016020604051808303815f875af1158015611ee6573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f0a9190612d21565b92505b611f16836124d6565b87602001818151611f279190612e65565b6001600160801b031690525050600101611cfd565b5050505050919050565b5f5f60205f8451602086015f885af180611f65576040513d5f823e3d81fd5b50505f513d91508115611f7c578060011415611f89565b6001600160a01b0384163b155b1561135b57604051635274afe760e01b81526001600160a01b03851660048201526024015b60405180910390fd5b80825d5050565b60405163b389020960e01b81525f906001600160a01b037f0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb169063b38902099061202c907fc715e3730000000000000000000000000000000000000000000000000000000090600401612898565b602060405180830381865afa158015612047573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061206b9190612a4f565b90506001600160a01b0381161561189957604051633bc9a43160e01b81526001600160a01b038381166004830152821690633bc9a431906024015f604051808303815f87803b1580156120bc575f5ffd5b505af11580156116a9573d5f5f3e3d5ffd5b604080518082019091525f80825260208201525f6120eb856113b4565b80519091505f90815b81811015612253575f84828151811061210f5761210f612ad6565b602002602001015190507f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b0316816001600160a01b0316036121c05761215c898961250d565b9350612167846124d6565b6001600160801b0316865286156121b2577f56d95056ce1c07cd2be5f6ba7c1032b2ced7959a89d4000fbfdb5b75562325485c6121ac6121a78683612d4c565b61189d565b50612224565b6121bb846117e5565b612224565b806001600160a01b0316634e71d92d6040518163ffffffff1660e01b81526004016020604051808303815f875af11580156121fd573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122219190612d21565b93505b61222d846124d6565b8660200181815161223e9190612e65565b6001600160801b0316905250506001016120f4565b505050509392505050565b604051630339050960e51b81526001600160a01b0382811660048301525f917f0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb90911690636720a12090602401602060405180830381865afa1580156122c6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122ea9190612a4f565b6040516001600160a01b037f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b681166024830152821660448201529091505f9060640160408051601f198184030181529190526020810180516001600160e01b0316639faceb1b60e01b179052905061236283826118f9565b61237f5760405163cc5c2c2760e01b815260040160405180910390fd5b60405163f815c03d60e01b81526001600160a01b0384811660048301525f917f0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb9091169063f815c03d90602401602060405180830381865afa1580156123e7573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061240b9190612a4f565b90505f816001600160a01b031663c4f59f9b6040518163ffffffff1660e01b81526004015f60405180830381865afa158015612449573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526124709190810190612d73565b905080515f03612481575050505050565b836001600160a01b0316636f4a2cd06040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156124b9575f5ffd5b505af11580156124cb573d5f5f3e3d5ffd5b505050505050505050565b5f6001600160801b03821115612509576040516306dfcc6560e41b81526080600482015260248101839052604401611fae565b5090565b5f5f836001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa15801561254b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061256f9190612a4f565b6040516370a0823160e01b81526001600160a01b037f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6811660048301529192505f917f000000000000000000000000331b9182088e2a7d6d3fe4742aba1fb231aecc5616906370a0823190602401602060405180830381865afa1580156125f8573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061261c9190612d21565b90507f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b03167f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b0316146126fa576040516327f18ae360e01b81526001600160a01b0386811660048301527f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6811660248301528316906327f18ae3906044015f604051808303815f87803b1580156126df575f5ffd5b505af11580156126f1573d5f5f3e3d5ffd5b50505050612765565b6040516001600160a01b03861660248201525f9060440160408051601f198184030181529190526020810180516001600160e01b03166335313c2160e11b179052905061274783826118f9565b6127635760405162ec6f7b60e31b815260040160405180910390fd5b505b6040516370a0823160e01b81526001600160a01b037f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b68116600483015282917f000000000000000000000000331b9182088e2a7d6d3fe4742aba1fb231aecc56909116906370a0823190602401602060405180830381865afa1580156127ed573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128119190612d21565b61281b9190612e52565b95945050505050565b5f60808284031215612834575f5ffd5b50919050565b803560028110612848575f5ffd5b919050565b5f5f6040838503121561285e575f5ffd5b823567ffffffffffffffff811115612874575f5ffd5b61288085828601612824565b92505061288f6020840161283a565b90509250929050565b6001600160e01b031991909116815260200190565b6001600160a01b0381168114610f8e575f5ffd5b5f602082840312156128d1575f5ffd5b81356114d0816128ad565b5f5f5f606084860312156128ee575f5ffd5b833567ffffffffffffffff811115612904575f5ffd5b61291086828701612824565b93505061291f6020850161283a565b9150604084013561292f816128ad565b809150509250925092565b634e487b7160e01b5f52604160045260245ffd5b6040516080810167ffffffffffffffff811182821017156129715761297161293a565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156129a0576129a061293a565b604052919050565b5f5f604083850312156129b9575f5ffd5b82356129c4816128ad565b9150602083013567ffffffffffffffff8111156129df575f5ffd5b8301601f810185136129ef575f5ffd5b803567ffffffffffffffff811115612a0957612a0961293a565b612a1c601f8201601f1916602001612977565b818152866020838501011115612a30575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b5f60208284031215612a5f575f5ffd5b81516114d0816128ad565b5f60208284031215612a7a575f5ffd5b815180151581146114d0575f5ffd5b5f5f8335601e19843603018112612a9e575f5ffd5b83018035915067ffffffffffffffff821115612ab8575f5ffd5b6020019150600581901b3603821315612acf575f5ffd5b9250929050565b634e487b7160e01b5f52603260045260245ffd5b5f67ffffffffffffffff821115612b0357612b0361293a565b5060051b60200190565b5f82601f830112612b1c575f5ffd5b8151612b2f612b2a82612aea565b612977565b8082825260208201915060208360051b860101925085831115612b50575f5ffd5b602085015b83811015612b76578051612b68816128ad565b835260209283019201612b55565b5095945050505050565b5f60208284031215612b90575f5ffd5b815167ffffffffffffffff811115612ba6575f5ffd5b820160808185031215612bb7575f5ffd5b612bbf61294e565b8151612bca816128ad565b81526020820151612bda816128ad565b6020820152604082015167ffffffffffffffff811115612bf8575f5ffd5b612c0486828501612b0d565b604083015250606082015167ffffffffffffffff811115612c23575f5ffd5b80830192505084601f830112612c37575f5ffd5b8151612c45612b2a82612aea565b8082825260208201915060208360051b860101925087831115612c66575f5ffd5b6020850194505b82851015612c88578451825260209485019490910190612c6d565b6060840152509095945050505050565b604080825283519082018190525f9060208501906060840190835b81811015612cda5783516001600160a01b0316835260209384019390920191600101612cb3565b5050838103602080860191909152855180835291810192508501905f5b81811015612d15578251845260209384019390920191600101612cf7565b50919695505050505050565b5f60208284031215612d31575f5ffd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561116357611163612d38565b634e487b7160e01b5f52602160045260245ffd5b5f60208284031215612d83575f5ffd5b815167ffffffffffffffff811115612d99575f5ffd5b6106c384828501612b0d565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b60018060a01b0385168152836020820152608060408201525f612df96080830185612da5565b905060028310612e1757634e487b7160e01b5f52602160045260245ffd5b82606083015295945050505050565b6001600160a01b038416815260ff831660208201526060604082018190525f9061281b90830184612da5565b8181038181111561116357611163612d38565b6001600160801b03818116838216019081111561116357611163612d3856fea26469706673582212207e647b1cbd8a017c0242c5d8171da613207b8c1e46a18034346843befba907e164736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6
-----Decoded View---------------
Arg [0] : _registry (address): 0x2d8BcE1FaE00a959354aCD9eBf9174337A64d4fb
Arg [1] : _locker (address): 0x0000000000000000000000000000000000000000
Arg [2] : _gateway (address): 0x52f541764E6e90eeBc5c21Ff570De0e2D63766B6
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb
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 ]
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.