{"file_path":"contracts/strategies/crosschain/CrossChainMasterStrategy.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Yearn V3 Master Strategy - the Mainnet part\n * @author Origin Protocol Inc\n *\n * @dev This strategy can only perform 1 deposit or withdrawal at a time. For that\n *      reason it shouldn't be configured as an asset default strategy.\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20, InitializableAbstractStrategy } from \"../../utils/InitializableAbstractStrategy.sol\";\nimport { AbstractCCTPIntegrator } from \"./AbstractCCTPIntegrator.sol\";\nimport { CrossChainStrategyHelper } from \"./CrossChainStrategyHelper.sol\";\n\ncontract CrossChainMasterStrategy is\n    AbstractCCTPIntegrator,\n    InitializableAbstractStrategy\n{\n    using SafeERC20 for IERC20;\n    using CrossChainStrategyHelper for bytes;\n\n    /**\n     * @notice Remote strategy balance\n     * @dev    The remote balance is cached and might not reflect the actual\n     *         real-time balance of the remote strategy.\n     */\n    uint256 public remoteStrategyBalance;\n\n    /// @notice Amount that's bridged due to a pending Deposit process\n    ///         but with no acknowledgement from the remote strategy yet\n    uint256 public pendingAmount;\n\n    uint256 internal constant MAX_BALANCE_CHECK_AGE = 1 days;\n\n    event RemoteStrategyBalanceUpdated(uint256 balance);\n    event WithdrawRequested(address indexed asset, uint256 amount);\n    event WithdrawAllSkipped();\n    event BalanceCheckIgnored(uint64 nonce, uint256 timestamp, bool isTooOld);\n\n    /**\n     * @param _stratConfig The platform and OToken vault addresses\n     */\n    constructor(\n        BaseStrategyConfig memory _stratConfig,\n        CCTPIntegrationConfig memory _cctpConfig\n    )\n        InitializableAbstractStrategy(_stratConfig)\n        AbstractCCTPIntegrator(_cctpConfig)\n    {\n        require(\n            _stratConfig.platformAddress == address(0),\n            \"Invalid platform address\"\n        );\n        require(\n            _stratConfig.vaultAddress != address(0),\n            \"Invalid Vault address\"\n        );\n    }\n\n    /**\n     * @dev Initialize the strategy implementation\n     * @param _operator Address of the operator\n     * @param _minFinalityThreshold Minimum finality threshold\n     * @param _feePremiumBps Fee premium in basis points\n     */\n    function initialize(\n        address _operator,\n        uint16 _minFinalityThreshold,\n        uint16 _feePremiumBps\n    ) external virtual onlyGovernor initializer {\n        _initialize(_operator, _minFinalityThreshold, _feePremiumBps);\n\n        address[] memory rewardTokens = new address[](0);\n        address[] memory assets = new address[](0);\n        address[] memory pTokens = new address[](0);\n\n        InitializableAbstractStrategy._initialize(\n            rewardTokens,\n            assets,\n            pTokens\n        );\n    }\n\n    /// @inheritdoc InitializableAbstractStrategy\n    function deposit(address _asset, uint256 _amount)\n        external\n        override\n        onlyVault\n        nonReentrant\n    {\n        _deposit(_asset, _amount);\n    }\n\n    /// @inheritdoc InitializableAbstractStrategy\n    function depositAll() external override onlyVault nonReentrant {\n        uint256 balance = IERC20(usdcToken).balanceOf(address(this));\n        // Deposit if balance is greater than 1 USDC\n        if (balance >= MIN_TRANSFER_AMOUNT) {\n            _deposit(usdcToken, balance);\n        }\n    }\n\n    /// @inheritdoc InitializableAbstractStrategy\n    function withdraw(\n        address _recipient,\n        address _asset,\n        uint256 _amount\n    ) external override onlyVault nonReentrant {\n        require(_recipient == vaultAddress, \"Only Vault can withdraw\");\n        _withdraw(_asset, _amount);\n    }\n\n    /// @inheritdoc InitializableAbstractStrategy\n    function withdrawAll() external override onlyVaultOrGovernor nonReentrant {\n        if (isTransferPending()) {\n            // Do nothing if there is a pending transfer\n            // Note: We never want withdrawAll to fail, so\n            // emit an event to indicate that the withdrawal was skipped\n            emit WithdrawAllSkipped();\n            return;\n        }\n\n        // Withdraw everything in Remote strategy\n        uint256 _remoteBalance = remoteStrategyBalance;\n        if (_remoteBalance < MIN_TRANSFER_AMOUNT) {\n            // Do nothing if there is less than 1 USDC in the Remote strategy\n            return;\n        }\n\n        _withdraw(\n            usdcToken,\n            _remoteBalance > MAX_TRANSFER_AMOUNT\n                ? MAX_TRANSFER_AMOUNT\n                : _remoteBalance\n        );\n    }\n\n    /**\n     * @notice Check the balance of the strategy that includes\n     *          the balance of the asset on this contract,\n     *          the amount of the asset being bridged,\n     *          and the balance reported by the Remote strategy.\n     * @param _asset Address of the asset to check\n     * @return balance Total balance of the asset\n     */\n    function checkBalance(address _asset)\n        public\n        view\n        override\n        returns (uint256 balance)\n    {\n        require(_asset == usdcToken, \"Unsupported asset\");\n\n        // USDC balance on this contract\n        // + USDC being bridged\n        // + USDC cached in the corresponding Remote part of this contract\n        return\n            IERC20(usdcToken).balanceOf(address(this)) +\n            pendingAmount +\n            remoteStrategyBalance;\n    }\n\n    /// @inheritdoc InitializableAbstractStrategy\n    function supportsAsset(address _asset) public view override returns (bool) {\n        return _asset == usdcToken;\n    }\n\n    /// @inheritdoc InitializableAbstractStrategy\n    function safeApproveAllTokens()\n        external\n        override\n        onlyGovernor\n        nonReentrant\n    {}\n\n    /// @inheritdoc InitializableAbstractStrategy\n    function _abstractSetPToken(address, address) internal override {}\n\n    /// @inheritdoc InitializableAbstractStrategy\n    function collectRewardTokens()\n        external\n        override\n        onlyHarvester\n        nonReentrant\n    {}\n\n    /// @inheritdoc AbstractCCTPIntegrator\n    function _onMessageReceived(bytes memory payload) internal override {\n        if (\n            payload.getMessageType() ==\n            CrossChainStrategyHelper.BALANCE_CHECK_MESSAGE\n        ) {\n            // Received when Remote strategy checks the balance\n            _processBalanceCheckMessage(payload);\n            return;\n        }\n\n        revert(\"Unknown message type\");\n    }\n\n    /// @inheritdoc AbstractCCTPIntegrator\n    function _onTokenReceived(\n        uint256 tokenAmount,\n        // solhint-disable-next-line no-unused-vars\n        uint256 feeExecuted,\n        bytes memory payload\n    ) internal override {\n        uint64 _nonce = lastTransferNonce;\n\n        // Should be expecting an acknowledgement\n        require(!isNonceProcessed(_nonce), \"Nonce already processed\");\n\n        // Now relay to the regular flow\n        // NOTE: Calling _onMessageReceived would mean that we are bypassing a\n        // few checks that the regular flow does (like sourceDomainID check\n        // and sender check in `handleReceiveFinalizedMessage`). However,\n        // CCTPMessageRelayer relays the message first (which will go through\n        // all the checks) and not update balance and then finally calls this\n        // `_onTokenReceived` which will update the balance.\n        // So, if any of the checks fail during the first no-balance-update flow,\n        // this won't happen either, since the tx would revert.\n        _onMessageReceived(payload);\n\n        // Send any tokens in the contract to the Vault\n        uint256 usdcBalance = IERC20(usdcToken).balanceOf(address(this));\n        // Should always have enough tokens\n        require(usdcBalance >= tokenAmount, \"Insufficient balance\");\n        // Transfer all tokens to the Vault to not leave any dust\n        IERC20(usdcToken).safeTransfer(vaultAddress, usdcBalance);\n\n        // Emit withdrawal amount\n        emit Withdrawal(usdcToken, usdcToken, usdcBalance);\n    }\n\n    /**\n     * @dev Bridge and deposit asset into the remote strategy\n     * @param _asset Address of the asset to deposit\n     * @param depositAmount Amount of the asset to deposit\n     */\n    function _deposit(address _asset, uint256 depositAmount) internal virtual {\n        require(_asset == usdcToken, \"Unsupported asset\");\n        require(pendingAmount == 0, \"Unexpected pending amount\");\n        // Deposit at least 1 USDC\n        require(\n            depositAmount >= MIN_TRANSFER_AMOUNT,\n            \"Deposit amount too small\"\n        );\n        require(\n            depositAmount <= MAX_TRANSFER_AMOUNT,\n            \"Deposit amount too high\"\n        );\n\n        // Get the next nonce\n        // Note: reverts if a transfer is pending\n        uint64 nonce = _getNextNonce();\n\n        // Set pending amount\n        pendingAmount = depositAmount;\n\n        // Build deposit message payload\n        bytes memory message = CrossChainStrategyHelper.encodeDepositMessage(\n            nonce,\n            depositAmount\n        );\n\n        // Send deposit message to the remote strategy\n        _sendTokens(depositAmount, message);\n\n        // Emit deposit event\n        emit Deposit(_asset, _asset, depositAmount);\n    }\n\n    /**\n     * @dev Send a withdraw request to the remote strategy\n     * @param _asset Address of the asset to withdraw\n     * @param _amount Amount of the asset to withdraw\n     */\n    function _withdraw(address _asset, uint256 _amount) internal virtual {\n        require(_asset == usdcToken, \"Unsupported asset\");\n        // Withdraw at least 1 USDC\n        require(_amount >= MIN_TRANSFER_AMOUNT, \"Withdraw amount too small\");\n        require(\n            _amount <= remoteStrategyBalance,\n            \"Withdraw amount exceeds remote strategy balance\"\n        );\n        require(\n            _amount <= MAX_TRANSFER_AMOUNT,\n            \"Withdraw amount exceeds max transfer amount\"\n        );\n\n        // Get the next nonce\n        // Note: reverts if a transfer is pending\n        uint64 nonce = _getNextNonce();\n\n        // Build and send withdrawal message with payload\n        bytes memory message = CrossChainStrategyHelper.encodeWithdrawMessage(\n            nonce,\n            _amount\n        );\n        _sendMessage(message);\n\n        // Emit WithdrawRequested event here,\n        // Withdraw will be emitted in _onTokenReceived\n        emit WithdrawRequested(usdcToken, _amount);\n    }\n\n    /**\n     * @dev Process balance check:\n     *  - Confirms a deposit to the remote strategy\n     *  - Skips balance update if there's a pending withdrawal\n     *  - Updates the remote strategy balance\n     * @param message The message containing the nonce and balance\n     */\n    function _processBalanceCheckMessage(bytes memory message)\n        internal\n        virtual\n    {\n        // Decode the message\n        // When transferConfirmation is true, it means that the message is a result of a deposit or a withdrawal\n        // process.\n        (\n            uint64 nonce,\n            uint256 balance,\n            bool transferConfirmation,\n            uint256 timestamp\n        ) = message.decodeBalanceCheckMessage();\n        // Get the last cached nonce\n        uint64 _lastCachedNonce = lastTransferNonce;\n\n        if (nonce != _lastCachedNonce) {\n            // If nonce is not the last cached nonce, it is an outdated message\n            // Ignore it\n            return;\n        }\n\n        // A received message nonce not yet processed indicates there is a\n        // deposit or withdrawal in progress.\n        bool transferInProgress = isTransferPending();\n\n        if (transferInProgress) {\n            if (transferConfirmation) {\n                // Apply the effects of the deposit / withdrawal completion\n                _markNonceAsProcessed(nonce);\n                pendingAmount = 0;\n            } else {\n                // A balanceCheck arrived that is not part of the deposit / withdrawal process\n                // that has been generated on the Remote contract after the deposit / withdrawal which is\n                // still pending. This can happen when the CCTP bridge delivers the messages out of order.\n                // Ignore it, since the pending deposit / withdrawal must first be cofirmed.\n                emit BalanceCheckIgnored(nonce, timestamp, false);\n                return;\n            }\n        } else {\n            if (block.timestamp > timestamp + MAX_BALANCE_CHECK_AGE) {\n                // Balance check is too old, ignore it\n                emit BalanceCheckIgnored(nonce, timestamp, true);\n                return;\n            }\n        }\n\n        // At this point update the strategy balance the balanceCheck message is either:\n        // - a confirmation of a deposit / withdrawal\n        // - a message that updates balances when no deposit / withdrawal is in progress\n        remoteStrategyBalance = balance;\n        emit RemoteStrategyBalanceUpdated(balance);\n    }\n}\n","deployed_bytecode":"0x608060405234801561001057600080fd5b506004361061028a5760003560e01c80637b2d9b2c1161015c578063b3ab15fb116100ce578063d9caed1211610087578063d9caed12146106b9578063dbe55e56146106cc578063de5f6268146106f3578063ed42412b146106fb578063f6ca71b014610704578063fc1b31131461071957600080fd5b8063b3ab15fb1461063d578063ba1066ed14610650578063c2e1e3f414610659578063c7af33521461066c578063d38bfff414610674578063d7dd614b1461068757600080fd5b80638c73eb04116101205780638c73eb04146105815780639136616a146105a857806396d538bb146105bb5780639748cf7c146105ce578063aa388af6146105f5578063ad1728cb1461063557600080fd5b80637b2d9b2c146104f05780637c92f219146105035780637ddfce2d14610516578063853828b61461053d5780638949f6f31461054557600080fd5b806342c8c11c116102005780635a063f63116101b95780635a063f63146104805780635a236417146104885780635d36b1901461049b5780635f515226146104a35780636369e49f146104b657806367c7066c146104dd57600080fd5b806342c8c11c146103f2578063430bf08a1461040557806347e7ef241461042c5780635324df321461043f578063564a515814610453578063570ca7351461046657600080fd5b806311eac8551161025257806311eac8551461032857806316a0f2501461034f5780631801c408146103705780631c4b995a1461039b57806323c9ab3d146103ae5780633c3dbbc7146103da57600080fd5b80630c340a241461028f5780630ed57b3a146102b45780630fc3b4c4146102c95780631072cbea146102f257806311cffb6714610305575b600080fd5b610297610726565b6040516001600160a01b0390911681526020015b60405180910390f35b6102c76102c2366004613931565b610743565b005b6102976102d736600461396a565b6067602052600090815260409020546001600160a01b031681565b6102c7610300366004613987565b61077e565b610318610313366004613a6f565b610839565b60405190151581526020016102ab565b6102977f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b60335461035d9061ffff1681565b60405161ffff90911681526020016102ab565b603354600160201b90046001600160401b031660009081526034602052604090205460ff1615610318565b6102c76103a9366004613ae8565b61091f565b6103186103bc366004613b42565b6001600160401b031660009081526034602052604090205460ff1690565b6103e4620f424081565b6040519081526020016102ab565b6102c7610400366004613b5f565b610a32565b6102977f000000000000000000000000e75d77b1865ae93c7eaa3040b038d7aa7bc02f7081565b6102c761043a366004613987565b610a62565b60335461035d9062010000900461ffff1681565b6102c7610461366004613b7a565b610af3565b60335461029790600160601b90046001600160a01b031681565b6102c7610ffd565b6102c7610496366004613b5f565b611090565b6102c76110bd565b6103e46104b136600461396a565b611163565b6102977f000000000000000000000000b1d624fc40824683e2bfbefd19eb208dbbe0086681565b606b54610297906001600160a01b031681565b6102976104fe366004613be1565b61125e565b610318610511366004613a6f565b611288565b6102977f000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda0291381565b6102c76113c0565b61056c7f000000000000000000000000000000000000000000000000000000000000000681565b60405163ffffffff90911681526020016102ab565b6102977f00000000000000000000000081d40f21f12a8f0e3252bccb954d722d4c464b6481565b6102c76105b6366004613be1565b611553565b6102c76105c9366004613bfa565b61171e565b6102977f00000000000000000000000028b5a0e9c621a5badaa536219b3a228c8168cf5d81565b61031861060336600461396a565b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0390811691161490565b6102c7611835565b6102c761064b36600461396a565b611859565b6103e460d05481565b6102c761066736600461396a565b611886565b610318611913565b6102c761068236600461396a565b611944565b6033546106a190600160201b90046001600160401b031681565b6040516001600160401b0390911681526020016102ab565b6102c76106c7366004613c6f565b6119e8565b6102977f000000000000000000000000000000000000000000000000000000000000000081565b6102c7611afb565b6103e460cf5481565b61070c611c3a565b6040516102ab9190613cb0565b6103e46509184e72a00081565b600061073e6000805160206142538339815191525490565b905090565b61074b611913565b6107705760405162461bcd60e51b815260040161076790613cfc565b60405180910390fd5b61077a8282611c9c565b5050565b610786611913565b6107a25760405162461bcd60e51b815260040161076790613cfc565b6001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881169083160361081d5760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610767565b61077a610828610726565b6001600160a01b0384169083611dfb565b6000336001600160a01b037f00000000000000000000000081d40f21f12a8f0e3252bccb954d722d4c464b6416146108b35760405162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206973206e6f742043435450207472616e736d697474657200006044820152606401610767565b6107d08363ffffffff16101561090b5760405162461bcd60e51b815260206004820152601a60248201527f46696e616c697479207468726573686f6c6420746f6f206c6f770000000000006044820152606401610767565b610916858584611e63565b95945050505050565b610927611913565b6109435760405162461bcd60e51b815260040161076790613cfc565b600054610100900460ff168061095c575060005460ff16155b6109bf5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610767565b600054610100900460ff161580156109e1576000805461ffff19166101011790555b6109ec848484611f5c565b6040805160008082526020820181815282840191825260608301909352909190610a17838383611fb1565b5050508015610a2c576000805461ff00191690555b50505050565b610a3a611913565b610a565760405162461bcd60e51b815260040161076790613cfc565b610a5f81612064565b50565b336001600160a01b037f000000000000000000000000e75d77b1865ae93c7eaa3040b038d7aa7bc02f701614610aaa5760405162461bcd60e51b815260040161076790613d33565b60008051602061423383398151915280546001198101610adc5760405162461bcd60e51b815260040161076790613d6a565b60028255610aea8484612106565b50600190555050565b603354600160601b90046001600160a01b03163314610b545760405162461bcd60e51b815260206004820152601a60248201527f43616c6c6572206973206e6f7420746865204f70657261746f720000000000006044820152606401610767565b6000806000806000610b65876122c4565b94509450945094509450600163ffffffff168563ffffffff1614610bcb5760405162461bcd60e51b815260206004820152601c60248201527f496e76616c69642043435450206d6573736167652076657273696f6e000000006044820152606401610767565b7f000000000000000000000000000000000000000000000000000000000000000663ffffffff168463ffffffff1614610c3e5760405162461bcd60e51b81526020600482015260156024820152742ab735b737bbb71029b7bab931b2902237b6b0b4b760591b6044820152606401610767565b610c4981600061231a565b945060007f00000000000000000000000028b5a0e9c621a5badaa536219b3a228c8168cf5d6001600160a01b0316846001600160a01b03161490508015610d8a578563ffffffff166001148015610ca25750815160e411155b610ce55760405162461bcd60e51b8152602060048201526014602482015273496e76616c6964206275726e206d65737361676560601b6044820152606401610767565b6000610cf2836004612339565b90507f000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda029136001600160a01b0316816001600160a01b031614610d6a5760405162461bcd60e51b815260206004820152601260248201527124b73b30b634b210313ab937103a37b5b2b760711b6044820152606401610767565b610d75836064612339565b9450610d82836024612339565b935050610de1565b63ffffffff86166103f214610de15760405162461bcd60e51b815260206004820152601b60248201527f556e737570706f72746564206d6573736167652076657273696f6e00000000006044820152606401610767565b306001600160a01b03841614610e395760405162461bcd60e51b815260206004820152601c60248201527f556e657870656374656420726563697069656e742061646472657373000000006044820152606401610767565b7f000000000000000000000000b1d624fc40824683e2bfbefd19eb208dbbe008666001600160a01b0316846001600160a01b031614610ec55760405162461bcd60e51b815260206004820152602260248201527f496e636f72726563742073656e6465722f726563697069656e74206164647265604482015261737360f01b6064820152608401610767565b604051630afd9fa560e31b81526000906001600160a01b037f00000000000000000000000081d40f21f12a8f0e3252bccb954d722d4c464b6416906357ecfd2890610f16908c908c90600401613de2565b6020604051808303816000875af1158015610f35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f599190613e17565b905080610fa15760405162461bcd60e51b8152602060048201526016602482015275149958d95a5d99481b595cdcd859d94819985a5b195960521b6044820152606401610767565b8115610ff2578251600090610fba90859060e490612353565b90506000610fc98560446124ad565b90506000610fd88660a46124ad565b9050610fee610fe78284613e48565b82856124c7565b5050505b505050505050505050565b606b546001600160a01b031633146110575760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610767565b600080516020614233833981519152805460011981016110895760405162461bcd60e51b815260040161076790613d6a565b5060019055565b611098611913565b6110b45760405162461bcd60e51b815260040161076790613cfc565b610a5f816126cf565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146111585760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610767565b6111613361276c565b565b60007f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316826001600160a01b0316146111b65760405162461bcd60e51b815260040161076790613e5b565b60cf5460d0546040516370a0823160e01b81523060048201527f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a0823190602401602060405180830381865afa158015611220573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112449190613e86565b61124e9190613e9f565b6112589190613e9f565b92915050565b606c818154811061126e57600080fd5b6000918252602090912001546001600160a01b0316905081565b6000336001600160a01b037f00000000000000000000000081d40f21f12a8f0e3252bccb954d722d4c464b6416146113025760405162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206973206e6f742043435450207472616e736d697474657200006044820152606401610767565b60335461ffff166103e8146113685760405162461bcd60e51b815260206004820152602660248201527f556e66696e616c697a6564206d6573736167657320617265206e6f74207375706044820152651c1bdc9d195960d21b6064820152608401610767565b6103e88363ffffffff16101561090b5760405162461bcd60e51b815260206004820152601a60248201527f46696e616c697479207468726573686f6c6420746f6f206c6f770000000000006044820152606401610767565b336001600160a01b037f000000000000000000000000e75d77b1865ae93c7eaa3040b038d7aa7bc02f7016148061140f57506113fa610726565b6001600160a01b0316336001600160a01b0316145b6114675760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610767565b600080516020614233833981519152805460011981016114995760405162461bcd60e51b815260040161076790613d6a565b60028255603354600160201b90046001600160401b031660009081526034602052604090205460ff166114f4576040517ff49d67e0c10520c98c98114270c479ce28ba2e7bef7908bb15914eb5a3b6165190600090a1611089565b60cf54620f42408110156115085750611089565b61154b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486509184e72a000831161153f57826127cb565b6509184e72a0006127cb565b505060019055565b61155b611913565b6115775760405162461bcd60e51b815260040161076790613cfc565b60685481106115b85760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610767565b6000606882815481106115cd576115cd613eb2565b60009182526020808320909101546001600160a01b0390811680845260679092526040909220546068549193509091169061160a90600190613e48565b83101561168c576068805461162190600190613e48565b8154811061163157611631613eb2565b600091825260209091200154606880546001600160a01b03909216918590811061165d5761165d613eb2565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b606880548061169d5761169d613ec8565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b038581168083526067855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b611726611913565b6117425760405162461bcd60e51b815260040161076790613cfc565b8060005b818110156117ec57600084848381811061176257611762613eb2565b9050602002016020810190611777919061396a565b6001600160a01b0316036117e45760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610767565b600101611746565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc606c848460405161182193929190613ede565b60405180910390a1610a2c606c848461384f565b61183d611913565b6110575760405162461bcd60e51b815260040161076790613cfc565b611861611913565b61187d5760405162461bcd60e51b815260040161076790613cfc565b610a5f816129c1565b61188e611913565b6118aa5760405162461bcd60e51b815260040161076790613cfc565b606b54604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a1606b80546001600160a01b0319166001600160a01b0392909216919091179055565b600061192b6000805160206142538339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61194c611913565b6119685760405162461bcd60e51b815260040161076790613cfc565b611990817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166119b06000805160206142538339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f000000000000000000000000e75d77b1865ae93c7eaa3040b038d7aa7bc02f701614611a305760405162461bcd60e51b815260040161076790613d33565b60008051602061423383398151915280546001198101611a625760405162461bcd60e51b815260040161076790613d6a565b600282557f000000000000000000000000e75d77b1865ae93c7eaa3040b038d7aa7bc02f706001600160a01b0316856001600160a01b031614611ae75760405162461bcd60e51b815260206004820152601760248201527f4f6e6c79205661756c742063616e2077697468647261770000000000000000006044820152606401610767565b611af184846127cb565b5060019055505050565b336001600160a01b037f000000000000000000000000e75d77b1865ae93c7eaa3040b038d7aa7bc02f701614611b435760405162461bcd60e51b815260040161076790613d33565b60008051602061423383398151915280546001198101611b755760405162461bcd60e51b815260040161076790613d6a565b600282556040516370a0823160e01b81523060048201526000907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a0823190602401602060405180830381865afa158015611be0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c049190613e86565b9050620f4240811061154b5761154b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4882612106565b6060606c805480602002602001604051908101604052809291908181526020018280548015611c9257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611c74575b5050505050905090565b6001600160a01b038281166000908152606760205260409020541615611cf95760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610767565b6001600160a01b03821615801590611d1957506001600160a01b03811615155b611d595760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610767565b6001600160a01b03828116600081815260676020908152604080832080549587166001600160a01b031996871681179091556068805460018101825594527fa2153420d844928b4421650203c77babc8b33d7f2e7b450e2966db0c2209775390930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b6040516001600160a01b038316602482015260448101829052611e5e90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612a1c565b505050565b60007f000000000000000000000000000000000000000000000000000000000000000663ffffffff168463ffffffff1614611ed85760405162461bcd60e51b81526020600482015260156024820152742ab735b737bbb71029b7bab931b2902237b6b0b4b760591b6044820152606401610767565b827f000000000000000000000000b1d624fc40824683e2bfbefd19eb208dbbe008666001600160a01b0390811690821614611f465760405162461bcd60e51b815260206004820152600e60248201526d2ab735b737bbb71029b2b73232b960911b6044820152606401610767565b611f4f83612aee565b60019150505b9392505050565b611f65836129c1565b611f6e826126cf565b611f7781612064565b5050600080525060346020527f2dc2afdad33a5feea586a9545052327b65d28efb10d11fa69e77da986a1031cd805460ff19166001179055565b8251611fc490606c9060208601906138b2565b5081518151811461200e5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610767565b60005b8181101561205d5761205584828151811061202e5761202e613eb2565b602002602001015184838151811061204857612048613eb2565b6020026020010151611c9c565b600101612011565b5050505050565b610bb88161ffff1611156120b15760405162461bcd60e51b815260206004820152601460248201527308ccaca40e0e4cadad2eada40e8dede40d0d2ced60631b6044820152606401610767565b6033805463ffff000019166201000061ffff8416908102919091179091556040519081527f938c72cb9ba014c7d4d26f156021299f8926dee2aab1421b32a2408a8261cf60906020015b60405180910390a150565b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316826001600160a01b0316146121575760405162461bcd60e51b815260040161076790613e5b565b60d054156121a75760405162461bcd60e51b815260206004820152601960248201527f556e65787065637465642070656e64696e6720616d6f756e74000000000000006044820152606401610767565b620f42408110156121fa5760405162461bcd60e51b815260206004820152601860248201527f4465706f73697420616d6f756e7420746f6f20736d616c6c00000000000000006044820152606401610767565b6509184e72a0008111156122505760405162461bcd60e51b815260206004820152601760248201527f4465706f73697420616d6f756e7420746f6f20686967680000000000000000006044820152606401610767565b600061225a612b4c565b60d08390559050600061226d8284612c2b565b90506122798382612c87565b604080516001600160a01b03861680825260208201869052917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f6291015b60405180910390a250505050565b600080808060606122d5868361231a565b94506122e286600461231a565b93506122ef86602c612339565b92506122fc86604c612339565b865190925061230f908790609490612353565b905091939590929450565b6000611f55612334848461232f600482613e9f565b612353565b612f13565b6000611f5561234e848461232f602082613e9f565b612f49565b60608282101561239b5760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420736c6963652072616e676560681b6044820152606401610767565b83518211156123ec5760405162461bcd60e51b815260206004820152601d60248201527f536c69636520656e6420657863656564732064617461206c656e6774680000006044820152606401610767565b60006123f88484613e48565b90506000816001600160401b03811115612414576124146139cc565b6040519080825280601f01601f19166020018201604052801561243e576020820181803683370190505b50905060005b828110156124a357866124578288613e9f565b8151811061246757612467613eb2565b602001015160f81c60f81b82828151811061248457612484613eb2565b60200101906001600160f81b031916908160001a905350600101612444565b5095945050505050565b6000611f556124c2848461232f602082613e9f565b612f80565b603354600160201b90046001600160401b031660008181526034602052604090205460ff16156125335760405162461bcd60e51b8152602060048201526017602482015276139bdb98d948185b1c9958591e481c1c9bd8d95cdcd959604a1b6044820152606401610767565b61253c82612aee565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a0823190602401602060405180830381865afa1580156125a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125c79190613e86565b9050848110156126105760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606401610767565b6126646001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48167f000000000000000000000000e75d77b1865ae93c7eaa3040b038d7aa7bc02f7083611dfb565b604080516001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb481680825260208201849052917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a25050505050565b8061ffff166103e814806126e857508061ffff166107d0145b6127285760405162461bcd60e51b8152602060048201526011602482015270125b9d985b1a59081d1a1c995cda1bdb19607a1b6044820152606401610767565b6033805461ffff191661ffff83169081179091556040519081527fe8fbd074d54232549e55ac463e02d202c16b1023e5d6aae276b3d8391b8c14bc906020016120fb565b6001600160a01b0381166127c25760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610767565b610a5f81612fb7565b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316826001600160a01b03161461281c5760405162461bcd60e51b815260040161076790613e5b565b620f424081101561286f5760405162461bcd60e51b815260206004820152601960248201527f576974686472617720616d6f756e7420746f6f20736d616c6c000000000000006044820152606401610767565b60cf548111156128d95760405162461bcd60e51b815260206004820152602f60248201527f576974686472617720616d6f756e7420657863656564732072656d6f7465207360448201526e747261746567792062616c616e636560881b6064820152608401610767565b6509184e72a0008111156129435760405162461bcd60e51b815260206004820152602b60248201527f576974686472617720616d6f756e742065786365656473206d6178207472616e60448201526a1cd9995c88185b5bdd5b9d60aa1b6064820152608401610767565b600061294d612b4c565b9050600061295b828461301e565b905061296681613048565b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b03167ff7774b688d56120b783560a913ee60792a73dfd511812b7be5eccf10d08c6689846040516122b691815260200190565b603380546bffffffffffffffffffffffff16600160601b6001600160a01b038416908102919091179091556040519081527f4721129e0e676ed6a92909bb24e853ccdd63ad72280cc2e974e38e480e0e6e54906020016120fb565b6000612a71826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166131969092919063ffffffff16565b805190915015611e5e5780806020019051810190612a8f9190613e17565b611e5e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610767565b6003612af9826131ad565b63ffffffff1603612b0d57610a5f816131ba565b60405162461bcd60e51b8152602060048201526014602482015273556e6b6e6f776e206d657373616765207479706560601b6044820152606401610767565b603354600160201b90046001600160401b031660008181526034602052604081205490919060ff16612bb95760405162461bcd60e51b81526020600482015260166024820152752832b73234b733903a37b5b2b7103a3930b739b332b960511b6044820152606401610767565b612bc4816001613f79565b603380546bffffffffffffffff000000001916600160201b6001600160401b038416908102919091179091556040519081529091507fc328b88555c22b57c1f2678e88ad3d9982d056ca6b05be82546e7b6bc6fda2db9060200160405180910390a1919050565b604080516001600160401b03841660208201529081018290526060906103f29060019083015b60408051601f1981840301815290829052612c70939291602001613f98565b604051602081830303815290604052905092915050565b6509184e72a000821115612cd55760405162461bcd60e51b81526020600482015260156024820152740a8ded6cadc40c2dadeeadce840e8dede40d0d2ced605b1b6044820152606401610767565b612d296001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48167f00000000000000000000000028b5a0e9c621a5badaa536219b3a228c8168cf5d84613328565b60335460009062010000900461ffff16612d44576000612d69565b60335461271090612d5f9062010000900461ffff1685613fdd565b612d699190613ff4565b60335460405163779b432d60e01b81529192506001600160a01b037f00000000000000000000000028b5a0e9c621a5badaa536219b3a228c8168cf5d81169263779b432d92612e329288927f0000000000000000000000000000000000000000000000000000000000000006927f000000000000000000000000b1d624fc40824683e2bfbefd19eb208dbbe00866909216917f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb489183918a9161ffff909116908c90600401614016565b600060405180830381600087803b158015612e4c57600080fd5b505af1158015612e60573d6000803e3d6000fd5b50506033546040517f149007d4a77eb98d041de59e6ca469bd27b351b74f16c4d0648978322a1b8a779350612f0692507f0000000000000000000000000000000000000000000000000000000000000006917f000000000000000000000000b1d624fc40824683e2bfbefd19eb208dbbe00866917f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48918991889161ffff16908a90614077565b60405180910390a1505050565b60008151600414612f365760405162461bcd60e51b8152600401610767906140d2565b60e0612f41836140ff565b901c92915050565b60008151602014612f6c5760405162461bcd60e51b8152600401610767906140d2565b818060200190518101906112589190614126565b60008151602014612fa35760405162461bcd60e51b8152600401610767906140d2565b818060200190518101906112589190613e86565b806001600160a01b0316612fd76000805160206142538339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a360008051602061425383398151915255565b604080516001600160401b03841660208201529081018290526060906103f2906002908301612c51565b6033546040516314b157ab60e01b81526001600160a01b037f00000000000000000000000081d40f21f12a8f0e3252bccb954d722d4c464b648116926314b157ab926130e6927f0000000000000000000000000000000000000000000000000000000000000006927f000000000000000000000000b1d624fc40824683e2bfbefd19eb208dbbe0086690911691829161ffff16908890600401614143565b600060405180830381600087803b15801561310057600080fd5b505af1158015613114573d6000803e3d6000fd5b50506033546040517f90d92e80437532a834bc16642d235a7c34efc4d5690f3f6e69794c6d8c5c729093506120fb92507f0000000000000000000000000000000000000000000000000000000000000006917f000000000000000000000000b1d624fc40824683e2bfbefd19eb208dbbe008669161ffff90911690869061417a565b60606131a5848460008561343d565b949350505050565b600061125882600461231a565b6000806000806131c985613565565b603354939750919550935091506001600160401b03600160201b909104811690851681146131f957505050505050565b603354600160201b90046001600160401b031660009081526034602052604090205460ff1615801561329557831561323e57613234866135ab565b600060d0556132f3565b604080516001600160401b0388168152602081018590526000918101919091527fb9bc68243850860710a5d53a1a72d81fc5caf0cf30620ed544cc098bd07dbd51906060015b60405180910390a150505050505050565b6132a26201518084613e9f565b4211156132f357604080516001600160401b0388168152602081018590526001918101919091527fb9bc68243850860710a5d53a1a72d81fc5caf0cf30620ed544cc098bd07dbd5190606001613284565b60cf8590556040518581527f1cc993845fe77d504bd0e3391d651586e84db1cefbcdd9b4f85e8ed1c1f13c1090602001613284565b8015806133a25750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa15801561337c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133a09190613e86565b155b61340d5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610767565b6040516001600160a01b038316602482015260448101829052611e5e90849063095ea7b360e01b90606401611e27565b60608247101561349e5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610767565b843b6134ec5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610767565b600080866001600160a01b0316858760405161350891906141bc565b60006040518083038185875af1925050503d8060008114613545576040519150601f19603f3d011682016040523d82523d6000602084013e61354a565b606091505b509150915061355a828286613738565b979650505050505050565b600080600080613576856003613771565b6000806000806135858961382a565b80602001905181019061359891906141d8565b929c919b50995090975095505050505050565b6033546001600160401b03600160201b90910481169082168111156136025760405162461bcd60e51b815260206004820152600d60248201526c4e6f6e636520746f6f206c6f7760981b6044820152606401610767565b6001600160401b03821660009081526034602052604090205460ff16156136655760405162461bcd60e51b8152602060048201526017602482015276139bdb98d948185b1c9958591e481c1c9bd8d95cdcd959604a1b6044820152606401610767565b6001600160401b038216600081815260346020908152604091829020805460ff1916600117905590519182527f8aa30b3e46076ef0187550969c01982aeb9af5db2eada56ab253a53e4c9946e9910160405180910390a1806001600160401b0316826001600160401b03161461077a57603380546bffffffffffffffff000000001916600160201b6001600160401b038516908102919091179091556040519081527fc328b88555c22b57c1f2678e88ad3d9982d056ca6b05be82546e7b6bc6fda2db9060200160405180910390a15050565b60608315613747575081611f55565b8251156137575782518084602001fd5b8160405162461bcd60e51b8152600401610767919061421f565b6103f261377d83613843565b63ffffffff16146137d05760405162461bcd60e51b815260206004820152601e60248201527f496e76616c6964204f726967696e204d6573736167652056657273696f6e00006044820152606401610767565b8063ffffffff166137e0836131ad565b63ffffffff161461077a5760405162461bcd60e51b8152602060048201526014602482015273496e76616c6964204d657373616765207479706560601b6044820152606401610767565b606061125860088351846123539092919063ffffffff16565b6000611258828261231a565b8280548282559060005260206000209081019282156138a2579160200282015b828111156138a25781546001600160a01b0319166001600160a01b0384351617825560209092019160019091019061386f565b506138ae929150613907565b5090565b8280548282559060005260206000209081019282156138a2579160200282015b828111156138a257825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906138d2565b5b808211156138ae5760008155600101613908565b6001600160a01b0381168114610a5f57600080fd5b6000806040838503121561394457600080fd5b823561394f8161391c565b9150602083013561395f8161391c565b809150509250929050565b60006020828403121561397c57600080fd5b8135611f558161391c565b6000806040838503121561399a57600080fd5b82356139a58161391c565b946020939093013593505050565b803563ffffffff811681146139c757600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126139f357600080fd5b81356001600160401b03811115613a0c57613a0c6139cc565b604051601f8201601f19908116603f011681016001600160401b0381118282101715613a3a57613a3a6139cc565b604052818152838201602001851015613a5257600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613a8557600080fd5b613a8e856139b3565b935060208501359250613aa3604086016139b3565b915060608501356001600160401b03811115613abe57600080fd5b613aca878288016139e2565b91505092959194509250565b803561ffff811681146139c757600080fd5b600080600060608486031215613afd57600080fd5b8335613b088161391c565b9250613b1660208501613ad6565b9150613b2460408501613ad6565b90509250925092565b6001600160401b0381168114610a5f57600080fd5b600060208284031215613b5457600080fd5b8135611f5581613b2d565b600060208284031215613b7157600080fd5b611f5582613ad6565b60008060408385031215613b8d57600080fd5b82356001600160401b03811115613ba357600080fd5b613baf858286016139e2565b92505060208301356001600160401b03811115613bcb57600080fd5b613bd7858286016139e2565b9150509250929050565b600060208284031215613bf357600080fd5b5035919050565b60008060208385031215613c0d57600080fd5b82356001600160401b03811115613c2357600080fd5b8301601f81018513613c3457600080fd5b80356001600160401b03811115613c4a57600080fd5b8560208260051b8401011115613c5f57600080fd5b6020919091019590945092505050565b600080600060608486031215613c8457600080fd5b8335613c8f8161391c565b92506020840135613c9f8161391c565b929592945050506040919091013590565b602080825282518282018190526000918401906040840190835b81811015613cf15783516001600160a01b0316835260209384019390920191600101613cca565b509095945050505050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b60005b83811015613dad578181015183820152602001613d95565b50506000910152565b60008151808452613dce816020860160208601613d92565b601f01601f19169290920160200192915050565b604081526000613df56040830185613db6565b82810360208401526109168185613db6565b805180151581146139c757600080fd5b600060208284031215613e2957600080fd5b611f5582613e07565b634e487b7160e01b600052601160045260246000fd5b8181038181111561125857611258613e32565b602080825260119082015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b604082015260600190565b600060208284031215613e9857600080fd5b5051919050565b8082018082111561125857611258613e32565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b6040808252845490820181905260008581526020812090916060840190835b81811015613f245783546001600160a01b0316835260019384019360209093019201613efd565b50508381036020808601919091528582520190508460005b85811015613f6d578135613f4f8161391c565b6001600160a01b031683526020928301929190910190600101613f3c565b50909695505050505050565b6001600160401b03818116838216019081111561125857611258613e32565b63ffffffff60e01b8460e01b16815263ffffffff60e01b8360e01b16600482015260008251613fce816008850160208701613d92565b91909101600801949350505050565b808202811582820484141761125857611258613e32565b60008261401157634e487b7160e01b600052601260045260246000fd5b500490565b88815263ffffffff8816602082015286604082015260018060a01b03861660608201528460808201528360a082015263ffffffff831660c082015261010060e08201526000614069610100830184613db6565b9a9950505050505050505050565b63ffffffff88811682526001600160a01b038881166020840152871660408301526060820186905260808201859052831660a082015260e060c082018190526000906140c590830184613db6565b9998505050505050505050565b602080825260139082015272092dcecc2d8d2c840c8c2e8c240d8cadccee8d606b1b604082015260600190565b80516020808301519190811015614120576000198160200360031b1b821691505b50919050565b60006020828403121561413857600080fd5b8151611f558161391c565b63ffffffff8616815284602082015283604082015263ffffffff8316606082015260a06080820152600061355a60a0830184613db6565b63ffffffff85811682526001600160a01b0385166020830152831660408201526080606082018190526000906141b290830184613db6565b9695505050505050565b600082516141ce818460208701613d92565b9190910192915050565b600080600080608085870312156141ee57600080fd5b84516141f981613b2d565b6020860151909450925061420f60408601613e07565b6060959095015193969295505050565b602081526000611f556020830184613db656fe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220f9e4003bc05a0917ebba798c964944fadf1dc0e546995b8d06b1544dadc5345b64736f6c634300081c0033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"paris","libraries":{},"metadata":{"bytecodeHash":"ipfs","useLiteralContent":true},"optimizer":{"enabled":true,"runs":200},"outputSelection":{"*":{"":["*"],"*":["*"]}}},"optimization_runs":200,"sourcify_repo_url":null,"decoded_constructor_args":[[["0x0000000000000000000000000000000000000000","0xE75D77B1865Ae93c7eaa3040B038D7aA7BC02F70"],{"components":[{"internalType":"address","name":"platformAddress","type":"address"},{"internalType":"address","name":"vaultAddress","type":"address"}],"internalType":"struct InitializableAbstractStrategy.BaseStrategyConfig","name":"_stratConfig","type":"tuple"}],[["0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d","0x81D40F21F12A8F0E3252Bccb954D722d4c464B64","6","0xB1d624fc40824683e2bFBEfd19eB208DbBE00866","0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48","0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"],{"components":[{"internalType":"address","name":"cctpTokenMessenger","type":"address"},{"internalType":"address","name":"cctpMessageTransmitter","type":"address"},{"internalType":"uint32","name":"peerDomainID","type":"uint32"},{"internalType":"address","name":"peerStrategy","type":"address"},{"internalType":"address","name":"usdcToken","type":"address"},{"internalType":"address","name":"peerUsdcToken","type":"address"}],"internalType":"struct AbstractCCTPIntegrator.CCTPIntegrationConfig","name":"_cctpConfig","type":"tuple"}]],"compiler_version":"v0.8.28+commit.7893614a","is_verified_via_verifier_alliance":false,"verified_at":"2026-02-10T15:49:18.856804Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x61018060405234801561001157600080fd5b50604051614c14380380614c148339810160408190526100309161060d565b6080810151829082906001600160a01b03166100935760405162461bcd60e51b815260206004820152601460248201527f496e76616c69642055534443206164647265737300000000000000000000000060448201526064015b60405180910390fd5b60a08101516001600160a01b03166100ed5760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420706565722055534443206164647265737300000000000000604482015260640161008a565b80516001600160a01b031661013a5760405162461bcd60e51b8152602060048201526013602482015272496e76616c6964204343545020636f6e66696760681b604482015260640161008a565b60208101516001600160a01b031661018a5760405162461bcd60e51b8152602060048201526013602482015272496e76616c6964204343545020636f6e66696760681b604482015260640161008a565b60608101516001600160a01b03166101e45760405162461bcd60e51b815260206004820152601d60248201527f496e76616c696420706565722073747261746567792061646472657373000000604482015260640161008a565b60208101516001600160a01b0390811660809081528251821660a052604083015163ffffffff166101005260608301518216610120528201805190911660c0525160009061023190610410565b9050600061024883608001516104f060201b60201c565b90508160061461029a5760405162461bcd60e51b815260206004820152601d60248201527f4261736520746f6b656e20646563696d616c73206d7573742062652036000000604482015260640161008a565b604051635553444360e01b602082015260240160405160208183030381529060405280519060200120816040516020016102d4919061070e565b60405160208183030381529060405280519060200120146103375760405162461bcd60e51b815260206004820152601960248201527f546f6b656e2073796d626f6c206d757374206265205553444300000000000000604482015260640161008a565b505060a001516001600160a01b0390811660e0528151811661014052602090910151811661016052825116156103af5760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420706c6174666f726d20616464726573730000000000000000604482015260640161008a565b60208201516001600160a01b03166104095760405162461bcd60e51b815260206004820152601560248201527f496e76616c6964205661756c7420616464726573730000000000000000000000604482015260640161008a565b50506107e1565b600080826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610451573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610475919061072a565b60ff1690506004811015801561048c575060128111155b6104ea5760405162461bcd60e51b815260206004820152602960248201527f546f6b656e206d75737420686176652073756666696369656e7420646563696d604482015268616c20706c6163657360b81b606482015260840161008a565b92915050565b60606000826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610532573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261055a919081019061074d565b9392505050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b038111828210171561059957610599610561565b60405290565b60405160c081016001600160401b038111828210171561059957610599610561565b604051601f8201601f191681016001600160401b03811182821017156105e9576105e9610561565b604052919050565b80516001600160a01b038116811461060857600080fd5b919050565b60008082840361010081121561062257600080fd5b604081121561063057600080fd5b610638610577565b610641856105f1565b815261064f602086016105f1565b6020820152925060c0603f198201121561066857600080fd5b5061067161059f565b61067d604085016105f1565b815261068b606085016105f1565b6020820152608084015163ffffffff811681146106a757600080fd5b60408201526106b860a085016105f1565b60608201526106c960c085016105f1565b60808201526106da60e085016105f1565b60a0820152809150509250929050565b60005b838110156107055781810151838201526020016106ed565b50506000910152565b600082516107208184602087016106ea565b9190910192915050565b60006020828403121561073c57600080fd5b815160ff8116811461055a57600080fd5b60006020828403121561075f57600080fd5b81516001600160401b0381111561077557600080fd5b8201601f8101841361078657600080fd5b80516001600160401b0381111561079f5761079f610561565b6107b2601f8201601f19166020016105c1565b8181528560208385010111156107c757600080fd5b6107d88260208301602086016106ea565b95945050505050565b60805160a05160c05160e051610100516101205161014051610160516142a861096c6000396000818161040a01528181610a6d015281816113cb015281816119f301528181611a6801528181611b06015261263f015260006106d10152600081816104bb01528181610e3b01528181611edb01528181612dd801528181612eb4015281816130b2015261316801526000818161054a01528181610bcd01528181611e6701528181612db601528181612e9201528181613090015261314601526000818161051b0152610cf601526000818161032d01528181610605015281816107ac01528181611167015281816111d10152818161150d01528181611b9101528181611c1501528181612108015281816125540152818161261d01528181612672015281816127cd0152818161296801528181612ce201528181612dfd0152612ed60152600081816105d301528181610c4f01528181612d040152612d860152600081816105860152818161084601528181610edf01528181611295015261306201526142a86000f3fe608060405234801561001057600080fd5b506004361061028a5760003560e01c80637b2d9b2c1161015c578063b3ab15fb116100ce578063d9caed1211610087578063d9caed12146106b9578063dbe55e56146106cc578063de5f6268146106f3578063ed42412b146106fb578063f6ca71b014610704578063fc1b31131461071957600080fd5b8063b3ab15fb1461063d578063ba1066ed14610650578063c2e1e3f414610659578063c7af33521461066c578063d38bfff414610674578063d7dd614b1461068757600080fd5b80638c73eb04116101205780638c73eb04146105815780639136616a146105a857806396d538bb146105bb5780639748cf7c146105ce578063aa388af6146105f5578063ad1728cb1461063557600080fd5b80637b2d9b2c146104f05780637c92f219146105035780637ddfce2d14610516578063853828b61461053d5780638949f6f31461054557600080fd5b806342c8c11c116102005780635a063f63116101b95780635a063f63146104805780635a236417146104885780635d36b1901461049b5780635f515226146104a35780636369e49f146104b657806367c7066c146104dd57600080fd5b806342c8c11c146103f2578063430bf08a1461040557806347e7ef241461042c5780635324df321461043f578063564a515814610453578063570ca7351461046657600080fd5b806311eac8551161025257806311eac8551461032857806316a0f2501461034f5780631801c408146103705780631c4b995a1461039b57806323c9ab3d146103ae5780633c3dbbc7146103da57600080fd5b80630c340a241461028f5780630ed57b3a146102b45780630fc3b4c4146102c95780631072cbea146102f257806311cffb6714610305575b600080fd5b610297610726565b6040516001600160a01b0390911681526020015b60405180910390f35b6102c76102c2366004613931565b610743565b005b6102976102d736600461396a565b6067602052600090815260409020546001600160a01b031681565b6102c7610300366004613987565b61077e565b610318610313366004613a6f565b610839565b60405190151581526020016102ab565b6102977f000000000000000000000000000000000000000000000000000000000000000081565b60335461035d9061ffff1681565b60405161ffff90911681526020016102ab565b603354600160201b90046001600160401b031660009081526034602052604090205460ff1615610318565b6102c76103a9366004613ae8565b61091f565b6103186103bc366004613b42565b6001600160401b031660009081526034602052604090205460ff1690565b6103e4620f424081565b6040519081526020016102ab565b6102c7610400366004613b5f565b610a32565b6102977f000000000000000000000000000000000000000000000000000000000000000081565b6102c761043a366004613987565b610a62565b60335461035d9062010000900461ffff1681565b6102c7610461366004613b7a565b610af3565b60335461029790600160601b90046001600160a01b031681565b6102c7610ffd565b6102c7610496366004613b5f565b611090565b6102c76110bd565b6103e46104b136600461396a565b611163565b6102977f000000000000000000000000000000000000000000000000000000000000000081565b606b54610297906001600160a01b031681565b6102976104fe366004613be1565b61125e565b610318610511366004613a6f565b611288565b6102977f000000000000000000000000000000000000000000000000000000000000000081565b6102c76113c0565b61056c7f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016102ab565b6102977f000000000000000000000000000000000000000000000000000000000000000081565b6102c76105b6366004613be1565b611553565b6102c76105c9366004613bfa565b61171e565b6102977f000000000000000000000000000000000000000000000000000000000000000081565b61031861060336600461396a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b6102c7611835565b6102c761064b36600461396a565b611859565b6103e460d05481565b6102c761066736600461396a565b611886565b610318611913565b6102c761068236600461396a565b611944565b6033546106a190600160201b90046001600160401b031681565b6040516001600160401b0390911681526020016102ab565b6102c76106c7366004613c6f565b6119e8565b6102977f000000000000000000000000000000000000000000000000000000000000000081565b6102c7611afb565b6103e460cf5481565b61070c611c3a565b6040516102ab9190613cb0565b6103e46509184e72a00081565b600061073e6000805160206142538339815191525490565b905090565b61074b611913565b6107705760405162461bcd60e51b815260040161076790613cfc565b60405180910390fd5b61077a8282611c9c565b5050565b610786611913565b6107a25760405162461bcd60e51b815260040161076790613cfc565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169083160361081d5760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610767565b61077a610828610726565b6001600160a01b0384169083611dfb565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146108b35760405162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206973206e6f742043435450207472616e736d697474657200006044820152606401610767565b6107d08363ffffffff16101561090b5760405162461bcd60e51b815260206004820152601a60248201527f46696e616c697479207468726573686f6c6420746f6f206c6f770000000000006044820152606401610767565b610916858584611e63565b95945050505050565b610927611913565b6109435760405162461bcd60e51b815260040161076790613cfc565b600054610100900460ff168061095c575060005460ff16155b6109bf5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610767565b600054610100900460ff161580156109e1576000805461ffff19166101011790555b6109ec848484611f5c565b6040805160008082526020820181815282840191825260608301909352909190610a17838383611fb1565b5050508015610a2c576000805461ff00191690555b50505050565b610a3a611913565b610a565760405162461bcd60e51b815260040161076790613cfc565b610a5f81612064565b50565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610aaa5760405162461bcd60e51b815260040161076790613d33565b60008051602061423383398151915280546001198101610adc5760405162461bcd60e51b815260040161076790613d6a565b60028255610aea8484612106565b50600190555050565b603354600160601b90046001600160a01b03163314610b545760405162461bcd60e51b815260206004820152601a60248201527f43616c6c6572206973206e6f7420746865204f70657261746f720000000000006044820152606401610767565b6000806000806000610b65876122c4565b94509450945094509450600163ffffffff168563ffffffff1614610bcb5760405162461bcd60e51b815260206004820152601c60248201527f496e76616c69642043435450206d6573736167652076657273696f6e000000006044820152606401610767565b7f000000000000000000000000000000000000000000000000000000000000000063ffffffff168463ffffffff1614610c3e5760405162461bcd60e51b81526020600482015260156024820152742ab735b737bbb71029b7bab931b2902237b6b0b4b760591b6044820152606401610767565b610c4981600061231a565b945060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b03161490508015610d8a578563ffffffff166001148015610ca25750815160e411155b610ce55760405162461bcd60e51b8152602060048201526014602482015273496e76616c6964206275726e206d65737361676560601b6044820152606401610767565b6000610cf2836004612339565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031614610d6a5760405162461bcd60e51b815260206004820152601260248201527124b73b30b634b210313ab937103a37b5b2b760711b6044820152606401610767565b610d75836064612339565b9450610d82836024612339565b935050610de1565b63ffffffff86166103f214610de15760405162461bcd60e51b815260206004820152601b60248201527f556e737570706f72746564206d6573736167652076657273696f6e00000000006044820152606401610767565b306001600160a01b03841614610e395760405162461bcd60e51b815260206004820152601c60248201527f556e657870656374656420726563697069656e742061646472657373000000006044820152606401610767565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614610ec55760405162461bcd60e51b815260206004820152602260248201527f496e636f72726563742073656e6465722f726563697069656e74206164647265604482015261737360f01b6064820152608401610767565b604051630afd9fa560e31b81526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906357ecfd2890610f16908c908c90600401613de2565b6020604051808303816000875af1158015610f35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f599190613e17565b905080610fa15760405162461bcd60e51b8152602060048201526016602482015275149958d95a5d99481b595cdcd859d94819985a5b195960521b6044820152606401610767565b8115610ff2578251600090610fba90859060e490612353565b90506000610fc98560446124ad565b90506000610fd88660a46124ad565b9050610fee610fe78284613e48565b82856124c7565b5050505b505050505050505050565b606b546001600160a01b031633146110575760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610767565b600080516020614233833981519152805460011981016110895760405162461bcd60e51b815260040161076790613d6a565b5060019055565b611098611913565b6110b45760405162461bcd60e51b815260040161076790613cfc565b610a5f816126cf565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b0316146111585760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610767565b6111613361276c565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316146111b65760405162461bcd60e51b815260040161076790613e5b565b60cf5460d0546040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611220573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112449190613e86565b61124e9190613e9f565b6112589190613e9f565b92915050565b606c818154811061126e57600080fd5b6000918252602090912001546001600160a01b0316905081565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146113025760405162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206973206e6f742043435450207472616e736d697474657200006044820152606401610767565b60335461ffff166103e8146113685760405162461bcd60e51b815260206004820152602660248201527f556e66696e616c697a6564206d6573736167657320617265206e6f74207375706044820152651c1bdc9d195960d21b6064820152608401610767565b6103e88363ffffffff16101561090b5760405162461bcd60e51b815260206004820152601a60248201527f46696e616c697479207468726573686f6c6420746f6f206c6f770000000000006044820152606401610767565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061140f57506113fa610726565b6001600160a01b0316336001600160a01b0316145b6114675760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610767565b600080516020614233833981519152805460011981016114995760405162461bcd60e51b815260040161076790613d6a565b60028255603354600160201b90046001600160401b031660009081526034602052604090205460ff166114f4576040517ff49d67e0c10520c98c98114270c479ce28ba2e7bef7908bb15914eb5a3b6165190600090a1611089565b60cf54620f42408110156115085750611089565b61154b7f00000000000000000000000000000000000000000000000000000000000000006509184e72a000831161153f57826127cb565b6509184e72a0006127cb565b505060019055565b61155b611913565b6115775760405162461bcd60e51b815260040161076790613cfc565b60685481106115b85760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610767565b6000606882815481106115cd576115cd613eb2565b60009182526020808320909101546001600160a01b0390811680845260679092526040909220546068549193509091169061160a90600190613e48565b83101561168c576068805461162190600190613e48565b8154811061163157611631613eb2565b600091825260209091200154606880546001600160a01b03909216918590811061165d5761165d613eb2565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b606880548061169d5761169d613ec8565b60008281526020808220600019908401810180546001600160a01b031990811690915593019093556001600160a01b038581168083526067855260409283902080549094169093559051908416815290917f16b7600acff27e39a8a96056b3d533045298de927507f5c1d97e4accde60488c910160405180910390a2505050565b611726611913565b6117425760405162461bcd60e51b815260040161076790613cfc565b8060005b818110156117ec57600084848381811061176257611762613eb2565b9050602002016020810190611777919061396a565b6001600160a01b0316036117e45760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610767565b600101611746565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc606c848460405161182193929190613ede565b60405180910390a1610a2c606c848461384f565b61183d611913565b6110575760405162461bcd60e51b815260040161076790613cfc565b611861611913565b61187d5760405162461bcd60e51b815260040161076790613cfc565b610a5f816129c1565b61188e611913565b6118aa5760405162461bcd60e51b815260040161076790613cfc565b606b54604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a1606b80546001600160a01b0319166001600160a01b0392909216919091179055565b600061192b6000805160206142538339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61194c611913565b6119685760405162461bcd60e51b815260040161076790613cfc565b611990817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166119b06000805160206142538339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611a305760405162461bcd60e51b815260040161076790613d33565b60008051602061423383398151915280546001198101611a625760405162461bcd60e51b815260040161076790613d6a565b600282557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b031614611ae75760405162461bcd60e51b815260206004820152601760248201527f4f6e6c79205661756c742063616e2077697468647261770000000000000000006044820152606401610767565b611af184846127cb565b5060019055505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611b435760405162461bcd60e51b815260040161076790613d33565b60008051602061423383398151915280546001198101611b755760405162461bcd60e51b815260040161076790613d6a565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611be0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c049190613e86565b9050620f4240811061154b5761154b7f000000000000000000000000000000000000000000000000000000000000000082612106565b6060606c805480602002602001604051908101604052809291908181526020018280548015611c9257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611c74575b5050505050905090565b6001600160a01b038281166000908152606760205260409020541615611cf95760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610767565b6001600160a01b03821615801590611d1957506001600160a01b03811615155b611d595760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610767565b6001600160a01b03828116600081815260676020908152604080832080549587166001600160a01b031996871681179091556068805460018101825594527fa2153420d844928b4421650203c77babc8b33d7f2e7b450e2966db0c2209775390930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a25050565b6040516001600160a01b038316602482015260448101829052611e5e90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612a1c565b505050565b60007f000000000000000000000000000000000000000000000000000000000000000063ffffffff168463ffffffff1614611ed85760405162461bcd60e51b81526020600482015260156024820152742ab735b737bbb71029b7bab931b2902237b6b0b4b760591b6044820152606401610767565b827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811690821614611f465760405162461bcd60e51b815260206004820152600e60248201526d2ab735b737bbb71029b2b73232b960911b6044820152606401610767565b611f4f83612aee565b60019150505b9392505050565b611f65836129c1565b611f6e826126cf565b611f7781612064565b5050600080525060346020527f2dc2afdad33a5feea586a9545052327b65d28efb10d11fa69e77da986a1031cd805460ff19166001179055565b8251611fc490606c9060208601906138b2565b5081518151811461200e5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610767565b60005b8181101561205d5761205584828151811061202e5761202e613eb2565b602002602001015184838151811061204857612048613eb2565b6020026020010151611c9c565b600101612011565b5050505050565b610bb88161ffff1611156120b15760405162461bcd60e51b815260206004820152601460248201527308ccaca40e0e4cadad2eada40e8dede40d0d2ced60631b6044820152606401610767565b6033805463ffff000019166201000061ffff8416908102919091179091556040519081527f938c72cb9ba014c7d4d26f156021299f8926dee2aab1421b32a2408a8261cf60906020015b60405180910390a150565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316146121575760405162461bcd60e51b815260040161076790613e5b565b60d054156121a75760405162461bcd60e51b815260206004820152601960248201527f556e65787065637465642070656e64696e6720616d6f756e74000000000000006044820152606401610767565b620f42408110156121fa5760405162461bcd60e51b815260206004820152601860248201527f4465706f73697420616d6f756e7420746f6f20736d616c6c00000000000000006044820152606401610767565b6509184e72a0008111156122505760405162461bcd60e51b815260206004820152601760248201527f4465706f73697420616d6f756e7420746f6f20686967680000000000000000006044820152606401610767565b600061225a612b4c565b60d08390559050600061226d8284612c2b565b90506122798382612c87565b604080516001600160a01b03861680825260208201869052917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f6291015b60405180910390a250505050565b600080808060606122d5868361231a565b94506122e286600461231a565b93506122ef86602c612339565b92506122fc86604c612339565b865190925061230f908790609490612353565b905091939590929450565b6000611f55612334848461232f600482613e9f565b612353565b612f13565b6000611f5561234e848461232f602082613e9f565b612f49565b60608282101561239b5760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420736c6963652072616e676560681b6044820152606401610767565b83518211156123ec5760405162461bcd60e51b815260206004820152601d60248201527f536c69636520656e6420657863656564732064617461206c656e6774680000006044820152606401610767565b60006123f88484613e48565b90506000816001600160401b03811115612414576124146139cc565b6040519080825280601f01601f19166020018201604052801561243e576020820181803683370190505b50905060005b828110156124a357866124578288613e9f565b8151811061246757612467613eb2565b602001015160f81c60f81b82828151811061248457612484613eb2565b60200101906001600160f81b031916908160001a905350600101612444565b5095945050505050565b6000611f556124c2848461232f602082613e9f565b612f80565b603354600160201b90046001600160401b031660008181526034602052604090205460ff16156125335760405162461bcd60e51b8152602060048201526017602482015276139bdb98d948185b1c9958591e481c1c9bd8d95cdcd959604a1b6044820152606401610767565b61253c82612aee565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156125a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125c79190613e86565b9050848110156126105760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606401610767565b6126646001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f000000000000000000000000000000000000000000000000000000000000000083611dfb565b604080516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001680825260208201849052917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a25050505050565b8061ffff166103e814806126e857508061ffff166107d0145b6127285760405162461bcd60e51b8152602060048201526011602482015270125b9d985b1a59081d1a1c995cda1bdb19607a1b6044820152606401610767565b6033805461ffff191661ffff83169081179091556040519081527fe8fbd074d54232549e55ac463e02d202c16b1023e5d6aae276b3d8391b8c14bc906020016120fb565b6001600160a01b0381166127c25760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610767565b610a5f81612fb7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161461281c5760405162461bcd60e51b815260040161076790613e5b565b620f424081101561286f5760405162461bcd60e51b815260206004820152601960248201527f576974686472617720616d6f756e7420746f6f20736d616c6c000000000000006044820152606401610767565b60cf548111156128d95760405162461bcd60e51b815260206004820152602f60248201527f576974686472617720616d6f756e7420657863656564732072656d6f7465207360448201526e747261746567792062616c616e636560881b6064820152608401610767565b6509184e72a0008111156129435760405162461bcd60e51b815260206004820152602b60248201527f576974686472617720616d6f756e742065786365656473206d6178207472616e60448201526a1cd9995c88185b5bdd5b9d60aa1b6064820152608401610767565b600061294d612b4c565b9050600061295b828461301e565b905061296681613048565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167ff7774b688d56120b783560a913ee60792a73dfd511812b7be5eccf10d08c6689846040516122b691815260200190565b603380546bffffffffffffffffffffffff16600160601b6001600160a01b038416908102919091179091556040519081527f4721129e0e676ed6a92909bb24e853ccdd63ad72280cc2e974e38e480e0e6e54906020016120fb565b6000612a71826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166131969092919063ffffffff16565b805190915015611e5e5780806020019051810190612a8f9190613e17565b611e5e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610767565b6003612af9826131ad565b63ffffffff1603612b0d57610a5f816131ba565b60405162461bcd60e51b8152602060048201526014602482015273556e6b6e6f776e206d657373616765207479706560601b6044820152606401610767565b603354600160201b90046001600160401b031660008181526034602052604081205490919060ff16612bb95760405162461bcd60e51b81526020600482015260166024820152752832b73234b733903a37b5b2b7103a3930b739b332b960511b6044820152606401610767565b612bc4816001613f79565b603380546bffffffffffffffff000000001916600160201b6001600160401b038416908102919091179091556040519081529091507fc328b88555c22b57c1f2678e88ad3d9982d056ca6b05be82546e7b6bc6fda2db9060200160405180910390a1919050565b604080516001600160401b03841660208201529081018290526060906103f29060019083015b60408051601f1981840301815290829052612c70939291602001613f98565b604051602081830303815290604052905092915050565b6509184e72a000821115612cd55760405162461bcd60e51b81526020600482015260156024820152740a8ded6cadc40c2dadeeadce840e8dede40d0d2ced605b1b6044820152606401610767565b612d296001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f000000000000000000000000000000000000000000000000000000000000000084613328565b60335460009062010000900461ffff16612d44576000612d69565b60335461271090612d5f9062010000900461ffff1685613fdd565b612d699190613ff4565b60335460405163779b432d60e01b81529192506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169263779b432d92612e329288927f0000000000000000000000000000000000000000000000000000000000000000927f0000000000000000000000000000000000000000000000000000000000000000909216917f00000000000000000000000000000000000000000000000000000000000000009183918a9161ffff909116908c90600401614016565b600060405180830381600087803b158015612e4c57600080fd5b505af1158015612e60573d6000803e3d6000fd5b50506033546040517f149007d4a77eb98d041de59e6ca469bd27b351b74f16c4d0648978322a1b8a779350612f0692507f0000000000000000000000000000000000000000000000000000000000000000917f0000000000000000000000000000000000000000000000000000000000000000917f0000000000000000000000000000000000000000000000000000000000000000918991889161ffff16908a90614077565b60405180910390a1505050565b60008151600414612f365760405162461bcd60e51b8152600401610767906140d2565b60e0612f41836140ff565b901c92915050565b60008151602014612f6c5760405162461bcd60e51b8152600401610767906140d2565b818060200190518101906112589190614126565b60008151602014612fa35760405162461bcd60e51b8152600401610767906140d2565b818060200190518101906112589190613e86565b806001600160a01b0316612fd76000805160206142538339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a360008051602061425383398151915255565b604080516001600160401b03841660208201529081018290526060906103f2906002908301612c51565b6033546040516314b157ab60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116926314b157ab926130e6927f0000000000000000000000000000000000000000000000000000000000000000927f000000000000000000000000000000000000000000000000000000000000000090911691829161ffff16908890600401614143565b600060405180830381600087803b15801561310057600080fd5b505af1158015613114573d6000803e3d6000fd5b50506033546040517f90d92e80437532a834bc16642d235a7c34efc4d5690f3f6e69794c6d8c5c729093506120fb92507f0000000000000000000000000000000000000000000000000000000000000000917f00000000000000000000000000000000000000000000000000000000000000009161ffff90911690869061417a565b60606131a5848460008561343d565b949350505050565b600061125882600461231a565b6000806000806131c985613565565b603354939750919550935091506001600160401b03600160201b909104811690851681146131f957505050505050565b603354600160201b90046001600160401b031660009081526034602052604090205460ff1615801561329557831561323e57613234866135ab565b600060d0556132f3565b604080516001600160401b0388168152602081018590526000918101919091527fb9bc68243850860710a5d53a1a72d81fc5caf0cf30620ed544cc098bd07dbd51906060015b60405180910390a150505050505050565b6132a26201518084613e9f565b4211156132f357604080516001600160401b0388168152602081018590526001918101919091527fb9bc68243850860710a5d53a1a72d81fc5caf0cf30620ed544cc098bd07dbd5190606001613284565b60cf8590556040518581527f1cc993845fe77d504bd0e3391d651586e84db1cefbcdd9b4f85e8ed1c1f13c1090602001613284565b8015806133a25750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa15801561337c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133a09190613e86565b155b61340d5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610767565b6040516001600160a01b038316602482015260448101829052611e5e90849063095ea7b360e01b90606401611e27565b60608247101561349e5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610767565b843b6134ec5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610767565b600080866001600160a01b0316858760405161350891906141bc565b60006040518083038185875af1925050503d8060008114613545576040519150601f19603f3d011682016040523d82523d6000602084013e61354a565b606091505b509150915061355a828286613738565b979650505050505050565b600080600080613576856003613771565b6000806000806135858961382a565b80602001905181019061359891906141d8565b929c919b50995090975095505050505050565b6033546001600160401b03600160201b90910481169082168111156136025760405162461bcd60e51b815260206004820152600d60248201526c4e6f6e636520746f6f206c6f7760981b6044820152606401610767565b6001600160401b03821660009081526034602052604090205460ff16156136655760405162461bcd60e51b8152602060048201526017602482015276139bdb98d948185b1c9958591e481c1c9bd8d95cdcd959604a1b6044820152606401610767565b6001600160401b038216600081815260346020908152604091829020805460ff1916600117905590519182527f8aa30b3e46076ef0187550969c01982aeb9af5db2eada56ab253a53e4c9946e9910160405180910390a1806001600160401b0316826001600160401b03161461077a57603380546bffffffffffffffff000000001916600160201b6001600160401b038516908102919091179091556040519081527fc328b88555c22b57c1f2678e88ad3d9982d056ca6b05be82546e7b6bc6fda2db9060200160405180910390a15050565b60608315613747575081611f55565b8251156137575782518084602001fd5b8160405162461bcd60e51b8152600401610767919061421f565b6103f261377d83613843565b63ffffffff16146137d05760405162461bcd60e51b815260206004820152601e60248201527f496e76616c6964204f726967696e204d6573736167652056657273696f6e00006044820152606401610767565b8063ffffffff166137e0836131ad565b63ffffffff161461077a5760405162461bcd60e51b8152602060048201526014602482015273496e76616c6964204d657373616765207479706560601b6044820152606401610767565b606061125860088351846123539092919063ffffffff16565b6000611258828261231a565b8280548282559060005260206000209081019282156138a2579160200282015b828111156138a25781546001600160a01b0319166001600160a01b0384351617825560209092019160019091019061386f565b506138ae929150613907565b5090565b8280548282559060005260206000209081019282156138a2579160200282015b828111156138a257825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906138d2565b5b808211156138ae5760008155600101613908565b6001600160a01b0381168114610a5f57600080fd5b6000806040838503121561394457600080fd5b823561394f8161391c565b9150602083013561395f8161391c565b809150509250929050565b60006020828403121561397c57600080fd5b8135611f558161391c565b6000806040838503121561399a57600080fd5b82356139a58161391c565b946020939093013593505050565b803563ffffffff811681146139c757600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126139f357600080fd5b81356001600160401b03811115613a0c57613a0c6139cc565b604051601f8201601f19908116603f011681016001600160401b0381118282101715613a3a57613a3a6139cc565b604052818152838201602001851015613a5257600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613a8557600080fd5b613a8e856139b3565b935060208501359250613aa3604086016139b3565b915060608501356001600160401b03811115613abe57600080fd5b613aca878288016139e2565b91505092959194509250565b803561ffff811681146139c757600080fd5b600080600060608486031215613afd57600080fd5b8335613b088161391c565b9250613b1660208501613ad6565b9150613b2460408501613ad6565b90509250925092565b6001600160401b0381168114610a5f57600080fd5b600060208284031215613b5457600080fd5b8135611f5581613b2d565b600060208284031215613b7157600080fd5b611f5582613ad6565b60008060408385031215613b8d57600080fd5b82356001600160401b03811115613ba357600080fd5b613baf858286016139e2565b92505060208301356001600160401b03811115613bcb57600080fd5b613bd7858286016139e2565b9150509250929050565b600060208284031215613bf357600080fd5b5035919050565b60008060208385031215613c0d57600080fd5b82356001600160401b03811115613c2357600080fd5b8301601f81018513613c3457600080fd5b80356001600160401b03811115613c4a57600080fd5b8560208260051b8401011115613c5f57600080fd5b6020919091019590945092505050565b600080600060608486031215613c8457600080fd5b8335613c8f8161391c565b92506020840135613c9f8161391c565b929592945050506040919091013590565b602080825282518282018190526000918401906040840190835b81811015613cf15783516001600160a01b0316835260209384019390920191600101613cca565b509095945050505050565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b60005b83811015613dad578181015183820152602001613d95565b50506000910152565b60008151808452613dce816020860160208601613d92565b601f01601f19169290920160200192915050565b604081526000613df56040830185613db6565b82810360208401526109168185613db6565b805180151581146139c757600080fd5b600060208284031215613e2957600080fd5b611f5582613e07565b634e487b7160e01b600052601160045260246000fd5b8181038181111561125857611258613e32565b602080825260119082015270155b9cdd5c1c1bdc9d195908185cdcd95d607a1b604082015260600190565b600060208284031215613e9857600080fd5b5051919050565b8082018082111561125857611258613e32565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b6040808252845490820181905260008581526020812090916060840190835b81811015613f245783546001600160a01b0316835260019384019360209093019201613efd565b50508381036020808601919091528582520190508460005b85811015613f6d578135613f4f8161391c565b6001600160a01b031683526020928301929190910190600101613f3c565b50909695505050505050565b6001600160401b03818116838216019081111561125857611258613e32565b63ffffffff60e01b8460e01b16815263ffffffff60e01b8360e01b16600482015260008251613fce816008850160208701613d92565b91909101600801949350505050565b808202811582820484141761125857611258613e32565b60008261401157634e487b7160e01b600052601260045260246000fd5b500490565b88815263ffffffff8816602082015286604082015260018060a01b03861660608201528460808201528360a082015263ffffffff831660c082015261010060e08201526000614069610100830184613db6565b9a9950505050505050505050565b63ffffffff88811682526001600160a01b038881166020840152871660408301526060820186905260808201859052831660a082015260e060c082018190526000906140c590830184613db6565b9998505050505050505050565b602080825260139082015272092dcecc2d8d2c840c8c2e8c240d8cadccee8d606b1b604082015260600190565b80516020808301519190811015614120576000198160200360031b1b821691505b50919050565b60006020828403121561413857600080fd5b8151611f558161391c565b63ffffffff8616815284602082015283604082015263ffffffff8316606082015260a06080820152600061355a60a0830184613db6565b63ffffffff85811682526001600160a01b0385166020830152831660408201526080606082018190526000906141b290830184613db6565b9695505050505050565b600082516141ce818460208701613d92565b9190910192915050565b600080600080608085870312156141ee57600080fd5b84516141f981613b2d565b6020860151909450925061420f60408601613e07565b6060959095015193969295505050565b602081526000611f556020830184613db656fe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220f9e4003bc05a0917ebba798c964944fadf1dc0e546995b8d06b1544dadc5345b64736f6c634300081c00330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e75d77b1865ae93c7eaa3040b038d7aa7bc02f7000000000000000000000000028b5a0e9c621a5badaa536219b3a228c8168cf5d00000000000000000000000081d40f21f12a8f0e3252bccb954d722d4c464b640000000000000000000000000000000000000000000000000000000000000006000000000000000000000000b1d624fc40824683e2bfbefd19eb208dbbe00866000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda02913","name":"CrossChainMasterStrategy","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":false,"language":"solidity","evm_version":"paris","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"@openzeppelin/contracts/token/ERC20/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `recipient`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `sender` to `recipient` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(\n        address sender,\n        address recipient,\n        uint256 amount\n    ) external returns (bool);\n\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"},{"file_path":"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    using Address for address;\n\n    function safeTransfer(\n        IERC20 token,\n        address to,\n        uint256 value\n    ) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    function safeTransferFrom(\n        IERC20 token,\n        address from,\n        address to,\n        uint256 value\n    ) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    /**\n     * @dev Deprecated. This function has issues similar to the ones found in\n     * {IERC20-approve}, and its usage is discouraged.\n     *\n     * Whenever possible, use {safeIncreaseAllowance} and\n     * {safeDecreaseAllowance} instead.\n     */\n    function safeApprove(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n        require(\n            (value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n    }\n\n    function safeIncreaseAllowance(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        uint256 newAllowance = token.allowance(address(this), spender) + value;\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n    }\n\n    function safeDecreaseAllowance(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            uint256 newAllowance = oldAllowance - value;\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n        if (returndata.length > 0) {\n            // Return data is optional\n            require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n        }\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/utils/Address.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize, which returns 0 for contracts in\n        // construction, since the code is only stored at the end of the\n        // constructor execution.\n\n        uint256 size;\n        assembly {\n            size := extcodesize(account)\n        }\n        return size > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length > 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n"},{"file_path":"@openzeppelin/contracts/utils/math/SafeCast.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n *\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\n * all math on `uint256` and `int256` and then downcasting.\n */\nlibrary SafeCast {\n    /**\n     * @dev Returns the downcasted uint224 from uint256, reverting on\n     * overflow (when the input is greater than largest uint224).\n     *\n     * Counterpart to Solidity's `uint224` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 224 bits\n     */\n    function toUint224(uint256 value) internal pure returns (uint224) {\n        require(value <= type(uint224).max, \"SafeCast: value doesn't fit in 224 bits\");\n        return uint224(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint128 from uint256, reverting on\n     * overflow (when the input is greater than largest uint128).\n     *\n     * Counterpart to Solidity's `uint128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     */\n    function toUint128(uint256 value) internal pure returns (uint128) {\n        require(value <= type(uint128).max, \"SafeCast: value doesn't fit in 128 bits\");\n        return uint128(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint96 from uint256, reverting on\n     * overflow (when the input is greater than largest uint96).\n     *\n     * Counterpart to Solidity's `uint96` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 96 bits\n     */\n    function toUint96(uint256 value) internal pure returns (uint96) {\n        require(value <= type(uint96).max, \"SafeCast: value doesn't fit in 96 bits\");\n        return uint96(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint64 from uint256, reverting on\n     * overflow (when the input is greater than largest uint64).\n     *\n     * Counterpart to Solidity's `uint64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     */\n    function toUint64(uint256 value) internal pure returns (uint64) {\n        require(value <= type(uint64).max, \"SafeCast: value doesn't fit in 64 bits\");\n        return uint64(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint32 from uint256, reverting on\n     * overflow (when the input is greater than largest uint32).\n     *\n     * Counterpart to Solidity's `uint32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     */\n    function toUint32(uint256 value) internal pure returns (uint32) {\n        require(value <= type(uint32).max, \"SafeCast: value doesn't fit in 32 bits\");\n        return uint32(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint16 from uint256, reverting on\n     * overflow (when the input is greater than largest uint16).\n     *\n     * Counterpart to Solidity's `uint16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     */\n    function toUint16(uint256 value) internal pure returns (uint16) {\n        require(value <= type(uint16).max, \"SafeCast: value doesn't fit in 16 bits\");\n        return uint16(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint8 from uint256, reverting on\n     * overflow (when the input is greater than largest uint8).\n     *\n     * Counterpart to Solidity's `uint8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits.\n     */\n    function toUint8(uint256 value) internal pure returns (uint8) {\n        require(value <= type(uint8).max, \"SafeCast: value doesn't fit in 8 bits\");\n        return uint8(value);\n    }\n\n    /**\n     * @dev Converts a signed int256 into an unsigned uint256.\n     *\n     * Requirements:\n     *\n     * - input must be greater than or equal to 0.\n     */\n    function toUint256(int256 value) internal pure returns (uint256) {\n        require(value >= 0, \"SafeCast: value must be positive\");\n        return uint256(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int128 from int256, reverting on\n     * overflow (when the input is less than smallest int128 or\n     * greater than largest int128).\n     *\n     * Counterpart to Solidity's `int128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt128(int256 value) internal pure returns (int128) {\n        require(value >= type(int128).min && value <= type(int128).max, \"SafeCast: value doesn't fit in 128 bits\");\n        return int128(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int64 from int256, reverting on\n     * overflow (when the input is less than smallest int64 or\n     * greater than largest int64).\n     *\n     * Counterpart to Solidity's `int64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt64(int256 value) internal pure returns (int64) {\n        require(value >= type(int64).min && value <= type(int64).max, \"SafeCast: value doesn't fit in 64 bits\");\n        return int64(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int32 from int256, reverting on\n     * overflow (when the input is less than smallest int32 or\n     * greater than largest int32).\n     *\n     * Counterpart to Solidity's `int32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt32(int256 value) internal pure returns (int32) {\n        require(value >= type(int32).min && value <= type(int32).max, \"SafeCast: value doesn't fit in 32 bits\");\n        return int32(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int16 from int256, reverting on\n     * overflow (when the input is less than smallest int16 or\n     * greater than largest int16).\n     *\n     * Counterpart to Solidity's `int16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt16(int256 value) internal pure returns (int16) {\n        require(value >= type(int16).min && value <= type(int16).max, \"SafeCast: value doesn't fit in 16 bits\");\n        return int16(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int8 from int256, reverting on\n     * overflow (when the input is less than smallest int8 or\n     * greater than largest int8).\n     *\n     * Counterpart to Solidity's `int8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits.\n     *\n     * _Available since v3.1._\n     */\n    function toInt8(int256 value) internal pure returns (int8) {\n        require(value >= type(int8).min && value <= type(int8).max, \"SafeCast: value doesn't fit in 8 bits\");\n        return int8(value);\n    }\n\n    /**\n     * @dev Converts an unsigned uint256 into a signed int256.\n     *\n     * Requirements:\n     *\n     * - input must be less than or equal to maxInt256.\n     */\n    function toInt256(uint256 value) internal pure returns (int256) {\n        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n        require(value <= uint256(type(int256).max), \"SafeCast: value doesn't fit in an int256\");\n        return int256(value);\n    }\n}\n"},{"file_path":"contracts/governance/Governable.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Base for contracts that are managed by the Origin Protocol's Governor.\n * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change\n *      from owner to governor and renounce methods removed. Does not use\n *      Context.sol like Ownable.sol does for simplification.\n * @author Origin Protocol Inc\n */\nabstract contract Governable {\n    // Storage position of the owner and pendingOwner of the contract\n    // keccak256(\"OUSD.governor\");\n    bytes32 private constant governorPosition =\n        0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a;\n\n    // keccak256(\"OUSD.pending.governor\");\n    bytes32 private constant pendingGovernorPosition =\n        0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db;\n\n    // keccak256(\"OUSD.reentry.status\");\n    bytes32 private constant reentryStatusPosition =\n        0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535;\n\n    // See OpenZeppelin ReentrancyGuard implementation\n    uint256 constant _NOT_ENTERED = 1;\n    uint256 constant _ENTERED = 2;\n\n    event PendingGovernorshipTransfer(\n        address indexed previousGovernor,\n        address indexed newGovernor\n    );\n\n    event GovernorshipTransferred(\n        address indexed previousGovernor,\n        address indexed newGovernor\n    );\n\n    /**\n     * @notice Returns the address of the current Governor.\n     */\n    function governor() public view returns (address) {\n        return _governor();\n    }\n\n    /**\n     * @dev Returns the address of the current Governor.\n     */\n    function _governor() internal view returns (address governorOut) {\n        bytes32 position = governorPosition;\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            governorOut := sload(position)\n        }\n    }\n\n    /**\n     * @dev Returns the address of the pending Governor.\n     */\n    function _pendingGovernor()\n        internal\n        view\n        returns (address pendingGovernor)\n    {\n        bytes32 position = pendingGovernorPosition;\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            pendingGovernor := sload(position)\n        }\n    }\n\n    /**\n     * @dev Throws if called by any account other than the Governor.\n     */\n    modifier onlyGovernor() {\n        require(isGovernor(), \"Caller is not the Governor\");\n        _;\n    }\n\n    /**\n     * @notice Returns true if the caller is the current Governor.\n     */\n    function isGovernor() public view returns (bool) {\n        return msg.sender == _governor();\n    }\n\n    function _setGovernor(address newGovernor) internal {\n        emit GovernorshipTransferred(_governor(), newGovernor);\n\n        bytes32 position = governorPosition;\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            sstore(position, newGovernor)\n        }\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and make it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        bytes32 position = reentryStatusPosition;\n        uint256 _reentry_status;\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            _reentry_status := sload(position)\n        }\n\n        // On the first call to nonReentrant, _notEntered will be true\n        require(_reentry_status != _ENTERED, \"Reentrant call\");\n\n        // Any calls to nonReentrant after this point will fail\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            sstore(position, _ENTERED)\n        }\n\n        _;\n\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            sstore(position, _NOT_ENTERED)\n        }\n    }\n\n    function _setPendingGovernor(address newGovernor) internal {\n        bytes32 position = pendingGovernorPosition;\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            sstore(position, newGovernor)\n        }\n    }\n\n    /**\n     * @notice Transfers Governance of the contract to a new account (`newGovernor`).\n     * Can only be called by the current Governor. Must be claimed for this to complete\n     * @param _newGovernor Address of the new Governor\n     */\n    function transferGovernance(address _newGovernor) external onlyGovernor {\n        _setPendingGovernor(_newGovernor);\n        emit PendingGovernorshipTransfer(_governor(), _newGovernor);\n    }\n\n    /**\n     * @notice Claim Governance of the contract to a new account (`newGovernor`).\n     * Can only be called by the new Governor.\n     */\n    function claimGovernance() external {\n        require(\n            msg.sender == _pendingGovernor(),\n            \"Only the pending Governor can complete the claim\"\n        );\n        _changeGovernor(msg.sender);\n    }\n\n    /**\n     * @dev Change Governance of the contract to a new account (`newGovernor`).\n     * @param _newGovernor Address of the new Governor\n     */\n    function _changeGovernor(address _newGovernor) internal {\n        require(_newGovernor != address(0), \"New Governor is address(0)\");\n        _setGovernor(_newGovernor);\n    }\n}\n"},{"file_path":"contracts/interfaces/IBasicToken.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IBasicToken {\n    function symbol() external view returns (string memory);\n\n    function decimals() external view returns (uint8);\n}\n"},{"file_path":"contracts/utils/Initializable.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Base contract any contracts that need to initialize state after deployment.\n * @author Origin Protocol Inc\n */\nabstract contract Initializable {\n    /**\n     * @dev Indicates that the contract has been initialized.\n     */\n    bool private initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private initializing;\n\n    /**\n     * @dev Modifier to protect an initializer function from being invoked twice.\n     */\n    modifier initializer() {\n        require(\n            initializing || !initialized,\n            \"Initializable: contract is already initialized\"\n        );\n\n        bool isTopLevelCall = !initializing;\n        if (isTopLevelCall) {\n            initializing = true;\n            initialized = true;\n        }\n\n        _;\n\n        if (isTopLevelCall) {\n            initializing = false;\n        }\n    }\n\n    uint256[50] private ______gap;\n}\n"},{"file_path":"contracts/utils/InitializableAbstractStrategy.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Base contract for vault strategies.\n * @author Origin Protocol Inc\n */\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { IVault } from \"../interfaces/IVault.sol\";\n\nabstract contract InitializableAbstractStrategy is Initializable, Governable {\n    using SafeERC20 for IERC20;\n\n    event PTokenAdded(address indexed _asset, address _pToken);\n    event PTokenRemoved(address indexed _asset, address _pToken);\n    event Deposit(address indexed _asset, address _pToken, uint256 _amount);\n    event Withdrawal(address indexed _asset, address _pToken, uint256 _amount);\n    event RewardTokenCollected(\n        address recipient,\n        address rewardToken,\n        uint256 amount\n    );\n    event RewardTokenAddressesUpdated(\n        address[] _oldAddresses,\n        address[] _newAddresses\n    );\n    event HarvesterAddressesUpdated(\n        address _oldHarvesterAddress,\n        address _newHarvesterAddress\n    );\n\n    /// @notice Address of the underlying platform\n    address public immutable platformAddress;\n    /// @notice Address of the OToken vault\n    address public immutable vaultAddress;\n\n    /// @dev Replaced with an immutable variable\n    // slither-disable-next-line constable-states\n    address private _deprecated_platformAddress;\n\n    /// @dev Replaced with an immutable\n    // slither-disable-next-line constable-states\n    address private _deprecated_vaultAddress;\n\n    /// @notice asset => pToken (Platform Specific Token Address)\n    mapping(address => address) public assetToPToken;\n\n    /// @notice Full list of all assets supported by the strategy\n    address[] internal assetsMapped;\n\n    // Deprecated: Reward token address\n    // slither-disable-next-line constable-states\n    address private _deprecated_rewardTokenAddress;\n\n    // Deprecated: now resides in Harvester's rewardTokenConfigs\n    // slither-disable-next-line constable-states\n    uint256 private _deprecated_rewardLiquidationThreshold;\n\n    /// @notice Address of the Harvester contract allowed to collect reward tokens\n    address public harvesterAddress;\n\n    /// @notice Address of the reward tokens. eg CRV, BAL, CVX, AURA\n    address[] public rewardTokenAddresses;\n\n    /* Reserved for future expansion. Used to be 100 storage slots\n     * and has decreased to accommodate:\n     * - harvesterAddress\n     * - rewardTokenAddresses\n     */\n    int256[98] private _reserved;\n\n    struct BaseStrategyConfig {\n        address platformAddress; // Address of the underlying platform\n        address vaultAddress; // Address of the OToken's Vault\n    }\n\n    /**\n     * @dev Verifies that the caller is the Governor or Strategist.\n     */\n    modifier onlyGovernorOrStrategist() virtual {\n        require(\n            isGovernor() || msg.sender == IVault(vaultAddress).strategistAddr(),\n            \"Caller is not the Strategist or Governor\"\n        );\n        _;\n    }\n\n    /**\n     * @param _config The platform and OToken vault addresses\n     */\n    constructor(BaseStrategyConfig memory _config) {\n        platformAddress = _config.platformAddress;\n        vaultAddress = _config.vaultAddress;\n    }\n\n    /**\n     * @dev Internal initialize function, to set up initial internal state\n     * @param _rewardTokenAddresses Address of reward token for platform\n     * @param _assets Addresses of initial supported assets\n     * @param _pTokens Platform Token corresponding addresses\n     */\n    function _initialize(\n        address[] memory _rewardTokenAddresses,\n        address[] memory _assets,\n        address[] memory _pTokens\n    ) internal {\n        rewardTokenAddresses = _rewardTokenAddresses;\n\n        uint256 assetCount = _assets.length;\n        require(assetCount == _pTokens.length, \"Invalid input arrays\");\n        for (uint256 i = 0; i < assetCount; ++i) {\n            _setPTokenAddress(_assets[i], _pTokens[i]);\n        }\n    }\n\n    /**\n     * @notice Collect accumulated reward token and send to Vault.\n     */\n    function collectRewardTokens() external virtual onlyHarvester nonReentrant {\n        _collectRewardTokens();\n    }\n\n    /**\n     * @dev Default implementation that transfers reward tokens to the Harvester\n     * Implementing strategies need to add custom logic to collect the rewards.\n     */\n    function _collectRewardTokens() internal virtual {\n        uint256 rewardTokenCount = rewardTokenAddresses.length;\n        for (uint256 i = 0; i < rewardTokenCount; ++i) {\n            IERC20 rewardToken = IERC20(rewardTokenAddresses[i]);\n            uint256 balance = rewardToken.balanceOf(address(this));\n            if (balance > 0) {\n                emit RewardTokenCollected(\n                    harvesterAddress,\n                    address(rewardToken),\n                    balance\n                );\n                rewardToken.safeTransfer(harvesterAddress, balance);\n            }\n        }\n    }\n\n    /**\n     * @dev Verifies that the caller is the Vault.\n     */\n    modifier onlyVault() {\n        require(msg.sender == vaultAddress, \"Caller is not the Vault\");\n        _;\n    }\n\n    /**\n     * @dev Verifies that the caller is the Harvester.\n     */\n    modifier onlyHarvester() {\n        require(msg.sender == harvesterAddress, \"Caller is not the Harvester\");\n        _;\n    }\n\n    /**\n     * @dev Verifies that the caller is the Vault or Governor.\n     */\n    modifier onlyVaultOrGovernor() {\n        require(\n            msg.sender == vaultAddress || msg.sender == governor(),\n            \"Caller is not the Vault or Governor\"\n        );\n        _;\n    }\n\n    /**\n     * @dev Verifies that the caller is the Vault, Governor, or Strategist.\n     */\n    modifier onlyVaultOrGovernorOrStrategist() {\n        require(\n            msg.sender == vaultAddress ||\n                msg.sender == governor() ||\n                msg.sender == IVault(vaultAddress).strategistAddr(),\n            \"Caller is not the Vault, Governor, or Strategist\"\n        );\n        _;\n    }\n\n    /**\n     * @notice Set the reward token addresses. Any old addresses will be overwritten.\n     * @param _rewardTokenAddresses Array of reward token addresses\n     */\n    function setRewardTokenAddresses(address[] calldata _rewardTokenAddresses)\n        external\n        onlyGovernor\n    {\n        uint256 rewardTokenCount = _rewardTokenAddresses.length;\n        for (uint256 i = 0; i < rewardTokenCount; ++i) {\n            require(\n                _rewardTokenAddresses[i] != address(0),\n                \"Can not set an empty address as a reward token\"\n            );\n        }\n\n        emit RewardTokenAddressesUpdated(\n            rewardTokenAddresses,\n            _rewardTokenAddresses\n        );\n        rewardTokenAddresses = _rewardTokenAddresses;\n    }\n\n    /**\n     * @notice Get the reward token addresses.\n     * @return address[] the reward token addresses.\n     */\n    function getRewardTokenAddresses()\n        external\n        view\n        returns (address[] memory)\n    {\n        return rewardTokenAddresses;\n    }\n\n    /**\n     * @notice Provide support for asset by passing its pToken address.\n     *      This method can only be called by the system Governor\n     * @param _asset    Address for the asset\n     * @param _pToken   Address for the corresponding platform token\n     */\n    function setPTokenAddress(address _asset, address _pToken)\n        external\n        virtual\n        onlyGovernor\n    {\n        _setPTokenAddress(_asset, _pToken);\n    }\n\n    /**\n     * @notice Remove a supported asset by passing its index.\n     *      This method can only be called by the system Governor\n     * @param _assetIndex Index of the asset to be removed\n     */\n    function removePToken(uint256 _assetIndex) external virtual onlyGovernor {\n        require(_assetIndex < assetsMapped.length, \"Invalid index\");\n        address asset = assetsMapped[_assetIndex];\n        address pToken = assetToPToken[asset];\n\n        if (_assetIndex < assetsMapped.length - 1) {\n            assetsMapped[_assetIndex] = assetsMapped[assetsMapped.length - 1];\n        }\n        assetsMapped.pop();\n        assetToPToken[asset] = address(0);\n\n        emit PTokenRemoved(asset, pToken);\n    }\n\n    /**\n     * @notice Provide support for asset by passing its pToken address.\n     *      Add to internal mappings and execute the platform specific,\n     * abstract method `_abstractSetPToken`\n     * @param _asset    Address for the asset\n     * @param _pToken   Address for the corresponding platform token\n     */\n    function _setPTokenAddress(address _asset, address _pToken) internal {\n        require(assetToPToken[_asset] == address(0), \"pToken already set\");\n        require(\n            _asset != address(0) && _pToken != address(0),\n            \"Invalid addresses\"\n        );\n\n        assetToPToken[_asset] = _pToken;\n        assetsMapped.push(_asset);\n\n        emit PTokenAdded(_asset, _pToken);\n\n        _abstractSetPToken(_asset, _pToken);\n    }\n\n    /**\n     * @notice Transfer token to governor. Intended for recovering tokens stuck in\n     *      strategy contracts, i.e. mistaken sends.\n     * @param _asset Address for the asset\n     * @param _amount Amount of the asset to transfer\n     */\n    function transferToken(address _asset, uint256 _amount)\n        public\n        virtual\n        onlyGovernor\n    {\n        require(!supportsAsset(_asset), \"Cannot transfer supported asset\");\n        IERC20(_asset).safeTransfer(governor(), _amount);\n    }\n\n    /**\n     * @notice Set the Harvester contract that can collect rewards.\n     * @param _harvesterAddress Address of the harvester contract.\n     */\n    function setHarvesterAddress(address _harvesterAddress)\n        external\n        onlyGovernor\n    {\n        emit HarvesterAddressesUpdated(harvesterAddress, _harvesterAddress);\n        harvesterAddress = _harvesterAddress;\n    }\n\n    /***************************************\n                 Abstract\n    ****************************************/\n\n    function _abstractSetPToken(address _asset, address _pToken)\n        internal\n        virtual;\n\n    function safeApproveAllTokens() external virtual;\n\n    /**\n     * @notice Deposit an amount of assets into the platform\n     * @param _asset               Address for the asset\n     * @param _amount              Units of asset to deposit\n     */\n    function deposit(address _asset, uint256 _amount) external virtual;\n\n    /**\n     * @notice Deposit all supported assets in this strategy contract to the platform\n     */\n    function depositAll() external virtual;\n\n    /**\n     * @notice Withdraw an `amount` of assets from the platform and\n     * send to the `_recipient`.\n     * @param _recipient         Address to which the asset should be sent\n     * @param _asset             Address of the asset\n     * @param _amount            Units of asset to withdraw\n     */\n    function withdraw(\n        address _recipient,\n        address _asset,\n        uint256 _amount\n    ) external virtual;\n\n    /**\n     * @notice Withdraw all supported assets from platform and\n     * sends to the OToken's Vault.\n     */\n    function withdrawAll() external virtual;\n\n    /**\n     * @notice Get the total asset value held in the platform.\n     *      This includes any interest that was generated since depositing.\n     * @param _asset      Address of the asset\n     * @return balance    Total value of the asset in the platform\n     */\n    function checkBalance(address _asset)\n        external\n        view\n        virtual\n        returns (uint256 balance);\n\n    /**\n     * @notice Check if an asset is supported.\n     * @param _asset    Address of the asset\n     * @return bool     Whether asset is supported\n     */\n    function supportsAsset(address _asset) public view virtual returns (bool);\n}\n"},{"file_path":"contracts/vault/VaultStorage.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OToken VaultStorage contract\n * @notice The VaultStorage contract defines the storage for the Vault contracts\n * @author Origin Protocol Inc\n */\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { Address } from \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport { IStrategy } from \"../interfaces/IStrategy.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { OUSD } from \"../token/OUSD.sol\";\nimport { Initializable } from \"../utils/Initializable.sol\";\nimport \"../utils/Helpers.sol\";\n\nabstract contract VaultStorage is Initializable, Governable {\n    using SafeERC20 for IERC20;\n\n    event AssetAllocated(address _asset, address _strategy, uint256 _amount);\n    event StrategyApproved(address _addr);\n    event StrategyRemoved(address _addr);\n    event Mint(address _addr, uint256 _value);\n    event Redeem(address _addr, uint256 _value);\n    event CapitalPaused();\n    event CapitalUnpaused();\n    event DefaultStrategyUpdated(address _strategy);\n    event RebasePaused();\n    event RebaseUnpaused();\n    event VaultBufferUpdated(uint256 _vaultBuffer);\n    event AllocateThresholdUpdated(uint256 _threshold);\n    event RebaseThresholdUpdated(uint256 _threshold);\n    event StrategistUpdated(address _address);\n    event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\n    event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\n    event TrusteeFeeBpsChanged(uint256 _basis);\n    event TrusteeAddressChanged(address _address);\n    event StrategyAddedToMintWhitelist(address indexed strategy);\n    event StrategyRemovedFromMintWhitelist(address indexed strategy);\n    event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);\n    event DripDurationChanged(uint256 dripDuration);\n    event WithdrawalRequested(\n        address indexed _withdrawer,\n        uint256 indexed _requestId,\n        uint256 _amount,\n        uint256 _queued\n    );\n    event WithdrawalClaimed(\n        address indexed _withdrawer,\n        uint256 indexed _requestId,\n        uint256 _amount\n    );\n    event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\n    event WithdrawalClaimDelayUpdated(uint256 _newDelay);\n\n    // Since we are proxy, all state should be uninitalized.\n    // Since this storage contract does not have logic directly on it\n    // we should not be checking for to see if these variables can be constant.\n    // slither-disable-start uninitialized-state\n    // slither-disable-start constable-states\n\n    /// @dev mapping of supported vault assets to their configuration\n    uint256 private _deprecated_assets;\n    /// @dev list of all assets supported by the vault.\n    address[] private _deprecated_allAssets;\n\n    // Strategies approved for use by the Vault\n    struct Strategy {\n        bool isSupported;\n        uint256 _deprecated; // Deprecated storage slot\n    }\n    /// @dev mapping of strategy contracts to their configuration\n    mapping(address => Strategy) public strategies;\n    /// @dev list of all vault strategies\n    address[] internal allStrategies;\n\n    /// @notice Address of the Oracle price provider contract\n    address private _deprecated_priceProvider;\n    /// @notice pause rebasing if true\n    bool public rebasePaused;\n    /// @notice pause operations that change the OToken supply.\n    /// eg mint, redeem, allocate, mint/burn for strategy\n    bool public capitalPaused;\n    /// @notice Redemption fee in basis points. eg 50 = 0.5%\n    uint256 private _deprecated_redeemFeeBps;\n    /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18.\n    uint256 public vaultBuffer;\n    /// @notice OToken mints over this amount automatically allocate funds. 18 decimals.\n    uint256 public autoAllocateThreshold;\n    /// @notice OToken mints over this amount automatically rebase. 18 decimals.\n    uint256 public rebaseThreshold;\n\n    /// @dev Address of the OToken token. eg OUSD or OETH.\n    OUSD public oToken;\n\n    /// @dev Address of the contract responsible for post rebase syncs with AMMs\n    address private _deprecated_rebaseHooksAddr = address(0);\n\n    /// @dev Deprecated: Address of Uniswap\n    address private _deprecated_uniswapAddr = address(0);\n\n    /// @notice Address of the Strategist\n    address public strategistAddr = address(0);\n\n    /// @notice Mapping of asset address to the Strategy that they should automatically\n    // be allocated to\n    uint256 private _deprecated_assetDefaultStrategies;\n\n    /// @notice Max difference between total supply and total value of assets. 18 decimals.\n    uint256 public maxSupplyDiff;\n\n    /// @notice Trustee contract that can collect a percentage of yield\n    address public trusteeAddress;\n\n    /// @notice Amount of yield collected in basis points. eg 2000 = 20%\n    uint256 public trusteeFeeBps;\n\n    /// @dev Deprecated: Tokens that should be swapped for stablecoins\n    address[] private _deprecated_swapTokens;\n\n    /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral\n\n    address private _deprecated_ousdMetaStrategy;\n\n    /// @notice How much OTokens are currently minted by the strategy\n    int256 private _deprecated_netOusdMintedForStrategy;\n\n    /// @notice How much net total OTokens are allowed to be minted by all strategies\n    uint256 private _deprecated_netOusdMintForStrategyThreshold;\n\n    uint256 private _deprecated_swapConfig;\n\n    // List of strategies that can mint oTokens directly\n    // Used in OETHBaseVaultCore\n    mapping(address => bool) public isMintWhitelistedStrategy;\n\n    /// @notice Address of the Dripper contract that streams harvested rewards to the Vault\n    /// @dev The vault is proxied so needs to be set with setDripper against the proxy contract.\n    address private _deprecated_dripper;\n\n    /// Withdrawal Queue Storage /////\n\n    struct WithdrawalQueueMetadata {\n        // cumulative total of all withdrawal requests included the ones that have already been claimed\n        uint128 queued;\n        // cumulative total of all the requests that can be claimed including the ones that have already been claimed\n        uint128 claimable;\n        // total of all the requests that have been claimed\n        uint128 claimed;\n        // index of the next withdrawal request starting at 0\n        uint128 nextWithdrawalIndex;\n    }\n\n    /// @notice Global metadata for the withdrawal queue including:\n    /// queued - cumulative total of all withdrawal requests included the ones that have already been claimed\n    /// claimable - cumulative total of all the requests that can be claimed including the ones already claimed\n    /// claimed - total of all the requests that have been claimed\n    /// nextWithdrawalIndex - index of the next withdrawal request starting at 0\n    WithdrawalQueueMetadata public withdrawalQueueMetadata;\n\n    struct WithdrawalRequest {\n        address withdrawer;\n        bool claimed;\n        uint40 timestamp; // timestamp of the withdrawal request\n        // Amount of oTokens to redeem. eg OETH\n        uint128 amount;\n        // cumulative total of all withdrawal requests including this one.\n        // this request can be claimed when this queued amount is less than or equal to the queue's claimable amount.\n        uint128 queued;\n    }\n\n    /// @notice Mapping of withdrawal request indices to the user withdrawal request data\n    mapping(uint256 => WithdrawalRequest) public withdrawalRequests;\n\n    /// @notice Sets a minimum delay that is required to elapse between\n    ///     requesting async withdrawals and claiming the request.\n    ///     When set to 0 async withdrawals are disabled.\n    uint256 public withdrawalClaimDelay;\n\n    /// @notice Time in seconds that the vault last rebased yield.\n    uint64 public lastRebase;\n\n    /// @notice Automatic rebase yield calculations. In seconds. Set to 0 or 1 to disable.\n    uint64 public dripDuration;\n\n    /// @notice max rebase percentage per second\n    ///   Can be used to set maximum yield of the protocol,\n    ///   spreading out yield over time\n    uint64 public rebasePerSecondMax;\n\n    /// @notice target rebase rate limit, based on past rates and funds available.\n    uint64 public rebasePerSecondTarget;\n\n    uint256 internal constant MAX_REBASE = 0.02 ether;\n    uint256 internal constant MAX_REBASE_PER_SECOND =\n        uint256(0.05 ether) / 1 days;\n\n    /// @notice Default strategy for asset\n    address public defaultStrategy;\n\n    // For future use\n    uint256[42] private __gap;\n\n    /// @notice Index of WETH asset in allAssets array\n    /// Legacy OETHVaultCore code, relocated here for vault consistency.\n    uint256 private _deprecated_wethAssetIndex;\n\n    /// @dev Address of the asset (eg. WETH or USDC)\n    address public immutable asset;\n    uint8 internal immutable assetDecimals;\n\n    // slither-disable-end constable-states\n    // slither-disable-end uninitialized-state\n\n    constructor(address _asset) {\n        uint8 _decimals = IERC20Metadata(_asset).decimals();\n        require(_decimals <= 18, \"invalid asset decimals\");\n        asset = _asset;\n        assetDecimals = _decimals;\n    }\n\n    /// @notice Deprecated: use `oToken()` instead.\n    function oUSD() external view returns (OUSD) {\n        return oToken;\n    }\n}\n"},{"file_path":"contracts/interfaces/IStrategy.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title Platform interface to integrate with lending platform like Compound, AAVE etc.\n */\ninterface IStrategy {\n    /**\n     * @dev Deposit the given asset to platform\n     * @param _asset asset address\n     * @param _amount Amount to deposit\n     */\n    function deposit(address _asset, uint256 _amount) external;\n\n    /**\n     * @dev Deposit the entire balance of all supported assets in the Strategy\n     *      to the platform\n     */\n    function depositAll() external;\n\n    /**\n     * @dev Withdraw given asset from Lending platform\n     */\n    function withdraw(\n        address _recipient,\n        address _asset,\n        uint256 _amount\n    ) external;\n\n    /**\n     * @dev Liquidate all assets in strategy and return them to Vault.\n     */\n    function withdrawAll() external;\n\n    /**\n     * @dev Returns the current balance of the given asset.\n     */\n    function checkBalance(address _asset)\n        external\n        view\n        returns (uint256 balance);\n\n    /**\n     * @dev Returns bool indicating whether strategy supports asset.\n     */\n    function supportsAsset(address _asset) external view returns (bool);\n\n    /**\n     * @dev Collect reward tokens from the Strategy.\n     */\n    function collectRewardTokens() external;\n\n    /**\n     * @dev The address array of the reward tokens for the Strategy.\n     */\n    function getRewardTokenAddresses() external view returns (address[] memory);\n\n    function harvesterAddress() external view returns (address);\n\n    function transferToken(address token, uint256 amount) external;\n\n    function setRewardTokenAddresses(address[] calldata _rewardTokenAddresses)\n        external;\n}\n"},{"file_path":"contracts/interfaces/IVault.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { VaultStorage } from \"../vault/VaultStorage.sol\";\n\ninterface IVault {\n    // slither-disable-start constable-states\n\n    event AssetAllocated(address _asset, address _strategy, uint256 _amount);\n    event StrategyApproved(address _addr);\n    event StrategyRemoved(address _addr);\n    event Mint(address _addr, uint256 _value);\n    event Redeem(address _addr, uint256 _value);\n    event CapitalPaused();\n    event CapitalUnpaused();\n    event DefaultStrategyUpdated(address _strategy);\n    event RebasePaused();\n    event RebaseUnpaused();\n    event VaultBufferUpdated(uint256 _vaultBuffer);\n    event AllocateThresholdUpdated(uint256 _threshold);\n    event RebaseThresholdUpdated(uint256 _threshold);\n    event StrategistUpdated(address _address);\n    event MaxSupplyDiffChanged(uint256 maxSupplyDiff);\n    event YieldDistribution(address _to, uint256 _yield, uint256 _fee);\n    event TrusteeFeeBpsChanged(uint256 _basis);\n    event TrusteeAddressChanged(address _address);\n    event StrategyAddedToMintWhitelist(address indexed strategy);\n    event StrategyRemovedFromMintWhitelist(address indexed strategy);\n    event RebasePerSecondMaxChanged(uint256 rebaseRatePerSecond);\n    event DripDurationChanged(uint256 dripDuration);\n    event WithdrawalRequested(\n        address indexed _withdrawer,\n        uint256 indexed _requestId,\n        uint256 _amount,\n        uint256 _queued\n    );\n    event WithdrawalClaimed(\n        address indexed _withdrawer,\n        uint256 indexed _requestId,\n        uint256 _amount\n    );\n    event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable);\n    event WithdrawalClaimDelayUpdated(uint256 _newDelay);\n\n    // Governable.sol\n    function transferGovernance(address _newGovernor) external;\n\n    function claimGovernance() external;\n\n    function governor() external view returns (address);\n\n    // VaultAdmin.sol\n    function setVaultBuffer(uint256 _vaultBuffer) external;\n\n    function vaultBuffer() external view returns (uint256);\n\n    function setAutoAllocateThreshold(uint256 _threshold) external;\n\n    function autoAllocateThreshold() external view returns (uint256);\n\n    function setRebaseThreshold(uint256 _threshold) external;\n\n    function rebaseThreshold() external view returns (uint256);\n\n    function setStrategistAddr(address _address) external;\n\n    function strategistAddr() external view returns (address);\n\n    function setMaxSupplyDiff(uint256 _maxSupplyDiff) external;\n\n    function maxSupplyDiff() external view returns (uint256);\n\n    function setTrusteeAddress(address _address) external;\n\n    function trusteeAddress() external view returns (address);\n\n    function setTrusteeFeeBps(uint256 _basis) external;\n\n    function trusteeFeeBps() external view returns (uint256);\n\n    function approveStrategy(address _addr) external;\n\n    function removeStrategy(address _addr) external;\n\n    function setDefaultStrategy(address _strategy) external;\n\n    function defaultStrategy() external view returns (address);\n\n    function pauseRebase() external;\n\n    function unpauseRebase() external;\n\n    function rebasePaused() external view returns (bool);\n\n    function pauseCapital() external;\n\n    function unpauseCapital() external;\n\n    function capitalPaused() external view returns (bool);\n\n    function transferToken(address _asset, uint256 _amount) external;\n\n    function withdrawAllFromStrategy(address _strategyAddr) external;\n\n    function withdrawAllFromStrategies() external;\n\n    function withdrawFromStrategy(\n        address _strategyFromAddress,\n        address[] calldata _assets,\n        uint256[] calldata _amounts\n    ) external;\n\n    function depositToStrategy(\n        address _strategyToAddress,\n        address[] calldata _assets,\n        uint256[] calldata _amounts\n    ) external;\n\n    // VaultCore.sol\n    function mint(\n        address _asset,\n        uint256 _amount,\n        uint256 _minimumOusdAmount\n    ) external;\n\n    function mintForStrategy(uint256 _amount) external;\n\n    function redeem(uint256 _amount, uint256 _minimumUnitAmount) external;\n\n    function burnForStrategy(uint256 _amount) external;\n\n    function allocate() external;\n\n    function rebase() external;\n\n    function totalValue() external view returns (uint256 value);\n\n    function checkBalance(address _asset) external view returns (uint256);\n\n    /// @notice Deprecated: use calculateRedeemOutput\n    function calculateRedeemOutputs(uint256 _amount)\n        external\n        view\n        returns (uint256[] memory);\n\n    function calculateRedeemOutput(uint256 _amount)\n        external\n        view\n        returns (uint256);\n\n    function getAssetCount() external view returns (uint256);\n\n    function getAllAssets() external view returns (address[] memory);\n\n    function getStrategyCount() external view returns (uint256);\n\n    function getAllStrategies() external view returns (address[] memory);\n\n    /// @notice Deprecated.\n    function isSupportedAsset(address _asset) external view returns (bool);\n\n    function dripper() external view returns (address);\n\n    function asset() external view returns (address);\n\n    function initialize(address) external;\n\n    function addWithdrawalQueueLiquidity() external;\n\n    function requestWithdrawal(uint256 _amount)\n        external\n        returns (uint256 requestId, uint256 queued);\n\n    function claimWithdrawal(uint256 requestId)\n        external\n        returns (uint256 amount);\n\n    function claimWithdrawals(uint256[] memory requestIds)\n        external\n        returns (uint256[] memory amounts, uint256 totalAmount);\n\n    function withdrawalQueueMetadata()\n        external\n        view\n        returns (VaultStorage.WithdrawalQueueMetadata memory);\n\n    function withdrawalRequests(uint256 requestId)\n        external\n        view\n        returns (VaultStorage.WithdrawalRequest memory);\n\n    function addStrategyToMintWhitelist(address strategyAddr) external;\n\n    function removeStrategyFromMintWhitelist(address strategyAddr) external;\n\n    function isMintWhitelistedStrategy(address strategyAddr)\n        external\n        view\n        returns (bool);\n\n    function withdrawalClaimDelay() external view returns (uint256);\n\n    function setWithdrawalClaimDelay(uint256 newDelay) external;\n\n    function lastRebase() external view returns (uint64);\n\n    function dripDuration() external view returns (uint64);\n\n    function setDripDuration(uint256 _dripDuration) external;\n\n    function rebasePerSecondMax() external view returns (uint64);\n\n    function setRebaseRateMax(uint256 yearlyApr) external;\n\n    function rebasePerSecondTarget() external view returns (uint64);\n\n    function previewYield() external view returns (uint256 yield);\n\n    function weth() external view returns (address);\n\n    // slither-disable-end constable-states\n}\n"},{"file_path":"contracts/interfaces/cctp/ICCTP.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\ninterface ICCTPTokenMessenger {\n    function depositForBurn(\n        uint256 amount,\n        uint32 destinationDomain,\n        bytes32 mintRecipient,\n        address burnToken,\n        bytes32 destinationCaller,\n        uint256 maxFee,\n        uint32 minFinalityThreshold\n    ) external;\n\n    function depositForBurnWithHook(\n        uint256 amount,\n        uint32 destinationDomain,\n        bytes32 mintRecipient,\n        address burnToken,\n        bytes32 destinationCaller,\n        uint256 maxFee,\n        uint32 minFinalityThreshold,\n        bytes memory hookData\n    ) external;\n\n    function getMinFeeAmount(uint256 amount) external view returns (uint256);\n}\n\ninterface ICCTPMessageTransmitter {\n    function sendMessage(\n        uint32 destinationDomain,\n        bytes32 recipient,\n        bytes32 destinationCaller,\n        uint32 minFinalityThreshold,\n        bytes memory messageBody\n    ) external;\n\n    function receiveMessage(bytes calldata message, bytes calldata attestation)\n        external\n        returns (bool);\n}\n\ninterface IMessageHandlerV2 {\n    /**\n     * @notice Handles an incoming finalized message from an IReceiverV2\n     * @dev Finalized messages have finality threshold values greater than or equal to 2000\n     * @param sourceDomain The source domain of the message\n     * @param sender The sender of the message\n     * @param finalityThresholdExecuted the finality threshold at which the message was attested to\n     * @param messageBody The raw bytes of the message body\n     * @return success True, if successful; false, if not.\n     */\n    function handleReceiveFinalizedMessage(\n        uint32 sourceDomain,\n        bytes32 sender,\n        uint32 finalityThresholdExecuted,\n        bytes calldata messageBody\n    ) external returns (bool);\n\n    /**\n     * @notice Handles an incoming unfinalized message from an IReceiverV2\n     * @dev Unfinalized messages have finality threshold values less than 2000\n     * @param sourceDomain The source domain of the message\n     * @param sender The sender of the message\n     * @param finalityThresholdExecuted The finality threshold at which the message was attested to\n     * @param messageBody The raw bytes of the message body\n     * @return success True, if successful; false, if not.\n     */\n    function handleReceiveUnfinalizedMessage(\n        uint32 sourceDomain,\n        bytes32 sender,\n        uint32 finalityThresholdExecuted,\n        bytes calldata messageBody\n    ) external returns (bool);\n}\n"},{"file_path":"contracts/strategies/crosschain/AbstractCCTPIntegrator.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title AbstractCCTPIntegrator\n * @author Origin Protocol Inc\n *\n * @dev Abstract contract that contains all the logic used to integrate with CCTP.\n */\n\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport { IERC20 } from \"../../utils/InitializableAbstractStrategy.sol\";\n\nimport { ICCTPTokenMessenger, ICCTPMessageTransmitter, IMessageHandlerV2 } from \"../../interfaces/cctp/ICCTP.sol\";\n\nimport { CrossChainStrategyHelper } from \"./CrossChainStrategyHelper.sol\";\nimport { Governable } from \"../../governance/Governable.sol\";\nimport { BytesHelper } from \"../../utils/BytesHelper.sol\";\nimport \"../../utils/Helpers.sol\";\n\nabstract contract AbstractCCTPIntegrator is Governable, IMessageHandlerV2 {\n    using SafeERC20 for IERC20;\n\n    using BytesHelper for bytes;\n    using CrossChainStrategyHelper for bytes;\n\n    event LastTransferNonceUpdated(uint64 lastTransferNonce);\n    event NonceProcessed(uint64 nonce);\n\n    event CCTPMinFinalityThresholdSet(uint16 minFinalityThreshold);\n    event CCTPFeePremiumBpsSet(uint16 feePremiumBps);\n    event OperatorChanged(address operator);\n    event TokensBridged(\n        uint32 destinationDomain,\n        address peerStrategy,\n        address tokenAddress,\n        uint256 tokenAmount,\n        uint256 maxFee,\n        uint32 minFinalityThreshold,\n        bytes hookData\n    );\n    event MessageTransmitted(\n        uint32 destinationDomain,\n        address peerStrategy,\n        uint32 minFinalityThreshold,\n        bytes message\n    );\n\n    // Message body V2 fields\n    // Ref: https://developers.circle.com/cctp/technical-guide#message-body\n    // Ref: https://github.com/circlefin/evm-cctp-contracts/blob/master/src/messages/v2/BurnMessageV2.sol\n    uint8 private constant BURN_MESSAGE_V2_VERSION_INDEX = 0;\n    uint8 private constant BURN_MESSAGE_V2_BURN_TOKEN_INDEX = 4;\n    uint8 private constant BURN_MESSAGE_V2_RECIPIENT_INDEX = 36;\n    uint8 private constant BURN_MESSAGE_V2_AMOUNT_INDEX = 68;\n    uint8 private constant BURN_MESSAGE_V2_MESSAGE_SENDER_INDEX = 100;\n    uint8 private constant BURN_MESSAGE_V2_FEE_EXECUTED_INDEX = 164;\n    uint8 private constant BURN_MESSAGE_V2_HOOK_DATA_INDEX = 228;\n\n    /**\n     * @notice  Max transfer threshold imposed by the CCTP\n     *          Ref: https://developers.circle.com/cctp/evm-smart-contracts#depositforburn\n     * @dev     10M USDC limit applies to both standard and fast transfer modes. The fast transfer mode has\n     *          an additional limitation that is not present on-chain and Circle may alter that amount off-chain\n     *          at their preference. The amount available for fast transfer can be queried here:\n     *          https://iris-api.circle.com/v2/fastBurn/USDC/allowance .\n     *          If a fast transfer token transaction has been issued and there is not enough allowance for it\n     *          the off-chain Iris component will re-attempt the transaction and if it fails it will fallback\n     *          to a standard transfer. Reference section 4.3 in the whitepaper:\n     *          https://6778953.fs1.hubspotusercontent-na1.net/hubfs/6778953/PDFs/Whitepapers/CCTPV2_White_Paper.pdf\n     */\n    uint256 public constant MAX_TRANSFER_AMOUNT = 10_000_000 * 10**6; // 10M USDC\n\n    /// @notice Minimum transfer amount to avoid zero or dust transfers\n    uint256 public constant MIN_TRANSFER_AMOUNT = 10**6;\n\n    // CCTP contracts\n    // This implementation assumes that remote and local chains have these contracts\n    // deployed on the same addresses.\n    /// @notice CCTP message transmitter contract\n    ICCTPMessageTransmitter public immutable cctpMessageTransmitter;\n    /// @notice CCTP token messenger contract\n    ICCTPTokenMessenger public immutable cctpTokenMessenger;\n\n    /// @notice USDC address on local chain\n    address public immutable usdcToken;\n\n    /// @notice USDC address on remote chain\n    address public immutable peerUsdcToken;\n\n    /// @notice Domain ID of the chain from which messages are accepted\n    uint32 public immutable peerDomainID;\n\n    /// @notice Strategy address on other chain\n    address public immutable peerStrategy;\n\n    /**\n     * @notice Minimum finality threshold\n     *         Can be 1000 (safe, after 1 epoch) or 2000 (finalized, after 2 epochs).\n     *         Ref: https://developers.circle.com/cctp/technical-guide#finality-thresholds\n     * @dev    When configuring the contract for fast transfer we should check the available\n     *         allowance of USDC that can be bridged using fast mode:\n     *         wget https://iris-api.circle.com/v2/fastBurn/USDC/allowance\n     */\n    uint16 public minFinalityThreshold;\n\n    /// @notice Fee premium in basis points\n    uint16 public feePremiumBps;\n\n    /// @notice Nonce of the last known deposit or withdrawal\n    uint64 public lastTransferNonce;\n\n    /// @notice Operator address: Can relay CCTP messages\n    address public operator;\n\n    /// @notice Mapping of processed nonces\n    mapping(uint64 => bool) private nonceProcessed;\n\n    // For future use\n    uint256[48] private __gap;\n\n    modifier onlyCCTPMessageTransmitter() {\n        require(\n            msg.sender == address(cctpMessageTransmitter),\n            \"Caller is not CCTP transmitter\"\n        );\n        _;\n    }\n\n    modifier onlyOperator() {\n        require(msg.sender == operator, \"Caller is not the Operator\");\n        _;\n    }\n\n    /**\n     * @notice Configuration for CCTP integration\n     * @param cctpTokenMessenger Address of the CCTP token messenger contract\n     * @param cctpMessageTransmitter Address of the CCTP message transmitter contract\n     * @param peerDomainID Domain ID of the chain from which messages are accepted.\n     *         0 for Ethereum, 6 for Base, etc.\n     *         Ref: https://developers.circle.com/cctp/cctp-supported-blockchains\n     * @param peerStrategy Address of the master or remote strategy on the other chain\n     * @param usdcToken USDC address on local chain\n     */\n    struct CCTPIntegrationConfig {\n        address cctpTokenMessenger;\n        address cctpMessageTransmitter;\n        uint32 peerDomainID;\n        address peerStrategy;\n        address usdcToken;\n        address peerUsdcToken;\n    }\n\n    constructor(CCTPIntegrationConfig memory _config) {\n        require(_config.usdcToken != address(0), \"Invalid USDC address\");\n        require(\n            _config.peerUsdcToken != address(0),\n            \"Invalid peer USDC address\"\n        );\n        require(\n            _config.cctpTokenMessenger != address(0),\n            \"Invalid CCTP config\"\n        );\n        require(\n            _config.cctpMessageTransmitter != address(0),\n            \"Invalid CCTP config\"\n        );\n        require(\n            _config.peerStrategy != address(0),\n            \"Invalid peer strategy address\"\n        );\n\n        cctpMessageTransmitter = ICCTPMessageTransmitter(\n            _config.cctpMessageTransmitter\n        );\n        cctpTokenMessenger = ICCTPTokenMessenger(_config.cctpTokenMessenger);\n\n        // Domain ID of the chain from which messages are accepted\n        peerDomainID = _config.peerDomainID;\n\n        // Strategy address on other chain, should\n        // always be same as the proxy of this strategy\n        peerStrategy = _config.peerStrategy;\n\n        // USDC address on local chain\n        usdcToken = _config.usdcToken;\n\n        // Just a sanity check to ensure the base token is USDC\n        uint256 _usdcTokenDecimals = Helpers.getDecimals(_config.usdcToken);\n        string memory _usdcTokenSymbol = Helpers.getSymbol(_config.usdcToken);\n        require(_usdcTokenDecimals == 6, \"Base token decimals must be 6\");\n        require(\n            keccak256(abi.encodePacked(_usdcTokenSymbol)) ==\n                keccak256(abi.encodePacked(\"USDC\")),\n            \"Token symbol must be USDC\"\n        );\n\n        // USDC address on remote chain\n        peerUsdcToken = _config.peerUsdcToken;\n    }\n\n    /**\n     * @dev Initialize the implementation contract\n     * @param _operator Operator address\n     * @param _minFinalityThreshold Minimum finality threshold\n     * @param _feePremiumBps Fee premium in basis points\n     */\n    function _initialize(\n        address _operator,\n        uint16 _minFinalityThreshold,\n        uint16 _feePremiumBps\n    ) internal {\n        _setOperator(_operator);\n        _setMinFinalityThreshold(_minFinalityThreshold);\n        _setFeePremiumBps(_feePremiumBps);\n\n        // Nonce starts at 1, so assume nonce 0 as processed.\n        // NOTE: This will cause the deposit/withdraw to fail if the\n        // strategy is not initialized properly (which is expected).\n        nonceProcessed[0] = true;\n    }\n\n    /***************************************\n                    Settings\n    ****************************************/\n    /**\n     * @dev Set the operator address\n     * @param _operator Operator address\n     */\n    function setOperator(address _operator) external onlyGovernor {\n        _setOperator(_operator);\n    }\n\n    /**\n     * @dev Set the operator address\n     * @param _operator Operator address\n     */\n    function _setOperator(address _operator) internal {\n        operator = _operator;\n        emit OperatorChanged(_operator);\n    }\n\n    /**\n     * @dev Set the minimum finality threshold at which\n     *      the message is considered to be finalized to relay.\n     *      Only accepts a value of 1000 (Safe, after 1 epoch) or\n     *      2000 (Finalized, after 2 epochs).\n     * @param _minFinalityThreshold Minimum finality threshold\n     */\n    function setMinFinalityThreshold(uint16 _minFinalityThreshold)\n        external\n        onlyGovernor\n    {\n        _setMinFinalityThreshold(_minFinalityThreshold);\n    }\n\n    /**\n     * @dev Set the minimum finality threshold\n     * @param _minFinalityThreshold Minimum finality threshold\n     */\n    function _setMinFinalityThreshold(uint16 _minFinalityThreshold) internal {\n        // 1000 for fast transfer and 2000 for standard transfer\n        require(\n            _minFinalityThreshold == 1000 || _minFinalityThreshold == 2000,\n            \"Invalid threshold\"\n        );\n\n        minFinalityThreshold = _minFinalityThreshold;\n        emit CCTPMinFinalityThresholdSet(_minFinalityThreshold);\n    }\n\n    /**\n     * @dev Set the fee premium in basis points.\n     *      Cannot be higher than 30% (3000 basis points).\n     * @param _feePremiumBps Fee premium in basis points\n     */\n    function setFeePremiumBps(uint16 _feePremiumBps) external onlyGovernor {\n        _setFeePremiumBps(_feePremiumBps);\n    }\n\n    /**\n     * @dev Set the fee premium in basis points\n     *      Cannot be higher than 30% (3000 basis points).\n     *      Ref: https://developers.circle.com/cctp/technical-guide#fees\n     * @param _feePremiumBps Fee premium in basis points\n     */\n    function _setFeePremiumBps(uint16 _feePremiumBps) internal {\n        require(_feePremiumBps <= 3000, \"Fee premium too high\"); // 30%\n\n        feePremiumBps = _feePremiumBps;\n        emit CCTPFeePremiumBpsSet(_feePremiumBps);\n    }\n\n    /***************************************\n             CCTP message handling\n    ****************************************/\n\n    /**\n     * @dev Handles a finalized CCTP message\n     * @param sourceDomain Source domain of the message\n     * @param sender Sender of the message\n     * @param finalityThresholdExecuted Fidelity threshold executed\n     * @param messageBody Message body\n     */\n    function handleReceiveFinalizedMessage(\n        uint32 sourceDomain,\n        bytes32 sender,\n        uint32 finalityThresholdExecuted,\n        bytes memory messageBody\n    ) external override onlyCCTPMessageTransmitter returns (bool) {\n        // Make sure the finality threshold at execution is at least 2000\n        require(\n            finalityThresholdExecuted >= 2000,\n            \"Finality threshold too low\"\n        );\n\n        return _handleReceivedMessage(sourceDomain, sender, messageBody);\n    }\n\n    /**\n     * @dev Handles an unfinalized but safe CCTP message\n     * @param sourceDomain Source domain of the message\n     * @param sender Sender of the message\n     * @param finalityThresholdExecuted Fidelity threshold executed\n     * @param messageBody Message body\n     */\n    function handleReceiveUnfinalizedMessage(\n        uint32 sourceDomain,\n        bytes32 sender,\n        uint32 finalityThresholdExecuted,\n        bytes memory messageBody\n    ) external override onlyCCTPMessageTransmitter returns (bool) {\n        // Make sure the contract is configured to handle unfinalized messages\n        require(\n            minFinalityThreshold == 1000,\n            \"Unfinalized messages are not supported\"\n        );\n        // Make sure the finality threshold at execution is at least 1000\n        require(\n            finalityThresholdExecuted >= 1000,\n            \"Finality threshold too low\"\n        );\n\n        return _handleReceivedMessage(sourceDomain, sender, messageBody);\n    }\n\n    /**\n     * @dev Handles a CCTP message\n     * @param sourceDomain Source domain of the message\n     * @param sender Sender of the message\n     * @param messageBody Message body\n     */\n    function _handleReceivedMessage(\n        uint32 sourceDomain,\n        bytes32 sender,\n        bytes memory messageBody\n    ) internal returns (bool) {\n        require(sourceDomain == peerDomainID, \"Unknown Source Domain\");\n\n        // Extract address from bytes32 (CCTP stores addresses as right-padded bytes32)\n        address senderAddress = address(uint160(uint256(sender)));\n        require(senderAddress == peerStrategy, \"Unknown Sender\");\n\n        _onMessageReceived(messageBody);\n\n        return true;\n    }\n\n    /**\n     * @dev Sends tokens to the peer strategy using CCTP Token Messenger\n     * @param tokenAmount Amount of tokens to send\n     * @param hookData Hook data\n     */\n    function _sendTokens(uint256 tokenAmount, bytes memory hookData)\n        internal\n        virtual\n    {\n        // CCTP has a maximum transfer amount of 10M USDC per tx\n        require(tokenAmount <= MAX_TRANSFER_AMOUNT, \"Token amount too high\");\n\n        // Approve only what needs to be transferred\n        IERC20(usdcToken).safeApprove(address(cctpTokenMessenger), tokenAmount);\n\n        // Compute the max fee to be paid.\n        // Ref: https://developers.circle.com/cctp/evm-smart-contracts#getminfeeamount\n        // The right way to compute fees would be to use CCTP's getMinFeeAmount function.\n        // The issue is that the getMinFeeAmount is not present on v2.0 contracts, but is on\n        // v2.1. Some of CCTP's deployed contracts are v2.0, some are v2.1.\n        // We will only be using standard transfers and fee on those is 0 for now. If they\n        // ever start implementing fee for standard transfers or if we decide to use fast\n        // trasnfer, we can use feePremiumBps as a workaround.\n        uint256 maxFee = feePremiumBps > 0\n            ? (tokenAmount * feePremiumBps) / 10000\n            : 0;\n\n        // Send tokens to the peer strategy using CCTP Token Messenger\n        cctpTokenMessenger.depositForBurnWithHook(\n            tokenAmount,\n            peerDomainID,\n            bytes32(uint256(uint160(peerStrategy))),\n            address(usdcToken),\n            bytes32(uint256(uint160(peerStrategy))),\n            maxFee,\n            uint32(minFinalityThreshold),\n            hookData\n        );\n\n        emit TokensBridged(\n            peerDomainID,\n            peerStrategy,\n            usdcToken,\n            tokenAmount,\n            maxFee,\n            uint32(minFinalityThreshold),\n            hookData\n        );\n    }\n\n    /**\n     * @dev Sends a message to the peer strategy using CCTP Message Transmitter\n     * @param message Payload of the message to send\n     */\n    function _sendMessage(bytes memory message) internal virtual {\n        cctpMessageTransmitter.sendMessage(\n            peerDomainID,\n            bytes32(uint256(uint160(peerStrategy))),\n            bytes32(uint256(uint160(peerStrategy))),\n            uint32(minFinalityThreshold),\n            message\n        );\n\n        emit MessageTransmitted(\n            peerDomainID,\n            peerStrategy,\n            uint32(minFinalityThreshold),\n            message\n        );\n    }\n\n    /**\n     * @dev Receives a message from the peer strategy on the other chain,\n     *      does some basic checks and relays it to the local MessageTransmitterV2.\n     *      If the message is a burn message, it will also handle the hook data\n     *      and call the _onTokenReceived function.\n     * @param message Payload of the message to send\n     * @param attestation Attestation of the message\n     */\n    function relay(bytes memory message, bytes memory attestation)\n        external\n        onlyOperator\n    {\n        (\n            uint32 version,\n            uint32 sourceDomainID,\n            address sender,\n            address recipient,\n            bytes memory messageBody\n        ) = message.decodeMessageHeader();\n\n        // Ensure that it's a CCTP message\n        require(\n            version == CrossChainStrategyHelper.CCTP_MESSAGE_VERSION,\n            \"Invalid CCTP message version\"\n        );\n\n        // Ensure that the source domain is the peer domain\n        require(sourceDomainID == peerDomainID, \"Unknown Source Domain\");\n\n        // Ensure message body version\n        version = messageBody.extractUint32(BURN_MESSAGE_V2_VERSION_INDEX);\n\n        // NOTE: There's a possibility that the CCTP Token Messenger might\n        // send other types of messages in future, not just the burn message.\n        // If it ever comes to that, this shouldn't cause us any problems\n        // because it has to still go through the followign checks:\n        // - version check\n        // - message body length check\n        // - sender and recipient (which should be in the same slots and same as address(this))\n        // - hook data handling (which will revert even if all the above checks pass)\n        bool isBurnMessageV1 = sender == address(cctpTokenMessenger);\n\n        if (isBurnMessageV1) {\n            // Handle burn message\n            require(\n                version == 1 &&\n                    messageBody.length >= BURN_MESSAGE_V2_HOOK_DATA_INDEX,\n                \"Invalid burn message\"\n            );\n\n            // Ensure the burn token is USDC\n            address burnToken = messageBody.extractAddress(\n                BURN_MESSAGE_V2_BURN_TOKEN_INDEX\n            );\n            require(burnToken == peerUsdcToken, \"Invalid burn token\");\n\n            // Address of caller of depositForBurn (or depositForBurnWithCaller) on source domain\n            sender = messageBody.extractAddress(\n                BURN_MESSAGE_V2_MESSAGE_SENDER_INDEX\n            );\n\n            recipient = messageBody.extractAddress(\n                BURN_MESSAGE_V2_RECIPIENT_INDEX\n            );\n        } else {\n            // We handle only Burn message or our custom messagee\n            require(\n                version == CrossChainStrategyHelper.ORIGIN_MESSAGE_VERSION,\n                \"Unsupported message version\"\n            );\n        }\n\n        // Ensure the recipient is this contract\n        // Both sender and recipient should be deployed to same address on both chains.\n        require(address(this) == recipient, \"Unexpected recipient address\");\n        require(sender == peerStrategy, \"Incorrect sender/recipient address\");\n\n        // Relay the message\n        // This step also mints USDC and transfers it to the recipient wallet\n        bool relaySuccess = cctpMessageTransmitter.receiveMessage(\n            message,\n            attestation\n        );\n        require(relaySuccess, \"Receive message failed\");\n\n        if (isBurnMessageV1) {\n            // Extract the hook data from the message body\n            bytes memory hookData = messageBody.extractSlice(\n                BURN_MESSAGE_V2_HOOK_DATA_INDEX,\n                messageBody.length\n            );\n\n            // Extract the token amount from the message body\n            uint256 tokenAmount = messageBody.extractUint256(\n                BURN_MESSAGE_V2_AMOUNT_INDEX\n            );\n\n            // Extract the fee executed from the message body\n            uint256 feeExecuted = messageBody.extractUint256(\n                BURN_MESSAGE_V2_FEE_EXECUTED_INDEX\n            );\n\n            // Call the _onTokenReceived function\n            _onTokenReceived(tokenAmount - feeExecuted, feeExecuted, hookData);\n        }\n    }\n\n    /***************************************\n                  Message utils\n    ****************************************/\n\n    /***************************************\n                  Nonce Handling\n    ****************************************/\n    /**\n     * @dev Checks if the last known transfer is pending.\n     *      Nonce starts at 1, so 0 is disregarded.\n     * @return True if a transfer is pending, false otherwise\n     */\n    function isTransferPending() public view returns (bool) {\n        return !nonceProcessed[lastTransferNonce];\n    }\n\n    /**\n     * @dev Checks if a given nonce is processed.\n     *      Nonce starts at 1, so 0 is disregarded.\n     * @param nonce Nonce to check\n     * @return True if the nonce is processed, false otherwise\n     */\n    function isNonceProcessed(uint64 nonce) public view returns (bool) {\n        return nonceProcessed[nonce];\n    }\n\n    /**\n     * @dev Marks a given nonce as processed.\n     *      Can only mark nonce as processed once. New nonce should\n     *      always be greater than the last known nonce. Also updates\n     *      the last known nonce.\n     * @param nonce Nonce to mark as processed\n     */\n    function _markNonceAsProcessed(uint64 nonce) internal {\n        uint64 lastNonce = lastTransferNonce;\n\n        // Can only mark latest nonce as processed\n        // Master strategy when receiving a message from the remote strategy\n        // will have lastNone == nonce, as the nonce is increase at the start\n        // of deposit / withdrawal flow.\n        // Remote strategy will have lastNonce < nonce, as a new nonce initiated\n        // from master will be greater than the last one.\n        require(nonce >= lastNonce, \"Nonce too low\");\n        // Can only mark nonce as processed once\n        require(!nonceProcessed[nonce], \"Nonce already processed\");\n\n        nonceProcessed[nonce] = true;\n        emit NonceProcessed(nonce);\n\n        if (nonce != lastNonce) {\n            // Update last known nonce\n            lastTransferNonce = nonce;\n            emit LastTransferNonceUpdated(nonce);\n        }\n    }\n\n    /**\n     * @dev Gets the next nonce to use.\n     *      Nonce starts at 1, so 0 is disregarded.\n     *      Reverts if last nonce hasn't been processed yet.\n     * @return Next nonce\n     */\n    function _getNextNonce() internal returns (uint64) {\n        uint64 nonce = lastTransferNonce;\n\n        require(nonceProcessed[nonce], \"Pending token transfer\");\n\n        nonce = nonce + 1;\n        lastTransferNonce = nonce;\n        emit LastTransferNonceUpdated(nonce);\n\n        return nonce;\n    }\n\n    /***************************************\n             Inheritence overrides\n    ****************************************/\n\n    /**\n     * @dev Called when the USDC is received from the CCTP\n     * @param tokenAmount The actual amount of USDC received (amount sent - fee executed)\n     * @param feeExecuted The fee executed\n     * @param payload The payload of the message (hook data)\n     */\n    function _onTokenReceived(\n        uint256 tokenAmount,\n        uint256 feeExecuted,\n        bytes memory payload\n    ) internal virtual;\n\n    /**\n     * @dev Called when the message is received\n     * @param payload The payload of the message\n     */\n    function _onMessageReceived(bytes memory payload) internal virtual;\n}\n"},{"file_path":"contracts/strategies/crosschain/CrossChainStrategyHelper.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title CrossChainStrategyHelper\n * @author Origin Protocol Inc\n * @dev This library is used to encode and decode the messages for the cross-chain strategy.\n *      It is used to ensure that the messages are valid and to get the message version and type.\n */\n\nimport { BytesHelper } from \"../../utils/BytesHelper.sol\";\n\nlibrary CrossChainStrategyHelper {\n    using BytesHelper for bytes;\n\n    uint32 public constant DEPOSIT_MESSAGE = 1;\n    uint32 public constant WITHDRAW_MESSAGE = 2;\n    uint32 public constant BALANCE_CHECK_MESSAGE = 3;\n\n    uint32 public constant CCTP_MESSAGE_VERSION = 1;\n    uint32 public constant ORIGIN_MESSAGE_VERSION = 1010;\n\n    // CCTP Message Header fields\n    // Ref: https://developers.circle.com/cctp/technical-guide#message-header\n    uint8 private constant VERSION_INDEX = 0;\n    uint8 private constant SOURCE_DOMAIN_INDEX = 4;\n    uint8 private constant SENDER_INDEX = 44;\n    uint8 private constant RECIPIENT_INDEX = 76;\n    uint8 private constant MESSAGE_BODY_INDEX = 148;\n\n    /**\n     * @dev Get the message version from the message.\n     *      It should always be 4 bytes long,\n     *      starting from the 0th index.\n     * @param message The message to get the version from\n     * @return The message version\n     */\n    function getMessageVersion(bytes memory message)\n        internal\n        pure\n        returns (uint32)\n    {\n        // uint32 bytes 0 to 4 is Origin message version\n        // uint32 bytes 4 to 8 is Message type\n        return message.extractUint32(0);\n    }\n\n    /**\n     * @dev Get the message type from the message.\n     *      It should always be 4 bytes long,\n     *      starting from the 4th index.\n     * @param message The message to get the type from\n     * @return The message type\n     */\n    function getMessageType(bytes memory message)\n        internal\n        pure\n        returns (uint32)\n    {\n        // uint32 bytes 0 to 4 is Origin message version\n        // uint32 bytes 4 to 8 is Message type\n        return message.extractUint32(4);\n    }\n\n    /**\n     * @dev Verify the message version and type.\n     *      The message version should be the same as the Origin message version,\n     *      and the message type should be the same as the expected message type.\n     * @param _message The message to verify\n     * @param _type The expected message type\n     */\n    function verifyMessageVersionAndType(bytes memory _message, uint32 _type)\n        internal\n        pure\n    {\n        require(\n            getMessageVersion(_message) == ORIGIN_MESSAGE_VERSION,\n            \"Invalid Origin Message Version\"\n        );\n        require(getMessageType(_message) == _type, \"Invalid Message type\");\n    }\n\n    /**\n     * @dev Get the message payload from the message.\n     *      The payload starts at the 8th byte.\n     * @param message The message to get the payload from\n     * @return The message payload\n     */\n    function getMessagePayload(bytes memory message)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        // uint32 bytes 0 to 4 is Origin message version\n        // uint32 bytes 4 to 8 is Message type\n        // Payload starts at byte 8\n        return message.extractSlice(8, message.length);\n    }\n\n    /**\n     * @dev Encode the deposit message.\n     *      The message version and type are always encoded in the message.\n     * @param nonce The nonce of the deposit\n     * @param depositAmount The amount of the deposit\n     * @return The encoded deposit message\n     */\n    function encodeDepositMessage(uint64 nonce, uint256 depositAmount)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return\n            abi.encodePacked(\n                ORIGIN_MESSAGE_VERSION,\n                DEPOSIT_MESSAGE,\n                abi.encode(nonce, depositAmount)\n            );\n    }\n\n    /**\n     * @dev Decode the deposit message.\n     *      The message version and type are verified in the message.\n     * @param message The message to decode\n     * @return The nonce and the amount of the deposit\n     */\n    function decodeDepositMessage(bytes memory message)\n        internal\n        pure\n        returns (uint64, uint256)\n    {\n        verifyMessageVersionAndType(message, DEPOSIT_MESSAGE);\n\n        (uint64 nonce, uint256 depositAmount) = abi.decode(\n            getMessagePayload(message),\n            (uint64, uint256)\n        );\n        return (nonce, depositAmount);\n    }\n\n    /**\n     * @dev Encode the withdrawal message.\n     *      The message version and type are always encoded in the message.\n     * @param nonce The nonce of the withdrawal\n     * @param withdrawAmount The amount of the withdrawal\n     * @return The encoded withdrawal message\n     */\n    function encodeWithdrawMessage(uint64 nonce, uint256 withdrawAmount)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return\n            abi.encodePacked(\n                ORIGIN_MESSAGE_VERSION,\n                WITHDRAW_MESSAGE,\n                abi.encode(nonce, withdrawAmount)\n            );\n    }\n\n    /**\n     * @dev Decode the withdrawal message.\n     *      The message version and type are verified in the message.\n     * @param message The message to decode\n     * @return The nonce and the amount of the withdrawal\n     */\n    function decodeWithdrawMessage(bytes memory message)\n        internal\n        pure\n        returns (uint64, uint256)\n    {\n        verifyMessageVersionAndType(message, WITHDRAW_MESSAGE);\n\n        (uint64 nonce, uint256 withdrawAmount) = abi.decode(\n            getMessagePayload(message),\n            (uint64, uint256)\n        );\n        return (nonce, withdrawAmount);\n    }\n\n    /**\n     * @dev Encode the balance check message.\n     *      The message version and type are always encoded in the message.\n     * @param nonce The nonce of the balance check\n     * @param balance The balance to check\n     * @param transferConfirmation Indicates if the message is a transfer confirmation. This is true\n     *                            when the message is a result of a deposit or a withdrawal.\n     * @return The encoded balance check message\n     */\n    function encodeBalanceCheckMessage(\n        uint64 nonce,\n        uint256 balance,\n        bool transferConfirmation,\n        uint256 timestamp\n    ) internal pure returns (bytes memory) {\n        return\n            abi.encodePacked(\n                ORIGIN_MESSAGE_VERSION,\n                BALANCE_CHECK_MESSAGE,\n                abi.encode(nonce, balance, transferConfirmation, timestamp)\n            );\n    }\n\n    /**\n     * @dev Decode the balance check message.\n     *      The message version and type are verified in the message.\n     * @param message The message to decode\n     * @return The nonce, the balance and indicates if the message is a transfer confirmation\n     */\n    function decodeBalanceCheckMessage(bytes memory message)\n        internal\n        pure\n        returns (\n            uint64,\n            uint256,\n            bool,\n            uint256\n        )\n    {\n        verifyMessageVersionAndType(message, BALANCE_CHECK_MESSAGE);\n\n        (\n            uint64 nonce,\n            uint256 balance,\n            bool transferConfirmation,\n            uint256 timestamp\n        ) = abi.decode(\n                getMessagePayload(message),\n                (uint64, uint256, bool, uint256)\n            );\n        return (nonce, balance, transferConfirmation, timestamp);\n    }\n\n    /**\n     * @dev Decode the CCTP message header\n     * @param message Message to decode\n     * @return version Version of the message\n     * @return sourceDomainID Source domain ID\n     * @return sender Sender of the message\n     * @return recipient Recipient of the message\n     * @return messageBody Message body\n     */\n    function decodeMessageHeader(bytes memory message)\n        internal\n        pure\n        returns (\n            uint32 version,\n            uint32 sourceDomainID,\n            address sender,\n            address recipient,\n            bytes memory messageBody\n        )\n    {\n        version = message.extractUint32(VERSION_INDEX);\n        sourceDomainID = message.extractUint32(SOURCE_DOMAIN_INDEX);\n        // Address of MessageTransmitterV2 caller on source domain\n        sender = message.extractAddress(SENDER_INDEX);\n        // Address to handle message body on destination domain\n        recipient = message.extractAddress(RECIPIENT_INDEX);\n        messageBody = message.extractSlice(MESSAGE_BODY_INDEX, message.length);\n    }\n}\n"},{"file_path":"contracts/token/OUSD.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title OUSD Token Contract\n * @dev ERC20 compatible contract for OUSD\n * @dev Implements an elastic supply\n * @author Origin Protocol Inc\n */\nimport { IVault } from \"../interfaces/IVault.sol\";\nimport { Governable } from \"../governance/Governable.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\ncontract OUSD is Governable {\n    using SafeCast for int256;\n    using SafeCast for uint256;\n\n    /// @dev Event triggered when the supply changes\n    /// @param totalSupply Updated token total supply\n    /// @param rebasingCredits Updated token rebasing credits\n    /// @param rebasingCreditsPerToken Updated token rebasing credits per token\n    event TotalSupplyUpdatedHighres(\n        uint256 totalSupply,\n        uint256 rebasingCredits,\n        uint256 rebasingCreditsPerToken\n    );\n    /// @dev Event triggered when an account opts in for rebasing\n    /// @param account Address of the account\n    event AccountRebasingEnabled(address account);\n    /// @dev Event triggered when an account opts out of rebasing\n    /// @param account Address of the account\n    event AccountRebasingDisabled(address account);\n    /// @dev Emitted when `value` tokens are moved from one account `from` to\n    ///      another `to`.\n    /// @param from Address of the account tokens are moved from\n    /// @param to Address of the account tokens are moved to\n    /// @param value Amount of tokens transferred\n    event Transfer(address indexed from, address indexed to, uint256 value);\n    /// @dev Emitted when the allowance of a `spender` for an `owner` is set by\n    ///      a call to {approve}. `value` is the new allowance.\n    /// @param owner Address of the owner approving allowance\n    /// @param spender Address of the spender allowance is granted to\n    /// @param value Amount of tokens spender can transfer\n    event Approval(\n        address indexed owner,\n        address indexed spender,\n        uint256 value\n    );\n    /// @dev Yield resulting from {changeSupply} that a `source` account would\n    ///      receive is directed to `target` account.\n    /// @param source Address of the source forwarding the yield\n    /// @param target Address of the target receiving the yield\n    event YieldDelegated(address source, address target);\n    /// @dev Yield delegation from `source` account to the `target` account is\n    ///      suspended.\n    /// @param source Address of the source suspending yield forwarding\n    /// @param target Address of the target no longer receiving yield from `source`\n    ///        account\n    event YieldUndelegated(address source, address target);\n\n    enum RebaseOptions {\n        NotSet,\n        StdNonRebasing,\n        StdRebasing,\n        YieldDelegationSource,\n        YieldDelegationTarget\n    }\n\n    uint256[154] private _gap; // Slots to align with deployed contract\n    uint256 private constant MAX_SUPPLY = type(uint128).max;\n    /// @dev The amount of tokens in existence\n    uint256 public totalSupply;\n    mapping(address => mapping(address => uint256)) private allowances;\n    /// @dev The vault with privileges to execute {mint}, {burn}\n    ///     and {changeSupply}\n    address public vaultAddress;\n    mapping(address => uint256) internal creditBalances;\n    // the 2 storage variables below need trailing underscores to not name collide with public functions\n    uint256 private rebasingCredits_; // Sum of all rebasing credits (creditBalances for rebasing accounts)\n    uint256 private rebasingCreditsPerToken_;\n    /// @dev The amount of tokens that are not rebasing - receiving yield\n    uint256 public nonRebasingSupply;\n    mapping(address => uint256) internal alternativeCreditsPerToken;\n    /// @dev A map of all addresses and their respective RebaseOptions\n    mapping(address => RebaseOptions) public rebaseState;\n    mapping(address => uint256) private __deprecated_isUpgraded;\n    /// @dev A map of addresses that have yields forwarded to. This is an\n    ///      inverse mapping of {yieldFrom}\n    /// Key Account forwarding yield\n    /// Value Account receiving yield\n    mapping(address => address) public yieldTo;\n    /// @dev A map of addresses that are receiving the yield. This is an\n    ///      inverse mapping of {yieldTo}\n    /// Key Account receiving yield\n    /// Value Account forwarding yield\n    mapping(address => address) public yieldFrom;\n\n    uint256 private constant RESOLUTION_INCREASE = 1e9;\n    uint256[34] private __gap; // including below gap totals up to 200\n\n    /// @dev Verifies that the caller is the Governor or Strategist.\n    modifier onlyGovernorOrStrategist() {\n        require(\n            isGovernor() || msg.sender == IVault(vaultAddress).strategistAddr(),\n            \"Caller is not the Strategist or Governor\"\n        );\n        _;\n    }\n\n    /// @dev Initializes the contract and sets necessary variables.\n    /// @param _vaultAddress Address of the vault contract\n    /// @param _initialCreditsPerToken The starting rebasing credits per token.\n    function initialize(address _vaultAddress, uint256 _initialCreditsPerToken)\n        external\n        onlyGovernor\n    {\n        require(_vaultAddress != address(0), \"Zero vault address\");\n        require(vaultAddress == address(0), \"Already initialized\");\n\n        rebasingCreditsPerToken_ = _initialCreditsPerToken;\n        vaultAddress = _vaultAddress;\n    }\n\n    /// @dev Returns the symbol of the token, a shorter version\n    ///      of the name.\n    function symbol() external pure virtual returns (string memory) {\n        return \"OUSD\";\n    }\n\n    /// @dev Returns the name of the token.\n    function name() external pure virtual returns (string memory) {\n        return \"Origin Dollar\";\n    }\n\n    /// @dev Returns the number of decimals used to get its user representation.\n    function decimals() external pure virtual returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev Verifies that the caller is the Vault contract\n     */\n    modifier onlyVault() {\n        require(vaultAddress == msg.sender, \"Caller is not the Vault\");\n        _;\n    }\n\n    /**\n     * @return High resolution rebasingCreditsPerToken\n     */\n    function rebasingCreditsPerTokenHighres() external view returns (uint256) {\n        return rebasingCreditsPerToken_;\n    }\n\n    /**\n     * @return Low resolution rebasingCreditsPerToken\n     */\n    function rebasingCreditsPerToken() external view returns (uint256) {\n        return rebasingCreditsPerToken_ / RESOLUTION_INCREASE;\n    }\n\n    /**\n     * @return High resolution total number of rebasing credits\n     */\n    function rebasingCreditsHighres() external view returns (uint256) {\n        return rebasingCredits_;\n    }\n\n    /**\n     * @return Low resolution total number of rebasing credits\n     */\n    function rebasingCredits() external view returns (uint256) {\n        return rebasingCredits_ / RESOLUTION_INCREASE;\n    }\n\n    /**\n     * @notice Gets the balance of the specified address.\n     * @param _account Address to query the balance of.\n     * @return A uint256 representing the amount of base units owned by the\n     *         specified address.\n     */\n    function balanceOf(address _account) public view returns (uint256) {\n        RebaseOptions state = rebaseState[_account];\n        if (state == RebaseOptions.YieldDelegationSource) {\n            // Saves a slot read when transferring to or from a yield delegating source\n            // since we know creditBalances equals the balance.\n            return creditBalances[_account];\n        }\n        uint256 baseBalance = (creditBalances[_account] * 1e18) /\n            _creditsPerToken(_account);\n        if (state == RebaseOptions.YieldDelegationTarget) {\n            // creditBalances of yieldFrom accounts equals token balances\n            return baseBalance - creditBalances[yieldFrom[_account]];\n        }\n        return baseBalance;\n    }\n\n    /**\n     * @notice Gets the credits balance of the specified address.\n     * @dev Backwards compatible with old low res credits per token.\n     * @param _account The address to query the balance of.\n     * @return (uint256, uint256) Credit balance and credits per token of the\n     *         address\n     */\n    function creditsBalanceOf(address _account)\n        external\n        view\n        returns (uint256, uint256)\n    {\n        uint256 cpt = _creditsPerToken(_account);\n        if (cpt == 1e27) {\n            // For a period before the resolution upgrade, we created all new\n            // contract accounts at high resolution. Since they are not changing\n            // as a result of this upgrade, we will return their true values\n            return (creditBalances[_account], cpt);\n        } else {\n            return (\n                creditBalances[_account] / RESOLUTION_INCREASE,\n                cpt / RESOLUTION_INCREASE\n            );\n        }\n    }\n\n    /**\n     * @notice Gets the credits balance of the specified address.\n     * @param _account The address to query the balance of.\n     * @return (uint256, uint256, bool) Credit balance, credits per token of the\n     *         address, and isUpgraded\n     */\n    function creditsBalanceOfHighres(address _account)\n        external\n        view\n        returns (\n            uint256,\n            uint256,\n            bool\n        )\n    {\n        return (\n            creditBalances[_account],\n            _creditsPerToken(_account),\n            true // all accounts have their resolution \"upgraded\"\n        );\n    }\n\n    // Backwards compatible view\n    function nonRebasingCreditsPerToken(address _account)\n        external\n        view\n        returns (uint256)\n    {\n        return alternativeCreditsPerToken[_account];\n    }\n\n    /**\n     * @notice Transfer tokens to a specified address.\n     * @param _to the address to transfer to.\n     * @param _value the amount to be transferred.\n     * @return true on success.\n     */\n    function transfer(address _to, uint256 _value) external returns (bool) {\n        require(_to != address(0), \"Transfer to zero address\");\n\n        _executeTransfer(msg.sender, _to, _value);\n\n        emit Transfer(msg.sender, _to, _value);\n        return true;\n    }\n\n    /**\n     * @notice Transfer tokens from one address to another.\n     * @param _from The address you want to send tokens from.\n     * @param _to The address you want to transfer to.\n     * @param _value The amount of tokens to be transferred.\n     * @return true on success.\n     */\n    function transferFrom(\n        address _from,\n        address _to,\n        uint256 _value\n    ) external returns (bool) {\n        require(_to != address(0), \"Transfer to zero address\");\n        uint256 userAllowance = allowances[_from][msg.sender];\n        require(_value <= userAllowance, \"Allowance exceeded\");\n\n        unchecked {\n            allowances[_from][msg.sender] = userAllowance - _value;\n        }\n\n        _executeTransfer(_from, _to, _value);\n\n        emit Transfer(_from, _to, _value);\n        return true;\n    }\n\n    function _executeTransfer(\n        address _from,\n        address _to,\n        uint256 _value\n    ) internal {\n        (\n            int256 fromRebasingCreditsDiff,\n            int256 fromNonRebasingSupplyDiff\n        ) = _adjustAccount(_from, -_value.toInt256());\n        (\n            int256 toRebasingCreditsDiff,\n            int256 toNonRebasingSupplyDiff\n        ) = _adjustAccount(_to, _value.toInt256());\n\n        _adjustGlobals(\n            fromRebasingCreditsDiff + toRebasingCreditsDiff,\n            fromNonRebasingSupplyDiff + toNonRebasingSupplyDiff\n        );\n    }\n\n    function _adjustAccount(address _account, int256 _balanceChange)\n        internal\n        returns (int256 rebasingCreditsDiff, int256 nonRebasingSupplyDiff)\n    {\n        RebaseOptions state = rebaseState[_account];\n        int256 currentBalance = balanceOf(_account).toInt256();\n        if (currentBalance + _balanceChange < 0) {\n            revert(\"Transfer amount exceeds balance\");\n        }\n        uint256 newBalance = (currentBalance + _balanceChange).toUint256();\n\n        if (state == RebaseOptions.YieldDelegationSource) {\n            address target = yieldTo[_account];\n            uint256 targetOldBalance = balanceOf(target);\n            uint256 targetNewCredits = _balanceToRebasingCredits(\n                targetOldBalance + newBalance\n            );\n            rebasingCreditsDiff =\n                targetNewCredits.toInt256() -\n                creditBalances[target].toInt256();\n\n            creditBalances[_account] = newBalance;\n            creditBalances[target] = targetNewCredits;\n        } else if (state == RebaseOptions.YieldDelegationTarget) {\n            uint256 newCredits = _balanceToRebasingCredits(\n                newBalance + creditBalances[yieldFrom[_account]]\n            );\n            rebasingCreditsDiff =\n                newCredits.toInt256() -\n                creditBalances[_account].toInt256();\n            creditBalances[_account] = newCredits;\n        } else {\n            _autoMigrate(_account);\n            uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[\n                _account\n            ];\n            if (alternativeCreditsPerTokenMem > 0) {\n                nonRebasingSupplyDiff = _balanceChange;\n                if (alternativeCreditsPerTokenMem != 1e18) {\n                    alternativeCreditsPerToken[_account] = 1e18;\n                }\n                creditBalances[_account] = newBalance;\n            } else {\n                uint256 newCredits = _balanceToRebasingCredits(newBalance);\n                rebasingCreditsDiff =\n                    newCredits.toInt256() -\n                    creditBalances[_account].toInt256();\n                creditBalances[_account] = newCredits;\n            }\n        }\n    }\n\n    function _adjustGlobals(\n        int256 _rebasingCreditsDiff,\n        int256 _nonRebasingSupplyDiff\n    ) internal {\n        if (_rebasingCreditsDiff != 0) {\n            rebasingCredits_ = (rebasingCredits_.toInt256() +\n                _rebasingCreditsDiff).toUint256();\n        }\n        if (_nonRebasingSupplyDiff != 0) {\n            nonRebasingSupply = (nonRebasingSupply.toInt256() +\n                _nonRebasingSupplyDiff).toUint256();\n        }\n    }\n\n    /**\n     * @notice Function to check the amount of tokens that _owner has allowed\n     *      to `_spender`.\n     * @param _owner The address which owns the funds.\n     * @param _spender The address which will spend the funds.\n     * @return The number of tokens still available for the _spender.\n     */\n    function allowance(address _owner, address _spender)\n        external\n        view\n        returns (uint256)\n    {\n        return allowances[_owner][_spender];\n    }\n\n    /**\n     * @notice Approve the passed address to spend the specified amount of\n     *      tokens on behalf of msg.sender.\n     * @param _spender The address which will spend the funds.\n     * @param _value The amount of tokens to be spent.\n     * @return true on success.\n     */\n    function approve(address _spender, uint256 _value) external returns (bool) {\n        allowances[msg.sender][_spender] = _value;\n        emit Approval(msg.sender, _spender, _value);\n        return true;\n    }\n\n    /**\n     * @notice Creates `_amount` tokens and assigns them to `_account`,\n     *     increasing the total supply.\n     */\n    function mint(address _account, uint256 _amount) external onlyVault {\n        require(_account != address(0), \"Mint to the zero address\");\n\n        // Account\n        (\n            int256 toRebasingCreditsDiff,\n            int256 toNonRebasingSupplyDiff\n        ) = _adjustAccount(_account, _amount.toInt256());\n        // Globals\n        _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);\n        totalSupply = totalSupply + _amount;\n\n        require(totalSupply < MAX_SUPPLY, \"Max supply\");\n        emit Transfer(address(0), _account, _amount);\n    }\n\n    /**\n     * @notice Destroys `_amount` tokens from `_account`,\n     *     reducing the total supply.\n     */\n    function burn(address _account, uint256 _amount) external onlyVault {\n        require(_account != address(0), \"Burn from the zero address\");\n        if (_amount == 0) {\n            return;\n        }\n\n        // Account\n        (\n            int256 toRebasingCreditsDiff,\n            int256 toNonRebasingSupplyDiff\n        ) = _adjustAccount(_account, -_amount.toInt256());\n        // Globals\n        _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff);\n        totalSupply = totalSupply - _amount;\n\n        emit Transfer(_account, address(0), _amount);\n    }\n\n    /**\n     * @dev Get the credits per token for an account. Returns a fixed amount\n     *      if the account is non-rebasing.\n     * @param _account Address of the account.\n     */\n    function _creditsPerToken(address _account)\n        internal\n        view\n        returns (uint256)\n    {\n        uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[\n            _account\n        ];\n        if (alternativeCreditsPerTokenMem != 0) {\n            return alternativeCreditsPerTokenMem;\n        } else {\n            return rebasingCreditsPerToken_;\n        }\n    }\n\n    /**\n     * @dev Auto migrate contracts to be non rebasing,\n     *     unless they have opted into yield.\n     * @param _account Address of the account.\n     */\n    function _autoMigrate(address _account) internal {\n        uint256 codeLen = _account.code.length;\n        bool isEOA = (codeLen == 0) ||\n            (codeLen == 23 && bytes3(_account.code) == 0xef0100);\n        // In previous code versions, contracts would not have had their\n        // rebaseState[_account] set to RebaseOptions.NonRebasing when migrated\n        // therefore we check the actual accounting used on the account as well.\n        if (\n            (!isEOA) &&\n            rebaseState[_account] == RebaseOptions.NotSet &&\n            alternativeCreditsPerToken[_account] == 0\n        ) {\n            _rebaseOptOut(_account);\n        }\n    }\n\n    /**\n     * @dev Calculates credits from contract's global rebasingCreditsPerToken_, and\n     *      also balance that corresponds to those credits. The latter is important\n     *      when adjusting the contract's global nonRebasingSupply to circumvent any\n     *      possible rounding errors.\n     *\n     * @param _balance Balance of the account.\n     */\n    function _balanceToRebasingCredits(uint256 _balance)\n        internal\n        view\n        returns (uint256 rebasingCredits)\n    {\n        // Rounds up, because we need to ensure that accounts always have\n        // at least the balance that they should have.\n        // Note this should always be used on an absolute account value,\n        // not on a possibly negative diff, because then the rounding would be wrong.\n        return ((_balance) * rebasingCreditsPerToken_ + 1e18 - 1) / 1e18;\n    }\n\n    /**\n     * @notice The calling account will start receiving yield after a successful call.\n     * @param _account Address of the account.\n     */\n    function governanceRebaseOptIn(address _account) external onlyGovernor {\n        require(_account != address(0), \"Zero address not allowed\");\n        _rebaseOptIn(_account);\n    }\n\n    /**\n     * @notice The calling account will start receiving yield after a successful call.\n     */\n    function rebaseOptIn() external {\n        _rebaseOptIn(msg.sender);\n    }\n\n    function _rebaseOptIn(address _account) internal {\n        uint256 balance = balanceOf(_account);\n\n        // prettier-ignore\n        require(\n            alternativeCreditsPerToken[_account] > 0 ||\n                // Accounts may explicitly `rebaseOptIn` regardless of\n                // accounting if they have a 0 balance.\n                creditBalances[_account] == 0\n            ,\n            \"Account must be non-rebasing\"\n        );\n        RebaseOptions state = rebaseState[_account];\n        // prettier-ignore\n        require(\n            state == RebaseOptions.StdNonRebasing ||\n                state == RebaseOptions.NotSet,\n            \"Only standard non-rebasing accounts can opt in\"\n        );\n\n        uint256 newCredits = _balanceToRebasingCredits(balance);\n\n        // Account\n        rebaseState[_account] = RebaseOptions.StdRebasing;\n        alternativeCreditsPerToken[_account] = 0;\n        creditBalances[_account] = newCredits;\n        // Globals\n        _adjustGlobals(newCredits.toInt256(), -balance.toInt256());\n\n        emit AccountRebasingEnabled(_account);\n    }\n\n    /**\n     * @notice The calling account will no longer receive yield\n     */\n    function rebaseOptOut() external {\n        _rebaseOptOut(msg.sender);\n    }\n\n    function _rebaseOptOut(address _account) internal {\n        require(\n            alternativeCreditsPerToken[_account] == 0,\n            \"Account must be rebasing\"\n        );\n        RebaseOptions state = rebaseState[_account];\n        require(\n            state == RebaseOptions.StdRebasing || state == RebaseOptions.NotSet,\n            \"Only standard rebasing accounts can opt out\"\n        );\n\n        uint256 oldCredits = creditBalances[_account];\n        uint256 balance = balanceOf(_account);\n\n        // Account\n        rebaseState[_account] = RebaseOptions.StdNonRebasing;\n        alternativeCreditsPerToken[_account] = 1e18;\n        creditBalances[_account] = balance;\n        // Globals\n        _adjustGlobals(-oldCredits.toInt256(), balance.toInt256());\n\n        emit AccountRebasingDisabled(_account);\n    }\n\n    /**\n     * @notice Distribute yield to users. This changes the exchange rate\n     *  between \"credits\" and OUSD tokens to change rebasing user's balances.\n     * @param _newTotalSupply New total supply of OUSD.\n     */\n    function changeSupply(uint256 _newTotalSupply) external onlyVault {\n        require(totalSupply > 0, \"Cannot increase 0 supply\");\n\n        if (totalSupply == _newTotalSupply) {\n            emit TotalSupplyUpdatedHighres(\n                totalSupply,\n                rebasingCredits_,\n                rebasingCreditsPerToken_\n            );\n            return;\n        }\n\n        totalSupply = _newTotalSupply > MAX_SUPPLY\n            ? MAX_SUPPLY\n            : _newTotalSupply;\n\n        uint256 rebasingSupply = totalSupply - nonRebasingSupply;\n        // round up in the favour of the protocol\n        rebasingCreditsPerToken_ =\n            (rebasingCredits_ * 1e18 + rebasingSupply - 1) /\n            rebasingSupply;\n\n        require(rebasingCreditsPerToken_ > 0, \"Invalid change in supply\");\n\n        emit TotalSupplyUpdatedHighres(\n            totalSupply,\n            rebasingCredits_,\n            rebasingCreditsPerToken_\n        );\n    }\n\n    /*\n     * @notice Send the yield from one account to another account.\n     *         Each account keeps its own balances.\n     */\n    function delegateYield(address _from, address _to)\n        external\n        onlyGovernorOrStrategist\n    {\n        require(_from != address(0), \"Zero from address not allowed\");\n        require(_to != address(0), \"Zero to address not allowed\");\n\n        require(_from != _to, \"Cannot delegate to self\");\n        require(\n            yieldFrom[_to] == address(0) &&\n                yieldTo[_to] == address(0) &&\n                yieldFrom[_from] == address(0) &&\n                yieldTo[_from] == address(0),\n            \"Blocked by existing yield delegation\"\n        );\n        RebaseOptions stateFrom = rebaseState[_from];\n        RebaseOptions stateTo = rebaseState[_to];\n\n        require(\n            stateFrom == RebaseOptions.NotSet ||\n                stateFrom == RebaseOptions.StdNonRebasing ||\n                stateFrom == RebaseOptions.StdRebasing,\n            \"Invalid rebaseState from\"\n        );\n\n        require(\n            stateTo == RebaseOptions.NotSet ||\n                stateTo == RebaseOptions.StdNonRebasing ||\n                stateTo == RebaseOptions.StdRebasing,\n            \"Invalid rebaseState to\"\n        );\n\n        if (alternativeCreditsPerToken[_from] == 0) {\n            _rebaseOptOut(_from);\n        }\n        if (alternativeCreditsPerToken[_to] > 0) {\n            _rebaseOptIn(_to);\n        }\n\n        uint256 fromBalance = balanceOf(_from);\n        uint256 toBalance = balanceOf(_to);\n        uint256 oldToCredits = creditBalances[_to];\n        uint256 newToCredits = _balanceToRebasingCredits(\n            fromBalance + toBalance\n        );\n\n        // Set up the bidirectional links\n        yieldTo[_from] = _to;\n        yieldFrom[_to] = _from;\n\n        // Local\n        rebaseState[_from] = RebaseOptions.YieldDelegationSource;\n        alternativeCreditsPerToken[_from] = 1e18;\n        creditBalances[_from] = fromBalance;\n        rebaseState[_to] = RebaseOptions.YieldDelegationTarget;\n        creditBalances[_to] = newToCredits;\n\n        // Global\n        int256 creditsChange = newToCredits.toInt256() -\n            oldToCredits.toInt256();\n        _adjustGlobals(creditsChange, -(fromBalance).toInt256());\n        emit YieldDelegated(_from, _to);\n    }\n\n    /*\n     * @notice Stop sending the yield from one account to another account.\n     */\n    function undelegateYield(address _from) external onlyGovernorOrStrategist {\n        // Require a delegation, which will also ensure a valid delegation\n        require(yieldTo[_from] != address(0), \"Zero address not allowed\");\n\n        address to = yieldTo[_from];\n        uint256 fromBalance = balanceOf(_from);\n        uint256 toBalance = balanceOf(to);\n        uint256 oldToCredits = creditBalances[to];\n        uint256 newToCredits = _balanceToRebasingCredits(toBalance);\n\n        // Remove the bidirectional links\n        yieldFrom[to] = address(0);\n        yieldTo[_from] = address(0);\n\n        // Local\n        rebaseState[_from] = RebaseOptions.StdNonRebasing;\n        // alternativeCreditsPerToken[from] already 1e18 from `delegateYield()`\n        creditBalances[_from] = fromBalance;\n        rebaseState[to] = RebaseOptions.StdRebasing;\n        // alternativeCreditsPerToken[to] already 0 from `delegateYield()`\n        creditBalances[to] = newToCredits;\n\n        // Global\n        int256 creditsChange = newToCredits.toInt256() -\n            oldToCredits.toInt256();\n        _adjustGlobals(creditsChange, fromBalance.toInt256());\n        emit YieldUndelegated(_from, to);\n    }\n}\n"},{"file_path":"contracts/utils/BytesHelper.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nuint256 constant UINT32_LENGTH = 4;\nuint256 constant UINT64_LENGTH = 8;\nuint256 constant UINT256_LENGTH = 32;\n// Address is 20 bytes, but we expect the data to be padded with 0s to 32 bytes\nuint256 constant ADDRESS_LENGTH = 32;\n\nlibrary BytesHelper {\n    /**\n     * @dev Extract a slice from bytes memory\n     * @param data The bytes memory to slice\n     * @param start The start index (inclusive)\n     * @param end The end index (exclusive)\n     * @return result A new bytes memory containing the slice\n     */\n    function extractSlice(\n        bytes memory data,\n        uint256 start,\n        uint256 end\n    ) internal pure returns (bytes memory) {\n        require(end >= start, \"Invalid slice range\");\n        require(end <= data.length, \"Slice end exceeds data length\");\n\n        uint256 length = end - start;\n        bytes memory result = new bytes(length);\n\n        // Simple byte-by-byte copy\n        for (uint256 i = 0; i < length; i++) {\n            result[i] = data[start + i];\n        }\n\n        return result;\n    }\n\n    /**\n     * @dev Decode a uint32 from a bytes memory\n     * @param data The bytes memory to decode\n     * @return uint32 The decoded uint32\n     */\n    function decodeUint32(bytes memory data) internal pure returns (uint32) {\n        require(data.length == 4, \"Invalid data length\");\n        return uint32(uint256(bytes32(data)) >> 224);\n    }\n\n    /**\n     * @dev Extract a uint32 from a bytes memory\n     * @param data The bytes memory to extract from\n     * @param start The start index (inclusive)\n     * @return uint32 The extracted uint32\n     */\n    function extractUint32(bytes memory data, uint256 start)\n        internal\n        pure\n        returns (uint32)\n    {\n        return decodeUint32(extractSlice(data, start, start + UINT32_LENGTH));\n    }\n\n    /**\n     * @dev Decode an address from a bytes memory.\n     *      Expects the data to be padded with 0s to 32 bytes.\n     * @param data The bytes memory to decode\n     * @return address The decoded address\n     */\n    function decodeAddress(bytes memory data) internal pure returns (address) {\n        // We expect the data to be padded with 0s, so length is 32 not 20\n        require(data.length == 32, \"Invalid data length\");\n        return abi.decode(data, (address));\n    }\n\n    /**\n     * @dev Extract an address from a bytes memory\n     * @param data The bytes memory to extract from\n     * @param start The start index (inclusive)\n     * @return address The extracted address\n     */\n    function extractAddress(bytes memory data, uint256 start)\n        internal\n        pure\n        returns (address)\n    {\n        return decodeAddress(extractSlice(data, start, start + ADDRESS_LENGTH));\n    }\n\n    /**\n     * @dev Decode a uint256 from a bytes memory\n     * @param data The bytes memory to decode\n     * @return uint256 The decoded uint256\n     */\n    function decodeUint256(bytes memory data) internal pure returns (uint256) {\n        require(data.length == 32, \"Invalid data length\");\n        return abi.decode(data, (uint256));\n    }\n\n    /**\n     * @dev Extract a uint256 from a bytes memory\n     * @param data The bytes memory to extract from\n     * @param start The start index (inclusive)\n     * @return uint256 The extracted uint256\n     */\n    function extractUint256(bytes memory data, uint256 start)\n        internal\n        pure\n        returns (uint256)\n    {\n        return decodeUint256(extractSlice(data, start, start + UINT256_LENGTH));\n    }\n}\n"},{"file_path":"contracts/utils/Helpers.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport { IBasicToken } from \"../interfaces/IBasicToken.sol\";\n\nlibrary Helpers {\n    /**\n     * @notice Fetch the `symbol()` from an ERC20 token\n     * @dev Grabs the `symbol()` from a contract\n     * @param _token Address of the ERC20 token\n     * @return string Symbol of the ERC20 token\n     */\n    function getSymbol(address _token) internal view returns (string memory) {\n        string memory symbol = IBasicToken(_token).symbol();\n        return symbol;\n    }\n\n    /**\n     * @notice Fetch the `decimals()` from an ERC20 token\n     * @dev Grabs the `decimals()` from a contract and fails if\n     *      the decimal value does not live within a certain range\n     * @param _token Address of the ERC20 token\n     * @return uint256 Decimals of the ERC20 token\n     */\n    function getDecimals(address _token) internal view returns (uint256) {\n        uint256 decimals = IBasicToken(_token).decimals();\n        require(\n            decimals >= 4 && decimals <= 18,\n            \"Token must have sufficient decimal places\"\n        );\n\n        return decimals;\n    }\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"components":[{"internalType":"address","name":"platformAddress","type":"address"},{"internalType":"address","name":"vaultAddress","type":"address"}],"internalType":"struct InitializableAbstractStrategy.BaseStrategyConfig","name":"_stratConfig","type":"tuple"},{"components":[{"internalType":"address","name":"cctpTokenMessenger","type":"address"},{"internalType":"address","name":"cctpMessageTransmitter","type":"address"},{"internalType":"uint32","name":"peerDomainID","type":"uint32"},{"internalType":"address","name":"peerStrategy","type":"address"},{"internalType":"address","name":"usdcToken","type":"address"},{"internalType":"address","name":"peerUsdcToken","type":"address"}],"internalType":"struct AbstractCCTPIntegrator.CCTPIntegrationConfig","name":"_cctpConfig","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"nonce","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isTooOld","type":"bool"}],"name":"BalanceCheckIgnored","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"feePremiumBps","type":"uint16"}],"name":"CCTPFeePremiumBpsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"minFinalityThreshold","type":"uint16"}],"name":"CCTPMinFinalityThresholdSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_asset","type":"address"},{"indexed":false,"internalType":"address","name":"_pToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousGovernor","type":"address"},{"indexed":true,"internalType":"address","name":"newGovernor","type":"address"}],"name":"GovernorshipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_oldHarvesterAddress","type":"address"},{"indexed":false,"internalType":"address","name":"_newHarvesterAddress","type":"address"}],"name":"HarvesterAddressesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"lastTransferNonce","type":"uint64"}],"name":"LastTransferNonceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"destinationDomain","type":"uint32"},{"indexed":false,"internalType":"address","name":"peerStrategy","type":"address"},{"indexed":false,"internalType":"uint32","name":"minFinalityThreshold","type":"uint32"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"}],"name":"MessageTransmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"nonce","type":"uint64"}],"name":"NonceProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"}],"name":"OperatorChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_asset","type":"address"},{"indexed":false,"internalType":"address","name":"_pToken","type":"address"}],"name":"PTokenAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_asset","type":"address"},{"indexed":false,"internalType":"address","name":"_pToken","type":"address"}],"name":"PTokenRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousGovernor","type":"address"},{"indexed":true,"internalType":"address","name":"newGovernor","type":"address"}],"name":"PendingGovernorshipTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"balance","type":"uint256"}],"name":"RemoteStrategyBalanceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"_oldAddresses","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"_newAddresses","type":"address[]"}],"name":"RewardTokenAddressesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"address","name":"rewardToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardTokenCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"destinationDomain","type":"uint32"},{"indexed":false,"internalType":"address","name":"peerStrategy","type":"address"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxFee","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"minFinalityThreshold","type":"uint32"},{"indexed":false,"internalType":"bytes","name":"hookData","type":"bytes"}],"name":"TokensBridged","type":"event"},{"anonymous":false,"inputs":[],"name":"WithdrawAllSkipped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_asset","type":"address"},{"indexed":false,"internalType":"address","name":"_pToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Withdrawal","type":"event"},{"inputs":[],"name":"MAX_TRANSFER_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_TRANSFER_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"assetToPToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cctpMessageTransmitter","outputs":[{"internalType":"contract ICCTPMessageTransmitter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cctpTokenMessenger","outputs":[{"internalType":"contract ICCTPTokenMessenger","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"checkBalance","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collectRewardTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feePremiumBps","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardTokenAddresses","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"sourceDomain","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint32","name":"finalityThresholdExecuted","type":"uint32"},{"internalType":"bytes","name":"messageBody","type":"bytes"}],"name":"handleReceiveFinalizedMessage","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"sourceDomain","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint32","name":"finalityThresholdExecuted","type":"uint32"},{"internalType":"bytes","name":"messageBody","type":"bytes"}],"name":"handleReceiveUnfinalizedMessage","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"harvesterAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"uint16","name":"_minFinalityThreshold","type":"uint16"},{"internalType":"uint16","name":"_feePremiumBps","type":"uint16"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isGovernor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"nonce","type":"uint64"}],"name":"isNonceProcessed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isTransferPending","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastTransferNonce","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minFinalityThreshold","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"peerDomainID","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"peerStrategy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"peerUsdcToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"platformAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"message","type":"bytes"},{"internalType":"bytes","name":"attestation","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"remoteStrategyBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetIndex","type":"uint256"}],"name":"removePToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardTokenAddresses","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"safeApproveAllTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_feePremiumBps","type":"uint16"}],"name":"setFeePremiumBps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_harvesterAddress","type":"address"}],"name":"setHarvesterAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_minFinalityThreshold","type":"uint16"}],"name":"setMinFinalityThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"}],"name":"setOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"address","name":"_pToken","type":"address"}],"name":"setPTokenAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_rewardTokenAddresses","type":"address[]"}],"name":"setRewardTokenAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"supportsAsset","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newGovernor","type":"address"}],"name":"transferGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"usdcToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawAll","outputs":[],"stateMutability":"nonpayable","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e75d77b1865ae93c7eaa3040b038d7aa7bc02f7000000000000000000000000028b5a0e9c621a5badaa536219b3a228c8168cf5d00000000000000000000000081d40f21f12a8f0e3252bccb954d722d4c464b640000000000000000000000000000000000000000000000000000000000000006000000000000000000000000b1d624fc40824683e2bfbefd19eb208dbbe00866000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda02913"}