FRAX Price: $0.99 (-2.33%)

Contract

0xbBA6a1ab4D927fC978AD92073487173a3a27bCEB

Overview

FRAX Balance | FXTL Balance

0 FRAX | 487 FXTL

FRAX Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
Sync Reward Toke...230181362025-07-18 13:56:23190 days ago1752846983IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000475610.00110025
Create228936042025-07-15 16:45:19193 days ago1752597919IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000388660.00110025
Sync Reward Toke...226331282025-07-09 16:02:47199 days ago1752076967IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000312750.00110025
Create217634822025-06-19 12:54:35219 days ago1750337675IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000152650.00150025
Create217634822025-06-19 12:54:35219 days ago1750337675IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000152650.00150025
Create217634812025-06-19 12:54:33219 days ago1750337673IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000150840.00150025
Create217634812025-06-19 12:54:33219 days ago1750337673IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000150820.00150025
Create217634812025-06-19 12:54:33219 days ago1750337673IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000150850.00150025
Create217634812025-06-19 12:54:33219 days ago1750337673IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000150880.00150025
Create217634812025-06-19 12:54:33219 days ago1750337673IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000150820.00150025
Create217634812025-06-19 12:54:33219 days ago1750337673IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000150840.00150025
Create217634802025-06-19 12:54:31219 days ago1750337671IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000150820.00150025
Create217634802025-06-19 12:54:31219 days ago1750337671IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000150880.00150025
Create217634802025-06-19 12:54:31219 days ago1750337671IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000150880.00150025
Create217634802025-06-19 12:54:31219 days ago1750337671IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000150840.00150025
Create217634802025-06-19 12:54:31219 days ago1750337671IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000150840.00150025
Create217634802025-06-19 12:54:31219 days ago1750337671IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000150840.00150025
Create217634802025-06-19 12:54:31219 days ago1750337671IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000150840.00150025
Create217634802025-06-19 12:54:31219 days ago1750337671IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000150840.00150025
Create217634792025-06-19 12:54:29219 days ago1750337669IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000150860.00150025
Create217634792025-06-19 12:54:29219 days ago1750337669IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000150880.00150025
Create217634792025-06-19 12:54:29219 days ago1750337669IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000150880.00150025
Create217634782025-06-19 12:54:27219 days ago1750337667IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000150880.00150025
Create217634782025-06-19 12:54:27219 days ago1750337667IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000150860.00150025
Create217634782025-06-19 12:54:27219 days ago1750337667IN
0xbBA6a1ab...a3a27bCEB
0 FRAX0.000150840.00150025
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
228936042025-07-15 16:45:19193 days ago1752597919
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
228936042025-07-15 16:45:19193 days ago1752597919
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634822025-06-19 12:54:35219 days ago1750337675
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634822025-06-19 12:54:35219 days ago1750337675
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634822025-06-19 12:54:35219 days ago1750337675
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634822025-06-19 12:54:35219 days ago1750337675
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634812025-06-19 12:54:33219 days ago1750337673
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634812025-06-19 12:54:33219 days ago1750337673
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634812025-06-19 12:54:33219 days ago1750337673
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634812025-06-19 12:54:33219 days ago1750337673
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634812025-06-19 12:54:33219 days ago1750337673
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634812025-06-19 12:54:33219 days ago1750337673
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634812025-06-19 12:54:33219 days ago1750337673
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634812025-06-19 12:54:33219 days ago1750337673
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634812025-06-19 12:54:33219 days ago1750337673
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634812025-06-19 12:54:33219 days ago1750337673
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634812025-06-19 12:54:33219 days ago1750337673
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634812025-06-19 12:54:33219 days ago1750337673
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634802025-06-19 12:54:31219 days ago1750337671
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634802025-06-19 12:54:31219 days ago1750337671
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634802025-06-19 12:54:31219 days ago1750337671
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634802025-06-19 12:54:31219 days ago1750337671
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634802025-06-19 12:54:31219 days ago1750337671
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634802025-06-19 12:54:31219 days ago1750337671
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
217634802025-06-19 12:54:31219 days ago1750337671
0xbBA6a1ab...a3a27bCEB
 Contract Creation0 FRAX
View All Internal Transactions

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
CurveFactory

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 {Factory} from "src/Factory.sol";
import {IL2Booster} from "@interfaces/convex/IL2Booster.sol";
import {IRewardVault} from "src/interfaces/IRewardVault.sol";
import {ISidecarFactory} from "src/interfaces/ISidecarFactory.sol";
import {IL2LiquidityGauge} from "@interfaces/curve/ILiquidityGauge.sol";
import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {IChildLiquidityGaugeFactory} from "@interfaces/curve/IChildLiquidityGaugeFactory.sol";

contract CurveFactory is Factory, Ownable2Step {
    /// @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 Convex Booster.
    address public immutable BOOSTER;

    /// @notice Convex Minimal Proxy Factory for Only Boost.
    address public immutable CONVEX_SIDECAR_FACTORY;

    /// @notice The child liquidity gauge factories.
    IChildLiquidityGaugeFactory[] public childLiquidityGaugeFactories;

    /// @notice Error thrown when the set reward receiver fails.
    error SetRewardReceiverFailed();

    /// @notice Error thrown when the convex sidecar factory is not set.
    error ConvexSidecarFactoryNotSet();

    /// @notice Error thrown when the child liquidity gauge factories are not set.
    error ChildLiquidityGaugeFactoriesNotSet();

    /// @notice Event emitted when a vault is deployed.
    event VaultDeployed(address gauge, address vault, address rewardReceiver, address sidecar);

    constructor(
        address admin,
        address protocolController,
        address vaultImplementation,
        address rewardReceiverImplementation,
        address locker,
        address gateway,
        address booster,
        address convexSidecarFactory
    )
        Factory(protocolController, vaultImplementation, rewardReceiverImplementation, CURVE_PROTOCOL_ID, locker, gateway)
        Ownable(admin)
    {
        BOOSTER = booster;
        CONVEX_SIDECAR_FACTORY = convexSidecarFactory;
    }

    /// @notice Create a new vault.
    /// @param _pid Pool id.
    function create(uint256 _pid) external returns (address vault, address rewardReceiver, address sidecar) {
        require(CONVEX_SIDECAR_FACTORY != address(0), ConvexSidecarFactoryNotSet());

        (, address gauge,,,) = IL2Booster(BOOSTER).poolInfo(_pid);

        /// 1. Create the vault.
        (vault, rewardReceiver) = createVault(gauge);

        /// 2. Attach the sidecar.
        sidecar = ISidecarFactory(CONVEX_SIDECAR_FACTORY).create(gauge, abi.encode(_pid));

        /// 3. Emit the event.
        emit VaultDeployed(gauge, vault, rewardReceiver, sidecar);
    }

    function _isValidToken(address _token) internal view virtual override returns (bool isValid) {
        /// If the token is not valid, return false.
        if (!super._isValidToken(_token)) return false;
        require(childLiquidityGaugeFactories.length > 0, ChildLiquidityGaugeFactoriesNotSet());

        /// If the token is available as an inflation receiver, it's not valid.
        for (uint256 i = 0; i < childLiquidityGaugeFactories.length; i++) {
            if (childLiquidityGaugeFactories[i].is_valid_gauge(_token)) {
                isValid = false;
                break;
            }
        }

        return isValid;
    }

    function _isValidGauge(address _gauge) internal view virtual override returns (bool isValid) {
        require(childLiquidityGaugeFactories.length > 0, ChildLiquidityGaugeFactoriesNotSet());
        /// Check if the gauge is a valid candidate and available as an inflation receiver.
        /// This call always reverts if the gauge is not valid.
        for (uint256 i = 0; i < childLiquidityGaugeFactories.length; i++) {

            if (childLiquidityGaugeFactories[i].is_valid_gauge(_gauge)) {
                isValid = true;
                break;
            }
        }

        /// Check if the gauge is not killed.
        if (IL2LiquidityGauge(_gauge).is_killed()) {
            isValid = false;
        }

        return isValid;
    }

    function _getAsset(address _gauge) internal view virtual override returns (address) {
        return IL2LiquidityGauge(_gauge).lp_token();
    }

    function _setupRewardTokens(address _vault, address _gauge, address _rewardReceiver) internal virtual override {
        /// Check if the gauge supports extra rewards.
        /// This function is not supported on all gauges, depending on when they were deployed.
        bytes memory data = abi.encodeWithSignature("reward_tokens(uint256)", 0);

        (bool success,) = _gauge.call(data);
        if (!success) return;

        /// Loop through the extra reward tokens.
        /// 8 is the maximum number of extra reward tokens supported by the gauges.
        for (uint8 i = 0; i < 8; i++) {
            /// Get the extra reward token address.
            address _extraRewardToken = IL2LiquidityGauge(_gauge).reward_tokens(i);
            (, uint256 periodFinish,,,) = IL2LiquidityGauge(_gauge).reward_data(_extraRewardToken);
            /// If the reward data is not active, skip.
            if (periodFinish < block.timestamp) continue;
            /// If the address is 0, it means there are no more extra reward tokens.
            if (_extraRewardToken == address(0)) break;
            /// If the extra reward token is already in the vault, skip.
            if (IRewardVault(_vault).isRewardToken(_extraRewardToken)) continue;
            /// Performs checks on the extra reward token.
            /// Checks like if the token is also an lp token that can be staked in the locker, these tokens are not supported.
            if (_isValidToken(_extraRewardToken)) {
                /// Then we add the extra reward token to the reward distributor through the strategy.
                IRewardVault(_vault).addRewardToken(_extraRewardToken, _rewardReceiver);
            }
        }
    }

    function _setRewardReceiver(address _gauge, address _rewardReceiver) internal override {
        /// Set RewardReceiver as RewardReceiver on Gauge.
        bytes memory data = abi.encodeWithSignature("set_rewards_receiver(address)", _rewardReceiver);
        require(_executeTransaction(_gauge, data), SetRewardReceiverFailed());
    }

    function _initializeVault(address, address _asset, address _gauge) internal override {
        /// Initialize the vault.
        /// We need to approve the asset to the gauge using the Locker.
        bytes memory data = abi.encodeWithSignature("approve(address,uint256)", _gauge, type(uint256).max);

        /// Execute the transaction.
        require(_executeTransaction(_asset, data), ApproveFailed());
    }

    /// @notice Set the child liquidity gauge factories.
    /// @param _childLiquidityGaugeFactories The child liquidity gauge factories.
    function setChildLiquidityGaugeFactories(IChildLiquidityGaugeFactory[] memory _childLiquidityGaugeFactories)
        external
        onlyOwner
    {
        childLiquidityGaugeFactories = _childLiquidityGaugeFactories;
    }
}

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

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

