Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00Token Holdings
More Info
Private Name Tags
ContractCreator
Latest 6 from a total of 6 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Multicall | 20487039 | 65 days ago | IN | 0 ETH | 0.00353398 | ||||
Multicall | 20119991 | 116 days ago | IN | 0 ETH | 0.00684339 | ||||
Multicall | 19134242 | 254 days ago | IN | 0 ETH | 0.01359 | ||||
Multicall | 18507347 | 342 days ago | IN | 0 ETH | 0.01619787 | ||||
Multicall | 18367092 | 361 days ago | IN | 0 ETH | 0.00049811 | ||||
0x60e06040 | 18335751 | 366 days ago | IN | 0 ETH | 0.14961816 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
LLSD_EthereumCompoundV3Balancer_wstETH_WETH
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 850 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { BaseTransfersNative } from "../../../base/BaseTransfersNative/v1/BaseTransfersNative.sol"; import { WETH9NativeWrapper, BaseNativeWrapperConfig } from "../../../modules/native-asset-wrappers/WETH9NativeWrapper.sol"; import { SwapPayload } from "../../../base/BaseSwap.sol"; import { DefinitiveAssets, IERC20 } from "../../../core/libraries/DefinitiveAssets.sol"; import { CoreAccessControlConfig, CoreSwapConfig, CoreFeesConfig, LLSDStrategy, LLSDStrategyConfig } from "../../../modules/LLSDStrategy/v1/LLSDStrategy.sol"; import { BalancerFlashloanBase } from "../../../protocols/balancer/BalancerFlashloanBase.sol"; import { CompoundV3 } from "../Compound/CompoundV3.sol"; // solhint-disable-next-line contract-name-camelcase contract LLSD_EthereumCompoundV3Balancer_wstETH_WETH is LLSDStrategy, BaseTransfersNative, WETH9NativeWrapper, BalancerFlashloanBase, CompoundV3 { using DefinitiveAssets for IERC20; /// @dev Compound V3 Mainnet Pool Address address public constant COMPOUND_POOL = 0xA17581A9E3356d9A858b789D68B4d866e593aE94; constructor( BaseNativeWrapperConfig memory baseNativeWrapperConfig, CoreAccessControlConfig memory coreAccessControlConfig, CoreSwapConfig memory coreSwapConfig, CoreFeesConfig memory coreFeesConfig ) /// @dev Compound V3 Mainnet Pool Address CompoundV3(COMPOUND_POOL) LLSDStrategy( coreAccessControlConfig, coreSwapConfig, coreFeesConfig, LLSDStrategyConfig( /// @dev STAKING_TOKEN: WETH 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, /// @dev STAKED_TOKEN: wstETH 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0 ) ) WETH9NativeWrapper(baseNativeWrapperConfig) {} function enter( uint256 flashloanAmount, SwapPayload calldata swapPayload, uint256 maxLTV ) external onlyWhitelisted stopGuarded nonReentrant enforceMaxLTV(maxLTV) emitEvent(FlashLoanContextType.ENTER) { EnterContext memory ctx = EnterContext(flashloanAmount, swapPayload, maxLTV); return flashloanAmount == 0 ? _enterContinue(abi.encode(ctx)) : initiateFlashLoan( STAKING_TOKEN(), flashloanAmount, abi.encode(FlashLoanContextType.ENTER, abi.encode(ctx)) ); } function exit( uint256 flashloanAmount, uint256 repayAmount, uint256 decollateralizeAmount, SwapPayload calldata swapPayload, uint256 maxLTV ) external onlyWhitelisted stopGuarded nonReentrant enforceMaxLTV(maxLTV) emitEvent(FlashLoanContextType.EXIT) { ExitContext memory ctx = ExitContext(flashloanAmount, repayAmount, decollateralizeAmount, swapPayload, maxLTV); return flashloanAmount == 0 ? _exitContinue(abi.encode(ctx)) : initiateFlashLoan( STAKING_TOKEN(), flashloanAmount, abi.encode(FlashLoanContextType.EXIT, abi.encode(ctx)) ); } function getCollateralToDebtPrice() external view returns (uint256, uint256) { // Gets price of wstETH in ETH (uint256 stakedAssetPriceETH, uint256 stakedAssetPricePrecision) = _getOraclePrice(STAKED_TOKEN()); // Returns reciprocal of wstETH price to get WETH price in wstETH return (1e18 / stakedAssetPriceETH, 1e18 / stakedAssetPricePrecision); } function getDebtAmount() public view override returns (uint256) { return _getTotalVariableDebt(); } function getCollateralAmount() public view override returns (uint256) { return _getTotalCollateral(STAKED_TOKEN()); } function getLTV() public view override returns (uint256) { return _getLTV(STAKED_TOKEN()); } function onFlashLoanReceived( address, // token uint256, // amount uint256, // feeAmount bytes memory userData ) internal override { (FlashLoanContextType ctxType, bytes memory data) = abi.decode(userData, (FlashLoanContextType, bytes)); if (ctxType == FlashLoanContextType.ENTER) { return _enterContinue(data); } if (ctxType == FlashLoanContextType.EXIT) { return _exitContinue(data); } } function _enterContinue(bytes memory contextData) internal { EnterContext memory context = abi.decode(contextData, (EnterContext)); address mSTAKED_TOKEN = STAKED_TOKEN(); // Swap in to staked asset if (context.swapPayload.amount > 0) { SwapPayload[] memory swapPayloads = new SwapPayload[](1); swapPayloads[0] = context.swapPayload; _swap(swapPayloads, mSTAKED_TOKEN); } // Supply dry balance of staked token _supply(DefinitiveAssets.getBalance(mSTAKED_TOKEN)); // Borrow flashloan amount for repayment _borrow(context.flashloanAmount); } function _exitContinue(bytes memory contextData) internal { ExitContext memory context = abi.decode(contextData, (ExitContext)); // Repay debt _repay(context.repayAmount); // Decollateralize _decollateralize(context.decollateralizeAmount); // Swap out of staked asset if (context.swapPayload.amount > 0) { SwapPayload[] memory swapPayloads = new SwapPayload[](1); swapPayloads[0] = context.swapPayload; _swap(swapPayloads, STAKING_TOKEN()); } } function _borrow(uint256 amount) internal override { borrow(STAKING_TOKEN(), amount); } function _decollateralize(uint256 amount) internal override { decollateralize(STAKED_TOKEN(), amount); } function _repay(uint256 amount) internal override { uint256 debtAmount = getDebtAmount(); repay(STAKING_TOKEN(), amount > debtAmount ? debtAmount : amount); } function _supply(uint256 amount) internal override { supply(STAKED_TOKEN(), amount); } }
// SPDX-License-Identifier: GPL-3.0-or-later // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. pragma solidity >=0.7.0 <0.9.0; interface IAuthentication { /** * @dev Returns the action identifier associated with the external function described by `selector`. */ function getActionId(bytes4 selector) external view returns (bytes32); }
// SPDX-License-Identifier: GPL-3.0-or-later // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. pragma solidity >=0.7.0 <0.9.0; /** * @dev Interface for the SignatureValidator helper, used to support meta-transactions. */ interface ISignaturesValidator { /** * @dev Returns the EIP712 domain separator. */ function getDomainSeparator() external view returns (bytes32); /** * @dev Returns the next nonce used by an address to sign messages. */ function getNextNonce(address user) external view returns (uint256); }
// SPDX-License-Identifier: GPL-3.0-or-later // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. pragma solidity >=0.7.0 <0.9.0; /** * @dev Interface for the TemporarilyPausable helper. */ interface ITemporarilyPausable { /** * @dev Emitted every time the pause state changes by `_setPaused`. */ event PausedStateChanged(bool paused); /** * @dev Returns the current paused state. */ function getPausedState() external view returns ( bool paused, uint256 pauseWindowEndTime, uint256 bufferPeriodEndTime ); }
// SPDX-License-Identifier: GPL-3.0-or-later // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. pragma solidity >=0.7.0 <0.9.0; import "../openzeppelin/IERC20.sol"; /** * @dev Interface for WETH9. * See https://github.com/gnosis/canonical-weth/blob/0dd1ea3e295eef916d0c6223ec63141137d22d67/contracts/WETH9.sol */ interface IWETH is IERC20 { function deposit() external payable; function withdraw(uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.7.0 <0.9.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: GPL-3.0-or-later // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. pragma solidity >=0.7.0 <0.9.0; /** * @dev This is an empty interface used to represent either ERC20-conforming token contracts or ETH (using the zero * address sentinel value). We're just relying on the fact that `interface` can be used to declare new address-like * types. * * This concept is unrelated to a Pool's Asset Managers. */ interface IAsset { // solhint-disable-previous-line no-empty-blocks }
// SPDX-License-Identifier: GPL-3.0-or-later // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. pragma solidity >=0.7.0 <0.9.0; interface IAuthorizer { /** * @dev Returns true if `account` can perform the action described by `actionId` in the contract `where`. */ function canPerform( bytes32 actionId, address account, address where ) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-or-later // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. pragma solidity >=0.7.0 <0.9.0; // Inspired by Aave Protocol's IFlashLoanReceiver. import "../solidity-utils/openzeppelin/IERC20.sol"; interface IFlashLoanRecipient { /** * @dev When `flashLoan` is called on the Vault, it invokes the `receiveFlashLoan` hook on the recipient. * * At the time of the call, the Vault will have transferred `amounts` for `tokens` to the recipient. Before this * call returns, the recipient must have transferred `amounts` plus `feeAmounts` for each token back to the * Vault, or else the entire flash loan will revert. * * `userData` is the same value passed in the `IVault.flashLoan` call. */ function receiveFlashLoan( IERC20[] memory tokens, uint256[] memory amounts, uint256[] memory feeAmounts, bytes memory userData ) external; }
// SPDX-License-Identifier: GPL-3.0-or-later // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. pragma solidity >=0.7.0 <0.9.0; pragma experimental ABIEncoderV2; import "../solidity-utils/openzeppelin/IERC20.sol"; import "./IVault.sol"; import "./IAuthorizer.sol"; interface IProtocolFeesCollector { event SwapFeePercentageChanged(uint256 newSwapFeePercentage); event FlashLoanFeePercentageChanged(uint256 newFlashLoanFeePercentage); function withdrawCollectedFees( IERC20[] calldata tokens, uint256[] calldata amounts, address recipient ) external; function setSwapFeePercentage(uint256 newSwapFeePercentage) external; function setFlashLoanFeePercentage(uint256 newFlashLoanFeePercentage) external; function getSwapFeePercentage() external view returns (uint256); function getFlashLoanFeePercentage() external view returns (uint256); function getCollectedFeeAmounts(IERC20[] memory tokens) external view returns (uint256[] memory feeAmounts); function getAuthorizer() external view returns (IAuthorizer); function vault() external view returns (IVault); }
// SPDX-License-Identifier: GPL-3.0-or-later // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. pragma experimental ABIEncoderV2; import "../solidity-utils/openzeppelin/IERC20.sol"; import "../solidity-utils/helpers/IAuthentication.sol"; import "../solidity-utils/helpers/ISignaturesValidator.sol"; import "../solidity-utils/helpers/ITemporarilyPausable.sol"; import "../solidity-utils/misc/IWETH.sol"; import "./IAsset.sol"; import "./IAuthorizer.sol"; import "./IFlashLoanRecipient.sol"; import "./IProtocolFeesCollector.sol"; pragma solidity >=0.7.0 <0.9.0; /** * @dev Full external interface for the Vault core contract - no external or public methods exist in the contract that * don't override one of these declarations. */ interface IVault is ISignaturesValidator, ITemporarilyPausable, IAuthentication { // Generalities about the Vault: // // - Whenever documentation refers to 'tokens', it strictly refers to ERC20-compliant token contracts. Tokens are // transferred out of the Vault by calling the `IERC20.transfer` function, and transferred in by calling // `IERC20.transferFrom`. In these cases, the sender must have previously allowed the Vault to use their tokens by // calling `IERC20.approve`. The only deviation from the ERC20 standard that is supported is functions not returning // a boolean value: in these scenarios, a non-reverting call is assumed to be successful. // // - All non-view functions in the Vault are non-reentrant: calling them while another one is mid-execution (e.g. // while execution control is transferred to a token contract during a swap) will result in a revert. View // functions can be called in a re-reentrant way, but doing so might cause them to return inconsistent results. // Contracts calling view functions in the Vault must make sure the Vault has not already been entered. // // - View functions revert if referring to either unregistered Pools, or unregistered tokens for registered Pools. // Authorizer // // Some system actions are permissioned, like setting and collecting protocol fees. This permissioning system exists // outside of the Vault in the Authorizer contract: the Vault simply calls the Authorizer to check if the caller // can perform a given action. /** * @dev Returns the Vault's Authorizer. */ function getAuthorizer() external view returns (IAuthorizer); /** * @dev Sets a new Authorizer for the Vault. The caller must be allowed by the current Authorizer to do this. * * Emits an `AuthorizerChanged` event. */ function setAuthorizer(IAuthorizer newAuthorizer) external; /** * @dev Emitted when a new authorizer is set by `setAuthorizer`. */ event AuthorizerChanged(IAuthorizer indexed newAuthorizer); // Relayers // // Additionally, it is possible for an account to perform certain actions on behalf of another one, using their // Vault ERC20 allowance and Internal Balance. These accounts are said to be 'relayers' for these Vault functions, // and are expected to be smart contracts with sound authentication mechanisms. For an account to be able to wield // this power, two things must occur: // - The Authorizer must grant the account the permission to be a relayer for the relevant Vault function. This // means that Balancer governance must approve each individual contract to act as a relayer for the intended // functions. // - Each user must approve the relayer to act on their behalf. // This double protection means users cannot be tricked into approving malicious relayers (because they will not // have been allowed by the Authorizer via governance), nor can malicious relayers approved by a compromised // Authorizer or governance drain user funds, since they would also need to be approved by each individual user. /** * @dev Returns true if `user` has approved `relayer` to act as a relayer for them. */ function hasApprovedRelayer(address user, address relayer) external view returns (bool); /** * @dev Allows `relayer` to act as a relayer for `sender` if `approved` is true, and disallows it otherwise. * * Emits a `RelayerApprovalChanged` event. */ function setRelayerApproval( address sender, address relayer, bool approved ) external; /** * @dev Emitted every time a relayer is approved or disapproved by `setRelayerApproval`. */ event RelayerApprovalChanged(address indexed relayer, address indexed sender, bool approved); // Internal Balance // // Users can deposit tokens into the Vault, where they are allocated to their Internal Balance, and later // transferred or withdrawn. It can also be used as a source of tokens when joining Pools, as a destination // when exiting them, and as either when performing swaps. This usage of Internal Balance results in greatly reduced // gas costs when compared to relying on plain ERC20 transfers, leading to large savings for frequent users. // // Internal Balance management features batching, which means a single contract call can be used to perform multiple // operations of different kinds, with different senders and recipients, at once. /** * @dev Returns `user`'s Internal Balance for a set of tokens. */ function getInternalBalance(address user, IERC20[] memory tokens) external view returns (uint256[] memory); /** * @dev Performs a set of user balance operations, which involve Internal Balance (deposit, withdraw or transfer) * and plain ERC20 transfers using the Vault's allowance. This last feature is particularly useful for relayers, as * it lets integrators reuse a user's Vault allowance. * * For each operation, if the caller is not `sender`, it must be an authorized relayer for them. */ function manageUserBalance(UserBalanceOp[] memory ops) external payable; /** * @dev Data for `manageUserBalance` operations, which include the possibility for ETH to be sent and received without manual WETH wrapping or unwrapping. */ struct UserBalanceOp { UserBalanceOpKind kind; IAsset asset; uint256 amount; address sender; address payable recipient; } // There are four possible operations in `manageUserBalance`: // // - DEPOSIT_INTERNAL // Increases the Internal Balance of the `recipient` account by transferring tokens from the corresponding // `sender`. The sender must have allowed the Vault to use their tokens via `IERC20.approve()`. // // ETH can be used by passing the ETH sentinel value as the asset and forwarding ETH in the call: it will be wrapped // and deposited as WETH. Any ETH amount remaining will be sent back to the caller (not the sender, which is // relevant for relayers). // // Emits an `InternalBalanceChanged` event. // // // - WITHDRAW_INTERNAL // Decreases the Internal Balance of the `sender` account by transferring tokens to the `recipient`. // // ETH can be used by passing the ETH sentinel value as the asset. This will deduct WETH instead, unwrap it and send // it to the recipient as ETH. // // Emits an `InternalBalanceChanged` event. // // // - TRANSFER_INTERNAL // Transfers tokens from the Internal Balance of the `sender` account to the Internal Balance of `recipient`. // // Reverts if the ETH sentinel value is passed. // // Emits an `InternalBalanceChanged` event. // // // - TRANSFER_EXTERNAL // Transfers tokens from `sender` to `recipient`, using the Vault's ERC20 allowance. This is typically used by // relayers, as it lets them reuse a user's Vault allowance. // // Reverts if the ETH sentinel value is passed. // // Emits an `ExternalBalanceTransfer` event. enum UserBalanceOpKind { DEPOSIT_INTERNAL, WITHDRAW_INTERNAL, TRANSFER_INTERNAL, TRANSFER_EXTERNAL } /** * @dev Emitted when a user's Internal Balance changes, either from calls to `manageUserBalance`, or through * interacting with Pools using Internal Balance. * * Because Internal Balance works exclusively with ERC20 tokens, ETH deposits and withdrawals will use the WETH * address. */ event InternalBalanceChanged(address indexed user, IERC20 indexed token, int256 delta); /** * @dev Emitted when a user's Vault ERC20 allowance is used by the Vault to transfer tokens to an external account. */ event ExternalBalanceTransfer(IERC20 indexed token, address indexed sender, address recipient, uint256 amount); // Pools // // There are three specialization settings for Pools, which allow for cheaper swaps at the cost of reduced // functionality: // // - General: no specialization, suited for all Pools. IGeneralPool is used for swap request callbacks, passing the // balance of all tokens in the Pool. These Pools have the largest swap costs (because of the extra storage reads), // which increase with the number of registered tokens. // // - Minimal Swap Info: IMinimalSwapInfoPool is used instead of IGeneralPool, which saves gas by only passing the // balance of the two tokens involved in the swap. This is suitable for some pricing algorithms, like the weighted // constant product one popularized by Balancer V1. Swap costs are smaller compared to general Pools, and are // independent of the number of registered tokens. // // - Two Token: only allows two tokens to be registered. This achieves the lowest possible swap gas cost. Like // minimal swap info Pools, these are called via IMinimalSwapInfoPool. enum PoolSpecialization { GENERAL, MINIMAL_SWAP_INFO, TWO_TOKEN } /** * @dev Registers the caller account as a Pool with a given specialization setting. Returns the Pool's ID, which * is used in all Pool-related functions. Pools cannot be deregistered, nor can the Pool's specialization be * changed. * * The caller is expected to be a smart contract that implements either `IGeneralPool` or `IMinimalSwapInfoPool`, * depending on the chosen specialization setting. This contract is known as the Pool's contract. * * Note that the same contract may register itself as multiple Pools with unique Pool IDs, or in other words, * multiple Pools may share the same contract. * * Emits a `PoolRegistered` event. */ function registerPool(PoolSpecialization specialization) external returns (bytes32); /** * @dev Emitted when a Pool is registered by calling `registerPool`. */ event PoolRegistered(bytes32 indexed poolId, address indexed poolAddress, PoolSpecialization specialization); /** * @dev Returns a Pool's contract address and specialization setting. */ function getPool(bytes32 poolId) external view returns (address, PoolSpecialization); /** * @dev Registers `tokens` for the `poolId` Pool. Must be called by the Pool's contract. * * Pools can only interact with tokens they have registered. Users join a Pool by transferring registered tokens, * exit by receiving registered tokens, and can only swap registered tokens. * * Each token can only be registered once. For Pools with the Two Token specialization, `tokens` must have a length * of two, that is, both tokens must be registered in the same `registerTokens` call, and they must be sorted in * ascending order. * * The `tokens` and `assetManagers` arrays must have the same length, and each entry in these indicates the Asset * Manager for the corresponding token. Asset Managers can manage a Pool's tokens via `managePoolBalance`, * depositing and withdrawing them directly, and can even set their balance to arbitrary amounts. They are therefore * expected to be highly secured smart contracts with sound design principles, and the decision to register an * Asset Manager should not be made lightly. * * Pools can choose not to assign an Asset Manager to a given token by passing in the zero address. Once an Asset * Manager is set, it cannot be changed except by deregistering the associated token and registering again with a * different Asset Manager. * * Emits a `TokensRegistered` event. */ function registerTokens( bytes32 poolId, IERC20[] memory tokens, address[] memory assetManagers ) external; /** * @dev Emitted when a Pool registers tokens by calling `registerTokens`. */ event TokensRegistered(bytes32 indexed poolId, IERC20[] tokens, address[] assetManagers); /** * @dev Deregisters `tokens` for the `poolId` Pool. Must be called by the Pool's contract. * * Only registered tokens (via `registerTokens`) can be deregistered. Additionally, they must have zero total * balance. For Pools with the Two Token specialization, `tokens` must have a length of two, that is, both tokens * must be deregistered in the same `deregisterTokens` call. * * A deregistered token can be re-registered later on, possibly with a different Asset Manager. * * Emits a `TokensDeregistered` event. */ function deregisterTokens(bytes32 poolId, IERC20[] memory tokens) external; /** * @dev Emitted when a Pool deregisters tokens by calling `deregisterTokens`. */ event TokensDeregistered(bytes32 indexed poolId, IERC20[] tokens); /** * @dev Returns detailed information for a Pool's registered token. * * `cash` is the number of tokens the Vault currently holds for the Pool. `managed` is the number of tokens * withdrawn and held outside the Vault by the Pool's token Asset Manager. The Pool's total balance for `token` * equals the sum of `cash` and `managed`. * * Internally, `cash` and `managed` are stored using 112 bits. No action can ever cause a Pool's token `cash`, * `managed` or `total` balance to be greater than 2^112 - 1. * * `lastChangeBlock` is the number of the block in which `token`'s total balance was last modified (via either a * join, exit, swap, or Asset Manager update). This value is useful to avoid so-called 'sandwich attacks', for * example when developing price oracles. A change of zero (e.g. caused by a swap with amount zero) is considered a * change for this purpose, and will update `lastChangeBlock`. * * `assetManager` is the Pool's token Asset Manager. */ function getPoolTokenInfo(bytes32 poolId, IERC20 token) external view returns ( uint256 cash, uint256 managed, uint256 lastChangeBlock, address assetManager ); /** * @dev Returns a Pool's registered tokens, the total balance for each, and the latest block when *any* of * the tokens' `balances` changed. * * The order of the `tokens` array is the same order that will be used in `joinPool`, `exitPool`, as well as in all * Pool hooks (where applicable). Calls to `registerTokens` and `deregisterTokens` may change this order. * * If a Pool only registers tokens once, and these are sorted in ascending order, they will be stored in the same * order as passed to `registerTokens`. * * Total balances include both tokens held by the Vault and those withdrawn by the Pool's Asset Managers. These are * the amounts used by joins, exits and swaps. For a detailed breakdown of token balances, use `getPoolTokenInfo` * instead. */ function getPoolTokens(bytes32 poolId) external view returns ( IERC20[] memory tokens, uint256[] memory balances, uint256 lastChangeBlock ); /** * @dev Called by users to join a Pool, which transfers tokens from `sender` into the Pool's balance. This will * trigger custom Pool behavior, which will typically grant something in return to `recipient` - often tokenized * Pool shares. * * If the caller is not `sender`, it must be an authorized relayer for them. * * The `assets` and `maxAmountsIn` arrays must have the same length, and each entry indicates the maximum amount * to send for each asset. The amounts to send are decided by the Pool and not the Vault: it just enforces * these maximums. * * If joining a Pool that holds WETH, it is possible to send ETH directly: the Vault will do the wrapping. To enable * this mechanism, the IAsset sentinel value (the zero address) must be passed in the `assets` array instead of the * WETH address. Note that it is not possible to combine ETH and WETH in the same join. Any excess ETH will be sent * back to the caller (not the sender, which is important for relayers). * * `assets` must have the same length and order as the array returned by `getPoolTokens`. This prevents issues when * interacting with Pools that register and deregister tokens frequently. If sending ETH however, the array must be * sorted *before* replacing the WETH address with the ETH sentinel value (the zero address), which means the final * `assets` array might not be sorted. Pools with no registered tokens cannot be joined. * * If `fromInternalBalance` is true, the caller's Internal Balance will be preferred: ERC20 transfers will only * be made for the difference between the requested amount and Internal Balance (if any). Note that ETH cannot be * withdrawn from Internal Balance: attempting to do so will trigger a revert. * * This causes the Vault to call the `IBasePool.onJoinPool` hook on the Pool's contract, where Pools implement * their own custom logic. This typically requires additional information from the user (such as the expected number * of Pool shares). This can be encoded in the `userData` argument, which is ignored by the Vault and passed * directly to the Pool's contract, as is `recipient`. * * Emits a `PoolBalanceChanged` event. */ function joinPool( bytes32 poolId, address sender, address recipient, JoinPoolRequest memory request ) external payable; struct JoinPoolRequest { IAsset[] assets; uint256[] maxAmountsIn; bytes userData; bool fromInternalBalance; } /** * @dev Called by users to exit a Pool, which transfers tokens from the Pool's balance to `recipient`. This will * trigger custom Pool behavior, which will typically ask for something in return from `sender` - often tokenized * Pool shares. The amount of tokens that can be withdrawn is limited by the Pool's `cash` balance (see * `getPoolTokenInfo`). * * If the caller is not `sender`, it must be an authorized relayer for them. * * The `tokens` and `minAmountsOut` arrays must have the same length, and each entry in these indicates the minimum * token amount to receive for each token contract. The amounts to send are decided by the Pool and not the Vault: * it just enforces these minimums. * * If exiting a Pool that holds WETH, it is possible to receive ETH directly: the Vault will do the unwrapping. To * enable this mechanism, the IAsset sentinel value (the zero address) must be passed in the `assets` array instead * of the WETH address. Note that it is not possible to combine ETH and WETH in the same exit. * * `assets` must have the same length and order as the array returned by `getPoolTokens`. This prevents issues when * interacting with Pools that register and deregister tokens frequently. If receiving ETH however, the array must * be sorted *before* replacing the WETH address with the ETH sentinel value (the zero address), which means the * final `assets` array might not be sorted. Pools with no registered tokens cannot be exited. * * If `toInternalBalance` is true, the tokens will be deposited to `recipient`'s Internal Balance. Otherwise, * an ERC20 transfer will be performed. Note that ETH cannot be deposited to Internal Balance: attempting to * do so will trigger a revert. * * `minAmountsOut` is the minimum amount of tokens the user expects to get out of the Pool, for each token in the * `tokens` array. This array must match the Pool's registered tokens. * * This causes the Vault to call the `IBasePool.onExitPool` hook on the Pool's contract, where Pools implement * their own custom logic. This typically requires additional information from the user (such as the expected number * of Pool shares to return). This can be encoded in the `userData` argument, which is ignored by the Vault and * passed directly to the Pool's contract. * * Emits a `PoolBalanceChanged` event. */ function exitPool( bytes32 poolId, address sender, address payable recipient, ExitPoolRequest memory request ) external; struct ExitPoolRequest { IAsset[] assets; uint256[] minAmountsOut; bytes userData; bool toInternalBalance; } /** * @dev Emitted when a user joins or exits a Pool by calling `joinPool` or `exitPool`, respectively. */ event PoolBalanceChanged( bytes32 indexed poolId, address indexed liquidityProvider, IERC20[] tokens, int256[] deltas, uint256[] protocolFeeAmounts ); enum PoolBalanceChangeKind { JOIN, EXIT } // Swaps // // Users can swap tokens with Pools by calling the `swap` and `batchSwap` functions. To do this, // they need not trust Pool contracts in any way: all security checks are made by the Vault. They must however be // aware of the Pools' pricing algorithms in order to estimate the prices Pools will quote. // // The `swap` function executes a single swap, while `batchSwap` can perform multiple swaps in sequence. // In each individual swap, tokens of one kind are sent from the sender to the Pool (this is the 'token in'), // and tokens of another kind are sent from the Pool to the recipient in exchange (this is the 'token out'). // More complex swaps, such as one token in to multiple tokens out can be achieved by batching together // individual swaps. // // There are two swap kinds: // - 'given in' swaps, where the amount of tokens in (sent to the Pool) is known, and the Pool determines (via the // `onSwap` hook) the amount of tokens out (to send to the recipient). // - 'given out' swaps, where the amount of tokens out (received from the Pool) is known, and the Pool determines // (via the `onSwap` hook) the amount of tokens in (to receive from the sender). // // Additionally, it is possible to chain swaps using a placeholder input amount, which the Vault replaces with // the calculated output of the previous swap. If the previous swap was 'given in', this will be the calculated // tokenOut amount. If the previous swap was 'given out', it will use the calculated tokenIn amount. These extended // swaps are known as 'multihop' swaps, since they 'hop' through a number of intermediate tokens before arriving at // the final intended token. // // In all cases, tokens are only transferred in and out of the Vault (or withdrawn from and deposited into Internal // Balance) after all individual swaps have been completed, and the net token balance change computed. This makes // certain swap patterns, such as multihops, or swaps that interact with the same token pair in multiple Pools, cost // much less gas than they would otherwise. // // It also means that under certain conditions it is possible to perform arbitrage by swapping with multiple // Pools in a way that results in net token movement out of the Vault (profit), with no tokens being sent in (only // updating the Pool's internal accounting). // // To protect users from front-running or the market changing rapidly, they supply a list of 'limits' for each token // involved in the swap, where either the maximum number of tokens to send (by passing a positive value) or the // minimum amount of tokens to receive (by passing a negative value) is specified. // // Additionally, a 'deadline' timestamp can also be provided, forcing the swap to fail if it occurs after // this point in time (e.g. if the transaction failed to be included in a block promptly). // // If interacting with Pools that hold WETH, it is possible to both send and receive ETH directly: the Vault will do // the wrapping and unwrapping. To enable this mechanism, the IAsset sentinel value (the zero address) must be // passed in the `assets` array instead of the WETH address. Note that it is possible to combine ETH and WETH in the // same swap. Any excess ETH will be sent back to the caller (not the sender, which is relevant for relayers). // // Finally, Internal Balance can be used when either sending or receiving tokens. enum SwapKind { GIVEN_IN, GIVEN_OUT } /** * @dev Performs a swap with a single Pool. * * If the swap is 'given in' (the number of tokens to send to the Pool is known), it returns the amount of tokens * taken from the Pool, which must be greater than or equal to `limit`. * * If the swap is 'given out' (the number of tokens to take from the Pool is known), it returns the amount of tokens * sent to the Pool, which must be less than or equal to `limit`. * * Internal Balance usage and the recipient are determined by the `funds` struct. * * Emits a `Swap` event. */ function swap( SingleSwap memory singleSwap, FundManagement memory funds, uint256 limit, uint256 deadline ) external payable returns (uint256); /** * @dev Data for a single swap executed by `swap`. `amount` is either `amountIn` or `amountOut` depending on * the `kind` value. * * `assetIn` and `assetOut` are either token addresses, or the IAsset sentinel value for ETH (the zero address). * Note that Pools never interact with ETH directly: it will be wrapped to or unwrapped from WETH by the Vault. * * The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be * used to extend swap behavior. */ struct SingleSwap { bytes32 poolId; SwapKind kind; IAsset assetIn; IAsset assetOut; uint256 amount; bytes userData; } /** * @dev Performs a series of swaps with one or multiple Pools. In each individual swap, the caller determines either * the amount of tokens sent to or received from the Pool, depending on the `kind` value. * * Returns an array with the net Vault asset balance deltas. Positive amounts represent tokens (or ETH) sent to the * Vault, and negative amounts represent tokens (or ETH) sent by the Vault. Each delta corresponds to the asset at * the same index in the `assets` array. * * Swaps are executed sequentially, in the order specified by the `swaps` array. Each array element describes a * Pool, the token to be sent to this Pool, the token to receive from it, and an amount that is either `amountIn` or * `amountOut` depending on the swap kind. * * Multihop swaps can be executed by passing an `amount` value of zero for a swap. This will cause the amount in/out * of the previous swap to be used as the amount in for the current one. In a 'given in' swap, 'tokenIn' must equal * the previous swap's `tokenOut`. For a 'given out' swap, `tokenOut` must equal the previous swap's `tokenIn`. * * The `assets` array contains the addresses of all assets involved in the swaps. These are either token addresses, * or the IAsset sentinel value for ETH (the zero address). Each entry in the `swaps` array specifies tokens in and * out by referencing an index in `assets`. Note that Pools never interact with ETH directly: it will be wrapped to * or unwrapped from WETH by the Vault. * * Internal Balance usage, sender, and recipient are determined by the `funds` struct. The `limits` array specifies * the minimum or maximum amount of each token the vault is allowed to transfer. * * `batchSwap` can be used to make a single swap, like `swap` does, but doing so requires more gas than the * equivalent `swap` call. * * Emits `Swap` events. */ function batchSwap( SwapKind kind, BatchSwapStep[] memory swaps, IAsset[] memory assets, FundManagement memory funds, int256[] memory limits, uint256 deadline ) external payable returns (int256[] memory); /** * @dev Data for each individual swap executed by `batchSwap`. The asset in and out fields are indexes into the * `assets` array passed to that function, and ETH assets are converted to WETH. * * If `amount` is zero, the multihop mechanism is used to determine the actual amount based on the amount in/out * from the previous swap, depending on the swap kind. * * The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be * used to extend swap behavior. */ struct BatchSwapStep { bytes32 poolId; uint256 assetInIndex; uint256 assetOutIndex; uint256 amount; bytes userData; } /** * @dev Emitted for each individual swap performed by `swap` or `batchSwap`. */ event Swap( bytes32 indexed poolId, IERC20 indexed tokenIn, IERC20 indexed tokenOut, uint256 amountIn, uint256 amountOut ); /** * @dev All tokens in a swap are either sent from the `sender` account to the Vault, or from the Vault to the * `recipient` account. * * If the caller is not `sender`, it must be an authorized relayer for them. * * If `fromInternalBalance` is true, the `sender`'s Internal Balance will be preferred, performing an ERC20 * transfer for the difference between the requested amount and the User's Internal Balance (if any). The `sender` * must have allowed the Vault to use their tokens via `IERC20.approve()`. This matches the behavior of * `joinPool`. * * If `toInternalBalance` is true, tokens will be deposited to `recipient`'s internal balance instead of * transferred. This matches the behavior of `exitPool`. * * Note that ETH cannot be deposited to or withdrawn from Internal Balance: attempting to do so will trigger a * revert. */ struct FundManagement { address sender; bool fromInternalBalance; address payable recipient; bool toInternalBalance; } /** * @dev Simulates a call to `batchSwap`, returning an array of Vault asset deltas. Calls to `swap` cannot be * simulated directly, but an equivalent `batchSwap` call can and will yield the exact same result. * * Each element in the array corresponds to the asset at the same index, and indicates the number of tokens (or ETH) * the Vault would take from the sender (if positive) or send to the recipient (if negative). The arguments it * receives are the same that an equivalent `batchSwap` call would receive. * * Unlike `batchSwap`, this function performs no checks on the sender or recipient field in the `funds` struct. * This makes it suitable to be called by off-chain applications via eth_call without needing to hold tokens, * approve them for the Vault, or even know a user's address. * * Note that this function is not 'view' (due to implementation details): the client code must explicitly execute * eth_call instead of eth_sendTransaction. */ function queryBatchSwap( SwapKind kind, BatchSwapStep[] memory swaps, IAsset[] memory assets, FundManagement memory funds ) external returns (int256[] memory assetDeltas); // Flash Loans /** * @dev Performs a 'flash loan', sending tokens to `recipient`, executing the `receiveFlashLoan` hook on it, * and then reverting unless the tokens plus a proportional protocol fee have been returned. * * The `tokens` and `amounts` arrays must have the same length, and each entry in these indicates the loan amount * for each token contract. `tokens` must be sorted in ascending order. * * The 'userData' field is ignored by the Vault, and forwarded as-is to `recipient` as part of the * `receiveFlashLoan` call. * * Emits `FlashLoan` events. */ function flashLoan( IFlashLoanRecipient recipient, IERC20[] memory tokens, uint256[] memory amounts, bytes memory userData ) external; /** * @dev Emitted for each individual flash loan performed by `flashLoan`. */ event FlashLoan(IFlashLoanRecipient indexed recipient, IERC20 indexed token, uint256 amount, uint256 feeAmount); // Asset Management // // Each token registered for a Pool can be assigned an Asset Manager, which is able to freely withdraw the Pool's // tokens from the Vault, deposit them, or assign arbitrary values to its `managed` balance (see // `getPoolTokenInfo`). This makes them extremely powerful and dangerous. Even if an Asset Manager only directly // controls one of the tokens in a Pool, a malicious manager could set that token's balance to manipulate the // prices of the other tokens, and then drain the Pool with swaps. The risk of using Asset Managers is therefore // not constrained to the tokens they are managing, but extends to the entire Pool's holdings. // // However, a properly designed Asset Manager smart contract can be safely used for the Pool's benefit, // for example by lending unused tokens out for interest, or using them to participate in voting protocols. // // This concept is unrelated to the IAsset interface. /** * @dev Performs a set of Pool balance operations, which may be either withdrawals, deposits or updates. * * Pool Balance management features batching, which means a single contract call can be used to perform multiple * operations of different kinds, with different Pools and tokens, at once. * * For each operation, the caller must be registered as the Asset Manager for `token` in `poolId`. */ function managePoolBalance(PoolBalanceOp[] memory ops) external; struct PoolBalanceOp { PoolBalanceOpKind kind; bytes32 poolId; IERC20 token; uint256 amount; } /** * Withdrawals decrease the Pool's cash, but increase its managed balance, leaving the total balance unchanged. * * Deposits increase the Pool's cash, but decrease its managed balance, leaving the total balance unchanged. * * Updates don't affect the Pool's cash balance, but because the managed balance changes, it does alter the total. * The external amount can be either increased or decreased by this call (i.e., reporting a gain or a loss). */ enum PoolBalanceOpKind { WITHDRAW, DEPOSIT, UPDATE } /** * @dev Emitted when a Pool's token Asset Manager alters its balance via `managePoolBalance`. */ event PoolBalanceManaged( bytes32 indexed poolId, address indexed assetManager, IERC20 indexed token, int256 cashDelta, int256 managedDelta ); // Protocol Fees // // Some operations cause the Vault to collect tokens in the form of protocol fees, which can then be withdrawn by // permissioned accounts. // // There are two kinds of protocol fees: // // - flash loan fees: charged on all flash loans, as a percentage of the amounts lent. // // - swap fees: a percentage of the fees charged by Pools when performing swaps. For a number of reasons, including // swap gas costs and interface simplicity, protocol swap fees are not charged on each individual swap. Rather, // Pools are expected to keep track of how much they have charged in swap fees, and pay any outstanding debts to the // Vault when they are joined or exited. This prevents users from joining a Pool with unpaid debt, as well as // exiting a Pool in debt without first paying their share. /** * @dev Returns the current protocol fee module. */ function getProtocolFeesCollector() external view returns (IProtocolFeesCollector); /** * @dev Safety mechanism to pause most Vault operations in the event of an emergency - typically detection of an * error in some part of the system. * * The Vault can only be paused during an initial time period, after which pausing is forever disabled. * * While the contract is paused, the following features are disabled: * - depositing and transferring internal balance * - transferring external balance (using the Vault's allowance) * - swaps * - joining Pools * - Asset Manager interactions * * Internal Balance can still be withdrawn, and Pools exited. */ function setPaused(bool paused) external; /** * @dev Returns the Vault's WETH instance. */ function WETH() external view returns (IWETH); // solhint-disable-previous-line func-name-mixedcase }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControl.sol"; import "../utils/Context.sol"; import "../utils/Strings.sol"; import "../utils/introspection/ERC165.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", Strings.toHexString(account), " is missing role ", Strings.toHexString(uint256(role), 32) ) ) ); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * May emit a {RoleGranted} event. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Grants `role` to `account`. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; import "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { CoreAccessControl, CoreAccessControlConfig } from "../core/CoreAccessControl/v1/CoreAccessControl.sol"; import { CoreStopGuardian } from "../core/CoreStopGuardian/v1/CoreStopGuardian.sol"; abstract contract BaseAccessControl is CoreAccessControl, CoreStopGuardian { /** * @dev * Modifiers inherited from CoreAccessControl: * onlyDefinitive * onlyClients * onlyWhitelisted * onlyClientAdmin * onlyDefinitiveAdmin * * Modifiers inherited from CoreStopGuardian: * stopGuarded */ constructor(CoreAccessControlConfig memory coreAccessControlConfig) CoreAccessControl(coreAccessControlConfig) {} /** * @dev Inherited from CoreStopGuardian */ function enableStopGuardian() public override onlyAdmins { return _enableStopGuardian(); } /** * @dev Inherited from CoreStopGuardian */ function disableStopGuardian() public override onlyClientAdmin { return _disableStopGuardian(); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { BaseAccessControl } from "./BaseAccessControl.sol"; import { CoreFees, CoreFeesConfig } from "../core/CoreFees/v1/CoreFees.sol"; import { DefinitiveAssets, IERC20 } from "../core/libraries/DefinitiveAssets.sol"; import { DefinitiveConstants } from "../core/libraries/DefinitiveConstants.sol"; import { InvalidFeePercent } from "../core/libraries/DefinitiveErrors.sol"; abstract contract BaseFees is BaseAccessControl, CoreFees { using DefinitiveAssets for IERC20; constructor(CoreFeesConfig memory coreFeesConfig) CoreFees(coreFeesConfig) {} function updateFeeAccount(address payable _feeAccount) public override onlyDefinitiveAdmin { _updateFeeAccount(_feeAccount); } function _handleFeesOnAmount(address token, uint256 amount, uint256 feePct) internal returns (uint256 feeAmount) { uint256 mMaxFeePCT = DefinitiveConstants.MAX_FEE_PCT; if (feePct > mMaxFeePCT) { revert InvalidFeePercent(); } feeAmount = (amount * feePct) / mMaxFeePCT; if (feeAmount > 0) { if (token == DefinitiveConstants.NATIVE_ASSET_ADDRESS) { DefinitiveAssets.safeTransferETH(FEE_ACCOUNT, feeAmount); } else { IERC20(token).safeTransfer(FEE_ACCOUNT, feeAmount); } } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { BaseAccessControl } from "../../BaseAccessControl.sol"; import { IBaseNativeWrapperV1 } from "./IBaseNativeWrapperV1.sol"; import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import { DefinitiveAssets, IERC20 } from "../../../core/libraries/DefinitiveAssets.sol"; struct BaseNativeWrapperConfig { address payable wrappedNativeAssetAddress; } abstract contract BaseNativeWrapper is IBaseNativeWrapperV1, BaseAccessControl, ReentrancyGuard { using DefinitiveAssets for IERC20; address payable public immutable WRAPPED_NATIVE_ASSET_ADDRESS; constructor(BaseNativeWrapperConfig memory baseNativeWrapperConfig) { WRAPPED_NATIVE_ASSET_ADDRESS = baseNativeWrapperConfig.wrappedNativeAssetAddress; } /** * @notice Publicly accessible method to wrap native assets * @param amount Amount of native assets to wrap */ function wrap(uint256 amount) public onlyWhitelisted nonReentrant { _wrap(amount); emit NativeAssetWrap(_msgSender(), amount, true /* wrappingToNative */); } /** * @notice Publicly accessible method to unwrap native assets * @param amount Amount of tokenized assets to unwrap */ function unwrap(uint256 amount) public onlyWhitelisted nonReentrant { _unwrap(amount); emit NativeAssetWrap(_msgSender(), amount, false /* wrappingToNative */); } /** * @notice Publicly accessible method to unwrap full balance of native assets * @dev Method is not marked as `nonReentrant` since it is a wrapper around `unwrap` */ function unwrapAll() external onlyWhitelisted { return unwrap(DefinitiveAssets.getBalance(WRAPPED_NATIVE_ASSET_ADDRESS)); } /** * @notice Internal method to wrap native assets * @dev Override this method with native asset wrapping implementation */ function _wrap(uint256 amount) internal virtual; /** * @notice Internal method to unwrap native assets * @dev Override this method with native asset unwrapping implementation */ function _unwrap(uint256 amount) internal virtual; }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; interface IBaseNativeWrapperV1 { event NativeAssetWrap(address actor, uint256 amount, bool indexed wrappingToNative); function wrap(uint256 amount) external; function unwrap(uint256 amount) external; function unwrapAll() external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { BaseAccessControl } from "../BaseAccessControl.sol"; import { CallUtils } from "../../tools/BubbleReverts/BubbleReverts.sol"; import { IBasePermissionedExecution } from "./IBasePermissionedExecution.sol"; abstract contract BasePermissionedExecution is BaseAccessControl, IBasePermissionedExecution { function executeOperation(address target, bytes calldata payload) external payable override onlyClientAdmin { (bool _success, bytes memory _returnedData) = payable(target).call{ value: msg.value }(payload); if (!_success) { CallUtils.revertFromReturnedData(_returnedData); } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { ICoreAccessControlV1 } from "../../core/CoreAccessControl/v1/ICoreAccessControlV1.sol"; interface IBasePermissionedExecution is ICoreAccessControlV1 { function executeOperation(address target, bytes calldata payload) external payable; }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { BaseFees } from "./BaseFees.sol"; import { CoreRewards } from "../core/CoreRewards/v1/CoreRewards.sol"; import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import { DefinitiveAssets, IERC20 } from "../core/libraries/DefinitiveAssets.sol"; abstract contract BaseRewards is BaseFees, CoreRewards, ReentrancyGuard { using DefinitiveAssets for IERC20; function claimAllRewards( uint256 feePct ) external override onlyWhitelisted nonReentrant stopGuarded returns (IERC20[] memory rewardTokens, uint256[] memory earnedAmounts) { (rewardTokens, earnedAmounts) = _claimAllRewards(); uint256 rewardTokensLength = rewardTokens.length; uint256[] memory feeAmounts = new uint256[](rewardTokensLength); if (FEE_ACCOUNT != address(0) && feePct > 0) { for (uint256 i; i < rewardTokensLength; ) { if (earnedAmounts[i] == 0) { unchecked { ++i; } continue; } feeAmounts[i] = _handleFeesOnAmount(address(rewardTokens[i]), earnedAmounts[i], feePct); unchecked { ++i; } } } emit RewardsClaimed(rewardTokens, earnedAmounts, feeAmounts); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { Context } from "@openzeppelin/contracts/utils/Context.sol"; import { BaseAccessControl } from "../../base/BaseAccessControl.sol"; import { IBaseSafeHarborMode } from "./IBaseSafeHarborMode.sol"; abstract contract BaseSafeHarborMode is Context, IBaseSafeHarborMode, BaseAccessControl { bool public SAFE_HARBOR_MODE_ENABLED; function disableSafeHarborMode() external onlyAdmins { _setSafeHarborMode(false); } function enableSafeHarborMode() external onlyWhitelisted { _setSafeHarborMode(true); } function _setSafeHarborMode(bool _enabled) internal { SAFE_HARBOR_MODE_ENABLED = _enabled; emit SafeHarborModeUpdate(_msgSender(), _enabled); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; // solhint-disable-next-line contract-name-camelcase interface IBaseSafeHarborMode { event SafeHarborModeUpdate(address indexed actor, bool indexed isEnabled); function SAFE_HARBOR_MODE_ENABLED() external view returns (bool); function enableSafeHarborMode() external; function disableSafeHarborMode() external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { BaseFees } from "./BaseFees.sol"; import { CoreSwap, CoreSwapConfig, SwapPayload } from "../core/CoreSwap/v1/CoreSwap.sol"; import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import { DefinitiveConstants } from "../core/libraries/DefinitiveConstants.sol"; import { InvalidFeePercent, InvalidSwapPayload, SlippageExceeded } from "../core/libraries/DefinitiveErrors.sol"; import { ICoreSwapHandlerV1 } from "../core/CoreSwapHandler/ICoreSwapHandlerV1.sol"; abstract contract BaseSwap is BaseFees, CoreSwap, ReentrancyGuard { constructor(CoreSwapConfig memory coreSwapConfig) CoreSwap(coreSwapConfig) {} function enableSwapTokens(address[] memory swapTokens) public override onlyClientAdmin stopGuarded { return _updateSwapTokens(swapTokens, true); } function disableSwapTokens(address[] memory swapTokens) public override onlyAdmins { return _updateSwapTokens(swapTokens, false); } function enableSwapOutputTokens(address[] memory swapOutputTokens) public override onlyClientAdmin stopGuarded { return _updateSwapOutputTokens(swapOutputTokens, true); } function disableSwapOutputTokens(address[] memory swapOutputTokens) public override onlyAdmins { return _updateSwapOutputTokens(swapOutputTokens, false); } function enableSwapHandlers(address[] memory swapHandlers) public override onlyClientAdmin stopGuarded { _updateSwapHandlers(swapHandlers, true); } function disableSwapHandlers(address[] memory swapHandlers) public override onlyAdmins { _updateSwapHandlers(swapHandlers, false); } function swap( SwapPayload[] memory payloads, address outputToken, uint256 amountOutMin, uint256 feePct ) external override onlyWhitelisted nonReentrant stopGuarded returns (uint256) { if (feePct > DefinitiveConstants.MAX_FEE_PCT) { revert InvalidFeePercent(); } (uint256[] memory inputAmounts, uint256 outputAmount) = _swap(payloads, outputToken); if (outputAmount < amountOutMin) { revert SlippageExceeded(outputAmount, amountOutMin); } address[] memory swapTokens = new address[](payloads.length); uint256 swapTokensLength = swapTokens.length; for (uint256 i; i < swapTokensLength; ) { swapTokens[i] = payloads[i].swapToken; unchecked { ++i; } } uint256 feeAmount; if (FEE_ACCOUNT != address(0) && outputAmount > 0 && feePct > 0) { feeAmount = _handleFeesOnAmount(outputToken, outputAmount, feePct); } emit SwapHandled(swapTokens, inputAmounts, outputToken, outputAmount, feeAmount); return outputAmount; } function _getEncodedSwapHandlerCalldata( SwapPayload memory payload, address expectedOutputToken, bool isPrincipalAssetSwap, bool isDelegateCall ) internal pure override returns (bytes memory) { // Principal Swaps if (isPrincipalAssetSwap && isDelegateCall) { revert InvalidSwapPayload(); } bytes4 selector; if (isPrincipalAssetSwap) { selector = ICoreSwapHandlerV1.swapUsingValidatedPathCall.selector; } else { selector = isDelegateCall ? ICoreSwapHandlerV1.swapDelegate.selector : ICoreSwapHandlerV1.swapCall.selector; } ICoreSwapHandlerV1.SwapParams memory _params = ICoreSwapHandlerV1.SwapParams({ inputAssetAddress: payload.swapToken, inputAmount: payload.amount, outputAssetAddress: expectedOutputToken, minOutputAmount: payload.amountOutMin, data: payload.handlerCalldata, signature: payload.signature }); return abi.encodeWithSelector(selector, _params); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { CoreDeposit } from "../../../core/CoreDeposit/v1/CoreDeposit.sol"; import { CoreWithdraw } from "../../../core/CoreWithdraw/v1/CoreWithdraw.sol"; import { BaseAccessControl } from "../../BaseAccessControl.sol"; import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; abstract contract BaseTransfers is CoreDeposit, CoreWithdraw, BaseAccessControl, ReentrancyGuard { function deposit( uint256[] calldata amounts, address[] calldata erc20Tokens ) external payable virtual override onlyClients nonReentrant stopGuarded { return _deposit(amounts, erc20Tokens); } function withdraw( uint256 amount, address erc20Token ) public virtual override onlyClients nonReentrant stopGuarded returns (bool) { return _withdraw(amount, erc20Token); } function withdrawTo( uint256 amount, address erc20Token, address to ) public virtual override onlyWhitelisted nonReentrant stopGuarded returns (bool) { // `to` account must be a client _checkRole(ROLE_CLIENT, to); return _withdrawTo(amount, erc20Token, to); } function withdrawAll( address[] calldata tokens ) public virtual override onlyClients nonReentrant stopGuarded returns (bool) { return _withdrawAll(tokens); } function withdrawAllTo( address[] calldata tokens, address to ) public virtual override onlyWhitelisted stopGuarded returns (bool) { _checkRole(ROLE_CLIENT, to); return _withdrawAllTo(tokens, to); } function supportsNativeAssets() public pure virtual override returns (bool) { return false; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { IBaseNativeWrapperV1 } from "../../BaseNativeWrapper/v1/IBaseNativeWrapperV1.sol"; import { BaseTransfers } from "../../BaseTransfers/v1/BaseTransfers.sol"; import { CoreTransfersNative } from "../../../core/CoreTransfersNative/v1/CoreTransfersNative.sol"; abstract contract BaseTransfersNative is IBaseNativeWrapperV1, CoreTransfersNative, BaseTransfers { function deposit( uint256[] calldata amounts, address[] calldata assetAddresses ) external payable override onlyClients nonReentrant stopGuarded { _depositNativeAndERC20(amounts, assetAddresses); emit Deposit(_msgSender(), assetAddresses, amounts); } function supportsNativeAssets() public pure override returns (bool) { return true; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { AccessControl as OZAccessControl } from "@openzeppelin/contracts/access/AccessControl.sol"; import { ICoreAccessControlV1 } from "./ICoreAccessControlV1.sol"; import { AccountNotAdmin, AccountNotWhitelisted, AccountMissingRole } from "../../libraries/DefinitiveErrors.sol"; struct CoreAccessControlConfig { address admin; address definitiveAdmin; address[] definitive; address[] client; } abstract contract CoreAccessControl is ICoreAccessControlV1, OZAccessControl { // roles bytes32 public constant ROLE_DEFINITIVE = keccak256("DEFINITIVE"); bytes32 public constant ROLE_DEFINITIVE_ADMIN = keccak256("DEFINITIVE_ADMIN"); bytes32 public constant ROLE_CLIENT = keccak256("CLIENT"); modifier onlyDefinitive() { _checkRole(ROLE_DEFINITIVE); _; } modifier onlyDefinitiveAdmin() { _checkRole(ROLE_DEFINITIVE_ADMIN); _; } modifier onlyClients() { _checkRole(ROLE_CLIENT); _; } modifier onlyClientAdmin() { _checkRole(DEFAULT_ADMIN_ROLE); _; } // default admin + definitive admin modifier onlyAdmins() { bool isAdmins = (hasRole(DEFAULT_ADMIN_ROLE, _msgSender()) || hasRole(ROLE_DEFINITIVE_ADMIN, _msgSender())); if (!isAdmins) { revert AccountNotAdmin(_msgSender()); } _; } // client + definitive modifier onlyWhitelisted() { bool isWhitelisted = (hasRole(ROLE_CLIENT, _msgSender()) || hasRole(ROLE_DEFINITIVE, _msgSender())); if (!isWhitelisted) { revert AccountNotWhitelisted(_msgSender()); } _; } constructor(CoreAccessControlConfig memory cfg) { // admin _setupRole(DEFAULT_ADMIN_ROLE, cfg.admin); // definitive admin _setupRole(ROLE_DEFINITIVE_ADMIN, cfg.definitiveAdmin); _setRoleAdmin(ROLE_DEFINITIVE_ADMIN, ROLE_DEFINITIVE_ADMIN); // definitive uint256 cfgDefinitiveLength = cfg.definitive.length; for (uint256 i; i < cfgDefinitiveLength; ) { _setupRole(ROLE_DEFINITIVE, cfg.definitive[i]); unchecked { ++i; } } _setRoleAdmin(ROLE_DEFINITIVE, ROLE_DEFINITIVE_ADMIN); // clients - implicit role admin is DEFAULT_ADMIN_ROLE uint256 cfgClientLength = cfg.client.length; for (uint256 i; i < cfgClientLength; ) { _setupRole(ROLE_CLIENT, cfg.client[i]); unchecked { ++i; } } } function _checkRole(bytes32 role, address account) internal view virtual override { if (!hasRole(role, account)) { revert AccountMissingRole(account, role); } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; interface ICoreAccessControlV1 is IAccessControl { function ROLE_CLIENT() external returns (bytes32); function ROLE_DEFINITIVE() external returns (bytes32); function ROLE_DEFINITIVE_ADMIN() external returns (bytes32); }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { ICoreDepositV1 } from "./ICoreDepositV1.sol"; import { Context } from "@openzeppelin/contracts/utils/Context.sol"; import { DefinitiveAssets, IERC20 } from "../../libraries/DefinitiveAssets.sol"; import { InvalidInputs } from "../../libraries/DefinitiveErrors.sol"; abstract contract CoreDeposit is ICoreDepositV1, Context { using DefinitiveAssets for IERC20; function deposit(uint256[] calldata amounts, address[] calldata assetAddresses) external payable virtual; function _deposit(uint256[] calldata amounts, address[] calldata erc20Tokens) internal virtual { _depositERC20(amounts, erc20Tokens); emit Deposit(_msgSender(), erc20Tokens, amounts); } function _depositERC20(uint256[] calldata amounts, address[] calldata erc20Tokens) internal { uint256 amountsLength = amounts.length; if (amountsLength != erc20Tokens.length) { revert InvalidInputs(); } for (uint256 i; i < amountsLength; ) { IERC20(erc20Tokens[i]).safeTransferFrom(_msgSender(), address(this), amounts[i]); unchecked { ++i; } } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; interface ICoreDepositV1 { event Deposit(address indexed actor, address[] assetAddresses, uint256[] amounts); function deposit(uint256[] calldata amounts, address[] calldata assetAddresses) external payable; }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { ICoreFeesV1 } from "./ICoreFeesV1.sol"; import { Context } from "@openzeppelin/contracts/utils/Context.sol"; struct CoreFeesConfig { address payable feeAccount; } abstract contract CoreFees is ICoreFeesV1, Context { address payable public FEE_ACCOUNT; constructor(CoreFeesConfig memory coreFeesConfig) { FEE_ACCOUNT = coreFeesConfig.feeAccount; } function _updateFeeAccount(address payable feeAccount) internal { FEE_ACCOUNT = feeAccount; emit FeeAccountUpdated(_msgSender(), feeAccount); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; interface ICoreFeesV1 { event FeeAccountUpdated(address actor, address feeAccount); function FEE_ACCOUNT() external returns (address payable); function updateFeeAccount(address payable feeAccount) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { ICoreMulticallV1 } from "./ICoreMulticallV1.sol"; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { DefinitiveAssets } from "../../libraries/DefinitiveAssets.sol"; /* solhint-disable max-line-length */ /** * @notice Implements openzeppelin/contracts/utils/Multicall.sol * Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5b027e517e6aee69f4b4b2f5e78274ac8ee53513/contracts/utils/Multicall.sol solhint-disable max-line-length */ /* solhint-enable max-line-length */ abstract contract CoreMulticall is ICoreMulticallV1 { /** * @dev Receives and executes a batch of function calls on this contract. */ function multicall(bytes[] calldata data) external returns (bytes[] memory results) { uint256 dataLength = data.length; results = new bytes[](dataLength); for (uint256 i; i < dataLength; ) { results[i] = Address.functionDelegateCall(address(this), data[i]); unchecked { ++i; } } } function getBalance(address assetAddress) public view returns (uint256) { return DefinitiveAssets.getBalance(assetAddress); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; interface ICoreMulticallV1 { function multicall(bytes[] calldata data) external returns (bytes[] memory results); function getBalance(address assetAddress) external view returns (uint256); }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { ICoreRewardsV1 } from "./ICoreRewardsV1.sol"; import { Context } from "@openzeppelin/contracts/utils/Context.sol"; import { IERC20 } from "../../libraries/DefinitiveAssets.sol"; abstract contract CoreRewards is ICoreRewardsV1, Context { /** * @dev Override this method for the implementation of returning tokens and their respective claim amounts * * @notice returns the reward token and amount of unclaimed tokens * @return (IERC20[], uint256[]) tokens and rewards */ function unclaimedRewards() public view virtual returns (IERC20[] memory, uint256[] memory); function claimAllRewards(uint256 feePct) external virtual returns (IERC20[] memory, uint256[] memory); /** * @dev Override this method for the implementation of claiming rewards */ function _claimAllRewards() internal virtual returns (IERC20[] memory, uint256[] memory); }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { IERC20 } from "../../../core/libraries/DefinitiveAssets.sol"; interface ICoreRewardsV1 { event RewardsClaimed(IERC20[] rewardTokens, uint256[] rewardAmounts, uint256[] feeAmounts); function unclaimedRewards() external view returns (IERC20[] memory, uint256[] memory); function claimAllRewards(uint256 feePct) external returns (IERC20[] memory, uint256[] memory); }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { ICoreStopGuardianV1 } from "./ICoreStopGuardianV1.sol"; import { Context } from "@openzeppelin/contracts/utils/Context.sol"; import { StopGuardianEnabled } from "../../libraries/DefinitiveErrors.sol"; abstract contract CoreStopGuardian is ICoreStopGuardianV1, Context { bool public STOP_GUARDIAN_ENABLED; // recommended for every public/external function modifier stopGuarded() { if (STOP_GUARDIAN_ENABLED) { revert StopGuardianEnabled(); } _; } function enableStopGuardian() public virtual; function disableStopGuardian() public virtual; function _enableStopGuardian() internal { STOP_GUARDIAN_ENABLED = true; emit StopGuardianUpdate(_msgSender(), true); } function _disableStopGuardian() internal { STOP_GUARDIAN_ENABLED = false; emit StopGuardianUpdate(_msgSender(), false); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; interface ICoreStopGuardianV1 { event StopGuardianUpdate(address indexed actor, bool indexed isEnabled); function STOP_GUARDIAN_ENABLED() external view returns (bool); function enableStopGuardian() external; function disableStopGuardian() external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { ICoreSwapV1 } from "./ICoreSwapV1.sol"; import { DefinitiveAssets, IERC20 } from "../../libraries/DefinitiveAssets.sol"; import { Context } from "@openzeppelin/contracts/utils/Context.sol"; import { CallUtils } from "../../../tools/BubbleReverts/BubbleReverts.sol"; import { DefinitiveConstants } from "../../libraries/DefinitiveConstants.sol"; import { InvalidSwapOutputToken, InvalidSwapHandler, InsufficientSwapTokenBalance, SwapTokenIsOutputToken, InvalidOutputToken, InvalidReportedOutputAmount, InvalidExecutedOutputAmount, SwapLimitExceeded } from "../../libraries/DefinitiveErrors.sol"; struct CoreSwapConfig { address[] swapTokens; address[] swapOutputTokens; address[] swapHandlers; } struct SwapPayload { address handler; uint256 amount; // set 0 for maximum available balance address swapToken; uint256 amountOutMin; bool isDelegate; bytes handlerCalldata; bytes signature; } abstract contract CoreSwap is ICoreSwapV1, Context { using DefinitiveAssets for IERC20; uint256 internal swapsThisBlock; uint256 internal latestBlockNumber; uint256 public immutable MAX_SWAPS_PER_BLOCK; /** * @notice Maintains mapping for reward tokens * @notice Tokens _not_ in this list will be treated as principal assets * @dev erc20 token => valid */ mapping(address => bool) public _swapTokens; /// @dev erc20 token => valid mapping(address => bool) public _swapOutputTokens; /// @dev handler contract => enabled mapping(address => bool) public _swapHandlers; modifier enforceSwapLimit(SwapPayload[] memory payloads) { if (block.number != latestBlockNumber) { latestBlockNumber = block.number; delete swapsThisBlock; } swapsThisBlock += payloads.length; if (swapsThisBlock > MAX_SWAPS_PER_BLOCK) { revert SwapLimitExceeded(); } _; } constructor(CoreSwapConfig memory coreSwapConfig) { uint256 coreswapConfigSwapTokensLength = coreSwapConfig.swapTokens.length; MAX_SWAPS_PER_BLOCK = DefinitiveConstants.MAX_SWAPS_PER_BLOCK; for (uint256 i; i < coreswapConfigSwapTokensLength; ) { _swapTokens[coreSwapConfig.swapTokens[i]] = true; unchecked { ++i; } } uint256 coreSwapConfigSwapOutputTokensLength = coreSwapConfig.swapOutputTokens.length; for (uint256 i; i < coreSwapConfigSwapOutputTokensLength; ) { _swapOutputTokens[coreSwapConfig.swapOutputTokens[i]] = true; unchecked { ++i; } } uint256 coreSwapConfigSwapHandlersLength = coreSwapConfig.swapHandlers.length; for (uint256 i; i < coreSwapConfigSwapHandlersLength; ) { _swapHandlers[coreSwapConfig.swapHandlers[i]] = true; unchecked { ++i; } } } function enableSwapTokens(address[] memory swapTokens) public virtual; function disableSwapTokens(address[] memory swapTokens) public virtual; function _updateSwapTokens(address[] memory swapTokens, bool enabled) internal { uint256 swapTokensLength = swapTokens.length; for (uint256 i; i < swapTokensLength; ) { _swapTokens[swapTokens[i]] = enabled; emit SwapTokenUpdate(_msgSender(), swapTokens[i], enabled); unchecked { ++i; } } } function enableSwapOutputTokens(address[] memory swapOutputTokens) public virtual; function disableSwapOutputTokens(address[] memory swapOutputTokens) public virtual; function _updateSwapOutputTokens(address[] memory swapOutputTokens, bool enabled) internal { uint256 swapOutputTokensLength = swapOutputTokens.length; for (uint256 i; i < swapOutputTokensLength; ) { _swapOutputTokens[swapOutputTokens[i]] = enabled; emit SwapOutputTokenUpdate(_msgSender(), swapOutputTokens[i], enabled); unchecked { ++i; } } } function enableSwapHandlers(address[] memory swapHandlers) public virtual; function disableSwapHandlers(address[] memory swapHandlers) public virtual; function _updateSwapHandlers(address[] memory swapHandlers, bool enabled) internal { uint256 swapHandlersLength = swapHandlers.length; for (uint256 i; i < swapHandlersLength; ) { _swapHandlers[swapHandlers[i]] = enabled; emit SwapHandlerUpdate(_msgSender(), swapHandlers[i], enabled); unchecked { ++i; } } } function swap( SwapPayload[] memory payloads, address outputToken, uint256 amountOutMin, uint256 feePct ) external virtual returns (uint256 outputAmount); function _swap( SwapPayload[] memory payloads, address expectedOutputToken ) internal enforceSwapLimit(payloads) returns (uint256[] memory inputTokenAmounts, uint256 outputTokenAmount) { if (!_swapOutputTokens[expectedOutputToken]) { revert InvalidSwapOutputToken(); } uint256 payloadsLength = payloads.length; inputTokenAmounts = new uint256[](payloadsLength); uint256 outputTokenBalanceStart = DefinitiveAssets.getBalance(expectedOutputToken); for (uint256 i; i < payloadsLength; ) { SwapPayload memory payload = payloads[i]; if (!_swapHandlers[payload.handler]) { revert InvalidSwapHandler(); } if (expectedOutputToken == payload.swapToken) { revert SwapTokenIsOutputToken(); } uint256 outputTokenBalanceBefore = DefinitiveAssets.getBalance(expectedOutputToken); inputTokenAmounts[i] = DefinitiveAssets.getBalance(payload.swapToken); (uint256 _outputAmount, address _outputToken) = _processSwap(payload, expectedOutputToken); if (_outputToken != expectedOutputToken) { revert InvalidOutputToken(); } if (_outputAmount < payload.amountOutMin) { revert InvalidReportedOutputAmount(); } uint256 outputTokenBalanceAfter = DefinitiveAssets.getBalance(expectedOutputToken); if ((outputTokenBalanceAfter - outputTokenBalanceBefore) < payload.amountOutMin) { revert InvalidExecutedOutputAmount(); } // Update `inputTokenAmounts` to reflect the amount of tokens actually swapped inputTokenAmounts[i] -= DefinitiveAssets.getBalance(payload.swapToken); unchecked { ++i; } } outputTokenAmount = DefinitiveAssets.getBalance(expectedOutputToken) - outputTokenBalanceStart; } function _processSwap(SwapPayload memory payload, address expectedOutputToken) private returns (uint256, address) { // Override payload.amount with validated amount payload.amount = _getValidatedPayloadAmount(payload); /// @dev if asset is in _swapTokens, then it is a reward token bool isPrincipalAssetSwap = !_swapTokens[payload.swapToken]; bytes memory _calldata = _getEncodedSwapHandlerCalldata( payload, expectedOutputToken, isPrincipalAssetSwap, payload.isDelegate ); bool _success; bytes memory _returnBytes; if (payload.isDelegate) { // slither-disable-next-line controlled-delegatecall (_success, _returnBytes) = payload.handler.delegatecall(_calldata); } else { _prepareAssetsForNonDelegateHandlerCall(payload, payload.amount); (_success, _returnBytes) = payload.handler.call(_calldata); } if (!_success) { CallUtils.revertFromReturnedData(_returnBytes); } return abi.decode(_returnBytes, (uint256, address)); } function _getEncodedSwapHandlerCalldata( SwapPayload memory payload, address expectedOutputToken, bool isPrincipalAssetSwap, bool isDelegateCall ) internal pure virtual returns (bytes memory); function _getValidatedPayloadAmount(SwapPayload memory payload) private view returns (uint256 amount) { uint256 balance = DefinitiveAssets.getBalance(payload.swapToken); // Ensure balance > 0 DefinitiveAssets.validateAmount(balance); amount = payload.amount; if (amount != 0 && balance < amount) { revert InsufficientSwapTokenBalance(); } // maximum available balance if amount == 0 if (amount == 0) { return balance; } } function _prepareAssetsForNonDelegateHandlerCall(SwapPayload memory payload, uint256 amount) private { if (payload.swapToken == DefinitiveConstants.NATIVE_ASSET_ADDRESS) { // Send ETH to handler DefinitiveAssets.safeTransferETH(payable(payload.handler), amount); } else { IERC20(payload.swapToken).resetAndSafeIncreaseAllowance(address(this), payload.handler, amount); } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { SwapPayload } from "./CoreSwap.sol"; interface ICoreSwapV1 { event SwapHandlerUpdate(address actor, address swapHandler, bool isEnabled); event SwapTokenUpdate(address actor, address swapToken, bool isEnabled); event SwapOutputTokenUpdate(address actor, address swapOutputToken, bool isEnabled); event SwapHandled( address[] swapTokens, uint256[] swapAmounts, address outputToken, uint256 outputAmount, uint256 feeAmount ); function enableSwapTokens(address[] memory swapTokens) external; function disableSwapTokens(address[] memory swapTokens) external; function enableSwapOutputTokens(address[] memory swapOutputTokens) external; function disableSwapOutputTokens(address[] memory swapOutputTokens) external; function enableSwapHandlers(address[] memory swapHandlers) external; function disableSwapHandlers(address[] memory swapHandlers) external; function swap( SwapPayload[] memory payloads, address outputToken, uint256 amountOutMin, uint256 feePct ) external returns (uint256 outputAmount); }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; interface ICoreSwapHandlerV1 { event Swap( address indexed actor, address indexed inputToken, uint256 inputAmount, address indexed outputToken, uint256 outputAmount ); struct SwapParams { address inputAssetAddress; uint256 inputAmount; address outputAssetAddress; uint256 minOutputAmount; bytes data; bytes signature; } function swapCall(SwapParams calldata params) external payable returns (uint256 amountOut, address outputAsset); function swapDelegate(SwapParams calldata params) external payable returns (uint256 amountOut, address outputAsset); function swapUsingValidatedPathCall( SwapParams calldata params ) external payable returns (uint256 amountOut, address outputAsset); }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { Context } from "@openzeppelin/contracts/utils/Context.sol"; import { ICoreTransfersNativeV1 } from "./ICoreTransfersNativeV1.sol"; import { DefinitiveAssets, IERC20 } from "../../libraries/DefinitiveAssets.sol"; import { DefinitiveConstants } from "../../libraries/DefinitiveConstants.sol"; import { InvalidInputs, InvalidMsgValue } from "../../libraries/DefinitiveErrors.sol"; abstract contract CoreTransfersNative is ICoreTransfersNativeV1, Context { using DefinitiveAssets for IERC20; /** * @notice Allows contract to receive native assets */ receive() external payable virtual {} /** * @notice This function is executed if none of the other functions * match the call data. `bytes calldata` will contain the full data sent * to the contract (equal to msg.data) and can return data in output. * The returned data will not be ABI-encoded, and will be returned without * modifications (not even padding). * https://docs.soliditylang.org/en/v0.8.17/contracts.html#fallback-function */ fallback(bytes calldata) external payable virtual returns (bytes memory) {} function _depositNativeAndERC20(uint256[] calldata amounts, address[] calldata assetAddresses) internal virtual { uint256 assetAddressesLength = assetAddresses.length; if (amounts.length != assetAddressesLength) { revert InvalidInputs(); } bool hasNativeAsset; uint256 nativeAssetIndex; for (uint256 i; i < assetAddressesLength; ) { if (assetAddresses[i] == DefinitiveConstants.NATIVE_ASSET_ADDRESS) { nativeAssetIndex = i; hasNativeAsset = true; unchecked { ++i; } continue; } // ERC20 tokens IERC20(assetAddresses[i]).safeTransferFrom(_msgSender(), address(this), amounts[i]); unchecked { ++i; } } // Revert if NATIVE_ASSET_ADDRESS is not in assetAddresses and msg.value is not zero if (!hasNativeAsset && msg.value != 0) { revert InvalidMsgValue(); } // Revert if depositing native asset and amount != msg.value if (hasNativeAsset && msg.value != amounts[nativeAssetIndex]) { revert InvalidMsgValue(); } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; interface ICoreTransfersNativeV1 { receive() external payable; fallback(bytes calldata) external payable returns (bytes memory); }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { ICoreWithdrawV1 } from "./ICoreWithdrawV1.sol"; import { DefinitiveAssets, IERC20 } from "../../libraries/DefinitiveAssets.sol"; import { Context } from "@openzeppelin/contracts/utils/Context.sol"; import { DefinitiveConstants } from "../../libraries/DefinitiveConstants.sol"; abstract contract CoreWithdraw is ICoreWithdrawV1, Context { using DefinitiveAssets for IERC20; function supportsNativeAssets() public pure virtual returns (bool); function withdraw(uint256 amount, address erc20Token) public virtual returns (bool); function withdrawTo(uint256 amount, address erc20Token, address to) public virtual returns (bool); function _withdraw(uint256 amount, address erc20Token) internal returns (bool) { return _withdrawTo(amount, erc20Token, _msgSender()); } function _withdrawTo(uint256 amount, address erc20Token, address to) internal returns (bool success) { if (erc20Token == DefinitiveConstants.NATIVE_ASSET_ADDRESS) { DefinitiveAssets.safeTransferETH(payable(to), amount); } else { IERC20(erc20Token).safeTransfer(to, amount); } emit Withdrawal(erc20Token, amount, to); success = true; } function withdrawAll(address[] calldata tokens) public virtual returns (bool); function withdrawAllTo(address[] calldata tokens, address to) public virtual returns (bool); function _withdrawAll(address[] calldata tokens) internal returns (bool) { return _withdrawAllTo(tokens, _msgSender()); } function _withdrawAllTo(address[] calldata tokens, address to) internal returns (bool success) { uint256 tokenLength = tokens.length; for (uint256 i; i < tokenLength; ) { uint256 tokenBalance = DefinitiveAssets.getBalance(tokens[i]); if (tokenBalance > 0) { _withdrawTo(tokenBalance, tokens[i], to); } unchecked { ++i; } } return true; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; interface ICoreWithdrawV1 { event Withdrawal(address indexed erc20Token, uint256 amount, address indexed recipient); function withdrawAll(address[] calldata tokens) external returns (bool); function withdrawAllTo(address[] calldata tokens, address to) external returns (bool); function supportsNativeAssets() external pure returns (bool); function withdraw(uint256 amount, address erc20Token) external returns (bool); }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { IERC20, SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { SafeTransferLib } from "solmate/src/utils/SafeTransferLib.sol"; import { DefinitiveConstants } from "./DefinitiveConstants.sol"; import { InsufficientBalance, InvalidAmount, InvalidAmounts, InvalidERC20Address } from "./DefinitiveErrors.sol"; /** * @notice Contains methods used throughout the Definitive contracts * @dev This file should only be used as an internal library. */ library DefinitiveAssets { /** * @dev Checks if an address is a valid ERC20 token */ modifier onlyValidERC20(address erc20Token) { if (address(erc20Token) == DefinitiveConstants.NATIVE_ASSET_ADDRESS) { revert InvalidERC20Address(); } _; } ////////////////////////////////////////////////// ////////////////////////////////////////////////// // ↓ ERC20 and Native Asset Methods ↓ ////////////////////////////////////////////////// /** * @dev Gets the balance of an ERC20 token or native asset */ function getBalance(address assetAddress) internal view returns (uint256) { if (assetAddress == DefinitiveConstants.NATIVE_ASSET_ADDRESS) { return address(this).balance; } else { return IERC20(assetAddress).balanceOf(address(this)); } } /** * @dev internal function to validate balance is higher than a given amount for ERC20 and native assets */ function validateBalance(address token, uint256 amount) internal view { if (token == DefinitiveConstants.NATIVE_ASSET_ADDRESS) { validateNativeBalance(amount); } else { validateERC20Balance(token, amount); } } ////////////////////////////////////////////////// ////////////////////////////////////////////////// // ↓ Native Asset Methods ↓ ////////////////////////////////////////////////// /** * @dev validates amount and balance, then uses SafeTransferLib to transfer native asset */ function safeTransferETH(address recipient, uint256 amount) internal { if (amount > 0) { SafeTransferLib.safeTransferETH(payable(recipient), amount); } } ////////////////////////////////////////////////// ////////////////////////////////////////////////// // ↓ ERC20 Methods ↓ ////////////////////////////////////////////////// /** * @dev Resets and increases the allowance of a spender for an ERC20 token */ function resetAndSafeIncreaseAllowance( IERC20 token, address owner, address spender, uint256 amount ) internal onlyValidERC20(address(token)) { if (token.allowance(owner, spender) > 0) { SafeERC20.safeApprove(token, spender, 0); } return SafeERC20.safeIncreaseAllowance(token, spender, amount); } function safeTransfer(IERC20 token, address to, uint256 amount) internal onlyValidERC20(address(token)) { if (amount > 0) { SafeERC20.safeTransfer(token, to, amount); } } function safeTransferFrom( IERC20 token, address from, address to, uint256 amount ) internal onlyValidERC20(address(token)) { if (amount > 0) { //slither-disable-next-line arbitrary-send-erc20 SafeERC20.safeTransferFrom(token, from, to, amount); } } ////////////////////////////////////////////////// ////////////////////////////////////////////////// // ↓ Asset Amount Helper Methods ↓ ////////////////////////////////////////////////// /** * @dev internal function to validate that amounts contains a value greater than zero */ function validateAmounts(uint256[] calldata amounts) internal pure { bool hasValidAmounts; uint256 amountsLength = amounts.length; for (uint256 i; i < amountsLength; ) { if (amounts[i] > 0) { hasValidAmounts = true; break; } unchecked { ++i; } } if (!hasValidAmounts) { revert InvalidAmounts(); } } /** * @dev internal function to validate if native asset balance is higher than the amount requested */ function validateNativeBalance(uint256 amount) internal view { if (getBalance(DefinitiveConstants.NATIVE_ASSET_ADDRESS) < amount) { revert InsufficientBalance(); } } /** * @dev internal function to validate balance is higher than the amount requested for a token */ function validateERC20Balance(address token, uint256 amount) internal view onlyValidERC20(token) { if (getBalance(token) < amount) { revert InsufficientBalance(); } } function validateAmount(uint256 _amount) internal pure { if (_amount == 0) { revert InvalidAmount(); } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; /** * @notice Contains constants used throughout the Definitive contracts * @dev This file should only be used as an internal library. */ library DefinitiveConstants { /** * @notice Maximum fee percentage */ uint256 internal constant MAX_FEE_PCT = 10000; /** * @notice Address to signify native assets */ address internal constant NATIVE_ASSET_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; /** * @notice Maximum number of swaps allowed per block */ uint8 internal constant MAX_SWAPS_PER_BLOCK = 25; struct Assets { uint256[] amounts; address[] addresses; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; /** * @notice Contains all errors used throughout the Definitive contracts * @dev This file should only be used as an internal library. * @dev When adding a new error, add alphabetically */ error AccountMissingRole(address _account, bytes32 _role); error AccountNotAdmin(address); error AccountNotWhitelisted(address); error AddLiquidityFailed(); error DeadlineExceeded(); error BorrowFailed(uint256 errorCode); error DecollateralizeFailed(uint256 errorCode); error DepositMoreThanMax(); error EnterAllFailed(); error EnforcedSafeLTV(uint256 invalidLTV); error ExceededMaxDelta(); error ExceededMaxLTV(); error ExceededShareToAssetRatioDeltaThreshold(); error ExitAllFailed(); error ExitOneCoinFailed(); error InitializeMarketsFailed(); error InputGreaterThanStaked(); error InsufficientBalance(); error InsufficientSwapTokenBalance(); error InvalidAmount(); error InvalidAmounts(); error InvalidCalldata(); error InvalidDestinationSwapper(); error InvalidERC20Address(); error InvalidExecutedOutputAmount(); error InvalidFeePercent(); error InvalidHandler(); error InvalidInputs(); error InvalidMsgValue(); error InvalidSingleHopSwap(); error InvalidMultiHopSwap(); error InvalidOutputToken(); error InvalidRedemptionRecipient(); // Used in cross-chain redeptions error InvalidReportedOutputAmount(); error InvalidRewardsClaim(); error InvalidSignature(); error InvalidSignatureLength(); error InvalidSwapHandler(); error InvalidSwapInputAmount(); error InvalidSwapOutputToken(); error InvalidSwapPath(); error InvalidSwapPayload(); error InvalidSwapToken(); error MintMoreThanMax(); error NativeAssetWrapFailed(bool wrappingToNative); error NoSignatureVerificationSignerSet(); error RedeemMoreThanMax(); error RemoveLiquidityFailed(); error RepayDebtFailed(); error SafeHarborModeEnabled(); error SafeHarborRedemptionDisabled(); error SlippageExceeded(uint256 _outputAmount, uint256 _outputAmountMin); error StakeFailed(); error SupplyFailed(); error StopGuardianEnabled(); error SwapDeadlineExceeded(); error SwapLimitExceeded(); error SwapTokenIsOutputToken(); error TransfersLimitExceeded(); error UnstakeFailed(); error UnauthenticatedFlashloan(); error UntrustedFlashLoanSender(address); error WithdrawMoreThanMax(); error ZeroShares();
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { ICoreMulticallV1 } from "../../../core/CoreMulticall/v1/ICoreMulticallV1.sol"; import { SwapPayload } from "../../../base/BaseSwap.sol"; import { IBasePermissionedExecution } from "../../../base/BasePermissionedExecution/IBasePermissionedExecution.sol"; interface ILLSDStrategyV1 is ICoreMulticallV1, IBasePermissionedExecution { event Enter( uint256 collateral, uint256 collateralDelta, uint256 debt, uint256 debtDelta, address[] dryAssets, int256[] dryBalanceDeltas, uint256 ltv ); event Exit( uint256 collateral, uint256 collateralDelta, uint256 debt, uint256 debtDelta, address[] dryAssets, int256[] dryBalanceDeltas, uint256 ltv ); event SweepDust(uint256 collateral, uint256 collateralDelta, uint256 debt, uint256 debtDelta, uint256 ltv); struct EnterContext { uint256 flashloanAmount; SwapPayload swapPayload; uint256 maxLTV; } struct ExitContext { uint256 flashloanAmount; uint256 repayAmount; uint256 decollateralizeAmount; SwapPayload swapPayload; uint256 maxLTV; } enum FlashLoanContextType { ENTER, EXIT } function STAKED_TOKEN() external view returns (address); function STAKING_TOKEN() external view returns (address); /** * @notice Enter or increase leverage using a flashloan. * Steps: * 1. Flashloan `flashloanAmount` of the staking asset (eg: WETH) * 2a. On chains that support staking, stake the entire dry balance of the staking token (eg: WETH) * 2b. All other chains, the `swapPayload` will swap `flashloanAmount` to the staked asset * 3. Collateralize strategy balance of `dry` staked token (eg: wstETH) * 4. Borrow `flashloanAmount` * 5. Repay flashloan * 6. Verify LTV is below inputted threshold * @dev Swapping is only initiated if `SwapPayload.amount` > 0. * @dev 2b: `SwapPayload.amount` determines the amount of staking asset to swap * @param flashloanAmount Amount to flashloan * @param swapPayload Swaps to staked asset when native staking is not possible. * Not used on chains that support native staking. * @param maxLTV Verify LTV at the end of the operation */ function enter(uint256 flashloanAmount, SwapPayload calldata swapPayload, uint256 maxLTV) external; /** * @notice Enter or increase leverage using multicall looping. * Steps: * 1. Collateralize strategy balance of `dry` staked asset (eg: wstETH) * 2. Borrow staking asset * 3a. On chains that support staking, stake the entire dry balance of the staking token (eg: WETH) * 3b. All other chains, the `swapPayload` will swap `flashloanAmount` to the staked asset * 4. Verify LTV is below inputted threshold * @dev Swapping is only initiated if `SwapPayload.amount` > 0. * This can occur to allow users to withdraw the staked asset. * @param borrowAmount Amount to borrow * @param swapPayload Swaps in to staked asset when native staking is not possible. * * Not used on chains that support native staking. * @param maxLTV Verify LTV at the end of the operation */ function enterMulticall(uint256 borrowAmount, SwapPayload calldata swapPayload, uint256 maxLTV) external; /** * @notice Exit or decrease leverage using a flashloan. * Steps: * 1. Flashloan `flashloanAmount` of the staking asset (eg: WETH) * 2. Repay `repayAmount` * 3. Decollateralize `flashloanAmount` * 4a. On chains that support unstaking, unstake `flashloanAmount` * 4b. All other chains, `swapPayload` will swap `decollateralizeAmount` out of the staked asset * 5. Repay `flashloanAmount` * 6. Verify LTV is below inputted threshold * @dev `flashloanAmount` less `repayAmount` is the amount of the staking asset to leave dry. * @dev Swapping is only initiated if `SwapPayload.amount` > 0. * This can occur to allow users to withdraw the staked asset. * @param flashloanAmount Amount to flashloan * @param repayAmount Amount of `flashloanAmount` to repay * @param decollateralizeAmount Amount of staked asset to remove as collateral * @param swapPayload Swaps to staking asset when native unstaking is not possible * On chains that support unstaking, `SwapPayload.amount` is used to unstake * @param maxLTV Verify LTV at the end of the operation */ function exit( uint256 flashloanAmount, uint256 repayAmount, uint256 decollateralizeAmount, SwapPayload calldata swapPayload, uint256 maxLTV ) external; /** * @notice Exit or decrease leverage using multicall looping. * Steps: * 1. Decollateralize `decollateralizeAmount` * 2a. On chains that support unstaking, unstake `decollateralizeAmount` * 2b. All other chains, `swapPayload` will swap `decollateralizeAmount` out of the staked asset * 3. If `repayDebt` is `true`, repay using the min(output of swap from step 2, outstanding debt) * Minimum amount is used to allow users to withdraw the staked asset. * If `repayDebt` is `false`, no repayment will be made. * 4. Verify LTV is below inputted threshold * @dev Swapping is only initiated if `SwapPayload.amount` > 0. * This can occur to allow users to withdraw the staked asset. * @dev `repayDebt` can be set to `true` to allow users to withdraw the staking asset. * @param decollateralizeAmount Amount of staked asset to remove as collateral * @param swapPayload Swaps to staking asset when native unstaking is not possible * On chains that support unstaking, `SwapPayload.amount` is used to unstake * @param repayDebt Flag to repay decollateralized asset * @param maxLTV Verify LTV at the end of the operation */ function exitMulticall( uint256 decollateralizeAmount, SwapPayload calldata swapPayload, bool repayDebt, uint256 maxLTV ) external; /** * @notice Vault balances of supplyable assets are supplied; * vault balances of repayable assets are repaid */ function sweepDust() external; // view functions function getDebtAmount() external view returns (uint256); function getCollateralAmount() external view returns (uint256); /// @notice Returns the oracle price of the debt asset in terms of the collateral asset function getCollateralToDebtPrice() external view returns (uint256 price, uint256 precision); function getLTV() external view returns (uint256); }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { ILLSDStrategyV1 } from "./ILLSDStrategyV1.sol"; import { BaseSwap, CoreSwapConfig, SwapPayload } from "../../../base/BaseSwap.sol"; import { CoreMulticall } from "../../../core/CoreMulticall/v1/CoreMulticall.sol"; import { BaseAccessControl, CoreAccessControlConfig } from "../../../base/BaseAccessControl.sol"; import { DefinitiveAssets, IERC20 } from "../../../core/libraries/DefinitiveAssets.sol"; import { ExceededMaxLTV, InvalidRewardsClaim } from "../../../core/libraries/DefinitiveErrors.sol"; import { BaseFees, CoreFeesConfig } from "../../../base/BaseFees.sol"; import { BasePermissionedExecution } from "../../../base/BasePermissionedExecution/BasePermissionedExecution.sol"; import { BaseSafeHarborMode } from "../../../base/BaseSafeHarborMode/BaseSafeHarborMode.sol"; import { BaseRewards } from "../../../base/BaseRewards.sol"; struct LLSDStrategyConfig { address stakingToken; address stakedToken; } abstract contract LLSDStrategy is ILLSDStrategyV1, BaseSwap, CoreMulticall, BasePermissionedExecution, BaseSafeHarborMode, BaseRewards { address[] internal DRY_TOKENS; constructor( CoreAccessControlConfig memory coreAccessControlConfig, CoreSwapConfig memory coreSwapConfig, CoreFeesConfig memory coreFeesConfig, LLSDStrategyConfig memory llsdConfig ) BaseAccessControl(coreAccessControlConfig) BaseSwap(coreSwapConfig) BaseFees(coreFeesConfig) { DRY_TOKENS = new address[](2); DRY_TOKENS[0] = llsdConfig.stakedToken; DRY_TOKENS[1] = llsdConfig.stakingToken; } function STAKED_TOKEN() public view returns (address) { return DRY_TOKENS[0]; } function STAKING_TOKEN() public view returns (address) { return DRY_TOKENS[1]; } modifier emitEvent(FlashLoanContextType _type) { (uint256 collateralBefore, uint256 debtBefore, int256[] memory dryBalanceDeltas) = ( getCollateralAmount(), getDebtAmount(), _getBalanceDeltas(new int256[](2)) ); _; emitEnterOrExitEvent(collateralBefore, debtBefore, dryBalanceDeltas, _type); } modifier enforceMaxLTV(uint256 maxLTV) { _; // Confirm LTV is below maxLTV if (getLTV() > maxLTV) { revert ExceededMaxLTV(); } } function emitEnterOrExitEvent( uint256 collateralBefore, uint256 debtBefore, int256[] memory dryBalancesBefore, FlashLoanContextType _type ) internal { (uint256 collateralAfter, uint256 debtAfter, int256[] memory dryBalanceDeltas, uint256 ltv) = ( getCollateralAmount(), getDebtAmount(), _getBalanceDeltas(dryBalancesBefore), getLTV() ); if (_type == FlashLoanContextType.ENTER) { // Upon enter, collateral and debt amounts can not decrease emit Enter( collateralAfter, collateralAfter - collateralBefore, debtAfter, debtAfter - debtBefore, DRY_TOKENS, dryBalanceDeltas, ltv ); } else if (_type == FlashLoanContextType.EXIT) { // Upon exit, collateral and debt amounts can not increase emit Exit( collateralAfter, collateralBefore - collateralAfter, debtAfter, debtBefore - debtAfter, DRY_TOKENS, dryBalanceDeltas, ltv ); } } function enterMulticall( uint256 borrowAmount, SwapPayload calldata swapPayload, uint256 maxLTV ) external virtual onlyWhitelisted stopGuarded nonReentrant enforceMaxLTV(maxLTV) emitEvent(FlashLoanContextType.ENTER) { address mSTAKED_TOKEN = STAKED_TOKEN(); // Supply dry balances of staked token _supply(DefinitiveAssets.getBalance(mSTAKED_TOKEN)); _borrow(borrowAmount); // Swap in to staked asset if (swapPayload.amount > 0) { SwapPayload[] memory swapPayloads = new SwapPayload[](1); swapPayloads[0] = swapPayload; _swap(swapPayloads, mSTAKED_TOKEN); } } function exitMulticall( uint256 decollateralizeAmount, SwapPayload calldata swapPayload, bool repayDebt, uint256 maxLTV ) external onlyWhitelisted stopGuarded nonReentrant enforceMaxLTV(maxLTV) emitEvent(FlashLoanContextType.EXIT) { // Decollateralize _decollateralize(decollateralizeAmount); address mSTAKING_TOKEN = STAKING_TOKEN(); uint256 swapOutput = DefinitiveAssets.getBalance(mSTAKING_TOKEN); // Swap out of staked asset if (swapPayload.amount > 0) { SwapPayload[] memory swapPayloads = new SwapPayload[](1); swapPayloads[0] = swapPayload; _swap(swapPayloads, mSTAKING_TOKEN); // Store the amount of staking asset received from swap swapOutput = DefinitiveAssets.getBalance(mSTAKING_TOKEN) - swapOutput; } // Repay debt if (repayDebt) { // Repay the min of the swap output or the debt amount uint256 debtAmount = getDebtAmount(); uint256 repayAmount = swapOutput < debtAmount ? swapOutput : debtAmount; _repay(repayAmount); } } function sweepDust() external onlyWhitelisted stopGuarded nonReentrant { (uint256 collateralBefore, uint256 debtBefore) = (getCollateralAmount(), getDebtAmount()); if (collateralBefore > 0 && debtBefore > 0) { _repay(DefinitiveAssets.getBalance(STAKING_TOKEN())); } _supply(DefinitiveAssets.getBalance(STAKED_TOKEN())); (uint256 collateralAfter, uint256 debtAfter) = (getCollateralAmount(), getDebtAmount()); emit SweepDust( collateralAfter, collateralAfter - collateralBefore, debtAfter, debtBefore - debtAfter, getLTV() ); } function getCollateralAmount() public view virtual returns (uint256); function getDebtAmount() public view virtual returns (uint256); function getLTV() public view virtual returns (uint256); /// @dev By default, `unclaimedRewards()` will return 0 tokens + 0 reward amounts function unclaimedRewards() public view virtual override returns (IERC20[] memory rewardTokens, uint256[] memory earnedAmounts) {} function _borrow(uint256 amount) internal virtual; function _decollateralize(uint256 amount) internal virtual; function _repay(uint256 amount) internal virtual; function _supply(uint256 amount) internal virtual; /// @dev By default, `_claimAllRewards()` will revert function _claimAllRewards() internal virtual override returns (IERC20[] memory, uint256[] memory) { revert InvalidRewardsClaim(); } function _getBalanceDeltas( int256[] memory previousDryBalances ) internal view returns (int256[] memory dryBalanceDeltas) { address[] memory mDryAssets = DRY_TOKENS; dryBalanceDeltas = new int256[](mDryAssets.length); uint256 length = mDryAssets.length; uint256 i = 0; while (i < length) { dryBalanceDeltas[i] = int256(DefinitiveAssets.getBalance(mDryAssets[i])) - previousDryBalances[i]; unchecked { ++i; } } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { BaseNativeWrapper, BaseNativeWrapperConfig } from "../../base/BaseNativeWrapper/v1/BaseNativeWrapper.sol"; import { IWETH9 } from "../../vendor/interfaces/IWETH9.sol"; abstract contract WETH9NativeWrapper is BaseNativeWrapper { constructor(BaseNativeWrapperConfig memory config) BaseNativeWrapper(config) {} function _wrap(uint256 amount) internal override { // slither-disable-next-line arbitrary-send-eth IWETH9(WRAPPED_NATIVE_ASSET_ADDRESS).deposit{ value: amount }(); } function _unwrap(uint256 amount) internal override { IWETH9(WRAPPED_NATIVE_ASSET_ADDRESS).withdraw(amount); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { IFlashLoanRecipient, IERC20 as BalancerIERC20 } from "@balancer-labs/v2-interfaces/contracts/vault/IFlashLoanRecipient.sol"; import { IVault } from "@balancer-labs/v2-interfaces/contracts/vault/IVault.sol"; import { DefinitiveAssets, IERC20 } from "../../core/libraries/DefinitiveAssets.sol"; import { UnauthenticatedFlashloan, UntrustedFlashLoanSender } from "../../core/libraries/DefinitiveErrors.sol"; abstract contract BalancerFlashloanBase { using DefinitiveAssets for IERC20; address private constant BALANCER_VAULT = 0xBA12222222228d8Ba445958a75a0704d566BF2C8; bool private isAuthenticated; function initiateFlashLoan(address borrowToken, uint256 amount, bytes memory userData) internal { (BalancerIERC20[] memory tokens, uint256[] memory amounts) = (new BalancerIERC20[](1), new uint256[](1)); tokens[0] = BalancerIERC20(borrowToken); amounts[0] = amount; isAuthenticated = true; IVault(BALANCER_VAULT).flashLoan(IFlashLoanRecipient(address(this)), tokens, amounts, userData); } function receiveFlashLoan( IERC20[] memory tokens, uint256[] memory amounts, uint256[] memory feeAmounts, bytes memory userData ) external { // we must enforce that only the flashloan provider vault can call this function if (msg.sender != BALANCER_VAULT) { revert UntrustedFlashLoanSender(msg.sender); } // Enforce we initiated the flashloan if (!isAuthenticated) { revert UnauthenticatedFlashloan(); } // Reset authentication isAuthenticated = false; onFlashLoanReceived(address(tokens[0]), amounts[0], feeAmounts[0], userData); // Send tokens back to the balancer vault // slither-disable-next-line arbitrary-send-erc20 tokens[0].safeTransfer(BALANCER_VAULT, amounts[0] + feeAmounts[0]); } function onFlashLoanReceived( address token, uint256 amount, uint256 feeAmount, bytes memory userData ) internal virtual; }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; /** * @dev IComet source code https://etherscan.io/address/0xea270ca1b5133e58f935a035f3bc5da53975fa9c#code */ interface IComet { /* solhint-disable explicit-types */ event Supply(address indexed from, address indexed dst, uint256 amount); event Withdraw(address indexed src, address indexed to, uint amount); event SupplyCollateral(address indexed from, address indexed dst, address indexed asset, uint amount); event WithdrawCollateral(address indexed src, address indexed to, address indexed asset, uint amount); function supply(address asset, uint amount) external; function withdraw(address asset, uint amount) external; function balanceOf(address account) external view returns (uint256); function borrowBalanceOf(address account) external view returns (uint256); function collateralBalanceOf(address account, address asset) external view returns (uint128); function getPrice(address priceFeed) external view returns (uint256); function getAssetInfoByAddress( address asset ) external view returns ( uint8 offset, address assetAddress, address priceFeed, uint64 scale, uint64 borrowCollateralFactor, uint64 liquidateCollateralFactor, uint64 liquidationFactor, uint128 supplyCap ); /* solhint-disable explicit-types */ }
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.18; import { IComet } from "../../../protocols/compound/Interfaces.sol"; import { DefinitiveAssets, IERC20 } from "../../../core/libraries/DefinitiveAssets.sol"; abstract contract CompoundV3 { using DefinitiveAssets for IERC20; address public immutable COMET_ADDRESS; constructor(address _cometAddress) { COMET_ADDRESS = _cometAddress; } function supply(address asset, uint256 amount) internal { if (amount > 0) { IERC20(asset).resetAndSafeIncreaseAllowance(address(this), COMET_ADDRESS, amount); IComet(COMET_ADDRESS).supply(asset, amount); } } function borrow(address asset, uint256 amount) internal { if (amount > 0) { IComet(COMET_ADDRESS).withdraw(asset, amount); } } /// @dev If `amount` is type(uint256).max, the entire debt balance will be used. function repay(address asset, uint256 amount) internal { uint256 debtAmount = _getTotalVariableDebt(); if (amount > debtAmount) { return supply(asset, debtAmount); } return supply(asset, amount); } /// @dev If `amount` is type(uint256).max, the entire collateral balance will be used. function decollateralize(address asset, uint256 amount) internal { uint256 collateralAmount = _getTotalCollateral(asset); if (amount > collateralAmount) { return borrow(asset, collateralAmount); } return borrow(asset, amount); } function _getTotalCollateral(address asset) internal view returns (uint256) { return IComet(COMET_ADDRESS).collateralBalanceOf(address(this), asset); } function _getLTV(address asset) internal view returns (uint256) { IComet comet = IComet(COMET_ADDRESS); (uint256 borrowAmount, uint256 collateralAmount) = ( comet.borrowBalanceOf(address(this)), comet.collateralBalanceOf(address(this), asset) ); (uint256 price, uint256 precision) = _getOraclePrice(asset); // LTV Basis Points Precision: 1e4 return collateralAmount * price == 0 ? 0 : (borrowAmount * 1e4 * precision) / (collateralAmount * price); } function _getTotalVariableDebt() internal view returns (uint256) { return IComet(COMET_ADDRESS).borrowBalanceOf(address(this)); } function _getOraclePrice(address tokenAddress) internal view returns (uint256 price, uint256 precision) { (, , address tokenPriceFeed, , , , , ) = IComet(COMET_ADDRESS).getAssetInfoByAddress(tokenAddress); return ( IComet(COMET_ADDRESS).getPrice(tokenPriceFeed), 1e8 // 1e8 is the precision of the price feed ); } }
// SPDX-License-Identifier: AGPLv3 pragma solidity >=0.8.18; import { InvalidCalldata } from "../../core/libraries/DefinitiveErrors.sol"; /** * @title Call utilities library that is absent from the OpenZeppelin * @author Superfluid * Forked from * https://github.com/superfluid-finance/protocol-monorepo/blob * /d473b4876a689efb3bbb05552040bafde364a8b2/packages/ethereum-contracts/contracts/libs/CallUtils.sol * (Separated by 2 lines to prevent going over 120 character per line limit) */ library CallUtils { /// @dev Bubble up the revert from the returnedData (supports Panic, Error & Custom Errors) /// @notice This is needed in order to provide some human-readable revert message from a call /// @param returnedData Response of the call function revertFromReturnedData(bytes memory returnedData) internal pure { if (returnedData.length < 4) { // case 1: catch all revert("CallUtils: target revert()"); // solhint-disable-line custom-errors } else { bytes4 errorSelector; // solhint-disable-next-line no-inline-assembly assembly { errorSelector := mload(add(returnedData, 0x20)) } if (errorSelector == bytes4(0x4e487b71) /* `seth sig "Panic(uint256)"` */) { // case 2: Panic(uint256) (Defined since 0.8.0) // solhint-disable-next-line max-line-length // ref: https://docs.soliditylang.org/en/v0.8.0/control-structures.html#panic-via-assert-and-error-via-require) string memory reason = "CallUtils: target panicked: 0x__"; uint256 errorCode; // solhint-disable-next-line no-inline-assembly assembly { errorCode := mload(add(returnedData, 0x24)) let reasonWord := mload(add(reason, 0x20)) // [0..9] is converted to ['0'..'9'] // [0xa..0xf] is not correctly converted to ['a'..'f'] // but since panic code doesn't have those cases, we will ignore them for now! let e1 := add(and(errorCode, 0xf), 0x30) let e2 := shl(8, add(shr(4, and(errorCode, 0xf0)), 0x30)) reasonWord := or( and(reasonWord, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000), or(e2, e1) ) mstore(add(reason, 0x20), reasonWord) } revert(reason); } else { // case 3: Error(string) (Defined at least since 0.7.0) // case 4: Custom errors (Defined since 0.8.0) uint256 len = returnedData.length; // solhint-disable-next-line no-inline-assembly assembly { revert(add(returnedData, 32), len) } } } } /** * @dev Helper method to parse data and extract the method signature (selector). * * Copied from: https://github.com/argentlabs/argent-contracts/ * blob/master/contracts/modules/common/Utils.sol#L54-L60 */ function parseSelector(bytes memory callData) internal pure returns (bytes4 selector) { if (callData.length < 4) { revert InvalidCalldata(); } // solhint-disable-next-line no-inline-assembly assembly { selector := mload(add(callData, 0x20)) } } /** * @dev Pad length to 32 bytes word boundary */ function padLength32(uint256 len) internal pure returns (uint256 paddedLen) { return ((len / 32) + (((len & 31) > 0) /* rounding? */ ? 1 : 0)) * 32; } /** * @dev Validate if the data is encoded correctly with abi.encode(bytesData) * * Expected ABI Encode Layout: * | word 1 | word 2 | word 3 | the rest... * | data length | bytesData offset | bytesData length | bytesData + padLength32 zeros | */ function isValidAbiEncodedBytes(bytes memory data) internal pure returns (bool) { if (data.length < 64) return false; uint256 bytesOffset; uint256 bytesLen; // bytes offset is always expected to be 32 // solhint-disable-next-line no-inline-assembly assembly { bytesOffset := mload(add(data, 32)) } if (bytesOffset != 32) return false; // solhint-disable-next-line no-inline-assembly assembly { bytesLen := mload(add(data, 64)) } // the data length should be bytesData.length + 64 + padded bytes length return data.length == 64 + padLength32(bytesLen); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.18; interface IWETH9 { function balanceOf(address) external view returns (uint256); function deposit() external payable; function withdraw(uint256 wad) external; }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s ); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "../tokens/ERC20.sol"; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. /// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller. library SafeTransferLib { /*////////////////////////////////////////////////////////////// ETH OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferETH(address to, uint256 amount) internal { bool success; /// @solidity memory-safe-assembly assembly { // Transfer the ETH and store if it succeeded or not. success := call(gas(), to, amount, 0, 0, 0, 0) } require(success, "ETH_TRANSFER_FAILED"); } /*////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument. mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 100, 0, 32) ) } require(success, "TRANSFER_FROM_FAILED"); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "TRANSFER_FAILED"); } function safeApprove( ERC20 token, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "APPROVE_FAILED"); } }
{ "metadata": { "bytecodeHash": "none" }, "optimizer": { "enabled": true, "runs": 850 }, "viaIR": false, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"components":[{"internalType":"address payable","name":"wrappedNativeAssetAddress","type":"address"}],"internalType":"struct BaseNativeWrapperConfig","name":"baseNativeWrapperConfig","type":"tuple"},{"components":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"definitiveAdmin","type":"address"},{"internalType":"address[]","name":"definitive","type":"address[]"},{"internalType":"address[]","name":"client","type":"address[]"}],"internalType":"struct CoreAccessControlConfig","name":"coreAccessControlConfig","type":"tuple"},{"components":[{"internalType":"address[]","name":"swapTokens","type":"address[]"},{"internalType":"address[]","name":"swapOutputTokens","type":"address[]"},{"internalType":"address[]","name":"swapHandlers","type":"address[]"}],"internalType":"struct CoreSwapConfig","name":"coreSwapConfig","type":"tuple"},{"components":[{"internalType":"address payable","name":"feeAccount","type":"address"}],"internalType":"struct CoreFeesConfig","name":"coreFeesConfig","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"bytes32","name":"_role","type":"bytes32"}],"name":"AccountMissingRole","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"AccountNotAdmin","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"AccountNotWhitelisted","type":"error"},{"inputs":[],"name":"ExceededMaxLTV","type":"error"},{"inputs":[],"name":"InsufficientSwapTokenBalance","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"InvalidERC20Address","type":"error"},{"inputs":[],"name":"InvalidExecutedOutputAmount","type":"error"},{"inputs":[],"name":"InvalidFeePercent","type":"error"},{"inputs":[],"name":"InvalidInputs","type":"error"},{"inputs":[],"name":"InvalidMsgValue","type":"error"},{"inputs":[],"name":"InvalidOutputToken","type":"error"},{"inputs":[],"name":"InvalidReportedOutputAmount","type":"error"},{"inputs":[],"name":"InvalidRewardsClaim","type":"error"},{"inputs":[],"name":"InvalidSwapHandler","type":"error"},{"inputs":[],"name":"InvalidSwapOutputToken","type":"error"},{"inputs":[],"name":"InvalidSwapPayload","type":"error"},{"inputs":[{"internalType":"uint256","name":"_outputAmount","type":"uint256"},{"internalType":"uint256","name":"_outputAmountMin","type":"uint256"}],"name":"SlippageExceeded","type":"error"},{"inputs":[],"name":"StopGuardianEnabled","type":"error"},{"inputs":[],"name":"SwapLimitExceeded","type":"error"},{"inputs":[],"name":"SwapTokenIsOutputToken","type":"error"},{"inputs":[],"name":"UnauthenticatedFlashloan","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"UntrustedFlashLoanSender","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"actor","type":"address"},{"indexed":false,"internalType":"address[]","name":"assetAddresses","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"collateral","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collateralDelta","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtDelta","type":"uint256"},{"indexed":false,"internalType":"address[]","name":"dryAssets","type":"address[]"},{"indexed":false,"internalType":"int256[]","name":"dryBalanceDeltas","type":"int256[]"},{"indexed":false,"internalType":"uint256","name":"ltv","type":"uint256"}],"name":"Enter","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"collateral","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collateralDelta","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtDelta","type":"uint256"},{"indexed":false,"internalType":"address[]","name":"dryAssets","type":"address[]"},{"indexed":false,"internalType":"int256[]","name":"dryBalanceDeltas","type":"int256[]"},{"indexed":false,"internalType":"uint256","name":"ltv","type":"uint256"}],"name":"Exit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"actor","type":"address"},{"indexed":false,"internalType":"address","name":"feeAccount","type":"address"}],"name":"FeeAccountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"actor","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"bool","name":"wrappingToNative","type":"bool"}],"name":"NativeAssetWrap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20[]","name":"rewardTokens","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"rewardAmounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"feeAmounts","type":"uint256[]"}],"name":"RewardsClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"actor","type":"address"},{"indexed":true,"internalType":"bool","name":"isEnabled","type":"bool"}],"name":"SafeHarborModeUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"actor","type":"address"},{"indexed":true,"internalType":"bool","name":"isEnabled","type":"bool"}],"name":"StopGuardianUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"swapTokens","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"swapAmounts","type":"uint256[]"},{"indexed":false,"internalType":"address","name":"outputToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"outputAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"SwapHandled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"actor","type":"address"},{"indexed":false,"internalType":"address","name":"swapHandler","type":"address"},{"indexed":false,"internalType":"bool","name":"isEnabled","type":"bool"}],"name":"SwapHandlerUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"actor","type":"address"},{"indexed":false,"internalType":"address","name":"swapOutputToken","type":"address"},{"indexed":false,"internalType":"bool","name":"isEnabled","type":"bool"}],"name":"SwapOutputTokenUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"actor","type":"address"},{"indexed":false,"internalType":"address","name":"swapToken","type":"address"},{"indexed":false,"internalType":"bool","name":"isEnabled","type":"bool"}],"name":"SwapTokenUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"collateral","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collateralDelta","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtDelta","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ltv","type":"uint256"}],"name":"SweepDust","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"erc20Token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"}],"name":"Withdrawal","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"COMET_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"COMPOUND_POOL","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_ACCOUNT","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SWAPS_PER_BLOCK","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROLE_CLIENT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROLE_DEFINITIVE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROLE_DEFINITIVE_ADMIN","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SAFE_HARBOR_MODE_ENABLED","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKED_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STOP_GUARDIAN_ENABLED","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WRAPPED_NATIVE_ASSET_ADDRESS","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_swapHandlers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_swapOutputTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_swapTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"feePct","type":"uint256"}],"name":"claimAllRewards","outputs":[{"internalType":"contract IERC20[]","name":"rewardTokens","type":"address[]"},{"internalType":"uint256[]","name":"earnedAmounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address[]","name":"assetAddresses","type":"address[]"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"disableSafeHarborMode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"disableStopGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"swapHandlers","type":"address[]"}],"name":"disableSwapHandlers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"swapOutputTokens","type":"address[]"}],"name":"disableSwapOutputTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"swapTokens","type":"address[]"}],"name":"disableSwapTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enableSafeHarborMode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enableStopGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"swapHandlers","type":"address[]"}],"name":"enableSwapHandlers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"swapOutputTokens","type":"address[]"}],"name":"enableSwapOutputTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"swapTokens","type":"address[]"}],"name":"enableSwapTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"flashloanAmount","type":"uint256"},{"components":[{"internalType":"address","name":"handler","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"swapToken","type":"address"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"bool","name":"isDelegate","type":"bool"},{"internalType":"bytes","name":"handlerCalldata","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct SwapPayload","name":"swapPayload","type":"tuple"},{"internalType":"uint256","name":"maxLTV","type":"uint256"}],"name":"enter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"components":[{"internalType":"address","name":"handler","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"swapToken","type":"address"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"bool","name":"isDelegate","type":"bool"},{"internalType":"bytes","name":"handlerCalldata","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct SwapPayload","name":"swapPayload","type":"tuple"},{"internalType":"uint256","name":"maxLTV","type":"uint256"}],"name":"enterMulticall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"executeOperation","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"flashloanAmount","type":"uint256"},{"internalType":"uint256","name":"repayAmount","type":"uint256"},{"internalType":"uint256","name":"decollateralizeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"handler","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"swapToken","type":"address"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"bool","name":"isDelegate","type":"bool"},{"internalType":"bytes","name":"handlerCalldata","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct SwapPayload","name":"swapPayload","type":"tuple"},{"internalType":"uint256","name":"maxLTV","type":"uint256"}],"name":"exit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"decollateralizeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"handler","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"swapToken","type":"address"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"bool","name":"isDelegate","type":"bool"},{"internalType":"bytes","name":"handlerCalldata","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct SwapPayload","name":"swapPayload","type":"tuple"},{"internalType":"bool","name":"repayDebt","type":"bool"},{"internalType":"uint256","name":"maxLTV","type":"uint256"}],"name":"exitMulticall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"assetAddress","type":"address"}],"name":"getBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCollateralAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCollateralToDebtPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDebtAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLTV","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"feeAmounts","type":"uint256[]"},{"internalType":"bytes","name":"userData","type":"bytes"}],"name":"receiveFlashLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"supportsNativeAssets","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"handler","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"swapToken","type":"address"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"bool","name":"isDelegate","type":"bool"},{"internalType":"bytes","name":"handlerCalldata","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct SwapPayload[]","name":"payloads","type":"tuple[]"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint256","name":"feePct","type":"uint256"}],"name":"swap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sweepDust","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unclaimedRewards","outputs":[{"internalType":"contract IERC20[]","name":"rewardTokens","type":"address[]"},{"internalType":"uint256[]","name":"earnedAmounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"unwrap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unwrapAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_feeAccount","type":"address"}],"name":"updateFeeAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"erc20Token","type":"address"}],"name":"withdraw","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"}],"name":"withdrawAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawAllTo","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"erc20Token","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawTo","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"wrap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60e06040523480156200001157600080fd5b506040516200674a3803806200674a833981016040819052620000349162000804565b73a17581a9e3356d9a858b789d68b4d866e593ae948480858585604051806040016040528073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03168152602001737f39c581f595b53c5cb19bd0b3f8da6c935e2ca06001600160a01b0316815250828083808780620000bc6000801b82600001516200046f60201b60201c565b620000e16000805160206200672a83398151915282602001516200046f60201b60201c565b620000fc6000805160206200672a833981519152806200047f565b60408101515160005b818110156200016957620001607fd9c9e1a27f80559d0ef9cb96900d3b37cb5d56df00dca6d004c3b26d13df7898846040015183815181106200014c576200014c6200091a565b60200260200101516200046f60201b60201c565b60010162000105565b50620001a57fd9c9e1a27f80559d0ef9cb96900d3b37cb5d56df00dca6d004c3b26d13df78986000805160206200672a8339815191526200047f565b60608201515160005b81811015620001fe57620001f57f43023f179164d629e1d761fb32e2db4dbd5ce417a23159d7da9cc7b562689285856060015183815181106200014c576200014c6200091a565b600101620001ae565b50509251600180546001600160a01b0390921661010002610100600160a81b0319909216919091179055505082515160196080529150600090505b818110156200029c57600160046000856000015184815181106200026157620002616200091a565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff191691151591909117905560010162000239565b5060208201515160005b81811015620003095760016005600086602001518481518110620002ce57620002ce6200091a565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff1916911515919091179055600101620002a6565b5060408301515160005b818110156200037657600160066000876040015184815181106200033b576200033b6200091a565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff191691151591909117905560010162000313565b5050600160075550600292506200038b915050565b604051908082528060200260200182016040528015620003b5578160200160208202803683370190505b508051620003cc916009916020909101906200056a565b5080602001516009600081548110620003e957620003e96200091a565b600091825260209091200180546001600160a01b0319166001600160a01b039290921691909117905580516009805460019081106200042c576200042c6200091a565b600091825260209091200180546001600160a01b0319166001600160a01b039283161790559451851660a052505050509190911660c05250620009309350505050565b6200047b8282620004ca565b5050565b600082815260208190526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff166200047b576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620005263390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b828054828255906000526020600020908101928215620005c2579160200282015b82811115620005c257825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906200058b565b50620005d0929150620005d4565b5090565b5b80821115620005d05760008155600101620005d5565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b0381118282101715620006265762000626620005eb565b60405290565b6001600160a01b03811681146200064257600080fd5b50565b6000602082840312156200065857600080fd5b604051602081016001600160401b03811182821017156200067d576200067d620005eb565b8060405250809150825162000692816200062c565b905292915050565b600082601f830112620006ac57600080fd5b815160206001600160401b0380831115620006cb57620006cb620005eb565b8260051b604051601f19603f83011681018181108482111715620006f357620006f3620005eb565b6040529384528581018301938381019250878511156200071257600080fd5b83870191505b848210156200073e5781516200072e816200062c565b8352918301919083019062000718565b979650505050505050565b6000606082840312156200075c57600080fd5b604051606081016001600160401b038082118383101715620007825762000782620005eb565b8160405282935084519150808211156200079b57600080fd5b620007a9868387016200069a565b83526020850151915080821115620007c057600080fd5b620007ce868387016200069a565b60208401526040850151915080821115620007e857600080fd5b50620007f7858286016200069a565b6040830152505092915050565b600080600080608085870312156200081b57600080fd5b62000827868662000645565b60208601519094506001600160401b03808211156200084557600080fd5b90860190608082890312156200085a57600080fd5b6200086462000601565b825162000871816200062c565b8152602083015162000883816200062c565b60208201526040830151828111156200089b57600080fd5b620008a98a8286016200069a565b604083015250606083015182811115620008c257600080fd5b620008d08a8286016200069a565b6060830152506040880151909550915080821115620008ee57600080fd5b50620008fd8782880162000749565b9250506200090f866060870162000645565b905092959194509250565b634e487b7160e01b600052603260045260246000fd5b60805160a05160c051615d76620009b46000396000818161048901528181612c6801528181612e79015281816133dd01528181613677015281816136f001528181613fe80152818161404c015261414e015260008181610947015281816110a901528181613a7e0152613af101526000818161066901526126450152615d766000f3fe6080604052600436106103835760003560e01c80637f3c505e116101d1578063cc0eb6c811610102578063ea598cb0116100a0578063f6a1e2bd1161006f578063f6a1e2bd14610ac2578063f85f91b414610ae2578063f8b2cb4f14610af7578063fff13ee714610b175761038a565b8063ea598cb014610a4f578063ec5486be14610a6f578063f04f270714610a8f578063f31cc89414610aaf5761038a565b8063de0e9a3e116100dc578063de0e9a3e146109da578063df1714f5146109fa578063e221633014610a0f578063e899d7b114610a2f5761038a565b8063cc0eb6c81461097e578063cdfe4fd514610998578063d547741f146109ba5761038a565b8063a53df2e21161016f578063b630252811610149578063b6302528146108f5578063c4cdee8f14610915578063c64fca1114610935578063ca6b7f19146109695761038a565b8063a53df2e214610893578063ac9650d8146108a8578063b2178c1d146108d55761038a565b80638d65a916116101ab5780638d65a916146107e05780638d6cb2091461081057806391d148541461083a578063a217fddf1461087e5761038a565b80637f3c505e146107705780638a850396146107905780638acd025e146107b05761038a565b806336568abe116102b65780635c09967a116102545780636d01875d116102235780636d01875d146106f35780637c8bcbc0146107085780637cca687b1461071d5780637ebd739f146107425761038a565b80635c09967a1461068b5780636568a2791461069e578063685dd655146106be578063686f957f146106d35761038a565b80634982e3b7116102905780634982e3b7146106195780634ed2b8ac1461062e5780635bec2a5a146106435780635befc80e146106575761038a565b806336568abe146105b757806342bd0567146105d757806343520fe1146105f75761038a565b8063194fe0ef116103235780632f2ff15d116102fd5780632f2ff15d1461054d5780632f7d6d5b1461056d578063312f6b831461058d578063315deeaa146105a25761038a565b8063194fe0ef146104ab5780631ace952b146104ed578063248a9ca31461051d5761038a565b80630479d6441161035f5780630479d64414610400578063054d026e1461042d57806307dceec71461044f578063081bd298146104775761038a565b80621eab8314610391578062f714ce146103c057806301ffc9a7146103e05761038a565b3661038a57005b6060516080f35b34801561039d57600080fd5b506008546103ab9060ff1681565b60405190151581526020015b60405180910390f35b3480156103cc57600080fd5b506103ab6103db3660046149f0565b610b37565b3480156103ec57600080fd5b506103ab6103fb366004614a20565b610b98565b34801561040c57600080fd5b50610415610bff565b6040516001600160a01b0390911681526020016103b7565b34801561043957600080fd5b5061044d610448366004614a75565b610c2f565b005b34801561045b57600080fd5b5061041573a17581a9e3356d9a858b789d68b4d866e593ae9481565b34801561048357600080fd5b506104157f000000000000000000000000000000000000000000000000000000000000000081565b3480156104b757600080fd5b506104df7f71b4013af46185a424aaa4fe1eb172247581306dd750cb51be59e3864d3dc98681565b6040519081526020016103b7565b3480156104f957600080fd5b506103ab610508366004614ad6565b60066020526000908152604090205460ff1681565b34801561052957600080fd5b506104df610538366004614af3565b60009081526020819052604090206001015490565b34801561055957600080fd5b5061044d6105683660046149f0565b610ea5565b34801561057957600080fd5b5061044d610588366004614bc3565b610ecf565b34801561059957600080fd5b50610415610f0b565b3480156105ae57600080fd5b506104df610f21565b3480156105c357600080fd5b5061044d6105d23660046149f0565b610f38565b3480156105e357600080fd5b506103ab6105f2366004614c9c565b610fc4565b34801561060357600080fd5b506104df600080516020615d0383398151915281565b34801561062557600080fd5b5061044d61105c565b34801561063a57600080fd5b506104df6110cd565b34801561064f57600080fd5b5060016103ab565b34801561066357600080fd5b506104df7f000000000000000000000000000000000000000000000000000000000000000081565b61044d610699366004614cf3565b6110df565b3480156106aa57600080fd5b506103ab6106b9366004614d5f565b611185565b3480156106ca57600080fd5b5061044d6111d4565b3480156106df57600080fd5b5061044d6106ee366004614da1565b61125f565b3480156106ff57600080fd5b506104df6113fa565b34801561071457600080fd5b5061044d611404565b34801561072957600080fd5b506001546104159061010090046001600160a01b031681565b34801561074e57600080fd5b5061076261075d366004614af3565b611418565b6040516103b7929190614e77565b34801561077c57600080fd5b5061044d61078b366004614bc3565b6115ec565b34801561079c57600080fd5b5061044d6107ab366004614e9c565b611640565b3480156107bc57600080fd5b506103ab6107cb366004614ad6565b60056020526000908152604090205460ff1681565b3480156107ec57600080fd5b506103ab6107fb366004614ad6565b60046020526000908152604090205460ff1681565b34801561081c57600080fd5b50610825611794565b604080519283526020830191909152016103b7565b34801561084657600080fd5b506103ab6108553660046149f0565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561088a57600080fd5b506104df600081565b34801561089f57600080fd5b5061044d6117dd565b3480156108b457600080fd5b506108c86108c3366004614d5f565b611935565b6040516103b79190614f3c565b3480156108e157600080fd5b506103ab6108f0366004614f9e565b611a21565b34801561090157600080fd5b5061044d610910366004614bc3565b611ac2565b34801561092157600080fd5b5061044d610930366004614bc3565b611afb565b34801561094157600080fd5b506104157f000000000000000000000000000000000000000000000000000000000000000081565b34801561097557600080fd5b5061044d611b34565b34801561098a57600080fd5b506001546103ab9060ff1681565b3480156109a457600080fd5b506104df600080516020615d2383398151915281565b3480156109c657600080fd5b5061044d6109d53660046149f0565b611b83565b3480156109e657600080fd5b5061044d6109f5366004614af3565b611ba8565b348015610a0657600080fd5b5061044d611c4e565b348015610a1b57600080fd5b506104df610a2a366004615104565b611ca1565b348015610a3b57600080fd5b5061044d610a4a366004614e9c565b611ecc565b348015610a5b57600080fd5b5061044d610a6a366004614af3565b612050565b348015610a7b57600080fd5b5061044d610a8a366004614bc3565b6120cf565b348015610a9b57600080fd5b5061044d610aaa36600461523d565b612123565b61044d610abd366004615348565b61229e565b348015610ace57600080fd5b5061044d610add366004614bc3565b61231b565b348015610aee57600080fd5b50606080610762565b348015610b0357600080fd5b506104df610b12366004614ad6565b61236f565b348015610b2357600080fd5b5061044d610b32366004614ad6565b61237a565b6000610b50600080516020615d038339815191526123ac565b610b586123b6565b60015460ff1615610b7c576040516363238ca360e01b815260040160405180910390fd5b610b86838361240f565b9050610b926001600755565b92915050565b60006001600160e01b031982167f7965db0b000000000000000000000000000000000000000000000000000000001480610b9257507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b0319831614610b92565b60006009600181548110610c1557610c156153cd565b6000918252602090912001546001600160a01b0316919050565b6000610c49600080516020615d0383398151915233610855565b80610c675750610c67600080516020615d2383398151915233610855565b905080610cb357335b6040517fd52b8d2e0000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024015b60405180910390fd5b60015460ff1615610cd7576040516363238ca360e01b815260040160405180910390fd5b610cdf6123b6565b8160016000806000610cef610f21565b610cf76113fa565b610d2c60025b604051908082528060200260200182016040528015610d26578160200160208202803683370190505b50612423565b925092509250610d3b8a61254b565b6000610d45610bff565b90506000610d528261255c565b905060208b013515610e2957604080516001808252818301909252600091816020015b610dc96040518060e0016040528060006001600160a01b031681526020016000815260200160006001600160a01b031681526020016000815260200160001515815260200160608152602001606081525090565b815260200190600190039081610d75579050509050610de78c6153e3565b81600081518110610dfa57610dfa6153cd565b6020026020010181905250610e0f8184612610565b505081610e1b8461255c565b610e259190615405565b9150505b8915610e5a576000610e396113fa565b90506000818310610e4a5781610e4c565b825b9050610e5781612988565b50505b5050610e68838383876129b2565b5050505080610e756110cd565b1115610e9357604051624d3d2d60e01b815260040160405180910390fd5b50610e9e6001600755565b5050505050565b600082815260208190526040902060010154610ec0816123ac565b610eca8383612ad1565b505050565b610ed960006123ac565b60015460ff1615610efd576040516363238ca360e01b815260040160405180910390fd5b610f08816001612b6f565b50565b60006009600081548110610c1557610c156153cd565b6000610f33610f2e610f0b565b612c40565b905090565b6001600160a01b0381163314610fb65760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610caa565b610fc08282612ced565b5050565b600080610fdf600080516020615d0383398151915233610855565b80610ffd5750610ffd600080516020615d2383398151915233610855565b90508061100a5733610c70565b60015460ff161561102e576040516363238ca360e01b815260040160405180910390fd5b611046600080516020615d0383398151915284612d6c565b611051858585612dd8565b91505b509392505050565b6000611076600080516020615d0383398151915233610855565b806110945750611094600080516020615d2383398151915233610855565b9050806110a15733610c70565b610f086109f57f000000000000000000000000000000000000000000000000000000000000000061255c565b6000610f336110da610f0b565b612e61565b6110f6600080516020615d038339815191526123ac565b6110fe6123b6565b60015460ff1615611122576040516363238ca360e01b815260040160405180910390fd5b61112e84848484612fd6565b336001600160a01b03167f83c419f8f26f4f5e29c5cde4c8ad1698228be27d717a8954b2465009955428ae8383878760405161116d9493929190615418565b60405180910390a261117f6001600755565b50505050565b600061119e600080516020615d038339815191526123ac565b6111a66123b6565b60015460ff16156111ca576040516363238ca360e01b815260040160405180910390fd5b610b86838361314c565b60006111e08133610855565b8061121057506112107f71b4013af46185a424aaa4fe1eb172247581306dd750cb51be59e3864d3dc98633610855565b90508061125757335b6040517f3ba76d110000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610caa565b610f08613159565b6000611279600080516020615d0383398151915233610855565b806112975750611297600080516020615d2383398151915233610855565b9050806112a45733610c70565b60015460ff16156112c8576040516363238ca360e01b815260040160405180910390fd5b6112d06123b6565b81600160008060006112e0610f21565b6112e86113fa565b6112f26002610cfd565b92509250925060006040518060a001604052808d81526020018c81526020018b81526020018a611321906153e3565b815260200189905290508b156113875761138261133c610bff565b8d6001846040516020016113509190615527565b60408051601f198184030181529082905261136e929160200161558d565b60405160208183030381529060405261319e565b6113af565b6113af8160405160200161139b9190615527565b6040516020818303038152906040526132d1565b506113bc838383876129b2565b50505050806113c96110cd565b11156113e757604051624d3d2d60e01b815260040160405180910390fd5b506113f26001600755565b505050505050565b6000610f336133c5565b61140e60006123ac565b611416613450565b565b6060806000611435600080516020615d0383398151915233610855565b806114535750611453600080516020615d2383398151915233610855565b9050806114605733610c70565b6114686123b6565b60015460ff161561148c576040516363238ca360e01b815260040160405180910390fd5b611494613462565b8151919450925060008167ffffffffffffffff8111156114b6576114b6614b0c565b6040519080825280602002602001820160405280156114df578160200160208202803683370190505b5060015490915061010090046001600160a01b0316158015906115025750600086115b1561159f5760005b8281101561159d57848181518110611524576115246153cd565b602002602001015160000361153b5760010161150a565b611578868281518110611550576115506153cd565b602002602001015186838151811061156a5761156a6153cd565b602002602001015189613497565b82828151811061158a5761158a6153cd565b602090810291909101015260010161150a565b505b7fc7eae855adfe2fa05433c7329cfb31d150a38d037e9e7dabc4c2a6ea05b05dbb8585836040516115d2939291906155c4565b60405180910390a150506115e66001600755565b50915091565b60006115f88133610855565b8061162857506116287f71b4013af46185a424aaa4fe1eb172247581306dd750cb51be59e3864d3dc98633610855565b9050806116355733611219565b610fc0826000612b6f565b600061165a600080516020615d0383398151915233610855565b806116785750611678600080516020615d2383398151915233610855565b9050806116855733610c70565b60015460ff16156116a9576040516363238ca360e01b815260040160405180910390fd5b6116b16123b6565b816000806000806116c0610f21565b6116c86113fa565b6116d26002610cfd565b925092509250600060405180606001604052808b81526020018a6116f5906153e3565b81526020018990529050891561172957611724611710610bff565b8b60008460405160200161135091906155fd565b611751565b6117518160405160200161173d91906155fd565b60405160208183030381529060405261353e565b5061175e838383876129b2565b505050508061176b6110cd565b111561178957604051624d3d2d60e01b815260040160405180910390fd5b5061117f6001600755565b6000806000806117aa6117a5610f0b565b613638565b90925090506117c182670de0b6b3a7640000615639565b6117d382670de0b6b3a7640000615639565b9350935050509091565b60006117f7600080516020615d0383398151915233610855565b806118155750611815600080516020615d2383398151915233610855565b9050806118225733610c70565b60015460ff1615611846576040516363238ca360e01b815260040160405180910390fd5b61184e6123b6565b600080611859610f21565b6118616113fa565b915091506000821180156118755750600081115b156118925761189261188d611888610bff565b61255c565b612988565b6118a56118a0611888610f0b565b613798565b6000806118b0610f21565b6118b86113fa565b90925090507fe8c4a4d11814d75355591f17d35b50f2c5b749ca6cfa2d07d0ab6b8abc67988e826118e98682615405565b836118f48188615405565b6118fc6110cd565b604080519586526020860194909452928401919091526060830152608082015260a00160405180910390a150505050610f086001600755565b6060818067ffffffffffffffff81111561195157611951614b0c565b60405190808252806020026020018201604052801561198457816020015b606081526020019060019003908161196f5790505b50915060005b81811015611a19576119f4308686848181106119a8576119a86153cd565b90506020028101906119ba919061565b565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506137a992505050565b838281518110611a0657611a066153cd565b602090810291909101015260010161198a565b505092915050565b600080611a3c600080516020615d0383398151915233610855565b80611a5a5750611a5a600080516020615d2383398151915233610855565b905080611a675733610c70565b611a6f6123b6565b60015460ff1615611a93576040516363238ca360e01b815260040160405180910390fd5b611aab600080516020615d0383398151915284612d6c565b611ab68585856137ce565b91506110546001600755565b611acc60006123ac565b60015460ff1615611af0576040516363238ca360e01b815260040160405180910390fd5b610f0881600161386e565b611b0560006123ac565b60015460ff1615611b29576040516363238ca360e01b815260040160405180910390fd5b610f0881600161393f565b6000611b4e600080516020615d0383398151915233610855565b80611b6c5750611b6c600080516020615d2383398151915233610855565b905080611b795733610c70565b610f086001613a10565b600082815260208190526040902060010154611b9e816123ac565b610eca8383612ced565b6000611bc2600080516020615d0383398151915233610855565b80611be05750611be0600080516020615d2383398151915233610855565b905080611bed5733610c70565b611bf56123b6565b611bfe82613a4f565b60007fdef0dc72021788040d6ab985a42aa3d5efe5a52d77485682afa2fc1525df6b7f335b604080516001600160a01b039092168252602082018690520160405180910390a2610fc06001600755565b6000611c5a8133610855565b80611c8a5750611c8a7f71b4013af46185a424aaa4fe1eb172247581306dd750cb51be59e3864d3dc98633610855565b905080611c975733611219565b610f086000613a10565b600080611cbc600080516020615d0383398151915233610855565b80611cda5750611cda600080516020615d2383398151915233610855565b905080611ce75733610c70565b611cef6123b6565b60015460ff1615611d13576040516363238ca360e01b815260040160405180910390fd5b612710831115611d3657604051638a81d3b360e01b815260040160405180910390fd5b600080611d438888612610565b9150915085811015611d8b576040517f71c4efed0000000000000000000000000000000000000000000000000000000081526004810182905260248101879052604401610caa565b6000885167ffffffffffffffff811115611da757611da7614b0c565b604051908082528060200260200182016040528015611dd0578160200160208202803683370190505b50805190915060005b81811015611e31578a8181518110611df357611df36153cd565b602002602001015160400151838281518110611e1157611e116153cd565b6001600160a01b0390921660209283029190910190910152600101611dd9565b5060015460009061010090046001600160a01b031615801590611e545750600084115b8015611e605750600088115b15611e7357611e708a858a613497565b90505b7ffbc1db932504c9fa40e26af5592335c371e6e180dd0c10c75d7ce23bb8a1ccde83868c8785604051611eaa9594939291906156a2565b60405180910390a150919450505050611ec36001600755565b50949350505050565b6000611ee6600080516020615d0383398151915233610855565b80611f045750611f04600080516020615d2383398151915233610855565b905080611f115733610c70565b60015460ff1615611f35576040516363238ca360e01b815260040160405180910390fd5b611f3d6123b6565b81600080600080611f4c610f21565b611f546113fa565b611f5e6002610cfd565b9250925092506000611f6e610f0b565b9050611f7c6118a08261255c565b611f858a613ade565b60208901351561175157604080516001808252818301909252600091816020015b611ffa6040518060e0016040528060006001600160a01b031681526020016000815260200160006001600160a01b031681526020016000815260200160001515815260200160608152602001606081525090565b815260200190600190039081611fa65790505090506120188a6153e3565b8160008151811061202b5761202b6153cd565b60200260200101819052506120408183612610565b5050505061175e838383876129b2565b600061206a600080516020615d0383398151915233610855565b806120885750612088600080516020615d2383398151915233610855565b9050806120955733610c70565b61209d6123b6565b6120a682613aef565b60017fdef0dc72021788040d6ab985a42aa3d5efe5a52d77485682afa2fc1525df6b7f33611c23565b60006120db8133610855565b8061210b575061210b7f71b4013af46185a424aaa4fe1eb172247581306dd750cb51be59e3864d3dc98633610855565b9050806121185733611219565b610fc082600061393f565b3373ba12222222228d8ba445958a75a0704d566bf2c814612172576040517f662602e5000000000000000000000000000000000000000000000000000000008152336004820152602401610caa565b600a5460ff166121ae576040517f78a2bd6a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a805460ff1916905583516122139085906000906121cf576121cf6153cd565b6020026020010151846000815181106121ea576121ea6153cd565b602002602001015184600081518110612205576122056153cd565b602002602001015184613b5e565b61117f73ba12222222228d8ba445958a75a0704d566bf2c88360008151811061223e5761223e6153cd565b602002602001015185600081518110612259576122596153cd565b602002602001015161226b9190615720565b8660008151811061227e5761227e6153cd565b60200260200101516001600160a01b0316613bc59092919063ffffffff16565b6122a860006123ac565b600080846001600160a01b03163485856040516122c6929190615733565b60006040518083038185875af1925050503d8060008114612303576040519150601f19603f3d011682016040523d82523d6000602084013e612308565b606091505b509150915081610e9e57610e9e81613c15565b60006123278133610855565b8061235757506123577f71b4013af46185a424aaa4fe1eb172247581306dd750cb51be59e3864d3dc98633610855565b9050806123645733611219565b610fc082600061386e565b6000610b928261255c565b6123a37f71b4013af46185a424aaa4fe1eb172247581306dd750cb51be59e3864d3dc9866123ac565b610f0881613d39565b610f088133612d6c565b6002600754036124085760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610caa565b6002600755565b600061241c8383336137ce565b9392505050565b60606000600980548060200260200160405190810160405280929190818152602001828054801561247d57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161245f575b50505050509050805167ffffffffffffffff81111561249e5761249e614b0c565b6040519080825280602002602001820160405280156124c7578160200160208202803683370190505b50815190925060005b81811015612543578481815181106124ea576124ea6153cd565b6020026020010151612514848381518110612507576125076153cd565b602002602001015161255c565b61251e9190615743565b848281518110612530576125306153cd565b60209081029190910101526001016124d0565b505050919050565b610f08612556610f0b565b82613db7565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0383160161258a575047919050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa1580156125e7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b92919061576a565b919050565b60606000836003544314612628574360035560006002555b80516002600082825461263b9190615720565b90915550506002547f0000000000000000000000000000000000000000000000000000000000000000101561269c576040517f7468c7a800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03841660009081526005602052604090205460ff166126ee576040517fd49aa89300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84518067ffffffffffffffff81111561270957612709614b0c565b604051908082528060200260200182016040528015612732578160200160208202803683370190505b50935060006127408661255c565b905060005b82811015612967576000888281518110612761576127616153cd565b60209081029190910181015180516001600160a01b03166000908152600690925260409091205490915060ff166127c4576040517f2de948b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80604001516001600160a01b0316886001600160a01b031603612813576040517ff7d6ef2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061281e8961255c565b905061282d826040015161255c565b88848151811061283f5761283f6153cd565b602002602001018181525050600080612858848c613de0565b915091508a6001600160a01b0316816001600160a01b03161461288d576040516231010160e51b815260040160405180910390fd5b83606001518210156128cb576040517fa9fe672d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006128d68c61255c565b60608601519091506128e88583615405565b1015612920576040517fc73b8cbc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61292d856040015161255c565b8b878151811061293f5761293f6153cd565b602002602001018181516129539190615405565b905250506001909401935061274592505050565b50806129728761255c565b61297c9190615405565b93505050509250929050565b60006129926113fa565b9050610fc061299f610bff565b8284116129ac5783613f49565b82613f49565b6000806000806129c0610f21565b6129c86113fa565b6129d188612423565b6129d96110cd565b9296509094509250905060008560018111156129f7576129f7615577565b03612a57577f645277b71c30a3f0974624ea80277595c99572708dc58898cc2472a82a4aecf184612a288a82615405565b85612a338b82615405565b60098787604051612a4a9796959493929190615783565b60405180910390a1612ac7565b6001856001811115612a6b57612a6b615577565b03612ac7577fdf72eaee67e40d79e8acfd072850a63186970e7894c5f48cbbf98597c888364a84612a9c818b615405565b85612aa7818c615405565b60098787604051612abe9796959493929190615783565b60405180910390a15b5050505050505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610fc0576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055612b2b3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b815160005b8181101561117f578260046000868481518110612b9357612b936153cd565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff19169115159190911790557fb7fb7a204fdbb641615538cf2a147d3682ea2307c8f45a172d8fed1addb1bcc133858381518110612bf957612bf96153cd565b602002602001015185604051612c30939291906001600160a01b039384168152919092166020820152901515604082015260600190565b60405180910390a1600101612b74565b604051632e12a4f760e11b81523060048201526001600160a01b0382811660248301526000917f000000000000000000000000000000000000000000000000000000000000000090911690635c2549ee90604401602060405180830381865afa158015612cb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cd59190615830565b6fffffffffffffffffffffffffffffffff1692915050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1615610fc0576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610fc0576040517f106571f00000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401610caa565b600082815b81811015612e55576000612e11878784818110612dfc57612dfc6153cd565b90506020020160208101906118889190614ad6565b90508015612e4c57612e4a81888885818110612e2f57612e2f6153cd565b9050602002016020810190612e449190614ad6565b876137ce565b505b50600101612ddd565b50600195945050505050565b604051630dd3126d60e21b81523060048201526000907f000000000000000000000000000000000000000000000000000000000000000090829081906001600160a01b0384169063374c49b490602401602060405180830381865afa158015612ece573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ef2919061576a565b604051632e12a4f760e11b81523060048201526001600160a01b038781166024830152851690635c2549ee90604401602060405180830381865afa158015612f3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f629190615830565b6fffffffffffffffffffffffffffffffff1691509150600080612f8487613638565b9092509050612f93828461584b565b15612fc857612fa2828461584b565b81612faf8661271061584b565b612fb9919061584b565b612fc39190615639565b612fcb565b60005b979650505050505050565b80838114613010576040517ff34cfab600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060005b838110156130d45773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee868683818110613045576130456153cd565b905060200201602081019061305a9190614ad6565b6001600160a01b03160361307657600192509050818101613016565b6130cc33308a8a8581811061308d5761308d6153cd565b905060200201358989868181106130a6576130a66153cd565b90506020020160208101906130bb9190614ad6565b6001600160a01b0316929190613f71565b600101613016565b50811580156130e257503415155b1561310057604051631841b4e160e01b815260040160405180910390fd5b818015613125575086868281811061311a5761311a6153cd565b905060200201353414155b1561314357604051631841b4e160e01b815260040160405180910390fd5b50505050505050565b600061241c838333612dd8565b6001805460ff191681178155335b6001600160a01b03167fddde86bf56483edaa0fa1fc39207f2c0b047851d6969f86042875f26c432580e60405160405180910390a3565b604080516001808252818301909252600091829190602080830190803683375050604080516001808252818301909252915060208083019080368337019050509150915084826000815181106131f6576131f66153cd565b60200260200101906001600160a01b031690816001600160a01b031681525050838160008151811061322a5761322a6153cd565b6020908102919091010152600a805460ff191660011790556040517f5c38449e00000000000000000000000000000000000000000000000000000000815273ba12222222228d8ba445958a75a0704d566bf2c890635c38449e90613298903090869086908990600401615862565b600060405180830381600087803b1580156132b257600080fd5b505af11580156132c6573d6000803e3d6000fd5b505050505050505050565b6000818060200190518101906132e791906159df565b90506132f68160200151612988565b613303816040015161254b565b60608101516020015115610fc057604080516001808252818301909252600091816020015b61337c6040518060e0016040528060006001600160a01b031681526020016000815260200160006001600160a01b031681526020016000815260200160001515815260200160608152602001606081525090565b8152602001906001900390816133285790505090508160600151816000815181106133a9576133a96153cd565b6020026020010181905250610e9e816133c0610bff565b612610565b604051630dd3126d60e21b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063374c49b490602401602060405180830381865afa15801561342c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f33919061576a565b6001805460ff19169055600033613167565b6060806040517faf73709900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612710808311156134bd57604051638a81d3b360e01b815260040160405180910390fd5b806134c8848661584b565b6134d29190615639565b915081156110545773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0386160161351f5760015461351a9061010090046001600160a01b031683613fc2565b611054565b600154611054906001600160a01b038781169161010090041684613bc5565b6000818060200190518101906135549190615a77565b90506000613560610f0b565b60208084015101519091501561362157604080516001808252818301909252600091816020015b6135db6040518060e0016040528060006001600160a01b031681526020016000815260200160006001600160a01b031681526020016000815260200160001515815260200160608152602001606081525090565b815260200190600190039081613587579050509050826020015181600081518110613608576136086153cd565b602002602001018190525061361d8183612610565b5050505b61362d6118a08261255c565b8151610eca90613ade565b6040517f3b3bec2e0000000000000000000000000000000000000000000000000000000081526001600160a01b038281166004830152600091829182917f000000000000000000000000000000000000000000000000000000000000000090911690633b3bec2e9060240161010060405180830381865afa1580156136c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136e59190615b29565b5050505050925050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166341976e09826040518263ffffffff1660e01b815260040161374991906001600160a01b0391909116815260200190565b602060405180830381865afa158015613766573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061378a919061576a565b946305f5e100945092505050565b610f086137a3610f0b565b82613fd2565b606061241c8383604051806060016040528060278152602001615d4360279139614091565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601613804576137ff8285613fc2565b613818565b6138186001600160a01b0384168386613bc5565b816001600160a01b0316836001600160a01b03167e1a143d5b175701cb3246058ffac3d63945192075a926ff73a19930f09d587a8660405161385c91815260200190565b60405180910390a35060019392505050565b815160005b8181101561117f578260066000868481518110613892576138926153cd565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff19169115159190911790557f5733671486228f19db2618b94a60764871edfd11635129ec2f88a9e76163784a338583815181106138f8576138f86153cd565b60200260200101518560405161392f939291906001600160a01b039384168152919092166020820152901515604082015260600190565b60405180910390a1600101613873565b815160005b8181101561117f578260056000868481518110613963576139636153cd565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff19169115159190911790557f022b5880fc0cf768365ffc145d8cf634cd8d1de03ea1f32b925ac5ddfe7a690e338583815181106139c9576139c96153cd565b602002602001015185604051613a00939291906001600160a01b039384168152919092166020820152901515604082015260600190565b60405180910390a1600101613944565b6008805460ff191682151590811790915560405133907f1d77290adeca4b6b665ebfa3cc7baa148cb14968d7c4b3fdfef9527a29d91d6590600090a350565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015613aca57600080fd5b505af1158015610e9e573d6000803e3d6000fd5b610f08613ae9610bff565b82614109565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015613b4a57600080fd5b505af11580156113f2573d6000803e3d6000fd5b60008082806020019051810190613b759190615bce565b90925090506000826001811115613b8e57613b8e615577565b03613ba357613b9c8161353e565b505061117f565b6001826001811115613bb757613bb7615577565b036113f257613b9c816132d1565b8273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601613c04576040516376fe282b60e11b815260040160405180910390fd5b811561117f5761117f84848461417d565b600481511015613c675760405162461bcd60e51b815260206004820152601a60248201527f43616c6c5574696c733a207461726765742072657665727428290000000000006044820152606401610caa565b60208101517fb1b7848f000000000000000000000000000000000000000000000000000000006001600160e01b0319821601613d305760408051808201825260208082527f43616c6c5574696c733a207461726765742070616e69636b65643a2030785f5f90820190815260248501517f43616c6c5574696c733a207461726765742070616e69636b65643a2030780000600482811c600f908116603090810160081b918516011791909117909252925162461bcd60e51b8152919291610caa91849101615c23565b81518060208401fd5b600180547fffffffffffffffffffffff0000000000000000000000000000000000000000ff166101006001600160a01b038416021790557f63f8f609737c2dc01ff1d619040ccd6cb6d0e1e7b04f5271d959deefa09ef54b33604080516001600160a01b03928316815291841660208301520160405180910390a150565b6000613dc283612c40565b905080821115613dd657610eca8382614109565b610eca8383614109565b600080613dec8461420e565b6020808601919091526040808601516001600160a01b031660009081526004909252812054608086015160ff909116159190613e2d90879087908590614289565b905060006060876080015115613ea45787600001516001600160a01b031683604051613e599190615c36565b600060405180830381855af49150503d8060008114613e94576040519150601f19603f3d011682016040523d82523d6000602084013e613e99565b606091505b509092509050613f17565b613eb28889602001516143ee565b87600001516001600160a01b031683604051613ece9190615c36565b6000604051808303816000865af19150503d8060008114613f0b576040519150601f19603f3d011682016040523d82523d6000602084013e613f10565b606091505b5090925090505b81613f2557613f2581613c15565b80806020019051810190613f399190615c52565b95509550505050505b9250929050565b6000613f536133c5565b905080821115613f6757610eca8382613fd2565b610eca8383613fd2565b8373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601613fb0576040516376fe282b60e11b815260040160405180910390fd5b8115610e9e57610e9e8585858561444a565b8015610fc057610fc0828261449b565b8015610fc05761400d6001600160a01b038316307f0000000000000000000000000000000000000000000000000000000000000000846144f6565b6040517ff2b9fdb80000000000000000000000000000000000000000000000000000000081526001600160a01b038381166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063f2b9fdb8906044015b600060405180830381600087803b158015613b4a57600080fd5b6060600080856001600160a01b0316856040516140ae9190615c36565b600060405180830381855af49150503d80600081146140e9576040519150601f19603f3d011682016040523d82523d6000602084013e6140ee565b606091505b50915091506140ff868383876145c8565b9695505050505050565b8015610fc0576040517ff3fef3a30000000000000000000000000000000000000000000000000000000081526001600160a01b038381166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063f3fef3a390604401614077565b6040516001600160a01b038316602482015260448101829052610eca9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152614641565b60008061421e836040015161255c565b905061422981614729565b60208301519150811580159061423e57508181105b15614275576040517fd852310600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816000036142835792915050565b50919050565b60608280156142955750815b156142cc576040517fad54954000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083156142fb57507f40eb440900000000000000000000000000000000000000000000000000000000614331565b8261430c5762edfd6d60e81b61432e565b7f6a89cd49000000000000000000000000000000000000000000000000000000005b90505b60006040518060c0016040528088604001516001600160a01b0316815260200188602001518152602001876001600160a01b03168152602001886060015181526020018860a0015181526020018860c001518152509050818160405160240161439a9190615c77565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152925050505b949350505050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b031682604001516001600160a01b03160361442b578151610fc09082613fc2565b81516040830151610fc0916001600160a01b03909116903090846144f6565b6040516001600160a01b038085166024830152831660448201526064810182905261117f9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016141c2565b600080600080600085875af1905080610eca5760405162461bcd60e51b815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152606401610caa565b8373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601614535576040516376fe282b60e11b815260040160405180910390fd5b604051636eb1769f60e11b81526001600160a01b03858116600483015284811660248301526000919087169063dd62ed3e90604401602060405180830381865afa158015614587573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145ab919061576a565b11156145bd576145bd85846000614763565b610e9e85848461487f565b60608315614637578251600003614630576001600160a01b0385163b6146305760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610caa565b50816143e6565b6143e6838361492c565b6000614696826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166149569092919063ffffffff16565b90508051600014806146b75750808060200190518101906146b79190615ce5565b610eca5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610caa565b80600003610f08576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8015806147dd5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa1580156147b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147db919061576a565b155b61484f5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152608401610caa565b6040516001600160a01b038316602482015260448101829052610eca90849063095ea7b360e01b906064016141c2565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa1580156148cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148f3919061576a565b905061117f8463095ea7b360e01b8561490c8686615720565b6040516001600160a01b03909216602483015260448201526064016141c2565b81511561493c5781518083602001fd5b8060405162461bcd60e51b8152600401610caa9190615c23565b60606143e6848460008585600080866001600160a01b0316858760405161497d9190615c36565b60006040518083038185875af1925050503d80600081146149ba576040519150601f19603f3d011682016040523d82523d6000602084013e6149bf565b606091505b5091509150612fcb878383876145c8565b6001600160a01b0381168114610f0857600080fd5b803561260b816149d0565b60008060408385031215614a0357600080fd5b823591506020830135614a15816149d0565b809150509250929050565b600060208284031215614a3257600080fd5b81356001600160e01b03198116811461241c57600080fd5b600060e0828403121561428357600080fd5b8015158114610f0857600080fd5b803561260b81614a5c565b60008060008060808587031215614a8b57600080fd5b84359350602085013567ffffffffffffffff811115614aa957600080fd5b614ab587828801614a4a565b9350506040850135614ac681614a5c565b9396929550929360600135925050565b600060208284031215614ae857600080fd5b813561241c816149d0565b600060208284031215614b0557600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60405160e0810167ffffffffffffffff81118282101715614b4557614b45614b0c565b60405290565b60405160a0810167ffffffffffffffff81118282101715614b4557614b45614b0c565b604051601f8201601f1916810167ffffffffffffffff81118282101715614b9757614b97614b0c565b604052919050565b600067ffffffffffffffff821115614bb957614bb9614b0c565b5060051b60200190565b60006020808385031215614bd657600080fd5b823567ffffffffffffffff811115614bed57600080fd5b8301601f81018513614bfe57600080fd5b8035614c11614c0c82614b9f565b614b6e565b81815260059190911b82018301908381019087831115614c3057600080fd5b928401925b82841015612fcb578335614c48816149d0565b82529284019290840190614c35565b60008083601f840112614c6957600080fd5b50813567ffffffffffffffff811115614c8157600080fd5b6020830191508360208260051b8501011115613f4257600080fd5b600080600060408486031215614cb157600080fd5b833567ffffffffffffffff811115614cc857600080fd5b614cd486828701614c57565b9094509250506020840135614ce8816149d0565b809150509250925092565b60008060008060408587031215614d0957600080fd5b843567ffffffffffffffff80821115614d2157600080fd5b614d2d88838901614c57565b90965094506020870135915080821115614d4657600080fd5b50614d5387828801614c57565b95989497509550505050565b60008060208385031215614d7257600080fd5b823567ffffffffffffffff811115614d8957600080fd5b614d9585828601614c57565b90969095509350505050565b600080600080600060a08688031215614db957600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff811115614de557600080fd5b614df188828901614a4a565b95989497509295608001359392505050565b600081518084526020808501945080840160005b83811015614e3c5781516001600160a01b031687529582019590820190600101614e17565b509495945050505050565b600081518084526020808501945080840160005b83811015614e3c57815187529582019590820190600101614e5b565b604081526000614e8a6040830185614e03565b82810360208401526110518185614e47565b600080600060608486031215614eb157600080fd5b83359250602084013567ffffffffffffffff811115614ecf57600080fd5b614edb86828701614a4a565b925050604084013590509250925092565b60005b83811015614f07578181015183820152602001614eef565b50506000910152565b60008151808452614f28816020860160208601614eec565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015614f9157603f19888603018452614f7f858351614f10565b94509285019290850190600101614f63565b5092979650505050505050565b600080600060608486031215614fb357600080fd5b833592506020840135614fc5816149d0565b91506040840135614ce8816149d0565b600067ffffffffffffffff821115614fef57614fef614b0c565b50601f01601f191660200190565b600082601f83011261500e57600080fd5b813561501c614c0c82614fd5565b81815284602083860101111561503157600080fd5b816020850160208301376000918101602001919091529392505050565b600060e0828403121561506057600080fd5b615068614b22565b9050615073826149e5565b81526020820135602082015261508b604083016149e5565b6040820152606082013560608201526150a660808301614a6a565b608082015260a082013567ffffffffffffffff808211156150c657600080fd5b6150d285838601614ffd565b60a084015260c08401359150808211156150eb57600080fd5b506150f884828501614ffd565b60c08301525092915050565b6000806000806080858703121561511a57600080fd5b843567ffffffffffffffff8082111561513257600080fd5b818701915087601f83011261514657600080fd5b81356020615156614c0c83614b9f565b82815260059290921b8401810191818101908b84111561517557600080fd5b8286015b848110156151ad578035868111156151915760008081fd5b61519f8e86838b010161504e565b845250918301918301615179565b5098506151bd90508982016149e5565b979a97995050505060408601359560600135949350505050565b600082601f8301126151e857600080fd5b813560206151f8614c0c83614b9f565b82815260059290921b8401810191818101908684111561521757600080fd5b8286015b84811015615232578035835291830191830161521b565b509695505050505050565b6000806000806080858703121561525357600080fd5b843567ffffffffffffffff8082111561526b57600080fd5b818701915087601f83011261527f57600080fd5b8135602061528f614c0c83614b9f565b82815260059290921b8401810191818101908b8411156152ae57600080fd5b948201945b838610156152d55785356152c6816149d0565b825294820194908201906152b3565b985050880135925050808211156152eb57600080fd5b6152f7888389016151d7565b9450604087013591508082111561530d57600080fd5b615319888389016151d7565b9350606087013591508082111561532f57600080fd5b5061533c87828801614ffd565b91505092959194509250565b60008060006040848603121561535d57600080fd5b8335615368816149d0565b9250602084013567ffffffffffffffff8082111561538557600080fd5b818601915086601f83011261539957600080fd5b8135818111156153a857600080fd5b8760208285010111156153ba57600080fd5b6020830194508093505050509250925092565b634e487b7160e01b600052603260045260246000fd5b6000610b92368361504e565b634e487b7160e01b600052601160045260246000fd5b81810381811115610b9257610b926153ef565b6040808252810184905260008560608301825b8781101561545b57823561543e816149d0565b6001600160a01b031682526020928301929091019060010161542b565b5083810360208501528481527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85111561549457600080fd5b8460051b915081866020830137016020019695505050505050565b60006001600160a01b0380835116845260208301516020850152806040840151166040850152506060820151606084015260808201511515608084015260a082015160e060a085015261550560e0850182614f10565b905060c083015184820360c086015261551e8282614f10565b95945050505050565b602081528151602082015260208201516040820152604082015160608201526000606083015160a0608084015261556160c08401826154af565b9050608084015160a08401528091505092915050565b634e487b7160e01b600052602160045260246000fd5b6000600284106155ad57634e487b7160e01b600052602160045260246000fd5b838252604060208301526143e66040830184614f10565b6060815260006155d76060830186614e03565b82810360208401526155e98186614e47565b905082810360408401526140ff8185614e47565b6020815281516020820152600060208301516060604084015261562360808401826154af565b9050604084015160608401528091505092915050565b60008261565657634e487b7160e01b600052601260045260246000fd5b500490565b6000808335601e1984360301811261567257600080fd5b83018035915067ffffffffffffffff82111561568d57600080fd5b602001915036819003821315613f4257600080fd5b60a0808252865190820181905260009060209060c0840190828a01845b828110156156e45781516001600160a01b0316845292840192908401906001016156bf565b505050838103828501526156f88189614e47565b6001600160a01b03979097166040850152505050606081019290925260809091015292915050565b80820180821115610b9257610b926153ef565b8183823760009101908152919050565b8181036000831280158383131683831282161715615763576157636153ef565b5092915050565b60006020828403121561577c57600080fd5b5051919050565b600060e082018983526020898185015288604085015287606085015260e06080850152818754808452610100860191508860005282600020935060005b818110156157e55784546001600160a01b0316835260019485019492840192016157c0565b505084810360a08601526157f98188614e47565b93505050508260c083015298975050505050505050565b80516fffffffffffffffffffffffffffffffff8116811461260b57600080fd5b60006020828403121561584257600080fd5b61241c82615810565b8082028115828204841417610b9257610b926153ef565b6000608082016001600160a01b038088168452602060808186015282885180855260a087019150828a01945060005b818110156158af578551851683529483019491830191600101615891565b505085810360408701526158c38189614e47565b93505050508281036060840152612fcb8185614f10565b805161260b816149d0565b805161260b81614a5c565b600082601f83011261590157600080fd5b815161590f614c0c82614fd5565b81815284602083860101111561592457600080fd5b6143e6826020830160208701614eec565b600060e0828403121561594757600080fd5b61594f614b22565b905061595a826158da565b815260208201516020820152615972604083016158da565b60408201526060820151606082015261598d608083016158e5565b608082015260a082015167ffffffffffffffff808211156159ad57600080fd5b6159b9858386016158f0565b60a084015260c08401519150808211156159d257600080fd5b506150f8848285016158f0565b6000602082840312156159f157600080fd5b815167ffffffffffffffff80821115615a0957600080fd5b9083019060a08286031215615a1d57600080fd5b615a25614b4b565b825181526020830151602082015260408301516040820152606083015182811115615a4f57600080fd5b615a5b87828601615935565b6060830152506080830151608082015280935050505092915050565b600060208284031215615a8957600080fd5b815167ffffffffffffffff80821115615aa157600080fd5b9083019060608286031215615ab557600080fd5b604051606081018181108382111715615ad057615ad0614b0c565b60405282518152602083015182811115615ae957600080fd5b615af587828601615935565b6020830152506040830151604082015280935050505092915050565b805167ffffffffffffffff8116811461260b57600080fd5b600080600080600080600080610100898b031215615b4657600080fd5b885160ff81168114615b5757600080fd5b60208a0151909850615b68816149d0565b60408a0151909750615b79816149d0565b9550615b8760608a01615b11565b9450615b9560808a01615b11565b9350615ba360a08a01615b11565b9250615bb160c08a01615b11565b9150615bbf60e08a01615810565b90509295985092959890939650565b60008060408385031215615be157600080fd5b825160028110615bf057600080fd5b602084015190925067ffffffffffffffff811115615c0d57600080fd5b615c19858286016158f0565b9150509250929050565b60208152600061241c6020830184614f10565b60008251615c48818460208701614eec565b9190910192915050565b60008060408385031215615c6557600080fd5b825191506020830151614a15816149d0565b6020815260006001600160a01b03808451166020840152602084015160408401528060408501511660608401525060608301516080830152608083015160c060a0840152615cc860e0840182614f10565b905060a0840151601f198483030160c085015261551e8282614f10565b600060208284031215615cf757600080fd5b815161241c81614a5c56fe43023f179164d629e1d761fb32e2db4dbd5ce417a23159d7da9cc7b562689285d9c9e1a27f80559d0ef9cb96900d3b37cb5d56df00dca6d004c3b26d13df7898416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a164736f6c6343000812000a71b4013af46185a424aaa4fe1eb172247581306dd750cb51be59e3864d3dc986000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001600000000000000000000000003b016025cd3d213c5779e10fe94a35ba440bd1c9000000000000000000000000a59c5bc33c9d705b738aa553b724d8c39324fd200000000000000000000000003b016025cd3d213c5779e10fe94a35ba440bd1c9000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000d056c0eee354b24fe7c5d4ee762c4d7574badac10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000003000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca00000000000000000000000000000000000000000000000000000000000000006000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000f155735395a323b2a12051b5bc076c2c49eebeb300000000000000000000000081261c3ae484d2c0873bbea019eaecebc0056f95
Deployed Bytecode
0x6080604052600436106103835760003560e01c80637f3c505e116101d1578063cc0eb6c811610102578063ea598cb0116100a0578063f6a1e2bd1161006f578063f6a1e2bd14610ac2578063f85f91b414610ae2578063f8b2cb4f14610af7578063fff13ee714610b175761038a565b8063ea598cb014610a4f578063ec5486be14610a6f578063f04f270714610a8f578063f31cc89414610aaf5761038a565b8063de0e9a3e116100dc578063de0e9a3e146109da578063df1714f5146109fa578063e221633014610a0f578063e899d7b114610a2f5761038a565b8063cc0eb6c81461097e578063cdfe4fd514610998578063d547741f146109ba5761038a565b8063a53df2e21161016f578063b630252811610149578063b6302528146108f5578063c4cdee8f14610915578063c64fca1114610935578063ca6b7f19146109695761038a565b8063a53df2e214610893578063ac9650d8146108a8578063b2178c1d146108d55761038a565b80638d65a916116101ab5780638d65a916146107e05780638d6cb2091461081057806391d148541461083a578063a217fddf1461087e5761038a565b80637f3c505e146107705780638a850396146107905780638acd025e146107b05761038a565b806336568abe116102b65780635c09967a116102545780636d01875d116102235780636d01875d146106f35780637c8bcbc0146107085780637cca687b1461071d5780637ebd739f146107425761038a565b80635c09967a1461068b5780636568a2791461069e578063685dd655146106be578063686f957f146106d35761038a565b80634982e3b7116102905780634982e3b7146106195780634ed2b8ac1461062e5780635bec2a5a146106435780635befc80e146106575761038a565b806336568abe146105b757806342bd0567146105d757806343520fe1146105f75761038a565b8063194fe0ef116103235780632f2ff15d116102fd5780632f2ff15d1461054d5780632f7d6d5b1461056d578063312f6b831461058d578063315deeaa146105a25761038a565b8063194fe0ef146104ab5780631ace952b146104ed578063248a9ca31461051d5761038a565b80630479d6441161035f5780630479d64414610400578063054d026e1461042d57806307dceec71461044f578063081bd298146104775761038a565b80621eab8314610391578062f714ce146103c057806301ffc9a7146103e05761038a565b3661038a57005b6060516080f35b34801561039d57600080fd5b506008546103ab9060ff1681565b60405190151581526020015b60405180910390f35b3480156103cc57600080fd5b506103ab6103db3660046149f0565b610b37565b3480156103ec57600080fd5b506103ab6103fb366004614a20565b610b98565b34801561040c57600080fd5b50610415610bff565b6040516001600160a01b0390911681526020016103b7565b34801561043957600080fd5b5061044d610448366004614a75565b610c2f565b005b34801561045b57600080fd5b5061041573a17581a9e3356d9a858b789d68b4d866e593ae9481565b34801561048357600080fd5b506104157f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae9481565b3480156104b757600080fd5b506104df7f71b4013af46185a424aaa4fe1eb172247581306dd750cb51be59e3864d3dc98681565b6040519081526020016103b7565b3480156104f957600080fd5b506103ab610508366004614ad6565b60066020526000908152604090205460ff1681565b34801561052957600080fd5b506104df610538366004614af3565b60009081526020819052604090206001015490565b34801561055957600080fd5b5061044d6105683660046149f0565b610ea5565b34801561057957600080fd5b5061044d610588366004614bc3565b610ecf565b34801561059957600080fd5b50610415610f0b565b3480156105ae57600080fd5b506104df610f21565b3480156105c357600080fd5b5061044d6105d23660046149f0565b610f38565b3480156105e357600080fd5b506103ab6105f2366004614c9c565b610fc4565b34801561060357600080fd5b506104df600080516020615d0383398151915281565b34801561062557600080fd5b5061044d61105c565b34801561063a57600080fd5b506104df6110cd565b34801561064f57600080fd5b5060016103ab565b34801561066357600080fd5b506104df7f000000000000000000000000000000000000000000000000000000000000001981565b61044d610699366004614cf3565b6110df565b3480156106aa57600080fd5b506103ab6106b9366004614d5f565b611185565b3480156106ca57600080fd5b5061044d6111d4565b3480156106df57600080fd5b5061044d6106ee366004614da1565b61125f565b3480156106ff57600080fd5b506104df6113fa565b34801561071457600080fd5b5061044d611404565b34801561072957600080fd5b506001546104159061010090046001600160a01b031681565b34801561074e57600080fd5b5061076261075d366004614af3565b611418565b6040516103b7929190614e77565b34801561077c57600080fd5b5061044d61078b366004614bc3565b6115ec565b34801561079c57600080fd5b5061044d6107ab366004614e9c565b611640565b3480156107bc57600080fd5b506103ab6107cb366004614ad6565b60056020526000908152604090205460ff1681565b3480156107ec57600080fd5b506103ab6107fb366004614ad6565b60046020526000908152604090205460ff1681565b34801561081c57600080fd5b50610825611794565b604080519283526020830191909152016103b7565b34801561084657600080fd5b506103ab6108553660046149f0565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561088a57600080fd5b506104df600081565b34801561089f57600080fd5b5061044d6117dd565b3480156108b457600080fd5b506108c86108c3366004614d5f565b611935565b6040516103b79190614f3c565b3480156108e157600080fd5b506103ab6108f0366004614f9e565b611a21565b34801561090157600080fd5b5061044d610910366004614bc3565b611ac2565b34801561092157600080fd5b5061044d610930366004614bc3565b611afb565b34801561094157600080fd5b506104157f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b34801561097557600080fd5b5061044d611b34565b34801561098a57600080fd5b506001546103ab9060ff1681565b3480156109a457600080fd5b506104df600080516020615d2383398151915281565b3480156109c657600080fd5b5061044d6109d53660046149f0565b611b83565b3480156109e657600080fd5b5061044d6109f5366004614af3565b611ba8565b348015610a0657600080fd5b5061044d611c4e565b348015610a1b57600080fd5b506104df610a2a366004615104565b611ca1565b348015610a3b57600080fd5b5061044d610a4a366004614e9c565b611ecc565b348015610a5b57600080fd5b5061044d610a6a366004614af3565b612050565b348015610a7b57600080fd5b5061044d610a8a366004614bc3565b6120cf565b348015610a9b57600080fd5b5061044d610aaa36600461523d565b612123565b61044d610abd366004615348565b61229e565b348015610ace57600080fd5b5061044d610add366004614bc3565b61231b565b348015610aee57600080fd5b50606080610762565b348015610b0357600080fd5b506104df610b12366004614ad6565b61236f565b348015610b2357600080fd5b5061044d610b32366004614ad6565b61237a565b6000610b50600080516020615d038339815191526123ac565b610b586123b6565b60015460ff1615610b7c576040516363238ca360e01b815260040160405180910390fd5b610b86838361240f565b9050610b926001600755565b92915050565b60006001600160e01b031982167f7965db0b000000000000000000000000000000000000000000000000000000001480610b9257507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b0319831614610b92565b60006009600181548110610c1557610c156153cd565b6000918252602090912001546001600160a01b0316919050565b6000610c49600080516020615d0383398151915233610855565b80610c675750610c67600080516020615d2383398151915233610855565b905080610cb357335b6040517fd52b8d2e0000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024015b60405180910390fd5b60015460ff1615610cd7576040516363238ca360e01b815260040160405180910390fd5b610cdf6123b6565b8160016000806000610cef610f21565b610cf76113fa565b610d2c60025b604051908082528060200260200182016040528015610d26578160200160208202803683370190505b50612423565b925092509250610d3b8a61254b565b6000610d45610bff565b90506000610d528261255c565b905060208b013515610e2957604080516001808252818301909252600091816020015b610dc96040518060e0016040528060006001600160a01b031681526020016000815260200160006001600160a01b031681526020016000815260200160001515815260200160608152602001606081525090565b815260200190600190039081610d75579050509050610de78c6153e3565b81600081518110610dfa57610dfa6153cd565b6020026020010181905250610e0f8184612610565b505081610e1b8461255c565b610e259190615405565b9150505b8915610e5a576000610e396113fa565b90506000818310610e4a5781610e4c565b825b9050610e5781612988565b50505b5050610e68838383876129b2565b5050505080610e756110cd565b1115610e9357604051624d3d2d60e01b815260040160405180910390fd5b50610e9e6001600755565b5050505050565b600082815260208190526040902060010154610ec0816123ac565b610eca8383612ad1565b505050565b610ed960006123ac565b60015460ff1615610efd576040516363238ca360e01b815260040160405180910390fd5b610f08816001612b6f565b50565b60006009600081548110610c1557610c156153cd565b6000610f33610f2e610f0b565b612c40565b905090565b6001600160a01b0381163314610fb65760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610caa565b610fc08282612ced565b5050565b600080610fdf600080516020615d0383398151915233610855565b80610ffd5750610ffd600080516020615d2383398151915233610855565b90508061100a5733610c70565b60015460ff161561102e576040516363238ca360e01b815260040160405180910390fd5b611046600080516020615d0383398151915284612d6c565b611051858585612dd8565b91505b509392505050565b6000611076600080516020615d0383398151915233610855565b806110945750611094600080516020615d2383398151915233610855565b9050806110a15733610c70565b610f086109f57f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc261255c565b6000610f336110da610f0b565b612e61565b6110f6600080516020615d038339815191526123ac565b6110fe6123b6565b60015460ff1615611122576040516363238ca360e01b815260040160405180910390fd5b61112e84848484612fd6565b336001600160a01b03167f83c419f8f26f4f5e29c5cde4c8ad1698228be27d717a8954b2465009955428ae8383878760405161116d9493929190615418565b60405180910390a261117f6001600755565b50505050565b600061119e600080516020615d038339815191526123ac565b6111a66123b6565b60015460ff16156111ca576040516363238ca360e01b815260040160405180910390fd5b610b86838361314c565b60006111e08133610855565b8061121057506112107f71b4013af46185a424aaa4fe1eb172247581306dd750cb51be59e3864d3dc98633610855565b90508061125757335b6040517f3ba76d110000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610caa565b610f08613159565b6000611279600080516020615d0383398151915233610855565b806112975750611297600080516020615d2383398151915233610855565b9050806112a45733610c70565b60015460ff16156112c8576040516363238ca360e01b815260040160405180910390fd5b6112d06123b6565b81600160008060006112e0610f21565b6112e86113fa565b6112f26002610cfd565b92509250925060006040518060a001604052808d81526020018c81526020018b81526020018a611321906153e3565b815260200189905290508b156113875761138261133c610bff565b8d6001846040516020016113509190615527565b60408051601f198184030181529082905261136e929160200161558d565b60405160208183030381529060405261319e565b6113af565b6113af8160405160200161139b9190615527565b6040516020818303038152906040526132d1565b506113bc838383876129b2565b50505050806113c96110cd565b11156113e757604051624d3d2d60e01b815260040160405180910390fd5b506113f26001600755565b505050505050565b6000610f336133c5565b61140e60006123ac565b611416613450565b565b6060806000611435600080516020615d0383398151915233610855565b806114535750611453600080516020615d2383398151915233610855565b9050806114605733610c70565b6114686123b6565b60015460ff161561148c576040516363238ca360e01b815260040160405180910390fd5b611494613462565b8151919450925060008167ffffffffffffffff8111156114b6576114b6614b0c565b6040519080825280602002602001820160405280156114df578160200160208202803683370190505b5060015490915061010090046001600160a01b0316158015906115025750600086115b1561159f5760005b8281101561159d57848181518110611524576115246153cd565b602002602001015160000361153b5760010161150a565b611578868281518110611550576115506153cd565b602002602001015186838151811061156a5761156a6153cd565b602002602001015189613497565b82828151811061158a5761158a6153cd565b602090810291909101015260010161150a565b505b7fc7eae855adfe2fa05433c7329cfb31d150a38d037e9e7dabc4c2a6ea05b05dbb8585836040516115d2939291906155c4565b60405180910390a150506115e66001600755565b50915091565b60006115f88133610855565b8061162857506116287f71b4013af46185a424aaa4fe1eb172247581306dd750cb51be59e3864d3dc98633610855565b9050806116355733611219565b610fc0826000612b6f565b600061165a600080516020615d0383398151915233610855565b806116785750611678600080516020615d2383398151915233610855565b9050806116855733610c70565b60015460ff16156116a9576040516363238ca360e01b815260040160405180910390fd5b6116b16123b6565b816000806000806116c0610f21565b6116c86113fa565b6116d26002610cfd565b925092509250600060405180606001604052808b81526020018a6116f5906153e3565b81526020018990529050891561172957611724611710610bff565b8b60008460405160200161135091906155fd565b611751565b6117518160405160200161173d91906155fd565b60405160208183030381529060405261353e565b5061175e838383876129b2565b505050508061176b6110cd565b111561178957604051624d3d2d60e01b815260040160405180910390fd5b5061117f6001600755565b6000806000806117aa6117a5610f0b565b613638565b90925090506117c182670de0b6b3a7640000615639565b6117d382670de0b6b3a7640000615639565b9350935050509091565b60006117f7600080516020615d0383398151915233610855565b806118155750611815600080516020615d2383398151915233610855565b9050806118225733610c70565b60015460ff1615611846576040516363238ca360e01b815260040160405180910390fd5b61184e6123b6565b600080611859610f21565b6118616113fa565b915091506000821180156118755750600081115b156118925761189261188d611888610bff565b61255c565b612988565b6118a56118a0611888610f0b565b613798565b6000806118b0610f21565b6118b86113fa565b90925090507fe8c4a4d11814d75355591f17d35b50f2c5b749ca6cfa2d07d0ab6b8abc67988e826118e98682615405565b836118f48188615405565b6118fc6110cd565b604080519586526020860194909452928401919091526060830152608082015260a00160405180910390a150505050610f086001600755565b6060818067ffffffffffffffff81111561195157611951614b0c565b60405190808252806020026020018201604052801561198457816020015b606081526020019060019003908161196f5790505b50915060005b81811015611a19576119f4308686848181106119a8576119a86153cd565b90506020028101906119ba919061565b565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506137a992505050565b838281518110611a0657611a066153cd565b602090810291909101015260010161198a565b505092915050565b600080611a3c600080516020615d0383398151915233610855565b80611a5a5750611a5a600080516020615d2383398151915233610855565b905080611a675733610c70565b611a6f6123b6565b60015460ff1615611a93576040516363238ca360e01b815260040160405180910390fd5b611aab600080516020615d0383398151915284612d6c565b611ab68585856137ce565b91506110546001600755565b611acc60006123ac565b60015460ff1615611af0576040516363238ca360e01b815260040160405180910390fd5b610f0881600161386e565b611b0560006123ac565b60015460ff1615611b29576040516363238ca360e01b815260040160405180910390fd5b610f0881600161393f565b6000611b4e600080516020615d0383398151915233610855565b80611b6c5750611b6c600080516020615d2383398151915233610855565b905080611b795733610c70565b610f086001613a10565b600082815260208190526040902060010154611b9e816123ac565b610eca8383612ced565b6000611bc2600080516020615d0383398151915233610855565b80611be05750611be0600080516020615d2383398151915233610855565b905080611bed5733610c70565b611bf56123b6565b611bfe82613a4f565b60007fdef0dc72021788040d6ab985a42aa3d5efe5a52d77485682afa2fc1525df6b7f335b604080516001600160a01b039092168252602082018690520160405180910390a2610fc06001600755565b6000611c5a8133610855565b80611c8a5750611c8a7f71b4013af46185a424aaa4fe1eb172247581306dd750cb51be59e3864d3dc98633610855565b905080611c975733611219565b610f086000613a10565b600080611cbc600080516020615d0383398151915233610855565b80611cda5750611cda600080516020615d2383398151915233610855565b905080611ce75733610c70565b611cef6123b6565b60015460ff1615611d13576040516363238ca360e01b815260040160405180910390fd5b612710831115611d3657604051638a81d3b360e01b815260040160405180910390fd5b600080611d438888612610565b9150915085811015611d8b576040517f71c4efed0000000000000000000000000000000000000000000000000000000081526004810182905260248101879052604401610caa565b6000885167ffffffffffffffff811115611da757611da7614b0c565b604051908082528060200260200182016040528015611dd0578160200160208202803683370190505b50805190915060005b81811015611e31578a8181518110611df357611df36153cd565b602002602001015160400151838281518110611e1157611e116153cd565b6001600160a01b0390921660209283029190910190910152600101611dd9565b5060015460009061010090046001600160a01b031615801590611e545750600084115b8015611e605750600088115b15611e7357611e708a858a613497565b90505b7ffbc1db932504c9fa40e26af5592335c371e6e180dd0c10c75d7ce23bb8a1ccde83868c8785604051611eaa9594939291906156a2565b60405180910390a150919450505050611ec36001600755565b50949350505050565b6000611ee6600080516020615d0383398151915233610855565b80611f045750611f04600080516020615d2383398151915233610855565b905080611f115733610c70565b60015460ff1615611f35576040516363238ca360e01b815260040160405180910390fd5b611f3d6123b6565b81600080600080611f4c610f21565b611f546113fa565b611f5e6002610cfd565b9250925092506000611f6e610f0b565b9050611f7c6118a08261255c565b611f858a613ade565b60208901351561175157604080516001808252818301909252600091816020015b611ffa6040518060e0016040528060006001600160a01b031681526020016000815260200160006001600160a01b031681526020016000815260200160001515815260200160608152602001606081525090565b815260200190600190039081611fa65790505090506120188a6153e3565b8160008151811061202b5761202b6153cd565b60200260200101819052506120408183612610565b5050505061175e838383876129b2565b600061206a600080516020615d0383398151915233610855565b806120885750612088600080516020615d2383398151915233610855565b9050806120955733610c70565b61209d6123b6565b6120a682613aef565b60017fdef0dc72021788040d6ab985a42aa3d5efe5a52d77485682afa2fc1525df6b7f33611c23565b60006120db8133610855565b8061210b575061210b7f71b4013af46185a424aaa4fe1eb172247581306dd750cb51be59e3864d3dc98633610855565b9050806121185733611219565b610fc082600061393f565b3373ba12222222228d8ba445958a75a0704d566bf2c814612172576040517f662602e5000000000000000000000000000000000000000000000000000000008152336004820152602401610caa565b600a5460ff166121ae576040517f78a2bd6a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a805460ff1916905583516122139085906000906121cf576121cf6153cd565b6020026020010151846000815181106121ea576121ea6153cd565b602002602001015184600081518110612205576122056153cd565b602002602001015184613b5e565b61117f73ba12222222228d8ba445958a75a0704d566bf2c88360008151811061223e5761223e6153cd565b602002602001015185600081518110612259576122596153cd565b602002602001015161226b9190615720565b8660008151811061227e5761227e6153cd565b60200260200101516001600160a01b0316613bc59092919063ffffffff16565b6122a860006123ac565b600080846001600160a01b03163485856040516122c6929190615733565b60006040518083038185875af1925050503d8060008114612303576040519150601f19603f3d011682016040523d82523d6000602084013e612308565b606091505b509150915081610e9e57610e9e81613c15565b60006123278133610855565b8061235757506123577f71b4013af46185a424aaa4fe1eb172247581306dd750cb51be59e3864d3dc98633610855565b9050806123645733611219565b610fc082600061386e565b6000610b928261255c565b6123a37f71b4013af46185a424aaa4fe1eb172247581306dd750cb51be59e3864d3dc9866123ac565b610f0881613d39565b610f088133612d6c565b6002600754036124085760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610caa565b6002600755565b600061241c8383336137ce565b9392505050565b60606000600980548060200260200160405190810160405280929190818152602001828054801561247d57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161245f575b50505050509050805167ffffffffffffffff81111561249e5761249e614b0c565b6040519080825280602002602001820160405280156124c7578160200160208202803683370190505b50815190925060005b81811015612543578481815181106124ea576124ea6153cd565b6020026020010151612514848381518110612507576125076153cd565b602002602001015161255c565b61251e9190615743565b848281518110612530576125306153cd565b60209081029190910101526001016124d0565b505050919050565b610f08612556610f0b565b82613db7565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0383160161258a575047919050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa1580156125e7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b92919061576a565b919050565b60606000836003544314612628574360035560006002555b80516002600082825461263b9190615720565b90915550506002547f0000000000000000000000000000000000000000000000000000000000000019101561269c576040517f7468c7a800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03841660009081526005602052604090205460ff166126ee576040517fd49aa89300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84518067ffffffffffffffff81111561270957612709614b0c565b604051908082528060200260200182016040528015612732578160200160208202803683370190505b50935060006127408661255c565b905060005b82811015612967576000888281518110612761576127616153cd565b60209081029190910181015180516001600160a01b03166000908152600690925260409091205490915060ff166127c4576040517f2de948b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80604001516001600160a01b0316886001600160a01b031603612813576040517ff7d6ef2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061281e8961255c565b905061282d826040015161255c565b88848151811061283f5761283f6153cd565b602002602001018181525050600080612858848c613de0565b915091508a6001600160a01b0316816001600160a01b03161461288d576040516231010160e51b815260040160405180910390fd5b83606001518210156128cb576040517fa9fe672d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006128d68c61255c565b60608601519091506128e88583615405565b1015612920576040517fc73b8cbc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61292d856040015161255c565b8b878151811061293f5761293f6153cd565b602002602001018181516129539190615405565b905250506001909401935061274592505050565b50806129728761255c565b61297c9190615405565b93505050509250929050565b60006129926113fa565b9050610fc061299f610bff565b8284116129ac5783613f49565b82613f49565b6000806000806129c0610f21565b6129c86113fa565b6129d188612423565b6129d96110cd565b9296509094509250905060008560018111156129f7576129f7615577565b03612a57577f645277b71c30a3f0974624ea80277595c99572708dc58898cc2472a82a4aecf184612a288a82615405565b85612a338b82615405565b60098787604051612a4a9796959493929190615783565b60405180910390a1612ac7565b6001856001811115612a6b57612a6b615577565b03612ac7577fdf72eaee67e40d79e8acfd072850a63186970e7894c5f48cbbf98597c888364a84612a9c818b615405565b85612aa7818c615405565b60098787604051612abe9796959493929190615783565b60405180910390a15b5050505050505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610fc0576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055612b2b3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b815160005b8181101561117f578260046000868481518110612b9357612b936153cd565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff19169115159190911790557fb7fb7a204fdbb641615538cf2a147d3682ea2307c8f45a172d8fed1addb1bcc133858381518110612bf957612bf96153cd565b602002602001015185604051612c30939291906001600160a01b039384168152919092166020820152901515604082015260600190565b60405180910390a1600101612b74565b604051632e12a4f760e11b81523060048201526001600160a01b0382811660248301526000917f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae9490911690635c2549ee90604401602060405180830381865afa158015612cb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cd59190615830565b6fffffffffffffffffffffffffffffffff1692915050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1615610fc0576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610fc0576040517f106571f00000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401610caa565b600082815b81811015612e55576000612e11878784818110612dfc57612dfc6153cd565b90506020020160208101906118889190614ad6565b90508015612e4c57612e4a81888885818110612e2f57612e2f6153cd565b9050602002016020810190612e449190614ad6565b876137ce565b505b50600101612ddd565b50600195945050505050565b604051630dd3126d60e21b81523060048201526000907f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae9490829081906001600160a01b0384169063374c49b490602401602060405180830381865afa158015612ece573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ef2919061576a565b604051632e12a4f760e11b81523060048201526001600160a01b038781166024830152851690635c2549ee90604401602060405180830381865afa158015612f3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f629190615830565b6fffffffffffffffffffffffffffffffff1691509150600080612f8487613638565b9092509050612f93828461584b565b15612fc857612fa2828461584b565b81612faf8661271061584b565b612fb9919061584b565b612fc39190615639565b612fcb565b60005b979650505050505050565b80838114613010576040517ff34cfab600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060005b838110156130d45773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee868683818110613045576130456153cd565b905060200201602081019061305a9190614ad6565b6001600160a01b03160361307657600192509050818101613016565b6130cc33308a8a8581811061308d5761308d6153cd565b905060200201358989868181106130a6576130a66153cd565b90506020020160208101906130bb9190614ad6565b6001600160a01b0316929190613f71565b600101613016565b50811580156130e257503415155b1561310057604051631841b4e160e01b815260040160405180910390fd5b818015613125575086868281811061311a5761311a6153cd565b905060200201353414155b1561314357604051631841b4e160e01b815260040160405180910390fd5b50505050505050565b600061241c838333612dd8565b6001805460ff191681178155335b6001600160a01b03167fddde86bf56483edaa0fa1fc39207f2c0b047851d6969f86042875f26c432580e60405160405180910390a3565b604080516001808252818301909252600091829190602080830190803683375050604080516001808252818301909252915060208083019080368337019050509150915084826000815181106131f6576131f66153cd565b60200260200101906001600160a01b031690816001600160a01b031681525050838160008151811061322a5761322a6153cd565b6020908102919091010152600a805460ff191660011790556040517f5c38449e00000000000000000000000000000000000000000000000000000000815273ba12222222228d8ba445958a75a0704d566bf2c890635c38449e90613298903090869086908990600401615862565b600060405180830381600087803b1580156132b257600080fd5b505af11580156132c6573d6000803e3d6000fd5b505050505050505050565b6000818060200190518101906132e791906159df565b90506132f68160200151612988565b613303816040015161254b565b60608101516020015115610fc057604080516001808252818301909252600091816020015b61337c6040518060e0016040528060006001600160a01b031681526020016000815260200160006001600160a01b031681526020016000815260200160001515815260200160608152602001606081525090565b8152602001906001900390816133285790505090508160600151816000815181106133a9576133a96153cd565b6020026020010181905250610e9e816133c0610bff565b612610565b604051630dd3126d60e21b81523060048201526000907f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae946001600160a01b03169063374c49b490602401602060405180830381865afa15801561342c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f33919061576a565b6001805460ff19169055600033613167565b6060806040517faf73709900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612710808311156134bd57604051638a81d3b360e01b815260040160405180910390fd5b806134c8848661584b565b6134d29190615639565b915081156110545773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0386160161351f5760015461351a9061010090046001600160a01b031683613fc2565b611054565b600154611054906001600160a01b038781169161010090041684613bc5565b6000818060200190518101906135549190615a77565b90506000613560610f0b565b60208084015101519091501561362157604080516001808252818301909252600091816020015b6135db6040518060e0016040528060006001600160a01b031681526020016000815260200160006001600160a01b031681526020016000815260200160001515815260200160608152602001606081525090565b815260200190600190039081613587579050509050826020015181600081518110613608576136086153cd565b602002602001018190525061361d8183612610565b5050505b61362d6118a08261255c565b8151610eca90613ade565b6040517f3b3bec2e0000000000000000000000000000000000000000000000000000000081526001600160a01b038281166004830152600091829182917f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae9490911690633b3bec2e9060240161010060405180830381865afa1580156136c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136e59190615b29565b5050505050925050507f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae946001600160a01b03166341976e09826040518263ffffffff1660e01b815260040161374991906001600160a01b0391909116815260200190565b602060405180830381865afa158015613766573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061378a919061576a565b946305f5e100945092505050565b610f086137a3610f0b565b82613fd2565b606061241c8383604051806060016040528060278152602001615d4360279139614091565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601613804576137ff8285613fc2565b613818565b6138186001600160a01b0384168386613bc5565b816001600160a01b0316836001600160a01b03167e1a143d5b175701cb3246058ffac3d63945192075a926ff73a19930f09d587a8660405161385c91815260200190565b60405180910390a35060019392505050565b815160005b8181101561117f578260066000868481518110613892576138926153cd565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff19169115159190911790557f5733671486228f19db2618b94a60764871edfd11635129ec2f88a9e76163784a338583815181106138f8576138f86153cd565b60200260200101518560405161392f939291906001600160a01b039384168152919092166020820152901515604082015260600190565b60405180910390a1600101613873565b815160005b8181101561117f578260056000868481518110613963576139636153cd565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff19169115159190911790557f022b5880fc0cf768365ffc145d8cf634cd8d1de03ea1f32b925ac5ddfe7a690e338583815181106139c9576139c96153cd565b602002602001015185604051613a00939291906001600160a01b039384168152919092166020820152901515604082015260600190565b60405180910390a1600101613944565b6008805460ff191682151590811790915560405133907f1d77290adeca4b6b665ebfa3cc7baa148cb14968d7c4b3fdfef9527a29d91d6590600090a350565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015613aca57600080fd5b505af1158015610e9e573d6000803e3d6000fd5b610f08613ae9610bff565b82614109565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015613b4a57600080fd5b505af11580156113f2573d6000803e3d6000fd5b60008082806020019051810190613b759190615bce565b90925090506000826001811115613b8e57613b8e615577565b03613ba357613b9c8161353e565b505061117f565b6001826001811115613bb757613bb7615577565b036113f257613b9c816132d1565b8273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601613c04576040516376fe282b60e11b815260040160405180910390fd5b811561117f5761117f84848461417d565b600481511015613c675760405162461bcd60e51b815260206004820152601a60248201527f43616c6c5574696c733a207461726765742072657665727428290000000000006044820152606401610caa565b60208101517fb1b7848f000000000000000000000000000000000000000000000000000000006001600160e01b0319821601613d305760408051808201825260208082527f43616c6c5574696c733a207461726765742070616e69636b65643a2030785f5f90820190815260248501517f43616c6c5574696c733a207461726765742070616e69636b65643a2030780000600482811c600f908116603090810160081b918516011791909117909252925162461bcd60e51b8152919291610caa91849101615c23565b81518060208401fd5b600180547fffffffffffffffffffffff0000000000000000000000000000000000000000ff166101006001600160a01b038416021790557f63f8f609737c2dc01ff1d619040ccd6cb6d0e1e7b04f5271d959deefa09ef54b33604080516001600160a01b03928316815291841660208301520160405180910390a150565b6000613dc283612c40565b905080821115613dd657610eca8382614109565b610eca8383614109565b600080613dec8461420e565b6020808601919091526040808601516001600160a01b031660009081526004909252812054608086015160ff909116159190613e2d90879087908590614289565b905060006060876080015115613ea45787600001516001600160a01b031683604051613e599190615c36565b600060405180830381855af49150503d8060008114613e94576040519150601f19603f3d011682016040523d82523d6000602084013e613e99565b606091505b509092509050613f17565b613eb28889602001516143ee565b87600001516001600160a01b031683604051613ece9190615c36565b6000604051808303816000865af19150503d8060008114613f0b576040519150601f19603f3d011682016040523d82523d6000602084013e613f10565b606091505b5090925090505b81613f2557613f2581613c15565b80806020019051810190613f399190615c52565b95509550505050505b9250929050565b6000613f536133c5565b905080821115613f6757610eca8382613fd2565b610eca8383613fd2565b8373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601613fb0576040516376fe282b60e11b815260040160405180910390fd5b8115610e9e57610e9e8585858561444a565b8015610fc057610fc0828261449b565b8015610fc05761400d6001600160a01b038316307f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae94846144f6565b6040517ff2b9fdb80000000000000000000000000000000000000000000000000000000081526001600160a01b038381166004830152602482018390527f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae94169063f2b9fdb8906044015b600060405180830381600087803b158015613b4a57600080fd5b6060600080856001600160a01b0316856040516140ae9190615c36565b600060405180830381855af49150503d80600081146140e9576040519150601f19603f3d011682016040523d82523d6000602084013e6140ee565b606091505b50915091506140ff868383876145c8565b9695505050505050565b8015610fc0576040517ff3fef3a30000000000000000000000000000000000000000000000000000000081526001600160a01b038381166004830152602482018390527f000000000000000000000000a17581a9e3356d9a858b789d68b4d866e593ae94169063f3fef3a390604401614077565b6040516001600160a01b038316602482015260448101829052610eca9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152614641565b60008061421e836040015161255c565b905061422981614729565b60208301519150811580159061423e57508181105b15614275576040517fd852310600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816000036142835792915050565b50919050565b60608280156142955750815b156142cc576040517fad54954000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083156142fb57507f40eb440900000000000000000000000000000000000000000000000000000000614331565b8261430c5762edfd6d60e81b61432e565b7f6a89cd49000000000000000000000000000000000000000000000000000000005b90505b60006040518060c0016040528088604001516001600160a01b0316815260200188602001518152602001876001600160a01b03168152602001886060015181526020018860a0015181526020018860c001518152509050818160405160240161439a9190615c77565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152925050505b949350505050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b031682604001516001600160a01b03160361442b578151610fc09082613fc2565b81516040830151610fc0916001600160a01b03909116903090846144f6565b6040516001600160a01b038085166024830152831660448201526064810182905261117f9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016141c2565b600080600080600085875af1905080610eca5760405162461bcd60e51b815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152606401610caa565b8373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601614535576040516376fe282b60e11b815260040160405180910390fd5b604051636eb1769f60e11b81526001600160a01b03858116600483015284811660248301526000919087169063dd62ed3e90604401602060405180830381865afa158015614587573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145ab919061576a565b11156145bd576145bd85846000614763565b610e9e85848461487f565b60608315614637578251600003614630576001600160a01b0385163b6146305760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610caa565b50816143e6565b6143e6838361492c565b6000614696826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166149569092919063ffffffff16565b90508051600014806146b75750808060200190518101906146b79190615ce5565b610eca5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610caa565b80600003610f08576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8015806147dd5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa1580156147b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147db919061576a565b155b61484f5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152608401610caa565b6040516001600160a01b038316602482015260448101829052610eca90849063095ea7b360e01b906064016141c2565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa1580156148cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148f3919061576a565b905061117f8463095ea7b360e01b8561490c8686615720565b6040516001600160a01b03909216602483015260448201526064016141c2565b81511561493c5781518083602001fd5b8060405162461bcd60e51b8152600401610caa9190615c23565b60606143e6848460008585600080866001600160a01b0316858760405161497d9190615c36565b60006040518083038185875af1925050503d80600081146149ba576040519150601f19603f3d011682016040523d82523d6000602084013e6149bf565b606091505b5091509150612fcb878383876145c8565b6001600160a01b0381168114610f0857600080fd5b803561260b816149d0565b60008060408385031215614a0357600080fd5b823591506020830135614a15816149d0565b809150509250929050565b600060208284031215614a3257600080fd5b81356001600160e01b03198116811461241c57600080fd5b600060e0828403121561428357600080fd5b8015158114610f0857600080fd5b803561260b81614a5c565b60008060008060808587031215614a8b57600080fd5b84359350602085013567ffffffffffffffff811115614aa957600080fd5b614ab587828801614a4a565b9350506040850135614ac681614a5c565b9396929550929360600135925050565b600060208284031215614ae857600080fd5b813561241c816149d0565b600060208284031215614b0557600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60405160e0810167ffffffffffffffff81118282101715614b4557614b45614b0c565b60405290565b60405160a0810167ffffffffffffffff81118282101715614b4557614b45614b0c565b604051601f8201601f1916810167ffffffffffffffff81118282101715614b9757614b97614b0c565b604052919050565b600067ffffffffffffffff821115614bb957614bb9614b0c565b5060051b60200190565b60006020808385031215614bd657600080fd5b823567ffffffffffffffff811115614bed57600080fd5b8301601f81018513614bfe57600080fd5b8035614c11614c0c82614b9f565b614b6e565b81815260059190911b82018301908381019087831115614c3057600080fd5b928401925b82841015612fcb578335614c48816149d0565b82529284019290840190614c35565b60008083601f840112614c6957600080fd5b50813567ffffffffffffffff811115614c8157600080fd5b6020830191508360208260051b8501011115613f4257600080fd5b600080600060408486031215614cb157600080fd5b833567ffffffffffffffff811115614cc857600080fd5b614cd486828701614c57565b9094509250506020840135614ce8816149d0565b809150509250925092565b60008060008060408587031215614d0957600080fd5b843567ffffffffffffffff80821115614d2157600080fd5b614d2d88838901614c57565b90965094506020870135915080821115614d4657600080fd5b50614d5387828801614c57565b95989497509550505050565b60008060208385031215614d7257600080fd5b823567ffffffffffffffff811115614d8957600080fd5b614d9585828601614c57565b90969095509350505050565b600080600080600060a08688031215614db957600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff811115614de557600080fd5b614df188828901614a4a565b95989497509295608001359392505050565b600081518084526020808501945080840160005b83811015614e3c5781516001600160a01b031687529582019590820190600101614e17565b509495945050505050565b600081518084526020808501945080840160005b83811015614e3c57815187529582019590820190600101614e5b565b604081526000614e8a6040830185614e03565b82810360208401526110518185614e47565b600080600060608486031215614eb157600080fd5b83359250602084013567ffffffffffffffff811115614ecf57600080fd5b614edb86828701614a4a565b925050604084013590509250925092565b60005b83811015614f07578181015183820152602001614eef565b50506000910152565b60008151808452614f28816020860160208601614eec565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015614f9157603f19888603018452614f7f858351614f10565b94509285019290850190600101614f63565b5092979650505050505050565b600080600060608486031215614fb357600080fd5b833592506020840135614fc5816149d0565b91506040840135614ce8816149d0565b600067ffffffffffffffff821115614fef57614fef614b0c565b50601f01601f191660200190565b600082601f83011261500e57600080fd5b813561501c614c0c82614fd5565b81815284602083860101111561503157600080fd5b816020850160208301376000918101602001919091529392505050565b600060e0828403121561506057600080fd5b615068614b22565b9050615073826149e5565b81526020820135602082015261508b604083016149e5565b6040820152606082013560608201526150a660808301614a6a565b608082015260a082013567ffffffffffffffff808211156150c657600080fd5b6150d285838601614ffd565b60a084015260c08401359150808211156150eb57600080fd5b506150f884828501614ffd565b60c08301525092915050565b6000806000806080858703121561511a57600080fd5b843567ffffffffffffffff8082111561513257600080fd5b818701915087601f83011261514657600080fd5b81356020615156614c0c83614b9f565b82815260059290921b8401810191818101908b84111561517557600080fd5b8286015b848110156151ad578035868111156151915760008081fd5b61519f8e86838b010161504e565b845250918301918301615179565b5098506151bd90508982016149e5565b979a97995050505060408601359560600135949350505050565b600082601f8301126151e857600080fd5b813560206151f8614c0c83614b9f565b82815260059290921b8401810191818101908684111561521757600080fd5b8286015b84811015615232578035835291830191830161521b565b509695505050505050565b6000806000806080858703121561525357600080fd5b843567ffffffffffffffff8082111561526b57600080fd5b818701915087601f83011261527f57600080fd5b8135602061528f614c0c83614b9f565b82815260059290921b8401810191818101908b8411156152ae57600080fd5b948201945b838610156152d55785356152c6816149d0565b825294820194908201906152b3565b985050880135925050808211156152eb57600080fd5b6152f7888389016151d7565b9450604087013591508082111561530d57600080fd5b615319888389016151d7565b9350606087013591508082111561532f57600080fd5b5061533c87828801614ffd565b91505092959194509250565b60008060006040848603121561535d57600080fd5b8335615368816149d0565b9250602084013567ffffffffffffffff8082111561538557600080fd5b818601915086601f83011261539957600080fd5b8135818111156153a857600080fd5b8760208285010111156153ba57600080fd5b6020830194508093505050509250925092565b634e487b7160e01b600052603260045260246000fd5b6000610b92368361504e565b634e487b7160e01b600052601160045260246000fd5b81810381811115610b9257610b926153ef565b6040808252810184905260008560608301825b8781101561545b57823561543e816149d0565b6001600160a01b031682526020928301929091019060010161542b565b5083810360208501528481527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85111561549457600080fd5b8460051b915081866020830137016020019695505050505050565b60006001600160a01b0380835116845260208301516020850152806040840151166040850152506060820151606084015260808201511515608084015260a082015160e060a085015261550560e0850182614f10565b905060c083015184820360c086015261551e8282614f10565b95945050505050565b602081528151602082015260208201516040820152604082015160608201526000606083015160a0608084015261556160c08401826154af565b9050608084015160a08401528091505092915050565b634e487b7160e01b600052602160045260246000fd5b6000600284106155ad57634e487b7160e01b600052602160045260246000fd5b838252604060208301526143e66040830184614f10565b6060815260006155d76060830186614e03565b82810360208401526155e98186614e47565b905082810360408401526140ff8185614e47565b6020815281516020820152600060208301516060604084015261562360808401826154af565b9050604084015160608401528091505092915050565b60008261565657634e487b7160e01b600052601260045260246000fd5b500490565b6000808335601e1984360301811261567257600080fd5b83018035915067ffffffffffffffff82111561568d57600080fd5b602001915036819003821315613f4257600080fd5b60a0808252865190820181905260009060209060c0840190828a01845b828110156156e45781516001600160a01b0316845292840192908401906001016156bf565b505050838103828501526156f88189614e47565b6001600160a01b03979097166040850152505050606081019290925260809091015292915050565b80820180821115610b9257610b926153ef565b8183823760009101908152919050565b8181036000831280158383131683831282161715615763576157636153ef565b5092915050565b60006020828403121561577c57600080fd5b5051919050565b600060e082018983526020898185015288604085015287606085015260e06080850152818754808452610100860191508860005282600020935060005b818110156157e55784546001600160a01b0316835260019485019492840192016157c0565b505084810360a08601526157f98188614e47565b93505050508260c083015298975050505050505050565b80516fffffffffffffffffffffffffffffffff8116811461260b57600080fd5b60006020828403121561584257600080fd5b61241c82615810565b8082028115828204841417610b9257610b926153ef565b6000608082016001600160a01b038088168452602060808186015282885180855260a087019150828a01945060005b818110156158af578551851683529483019491830191600101615891565b505085810360408701526158c38189614e47565b93505050508281036060840152612fcb8185614f10565b805161260b816149d0565b805161260b81614a5c565b600082601f83011261590157600080fd5b815161590f614c0c82614fd5565b81815284602083860101111561592457600080fd5b6143e6826020830160208701614eec565b600060e0828403121561594757600080fd5b61594f614b22565b905061595a826158da565b815260208201516020820152615972604083016158da565b60408201526060820151606082015261598d608083016158e5565b608082015260a082015167ffffffffffffffff808211156159ad57600080fd5b6159b9858386016158f0565b60a084015260c08401519150808211156159d257600080fd5b506150f8848285016158f0565b6000602082840312156159f157600080fd5b815167ffffffffffffffff80821115615a0957600080fd5b9083019060a08286031215615a1d57600080fd5b615a25614b4b565b825181526020830151602082015260408301516040820152606083015182811115615a4f57600080fd5b615a5b87828601615935565b6060830152506080830151608082015280935050505092915050565b600060208284031215615a8957600080fd5b815167ffffffffffffffff80821115615aa157600080fd5b9083019060608286031215615ab557600080fd5b604051606081018181108382111715615ad057615ad0614b0c565b60405282518152602083015182811115615ae957600080fd5b615af587828601615935565b6020830152506040830151604082015280935050505092915050565b805167ffffffffffffffff8116811461260b57600080fd5b600080600080600080600080610100898b031215615b4657600080fd5b885160ff81168114615b5757600080fd5b60208a0151909850615b68816149d0565b60408a0151909750615b79816149d0565b9550615b8760608a01615b11565b9450615b9560808a01615b11565b9350615ba360a08a01615b11565b9250615bb160c08a01615b11565b9150615bbf60e08a01615810565b90509295985092959890939650565b60008060408385031215615be157600080fd5b825160028110615bf057600080fd5b602084015190925067ffffffffffffffff811115615c0d57600080fd5b615c19858286016158f0565b9150509250929050565b60208152600061241c6020830184614f10565b60008251615c48818460208701614eec565b9190910192915050565b60008060408385031215615c6557600080fd5b825191506020830151614a15816149d0565b6020815260006001600160a01b03808451166020840152602084015160408401528060408501511660608401525060608301516080830152608083015160c060a0840152615cc860e0840182614f10565b905060a0840151601f198483030160c085015261551e8282614f10565b600060208284031215615cf757600080fd5b815161241c81614a5c56fe43023f179164d629e1d761fb32e2db4dbd5ce417a23159d7da9cc7b562689285d9c9e1a27f80559d0ef9cb96900d3b37cb5d56df00dca6d004c3b26d13df7898416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a164736f6c6343000812000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001600000000000000000000000003b016025cd3d213c5779e10fe94a35ba440bd1c9000000000000000000000000a59c5bc33c9d705b738aa553b724d8c39324fd200000000000000000000000003b016025cd3d213c5779e10fe94a35ba440bd1c9000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000d056c0eee354b24fe7c5d4ee762c4d7574badac10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000003000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca00000000000000000000000000000000000000000000000000000000000000006000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000f155735395a323b2a12051b5bc076c2c49eebeb300000000000000000000000081261c3ae484d2c0873bbea019eaecebc0056f95
-----Decoded View---------------
Arg [0] : baseNativeWrapperConfig (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [1] : coreAccessControlConfig (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [2] : coreSwapConfig (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [3] : coreFeesConfig (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
-----Encoded View---------------
28 Constructor Arguments found :
Arg [0] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [3] : 0000000000000000000000003b016025cd3d213c5779e10fe94a35ba440bd1c9
Arg [4] : 000000000000000000000000a59c5bc33c9d705b738aa553b724d8c39324fd20
Arg [5] : 0000000000000000000000003b016025cd3d213c5779e10fe94a35ba440bd1c9
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [7] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [9] : 000000000000000000000000d056c0eee354b24fe7c5d4ee762c4d7574badac1
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [12] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [13] : 00000000000000000000000000000000000000000000000000000000000001c0
Arg [14] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [15] : 000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
Arg [16] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [17] : 0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0
Arg [18] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [19] : 000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
Arg [20] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [21] : 0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0
Arg [22] : 000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7
Arg [23] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [24] : 0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f
Arg [25] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [26] : 000000000000000000000000f155735395a323b2a12051b5bc076c2c49eebeb3
Arg [27] : 00000000000000000000000081261c3ae484d2c0873bbea019eaecebc0056f95
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 27 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.