FRAX Price: $1.03 (+6.53%)
Gas: 1 Gwei

Contract

0x735A969463967578Fcc17cEB9bba32893d00f71d

Overview

FRAX Balance | FXTL Balance

0 FRAX | 236 FXTL

FRAX Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

1 Internal Transaction and 1 Token Transfer found.

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
232365662025-07-23 15:17:23185 days ago1753283843  Contract Creation0 FRAX

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ConvexSidecarL2

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import {IL2Booster} from "@interfaces/convex/IL2Booster.sol";
import {IL2BaseRewardPool} from "@interfaces/convex/IL2BaseRewardPool.sol";
import {IStashTokenWrapper} from "@interfaces/convex/IStashTokenWrapper.sol";
import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {CurveProtocol} from "@address-book/src/CurveEthereum.sol";
import {ImmutableArgsParser} from "src/libraries/ImmutableArgsParser.sol";
import {Sidecar} from "src/Sidecar.sol";

/// @title ConvexSidecarL2.
/// @author Stake DAO
/// @custom:github @stake-dao
/// @custom:contact [email protected]

/// @notice ConvexSidecarL2 is a specialized sidecar implementation for Convex integration on Layer 2 networks.
///         For each PID, a minimal proxy is deployed using this contract as implementation.
///
///         Key differences from mainnet ConvexSidecar:
///         - Uses L2-specific interfaces (IL2Booster, IL2BaseRewardPool)
///         - No extra reward differentiation, all rewards are claimed and sent to the
///           good reward receiver, either the RewardReceiver or the Accountant.
contract ConvexSidecarL2 is Sidecar {
    using SafeERC20 for IERC20;
    using ImmutableArgsParser for address;

    /// @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"));

    //////////////////////////////////////////////////////
    // ---  IMPLEMENTATION CONSTANTS
    //////////////////////////////////////////////////////

    /// @notice Convex Reward Token address.
    IERC20 public immutable CVX;

    /// @notice Convex Booster address.
    address public immutable BOOSTER;

    //////////////////////////////////////////////////////
    // --- ISIDECAR CLONE IMMUTABLES
    //////////////////////////////////////////////////////

    /// @notice Staking token address.
    function asset() public view override returns (IERC20 _asset) {
        return IERC20(address(this).readAddress(0));
    }

    function rewardReceiver() public view override returns (address _rewardReceiver) {
        return address(this).readAddress(20);
    }

    //////////////////////////////////////////////////////
    // --- CONVEX CLONE IMMUTABLES
    //////////////////////////////////////////////////////

    /// @notice Staking Convex LP contract address.
    function baseRewardPool() public view returns (IL2BaseRewardPool _baseRewardPool) {
        return IL2BaseRewardPool(address(this).readAddress(40));
    }

    /// @notice Identifier of the pool on Convex.
    function pid() public view returns (uint256 _pid) {
        return address(this).readUint256(60);
    }

    //////////////////////////////////////////////////////
    // --- CONSTRUCTOR
    //////////////////////////////////////////////////////

    constructor(address _accountant, address _protocolController, address _cvx, address _booster)
        Sidecar(CURVE_PROTOCOL_ID, _accountant, _protocolController)
    {
        CVX = IERC20(_cvx);
        BOOSTER = _booster;
    }

    //////////////////////////////////////////////////////
    // --- INITIALIZATION
    //////////////////////////////////////////////////////

    /// @notice Initialize the contract by approving the ConvexCurve booster to spend the LP token.
    function _initialize() internal override {
        require(asset().allowance(address(this), address(BOOSTER)) == 0, AlreadyInitialized());

        asset().forceApprove(address(BOOSTER), type(uint256).max);
    }

    //////////////////////////////////////////////////////
    // --- ISIDECAR OPERATIONS OVERRIDE
    //////////////////////////////////////////////////////

    /// @notice Deposit LP token into Convex.
    /// @param amount Amount of LP token to deposit.
    /// @dev The reason there's an empty address parameter is to keep flexibility for future implementations.
    /// Not all fallbacks will be minimal proxies, so we need to keep the same function signature.
    /// Only callable by the strategy.
    function _deposit(uint256 amount) internal override {
        /// Deposit the LP token into Convex.
        IL2Booster(BOOSTER).deposit(pid(), amount);
    }

    /// @notice Withdraw LP token from Convex.
    /// @param amount Amount of LP token to withdraw.
    /// @param receiver Address to receive the LP token.
    function _withdraw(uint256 amount, address receiver) internal override {
        /// Withdraw from Convex gauge with claiming rewards (true).
        baseRewardPool().withdraw(amount, true);

        /// Send the LP token to the receiver.
        asset().safeTransfer(receiver, amount);
    }

    /// @notice Claim rewards from Convex.
    /// @return rewardTokenAmount Amount of reward token claimed.
    function _claim() internal override returns (uint256 rewardTokenAmount) {
        /// Claim rewardToken.
        baseRewardPool().getReward(address(this));

        address[] memory rewardTokens = getRewardTokens();

        for (uint256 i = 0; i < rewardTokens.length;) {
            address rewardToken = rewardTokens[i];
            uint256 _balance = IERC20(rewardToken).balanceOf(address(this));

            if (_balance > 0) {
                if (rewardToken == address(REWARD_TOKEN)) {
                    rewardTokenAmount += _balance;
                    IERC20(rewardToken).safeTransfer(ACCOUNTANT, _balance);
                } else {
                    /// Send the whole balance to the strategy.
                    IERC20(rewardToken).safeTransfer(rewardReceiver(), _balance);
                }
            }

            unchecked {
                ++i;
            }
        }
    }

    /// @notice Get the balance of the LP token on Convex held by this contract.
    function balanceOf() public view override returns (uint256) {
        return baseRewardPool().balanceOf(address(this));
    }

    /// @notice Get the reward tokens from the base reward pool.
    /// @return Array of all extra reward tokens.
    function getRewardTokens() public view override returns (address[] memory) {
        // Check if there is extra rewards
        uint256 extraRewardsLength = baseRewardPool().rewardLength();

        address[] memory tokens = new address[](extraRewardsLength);

        for (uint256 i; i < extraRewardsLength;) {
            IL2BaseRewardPool.RewardType memory reward = baseRewardPool().rewards(i);
            tokens[i] = reward.rewardToken;
            unchecked {
                ++i;
            }
        }

        return tokens;
    }

    /// @notice Get the amount of reward token earned by the strategy.
    /// @return The amount of reward token earned by the strategy.
    function getPendingRewards() public override returns (uint256) {
        IL2BaseRewardPool.EarnedData[] memory earned = baseRewardPool().earned(address(this));

        uint256 totalRewards = 0;

        for (uint256 i; i < earned.length;) {
            if (earned[i].rewardToken == address(REWARD_TOKEN)) {
                totalRewards += earned[i].earnedAmount;
                break;
            }

            unchecked {
                ++i;
            }
        }

        return totalRewards + REWARD_TOKEN.balanceOf(address(this));
    }
}

/// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.19;

interface IL2Booster {
    function poolLength() external view returns (uint256);

    function poolInfo(uint256 pid)
        external
        view
        returns (address lpToken, address gauge, address rewards, bool shutdown, address factory);

    function deposit(uint256 _pid, uint256 _amount) external returns (bool);

}

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.19;

interface IL2BaseRewardPool {

    struct EarnedData {
        address rewardToken;
        uint256 earnedAmount;
    }

    struct RewardType {
        address rewardToken;
        uint256 rewardIntegral;
        uint256 rewardRemaining;
    }

    function getReward(address _account) external;
    function withdraw(uint256 amount, bool claim) external returns (bool);
    function balanceOf(address _account) external view returns (uint256);
    function earned(address _account) external returns (EarnedData[] memory);
    function rewardLength() external view returns (uint256);
    function rewards(uint256 index) external view returns (RewardType memory);
}

File 4 of 21 : IStashTokenWrapper.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.19;

interface IStashTokenWrapper {
    function token() external view returns (address);
}

// 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: AGPL-3.0-only
pragma solidity >=0.8.0;

library CurveProtocol {
    address internal constant CRV = 0xD533a949740bb3306d119CC777fa900bA034cd52;
    address internal constant VECRV = 0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2;
    address internal constant CRV_USD = 0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E;
    address internal constant SD_VE_CRV = 0x478bBC744811eE8310B461514BDc29D03739084D;

    address internal constant FEE_DISTRIBUTOR = 0xD16d5eC345Dd86Fb63C6a9C43c517210F1027914;
    address internal constant GAUGE_CONTROLLER = 0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB;
    address internal constant SMART_WALLET_CHECKER = 0xca719728Ef172d0961768581fdF35CB116e0B7a4;

    address internal constant VOTING_APP_OWNERSHIP = 0xE478de485ad2fe566d49342Cbd03E49ed7DB3356;
    address internal constant VOTING_APP_PARAMETER = 0xBCfF8B0b9419b9A88c44546519b1e909cF330399;
    address internal constant MINTER = 0xd061D61a4d941c39E5453435B6345Dc261C2fcE0;
    address internal constant VE_BOOST = 0xD37A6aa3d8460Bd2b6536d608103D880695A23CD;

    // Convex
    address internal constant CONVEX_PROXY = 0x989AEb4d175e16225E39E87d0D97A3360524AD80;
    address internal constant CONVEX_BOOSTER = 0xF403C135812408BFbE8713b5A23a04b3D48AAE31;
    address internal constant CONVEX_TOKEN = 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B; // CVX
}

library CurveLocker {
    address internal constant TOKEN = 0xD533a949740bb3306d119CC777fa900bA034cd52;
    address internal constant SDTOKEN = 0xD1b5651E55D4CeeD36251c61c50C889B36F6abB5;
    address internal constant LOCKER = 0x52f541764E6e90eeBc5c21Ff570De0e2D63766B6;
    address internal constant DEPOSITOR = 0x88C88Aa6a9cedc2aff9b4cA6820292F39cc64026;
    address internal constant GAUGE = 0x7f50786A0b15723D741727882ee99a0BF34e3466;
    address internal constant ACCUMULATOR = 0x615959a1d3E2740054d7130028613ECfa988056f;
    address internal constant VOTER = 0x20b22019406Cf990F0569a6161cf30B8e6651dDa;

    address internal constant STRATEGY = 0x69D61428d089C2F35Bf6a472F540D0F82D1EA2cd;
    address internal constant FACTORY = 0xDC9718E7704f10DB1aFaad737f8A04bcd14C20AA;
    address internal constant VE_BOOST_DELEGATION = 0xe1F9C8ebBC80A013cAf0940fdD1A8554d763b9cf;
}