/// @title Factory - Abstract Base Factory Contract
/// @notice A base contract for implementing protocol-specific vault factories
/// @dev Provides core functionality for creating and managing vaults across different protocols
///      Key responsibilities:
///      - Deploys vaults and reward receivers for protocol gauges
///      - Validates gauges and tokens
///      - Registers vaults with the protocol controller
///      - Sets up reward tokens for vaults
abstract contract Factory is ProtocolContext {
    //////////////////////////////////////////////////////
    // --- IMMUTABLES
    //////////////////////////////////////////////////////

    /// @notice Reward vault implementation address
    /// @dev The implementation contract that will be cloned for each new vault
    address public immutable REWARD_VAULT_IMPLEMENTATION;

    /// @notice Reward receiver implementation address
    /// @dev The implementation contract that will be cloned for each new reward receiver
    address public immutable REWARD_RECEIVER_IMPLEMENTATION;

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

    /// @notice Error thrown when the gauge is not a valid candidate
    error InvalidGauge();

    /// @notice Error thrown when the approve fails
    error ApproveFailed();

    /// @notice Error thrown when the token is not valid
    error InvalidToken();

    /// @notice Error thrown when the deployment is not valid
    error InvalidDeployment();

    /// @notice Error thrown when the gauge has been already used
    error AlreadyDeployed();

    //////////////////////////////////////////////////////
    // --- EVENTS
    //////////////////////////////////////////////////////

    /// @notice Emitted when a new vault is deployed
    /// @param vault Address of the deployed vault
    /// @param asset Address of the underlying asset
    /// @param gauge Address of the associated gauge
    event VaultDeployed(address vault, address asset, address gauge);

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

    /// @notice Initializes the factory with protocol controller, reward token, and vault implementation
    /// @param _protocolController Address of the protocol controller
    /// @param _vaultImplementation Address of the reward vault implementation
    /// @param _rewardReceiverImplementation Address of the reward receiver implementation
    /// @param _protocolId Protocol identifier
    /// @param _locker Address of the locker
    /// @param _gateway Address of the gateway
    constructor(
        address _protocolController,
        address _vaultImplementation,
        address _rewardReceiverImplementation,
        bytes4 _protocolId,
        address _locker,
        address _gateway
    ) ProtocolContext(_protocolId, _protocolController, _locker, _gateway) {
        require(
            _protocolController != address(0) && _vaultImplementation != address(0)
                && _rewardReceiverImplementation != address(0),
            ZeroAddress()
        );

        REWARD_VAULT_IMPLEMENTATION = _vaultImplementation;
        REWARD_RECEIVER_IMPLEMENTATION = _rewardReceiverImplementation;
    }

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

    /// @notice Create a new vault for a given gauge
    /// @dev Deploys a vault and reward receiver for the gauge, registers them, and sets up reward tokens
    /// @param gauge Address of the gauge
    /// @return vault Address of the deployed vault
    /// @return rewardReceiver Address of the deployed reward receiver
    /// @custom:throws InvalidGauge If the gauge is not valid
    /// @custom:throws InvalidDeployment If the deployment is not valid
    /// @custom:throws GaugeAlreadyUsed If the gauge has already been used
    function createVault(address gauge) public virtual returns (address vault, address rewardReceiver) {
        /// Perform checks on the gauge to make sure it's valid and can be used
        require(_isValidGauge(gauge), InvalidGauge());
        require(_isValidDeployment(gauge), InvalidDeployment());
        require(PROTOCOL_CONTROLLER.vaults(gauge) == address(0), AlreadyDeployed());

        /// Get the asset address from the gauge
        address asset = _getAsset(gauge);

        /// Prepare the initialization data for the vault
        /// The vault needs: gauge and asset
        bytes memory data = abi.encodePacked(gauge, asset);

        /// Generate a deterministic salt based on the gauge and asset
        bytes32 salt = keccak256(data);

        /// Clone the vault implementation with the initialization data
        vault = Clones.cloneDeterministicWithImmutableArgs(REWARD_VAULT_IMPLEMENTATION, data, salt);

        /// Prepare the initialization data for the reward receiver
        /// The reward receiver needs: vault
        data = abi.encodePacked(vault);

        /// Generate a deterministic salt based on the vault
        salt = keccak256(abi.encodePacked(vault));

        /// Deploy Reward Receiver.
        rewardReceiver = Clones.cloneDeterministicWithImmutableArgs(REWARD_RECEIVER_IMPLEMENTATION, data, salt);

        /// Initialize the vault.
        /// @dev Can be approval if needed etc.
        _initializeVault(vault, asset, gauge);

        /// Register the vault in the protocol controller
        _registerVault(gauge, vault, asset, rewardReceiver);

        /// Add extra reward tokens to the vault
        _setupRewardTokens(vault, gauge, rewardReceiver);

        /// Set the reward receiver for the gauge
        _setRewardReceiver(gauge, rewardReceiver);

        /// Set the valid allocation target.
        PROTOCOL_CONTROLLER.setValidAllocationTarget(gauge, LOCKER);

        emit VaultDeployed(vault, asset, gauge);
    }

    /// @notice Sync reward tokens for a gauge
    /// @dev Updates the reward tokens for an existing vault
    /// @param gauge Address of the gauge
    /// @custom:throws InvalidGauge If the gauge is not valid or has no associated vault
    function syncRewardTokens(address gauge) external {
        address vault = PROTOCOL_CONTROLLER.vaults(gauge);
        require(vault != address(0), InvalidGauge());

        _setupRewardTokens(vault, gauge, PROTOCOL_CONTROLLER.rewardReceiver(gauge));
    }

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

    /// @notice Get the asset address from a gauge
    /// @dev Must be implemented by derived factories to handle protocol-specific asset retrieval
    /// @param gauge Address of the gauge
    /// @return The address of the asset associated with the gauge
    function _getAsset(address gauge) internal view virtual returns (address);

    /// @notice Check if a deployment is valid
    /// @dev Can be overridden by derived factories to add additional deployment validation
    /// @return True if the deployment is valid, false otherwise
    function _isValidDeployment(address) internal view virtual returns (bool) {
        return true;
    }

    /// @notice Initialize the vault
    /// @param vault Address of the vault
    /// @param asset Address of the asset
    /// @param gauge Address of the gauge
    function _initializeVault(address vault, address asset, address gauge) internal virtual;

    /// @notice Register the vault in the protocol controller
    /// @param gauge Address of the gauge
    /// @param vault Address of the vault
    /// @param asset Address of the asset
    /// @param rewardReceiver Address of the reward receiver
    function _registerVault(address gauge, address vault, address asset, address rewardReceiver) internal {
        PROTOCOL_CONTROLLER.registerVault(gauge, vault, asset, rewardReceiver, PROTOCOL_ID);
    }

    /// @notice Setup reward tokens for the vault
    /// @dev Must be implemented by derived factories to handle protocol-specific reward token setup
    /// @param vault Address of the vault
    /// @param gauge Address of the gauge
    /// @param rewardReceiver Address of the reward receiver
    function _setupRewardTokens(address vault, address gauge, address rewardReceiver) internal virtual;

    /// @notice Set the reward receiver for a gauge
    /// @dev Must be implemented by derived factories to handle protocol-specific reward receiver setup
    /// @param gauge Address of the gauge
    /// @param rewardReceiver Address of the reward receiver
    function _setRewardReceiver(address gauge, address rewardReceiver) internal virtual;

    /// @notice Check if a gauge is valid
    /// @dev Must be implemented by derived factories to handle protocol-specific gauge validation
    /// @param gauge Address of the gauge
    /// @return isValid True if the gauge is valid
    function _isValidGauge(address gauge) internal view virtual returns (bool);

    /// @notice Check if a token is valid as a reward token
    /// @dev Validates that the token is not zero address and not the main reward token
    /// @param token Address of the token
    /// @return isValid True if the token is valid
    function _isValidToken(address token) internal view virtual returns (bool) {
        return token != address(0) && token != REWARD_TOKEN;
    }
}

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

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

interface ISidecarFactory {
    function sidecar(address gauge) external view returns (address);
    function create(address token, bytes memory args) external returns (address);
}

File 6 of 20 : ILiquidityGauge.sol
// 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: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/Ownable2Step.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * This extension of the {Ownable} contract includes a two-step mechanism to transfer
 * ownership, where the new owner must call {acceptOwnership} in order to replace the
 * old one. This can help prevent common mistakes, such as transfers of ownership to
 * incorrect accounts, or to contracts that are unable to interact with the
 * permission system.
 *
 * The initial owner is specified at deployment time in the constructor for `Ownable`. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2Step is Ownable {
    address private _pendingOwner;

    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        return _pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     *
     * Setting `newOwner` to the zero address is allowed; this can be used to cancel an initiated ownership transfer.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        _pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        delete _pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        if (pendingOwner() != sender) {
            revert OwnableUnauthorizedAccount(sender);
        }
        _transferOwnership(sender);
    }
}

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;

interface IChildLiquidityGaugeFactory {
    function voting_escrow() external view returns (address);
    function is_valid_gauge(address _gauge) external view 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 {IModuleManager} from "@interfaces/safe/IModuleManager.sol";

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

/// @title ProtocolContext
/// @author Stake DAO
/// @notice Base contract providing shared protocol configuration and transaction execution
/// @dev Inherited by Strategy and other protocol-specific contracts to ensure consistent configuration
contract ProtocolContext {
    //////////////////////////////////////////////////////
    // --- IMMUTABLES
    //////////////////////////////////////////////////////

    /// @notice Unique identifier for the protocol (e.g., keccak256("CURVE") for Curve)
    /// @dev Used to look up protocol-specific components in ProtocolController
    bytes4 public immutable PROTOCOL_ID;

    /// @notice The locker contract that holds and manages protocol tokens (e.g., veCRV)
    /// @dev On L2s, this may be the same as GATEWAY when no separate locker exists
    address public immutable LOCKER;

    /// @notice Safe multisig that owns the locker and executes privileged operations
    /// @dev All protocol interactions go through this gateway for security
    address public immutable GATEWAY;

    /// @notice The accountant responsible for tracking rewards and user balances
    /// @dev Retrieved from ProtocolController during construction
    address public immutable ACCOUNTANT;

    /// @notice The main reward token for this protocol (e.g., CRV for Curve)
    /// @dev Retrieved from the accountant's configuration
    address public immutable REWARD_TOKEN;

    /// @notice Reference to the central registry for protocol components
    IProtocolController public immutable PROTOCOL_CONTROLLER;

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

    /// @notice Error thrown when a required address is zero
    error ZeroAddress();

    /// @notice Error thrown when a protocol ID is zero
    error InvalidProtocolId();

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

    /// @notice Initializes protocol configuration that all inheriting contracts will use
    /// @dev Retrieves accountant and reward token from ProtocolController for consistency
    /// @param _protocolId The protocol identifier (must match registered protocol in controller)
    /// @param _protocolController The protocol controller contract address
    /// @param _locker The locker contract address (pass address(0) for L2s where gateway acts as locker)
    /// @param _gateway The gateway contract address (Safe multisig)
    /// @custom:throws ZeroAddress If protocol controller or gateway is zero
    /// @custom:throws InvalidProtocolId If protocol ID is empty
    constructor(bytes4 _protocolId, address _protocolController, address _locker, address _gateway) {
        require(_protocolController != address(0) && _gateway != address(0), ZeroAddress());
        require(_protocolId != bytes4(0), InvalidProtocolId());

        GATEWAY = _gateway;
        PROTOCOL_ID = _protocolId;
        ACCOUNTANT = IProtocolController(_protocolController).accountant(_protocolId);
        REWARD_TOKEN = IAccountant(ACCOUNTANT).REWARD_TOKEN();
        PROTOCOL_CONTROLLER = IProtocolController(_protocolController);

        // L2 optimization: Gateway can act as both transaction executor and token holder
        if (_locker == address(0)) {
            LOCKER = GATEWAY;
        } else {
            LOCKER = _locker;
        }
    }

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

    /// @notice Executes privileged transactions through the Safe module system
    /// @dev Handles two execution patterns:
    ///      - Mainnet: Gateway -> Locker -> Target (locker holds funds and executes)
    ///      - L2: Gateway acts as locker and executes directly on target
    /// @param target The address of the contract to interact with
    /// @param data The calldata to send to the target
    /// @return success Whether the transaction executed successfully
    function _executeTransaction(address target, bytes memory data) internal returns (bool success) {
        if (LOCKER == GATEWAY) {
            // L2 pattern: Gateway holds funds and executes directly
            success = IModuleManager(GATEWAY).execTransactionFromModule(target, 0, data, IModuleManager.Operation.Call);
        } else {
            // Mainnet pattern: Gateway instructs locker (which holds funds) to execute
            // The locker contract has the necessary approvals and balances
            success = IModuleManager(GATEWAY).execTransactionFromModule(
                LOCKER,
                0,
                abi.encodeWithSignature("execute(address,uint256,bytes)", target, 0, data),
                IModuleManager.Operation.Call
            );
        }
    }
}

// SPDX-License-Identifier: 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.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// 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 14 of 20 : 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: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;

/**
 * @title IModuleManager - An interface of contract managing Safe modules
 * @notice Modules are extensions with unlimited access to a Safe that can be added to a Safe by its owners.
           ⚠️ WARNING: Modules are a security risk since they can execute arbitrary transactions, 
           so only trusted and audited modules should be added to a Safe. A malicious module can
           completely takeover a Safe.
 * @author @safe-global/safe-protocol
 */
interface IModuleManager {