library CurveVotemarket {
    address internal constant PLATFORM = 0x0000000895cB182E6f983eb4D8b4E0Aa0B31Ae4c;
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";

/// @title ImmutableArgsParser
/// @notice A library for reading immutable arguments from a clone.
library ImmutableArgsParser {
    /// @dev Safely read an `address` from `clone`'s immutable args at `offset`.
    function readAddress(address clone, uint256 offset) internal view returns (address result) {
        bytes memory args = Clones.fetchCloneArgs(clone);
        assembly {
            // Load 32 bytes starting at `args + offset + 32`. Then shift right
            // by 96 bits (12 bytes) so that the address is right‐aligned and
            // the high bits are cleared.
            result := shr(96, mload(add(add(args, 0x20), offset)))
        }
    }

    /// @dev Safely read a `uint256` from `clone`'s immutable args at `offset`.
    function readUint256(address clone, uint256 offset) internal view returns (uint256 result) {
        bytes memory args = Clones.fetchCloneArgs(clone);
        assembly {
            // Load the entire 32‐byte word directly.
            result := mload(add(add(args, 0x20), offset))
        }
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import {ISidecar} from "src/interfaces/ISidecar.sol";
import {IAccountant} from "src/interfaces/IAccountant.sol";
import {IProtocolController} from "src/interfaces/IProtocolController.sol";

/// @title Sidecar.
/// @author Stake DAO
/// @custom:github @stake-dao
/// @custom:contact [email protected]

/// @notice Sidecar is an abstract base contract for protocol-specific yield sources that complement the main locker strategy.
///         It enables yield diversification beyond the main protocol locker (e.g., Convex alongside veCRV) and provides
///         a protocol-agnostic base that can be extended for any yield source. Sidecars are managed by the Strategy
///         for unified deposit/withdraw/harvest operations, with rewards flowing through the Accountant for consistent distribution.
abstract contract Sidecar is ISidecar {
    using SafeERC20 for IERC20;

    //////////////////////////////////////////////////////
    // --- IMMUTABLES
    //////////////////////////////////////////////////////

    /// @notice Protocol identifier matching the Strategy that manages this sidecar
    bytes4 public immutable PROTOCOL_ID;

    /// @notice Accountant that receives and distributes rewards from this sidecar
    address public immutable ACCOUNTANT;

    /// @notice Main protocol reward token claimed by this sidecar (e.g., CRV)
    IERC20 public immutable REWARD_TOKEN;

    /// @notice Registry used to verify the authorized strategy for this protocol
    IProtocolController public immutable PROTOCOL_CONTROLLER;

    //////////////////////////////////////////////////////
    // --- STORAGE
    //////////////////////////////////////////////////////

    /// @notice Prevents double initialization in factory deployment pattern
    bool private _initialized;

    //////////////////////////////////////////////////////
    // --- ERRORS
    //////////////////////////////////////////////////////

    error ZeroAddress();

    error OnlyStrategy();

    error OnlyAccountant();

    error AlreadyInitialized();

    error NotInitialized();

    error InvalidProtocolId();

    //////////////////////////////////////////////////////
    // --- MODIFIERS
    //////////////////////////////////////////////////////

    /// @notice Restricts access to the authorized strategy for this protocol
    /// @dev Prevents unauthorized manipulation of user funds
    modifier onlyStrategy() {
        require(PROTOCOL_CONTROLLER.strategy(PROTOCOL_ID) == msg.sender, OnlyStrategy());
        _;
    }

    //////////////////////////////////////////////////////
    // --- CONSTRUCTOR
    //////////////////////////////////////////////////////

    /// @notice Sets up immutable protocol connections
    /// @dev Called by factory during deployment. Reward token fetched from accountant
    /// @param _protocolId Protocol identifier for strategy verification
    /// @param _accountant Where to send claimed rewards for distribution
    /// @param _protocolController Registry for strategy lookup and validation
    constructor(bytes4 _protocolId, address _accountant, address _protocolController) {
        require(_protocolId != bytes4(0), InvalidProtocolId());
        require(_accountant != address(0) && _protocolController != address(0), ZeroAddress());

        PROTOCOL_ID = _protocolId;
        ACCOUNTANT = _accountant;
        PROTOCOL_CONTROLLER = IProtocolController(_protocolController);
        REWARD_TOKEN = IERC20(IAccountant(_accountant).REWARD_TOKEN());

        _initialized = true;
    }

    //////////////////////////////////////////////////////
    // --- EXTERNAL FUNCTIONS
    //////////////////////////////////////////////////////

    /// @notice One-time setup for protocol-specific configuration
    /// @dev Factory pattern: minimal proxy clones need post-deployment init
    ///      Base constructor sets _initialized=true, clones must call this
    function initialize() external {
        if (_initialized) revert AlreadyInitialized();
        _initialized = true;
        _initialize();
    }

    /// @notice Stakes LP tokens into the protocol-specific yield source
    /// @dev Strategy transfers tokens here first, then calls deposit
    /// @param amount LP tokens to stake (must already be transferred)
    function deposit(uint256 amount) external onlyStrategy {
        _deposit(amount);
    }

    /// @notice Unstakes LP tokens and sends directly to receiver
    /// @dev Used during user withdrawals and emergency shutdowns
    /// @param amount LP tokens to unstake from yield source
    /// @param receiver Where to send the unstaked tokens (vault or user)
    function withdraw(uint256 amount, address receiver) external onlyStrategy {
        _withdraw(amount, receiver);
    }

    /// @notice Harvests rewards and transfers to accountant
    /// @dev Part of Strategy's harvest flow. Returns amount for accounting
    /// @return Amount of reward tokens sent to accountant
    function claim() external onlyStrategy returns (uint256) {
        return _claim();
    }

    //////////////////////////////////////////////////////
    // --- IMMUTABLES
    //////////////////////////////////////////////////////

    /// @notice LP token this sidecar manages (e.g., CRV/ETH LP)
    /// @dev Must match the asset used by the associated Strategy
    function asset() public view virtual returns (IERC20);

    /// @notice Where extra rewards (not main protocol rewards) should be sent
    /// @dev Typically the RewardVault for the gauge this sidecar supports
    function rewardReceiver() public view virtual returns (address);

    //////////////////////////////////////////////////////
    // --- INTERNAL VIRTUAL FUNCTIONS
    //////////////////////////////////////////////////////

    /// @dev Protocol-specific setup (approvals, staking contracts, etc.)
    function _initialize() internal virtual;

    /// @dev Stakes tokens in protocol-specific way (e.g., Convex deposit)
    /// @param amount Tokens to stake (already transferred to this contract)
    function _deposit(uint256 amount) internal virtual;

    /// @dev Claims all available rewards and transfers to accountant
    /// @return Total rewards claimed and transferred
    function _claim() internal virtual returns (uint256);

    /// @dev Unstakes from protocol and sends tokens to receiver
    /// @param amount Tokens to unstake
    /// @param receiver Destination for unstaked tokens
    function _withdraw(uint256 amount, address receiver) internal virtual;

    /// @notice Total LP tokens staked in this sidecar
    /// @dev Used by Strategy to calculate total assets across all sources
    /// @return Current staked balance
    function balanceOf() public view virtual returns (uint256);

    /// @notice Unclaimed rewards available for harvest
    /// @dev May perform view-only simulation or on-chain checkpoint
    /// @return Claimable reward token amount
    function getPendingRewards() public virtual returns (uint256);
}

// 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) (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: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (proxy/Clones.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev https://eips.ethereum.org/EIPS/eip-1167[ERC-1167] is a standard for
 * deploying minimal proxy contracts, also known as "clones".
 *
 * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
 * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
 *
 * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
 * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
 * deterministic method.
 */
library Clones {
    error CloneArgumentsTooLong();

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create opcode, which should never revert.
     */
    function clone(address implementation) internal returns (address instance) {
        return clone(implementation, 0);
    }

    /**
     * @dev Same as {xref-Clones-clone-address-}[clone], but with a `value` parameter to send native currency
     * to the new contract.
     *
     * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
     * to always have enough balance for new deployments. Consider exposing this function under a payable method.
     */
    function clone(address implementation, uint256 value) internal returns (address instance) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        assembly ("memory-safe") {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create(value, 0x09, 0x37)
        }
        if (instance == address(0)) {
            revert Errors.FailedDeployment();
        }
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy
     * the clone. Using the same `implementation` and `salt` multiple times will revert, since
     * the clones cannot be deployed twice at the same address.
     */
    function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
        return cloneDeterministic(implementation, salt, 0);
    }

    /**
     * @dev Same as {xref-Clones-cloneDeterministic-address-bytes32-}[cloneDeterministic], but with
     * a `value` parameter to send native currency to the new contract.
     *
     * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
     * to always have enough balance for new deployments. Consider exposing this function under a payable method.
     */
    function cloneDeterministic(
        address implementation,
        bytes32 salt,
        uint256 value
    ) internal returns (address instance) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        assembly ("memory-safe") {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create2(value, 0x09, 0x37, salt)
        }
        if (instance == address(0)) {
            revert Errors.FailedDeployment();
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            mstore(add(ptr, 0x38), deployer)
            mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
            mstore(add(ptr, 0x14), implementation)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
            mstore(add(ptr, 0x58), salt)
            mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
            predicted := and(keccak256(add(ptr, 0x43), 0x55), 0xffffffffffffffffffffffffffffffffffffffff)
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt
    ) internal view returns (address predicted) {
        return predictDeterministicAddress(implementation, salt, address(this));
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom
     * immutable arguments. These are provided through `args` and cannot be changed after deployment. To
     * access the arguments within the implementation, use {fetchCloneArgs}.
     *
     * This function uses the create opcode, which should never revert.
     */
    function cloneWithImmutableArgs(address implementation, bytes memory args) internal returns (address instance) {
        return cloneWithImmutableArgs(implementation, args, 0);
    }

    /**
     * @dev Same as {xref-Clones-cloneWithImmutableArgs-address-bytes-}[cloneWithImmutableArgs], but with a `value`
     * parameter to send native currency to the new contract.
     *
     * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
     * to always have enough balance for new deployments. Consider exposing this function under a payable method.
     */
    function cloneWithImmutableArgs(
        address implementation,
        bytes memory args,
        uint256 value
    ) internal returns (address instance) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
        assembly ("memory-safe") {
            instance := create(value, add(bytecode, 0x20), mload(bytecode))
        }
        if (instance == address(0)) {
            revert Errors.FailedDeployment();
        }
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation` with custom
     * immutable arguments. These are provided through `args` and cannot be changed after deployment. To
     * access the arguments within the implementation, use {fetchCloneArgs}.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy the clone. Using the same
     * `implementation`, `args` and `salt` multiple times will revert, since the clones cannot be deployed twice
     * at the same address.
     */
    function cloneDeterministicWithImmutableArgs(
        address implementation,
        bytes memory args,
        bytes32 salt
    ) internal returns (address instance) {
        return cloneDeterministicWithImmutableArgs(implementation, args, salt, 0);
    }

    /**
     * @dev Same as {xref-Clones-cloneDeterministicWithImmutableArgs-address-bytes-bytes32-}[cloneDeterministicWithImmutableArgs],
     * but with a `value` parameter to send native currency to the new contract.
     *
     * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
     * to always have enough balance for new deployments. Consider exposing this function under a payable method.
     */
    function cloneDeterministicWithImmutableArgs(
        address implementation,
        bytes memory args,
        bytes32 salt,
        uint256 value
    ) internal returns (address instance) {
        bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
        return Create2.deploy(value, salt, bytecode);
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}.
     */
    function predictDeterministicAddressWithImmutableArgs(
        address implementation,
        bytes memory args,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
        return Create2.computeAddress(salt, keccak256(bytecode), deployer);
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}.
     */
    function predictDeterministicAddressWithImmutableArgs(
        address implementation,
        bytes memory args,
        bytes32 salt
    ) internal view returns (address predicted) {
        return predictDeterministicAddressWithImmutableArgs(implementation, args, salt, address(this));
    }

    /**
     * @dev Get the immutable args attached to a clone.
     *
     * - If `instance` is a clone that was deployed using `clone` or `cloneDeterministic`, this
     *   function will return an empty array.
     * - If `instance` is a clone that was deployed using `cloneWithImmutableArgs` or
     *   `cloneDeterministicWithImmutableArgs`, this function will return the args array used at
     *   creation.
     * - If `instance` is NOT a clone deployed using this library, the behavior is undefined. This
     *   function should only be used to check addresses that are known to be clones.
     */
    function fetchCloneArgs(address instance) internal view returns (bytes memory) {
        bytes memory result = new bytes(instance.code.length - 45); // revert if length is too short
        assembly ("memory-safe") {
            extcodecopy(instance, add(result, 32), 45, mload(result))
        }
        return result;
    }

    /**
     * @dev Helper that prepares the initcode of the proxy with immutable args.
     *
     * An assembly variant of this function requires copying the `args` array, which can be efficiently done using
     * `mcopy`. Unfortunately, that opcode is not available before cancun. A pure solidity implementation using
     * abi.encodePacked is more expensive but also more portable and easier to review.
     *
     * NOTE: https://eips.ethereum.org/EIPS/eip-170[EIP-170] limits the length of the contract code to 24576 bytes.
     * With the proxy code taking 45 bytes, that limits the length of the immutable args to 24531 bytes.
     */
    function _cloneCodeWithImmutableArgs(
        address implementation,
        bytes memory args
    ) private pure returns (bytes memory) {
        if (args.length > 24531) revert CloneArgumentsTooLong();
        return
            abi.encodePacked(
                hex"61",
                uint16(args.length + 45),
                hex"3d81600a3d39f3363d3d373d3d3d363d73",
                implementation,
                hex"5af43d82803e903d91602b57fd5bf3",
                args
            );
    }
}

/// 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: 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;
}

File 15 of 21 : IERC20.sol
// 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";

File 16 of 21 : IERC165.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/Create2.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
 * `CREATE2` can be used to compute in advance the address where a smart
 * contract will be deployed, which allows for interesting new mechanisms known
 * as 'counterfactual interactions'.
 *
 * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
 * information.
 */
library Create2 {
    /**
     * @dev There's no code to deploy.
     */
    error Create2EmptyBytecode();

    /**
     * @dev Deploys a contract using `CREATE2`. The address where the contract
     * will be deployed can be known in advance via {computeAddress}.
     *
     * The bytecode for a contract can be obtained from Solidity with
     * `type(contractName).creationCode`.
     *
     * Requirements:
     *
     * - `bytecode` must not be empty.
     * - `salt` must have not been used for `bytecode` already.
     * - the factory must have a balance of at least `amount`.
     * - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
     */
    function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) {
        if (address(this).balance < amount) {
            revert Errors.InsufficientBalance(address(this).balance, amount);
        }
        if (bytecode.length == 0) {
            revert Create2EmptyBytecode();
        }
        assembly ("memory-safe") {
            addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
            // if no address was created, and returndata is not empty, bubble revert
            if and(iszero(addr), not(iszero(returndatasize()))) {
                let p := mload(0x40)
                returndatacopy(p, 0, returndatasize())
                revert(p, returndatasize())
            }
        }
        if (addr == address(0)) {
            revert Errors.FailedDeployment();
        }
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
     * `bytecodeHash` or `salt` will result in a new destination address.
     */
    function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
        return computeAddress(salt, bytecodeHash, address(this));
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
     * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
     */
    function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) {
        assembly ("memory-safe") {
            let ptr := mload(0x40) // Get free memory pointer

            // |                   | ↓ ptr ...  ↓ ptr + 0x0B (start) ...  ↓ ptr + 0x20 ...  ↓ ptr + 0x40 ...   |
            // |-------------------|---------------------------------------------------------------------------|
            // | bytecodeHash      |                                                        CCCCCCCCCCCCC...CC |
            // | salt              |                                      BBBBBBBBBBBBB...BB                   |
            // | deployer          | 000000...0000AAAAAAAAAAAAAAAAAAA...AA                                     |
            // | 0xFF              |            FF                                                             |
            // |-------------------|---------------------------------------------------------------------------|
            // | memory            | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
            // | keccak(start, 85) |            ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |

            mstore(add(ptr, 0x40), bytecodeHash)
            mstore(add(ptr, 0x20), salt)
            mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
            let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
            mstore8(start, 0xff)
            addr := and(keccak256(start, 85), 0xffffffffffffffffffffffffffffffffffffffff)
        }
    }
}

File 18 of 21 : Errors.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)

pragma solidity ^0.8.20;

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

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

    /**
     * @dev The deployment failed.
     */
    error FailedDeployment();

    /**
     * @dev A necessary precompile is missing.
     */
    error MissingPrecompile(address);
}

// 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: 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);
}

// 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);
}

Settings
{
  "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

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_accountant","type":"address"},{"internalType":"address","name":"_protocolController","type":"address"},{"internalType":"address","name":"_cvx","type":"address"},{"internalType":"address","name":"_booster","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"InvalidProtocolId","type":"error"},{"inputs":[],"name":"NotInitialized","type":"error"},{"inputs":[],"name":"OnlyAccountant","type":"error"},{"inputs":[],"name":"OnlyStrategy","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ACCOUNTANT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BOOSTER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CVX","outputs":[{"internalType":"contract IERC20","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":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"contract IERC20","name":"_asset","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseRewardPool","outputs":[{"internalType":"contract IL2BaseRewardPool","name":"_baseRewardPool","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getPendingRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getRewardTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pid","outputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardReceiver","outputs":[{"internalType":"address","name":"_rewardReceiver","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

610140604052348015610010575f5ffd5b5060405161151f38038061151f83398101604081905261002f9161015c565b7fc715e3736a8cb018f630cb9a1df908ad1629e9c2da4cd190b2dc83d6687ba16984846001600160a01b0382161580159061007257506001600160a01b03811615155b61008f5760405163d92e233d60e01b815260040160405180910390fd5b6001600160e01b031983166080526001600160a01b0380831660a081905290821660e052604080516399248ea760e01b815290516399248ea7916004808201926020929091908290030181865afa1580156100ec573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061011091906101ad565b6001600160a01b0390811660c0525f805460ff19166001179055948516610100525050501661012052506101cd9050565b80516001600160a01b0381168114610157575f5ffd5b919050565b5f5f5f5f6080858703121561016f575f5ffd5b61017885610141565b935061018660208601610141565b925061019460408601610141565b91506101a260608601610141565b905092959194509250565b5f602082840312156101bd575f5ffd5b6101c682610141565b9392505050565b60805160a05160c05160e05161010051610120516112b061026f5f395f81816101dd01528181610bdf01528181610c740152610caf01525f6101b601525f8181610204015281816102fd0152818161040e015261059801525f818161025a01528181610828015281816108c90152610b1301525f81816102330152610b6501525f8181610123015281816102cc015281816103db015261056701526112b05ff3fe608060405234801561000f575f5ffd5b5060043610610105575f3560e01c806375b0ffd11161009e57806399248ea71161006e57806399248ea714610255578063b6b55f251461027c578063c4f59f9b1461028f578063d9621f9e146102a4578063f1068454146102ac575f5ffd5b806375b0ffd1146101d85780637aaf53e6146101ff5780638129fc1c146102265780638b9d29401461022e575f5ffd5b8063475a91d1116100d9578063475a91d11461018b5780634e71d92d14610193578063722713f7146101a9578063759cb53b146101b1575f5ffd5b8062f714ce146101095780630db41f311461011e5780631dac30b01461016357806338d52e0f14610183575b5f5ffd5b61011c610117366004610f9a565b6102b4565b005b6101457f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160e01b031990911681526020015b60405180910390f35b61016b61039b565b6040516001600160a01b03909116815260200161015a565b61016b6103ac565b61016b6103b7565b61019b6103c3565b60405190815260200161015a565b61019b6104a6565b61016b7f000000000000000000000000000000000000000000000000000000000000000081565b61016b7f000000000000000000000000000000000000000000000000000000000000000081565b61016b7f000000000000000000000000000000000000000000000000000000000000000081565b61011c610517565b61016b7f000000000000000000000000000000000000000000000000000000000000000081565b61016b7f000000000000000000000000000000000000000000000000000000000000000081565b61011c61028a366004610fc8565b61054f565b610297610634565b60405161015a9190610fdf565b61019b6107a5565b61019b61094b565b604051630165699560e21b81526001600160e01b03197f000000000000000000000000000000000000000000000000000000000000000016600482015233906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690630595a65490602401602060405180830381865afa158015610342573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610366919061102a565b6001600160a01b03161461038d5760405163ade5da5f60e01b815260040160405180910390fd5b6103978282610957565b5050565b5f6103a73060146109ee565b905090565b5f6103a730826109ee565b5f6103a73060286109ee565b604051630165699560e21b81526001600160e01b03197f00000000000000000000000000000000000000000000000000000000000000001660048201525f9033906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690630595a65490602401602060405180830381865afa158015610453573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610477919061102a565b6001600160a01b03161461049e5760405163ade5da5f60e01b815260040160405180910390fd5b6103a7610a0b565b5f6104af6103b7565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa1580156104f3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103a7919061104c565b5f5460ff16156105395760405162dc149f60e41b815260040160405180910390fd5b5f805460ff1916600117905561054d610bba565b565b604051630165699560e21b81526001600160e01b03197f000000000000000000000000000000000000000000000000000000000000000016600482015233906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690630595a65490602401602060405180830381865afa1580156105dd573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610601919061102a565b6001600160a01b0316146106285760405163ade5da5f60e01b815260040160405180910390fd5b61063181610cad565b50565b60605f61063f6103b7565b6001600160a01b031663b95c57466040518163ffffffff1660e01b8152600401602060405180830381865afa15801561067a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061069e919061104c565b90505f8167ffffffffffffffff8111156106ba576106ba611063565b6040519080825280602002602001820160405280156106e3578160200160208202803683370190505b5090505f5b8281101561079e575f6106f96103b7565b6001600160a01b031663f301af42836040518263ffffffff1660e01b815260040161072691815260200190565b606060405180830381865afa158015610741573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061076591906110d1565b9050805f015183838151811061077d5761077d611133565b6001600160a01b0390921660209283029190910190910152506001016106e8565b5092915050565b5f5f6107af6103b7565b6040516246613160e11b81523060048201526001600160a01b039190911690628cc262906024015f604051808303815f875af11580156107f1573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526108189190810190611147565b90505f805b82518110156108b3577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031683828151811061086257610862611133565b60200260200101515f01516001600160a01b0316036108ab5782818151811061088d5761088d611133565b602002602001015160200151826108a49190611235565b91506108b3565b60010161081d565b506040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610916573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061093a919061104c565b6109449082611235565b9250505090565b5f6103a730603c610d4b565b61095f6103b7565b604051631c683a1b60e11b815260048101849052600160248201526001600160a01b0391909116906338d07436906044016020604051808303815f875af11580156109ac573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109d09190611248565b5061039781836109de6103ac565b6001600160a01b03169190610d65565b5f5f6109f984610dc9565b929092016020015160601c9392505050565b5f610a146103b7565b604051630c00007b60e41b81523060048201526001600160a01b03919091169063c00007b0906024015f604051808303815f87803b158015610a54575f5ffd5b505af1158015610a66573d5f5f3e3d5ffd5b505050505f610a73610634565b90505f5b8151811015610bb5575f828281518110610a9357610a93611133565b60209081029190910101516040516370a0823160e01b81523060048201529091505f906001600160a01b038316906370a0823190602401602060405180830381865afa158015610ae5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b09919061104c565b90508015610bab577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031603610b8f57610b548186611235565b9450610b8a6001600160a01b0383167f000000000000000000000000000000000000000000000000000000000000000083610d65565b610bab565b610bab610b9a61039b565b6001600160a01b0384169083610d65565b5050600101610a77565b505090565b610bc26103ac565b604051636eb1769f60e11b81523060048201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166024830152919091169063dd62ed3e90604401602060405180830381865afa158015610c2e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c52919061104c565b15610c6f5760405162dc149f60e41b815260040160405180910390fd5b61054d7f00000000000000000000000000000000000000000000000000000000000000005f19610c9d6103ac565b6001600160a01b03169190610e36565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e2bbb158610ce461094b565b836040518363ffffffff1660e01b8152600401610d0b929190918252602082015260400190565b6020604051808303815f875af1158015610d27573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103979190611248565b5f5f610d5684610dc9565b92909201602001519392505050565b6040516001600160a01b03838116602483015260448201839052610dc491859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050610ecb565b505050565b60605f610de1602d6001600160a01b0385163b611267565b67ffffffffffffffff811115610df957610df9611063565b6040519080825280601f01601f191660200182016040528015610e23576020820181803683370190505b5090508051602d60208301853c92915050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052610e878482610f3b565b610ec5576040516001600160a01b0384811660248301525f6044830152610ebb91869182169063095ea7b390606401610d92565b610ec58482610ecb565b50505050565b5f5f60205f8451602086015f885af180610eea576040513d5f823e3d81fd5b50505f513d91508115610f01578060011415610f0e565b6001600160a01b0384163b155b15610ec557604051635274afe760e01b81526001600160a01b038516600482015260240160405180910390fd5b5f5f5f5f60205f8651602088015f8a5af192503d91505f519050828015610f7a57508115610f6c5780600114610f7a565b5f866001600160a01b03163b115b93505050505b92915050565b6001600160a01b0381168114610631575f5ffd5b5f5f60408385031215610fab575f5ffd5b823591506020830135610fbd81610f86565b809150509250929050565b5f60208284031215610fd8575f5ffd5b5035919050565b602080825282518282018190525f918401906040840190835b8181101561101f5783516001600160a01b0316835260209384019390920191600101610ff8565b509095945050505050565b5f6020828403121561103a575f5ffd5b815161104581610f86565b9392505050565b5f6020828403121561105c575f5ffd5b5051919050565b634e487b7160e01b5f52604160045260245ffd5b6040805190810167ffffffffffffffff8111828210171561109a5761109a611063565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156110c9576110c9611063565b604052919050565b5f60608284031280156110e2575f5ffd5b506040516060810167ffffffffffffffff8111828210171561110657611106611063565b604052825161111481610f86565b8152602083810151908201526040928301519281019290925250919050565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215611157575f5ffd5b815167ffffffffffffffff81111561116d575f5ffd5b8201601f8101841361117d575f5ffd5b805167ffffffffffffffff81111561119757611197611063565b6111a660208260051b016110a0565b8082825260208201915060208360061b8501019250868311156111c7575f5ffd5b6020840193505b8284101561121757604084880312156111e5575f5ffd5b6111ed611077565b84516111f881610f86565b81526020858101518183015290835260409094019391909101906111ce565b9695505050505050565b634e487b7160e01b5f52601160045260245ffd5b80820180821115610f8057610f80611221565b5f60208284031215611258575f5ffd5b81518015158114611045575f5ffd5b81810381811115610f8057610f8061122156fea264697066735822122002726409c7c6658ddd224be87f18461e872b2029f3dcf4c32adedd28a305c51964736f6c634300081c003300000000000000000000000093b4b9bd266ffa8af68e39edfa8cfe2a62011ce00000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb0000000000000000000000004e3fbd56cd56c3e72c1403e103b45db9da5b9d2b000000000000000000000000d3327cb05a8e0095a543d582b5b3ce3e19270389

Deployed Bytecode

0x608060405234801561000f575f5ffd5b5060043610610105575f3560e01c806375b0ffd11161009e57806399248ea71161006e57806399248ea714610255578063b6b55f251461027c578063c4f59f9b1461028f578063d9621f9e146102a4578063f1068454146102ac575f5ffd5b806375b0ffd1146101d85780637aaf53e6146101ff5780638129fc1c146102265780638b9d29401461022e575f5ffd5b8063475a91d1116100d9578063475a91d11461018b5780634e71d92d14610193578063722713f7146101a9578063759cb53b146101b1575f5ffd5b8062f714ce146101095780630db41f311461011e5780631dac30b01461016357806338d52e0f14610183575b5f5ffd5b61011c610117366004610f9a565b6102b4565b005b6101457fc715e3730000000000000000000000000000000000000000000000000000000081565b6040516001600160e01b031990911681526020015b60405180910390f35b61016b61039b565b6040516001600160a01b03909116815260200161015a565b61016b6103ac565b61016b6103b7565b61019b6103c3565b60405190815260200161015a565b61019b6104a6565b61016b7f0000000000000000000000004e3fbd56cd56c3e72c1403e103b45db9da5b9d2b81565b61016b7f000000000000000000000000d3327cb05a8e0095a543d582b5b3ce3e1927038981565b61016b7f0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb81565b61011c610517565b61016b7f00000000000000000000000093b4b9bd266ffa8af68e39edfa8cfe2a62011ce081565b61016b7f000000000000000000000000331b9182088e2a7d6d3fe4742aba1fb231aecc5681565b61011c61028a366004610fc8565b61054f565b610297610634565b60405161015a9190610fdf565b61019b6107a5565b61019b61094b565b604051630165699560e21b81526001600160e01b03197fc715e3730000000000000000000000000000000000000000000000000000000016600482015233906001600160a01b037f0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb1690630595a65490602401602060405180830381865afa158015610342573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610366919061102a565b6001600160a01b03161461038d5760405163ade5da5f60e01b815260040160405180910390fd5b6103978282610957565b5050565b5f6103a73060146109ee565b905090565b5f6103a730826109ee565b5f6103a73060286109ee565b604051630165699560e21b81526001600160e01b03197fc715e373000000000000000000000000000000000000000000000000000000001660048201525f9033906001600160a01b037f0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb1690630595a65490602401602060405180830381865afa158015610453573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610477919061102a565b6001600160a01b03161461049e5760405163ade5da5f60e01b815260040160405180910390fd5b6103a7610a0b565b5f6104af6103b7565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa1580156104f3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103a7919061104c565b5f5460ff16156105395760405162dc149f60e41b815260040160405180910390fd5b5f805460ff1916600117905561054d610bba565b565b604051630165699560e21b81526001600160e01b03197fc715e3730000000000000000000000000000000000000000000000000000000016600482015233906001600160a01b037f0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb1690630595a65490602401602060405180830381865afa1580156105dd573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610601919061102a565b6001600160a01b0316146106285760405163ade5da5f60e01b815260040160405180910390fd5b61063181610cad565b50565b60605f61063f6103b7565b6001600160a01b031663b95c57466040518163ffffffff1660e01b8152600401602060405180830381865afa15801561067a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061069e919061104c565b90505f8167ffffffffffffffff8111156106ba576106ba611063565b6040519080825280602002602001820160405280156106e3578160200160208202803683370190505b5090505f5b8281101561079e575f6106f96103b7565b6001600160a01b031663f301af42836040518263ffffffff1660e01b815260040161072691815260200190565b606060405180830381865afa158015610741573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061076591906110d1565b9050805f015183838151811061077d5761077d611133565b6001600160a01b0390921660209283029190910190910152506001016106e8565b5092915050565b5f5f6107af6103b7565b6040516246613160e11b81523060048201526001600160a01b039190911690628cc262906024015f604051808303815f875af11580156107f1573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526108189190810190611147565b90505f805b82518110156108b3577f000000000000000000000000331b9182088e2a7d6d3fe4742aba1fb231aecc566001600160a01b031683828151811061086257610862611133565b60200260200101515f01516001600160a01b0316036108ab5782818151811061088d5761088d611133565b602002602001015160200151826108a49190611235565b91506108b3565b60010161081d565b506040516370a0823160e01b81523060048201527f000000000000000000000000331b9182088e2a7d6d3fe4742aba1fb231aecc566001600160a01b0316906370a0823190602401602060405180830381865afa158015610916573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061093a919061104c565b6109449082611235565b9250505090565b5f6103a730603c610d4b565b61095f6103b7565b604051631c683a1b60e11b815260048101849052600160248201526001600160a01b0391909116906338d07436906044016020604051808303815f875af11580156109ac573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109d09190611248565b5061039781836109de6103ac565b6001600160a01b03169190610d65565b5f5f6109f984610dc9565b929092016020015160601c9392505050565b5f610a146103b7565b604051630c00007b60e41b81523060048201526001600160a01b03919091169063c00007b0906024015f604051808303815f87803b158015610a54575f5ffd5b505af1158015610a66573d5f5f3e3d5ffd5b505050505f610a73610634565b90505f5b8151811015610bb5575f828281518110610a9357610a93611133565b60209081029190910101516040516370a0823160e01b81523060048201529091505f906001600160a01b038316906370a0823190602401602060405180830381865afa158015610ae5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b09919061104c565b90508015610bab577f000000000000000000000000331b9182088e2a7d6d3fe4742aba1fb231aecc566001600160a01b0316826001600160a01b031603610b8f57610b548186611235565b9450610b8a6001600160a01b0383167f00000000000000000000000093b4b9bd266ffa8af68e39edfa8cfe2a62011ce083610d65565b610bab565b610bab610b9a61039b565b6001600160a01b0384169083610d65565b5050600101610a77565b505090565b610bc26103ac565b604051636eb1769f60e11b81523060048201526001600160a01b037f000000000000000000000000d3327cb05a8e0095a543d582b5b3ce3e1927038981166024830152919091169063dd62ed3e90604401602060405180830381865afa158015610c2e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c52919061104c565b15610c6f5760405162dc149f60e41b815260040160405180910390fd5b61054d7f000000000000000000000000d3327cb05a8e0095a543d582b5b3ce3e192703895f19610c9d6103ac565b6001600160a01b03169190610e36565b7f000000000000000000000000d3327cb05a8e0095a543d582b5b3ce3e192703896001600160a01b031663e2bbb158610ce461094b565b836040518363ffffffff1660e01b8152600401610d0b929190918252602082015260400190565b6020604051808303815f875af1158015610d27573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103979190611248565b5f5f610d5684610dc9565b92909201602001519392505050565b6040516001600160a01b03838116602483015260448201839052610dc491859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050610ecb565b505050565b60605f610de1602d6001600160a01b0385163b611267565b67ffffffffffffffff811115610df957610df9611063565b6040519080825280601f01601f191660200182016040528015610e23576020820181803683370190505b5090508051602d60208301853c92915050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052610e878482610f3b565b610ec5576040516001600160a01b0384811660248301525f6044830152610ebb91869182169063095ea7b390606401610d92565b610ec58482610ecb565b50505050565b5f5f60205f8451602086015f885af180610eea576040513d5f823e3d81fd5b50505f513d91508115610f01578060011415610f0e565b6001600160a01b0384163b155b15610ec557604051635274afe760e01b81526001600160a01b038516600482015260240160405180910390fd5b5f5f5f5f60205f8651602088015f8a5af192503d91505f519050828015610f7a57508115610f6c5780600114610f7a565b5f866001600160a01b03163b115b93505050505b92915050565b6001600160a01b0381168114610631575f5ffd5b5f5f60408385031215610fab575f5ffd5b823591506020830135610fbd81610f86565b809150509250929050565b5f60208284031215610fd8575f5ffd5b5035919050565b602080825282518282018190525f918401906040840190835b8181101561101f5783516001600160a01b0316835260209384019390920191600101610ff8565b509095945050505050565b5f6020828403121561103a575f5ffd5b815161104581610f86565b9392505050565b5f6020828403121561105c575f5ffd5b5051919050565b634e487b7160e01b5f52604160045260245ffd5b6040805190810167ffffffffffffffff8111828210171561109a5761109a611063565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156110c9576110c9611063565b604052919050565b5f60608284031280156110e2575f5ffd5b506040516060810167ffffffffffffffff8111828210171561110657611106611063565b604052825161111481610f86565b8152602083810151908201526040928301519281019290925250919050565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215611157575f5ffd5b815167ffffffffffffffff81111561116d575f5ffd5b8201601f8101841361117d575f5ffd5b805167ffffffffffffffff81111561119757611197611063565b6111a660208260051b016110a0565b8082825260208201915060208360061b8501019250868311156111c7575f5ffd5b6020840193505b8284101561121757604084880312156111e5575f5ffd5b6111ed611077565b84516111f881610f86565b81526020858101518183015290835260409094019391909101906111ce565b9695505050505050565b634e487b7160e01b5f52601160045260245ffd5b80820180821115610f8057610f80611221565b5f60208284031215611258575f5ffd5b81518015158114611045575f5ffd5b81810381811115610f8057610f8061122156fea264697066735822122002726409c7c6658ddd224be87f18461e872b2029f3dcf4c32adedd28a305c51964736f6c634300081c0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000093b4b9bd266ffa8af68e39edfa8cfe2a62011ce00000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb0000000000000000000000004e3fbd56cd56c3e72c1403e103b45db9da5b9d2b000000000000000000000000d3327cb05a8e0095a543d582b5b3ce3e19270389

-----Decoded View---------------
Arg [0] : _accountant (address): 0x93b4B9bd266fFA8AF68e39EDFa8cFe2A62011Ce0
Arg [1] : _protocolController (address): 0x2d8BcE1FaE00a959354aCD9eBf9174337A64d4fb
Arg [2] : _cvx (address): 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B
Arg [3] : _booster (address): 0xd3327cb05a8E0095A543D582b5B3Ce3e19270389

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 00000000000000000000000093b4b9bd266ffa8af68e39edfa8cfe2a62011ce0
Arg [1] : 0000000000000000000000002d8bce1fae00a959354acd9ebf9174337a64d4fb
Arg [2] : 0000000000000000000000004e3fbd56cd56c3e72c1403e103b45db9da5b9d2b
Arg [3] : 000000000000000000000000d3327cb05a8e0095a543d582b5b3ce3e19270389


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
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.