    enum Operation {
        Call,
        DelegateCall
    }
    event EnabledModule(address indexed module);
    event DisabledModule(address indexed module);
    event ExecutionFromModuleSuccess(address indexed module);
    event ExecutionFromModuleFailure(address indexed module);
    event ChangedModuleGuard(address indexed moduleGuard);

    /**
     * @notice Enables the module `module` for the Safe.
     * @dev This can only be done via a Safe transaction.
     * @param module Module to be whitelisted.
     */
    function enableModule(address module) external;

    /**
     * @notice Disables the module `module` for the Safe.
     * @dev This can only be done via a Safe transaction.
     * @param prevModule Previous module in the modules linked list.
     * @param module Module to be removed.
     */
    function disableModule(address prevModule, address module) external;

    /**
     * @notice Execute `operation` (0: Call, 1: DelegateCall) to `to` with `value` (Native Token)
     * @param to Destination address of module transaction.
     * @param value Ether value of module transaction.
     * @param data Data payload of module transaction.
     * @param operation Operation type of module transaction.
     * @return success Boolean flag indicating if the call succeeded.
     */
    function execTransactionFromModule(
        address to,
        uint256 value,
        bytes memory data,
        Operation operation
    ) external returns (bool success);

    /**
     * @notice Execute `operation` (0: Call, 1: DelegateCall) to `to` with `value` (Native Token) and return data
     * @param to Destination address of module transaction.
     * @param value Ether value of module transaction.
     * @param data Data payload of module transaction.
     * @param operation Operation type of module transaction.
     * @return success Boolean flag indicating if the call succeeded.
     * @return returnData Data returned by the call.
     */
    function execTransactionFromModuleReturnData(
        address to,
        uint256 value,
        bytes memory data,
        Operation operation
    ) external returns (bool success, bytes memory returnData);

    /**
     * @notice Returns if a module is enabled
     * @return True if the module is enabled
     */
    function isModuleEnabled(address module) external view returns (bool);

    /**
     * @notice Returns an array of modules.
     *         If all entries fit into a single page, the next pointer will be 0x1.
     *         If another page is present, next will be the last element of the returned array.
     * @param start Start of the page. Has to be a module or start pointer (0x1 address)
     * @param pageSize Maximum number of modules that should be returned. Has to be > 0
     * @return array Array of modules.
     * @return next Start of the next page.
     */
    function getModulesPaginated(address start, uint256 pageSize) external view returns (address[] memory array, address next);

    /**
     * @dev Set a module guard that checks transactions initiated by the module before execution
     *      This can only be done via a Safe transaction.
     *      ⚠️ IMPORTANT: Since a module guard has full power to block Safe transaction execution initiated via a module,
     *        a broken module guard can cause a denial of service for the Safe modules. Make sure to carefully
     *        audit the module guard code and design recovery mechanisms.
     * @notice Set Module Guard `moduleGuard` for the Safe. Make sure you trust the module guard.
     * @param moduleGuard The address of the module guard to be used or the zero address to disable the module guard.
     */
    function setModuleGuard(address moduleGuard) external;
}

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

import {IStrategy} from "src/interfaces/IStrategy.sol";

interface IAccountant {
    function checkpoint(
        address gauge,
        address from,
        address to,
        uint128 amount,
        IStrategy.PendingRewards calldata pendingRewards,
        IStrategy.HarvestPolicy policy
    ) external;

    function checkpoint(
        address gauge,
        address from,
        address to,
        uint128 amount,
        IStrategy.PendingRewards calldata pendingRewards,
        IStrategy.HarvestPolicy policy,
        address referrer
    ) external;

    function totalSupply(address asset) external view returns (uint128);
    function balanceOf(address asset, address account) external view returns (uint128);

    function claim(address[] calldata _vaults, bytes[] calldata harvestData) external;
    function claim(address[] calldata _vaults, bytes[] calldata harvestData, address receiver) external;
    function claim(address[] calldata _vaults, address account, bytes[] calldata harvestData) external;
    function claim(address[] calldata _vaults, address account, bytes[] calldata harvestData, address receiver)
        external;

    function claimProtocolFees() external;
    function harvest(address[] calldata _vaults, bytes[] calldata _harvestData, address _receiver) external;

    function REWARD_TOKEN() external view returns (address);
}

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

interface IProtocolController {
    function vaults(address) external view returns (address);
    function asset(address) external view returns (address);
    function rewardReceiver(address) external view returns (address);

    function allowed(address, address, bytes4 selector) external view returns (bool);
    function permissionSetters(address) external view returns (bool);
    function isRegistrar(address) external view returns (bool);

    function strategy(bytes4 protocolId) external view returns (address);
    function allocator(bytes4 protocolId) external view returns (address);
    function accountant(bytes4 protocolId) external view returns (address);
    function feeReceiver(bytes4 protocolId) external view returns (address);
    function isShutdown(address) external view returns (bool);
    function isFullyWithdrawn(address) external view returns (bool);

    function registerVault(address _gauge, address _vault, address _asset, address _rewardReceiver, bytes4 _protocolId)
        external;

    function setValidAllocationTarget(address _gauge, address _target) external;
    function removeValidAllocationTarget(address _gauge, address _target) external;
    function isValidAllocationTarget(address _gauge, address _target) external view returns (bool);

    function shutdown(address _gauge) external;
    function markGaugeAsFullyWithdrawn(address _gauge) external;

    function setPermissionSetter(address _setter, bool _allowed) external;
    function setPermission(address _contract, address _caller, bytes4 _selector, bool _allowed) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

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

import "src/interfaces/IAllocator.sol";

interface IStrategy {
    /// @notice The policy for harvesting rewards.
    enum HarvestPolicy {
        CHECKPOINT,
        HARVEST
    }

    struct PendingRewards {
        uint128 feeSubjectAmount;
        uint128 totalAmount;
    }

    function deposit(IAllocator.Allocation calldata allocation, HarvestPolicy policy)
        external
        returns (PendingRewards memory pendingRewards);
    function withdraw(IAllocator.Allocation calldata allocation, HarvestPolicy policy, address receiver)
        external
        returns (PendingRewards memory pendingRewards);

    function balanceOf(address gauge) external view returns (uint256 balance);

    function harvest(address gauge, bytes calldata extraData) external returns (PendingRewards memory pendingRewards);
    function flush() external;
}

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

interface 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":"admin","type":"address"},{"internalType":"address","name":"protocolController","type":"address"},{"internalType":"address","name":"vaultImplementation","type":"address"},{"internalType":"address","name":"rewardReceiverImplementation","type":"address"},{"internalType":"address","name":"locker","type":"address"},{"internalType":"address","name":"gateway","type":"address"},{"internalType":"address","name":"booster","type":"address"},{"internalType":"address","name":"convexSidecarFactory","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyDeployed","type":"error"},{"inputs":[],"name":"ApproveFailed","type":"error"},{"inputs":[],"name":"ChildLiquidityGaugeFactoriesNotSet","type":"error"},{"inputs":[],"name":"CloneArgumentsTooLong","type":"error"},{"inputs":[],"name":"ConvexSidecarFactoryNotSet","type":"error"},{"inputs":[],"name":"Create2EmptyBytecode","type":"error"},{"inputs":[],"name":"FailedDeployment","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidDeployment","type":"error"},{"inputs":[],"name":"InvalidGauge","type":"error"},{"inputs":[],"name":"InvalidProtocolId","type":"error"},{"inputs":[],"name":"InvalidToken","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"SetRewardReceiverFailed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"address","name":"gauge","type":"address"}],"name":"VaultDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"gauge","type":"address"},{"indexed":false,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"address","name":"rewardReceiver","type":"address"},{"indexed":false,"internalType":"address","name":"sidecar","type":"address"}],"name":"VaultDeployed","type":"event"},{"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":"CONVEX_SIDECAR_FACTORY","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_RECEIVER_IMPLEMENTATION","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARD_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARD_VAULT_IMPLEMENTATION","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"childLiquidityGaugeFactories","outputs":[{"internalType":"contract IChildLiquidityGaugeFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"create","outputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"rewardReceiver","type":"address"},{"internalType":"address","name":"sidecar","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"gauge","type":"address"}],"name":"createVault","outputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"rewardReceiver","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IChildLiquidityGaugeFactory[]","name":"_childLiquidityGaugeFactories","type":"address[]"}],"name":"setChildLiquidityGaugeFactories","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"gauge","type":"address"}],"name":"syncRewardTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6101c0604052348015610010575f5ffd5b50604051611f2d380380611f2d83398101604081905261002f9161032b565b878787877fc715e3736a8cb018f630cb9a1df908ad1629e9c2da4cd190b2dc83d6687ba1698888828683836001600160a01b0383161580159061007a57506001600160a01b03811615155b6100975760405163d92e233d60e01b815260040160405180910390fd5b6001600160e01b031984166100bf576040516355e7c3d960e11b815260040160405180910390fd5b6001600160a01b0381811660c0526001600160e01b03198516608081905260405163669cc2c960e11b815260048101919091529084169063cd39859290602401602060405180830381865afa15801561011a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061013e91906103bd565b6001600160a01b031660e0819052604080516399248ea760e01b815290516399248ea7916004808201926020929091908290030181865afa158015610185573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101a991906103bd565b6001600160a01b03908116610100528381166101205282166101d95760c0516001600160a01b031660a0526101e7565b6001600160a01b03821660a0525b505050506001600160a01b0386161580159061020b57506001600160a01b03851615155b801561021f57506001600160a01b03841615155b61023c5760405163d92e233d60e01b815260040160405180910390fd5b5050506001600160a01b03918216610140528116610160528216905061027b57604051631e4fbdf760e01b81525f600482015260240160405180910390fd5b610284816102a5565b506001600160a01b0391821661018052166101a052506103dd945050505050565b600180546001600160a01b03191690556102be816102c1565b50565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b0381168114610326575f5ffd5b919050565b5f5f5f5f5f5f5f5f610100898b031215610343575f5ffd5b61034c89610310565b975061035a60208a01610310565b965061036860408a01610310565b955061037660608a01610310565b945061038460808a01610310565b935061039260a08a01610310565b92506103a060c08a01610310565b91506103ae60e08a01610310565b90509295985092959890939650565b5f602082840312156103cd575f5ffd5b6103d682610310565b9392505050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a051611a636104ca5f395f81816103a10152818161053e015261062501525f818161021f015261059b01525f8181610369015261095901525f81816101f001526108cf01525f818161028b015281816103f7015281816104b2015281816107eb015281816109f401526110ab01525f81816102fc01526114c801525f6102c501525f81816101b4015281816112cf0152818161133d01526113c101525f8181610130015281816109cc015281816112f901526113f001525f818161017401526110840152611a635ff3fe608060405234801561000f575f5ffd5b5060043610610127575f3560e01c80637dc93390116100a9578063c7da89611161006e578063c7da896114610351578063e14e387814610364578063e30c39781461038b578063ec1100c21461039c578063f2fde38b146103c3575f5ffd5b80637dc93390146102ad5780638b9d2940146102c05780638da5cb5b146102e757806399248ea7146102f7578063b4bd6f461461031e575f5ffd5b8063715018a6116100ef578063715018a61461021257806375b0ffd11461021a578063780900dc1461024157806379ba50971461027e5780637aaf53e614610286575f5ffd5b806308ecd9a61461012b5780630db41f311461016f578063338c5371146101af5780633bc9a431146101d65780634a7500a6146101eb575b5f5ffd5b6101527f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6101967f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160e01b03199091168152602001610166565b6101527f000000000000000000000000000000000000000000000000000000000000000081565b6101e96101e436600461167f565b6103d6565b005b6101527f000000000000000000000000000000000000000000000000000000000000000081565b6101e9610526565b6101527f000000000000000000000000000000000000000000000000000000000000000081565b61025461024f36600461169a565b610539565b604080516001600160a01b0394851681529284166020840152921691810191909152606001610166565b6101e9610731565b6101527f000000000000000000000000000000000000000000000000000000000000000081565b6101526102bb36600461169a565b61077a565b6101527f000000000000000000000000000000000000000000000000000000000000000081565b5f546001600160a01b0316610152565b6101527f000000000000000000000000000000000000000000000000000000000000000081565b61033161032c36600461167f565b6107a2565b604080516001600160a01b03938416815292909116602083015201610166565b6101e961035f3660046116d0565b610a9f565b6101527f000000000000000000000000000000000000000000000000000000000000000081565b6001546001600160a01b0316610152565b6101527f000000000000000000000000000000000000000000000000000000000000000081565b6101e96103d136600461167f565b610aba565b604051632988bb9f60e21b81526001600160a01b0382811660048301525f917f00000000000000000000000000000000000000000000000000000000000000009091169063a622ee7c90602401602060405180830381865afa15801561043e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610462919061179b565b90506001600160a01b03811661048b576040516365da5bb960e11b815260040160405180910390fd5b604051630339050960e51b81526001600160a01b03838116600483015261052291839185917f000000000000000000000000000000000000000000000000000000000000000090911690636720a12090602401602060405180830381865afa1580156104f9573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061051d919061179b565b610b2a565b5050565b61052e610dd1565b6105375f610dfd565b565b5f80807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166105835760405163267f175960e01b815260040160405180910390fd5b604051631526fe2760e01b8152600481018590525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690631526fe279060240160a060405180830381865afa1580156105e8573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061060c91906117c5565b50505091505061061b816107a2565b80945081955050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a3f697ba828760405160200161066691815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610692929190611860565b6020604051808303815f875af11580156106ae573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106d2919061179b565b604080516001600160a01b0384811682528781166020830152868116828401528316606082015290519193507f08063c8075192206c58e6dd01ffef672f99055179aead6066f80fb31dd2db150919081900360800190a1509193909250565b60015433906001600160a01b0316811461076e5760405163118cdaa760e01b81526001600160a01b03821660048201526024015b60405180910390fd5b61077781610dfd565b50565b60028181548110610789575f80fd5b5f918252602090912001546001600160a01b0316905081565b5f5f6107ad83610e16565b6107ca576040516365da5bb960e11b815260040160405180910390fd5b604051632988bb9f60e21b81526001600160a01b0384811660048301525f917f00000000000000000000000000000000000000000000000000000000000000009091169063a622ee7c90602401602060405180830381865afa158015610832573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610856919061179b565b6001600160a01b03161461087d5760405163a6ef0ba160e01b815260040160405180910390fd5b5f61088784610f4f565b6040516001600160601b0319606087811b8216602084015283901b1660348201529091505f9060480160408051601f19818403018152919052805160208201209091506108f57f00000000000000000000000000000000000000000000000000000000000000008383610fb6565b6040516001600160601b0319606083901b16602082015290955060340160408051601f19818403018152908290526001600160601b0319606088901b166020830152925060340160405160208183030381529060405280519060200120905061097f7f00000000000000000000000000000000000000000000000000000000000000008383610fb6565b935061098c858488610fcd565b61099886868587611044565b6109a3858786610b2a565b6109ad8685611108565b60405163a129290360e01b81526001600160a01b0387811660048301527f0000000000000000000000000000000000000000000000000000000000000000811660248301527f0000000000000000000000000000000000000000000000000000000000000000169063a1292903906044015f604051808303815f87803b158015610a35575f5ffd5b505af1158015610a47573d5f5f3e3d5ffd5b5050604080516001600160a01b03898116825287811660208301528a168183015290517f26ad9f07a47e389150a15677a365d64f42af0000b792c182ada6a3b5ab193a0b9350908190036060019150a1505050915091565b610aa7610dd1565b80516105229060029060208401906115f4565b610ac2610dd1565b600180546001600160a01b0383166001600160a01b03199091168117909155610af25f546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040515f602482018190529060440160408051601f198184030181529181526020820180516001600160e01b03166354c49fe960e01b179052519091505f906001600160a01b03851690610b7f90849061189a565b5f604051808303815f865af19150503d805f8114610bb8576040519150601f19603f3d011682016040523d82523d5f602084013e610bbd565b606091505b5050905080610bcd575050505050565b5f5b60088160ff161015610dc9576040516354c49fe960e01b815260ff821660048201525f906001600160a01b038716906354c49fe990602401602060405180830381865afa158015610c22573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c46919061179b565b604051632474e32f60e11b81526001600160a01b0380831660048301529192505f918816906348e9c65e9060240160a060405180830381865afa158015610c8f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cb391906118a5565b50505091505042811015610cc8575050610dc1565b6001600160a01b038216610cdd575050610dc9565b6040516316bfae7f60e31b81526001600160a01b03838116600483015289169063b5fd73f890602401602060405180830381865afa158015610d21573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d4591906118ea565b15610d51575050610dc1565b610d5a82611177565b15610dbe5760405163023cb23960e41b81526001600160a01b03838116600483015287811660248301528916906323cb2390906044015f604051808303815f87803b158015610da7575f5ffd5b505af1158015610db9573d5f5f3e3d5ffd5b505050505b50505b600101610bcf565b505050505050565b5f546001600160a01b031633146105375760405163118cdaa760e01b8152336004820152602401610765565b600180546001600160a01b03191690556107778161125a565b6002545f90610e385760405163242a2cc560e01b815260040160405180910390fd5b5f5b600254811015610ee15760028181548110610e5757610e57611903565b5f91825260209091200154604051634b92037960e01b81526001600160a01b03858116600483015290911690634b92037990602401602060405180830381865afa158015610ea7573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ecb91906118ea565b15610ed95760019150610ee1565b600101610e3a565b50816001600160a01b0316639c868ac06040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f1e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f4291906118ea565b15610f4a57505f5b919050565b5f816001600160a01b03166382c630666040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f8c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fb0919061179b565b92915050565b5f610fc38484845f6112a9565b90505b9392505050565b6040516001600160a01b03821660248201525f1960448201525f9060640160408051601f198184030181529190526020810180516001600160e01b031663095ea7b360e01b179052905061102183826112cc565b61103e57604051633e3f8f7360e01b815260040160405180910390fd5b50505050565b604051633e331d7160e11b81526001600160a01b0385811660048301528481166024830152838116604483015282811660648301526001600160e01b03197f00000000000000000000000000000000000000000000000000000000000000001660848301527f00000000000000000000000000000000000000000000000000000000000000001690637c663ae29060a4015f604051808303815f87803b1580156110ec575f5ffd5b505af11580156110fe573d5f5f3e3d5ffd5b5050505050505050565b6040516001600160a01b03821660248201525f9060440160408051601f198184030181529190526020810180516001600160e01b0316635efcc08b60e11b179052905061115583826112cc565b61117257604051631475790360e11b815260040160405180910390fd5b505050565b5f611181826114b2565b61118c57505f919050565b6002546111ac5760405163242a2cc560e01b815260040160405180910390fd5b5f5b60025481101561125457600281815481106111cb576111cb611903565b5f91825260209091200154604051634b92037960e01b81526001600160a01b03858116600483015290911690634b92037990602401602060405180830381865afa15801561121b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061123f91906118ea565b1561124c575f9150611254565b6001016111ae565b50919050565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f5f6112b58686611502565b90506112c2838583611560565b9695505050505050565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316036113bf5760405163468721a760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063468721a7906113789086905f9087908290600401611917565b6020604051808303815f875af1158015611394573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113b891906118ea565b9050610fb0565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663468721a77f00000000000000000000000000000000000000000000000000000000000000005f865f876040516024016114259392919061196a565b60408051601f198184030181529181526020820180516001600160e01b0316635b0e93fb60e11b1790525160e085901b6001600160e01b0319168152611472939291905f90600401611917565b6020604051808303815f875af115801561148e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fc691906118ea565b5f6001600160a01b03821615801590610fb057507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141592915050565b6060615fd3825111156115285760405163250a241560e21b815260040160405180910390fd5b815161153590602d61199f565b8383604051602001611549939291906119be565b604051602081830303815290604052905092915050565b5f8347101561158b5760405163cf47918160e01b815247600482015260248101859052604401610765565b81515f036115ac57604051631328927760e21b815260040160405180910390fd5b8282516020840186f590503d1519811516156115cd576040513d5f823e3d81fd5b6001600160a01b038116610fc65760405163b06ebf3d60e01b815260040160405180910390fd5b828054828255905f5260205f20908101928215611647579160200282015b8281111561164757825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190611612565b50611653929150611657565b5090565b5b80821115611653575f8155600101611658565b6001600160a01b0381168114610777575f5ffd5b5f6020828403121561168f575f5ffd5b8135610fc68161166b565b5f602082840312156116aa575f5ffd5b5035919050565b634e487b7160e01b5f52604160045260245ffd5b8035610f4a8161166b565b5f602082840312156116e0575f5ffd5b813567ffffffffffffffff8111156116f6575f5ffd5b8201601f81018413611706575f5ffd5b803567ffffffffffffffff811115611720576117206116b1565b8060051b604051601f19603f830116810181811067ffffffffffffffff8211171561174d5761174d6116b1565b60405291825260208184018101929081018784111561176a575f5ffd5b6020850194505b8385101561179057611782856116c5565b815260209485019401611771565b509695505050505050565b5f602082840312156117ab575f5ffd5b8151610fc68161166b565b80518015158114610f4a575f5ffd5b5f5f5f5f5f60a086880312156117d9575f5ffd5b85516117e48161166b565b60208701519095506117f58161166b565b60408701519094506118068161166b565b9250611814606087016117b6565b915060808601516118248161166b565b809150509295509295909350565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160a01b03831681526040602082018190525f90610fc390830184611832565b5f81518060208401855e5f93019283525090919050565b5f610fc68284611883565b5f5f5f5f5f60a086880312156118b9575f5ffd5b85516118c48161166b565b602087015160408801516060890151608090990151929a91995097965090945092505050565b5f602082840312156118fa575f5ffd5b610fc6826117b6565b634e487b7160e01b5f52603260045260245ffd5b60018060a01b0385168152836020820152608060408201525f61193d6080830185611832565b90506002831061195b57634e487b7160e01b5f52602160045260245ffd5b82606083015295945050505050565b6001600160a01b038416815260ff831660208201526060604082018190525f9061199690830184611832565b95945050505050565b80820180821115610fb057634e487b7160e01b5f52601160045260245ffd5b606160f81b815260f084901b6001600160f01b0319166001820152703d81600a3d39f3363d3d373d3d3d363d7360781b6003820152606083901b6001600160601b03191660148201526e5af43d82803e903d91602b57fd5bf360881b60288201525f611996603783018461188356fea26469706673582212203999f4521ca8146620c8bc7b3a4f59595ecc9148aef4303b9d7a2cf882971d1a64736f6c634300081c0033000000000000000000000000000755fbe4a24d7478bfcfc1e561afce82d1ff620000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a80000000000000000000000000b8b83008a2aca8d5f5feeae2c3e764de0290c286000000000000000000000000182137f70a3639a07ec385dec750d60b70bb3fbe000000000000000000000000000000000000000000000000000000000000000000000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6000000000000000000000000d3327cb05a8e0095a543d582b5b3ce3e19270389000000000000000000000000b8368dd16e0a29ba8936856887003be9bf31d3a4

Deployed Bytecode

0x608060405234801561000f575f5ffd5b5060043610610127575f3560e01c80637dc93390116100a9578063c7da89611161006e578063c7da896114610351578063e14e387814610364578063e30c39781461038b578063ec1100c21461039c578063f2fde38b146103c3575f5ffd5b80637dc93390146102ad5780638b9d2940146102c05780638da5cb5b146102e757806399248ea7146102f7578063b4bd6f461461031e575f5ffd5b8063715018a6116100ef578063715018a61461021257806375b0ffd11461021a578063780900dc1461024157806379ba50971461027e5780637aaf53e614610286575f5ffd5b806308ecd9a61461012b5780630db41f311461016f578063338c5371146101af5780633bc9a431146101d65780634a7500a6146101eb575b5f5ffd5b6101527f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101967fc715e3730000000000000000000000000000000000000000000000000000000081565b6040516001600160e01b03199091168152602001610166565b6101527f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b681565b6101e96101e436600461167f565b6103d6565b005b6101527f000000000000000000000000b8b83008a2aca8d5f5feeae2c3e764de0290c28681565b6101e9610526565b6101527f000000000000000000000000d3327cb05a8e0095a543d582b5b3ce3e1927038981565b61025461024f36600461169a565b610539565b604080516001600160a01b0394851681529284166020840152921691810191909152606001610166565b6101e9610731565b6101527f0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a8081565b6101526102bb36600461169a565b61077a565b6101527f000000000000000000000000a7d6dd95a06d95b65edf32b94ed46996e151c06f81565b5f546001600160a01b0316610152565b6101527f000000000000000000000000331b9182088e2a7d6d3fe4742aba1fb231aecc5681565b61033161032c36600461167f565b6107a2565b604080516001600160a01b03938416815292909116602083015201610166565b6101e961035f3660046116d0565b610a9f565b6101527f000000000000000000000000182137f70a3639a07ec385dec750d60b70bb3fbe81565b6001546001600160a01b0316610152565b6101527f000000000000000000000000b8368dd16e0a29ba8936856887003be9bf31d3a481565b6101e96103d136600461167f565b610aba565b604051632988bb9f60e21b81526001600160a01b0382811660048301525f917f0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a809091169063a622ee7c90602401602060405180830381865afa15801561043e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610462919061179b565b90506001600160a01b03811661048b576040516365da5bb960e11b815260040160405180910390fd5b604051630339050960e51b81526001600160a01b03838116600483015261052291839185917f0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a8090911690636720a12090602401602060405180830381865afa1580156104f9573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061051d919061179b565b610b2a565b5050565b61052e610dd1565b6105375f610dfd565b565b5f80807f000000000000000000000000b8368dd16e0a29ba8936856887003be9bf31d3a46001600160a01b03166105835760405163267f175960e01b815260040160405180910390fd5b604051631526fe2760e01b8152600481018590525f907f000000000000000000000000d3327cb05a8e0095a543d582b5b3ce3e192703896001600160a01b031690631526fe279060240160a060405180830381865afa1580156105e8573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061060c91906117c5565b50505091505061061b816107a2565b80945081955050507f000000000000000000000000b8368dd16e0a29ba8936856887003be9bf31d3a46001600160a01b031663a3f697ba828760405160200161066691815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610692929190611860565b6020604051808303815f875af11580156106ae573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106d2919061179b565b604080516001600160a01b0384811682528781166020830152868116828401528316606082015290519193507f08063c8075192206c58e6dd01ffef672f99055179aead6066f80fb31dd2db150919081900360800190a1509193909250565b60015433906001600160a01b0316811461076e5760405163118cdaa760e01b81526001600160a01b03821660048201526024015b60405180910390fd5b61077781610dfd565b50565b60028181548110610789575f80fd5b5f918252602090912001546001600160a01b0316905081565b5f5f6107ad83610e16565b6107ca576040516365da5bb960e11b815260040160405180910390fd5b604051632988bb9f60e21b81526001600160a01b0384811660048301525f917f0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a809091169063a622ee7c90602401602060405180830381865afa158015610832573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610856919061179b565b6001600160a01b03161461087d5760405163a6ef0ba160e01b815260040160405180910390fd5b5f61088784610f4f565b6040516001600160601b0319606087811b8216602084015283901b1660348201529091505f9060480160408051601f19818403018152919052805160208201209091506108f57f000000000000000000000000b8b83008a2aca8d5f5feeae2c3e764de0290c2868383610fb6565b6040516001600160601b0319606083901b16602082015290955060340160408051601f19818403018152908290526001600160601b0319606088901b166020830152925060340160405160208183030381529060405280519060200120905061097f7f000000000000000000000000182137f70a3639a07ec385dec750d60b70bb3fbe8383610fb6565b935061098c858488610fcd565b61099886868587611044565b6109a3858786610b2a565b6109ad8685611108565b60405163a129290360e01b81526001600160a01b0387811660048301527f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6811660248301527f0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a80169063a1292903906044015f604051808303815f87803b158015610a35575f5ffd5b505af1158015610a47573d5f5f3e3d5ffd5b5050604080516001600160a01b03898116825287811660208301528a168183015290517f26ad9f07a47e389150a15677a365d64f42af0000b792c182ada6a3b5ab193a0b9350908190036060019150a1505050915091565b610aa7610dd1565b80516105229060029060208401906115f4565b610ac2610dd1565b600180546001600160a01b0383166001600160a01b03199091168117909155610af25f546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040515f602482018190529060440160408051601f198184030181529181526020820180516001600160e01b03166354c49fe960e01b179052519091505f906001600160a01b03851690610b7f90849061189a565b5f604051808303815f865af19150503d805f8114610bb8576040519150601f19603f3d011682016040523d82523d5f602084013e610bbd565b606091505b5050905080610bcd575050505050565b5f5b60088160ff161015610dc9576040516354c49fe960e01b815260ff821660048201525f906001600160a01b038716906354c49fe990602401602060405180830381865afa158015610c22573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c46919061179b565b604051632474e32f60e11b81526001600160a01b0380831660048301529192505f918816906348e9c65e9060240160a060405180830381865afa158015610c8f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cb391906118a5565b50505091505042811015610cc8575050610dc1565b6001600160a01b038216610cdd575050610dc9565b6040516316bfae7f60e31b81526001600160a01b03838116600483015289169063b5fd73f890602401602060405180830381865afa158015610d21573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d4591906118ea565b15610d51575050610dc1565b610d5a82611177565b15610dbe5760405163023cb23960e41b81526001600160a01b03838116600483015287811660248301528916906323cb2390906044015f604051808303815f87803b158015610da7575f5ffd5b505af1158015610db9573d5f5f3e3d5ffd5b505050505b50505b600101610bcf565b505050505050565b5f546001600160a01b031633146105375760405163118cdaa760e01b8152336004820152602401610765565b600180546001600160a01b03191690556107778161125a565b6002545f90610e385760405163242a2cc560e01b815260040160405180910390fd5b5f5b600254811015610ee15760028181548110610e5757610e57611903565b5f91825260209091200154604051634b92037960e01b81526001600160a01b03858116600483015290911690634b92037990602401602060405180830381865afa158015610ea7573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ecb91906118ea565b15610ed95760019150610ee1565b600101610e3a565b50816001600160a01b0316639c868ac06040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f1e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f4291906118ea565b15610f4a57505f5b919050565b5f816001600160a01b03166382c630666040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f8c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fb0919061179b565b92915050565b5f610fc38484845f6112a9565b90505b9392505050565b6040516001600160a01b03821660248201525f1960448201525f9060640160408051601f198184030181529190526020810180516001600160e01b031663095ea7b360e01b179052905061102183826112cc565b61103e57604051633e3f8f7360e01b815260040160405180910390fd5b50505050565b604051633e331d7160e11b81526001600160a01b0385811660048301528481166024830152838116604483015282811660648301526001600160e01b03197fc715e373000000000000000000000000000000000000000000000000000000001660848301527f0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a801690637c663ae29060a4015f604051808303815f87803b1580156110ec575f5ffd5b505af11580156110fe573d5f5f3e3d5ffd5b5050505050505050565b6040516001600160a01b03821660248201525f9060440160408051601f198184030181529190526020810180516001600160e01b0316635efcc08b60e11b179052905061115583826112cc565b61117257604051631475790360e11b815260040160405180910390fd5b505050565b5f611181826114b2565b61118c57505f919050565b6002546111ac5760405163242a2cc560e01b815260040160405180910390fd5b5f5b60025481101561125457600281815481106111cb576111cb611903565b5f91825260209091200154604051634b92037960e01b81526001600160a01b03858116600483015290911690634b92037990602401602060405180830381865afa15801561121b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061123f91906118ea565b1561124c575f9150611254565b6001016111ae565b50919050565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f5f6112b58686611502565b90506112c2838583611560565b9695505050505050565b5f7f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b03167f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b0316036113bf5760405163468721a760e01b81526001600160a01b037f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6169063468721a7906113789086905f9087908290600401611917565b6020604051808303815f875af1158015611394573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113b891906118ea565b9050610fb0565b7f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b66001600160a01b031663468721a77f00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b65f865f876040516024016114259392919061196a565b60408051601f198184030181529181526020820180516001600160e01b0316635b0e93fb60e11b1790525160e085901b6001600160e01b0319168152611472939291905f90600401611917565b6020604051808303815f875af115801561148e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fc691906118ea565b5f6001600160a01b03821615801590610fb057507f000000000000000000000000331b9182088e2a7d6d3fe4742aba1fb231aecc566001600160a01b0316826001600160a01b0316141592915050565b6060615fd3825111156115285760405163250a241560e21b815260040160405180910390fd5b815161153590602d61199f565b8383604051602001611549939291906119be565b604051602081830303815290604052905092915050565b5f8347101561158b5760405163cf47918160e01b815247600482015260248101859052604401610765565b81515f036115ac57604051631328927760e21b815260040160405180910390fd5b8282516020840186f590503d1519811516156115cd576040513d5f823e3d81fd5b6001600160a01b038116610fc65760405163b06ebf3d60e01b815260040160405180910390fd5b828054828255905f5260205f20908101928215611647579160200282015b8281111561164757825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190611612565b50611653929150611657565b5090565b5b80821115611653575f8155600101611658565b6001600160a01b0381168114610777575f5ffd5b5f6020828403121561168f575f5ffd5b8135610fc68161166b565b5f602082840312156116aa575f5ffd5b5035919050565b634e487b7160e01b5f52604160045260245ffd5b8035610f4a8161166b565b5f602082840312156116e0575f5ffd5b813567ffffffffffffffff8111156116f6575f5ffd5b8201601f81018413611706575f5ffd5b803567ffffffffffffffff811115611720576117206116b1565b8060051b604051601f19603f830116810181811067ffffffffffffffff8211171561174d5761174d6116b1565b60405291825260208184018101929081018784111561176a575f5ffd5b6020850194505b8385101561179057611782856116c5565b815260209485019401611771565b509695505050505050565b5f602082840312156117ab575f5ffd5b8151610fc68161166b565b80518015158114610f4a575f5ffd5b5f5f5f5f5f60a086880312156117d9575f5ffd5b85516117e48161166b565b60208701519095506117f58161166b565b60408701519094506118068161166b565b9250611814606087016117b6565b915060808601516118248161166b565b809150509295509295909350565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160a01b03831681526040602082018190525f90610fc390830184611832565b5f81518060208401855e5f93019283525090919050565b5f610fc68284611883565b5f5f5f5f5f60a086880312156118b9575f5ffd5b85516118c48161166b565b602087015160408801516060890151608090990151929a91995097965090945092505050565b5f602082840312156118fa575f5ffd5b610fc6826117b6565b634e487b7160e01b5f52603260045260245ffd5b60018060a01b0385168152836020820152608060408201525f61193d6080830185611832565b90506002831061195b57634e487b7160e01b5f52602160045260245ffd5b82606083015295945050505050565b6001600160a01b038416815260ff831660208201526060604082018190525f9061199690830184611832565b95945050505050565b80820180821115610fb057634e487b7160e01b5f52601160045260245ffd5b606160f81b815260f084901b6001600160f01b0319166001820152703d81600a3d39f3363d3d373d3d3d363d7360781b6003820152606083901b6001600160601b03191660148201526e5af43d82803e903d91602b57fd5bf360881b60288201525f611996603783018461188356fea26469706673582212203999f4521ca8146620c8bc7b3a4f59595ecc9148aef4303b9d7a2cf882971d1a64736f6c634300081c0033

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

000000000000000000000000000755fbe4a24d7478bfcfc1e561afce82d1ff620000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a80000000000000000000000000b8b83008a2aca8d5f5feeae2c3e764de0290c286000000000000000000000000182137f70a3639a07ec385dec750d60b70bb3fbe000000000000000000000000000000000000000000000000000000000000000000000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6000000000000000000000000d3327cb05a8e0095a543d582b5b3ce3e19270389000000000000000000000000b8368dd16e0a29ba8936856887003be9bf31d3a4

-----Decoded View---------------
Arg [0] : admin (address): 0x000755Fbe4A24d7478bfcFC1E561AfCE82d1ff62
Arg [1] : protocolController (address): 0x4D4c2C4777625e97be1985682fAE5A53f5C44A80
Arg [2] : vaultImplementation (address): 0xB8B83008a2Aca8D5F5feeae2c3e764DE0290c286
Arg [3] : rewardReceiverImplementation (address): 0x182137f70A3639A07EC385DeC750d60B70bb3fbE
Arg [4] : locker (address): 0x0000000000000000000000000000000000000000
Arg [5] : gateway (address): 0x52f541764E6e90eeBc5c21Ff570De0e2D63766B6
Arg [6] : booster (address): 0xd3327cb05a8E0095A543D582b5B3Ce3e19270389
Arg [7] : convexSidecarFactory (address): 0xb8368DD16E0A29ba8936856887003Be9bF31d3A4

-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 000000000000000000000000000755fbe4a24d7478bfcfc1e561afce82d1ff62
Arg [1] : 0000000000000000000000004d4c2c4777625e97be1985682fae5a53f5c44a80
Arg [2] : 000000000000000000000000b8b83008a2aca8d5f5feeae2c3e764de0290c286
Arg [3] : 000000000000000000000000182137f70a3639a07ec385dec750d60b70bb3fbe
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [5] : 00000000000000000000000052f541764e6e90eebc5c21ff570de0e2d63766b6
Arg [6] : 000000000000000000000000d3327cb05a8e0095a543d582b5b3ce3e19270389
Arg [7] : 000000000000000000000000b8368dd16e0a29ba8936856887003be9bf31d3a4


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  ]
[ 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.