Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 211 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Multicall | 19741808 | 288 days ago | IN | 0 ETH | 0.00141152 | ||||
Multicall | 19733699 | 289 days ago | IN | 0 ETH | 0.00336278 | ||||
Multicall | 19679404 | 297 days ago | IN | 0 ETH | 0.00267378 | ||||
Multicall | 19665028 | 299 days ago | IN | 0 ETH | 0.00207964 | ||||
Multicall | 19604881 | 307 days ago | IN | 0 ETH | 0.0054365 | ||||
Multicall | 19578039 | 311 days ago | IN | 1 ETH | 0.00824287 | ||||
Multicall | 19556213 | 314 days ago | IN | 0.006 ETH | 0.00963808 | ||||
Multicall | 19552681 | 315 days ago | IN | 0.01 ETH | 0.00519493 | ||||
Multicall | 19547336 | 316 days ago | IN | 0.0015 ETH | 0.00691342 | ||||
Multicall | 19539739 | 317 days ago | IN | 0 ETH | 0.00625193 | ||||
Multicall | 19539733 | 317 days ago | IN | 0.0015 ETH | 0.00887757 | ||||
Multicall | 19538199 | 317 days ago | IN | 0.0015 ETH | 0.00551275 | ||||
Multicall | 19535123 | 317 days ago | IN | 0 ETH | 0.01213215 | ||||
Multicall | 19529126 | 318 days ago | IN | 0 ETH | 0.00721079 | ||||
Multicall | 19527275 | 318 days ago | IN | 0 ETH | 0.00214432 | ||||
Multicall | 19527271 | 318 days ago | IN | 0 ETH | 0.00272963 | ||||
Multicall | 19527268 | 318 days ago | IN | 0 ETH | 0.00279773 | ||||
Multicall | 19525896 | 319 days ago | IN | 0.03723742 ETH | 0.01485722 | ||||
Multicall | 19525514 | 319 days ago | IN | 0 ETH | 0.00641891 | ||||
Multicall | 19488838 | 324 days ago | IN | 0 ETH | 0.00508853 | ||||
Multicall | 19475797 | 326 days ago | IN | 0 ETH | 0.008265 | ||||
Multicall | 19446498 | 330 days ago | IN | 0 ETH | 0.00555684 | ||||
Multicall | 19445678 | 330 days ago | IN | 0.0014 ETH | 0.00689909 | ||||
Multicall | 19381606 | 339 days ago | IN | 0 ETH | 0.00930435 | ||||
Multicall | 19358058 | 342 days ago | IN | 0.006 ETH | 0.01540275 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
19578039 | 311 days ago | 1 ETH | ||||
19556213 | 314 days ago | 0.006 ETH | ||||
19552681 | 315 days ago | 0.01 ETH | ||||
19547336 | 316 days ago | 0.0015 ETH | ||||
19539739 | 317 days ago | 0.0015 ETH | ||||
19539739 | 317 days ago | 0.0015 ETH | ||||
19539733 | 317 days ago | 0.0015 ETH | ||||
19538199 | 317 days ago | 0.0015 ETH | ||||
19525896 | 319 days ago | 0.03723742 ETH | ||||
19525514 | 319 days ago | 0.99128149 ETH | ||||
19525514 | 319 days ago | 0.99128149 ETH | ||||
19488838 | 324 days ago | 2.08214001 ETH | ||||
19488838 | 324 days ago | 2.08214001 ETH | ||||
19445678 | 330 days ago | 0.0014 ETH | ||||
19381606 | 339 days ago | 1.86798883 ETH | ||||
19381606 | 339 days ago | 1.86798883 ETH | ||||
19358058 | 342 days ago | 0.006 ETH | ||||
19304333 | 350 days ago | 0.03273207 ETH | ||||
19304333 | 350 days ago | 0.03273207 ETH | ||||
19249039 | 357 days ago | 1.98288941 ETH | ||||
19249039 | 357 days ago | 1.98288941 ETH | ||||
19225710 | 361 days ago | 9.06501798 ETH | ||||
19225710 | 361 days ago | 9.06501798 ETH | ||||
19207955 | 363 days ago | 0.01711332 ETH | ||||
19207955 | 363 days ago | 0.01711332 ETH |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
DCAHubCompanion
Compiler Version
v0.8.16+commit.07a7930e
Optimization Enabled:
Yes with 9999 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.7 <0.9.0; import './DCAHubCompanionLibrariesHandler.sol'; import './DCAHubCompanionHubProxyHandler.sol'; import '../utils/BaseCompanion.sol'; contract DCAHubCompanion is DCAHubCompanionLibrariesHandler, DCAHubCompanionHubProxyHandler, BaseCompanion, IDCAHubCompanion { constructor( address _swapper, address _allowanceTarget, address _governor, IPermit2 _permit2 ) BaseCompanion(_swapper, _allowanceTarget, _governor, _permit2) {} }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.7 <0.9.0; import '../libraries/InputBuilding.sol'; import '../libraries/SecondsUntilNextSwap.sol'; import '../interfaces/IDCAHubCompanion.sol'; abstract contract DCAHubCompanionLibrariesHandler is IDCAHubCompanionLibrariesHandler { /// @inheritdoc IDCAHubCompanionLibrariesHandler function getNextSwapInfo( IDCAHub _hub, Pair[] calldata _pairs, bool _calculatePrivilegedAvailability, bytes calldata _oracleData ) external view returns (IDCAHub.SwapInfo memory) { (address[] memory _tokens, IDCAHub.PairIndexes[] memory _indexes) = InputBuilding.buildGetNextSwapInfoInput(_pairs); return _hub.getNextSwapInfo(_tokens, _indexes, _calculatePrivilegedAvailability, _oracleData); } /// @inheritdoc IDCAHubCompanionLibrariesHandler function legacyGetNextSwapInfo(ILegacyDCAHub _hub, Pair[] calldata _pairs) external view returns (ILegacyDCAHub.SwapInfo memory) { (address[] memory _tokens, IDCAHub.PairIndexes[] memory _indexes) = InputBuilding.buildGetNextSwapInfoInput(_pairs); return _hub.getNextSwapInfo(_tokens, _indexes); } /// @inheritdoc IDCAHubCompanionLibrariesHandler function secondsUntilNextSwap( IDCAHub _hub, Pair[] calldata _pairs, bool _calculatePrivilegedAvailability ) external view returns (uint256[] memory) { return SecondsUntilNextSwap.secondsUntilNextSwap(_hub, _pairs, _calculatePrivilegedAvailability); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.7 <0.9.0; import '@mean-finance/swappers/solidity/contracts/extensions/RevokableWithGovernor.sol'; import '@mean-finance/swappers/solidity/contracts/extensions/PayableMulticall.sol'; import {SimulationAdapter} from '@mean-finance/call-simulation/contracts/SimulationAdapter.sol'; import {IPermit2} from '../interfaces/external/IPermit2.sol'; import {Permit2Transfers} from '../libraries/Permit2Transfers.sol'; /** * @notice This contract will work as base companion for all our contracts. It will extend the capabilities of our companion * contracts so that they can execute multicalls, swaps, revokes and more * @dev All public functions are payable, so that they can be multicalled together with other payable functions when msg.value > 0 */ abstract contract BaseCompanion is SimulationAdapter, RevokableWithGovernor, PayableMulticall { using Permit2Transfers for IPermit2; using SafeERC20 for IERC20; /** * @notice Thrown when the swap produced less token out than expected * @param received The amount of token out received * @param expected The amount of token out expected */ error ReceivedTooLittleTokenOut(uint256 received, uint256 expected); /** * @notice Returns the address of the Permit2 contract * @dev This value is constant and cannot change * @return The address of the Permit2 contract */ // solhint-disable-next-line var-name-mixedcase IPermit2 public immutable PERMIT2; /// @notice The address of the swapper address public swapper; /// @notice The address of the allowance target address public allowanceTarget; constructor( address _swapper, address _allowanceTarget, address _governor, IPermit2 _permit2 ) SwapAdapter(address(1)) Governable(_governor) { swapper = _swapper; allowanceTarget = _allowanceTarget; PERMIT2 = _permit2; } /** * @notice Sends the specified amount of the given token to the recipient * @param _token The token to transfer * @param _amount The amount to transfer * @param _recipient The recipient of the token balance */ function sendToRecipient( address _token, uint256 _amount, address _recipient ) external payable { _sendToRecipient(_token, _amount, _recipient); } /** * @notice Takes the given amount of tokens from the caller and transfers it to this contract * @param _token The token to take * @param _amount The amount to take */ function takeFromCaller( IERC20 _token, uint256 _amount, address _recipient ) external payable { _token.safeTransferFrom(msg.sender, _recipient, _amount); } /** * @notice Executes a swap against the swapper * @param _allowanceToken The token to set allowance for (can be set to zero address to ignore) * @param _value The value to send to the swapper as part of the swap * @param _swapData The swap data * @param _tokenOut The token that will be bought as part of the swap * @param _minTokenOut The min amount of token out that we expect */ function runSwap( address _allowanceToken, uint256 _value, bytes calldata _swapData, address _tokenOut, uint256 _minTokenOut ) external payable returns (uint256 _amountOut) { if (_allowanceToken != address(0)) { IERC20(_allowanceToken).approve(allowanceTarget, type(uint256).max); } _executeSwap(swapper, _swapData, _value); _amountOut = _tokenOut == PROTOCOL_TOKEN ? address(this).balance : IERC20(_tokenOut).balanceOf(address(this)); if (_amountOut < _minTokenOut) revert ReceivedTooLittleTokenOut(_amountOut, _minTokenOut); } /** * @notice Takes the given amount of tokens from the caller with Permit2 and transfers it to this contract * @param _token The token to take * @param _amount The amount to take * @param _nonce The signed nonce * @param _deadline The signature's deadline * @param _signature The owner's signature * @param _recipient The address that will receive the funds */ function permitTakeFromCaller( address _token, uint256 _amount, uint256 _nonce, uint256 _deadline, bytes calldata _signature, address _recipient ) external payable { PERMIT2.takeFromCaller(_token, _amount, _nonce, _deadline, _signature, _recipient); } /** * @notice Takes the a batch of tokens from the caller with Permit2 and transfers it to this contract * @param _tokens The tokens to take * @param _nonce The signed nonce * @param _deadline The signature's deadline * @param _signature The owner's signature * @param _recipient The address that will receive the funds */ function batchPermitTakeFromCaller( IPermit2.TokenPermissions[] calldata _tokens, uint256 _nonce, uint256 _deadline, bytes calldata _signature, address _recipient ) external payable { PERMIT2.batchTakeFromCaller(_tokens, _nonce, _deadline, _signature, _recipient); } /** * @notice Checks if the contract has any balance of the given token, and if it does, * it sends it to the given recipient * @param _token The token to check * @param _recipient The recipient of the token balance */ function sendBalanceOnContractToRecipient(address _token, address _recipient) external payable { _sendBalanceOnContractToRecipient(_token, _recipient); } /** * @notice Sets a new swapper and allowance target * @param _newSwapper The address of the new swapper * @param _newAllowanceTarget The address of the new allowance target */ function setSwapper(address _newSwapper, address _newAllowanceTarget) external onlyGovernor { swapper = _newSwapper; allowanceTarget = _newAllowanceTarget; } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.7 <0.9.0; import '../interfaces/IDCAHubCompanion.sol'; /// @dev All public functions are payable, so that they can be multicalled together with other payable functions when msg.value > 0 abstract contract DCAHubCompanionHubProxyHandler is IDCAHubCompanionHubProxyHandler { /// @inheritdoc IDCAHubCompanionHubProxyHandler function permissionPermit( IDCAPermissionManager _permissionManager, IDCAPermissionManager.PermissionSet[] calldata _permissions, uint256 _tokenId, uint256 _deadline, uint8 _v, bytes32 _r, bytes32 _s ) external payable { _permissionManager.permissionPermit(_permissions, _tokenId, _deadline, _v, _r, _s); } /// @inheritdoc IDCAHubCompanionHubProxyHandler function multiPermissionPermit( IDCAPermissionManager _permissionManager, IDCAPermissionManager.PositionPermissions[] calldata _permissions, uint256 _deadline, uint8 _v, bytes32 _r, bytes32 _s ) external payable { _permissionManager.multiPermissionPermit(_permissions, _deadline, _v, _r, _s); } /// @inheritdoc IDCAHubCompanionHubProxyHandler function deposit( IDCAHub _hub, address _from, address _to, uint256 _amount, uint32 _amountOfSwaps, uint32 _swapInterval, address _owner, IDCAPermissionManager.PermissionSet[] calldata _permissions, bytes calldata _miscellaneous ) public payable virtual returns (uint256 _positionId) { _approveHub(address(_from), _hub, _amount); _positionId = _miscellaneous.length > 0 ? _hub.deposit(_from, _to, _amount, _amountOfSwaps, _swapInterval, _owner, _permissions, _miscellaneous) : _hub.deposit(_from, _to, _amount, _amountOfSwaps, _swapInterval, _owner, _permissions); } /// @inheritdoc IDCAHubCompanionHubProxyHandler function depositWithBalanceOnContract( IDCAHub _hub, address _from, address _to, uint32 _amountOfSwaps, uint32 _swapInterval, address _owner, IDCAPermissionManager.PermissionSet[] calldata _permissions, bytes calldata _miscellaneous ) external payable returns (uint256 _positionId) { uint256 _amount = IERC20(_from).balanceOf(address(this)); return deposit(_hub, _from, _to, _amount, _amountOfSwaps, _swapInterval, _owner, _permissions, _miscellaneous); } /// @inheritdoc IDCAHubCompanionHubProxyHandler function withdrawSwapped( IDCAHub _hub, uint256 _positionId, address _recipient ) external payable verifyPermission(_hub, _positionId, IDCAPermissionManager.Permission.WITHDRAW) returns (uint256 _swapped) { _swapped = _hub.withdrawSwapped(_positionId, _recipient); } /// @inheritdoc IDCAHubCompanionHubProxyHandler function withdrawSwappedMany( IDCAHub _hub, IDCAHub.PositionSet[] calldata _positions, address _recipient ) external payable returns (uint256[] memory _withdrawn) { for (uint256 i = 0; i < _positions.length; ) { uint256[] memory _positionIds = _positions[i].positionIds; for (uint256 j = 0; j < _positionIds.length; ) { _checkPermissionOrFail(_hub, _positionIds[j], IDCAPermissionManager.Permission.WITHDRAW); unchecked { j++; } } unchecked { i++; } } _withdrawn = _hub.withdrawSwappedMany(_positions, _recipient); } /// @inheritdoc IDCAHubCompanionHubProxyHandler function increasePosition( IDCAHub _hub, uint256 _positionId, uint256 _amount, uint32 _newSwaps ) external payable verifyPermission(_hub, _positionId, IDCAPermissionManager.Permission.INCREASE) { IERC20Metadata _from = _hub.userPosition(_positionId).from; _approveHub(address(_from), _hub, _amount); _hub.increasePosition(_positionId, _amount, _newSwaps); } /// @inheritdoc IDCAHubCompanionHubProxyHandler function increasePositionWithBalanceOnContract( IDCAHub _hub, uint256 _positionId, uint32 _newSwaps ) external payable verifyPermission(_hub, _positionId, IDCAPermissionManager.Permission.INCREASE) { IERC20Metadata _from = _hub.userPosition(_positionId).from; uint256 _amount = _from.balanceOf(address(this)); _approveHub(address(_from), _hub, _amount); _hub.increasePosition(_positionId, _amount, _newSwaps); } /// @inheritdoc IDCAHubCompanionHubProxyHandler function reducePosition( IDCAHub _hub, uint256 _positionId, uint256 _amount, uint32 _newSwaps, address _recipient ) external payable verifyPermission(_hub, _positionId, IDCAPermissionManager.Permission.REDUCE) { _hub.reducePosition(_positionId, _amount, _newSwaps, _recipient); } /// @inheritdoc IDCAHubCompanionHubProxyHandler function terminate( IDCAHub _hub, uint256 _positionId, address _recipientUnswapped, address _recipientSwapped ) external payable verifyPermission(_hub, _positionId, IDCAPermissionManager.Permission.TERMINATE) returns (uint256 _unswapped, uint256 _swapped) { (_unswapped, _swapped) = _hub.terminate(_positionId, _recipientUnswapped, _recipientSwapped); } function _approveHub( address _token, IDCAHub _hub, uint256 _amount ) internal { uint256 _allowance = IERC20(_token).allowance(address(this), address(_hub)); if (_allowance < _amount) { if (_allowance > 0) { IERC20(_token).approve(address(_hub), 0); // We do this because some tokens (like USDT) fail if we don't } IERC20(_token).approve(address(_hub), type(uint256).max); } } function _checkPermissionOrFail( IDCAHub _hub, uint256 _positionId, IDCAPermissionManager.Permission _permission ) internal view { if (!_hub.permissionManager().hasPermission(_positionId, msg.sender, _permission)) revert UnauthorizedCaller(); } modifier verifyPermission( IDCAHub _hub, uint256 _positionId, IDCAPermissionManager.Permission _permission ) { _checkPermissionOrFail(_hub, _positionId, _permission); _; } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.7 <0.9.0; import '@mean-finance/dca-v2-core/contracts/interfaces/IDCAHub.sol'; import '@mean-finance/dca-v2-core/contracts/interfaces/IDCAPermissionManager.sol'; import './ILegacyDCAHub.sol'; import './ISharedTypes.sol'; /** * @notice This contract exposes many utils that are also available through libraries. The idea is to make * these functions available here, so others don't need to deploy new contracts */ interface IDCAHubCompanionLibrariesHandler { /** * @notice Takes a list of pairs and returns how it would look like to execute a swap for all of them * @dev Please note that this function is very expensive. Ideally, it would be used for off-chain purposes * @param hub The address of the DCAHub * @param pairs The pairs to be involved in the swap * @param calculatePrivilegedAvailability Some accounts get privileged availability and can execute swaps before others. This flag provides * the possibility to calculate the next swap information for privileged and non-privileged accounts * @param oracleData Bytes to send to the oracle when executing a quote * @return How executing a swap for all the given pairs would look like */ function getNextSwapInfo( IDCAHub hub, Pair[] calldata pairs, bool calculatePrivilegedAvailability, bytes calldata oracleData ) external view returns (IDCAHub.SwapInfo memory); /** * @notice Takes a list of pairs and returns how it would look like to execute a swap for all of them * @dev Please note that this function is very expensive. Ideally, it would be used for off-chain purposes * @param hub The address of the DCAHub * @param pairs The pairs to be involved in the swap * @return How executing a swap for all the given pairs would look like */ function legacyGetNextSwapInfo(ILegacyDCAHub hub, Pair[] calldata pairs) external view returns (ILegacyDCAHub.SwapInfo memory); /** * @notice Returns how many seconds left until the next swap is available for a list of pairs * @dev Tokens in pairs may be passed in either tokenA/tokenB or tokenB/tokenA order * @param hub The address of the DCAHub * @param pairs Pairs to check * @param calculatePrivilegedAvailability Some accounts get privileged availability and can execute swaps before others. This flag provides * the possibility to calculate the seconds until next swap for privileged and non-privileged accounts * @return The amount of seconds until next swap for each of the pairs */ function secondsUntilNextSwap( IDCAHub hub, Pair[] calldata pairs, bool calculatePrivilegedAvailability ) external view returns (uint256[] memory); } interface IDCAHubCompanionHubProxyHandler { /// @notice Thrown when a user tries operate on a position that they don't have access to error UnauthorizedCaller(); /** * @notice Creates a new position * @dev Meant to be used as part of a multicall * @param hub The address of the DCAHub * @param from The address of the "from" token * @param to The address of the "to" token * @param amount How many "from" tokens will be swapped in total * @param amountOfSwaps How many swaps to execute for this position * @param swapInterval How frequently the position's swaps should be executed * @param owner The address of the owner of the position being created * @param miscellaneous Bytes that will be emitted, and associated with the position. If empty, no event will be emitted * @return positionId The id of the created position */ function deposit( IDCAHub hub, address from, address to, uint256 amount, uint32 amountOfSwaps, uint32 swapInterval, address owner, IDCAPermissionManager.PermissionSet[] calldata permissions, bytes calldata miscellaneous ) external payable returns (uint256 positionId); /** * @notice Creates a new position using the entire balance available on the contract * @dev Meant to be used as part of a multicall * @param hub The address of the DCAHub * @param from The address of the "from" token * @param to The address of the "to" token * @param amountOfSwaps How many swaps to execute for this position * @param swapInterval How frequently the position's swaps should be executed * @param owner The address of the owner of the position being created * @param miscellaneous Bytes that will be emitted, and associated with the position. If empty, no event will be emitted * @return positionId The id of the created position */ function depositWithBalanceOnContract( IDCAHub hub, address from, address to, uint32 amountOfSwaps, uint32 swapInterval, address owner, IDCAPermissionManager.PermissionSet[] calldata permissions, bytes calldata miscellaneous ) external payable returns (uint256 positionId); /** * @notice Call the hub and withdraws all swapped tokens from a position to a recipient * @dev Meant to be used as part of a multicall * @param hub The address of the DCAHub * @param positionId The position's id * @param recipient The address to withdraw swapped tokens to * @return swapped How much was withdrawn */ function withdrawSwapped( IDCAHub hub, uint256 positionId, address recipient ) external payable returns (uint256 swapped); /** * @notice Call the hub and withdraws all swapped tokens from multiple positions * @dev Meant to be used as part of a multicall * @param hub The address of the DCAHub * @param positions A list positions, grouped by `to` token * @param recipient The address to withdraw swapped tokens to * @return withdrawn How much was withdrawn for each token */ function withdrawSwappedMany( IDCAHub hub, IDCAHub.PositionSet[] calldata positions, address recipient ) external payable returns (uint256[] memory withdrawn); /** * @notice Call the hub and takes the unswapped balance, adds the new deposited funds and modifies the position so that * it is executed in `newSwaps` swaps * @dev Meant to be used as part of a multicall * @param hub The address of the DCAHub * @param positionId The position's id * @param amount Amount of funds to add to the position * @param newSwaps The new amount of swaps */ function increasePosition( IDCAHub hub, uint256 positionId, uint256 amount, uint32 newSwaps ) external payable; /** * @notice Call the hub and takes the unswapped balance, adds the Companion's current balance and modifies the position so that * it is executed in `newSwaps` swaps * @dev Meant to be used as part of a multicall * @param hub The address of the DCAHub * @param positionId The position's id * @param newSwaps The new amount of swaps */ function increasePositionWithBalanceOnContract( IDCAHub hub, uint256 positionId, uint32 newSwaps ) external payable; /** * @notice Call the hub and withdraws the specified amount from the unswapped balance and modifies the position so that * it is executed in newSwaps swaps * @dev Meant to be used as part of a multicall * @param hub The address of the DCAHub * @param positionId The position's id * @param amount Amount of funds to withdraw from the position * @param newSwaps The new amount of swaps * @param recipient The address to send tokens to */ function reducePosition( IDCAHub hub, uint256 positionId, uint256 amount, uint32 newSwaps, address recipient ) external payable; /** * @notice Calls the hub and terminates the position and sends all unswapped and swapped balance to the specified recipients * @dev Meant to be used as part of a multicall * @param hub The address of the DCAHub * @param positionId The position's id * @param recipientUnswapped The address to withdraw unswapped tokens to * @param recipientSwapped The address to withdraw swapped tokens to * @return unswapped The unswapped balance sent to `recipientUnswapped` * @return swapped The swapped balance sent to `recipientSwapped` */ function terminate( IDCAHub hub, uint256 positionId, address recipientUnswapped, address recipientSwapped ) external payable returns (uint256 unswapped, uint256 swapped); /** * @notice Calls the permission manager and sets multiple permissions via signature * @param permissionManager The address of the permission manager * @param permissions The permissions to set * @param deadline The deadline timestamp by which the call must be mined for the approve to work * @param v Must produce valid secp256k1 signature from the holder along with `r` and `s` * @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` * @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` */ function multiPermissionPermit( IDCAPermissionManager permissionManager, IDCAPermissionManager.PositionPermissions[] calldata permissions, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external payable; /** * @notice Calls the permission manager and sets permissions via signature * @param permissionManager The address of the permission manager * @param permissions The permissions to set * @param tokenId The token's id * @param deadline The deadline timestamp by which the call must be mined for the approve to work * @param v Must produce valid secp256k1 signature from the holder along with `r` and `s` * @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` * @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` */ function permissionPermit( IDCAPermissionManager permissionManager, IDCAPermissionManager.PermissionSet[] calldata permissions, uint256 tokenId, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external payable; } interface IDCAHubCompanion is IDCAHubCompanionLibrariesHandler, IDCAHubCompanionHubProxyHandler {}
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.7 <0.9.0; import '@mean-finance/dca-v2-core/contracts/interfaces/IDCAHub.sol'; import '@mean-finance/dca-v2-core/contracts/libraries/TokenSorting.sol'; import '@mean-finance/dca-v2-core/contracts/libraries/Intervals.sol'; import '../interfaces/ISharedTypes.sol'; /** * @title Seconds Until Next Swap Library * @notice Provides functions to calculate how long users have to wait until a pair's next swap is available */ library SecondsUntilNextSwap { /** * @notice Returns how many seconds left until the next swap is available for a specific pair * @dev _tokenA and _tokenB may be passed in either tokenA/tokenB or tokenB/tokenA order * @param _hub The address of the DCA Hub * @param _tokenA One of the pair's tokens * @param _tokenB The other of the pair's tokens * @param _calculatePrivilegedAvailability Some accounts get privileged availability and can execute swaps before others. This flag provides * the possibility to calculate the seconds until next swap for privileged and non-privileged accounts * @return The amount of seconds until next swap. Returns 0 if a swap can already be executed and max(uint256) if there is nothing to swap */ function secondsUntilNextSwap( IDCAHub _hub, address _tokenA, address _tokenB, bool _calculatePrivilegedAvailability ) internal view returns (uint256) { (address __tokenA, address __tokenB) = TokenSorting.sortTokens(_tokenA, _tokenB); bytes1 _activeIntervals = _hub.activeSwapIntervals(__tokenA, __tokenB); bytes1 _mask = 0x01; uint256 _smallerIntervalBlocking; while (_activeIntervals >= _mask && _mask > 0) { if (_activeIntervals & _mask == _mask) { (, uint224 _nextAmountToSwapAToB, uint32 _lastSwappedAt, uint224 _nextAmountToSwapBToA) = _hub.swapData(_tokenA, _tokenB, _mask); uint32 _swapInterval = Intervals.maskToInterval(_mask); uint256 _nextAvailable = ((_lastSwappedAt / _swapInterval) + 1) * _swapInterval; if (!_calculatePrivilegedAvailability) { // If the caller does not have privileges, then they will have to wait a little more to execute swaps _nextAvailable += _swapInterval / 3; } if (_nextAmountToSwapAToB > 0 || _nextAmountToSwapBToA > 0) { if (_nextAvailable <= block.timestamp) { return _smallerIntervalBlocking; } else { return _nextAvailable - block.timestamp; } } else if (_nextAvailable > block.timestamp) { _smallerIntervalBlocking = _smallerIntervalBlocking == 0 ? _nextAvailable - block.timestamp : _smallerIntervalBlocking; } } _mask <<= 1; } return type(uint256).max; } /** * @notice Returns how many seconds left until the next swap is available for a list of pairs * @dev Tokens in pairs may be passed in either tokenA/tokenB or tokenB/tokenA order * @param _hub The address of the DCA Hub * @param _pairs Pairs to check * @return _seconds The amount of seconds until next swap for each of the pairs * @param _calculatePrivilegedAvailability Some accounts get privileged availability and can execute swaps before others. This flag provides * the possibility to calculate the seconds until next swap for privileged and non-privileged accounts */ function secondsUntilNextSwap( IDCAHub _hub, Pair[] calldata _pairs, bool _calculatePrivilegedAvailability ) internal view returns (uint256[] memory _seconds) { _seconds = new uint256[](_pairs.length); for (uint256 i; i < _pairs.length; i++) { _seconds[i] = secondsUntilNextSwap(_hub, _pairs[i].tokenA, _pairs[i].tokenB, _calculatePrivilegedAvailability); } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.7 <0.9.0; import '@mean-finance/dca-v2-core/contracts/interfaces/IDCAHub.sol'; import '../interfaces/ISharedTypes.sol'; /// @title Input Building Library /// @notice Provides functions to build input for swap related actions /// @dev Please note that these functions are very expensive. Ideally, these would be used for off-chain purposes library InputBuilding { /// @notice Takes a list of pairs and returns the input necessary to check the next swap /// @dev Even though this function allows it, the DCAHub will fail if duplicated pairs are used /// @return _tokens A sorted list of all the tokens involved in the swap /// @return _pairsToSwap A sorted list of indexes that represent the pairs involved in the swap function buildGetNextSwapInfoInput(Pair[] calldata _pairs) internal pure returns (address[] memory _tokens, IDCAHub.PairIndexes[] memory _pairsToSwap) { (_tokens, _pairsToSwap, ) = buildSwapInput(_pairs, new IDCAHub.AmountOfToken[](0)); } /// @notice Takes a list of pairs and a list of tokens to borrow and returns the input necessary to execute a swap /// @dev Even though this function allows it, the DCAHub will fail if duplicated pairs are used /// @return _tokens A sorted list of all the tokens involved in the swap /// @return _pairsToSwap A sorted list of indexes that represent the pairs involved in the swap /// @return _borrow A list of amounts to borrow, based on the sorted token list function buildSwapInput(Pair[] calldata _pairs, IDCAHub.AmountOfToken[] memory _toBorrow) internal pure returns ( address[] memory _tokens, IDCAHub.PairIndexes[] memory _pairsToSwap, uint256[] memory _borrow ) { _tokens = _calculateUniqueTokens(_pairs, _toBorrow); _pairsToSwap = _calculatePairIndexes(_pairs, _tokens); _borrow = _calculateTokensToBorrow(_toBorrow, _tokens); } /// @dev Given a list of token pairs and tokens to borrow, returns a list of all the tokens involved, sorted function _calculateUniqueTokens(Pair[] memory _pairs, IDCAHub.AmountOfToken[] memory _toBorrow) private pure returns (address[] memory _tokens) { uint256 _uniqueTokens; address[] memory _tokensPlaceholder = new address[](_pairs.length * 2 + _toBorrow.length); // Load tokens in pairs onto placeholder for (uint256 i; i < _pairs.length; i++) { bool _foundA = false; bool _foundB = false; for (uint256 j; j < _uniqueTokens && !(_foundA && _foundB); j++) { if (!_foundA && _tokensPlaceholder[j] == _pairs[i].tokenA) _foundA = true; if (!_foundB && _tokensPlaceholder[j] == _pairs[i].tokenB) _foundB = true; } if (!_foundA) _tokensPlaceholder[_uniqueTokens++] = _pairs[i].tokenA; if (!_foundB) _tokensPlaceholder[_uniqueTokens++] = _pairs[i].tokenB; } // Load tokens to borrow onto placeholder for (uint256 i; i < _toBorrow.length; i++) { bool _found = false; for (uint256 j; j < _uniqueTokens && !_found; j++) { if (_tokensPlaceholder[j] == _toBorrow[i].token) _found = true; } if (!_found) _tokensPlaceholder[_uniqueTokens++] = _toBorrow[i].token; } // Load sorted into new array _tokens = new address[](_uniqueTokens); for (uint256 i; i < _uniqueTokens; i++) { address _token = _tokensPlaceholder[i]; // Find index where the token should be uint256 _tokenIndex; while (_tokens[_tokenIndex] < _token && _tokens[_tokenIndex] != address(0)) _tokenIndex++; // Move everything one place back for (uint256 j = i; j > _tokenIndex; j--) { _tokens[j] = _tokens[j - 1]; } // Set token on the correct index _tokens[_tokenIndex] = _token; } } /// @dev Given a list of pairs, and a list of sorted tokens, it translates the first list into indexes of the second list. This list of indexes will /// be sorted. For example, if pairs are [{ tokenA, tokenB }, { tokenC, tokenB }] and tokens are: [ tokenA, tokenB, tokenC ], the following is returned /// [ { 0, 1 }, { 1, 1 }, { 1, 2 } ] function _calculatePairIndexes(Pair[] calldata _pairs, address[] memory _tokens) private pure returns (IDCAHub.PairIndexes[] memory _pairIndexes) { _pairIndexes = new IDCAHub.PairIndexes[](_pairs.length); uint256 _count; for (uint8 i; i < _tokens.length; i++) { for (uint8 j = i + 1; j < _tokens.length; j++) { for (uint256 k; k < _pairs.length; k++) { if ( (_tokens[i] == _pairs[k].tokenA && _tokens[j] == _pairs[k].tokenB) || (_tokens[i] == _pairs[k].tokenB && _tokens[j] == _pairs[k].tokenA) ) { _pairIndexes[_count++] = IDCAHubSwapHandler.PairIndexes({indexTokenA: i, indexTokenB: j}); } } } } } /// @dev Given a list of tokens to borrow and a list of sorted tokens, it translated the first list into a list of amounts, sorted by the indexed of /// the seconds list. For example, if `toBorrow` are [{ tokenA, 100 }, { tokenC, 200 }, { tokenB, 500 }] and tokens are [ tokenA, tokenB, tokenC], the /// following is returned [100, 500, 200] function _calculateTokensToBorrow(IDCAHub.AmountOfToken[] memory _toBorrow, address[] memory _tokens) private pure returns (uint256[] memory _borrow) { _borrow = new uint256[](_tokens.length); for (uint256 i; i < _toBorrow.length; i++) { uint256 j; while (_tokens[j] != _toBorrow[i].token) j++; _borrow[j] = _toBorrow[i].amount; } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.7 <0.9.0; import '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol'; import '@mean-finance/oracles/solidity/interfaces/ITokenPriceOracle.sol'; import './IDCAPermissionManager.sol'; /** * @title The interface for all state related queries * @notice These methods allow users to read the hubs's current values */ interface IDCAHubParameters { /** * @notice Returns how much will the amount to swap differ from the previous swap. f.e. if the returned value is -100, then the amount to swap will be 100 less than the swap just before it * @dev `tokenA` must be smaller than `tokenB` (tokenA < tokenB) * @param tokenA One of the pair's token * @param tokenB The other of the pair's token * @param swapIntervalMask The byte representation of the swap interval to check * @param swapNumber The swap number to check * @return swapDeltaAToB How much less of token A will the following swap require * @return swapDeltaBToA How much less of token B will the following swap require */ function swapAmountDelta( address tokenA, address tokenB, bytes1 swapIntervalMask, uint32 swapNumber ) external view returns (uint128 swapDeltaAToB, uint128 swapDeltaBToA); /** * @notice Returns the sum of the ratios reported in all swaps executed until the given swap number * @dev `tokenA` must be smaller than `tokenB` (tokenA < tokenB) * @param tokenA One of the pair's token * @param tokenB The other of the pair's token * @param swapIntervalMask The byte representation of the swap interval to check * @param swapNumber The swap number to check * @return accumRatioAToB The sum of all ratios from A to B * @return accumRatioBToA The sum of all ratios from B to A */ function accumRatio( address tokenA, address tokenB, bytes1 swapIntervalMask, uint32 swapNumber ) external view returns (uint256 accumRatioAToB, uint256 accumRatioBToA); /** * @notice Returns swapping information about a specific pair * @dev `tokenA` must be smaller than `tokenB` (tokenA < tokenB) * @param tokenA One of the pair's token * @param tokenB The other of the pair's token * @param swapIntervalMask The byte representation of the swap interval to check * @return performedSwaps How many swaps have been executed * @return nextAmountToSwapAToB How much of token A will be swapped on the next swap * @return lastSwappedAt Timestamp of the last swap * @return nextAmountToSwapBToA How much of token B will be swapped on the next swap */ function swapData( address tokenA, address tokenB, bytes1 swapIntervalMask ) external view returns ( uint32 performedSwaps, uint224 nextAmountToSwapAToB, uint32 lastSwappedAt, uint224 nextAmountToSwapBToA ); /** * @notice Returns the byte representation of the set of actice swap intervals for the given pair * @dev `tokenA` must be smaller than `tokenB` (tokenA < tokenB) * @param tokenA The smaller of the pair's token * @param tokenB The other of the pair's token * @return The byte representation of the set of actice swap intervals */ function activeSwapIntervals(address tokenA, address tokenB) external view returns (bytes1); /** * @notice Returns how much of the hub's token balance belongs to the platform * @param token The token to check * @return The amount that belongs to the platform */ function platformBalance(address token) external view returns (uint256); } /** * @title The interface for all position related matters * @notice These methods allow users to create, modify and terminate their positions */ interface IDCAHubPositionHandler { /// @notice The position of a certain user struct UserPosition { // The token that the user deposited and will be swapped in exchange for "to" IERC20Metadata from; // The token that the user will get in exchange for their "from" tokens in each swap IERC20Metadata to; // How frequently the position's swaps should be executed uint32 swapInterval; // How many swaps were executed since deposit, last modification, or last withdraw uint32 swapsExecuted; // How many "to" tokens can currently be withdrawn uint256 swapped; // How many swaps left the position has to execute uint32 swapsLeft; // How many "from" tokens there are left to swap uint256 remaining; // How many "from" tokens need to be traded in each swap uint120 rate; } /// @notice A list of positions that all have the same `to` token struct PositionSet { // The `to` token address token; // The position ids uint256[] positionIds; } /** * @notice Emitted when a position is terminated * @param user The address of the user that terminated the position * @param recipientUnswapped The address of the user that will receive the unswapped tokens * @param recipientSwapped The address of the user that will receive the swapped tokens * @param positionId The id of the position that was terminated * @param returnedUnswapped How many "from" tokens were returned to the caller * @param returnedSwapped How many "to" tokens were returned to the caller */ event Terminated( address indexed user, address indexed recipientUnswapped, address indexed recipientSwapped, uint256 positionId, uint256 returnedUnswapped, uint256 returnedSwapped ); /** * @notice Emitted when a position is created * @param depositor The address of the user that creates the position * @param owner The address of the user that will own the position * @param positionId The id of the position that was created * @param fromToken The address of the "from" token * @param toToken The address of the "to" token * @param swapInterval How frequently the position's swaps should be executed * @param rate How many "from" tokens need to be traded in each swap * @param startingSwap The number of the swap when the position will be executed for the first time * @param lastSwap The number of the swap when the position will be executed for the last time * @param permissions The permissions defined for the position */ event Deposited( address indexed depositor, address indexed owner, uint256 positionId, address fromToken, address toToken, uint32 swapInterval, uint120 rate, uint32 startingSwap, uint32 lastSwap, IDCAPermissionManager.PermissionSet[] permissions ); /** * @notice Emitted when a position is created and extra data is provided * @param positionId The id of the position that was created * @param data The extra data that was provided */ event Miscellaneous(uint256 positionId, bytes data); /** * @notice Emitted when a user withdraws all swapped tokens from a position * @param withdrawer The address of the user that executed the withdraw * @param recipient The address of the user that will receive the withdrawn tokens * @param positionId The id of the position that was affected * @param token The address of the withdrawn tokens. It's the same as the position's "to" token * @param amount The amount that was withdrawn */ event Withdrew(address indexed withdrawer, address indexed recipient, uint256 positionId, address token, uint256 amount); /** * @notice Emitted when a user withdraws all swapped tokens from many positions * @param withdrawer The address of the user that executed the withdraws * @param recipient The address of the user that will receive the withdrawn tokens * @param positions The positions to withdraw from * @param withdrew The total amount that was withdrawn from each token */ event WithdrewMany(address indexed withdrawer, address indexed recipient, PositionSet[] positions, uint256[] withdrew); /** * @notice Emitted when a position is modified * @param user The address of the user that modified the position * @param positionId The id of the position that was modified * @param rate How many "from" tokens need to be traded in each swap * @param startingSwap The number of the swap when the position will be executed for the first time * @param lastSwap The number of the swap when the position will be executed for the last time */ event Modified(address indexed user, uint256 positionId, uint120 rate, uint32 startingSwap, uint32 lastSwap); /// @notice Thrown when a user tries to create a position with the same `from` & `to` error InvalidToken(); /// @notice Thrown when a user tries to create a position with a swap interval that is not allowed error IntervalNotAllowed(); /// @notice Thrown when a user tries operate on a position that doesn't exist (it might have been already terminated) error InvalidPosition(); /// @notice Thrown when a user tries operate on a position that they don't have access to error UnauthorizedCaller(); /// @notice Thrown when a user tries to create a position with zero swaps error ZeroSwaps(); /// @notice Thrown when a user tries to create a position with zero funds error ZeroAmount(); /// @notice Thrown when a user tries to withdraw a position whose `to` token doesn't match the specified one error PositionDoesNotMatchToken(); /// @notice Thrown when a user tries create or modify a position with an amount too big error AmountTooBig(); /** * @notice Returns the permission manager contract * @return The contract itself */ function permissionManager() external view returns (IDCAPermissionManager); /** * @notice Returns total created positions * @return The total created positions */ function totalCreatedPositions() external view returns (uint256); /** * @notice Returns a user position * @param positionId The id of the position * @return position The position itself */ function userPosition(uint256 positionId) external view returns (UserPosition memory position); /** * @notice Creates a new position * @dev Will revert: * - With ZeroAddress if from, to or owner are zero * - With InvalidToken if from == to * - With ZeroAmount if amount is zero * - With AmountTooBig if amount is too big * - With ZeroSwaps if amountOfSwaps is zero * - With IntervalNotAllowed if swapInterval is not allowed * @param from The address of the "from" token * @param to The address of the "to" token * @param amount How many "from" tokens will be swapped in total * @param amountOfSwaps How many swaps to execute for this position * @param swapInterval How frequently the position's swaps should be executed * @param owner The address of the owner of the position being created * @param permissions Extra permissions to add to the position. Can be empty * @return positionId The id of the created position */ function deposit( address from, address to, uint256 amount, uint32 amountOfSwaps, uint32 swapInterval, address owner, IDCAPermissionManager.PermissionSet[] calldata permissions ) external returns (uint256 positionId); /** * @notice Creates a new position * @dev Will revert: * - With ZeroAddress if from, to or owner are zero * - With InvalidToken if from == to * - With ZeroAmount if amount is zero * - With AmountTooBig if amount is too big * - With ZeroSwaps if amountOfSwaps is zero * - With IntervalNotAllowed if swapInterval is not allowed * @param from The address of the "from" token * @param to The address of the "to" token * @param amount How many "from" tokens will be swapped in total * @param amountOfSwaps How many swaps to execute for this position * @param swapInterval How frequently the position's swaps should be executed * @param owner The address of the owner of the position being created * @param permissions Extra permissions to add to the position. Can be empty * @param miscellaneous Bytes that will be emitted, and associated with the position * @return positionId The id of the created position */ function deposit( address from, address to, uint256 amount, uint32 amountOfSwaps, uint32 swapInterval, address owner, IDCAPermissionManager.PermissionSet[] calldata permissions, bytes calldata miscellaneous ) external returns (uint256 positionId); /** * @notice Withdraws all swapped tokens from a position to a recipient * @dev Will revert: * - With InvalidPosition if positionId is invalid * - With UnauthorizedCaller if the caller doesn't have access to the position * - With ZeroAddress if recipient is zero * @param positionId The position's id * @param recipient The address to withdraw swapped tokens to * @return swapped How much was withdrawn */ function withdrawSwapped(uint256 positionId, address recipient) external returns (uint256 swapped); /** * @notice Withdraws all swapped tokens from multiple positions * @dev Will revert: * - With InvalidPosition if any of the position ids are invalid * - With UnauthorizedCaller if the caller doesn't have access to the position to any of the given positions * - With ZeroAddress if recipient is zero * - With PositionDoesNotMatchToken if any of the positions do not match the token in their position set * @param positions A list positions, grouped by `to` token * @param recipient The address to withdraw swapped tokens to * @return withdrawn How much was withdrawn for each token */ function withdrawSwappedMany(PositionSet[] calldata positions, address recipient) external returns (uint256[] memory withdrawn); /** * @notice Takes the unswapped balance, adds the new deposited funds and modifies the position so that * it is executed in newSwaps swaps * @dev Will revert: * - With InvalidPosition if positionId is invalid * - With UnauthorizedCaller if the caller doesn't have access to the position * - With AmountTooBig if amount is too big * @param positionId The position's id * @param amount Amount of funds to add to the position * @param newSwaps The new amount of swaps */ function increasePosition( uint256 positionId, uint256 amount, uint32 newSwaps ) external; /** * @notice Withdraws the specified amount from the unswapped balance and modifies the position so that * it is executed in newSwaps swaps * @dev Will revert: * - With InvalidPosition if positionId is invalid * - With UnauthorizedCaller if the caller doesn't have access to the position * - With ZeroSwaps if newSwaps is zero and amount is not the total unswapped balance * @param positionId The position's id * @param amount Amount of funds to withdraw from the position * @param newSwaps The new amount of swaps * @param recipient The address to send tokens to */ function reducePosition( uint256 positionId, uint256 amount, uint32 newSwaps, address recipient ) external; /** * @notice Terminates the position and sends all unswapped and swapped balance to the specified recipients * @dev Will revert: * - With InvalidPosition if positionId is invalid * - With UnauthorizedCaller if the caller doesn't have access to the position * - With ZeroAddress if recipientUnswapped or recipientSwapped is zero * @param positionId The position's id * @param recipientUnswapped The address to withdraw unswapped tokens to * @param recipientSwapped The address to withdraw swapped tokens to * @return unswapped The unswapped balance sent to `recipientUnswapped` * @return swapped The swapped balance sent to `recipientSwapped` */ function terminate( uint256 positionId, address recipientUnswapped, address recipientSwapped ) external returns (uint256 unswapped, uint256 swapped); } /** * @title The interface for all swap related matters * @notice These methods allow users to get information about the next swap, and how to execute it */ interface IDCAHubSwapHandler { /// @notice Information about a swap struct SwapInfo { // The tokens involved in the swap TokenInSwap[] tokens; // The pairs involved in the swap PairInSwap[] pairs; } /// @notice Information about a token's role in a swap struct TokenInSwap { // The token's address address token; // How much will be given of this token as a reward uint256 reward; // How much of this token needs to be provided by swapper uint256 toProvide; // How much of this token will be paid to the platform uint256 platformFee; } /// @notice Information about a pair in a swap struct PairInSwap { // The address of one of the tokens address tokenA; // The address of the other token address tokenB; // The total amount of token A swapped in this pair uint256 totalAmountToSwapTokenA; // The total amount of token B swapped in this pair uint256 totalAmountToSwapTokenB; // How much is 1 unit of token A when converted to B uint256 ratioAToB; // How much is 1 unit of token B when converted to A uint256 ratioBToA; // The swap intervals involved in the swap, represented as a byte bytes1 intervalsInSwap; } /// @notice A pair of tokens, represented by their indexes in an array struct PairIndexes { // The index of the token A uint8 indexTokenA; // The index of the token B uint8 indexTokenB; } /** * @notice Emitted when a swap is executed * @param sender The address of the user that initiated the swap * @param rewardRecipient The address that received the reward * @param callbackHandler The address that executed the callback * @param swapInformation All information related to the swap * @param borrowed How much was borrowed * @param fee The swap fee at the moment of the swap */ event Swapped( address indexed sender, address indexed rewardRecipient, address indexed callbackHandler, SwapInfo swapInformation, uint256[] borrowed, uint32 fee ); /// @notice Thrown when pairs indexes are not sorted correctly error InvalidPairs(); /// @notice Thrown when trying to execute a swap, but there is nothing to swap error NoSwapsToExecute(); /** * @notice Returns all information related to the next swap * @dev Will revert with: * - With InvalidTokens if tokens are not sorted, or if there are duplicates * - With InvalidPairs if pairs are not sorted (first by indexTokenA and then indexTokenB), or if indexTokenA >= indexTokenB for any pair * @param tokens The tokens involved in the next swap * @param pairs The pairs that you want to swap. Each element of the list points to the index of the token in the tokens array * @param calculatePrivilegedAvailability Some accounts get privileged availability and can execute swaps before others. This flag provides * the possibility to calculate the next swap information for privileged and non-privileged accounts * @param oracleData Bytes to send to the oracle when executing a quote * @return swapInformation The information about the next swap */ function getNextSwapInfo( address[] calldata tokens, PairIndexes[] calldata pairs, bool calculatePrivilegedAvailability, bytes calldata oracleData ) external view returns (SwapInfo memory swapInformation); /** * @notice Executes a flash swap * @dev Will revert with: * - With InvalidTokens if tokens are not sorted, or if there are duplicates * - With InvalidPairs if pairs are not sorted (first by indexTokenA and then indexTokenB), or if indexTokenA >= indexTokenB for any pair * - With Paused if swaps are paused by protocol * - With NoSwapsToExecute if there are no swaps to execute for the given pairs * - With LiquidityNotReturned if the required tokens were not back during the callback * @param tokens The tokens involved in the next swap * @param pairsToSwap The pairs that you want to swap. Each element of the list points to the index of the token in the tokens array * @param rewardRecipient The address to send the reward to * @param callbackHandler Address to call for callback (and send the borrowed tokens to) * @param borrow How much to borrow of each of the tokens in tokens. The amount must match the position of the token in the tokens array * @param callbackData Bytes to send to the caller during the callback * @param oracleData Bytes to send to the oracle when executing a quote * @return Information about the executed swap */ function swap( address[] calldata tokens, PairIndexes[] calldata pairsToSwap, address rewardRecipient, address callbackHandler, uint256[] calldata borrow, bytes calldata callbackData, bytes calldata oracleData ) external returns (SwapInfo memory); } /** * @title The interface for handling all configuration * @notice This contract will manage configuration that affects all pairs, swappers, etc */ interface IDCAHubConfigHandler { /** * @notice Emitted when a new oracle is set * @param oracle The new oracle contract */ event OracleSet(ITokenPriceOracle oracle); /** * @notice Emitted when a new swap fee is set * @param feeSet The new swap fee */ event SwapFeeSet(uint32 feeSet); /** * @notice Emitted when new swap intervals are allowed * @param swapIntervals The new swap intervals */ event SwapIntervalsAllowed(uint32[] swapIntervals); /** * @notice Emitted when some swap intervals are no longer allowed * @param swapIntervals The swap intervals that are no longer allowed */ event SwapIntervalsForbidden(uint32[] swapIntervals); /** * @notice Emitted when a new platform fee ratio is set * @param platformFeeRatio The new platform fee ratio */ event PlatformFeeRatioSet(uint16 platformFeeRatio); /** * @notice Emitted when allowed states of tokens are updated * @param tokens Array of updated tokens * @param allowed Array of new allow state per token were allowed[i] is the updated state of tokens[i] */ event TokensAllowedUpdated(address[] tokens, bool[] allowed); /// @notice Thrown when trying to interact with an unallowed token error UnallowedToken(); /// @notice Thrown when set allowed tokens input is not valid error InvalidAllowedTokensInput(); /// @notice Thrown when trying to set a fee higher than the maximum allowed error HighFee(); /// @notice Thrown when trying to set a fee that is not multiple of 100 error InvalidFee(); /// @notice Thrown when trying to set a fee ratio that is higher that the maximum allowed error HighPlatformFeeRatio(); /** * @notice Returns the max fee ratio that can be set * @dev Cannot be modified * @return The maximum possible value */ // solhint-disable-next-line func-name-mixedcase function MAX_PLATFORM_FEE_RATIO() external view returns (uint16); /** * @notice Returns the fee charged on swaps * @return swapFee The fee itself */ function swapFee() external view returns (uint32 swapFee); /** * @notice Returns the price oracle contract * @return oracle The contract itself */ function oracle() external view returns (ITokenPriceOracle oracle); /** * @notice Returns how much will the platform take from the fees collected in swaps * @return The current ratio */ function platformFeeRatio() external view returns (uint16); /** * @notice Returns the max fee that can be set for swaps * @dev Cannot be modified * @return maxFee The maximum possible fee */ // solhint-disable-next-line func-name-mixedcase function MAX_FEE() external view returns (uint32 maxFee); /** * @notice Returns a byte that represents allowed swap intervals * @return allowedSwapIntervals The allowed swap intervals */ function allowedSwapIntervals() external view returns (bytes1 allowedSwapIntervals); /** * @notice Returns if a token is currently allowed or not * @return Allowed state of token */ function allowedTokens(address token) external view returns (bool); /** * @notice Returns token's magnitude (10**decimals) * @return Stored magnitude for token */ function tokenMagnitude(address token) external view returns (uint120); /** * @notice Returns whether swaps and deposits are currently paused * @return isPaused Whether swaps and deposits are currently paused */ function paused() external view returns (bool isPaused); /** * @notice Sets a new swap fee * @dev Will revert with HighFee if the fee is higher than the maximum * @dev Will revert with InvalidFee if the fee is not multiple of 100 * @param fee The new swap fee */ function setSwapFee(uint32 fee) external; /** * @notice Sets a new price oracle * @dev Will revert with ZeroAddress if the zero address is passed * @param oracle The new oracle contract */ function setOracle(ITokenPriceOracle oracle) external; /** * @notice Sets a new platform fee ratio * @dev Will revert with HighPlatformFeeRatio if given ratio is too high * @param platformFeeRatio The new ratio */ function setPlatformFeeRatio(uint16 platformFeeRatio) external; /** * @notice Adds new swap intervals to the allowed list * @param swapIntervals The new swap intervals */ function addSwapIntervalsToAllowedList(uint32[] calldata swapIntervals) external; /** * @notice Removes some swap intervals from the allowed list * @param swapIntervals The swap intervals to remove */ function removeSwapIntervalsFromAllowedList(uint32[] calldata swapIntervals) external; /// @notice Pauses all swaps and deposits function pause() external; /// @notice Unpauses all swaps and deposits function unpause() external; } /** * @title The interface for handling platform related actions * @notice This contract will handle all actions that affect the platform in some way */ interface IDCAHubPlatformHandler { /** * @notice Emitted when someone withdraws from the paltform balance * @param sender The address of the user that initiated the withdraw * @param recipient The address that received the withdraw * @param amounts The tokens (and the amount) that were withdrawn */ event WithdrewFromPlatform(address indexed sender, address indexed recipient, IDCAHub.AmountOfToken[] amounts); /** * @notice Withdraws tokens from the platform balance * @param amounts The amounts to withdraw * @param recipient The address that will receive the tokens */ function withdrawFromPlatformBalance(IDCAHub.AmountOfToken[] calldata amounts, address recipient) external; } interface IDCAHub is IDCAHubParameters, IDCAHubConfigHandler, IDCAHubSwapHandler, IDCAHubPositionHandler, IDCAHubPlatformHandler { /// @notice Specifies an amount of a token. For example to determine how much to borrow from certain tokens struct AmountOfToken { // The tokens' address address token; // How much to borrow or withdraw of the specified token uint256 amount; } /// @notice Thrown when one of the parameters is a zero address error ZeroAddress(); /// @notice Thrown when the expected liquidity is not returned in flash swaps error LiquidityNotReturned(); /// @notice Thrown when a list of token pairs is not sorted, or if there are duplicates error InvalidTokens(); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.7 <0.9.0; import '@openzeppelin/contracts/token/ERC721/IERC721.sol'; import '@mean-finance/nft-descriptors/solidity/interfaces/IDCAHubPositionDescriptor.sol'; interface IERC721BasicEnumerable { /** * @notice Count NFTs tracked by this contract * @return A count of valid NFTs tracked by this contract, where each one of * them has an assigned and queryable owner not equal to the zero address */ function totalSupply() external view returns (uint256); } /** * @title The interface for all permission related matters * @notice These methods allow users to set and remove permissions to their positions */ interface IDCAPermissionManager is IERC721, IERC721BasicEnumerable { /// @notice Set of possible permissions enum Permission { INCREASE, REDUCE, WITHDRAW, TERMINATE } /// @notice A set of permissions for a specific operator struct PermissionSet { // The address of the operator address operator; // The permissions given to the overator Permission[] permissions; } /// @notice A collection of permissions sets for a specific position struct PositionPermissions { // The id of the token uint256 tokenId; // The permissions to assign to the position PermissionSet[] permissionSets; } /** * @notice Emitted when permissions for a token are modified * @param tokenId The id of the token * @param permissions The set of permissions that were updated */ event Modified(uint256 tokenId, PermissionSet[] permissions); /** * @notice Emitted when the address for a new descritor is set * @param descriptor The new descriptor contract */ event NFTDescriptorSet(IDCAHubPositionDescriptor descriptor); /// @notice Thrown when a user tries to set the hub, once it was already set error HubAlreadySet(); /// @notice Thrown when a user provides a zero address when they shouldn't error ZeroAddress(); /// @notice Thrown when a user calls a method that can only be executed by the hub error OnlyHubCanExecute(); /// @notice Thrown when a user tries to modify permissions for a token they do not own error NotOwner(); /// @notice Thrown when a user tries to execute a permit with an expired deadline error ExpiredDeadline(); /// @notice Thrown when a user tries to execute a permit with an invalid signature error InvalidSignature(); /** * @notice The permit typehash used in the permit signature * @return The typehash for the permit */ // solhint-disable-next-line func-name-mixedcase function PERMIT_TYPEHASH() external pure returns (bytes32); /** * @notice The permit typehash used in the permission permit signature * @return The typehash for the permission permit */ // solhint-disable-next-line func-name-mixedcase function PERMISSION_PERMIT_TYPEHASH() external pure returns (bytes32); /** * @notice The permit typehash used in the multi permission permit signature * @return The typehash for the multi permission permit */ // solhint-disable-next-line func-name-mixedcase function MULTI_PERMISSION_PERMIT_TYPEHASH() external pure returns (bytes32); /** * @notice The permit typehash used in the permission permit signature * @return The typehash for the permission set */ // solhint-disable-next-line func-name-mixedcase function PERMISSION_SET_TYPEHASH() external pure returns (bytes32); /** * @notice The permit typehash used in the multi permission permit signature * @return The typehash for the position permissions */ // solhint-disable-next-line func-name-mixedcase function POSITION_PERMISSIONS_TYPEHASH() external pure returns (bytes32); /** * @notice The domain separator used in the permit signature * @return The domain seperator used in encoding of permit signature */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); /** * @notice Returns the NFT descriptor contract * @return The contract for the NFT descriptor */ function nftDescriptor() external returns (IDCAHubPositionDescriptor); /** * @notice Returns the address of the DCA Hub * @return The address of the DCA Hub */ function hub() external returns (address); /** * @notice Returns the next nonce to use for a given user * @param user The address of the user * @return nonce The next nonce to use */ function nonces(address user) external returns (uint256 nonce); /** * @notice Returns whether the given address has the permission for the given token * @param id The id of the token to check * @param account The address of the user to check * @param permission The permission to check * @return Whether the user has the permission or not */ function hasPermission( uint256 id, address account, Permission permission ) external view returns (bool); /** * @notice Returns whether the given address has the permissions for the given token * @param id The id of the token to check * @param account The address of the user to check * @param permissions The permissions to check * @return hasPermissions Whether the user has each permission or not */ function hasPermissions( uint256 id, address account, Permission[] calldata permissions ) external view returns (bool[] memory hasPermissions); /** * @notice Sets the address for the hub * @dev Can only be successfully executed once. Once it's set, it can be modified again * Will revert: * - With ZeroAddress if address is zero * - With HubAlreadySet if the hub has already been set * @param hub The address to set for the hub */ function setHub(address hub) external; /** * @notice Mints a new NFT with the given id, and sets the permissions for it * @dev Will revert with OnlyHubCanExecute if the caller is not the hub * @param id The id of the new NFT * @param owner The owner of the new NFT * @param permissions Permissions to set for the new NFT */ function mint( uint256 id, address owner, PermissionSet[] calldata permissions ) external; /** * @notice Burns the NFT with the given id, and clears all permissions * @dev Will revert with OnlyHubCanExecute if the caller is not the hub * @param id The token's id */ function burn(uint256 id) external; /** * @notice Sets new permissions for the given position * @dev Will revert with NotOwner if the caller is not the token's owner. * Operators that are not part of the given permission sets do not see their permissions modified. * In order to remove permissions to an operator, provide an empty list of permissions for them * @param id The token's id * @param permissions A list of permission sets */ function modify(uint256 id, PermissionSet[] calldata permissions) external; /** * @notice Sets new permissions for the given positions * @dev This is basically the same as executing multiple `modify` * @param permissions A list of position permissions to set */ function modifyMany(PositionPermissions[] calldata permissions) external; /** * @notice Approves spending of a specific token ID by spender via signature * @param spender The account that is being approved * @param tokenId The ID of the token that is being approved for spending * @param deadline The deadline timestamp by which the call must be mined for the approve to work * @param v Must produce valid secp256k1 signature from the holder along with `r` and `s` * @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` * @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` */ function permit( address spender, uint256 tokenId, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @notice Sets permissions via signature * @dev This method works similarly to `modifyMany`, but instead of being executed by the owner, it can be set by signature * @param permissions The permissions to set for the different positions * @param deadline The deadline timestamp by which the call must be mined for the approve to work * @param v Must produce valid secp256k1 signature from the holder along with `r` and `s` * @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` * @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` */ function multiPermissionPermit( PositionPermissions[] calldata permissions, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @notice Sets permissions via signature * @dev This method works similarly to `modify`, but instead of being executed by the owner, it can be set my signature * @param permissions The permissions to set * @param tokenId The token's id * @param deadline The deadline timestamp by which the call must be mined for the approve to work * @param v Must produce valid secp256k1 signature from the holder along with `r` and `s` * @param r Must produce valid secp256k1 signature from the holder along with `v` and `s` * @param s Must produce valid secp256k1 signature from the holder along with `r` and `v` */ function permissionPermit( PermissionSet[] calldata permissions, uint256 tokenId, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @notice Sets a new NFT descriptor * @dev Will revert with ZeroAddress if address is zero * @param descriptor The new NFT descriptor contract */ function setNFTDescriptor(IDCAHubPositionDescriptor descriptor) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.7 <0.9.0; import '@mean-finance/dca-v2-core/contracts/interfaces/IDCAHub.sol'; interface ILegacyDCAHub { /// @notice Information about a swap struct SwapInfo { // The tokens involved in the swap TokenInSwap[] tokens; // The pairs involved in the swap PairInSwap[] pairs; } /// @notice Information about a token's role in a swap struct TokenInSwap { // The token's address address token; // How much will be given of this token as a reward uint256 reward; // How much of this token needs to be provided by swapper uint256 toProvide; // How much of this token will be paid to the platform uint256 platformFee; } /// @notice Information about a pair in a swap struct PairInSwap { // The address of one of the tokens address tokenA; // The address of the other token address tokenB; // How much is 1 unit of token A when converted to B uint256 ratioAToB; // How much is 1 unit of token B when converted to A uint256 ratioBToA; // The swap intervals involved in the swap, represented as a byte bytes1 intervalsInSwap; } /** * @notice Returns all information related to the next swap * @dev Will revert with: * - With InvalidTokens if tokens are not sorted, or if there are duplicates * - With InvalidPairs if pairs are not sorted (first by indexTokenA and then indexTokenB), or if indexTokenA >= indexTokenB for any pair * @param tokens The tokens involved in the next swap * @param pairs The pairs that you want to swap. Each element of the list points to the index of the token in the tokens array * @return swapInformation The information about the next swap */ function getNextSwapInfo(address[] calldata tokens, IDCAHub.PairIndexes[] calldata pairs) external view returns (SwapInfo memory swapInformation); /** * @notice Executes a flash swap * @dev Will revert with: * - With InvalidTokens if tokens are not sorted, or if there are duplicates * - With InvalidPairs if pairs are not sorted (first by indexTokenA and then indexTokenB), or if indexTokenA >= indexTokenB for any pair * - With Paused if swaps are paused by protocol * - With NoSwapsToExecute if there are no swaps to execute for the given pairs * - With LiquidityNotReturned if the required tokens were not back during the callback * @param tokens The tokens involved in the next swap * @param pairsToSwap The pairs that you want to swap. Each element of the list points to the index of the token in the tokens array * @param rewardRecipient The address to send the reward to * @param callbackHandler Address to call for callback (and send the borrowed tokens to) * @param borrow How much to borrow of each of the tokens in tokens. The amount must match the position of the token in the tokens array * @param callbackData Bytes to send to the caller during the callback * @return Information about the executed swap */ function swap( address[] calldata tokens, IDCAHub.PairIndexes[] calldata pairsToSwap, address rewardRecipient, address callbackHandler, uint256[] calldata borrow, bytes calldata callbackData ) external returns (SwapInfo memory); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.7 <0.9.0; /// @notice A pair of tokens struct Pair { address tokenA; address tokenB; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /** * @title The interface for an oracle that provides price quotes * @notice These methods allow users to add support for pairs, and then ask for quotes */ interface ITokenPriceOracle { /// @notice Thrown when trying to add support for a pair that cannot be supported error PairCannotBeSupported(address tokenA, address tokenB); /// @notice Thrown when trying to execute a quote with a pair that isn't supported yet error PairNotSupportedYet(address tokenA, address tokenB); /** * @notice Returns whether this oracle can support the given pair of tokens * @dev tokenA and tokenB may be passed in either tokenA/tokenB or tokenB/tokenA order * @param tokenA One of the pair's tokens * @param tokenB The other of the pair's tokens * @return Whether the given pair of tokens can be supported by the oracle */ function canSupportPair(address tokenA, address tokenB) external view returns (bool); /** * @notice Returns whether this oracle is already supporting the given pair of tokens * @dev tokenA and tokenB may be passed in either tokenA/tokenB or tokenB/tokenA order * @param tokenA One of the pair's tokens * @param tokenB The other of the pair's tokens * @return Whether the given pair of tokens is already being supported by the oracle */ function isPairAlreadySupported(address tokenA, address tokenB) external view returns (bool); /** * @notice Returns a quote, based on the given tokens and amount * @dev Will revert if pair isn't supported * @param tokenIn The token that will be provided * @param amountIn The amount that will be provided * @param tokenOut The token we would like to quote * @param data Custom data that the oracle might need to operate * @return amountOut How much `tokenOut` will be returned in exchange for `amountIn` amount of `tokenIn` */ function quote( address tokenIn, uint256 amountIn, address tokenOut, bytes calldata data ) external view returns (uint256 amountOut); /** * @notice Add or reconfigures the support for a given pair. This function will let the oracle take some actions * to configure the pair, in preparation for future quotes. Can be called many times in order to let the oracle * re-configure for a new context * @dev Will revert if pair cannot be supported. tokenA and tokenB may be passed in either tokenA/tokenB or tokenB/tokenA order * @param tokenA One of the pair's tokens * @param tokenB The other of the pair's tokens * @param data Custom data that the oracle might need to operate */ function addOrModifySupportForPair( address tokenA, address tokenB, bytes calldata data ) external; /** * @notice Adds support for a given pair if the oracle didn't support it already. If called for a pair that is already supported, * then nothing will happen. This function will let the oracle take some actions to configure the pair, in preparation * for future quotes * @dev Will revert if pair cannot be supported. tokenA and tokenB may be passed in either tokenA/tokenB or tokenB/tokenA order * @param tokenA One of the pair's tokens * @param tokenB The other of the pair's tokens * @param data Custom data that the oracle might need to operate */ function addSupportForPairIfNeeded( address tokenA, address tokenB, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.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.7.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.7 <0.9.0; /** * @title The interface for generating a description for a position in a DCA Hub * @notice Contracts that implement this interface must return a base64 JSON with the entire description */ interface IDCAHubPositionDescriptor { /** * @notice Generates a positions's description, both the JSON and the image inside * @param hub The address of the DCA Hub * @param positionId The token/position id * @return description The position's description */ function tokenURI(address hub, uint256 positionId) external view returns (string memory description); }
// 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: GPL-2.0-or-later pragma solidity >0.6; /// @title TokenSorting library /// @notice Provides functions to sort tokens easily library TokenSorting { /// @notice Takes two tokens, and returns them sorted /// @param _tokenA One of the tokens /// @param _tokenB The other token /// @return __tokenA The first of the tokens /// @return __tokenB The second of the tokens function sortTokens(address _tokenA, address _tokenB) internal pure returns (address __tokenA, address __tokenB) { (__tokenA, __tokenB) = _tokenA < _tokenB ? (_tokenA, _tokenB) : (_tokenB, _tokenA); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.7 <0.9.0; /// @title Intervals library /// @notice Provides functions to easily convert from swap intervals to their byte representation and viceversa library Intervals { /// @notice Thrown when a user tries convert and invalid interval to a byte representation error InvalidInterval(); /// @notice Thrown when a user tries convert and invalid byte representation to an interval error InvalidMask(); /// @notice Takes a swap interval and returns its byte representation /// @dev Will revert with InvalidInterval if the swap interval is not valid /// @param _swapInterval The swap interval /// @return The interval's byte representation function intervalToMask(uint32 _swapInterval) internal pure returns (bytes1) { if (_swapInterval == 1 minutes) return 0x01; if (_swapInterval == 5 minutes) return 0x02; if (_swapInterval == 15 minutes) return 0x04; if (_swapInterval == 30 minutes) return 0x08; if (_swapInterval == 1 hours) return 0x10; if (_swapInterval == 4 hours) return 0x20; if (_swapInterval == 1 days) return 0x40; if (_swapInterval == 1 weeks) return 0x80; revert InvalidInterval(); } /// @notice Takes a byte representation of a swap interval and returns the swap interval /// @dev Will revert with InvalidMask if the byte representation is not valid /// @param _mask The byte representation /// @return The swap interval function maskToInterval(bytes1 _mask) internal pure returns (uint32) { if (_mask == 0x01) return 1 minutes; if (_mask == 0x02) return 5 minutes; if (_mask == 0x04) return 15 minutes; if (_mask == 0x08) return 30 minutes; if (_mask == 0x10) return 1 hours; if (_mask == 0x20) return 4 hours; if (_mask == 0x40) return 1 days; if (_mask == 0x80) return 1 weeks; revert InvalidMask(); } /// @notice Takes a byte representation of a set of swap intervals and returns which ones are in the set /// @dev Will always return an array of length 8, with zeros at the end if there are less than 8 intervals /// @param _byte The byte representation /// @return _intervals The swap intervals in the set function intervalsInByte(bytes1 _byte) internal pure returns (uint32[] memory _intervals) { _intervals = new uint32[](8); uint8 _index; bytes1 _mask = 0x01; while (_byte >= _mask && _mask > 0) { if (_byte & _mask != 0) { _intervals[_index++] = maskToInterval(_mask); } _mask <<= 1; } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.0; import { IERC165 } from "./interfaces/external/IERC165.sol"; import { ISimulationAdapter } from "./interfaces/ISimulationAdapter.sol"; /** * @title Simulation Adapter * @author Sam Bugs * @notice This contracts adds off-chain simulation capabilities to existing contracts. It works similarly to a * multicall, but the state is not modified in each subcall. */ abstract contract SimulationAdapter is IERC165, ISimulationAdapter { /// @notice An error that contains a simulation's result error SimulatedCall(SimulationResult result); /// @inheritdoc IERC165 function supportsInterface(bytes4 _interfaceId) public view virtual override returns (bool) { return _interfaceId == type(ISimulationAdapter).interfaceId || _interfaceId == type(IERC165).interfaceId; } /// @inheritdoc ISimulationAdapter function simulate(bytes[] calldata _calls) external payable returns (SimulationResult[] memory _results) { _results = new SimulationResult[](_calls.length); for (uint256 i = 0; i < _calls.length; i++) { _results[i] = _simulate(_calls[i]); } return _results; } /** * @notice Executes a simulation and returns the result * @param _call The call to simulate * @return _simulationResult The simulation's result */ function _simulate(bytes calldata _call) internal returns (SimulationResult memory _simulationResult) { (bool _success, bytes memory _result) = // solhint-disable-next-line avoid-low-level-calls address(this).delegatecall(abi.encodeWithSelector(this.simulateAndRevert.selector, _call)); require(!_success, "WTF? Should have failed!"); // Move pointer to ignore selector // solhint-disable-next-line no-inline-assembly assembly { _result := add(_result, 0x04) } (_simulationResult) = abi.decode(_result, (SimulationResult)); } /** * @notice Executes a call agains this contract and reverts with the result * @dev This is meant to be used internally, do not call! * @param _call The call to simulate */ function simulateAndRevert(bytes calldata _call) external payable { uint256 _gasAtStart = gasleft(); // solhint-disable-next-line avoid-low-level-calls (bool _success, bytes memory _result) = address(this).delegatecall(_call); uint256 _gasSpent = _gasAtStart - gasleft(); revert SimulatedCall(SimulationResult({ success: _success, result: _result, gasSpent: _gasSpent })); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.7 <0.9.0; import '../utils/Governable.sol'; import '../SwapAdapter.sol'; abstract contract RevokableWithGovernor is SwapAdapter, Governable { /** * @notice Revokes ERC20 allowances for the given spenders * @dev Can only be called by the governor * @param _revokeActions The spenders and tokens to revoke */ function revokeAllowances(RevokeAction[] calldata _revokeActions) external onlyGovernor { _revokeAllowances(_revokeActions); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.0; import {IPermit2} from '../interfaces/external/IPermit2.sol'; /** * @title Permit2 Transfers Library * @author Sam Bugs * @notice A small library to call Permit2's transfer from methods */ library Permit2Transfers { /** * @notice Executes a transfer from using Permit2 * @param _permit2 The Permit2 contract * @param _token The token to transfer * @param _amount The amount to transfer * @param _nonce The owner's nonce * @param _deadline The signature's expiration deadline * @param _signature The signature that allows the transfer * @param _recipient The address that will receive the funds */ function takeFromCaller( IPermit2 _permit2, address _token, uint256 _amount, uint256 _nonce, uint256 _deadline, bytes calldata _signature, address _recipient ) internal { _permit2.permitTransferFrom( // The permit message. IPermit2.PermitTransferFrom({permitted: IPermit2.TokenPermissions({token: _token, amount: _amount}), nonce: _nonce, deadline: _deadline}), // The transfer recipient and amount. IPermit2.SignatureTransferDetails({to: _recipient, requestedAmount: _amount}), // The owner of the tokens, which must also be // the signer of the message, otherwise this call // will fail. msg.sender, // The packed signature that was the result of signing // the EIP712 hash of `permit`. _signature ); } /** * @notice Executes a batch transfer from using Permit2 * @param _permit2 The Permit2 contract * @param _tokens The amount of tokens to transfer * @param _nonce The owner's nonce * @param _deadline The signature's expiration deadline * @param _signature The signature that allows the transfer * @param _recipient The address that will receive the funds */ function batchTakeFromCaller( IPermit2 _permit2, IPermit2.TokenPermissions[] calldata _tokens, uint256 _nonce, uint256 _deadline, bytes calldata _signature, address _recipient ) internal { if (_tokens.length > 0) { _permit2.permitTransferFrom( // The permit message. IPermit2.PermitBatchTransferFrom({permitted: _tokens, nonce: _nonce, deadline: _deadline}), // The transfer recipients and amounts. _buildTransferDetails(_tokens, _recipient), // The owner of the tokens, which must also be // the signer of the message, otherwise this call // will fail. msg.sender, // The packed signature that was the result of signing // the EIP712 hash of `permit`. _signature ); } } function _buildTransferDetails(IPermit2.TokenPermissions[] calldata _tokens, address _recipient) private pure returns (IPermit2.SignatureTransferDetails[] memory _details) { _details = new IPermit2.SignatureTransferDetails[](_tokens.length); for (uint256 i; i < _details.length; ) { _details[i] = IPermit2.SignatureTransferDetails({to: _recipient, requestedAmount: _tokens[i].amount}); unchecked { ++i; } } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.7 <0.9.0; import '@openzeppelin/contracts/utils/Address.sol'; /** * @dev Adding this contract will enable batching calls. This is basically the same as Open Zeppelin's * Multicall contract, but we have made it payable. It supports both payable and non payable * functions. However, if `msg.value` is not zero, then non payable functions cannot be called. * Any contract that uses this Multicall version should be very careful when using msg.value. * For more context, read: https://github.com/Uniswap/v3-periphery/issues/52 */ abstract contract PayableMulticall { /** * @notice Receives and executes a batch of function calls on this contract. * @param _data A list of different function calls to execute * @return _results The result of executing each of those calls */ function multicall(bytes[] calldata _data) external payable returns (bytes[] memory _results) { _results = new bytes[](_data.length); for (uint256 i = 0; i < _data.length; ) { _results[i] = Address.functionDelegateCall(address(this), _data[i]); unchecked { i++; } } return _results; } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.0; // Minimal Permit2 interface, derived from // https://github.com/Uniswap/permit2/blob/main/src/interfaces/ISignatureTransfer.sol interface IPermit2 { struct TokenPermissions { address token; uint256 amount; } struct PermitTransferFrom { TokenPermissions permitted; uint256 nonce; uint256 deadline; } struct PermitBatchTransferFrom { TokenPermissions[] permitted; uint256 nonce; uint256 deadline; } struct SignatureTransferDetails { address to; uint256 requestedAmount; } // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); function permitTransferFrom( PermitTransferFrom calldata permit, SignatureTransferDetails calldata transferDetails, address owner, bytes calldata signature ) external; function permitTransferFrom( PermitBatchTransferFrom memory permit, SignatureTransferDetails[] calldata transferDetails, address owner, bytes calldata signature ) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.0; interface ISimulationAdapter { /// @notice A simulation's result struct SimulationResult { bool success; bytes result; uint256 gasSpent; } /** * @notice Executes individual simulations against this contract but doesn't modify the state when doing so * @dev This function is meant to be used for off-chain simulation and should not be called on-chain * @param calls The calls to simulate * @return results Each simulation result */ function simulate(bytes[] calldata calls) external payable returns (SimulationResult[] memory results); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.0; 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: GPL-2.0-or-later pragma solidity >=0.8.7 <0.9.0; import '../../interfaces/utils/IGovernable.sol'; /** * @notice This contract is meant to be used in other contracts. By using this contract, * a specific address will be given a "governor" role, which basically will be able to * control certains aspects of the contract. There are other contracts that do the same, * but this contract forces a new governor to accept the role before it's transferred. * This is a basically a safety measure to prevent losing access to the contract. */ abstract contract Governable is IGovernable { /// @inheritdoc IGovernable address public governor; /// @inheritdoc IGovernable address public pendingGovernor; constructor(address _governor) { if (_governor == address(0)) revert GovernorIsZeroAddress(); governor = _governor; } /// @inheritdoc IGovernable function isGovernor(address _account) public view returns (bool) { return _account == governor; } /// @inheritdoc IGovernable function isPendingGovernor(address _account) public view returns (bool) { return _account == pendingGovernor; } /// @inheritdoc IGovernable function setPendingGovernor(address _pendingGovernor) external onlyGovernor { pendingGovernor = _pendingGovernor; emit PendingGovernorSet(_pendingGovernor); } /// @inheritdoc IGovernable function acceptPendingGovernor() external onlyPendingGovernor { governor = pendingGovernor; pendingGovernor = address(0); emit PendingGovernorAccepted(); } modifier onlyGovernor() { if (!isGovernor(msg.sender)) revert OnlyGovernor(); _; } modifier onlyPendingGovernor() { if (!isPendingGovernor(msg.sender)) revert OnlyPendingGovernor(); _; } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.7 <0.9.0; import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; import '@openzeppelin/contracts/utils/Address.sol'; import '../interfaces/ISwapAdapter.sol'; abstract contract SwapAdapter is ISwapAdapter { using SafeERC20 for IERC20; using Address for address; using Address for address payable; /// @inheritdoc ISwapAdapter address public constant PROTOCOL_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; /// @inheritdoc ISwapAdapter ISwapperRegistry public immutable SWAPPER_REGISTRY; constructor(address _swapperRegistry) { if (_swapperRegistry == address(0)) revert ZeroAddress(); SWAPPER_REGISTRY = ISwapperRegistry(_swapperRegistry); } receive() external payable {} /** * @notice Takes the given amount of tokens from the caller * @param _token The token to check * @param _amount The amount to take */ function _takeFromMsgSender(IERC20 _token, uint256 _amount) internal virtual { _token.safeTransferFrom(msg.sender, address(this), _amount); } /** * @notice Checks if the given spender has enough allowance, and approves the max amount * if it doesn't * @param _token The token to check * @param _spender The spender to check * @param _minAllowance The min allowance. If the spender has over this amount, then no extra approve is needed */ function _maxApproveSpenderIfNeeded( IERC20 _token, address _spender, bool _alreadyValidatedSpender, uint256 _minAllowance ) internal virtual { if (_spender != address(0)) { uint256 _allowance = _token.allowance(address(this), _spender); if (_allowance < _minAllowance) { if (!_alreadyValidatedSpender && !SWAPPER_REGISTRY.isValidAllowanceTarget(_spender)) { revert InvalidAllowanceTarget(_spender); } if (_allowance > 0) { _token.approve(_spender, 0); // We do this because some tokens (like USDT) fail if we don't } _token.approve(_spender, type(uint256).max); } } } /** * @notice Executes a swap for the given swapper * @param _swapper The actual swapper * @param _swapData The swap execution data */ function _executeSwap( address _swapper, bytes calldata _swapData, uint256 _value ) internal virtual { _swapper.functionCallWithValue(_swapData, _value); } /** * @notice Checks if the contract has any balance of the given token, and if it does, * it sends it to the given recipient * @param _token The token to check * @param _recipient The recipient of the token balance */ function _sendBalanceOnContractToRecipient(address _token, address _recipient) internal virtual { uint256 _balance = _token == PROTOCOL_TOKEN ? address(this).balance : IERC20(_token).balanceOf(address(this)); if (_balance > 0) { _sendToRecipient(_token, _balance, _recipient); } } /** * @notice Transfers the given amount of tokens from the contract to the recipient * @param _token The token to check * @param _amount The amount to send * @param _recipient The recipient */ function _sendToRecipient( address _token, uint256 _amount, address _recipient ) internal virtual { if (_recipient == address(0)) _recipient = msg.sender; if (_token == PROTOCOL_TOKEN) { payable(_recipient).sendValue(_amount); } else { IERC20(_token).safeTransfer(_recipient, _amount); } } /** * @notice Checks if given swapper is allowlisted, and fails if it isn't * @param _swapper The swapper to check */ function _assertSwapperIsAllowlisted(address _swapper) internal view { if (!SWAPPER_REGISTRY.isSwapperAllowlisted(_swapper)) revert SwapperNotAllowlisted(_swapper); } /** * @notice Revokes ERC20 allowances for the given spenders * @dev If exposed, then it should be permissioned * @param _revokeActions The spenders and tokens to revoke */ function _revokeAllowances(RevokeAction[] calldata _revokeActions) internal virtual { for (uint256 i = 0; i < _revokeActions.length; ) { RevokeAction memory _action = _revokeActions[i]; for (uint256 j = 0; j < _action.tokens.length; ) { _action.tokens[j].approve(_action.spender, 0); unchecked { j++; } } unchecked { i++; } } } modifier onlyAllowlisted(address _swapper) { _assertSwapperIsAllowlisted(_swapper); _; } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.7 <0.9.0; /** * @title A contract that manages a "governor" role */ interface IGovernable { /// @notice Thrown when trying to set the zero address as governor error GovernorIsZeroAddress(); /// @notice Thrown when trying to execute an action that only the governor an execute error OnlyGovernor(); /// @notice Thrown when trying to execute an action that only the pending governor an execute error OnlyPendingGovernor(); /** * @notice Emitted when a new pending governor is set * @param newPendingGovernor The new pending governor */ event PendingGovernorSet(address newPendingGovernor); /** * @notice Emitted when the pending governor accepts the role and becomes the governor */ event PendingGovernorAccepted(); /** * @notice Returns the address of the governor * @return The address of the governor */ function governor() external view returns (address); /** * @notice Returns the address of the pending governor * @return The address of the pending governor */ function pendingGovernor() external view returns (address); /** * @notice Returns whether the given account is the current governor * @param account The account to check * @return Whether it is the current governor or not */ function isGovernor(address account) external view returns (bool); /** * @notice Returns whether the given account is the pending governor * @param account The account to check * @return Whether it is the pending governor or not */ function isPendingGovernor(address account) external view returns (bool); /** * @notice Sets a new pending governor * @dev Only the current governor can execute this action * @param pendingGovernor The new pending governor */ function setPendingGovernor(address pendingGovernor) external; /** * @notice Sets the pending governor as the governor * @dev Only the pending governor can execute this action */ function acceptPendingGovernor() external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.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 * ==== * * [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://diligence.consensys.net/posts/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.5.11/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 functionCall(target, data, "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"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(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) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(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) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason 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 { // 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: GPL-2.0-or-later pragma solidity >=0.8.7 <0.9.0; import '@openzeppelin/contracts/interfaces/IERC20.sol'; import './ISwapperRegistry.sol'; /** * @notice This abstract contract will give contracts that implement it swapping capabilities. It will * take a swapper and a swap's data, and if the swapper is valid, it will execute the swap */ interface ISwapAdapter { /// @notice Describes how the allowance should be revoked for the given spender struct RevokeAction { address spender; IERC20[] tokens; } /// @notice Thrown when one of the parameters is a zero address error ZeroAddress(); /** * @notice Thrown when trying to execute a swap with a swapper that is not allowlisted * @param swapper The swapper that was not allowlisted */ error SwapperNotAllowlisted(address swapper); /// @notice Thrown when the allowance target is not allowed by the swapper registry error InvalidAllowanceTarget(address spender); /** * @notice Returns the address of the swapper registry * @dev Cannot be modified * @return The address of the swapper registry */ function SWAPPER_REGISTRY() external view returns (ISwapperRegistry); /** * @notice Returns the address of the protocol token * @dev Cannot be modified * @return The address of the protocol token; */ function PROTOCOL_TOKEN() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-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; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } 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)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } 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"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } 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"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.7 <0.9.0; /** * @notice This contract will act as a registry to allowlist swappers. Different contracts from the Mean * ecosystem will ask this contract if an address is a valid swapper or not * In some cases, swappers have supplementary allowance targets that need ERC20 approvals. We * will also track those here */ interface ISwapperRegistry { /// @notice Thrown when one of the parameters is a zero address error ZeroAddress(); /// @notice Thrown when trying to remove an account from the swappers list, when it wasn't there before error AccountIsNotSwapper(address account); /** * @notice Thrown when trying to remove an account from the supplementary allowance target list, * when it wasn't there before */ error AccountIsNotSupplementaryAllowanceTarget(address account); /// @notice Thrown when trying to mark an account as swapper or allowance target, but it already has a role assigned error AccountAlreadyHasRole(address account); /** * @notice Emitted when swappers are removed from the allowlist * @param swappers The swappers that were removed */ event RemoveSwappersFromAllowlist(address[] swappers); /** * @notice Emitted when new swappers are added to the allowlist * @param swappers The swappers that were added */ event AllowedSwappers(address[] swappers); /** * @notice Emitted when new supplementary allowance targets are are added to the allowlist * @param allowanceTargets The allowance targets that were added */ event AllowedSupplementaryAllowanceTargets(address[] allowanceTargets); /** * @notice Emitted when supplementary allowance targets are removed from the allowlist * @param allowanceTargets The allowance targets that were removed */ event RemovedAllowanceTargetsFromAllowlist(address[] allowanceTargets); /** * @notice Returns whether a given account is allowlisted for swaps * @param account The address to check * @return Whether it is allowlisted for swaps */ function isSwapperAllowlisted(address account) external view returns (bool); /** * @notice Returns whether a given account is a valid allowance target. This would be true * if the account is either a swapper, or a supplementary allowance target * @param account The address to check * @return Whether it is a valid allowance target */ function isValidAllowanceTarget(address account) external view returns (bool); /** * @notice Adds a list of swappers to the allowlist * @dev Can only be called by users with the admin role * @param swappers The list of swappers to add */ function allowSwappers(address[] calldata swappers) external; /** * @notice Removes the given swappers from the allowlist * @dev Can only be called by users with the admin role * @param swappers The list of swappers to remove */ function removeSwappersFromAllowlist(address[] calldata swappers) external; /** * @notice Adds a list of supplementary allowance targets to the allowlist * @dev Can only be called by users with the admin role * @param allowanceTargets The list of allowance targets to add */ function allowSupplementaryAllowanceTargets(address[] calldata allowanceTargets) external; /** * @notice Removes the given allowance targets from the allowlist * @dev Can only be called by users with the admin role * @param allowanceTargets The list of allowance targets to remove */ function removeSupplementaryAllowanceTargetsFromAllowlist(address[] calldata allowanceTargets) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-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); }
{ "optimizer": { "enabled": true, "runs": 9999 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_swapper","type":"address"},{"internalType":"address","name":"_allowanceTarget","type":"address"},{"internalType":"address","name":"_governor","type":"address"},{"internalType":"contract IPermit2","name":"_permit2","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"GovernorIsZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"InvalidAllowanceTarget","type":"error"},{"inputs":[],"name":"InvalidMask","type":"error"},{"inputs":[],"name":"OnlyGovernor","type":"error"},{"inputs":[],"name":"OnlyPendingGovernor","type":"error"},{"inputs":[{"internalType":"uint256","name":"received","type":"uint256"},{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"ReceivedTooLittleTokenOut","type":"error"},{"inputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"result","type":"bytes"},{"internalType":"uint256","name":"gasSpent","type":"uint256"}],"internalType":"struct ISimulationAdapter.SimulationResult","name":"result","type":"tuple"}],"name":"SimulatedCall","type":"error"},{"inputs":[{"internalType":"address","name":"swapper","type":"address"}],"name":"SwapperNotAllowlisted","type":"error"},{"inputs":[],"name":"UnauthorizedCaller","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[],"name":"PendingGovernorAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newPendingGovernor","type":"address"}],"name":"PendingGovernorSet","type":"event"},{"inputs":[],"name":"PERMIT2","outputs":[{"internalType":"contract IPermit2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROTOCOL_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SWAPPER_REGISTRY","outputs":[{"internalType":"contract ISwapperRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptPendingGovernor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"allowanceTarget","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IPermit2.TokenPermissions[]","name":"_tokens","type":"tuple[]"},{"internalType":"uint256","name":"_nonce","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"bytes","name":"_signature","type":"bytes"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"batchPermitTakeFromCaller","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IDCAHub","name":"_hub","type":"address"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint32","name":"_amountOfSwaps","type":"uint32"},{"internalType":"uint32","name":"_swapInterval","type":"uint32"},{"internalType":"address","name":"_owner","type":"address"},{"components":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"enum IDCAPermissionManager.Permission[]","name":"permissions","type":"uint8[]"}],"internalType":"struct IDCAPermissionManager.PermissionSet[]","name":"_permissions","type":"tuple[]"},{"internalType":"bytes","name":"_miscellaneous","type":"bytes"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"_positionId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IDCAHub","name":"_hub","type":"address"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint32","name":"_amountOfSwaps","type":"uint32"},{"internalType":"uint32","name":"_swapInterval","type":"uint32"},{"internalType":"address","name":"_owner","type":"address"},{"components":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"enum IDCAPermissionManager.Permission[]","name":"permissions","type":"uint8[]"}],"internalType":"struct IDCAPermissionManager.PermissionSet[]","name":"_permissions","type":"tuple[]"},{"internalType":"bytes","name":"_miscellaneous","type":"bytes"}],"name":"depositWithBalanceOnContract","outputs":[{"internalType":"uint256","name":"_positionId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IDCAHub","name":"_hub","type":"address"},{"components":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"}],"internalType":"struct Pair[]","name":"_pairs","type":"tuple[]"},{"internalType":"bool","name":"_calculatePrivilegedAvailability","type":"bool"},{"internalType":"bytes","name":"_oracleData","type":"bytes"}],"name":"getNextSwapInfo","outputs":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"reward","type":"uint256"},{"internalType":"uint256","name":"toProvide","type":"uint256"},{"internalType":"uint256","name":"platformFee","type":"uint256"}],"internalType":"struct IDCAHubSwapHandler.TokenInSwap[]","name":"tokens","type":"tuple[]"},{"components":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"totalAmountToSwapTokenA","type":"uint256"},{"internalType":"uint256","name":"totalAmountToSwapTokenB","type":"uint256"},{"internalType":"uint256","name":"ratioAToB","type":"uint256"},{"internalType":"uint256","name":"ratioBToA","type":"uint256"},{"internalType":"bytes1","name":"intervalsInSwap","type":"bytes1"}],"internalType":"struct IDCAHubSwapHandler.PairInSwap[]","name":"pairs","type":"tuple[]"}],"internalType":"struct IDCAHubSwapHandler.SwapInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IDCAHub","name":"_hub","type":"address"},{"internalType":"uint256","name":"_positionId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint32","name":"_newSwaps","type":"uint32"}],"name":"increasePosition","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IDCAHub","name":"_hub","type":"address"},{"internalType":"uint256","name":"_positionId","type":"uint256"},{"internalType":"uint32","name":"_newSwaps","type":"uint32"}],"name":"increasePositionWithBalanceOnContract","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isGovernor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isPendingGovernor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ILegacyDCAHub","name":"_hub","type":"address"},{"components":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"}],"internalType":"struct Pair[]","name":"_pairs","type":"tuple[]"}],"name":"legacyGetNextSwapInfo","outputs":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"reward","type":"uint256"},{"internalType":"uint256","name":"toProvide","type":"uint256"},{"internalType":"uint256","name":"platformFee","type":"uint256"}],"internalType":"struct ILegacyDCAHub.TokenInSwap[]","name":"tokens","type":"tuple[]"},{"components":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"ratioAToB","type":"uint256"},{"internalType":"uint256","name":"ratioBToA","type":"uint256"},{"internalType":"bytes1","name":"intervalsInSwap","type":"bytes1"}],"internalType":"struct ILegacyDCAHub.PairInSwap[]","name":"pairs","type":"tuple[]"}],"internalType":"struct ILegacyDCAHub.SwapInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IDCAPermissionManager","name":"_permissionManager","type":"address"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"components":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"enum IDCAPermissionManager.Permission[]","name":"permissions","type":"uint8[]"}],"internalType":"struct IDCAPermissionManager.PermissionSet[]","name":"permissionSets","type":"tuple[]"}],"internalType":"struct IDCAPermissionManager.PositionPermissions[]","name":"_permissions","type":"tuple[]"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"multiPermissionPermit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"_data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"_results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"pendingGovernor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IDCAPermissionManager","name":"_permissionManager","type":"address"},{"components":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"enum IDCAPermissionManager.Permission[]","name":"permissions","type":"uint8[]"}],"internalType":"struct IDCAPermissionManager.PermissionSet[]","name":"_permissions","type":"tuple[]"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"permissionPermit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_nonce","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"bytes","name":"_signature","type":"bytes"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"permitTakeFromCaller","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IDCAHub","name":"_hub","type":"address"},{"internalType":"uint256","name":"_positionId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint32","name":"_newSwaps","type":"uint32"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"reducePosition","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"}],"internalType":"struct ISwapAdapter.RevokeAction[]","name":"_revokeActions","type":"tuple[]"}],"name":"revokeAllowances","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_allowanceToken","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"bytes","name":"_swapData","type":"bytes"},{"internalType":"address","name":"_tokenOut","type":"address"},{"internalType":"uint256","name":"_minTokenOut","type":"uint256"}],"name":"runSwap","outputs":[{"internalType":"uint256","name":"_amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IDCAHub","name":"_hub","type":"address"},{"components":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"}],"internalType":"struct Pair[]","name":"_pairs","type":"tuple[]"},{"internalType":"bool","name":"_calculatePrivilegedAvailability","type":"bool"}],"name":"secondsUntilNextSwap","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"sendBalanceOnContractToRecipient","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"sendToRecipient","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_pendingGovernor","type":"address"}],"name":"setPendingGovernor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newSwapper","type":"address"},{"internalType":"address","name":"_newAllowanceTarget","type":"address"}],"name":"setSwapper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"_calls","type":"bytes[]"}],"name":"simulate","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"result","type":"bytes"},{"internalType":"uint256","name":"gasSpent","type":"uint256"}],"internalType":"struct ISimulationAdapter.SimulationResult[]","name":"_results","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_call","type":"bytes"}],"name":"simulateAndRevert","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"takeFromCaller","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IDCAHub","name":"_hub","type":"address"},{"internalType":"uint256","name":"_positionId","type":"uint256"},{"internalType":"address","name":"_recipientUnswapped","type":"address"},{"internalType":"address","name":"_recipientSwapped","type":"address"}],"name":"terminate","outputs":[{"internalType":"uint256","name":"_unswapped","type":"uint256"},{"internalType":"uint256","name":"_swapped","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IDCAHub","name":"_hub","type":"address"},{"internalType":"uint256","name":"_positionId","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"withdrawSwapped","outputs":[{"internalType":"uint256","name":"_swapped","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IDCAHub","name":"_hub","type":"address"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256[]","name":"positionIds","type":"uint256[]"}],"internalType":"struct IDCAHubPositionHandler.PositionSet[]","name":"_positions","type":"tuple[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"withdrawSwappedMany","outputs":[{"internalType":"uint256[]","name":"_withdrawn","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60c06040523480156200001157600080fd5b5060405162005ca538038062005ca58339810160408190526200003491620000cf565b600160805283838383816001600160a01b038116620000665760405163e6250e3360e01b815260040160405180910390fd5b600080546001600160a01b03199081166001600160a01b0393841617909155600280548216968316969096179095556003805490951693811693909317909355501660a052506200013792505050565b6001600160a01b0381168114620000cc57600080fd5b50565b60008060008060808587031215620000e657600080fd5b8451620000f381620000b6565b60208601519094506200010681620000b6565b60408601519093506200011981620000b6565b60608601519092506200012c81620000b6565b939692955090935050565b60805160a051615b3a6200016b600039600081816104cb015281816112120152611548015260006105520152615b3a6000f3fe6080604052600436106102535760003560e01c806362b850c711610138578063d9a673ef116100b0578063e43581b81161007f578063effca70511610064578063effca7051461066b578063f235757f1461068b578063fa0c9555146106ab57600080fd5b8063e43581b81461061c578063e9c040711461064b57600080fd5b8063d9a673ef146105a7578063db8266de146105ba578063df08aed5146105cd578063e3056a34146105fc57600080fd5b8063910cab1111610107578063b3b48afb116100ec578063b3b48afb14610540578063bb2871a514610574578063bcbef2061461059457600080fd5b8063910cab1114610500578063ac9650d81461052057600080fd5b806362b850c71461049357806362dd9af3146104a65780636afdd850146104b957806389352328146104ed57600080fd5b806337b0c09d116101cb578063484b35771161019a578063585cc6a51161017f578063585cc6a5146104305780635d25d6eb146104585780635f963dcf1461046b57600080fd5b8063484b3577146103d65780635684c2751461040357600080fd5b806337b0c09d1461037d5780633a79d674146103905780633ed242b4146103a357806340c5710c146103c357600080fd5b80631f66925c116102225780632b3297f9116102075780632b3297f91461032a578063340b532f1461034a57806335ac2a501461035d57600080fd5b80631f66925c146102f65780631f8b479d1461031757600080fd5b806301ffc9a71461025f57806305ce20d6146102945780630c340a24146102a957806313f6986d146102e157600080fd5b3661025a57005b600080fd5b34801561026b57600080fd5b5061027f61027a3660046138b7565b6106be565b60405190151581526020015b60405180910390f35b6102a76102a2366004613933565b610757565b005b3480156102b557600080fd5b506000546102c9906001600160a01b031681565b6040516001600160a01b03909116815260200161028b565b3480156102ed57600080fd5b506102a761088b565b610309610304366004613988565b610937565b60405190815260200161028b565b6102a7610325366004613a27565b6109df565b34801561033657600080fd5b506002546102c9906001600160a01b031681565b6102a7610358366004613ab3565b610a30565b61037061036b366004613aec565b610a3e565b60405161028b9190613b49565b6102a761038b366004613988565b610b8d565b6102a761039e366004613988565b610ba7565b6103b66103b1366004613b8d565b610bb2565b60405161028b9190613c54565b6102a76103d1366004613cd4565b610c95565b3480156103e257600080fd5b506103f66103f1366004613da0565b610e18565b60405161028b9190613e37565b34801561040f57600080fd5b5061042361041e366004613f66565b610edf565b60405161028b9190613fbb565b34801561043c57600080fd5b506102c973eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6103096104663660046140c7565b610f9d565b61047e610479366004614143565b611150565b6040805192835260208301919091520161028b565b6102a76104a136600461418b565b611205565b6102a76104b4366004614222565b611247565b3480156104c557600080fd5b506102c97f000000000000000000000000000000000000000000000000000000000000000081565b6103096104fb3660046142a5565b6112d1565b34801561050c57600080fd5b506003546102c9906001600160a01b031681565b61053361052e366004613b8d565b61137c565b60405161028b9190614386565b34801561054c57600080fd5b506102c97f000000000000000000000000000000000000000000000000000000000000000081565b34801561058057600080fd5b5061037061058f3660046143f9565b61145f565b6102a76105a2366004614456565b611475565b6102a76105b536600461448c565b61153b565b6102a76105c8366004614503565b611574565b3480156105d957600080fd5b5061027f6105e8366004614562565b6001546001600160a01b0391821691161490565b34801561060857600080fd5b506001546102c9906001600160a01b031681565b34801561062857600080fd5b5061027f610637366004614562565b6000546001600160a01b0391821691161490565b34801561065757600080fd5b506102a7610666366004613b8d565b6115e4565b34801561067757600080fd5b506102a7610686366004613ab3565b611632565b34801561069757600080fd5b506102a76106a6366004614562565b6116bc565b6103096106b936600461457f565b61176c565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f3ed242b400000000000000000000000000000000000000000000000000000000148061075157507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b838360006107668383836118b3565b6040517f5b6fd01d000000000000000000000000000000000000000000000000000000008152600481018790526000906001600160a01b03891690635b6fd01d9060240161010060405180830381865afa1580156107c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ec9190614794565b5190506107fa8189886119bb565b6040517fded700a6000000000000000000000000000000000000000000000000000000008152600481018890526024810187905263ffffffff861660448201526001600160a01b0389169063ded700a6906064015b600060405180830381600087803b15801561086957600080fd5b505af115801561087d573d6000803e3d6000fd5b505050505050505050505050565b6001546001600160a01b031633146108cf576040517f9ba0305d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018054600080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081166001600160a01b0384161782559091169091556040517fdc57ca23c46d823853915ed5a090ca0ee9db5eb6a46f5c58e1c9158de861fd769190a1565b6000838360026109488383836118b3565b6040517f17621890000000000000000000000000000000000000000000000000000000008152600481018790526001600160a01b0386811660248301528816906317621890906044016020604051808303816000875af11580156109b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109d49190614850565b979650505050505050565b6040517f4faa38830000000000000000000000000000000000000000000000000000000081526001600160a01b03891690634faa38839061084f908a908a908a908a908a908a908a90600401614a0a565b610a3a8282611b7b565b5050565b606060005b83811015610af3576000858583818110610a5f57610a5f614a4b565b9050602002810190610a719190614a7a565b610a7f906020810190614ab8565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201829052509394505050505b8151811015610ae957610ae188838381518110610ad257610ad2614a4b565b602002602001015160026118b3565b600101610ab3565b5050600101610a43565b506040517f480b37960000000000000000000000000000000000000000000000000000000081526001600160a01b0386169063480b379690610b3d90879087908790600401614b20565b6000604051808303816000875af1158015610b5c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b849190810190614c38565b95945050505050565b610ba26001600160a01b038416338385611c3c565b505050565b610ba2838383611ced565b60608167ffffffffffffffff811115610bcd57610bcd61466d565b604051908082528060200260200182016040528015610c2457816020015b610c11604051806060016040528060001515815260200160608152602001600081525090565b815260200190600190039081610beb5790505b50905060005b82811015610c8e57610c5e848483818110610c4757610c47614a4b565b9050602002810190610c599190614cc3565b611d55565b828281518110610c7057610c70614a4b565b60200260200101819052508080610c8690614d57565b915050610c2a565b5092915050565b82826000610ca48383836118b3565b6040517f5b6fd01d000000000000000000000000000000000000000000000000000000008152600481018690526000906001600160a01b03881690635b6fd01d9060240161010060405180830381865afa158015610d06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2a9190614794565b516040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610d8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610db29190614850565b9050610dbf8289836119bb565b6040517fded700a6000000000000000000000000000000000000000000000000000000008152600481018890526024810182905263ffffffff871660448201526001600160a01b0389169063ded700a69060640161084f565b6040805180820190915260608082526020820152600080610e398888611ed5565b6040517f4997cdc300000000000000000000000000000000000000000000000000000000815291935091506001600160a01b038a1690634997cdc390610e8b90859085908b908b908b90600401614e22565b600060405180830381865afa158015610ea8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ed09190810190614f52565b925050505b9695505050505050565b6040805180820190915260608082526020820152600080610f008585611ed5565b6040517fd2d95b2d00000000000000000000000000000000000000000000000000000000815291935091506001600160a01b0387169063d2d95b2d90610f4c90859085906004016150bd565b600060405180830381865afa158015610f69573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f9191908101906150e2565b925050505b9392505050565b60006001600160a01b03871615611041576003546040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015260001960248201529088169063095ea7b3906044016020604051808303816000875af115801561101b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103f9190615226565b505b600254611059906001600160a01b0316868689611f36565b6001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611103576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156110da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110fe9190614850565b611105565b475b905081811015610ed5576040517f763dfca000000000000000000000000000000000000000000000000000000000815260048101829052602481018390526044015b60405180910390fd5b600080858560036111628383836118b3565b6040517f72ada4c5000000000000000000000000000000000000000000000000000000008152600481018990526001600160a01b03888116602483015287811660448301528a16906372ada4c59060640160408051808303816000875af11580156111d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111f59190615243565b909a909950975050505050505050565b61123e6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001688888888888888611f81565b50505050505050565b6040517f3dff05870000000000000000000000000000000000000000000000000000000081526001600160a01b03881690633dff05879061129690899089908990899089908990600401615267565b600060405180830381600087803b1580156112b057600080fd5b505af11580156112c4573d6000803e3d6000fd5b5050505050505050505050565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009081906001600160a01b038c16906370a0823190602401602060405180830381865afa158015611333573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113579190614850565b905061136c8c8c8c848d8d8d8d8d8d8d61176c565b9c9b505050505050505050505050565b60608167ffffffffffffffff8111156113975761139761466d565b6040519080825280602002602001820160405280156113ca57816020015b60608152602001906001900390816113b55790505b50905060005b82811015610c8e5761143a308585848181106113ee576113ee614a4b565b90506020028101906114009190614cc3565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061203b92505050565b82828151811061144c5761144c614a4b565b60209081029190910101526001016113d0565b6060610b8485858585612060565b949350505050565b60005a9050600080306001600160a01b031685856040516114979291906153f6565b600060405180830381855af49150503d80600081146114d2576040519150601f19603f3d011682016040523d82523d6000602084013e6114d7565b606091505b509150915060005a6114e99085615406565b905060405180606001604052808415158152602001838152602001828152506040517f493703af0000000000000000000000000000000000000000000000000000000081526004016111479190615419565b61123e6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001688888888888888612146565b848460016115838383836118b3565b6040517ff1accf39000000000000000000000000000000000000000000000000000000008152600481018890526024810187905263ffffffff861660448201526001600160a01b03858116606483015289169063f1accf399060840161084f565b6000546001600160a01b03163314611628576040517fe0a8b92000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a3a82826121cf565b6000546001600160a01b03163314611676576040517fe0a8b92000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280546001600160a01b039384167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161790915560038054929093169116179055565b6000546001600160a01b03163314611700576040517fe0a8b92000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f56bddfa0cee9697cebddf9acd7f23dc6583663b05e007b877056d05017994def9060200160405180910390a150565b60006117798b8d8b6119bb565b81611819576040517f6b29e1bd0000000000000000000000000000000000000000000000000000000081526001600160a01b038d1690636b29e1bd906117d1908e908e908e908e908e908e908e908e9060040161542c565b6020604051808303816000875af11580156117f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118149190614850565b61136c565b6040517fb2b513c10000000000000000000000000000000000000000000000000000000081526001600160a01b038d169063b2b513c190611870908e908e908e908e908e908e908e908e908e908e9060040161548b565b6020604051808303816000875af115801561188f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061136c9190614850565b826001600160a01b031663cc7a20496040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119159190615502565b6001600160a01b031663823abfd98333846040518463ffffffff1660e01b81526004016119449392919061551f565b602060405180830381865afa158015611961573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119859190615226565b610ba2576040517f5c427cd900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015611a24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a489190614850565b905081811015611b75578015611ae6576040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301526000602483015285169063095ea7b3906044016020604051808303816000875af1158015611ac0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ae49190615226565b505b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152600019602483015285169063095ea7b3906044016020604051808303816000875af1158015611b4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b739190615226565b505b50505050565b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611c27576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015611bfe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c229190614850565b611c29565b475b90508015610ba257610ba2838284611ced565b6040516001600160a01b0380851660248301528316604482015260648101829052611b759085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526122dd565b6001600160a01b038116611cfe5750335b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611d4157610ba26001600160a01b038216836123dc565b610ba26001600160a01b0384168284612529565b611d7b604051806060016040528060001515815260200160608152602001600081525090565b600080306001600160a01b031663bcbef20660e01b8686604051602401611da3929190615542565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051611e0e9190615556565b600060405180830381855af49150503d8060008114611e49576040519150601f19603f3d011682016040523d82523d6000602084013e611e4e565b606091505b50915091508115611ebb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f5754463f2053686f756c642068617665206661696c65642100000000000000006044820152606401611147565b60048101905080806020019051810190610b849190615568565b606080611f2a84846000604051908082528060200260200182016040528015611f2457816020015b6040805180820190915260008082526020820152815260200190600190039081611efd5790505b50612572565b50909590945092505050565b611b7383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050506001600160a01b038716919050836125f7565b851561203157876001600160a01b031663edd9444b60405180606001604052808a8a808060200260200160405190810160405280939291908181526020016000905b82821015611fef57611fe06040830286013681900381019061563e565b81526020019060010190611fc3565b505050505081526020018881526020018781525061200e8a8a8661261d565b3387876040518663ffffffff1660e01b815260040161084f9594939291906156c5565b5050505050505050565b6060610f968383604051806060016040528060278152602001615ade602791396126f2565b60608267ffffffffffffffff81111561207b5761207b61466d565b6040519080825280602002602001820160405280156120a4578160200160208202803683370190505b50905060005b8381101561213d5761210e868686848181106120c8576120c8614a4b565b6120de9260206040909202019081019150614562565b8787858181106120f0576120f0614a4b565b90506040020160200160208101906121089190614562565b866127f6565b82828151811061212057612120614a4b565b60209081029190910101528061213581614d57565b9150506120aa565b50949350505050565b6040805160a0810182526001600160a01b0389811660608301908152608083018a9052825260208083018990528284018890528351808501855285831681529081018a905292517f30f28b7a000000000000000000000000000000000000000000000000000000008152908b16926330f28b7a9261084f9290919033908990899060040161577c565b60005b81811015610ba25760008383838181106121ee576121ee614a4b565b90506020028101906122009190614a7a565b612209906157f5565b905060005b8160200151518110156122d3578160200151818151811061223157612231614a4b565b602090810291909101015182516040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201526000602482015291169063095ea7b3906044016020604051808303816000875af11580156122a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ca9190615226565b5060010161220e565b50506001016121d2565b6000612332826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612b6d9092919063ffffffff16565b805190915015610ba257808060200190518101906123509190615226565b610ba2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401611147565b80471015612446576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401611147565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612493576040519150601f19603f3d011682016040523d82523d6000602084013e612498565b606091505b5050905080610ba2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401611147565b6040516001600160a01b038316602482015260448101829052610ba29084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611c89565b60608060606125d38686808060200260200160405190810160405280939291908181526020016000905b828210156125c8576125b9604083028601368190038101906158ad565b8152602001906001019061259c565b505050505085612b7c565b92506125e0868685613060565b91506125ec84846132fb565b905093509350939050565b606061146d848484604051806060016040528060298152602001615ab560299139613401565b60608267ffffffffffffffff8111156126385761263861466d565b60405190808252806020026020018201604052801561267d57816020015b60408051808201909152600080825260208201528152602001906001900390816126565790505b50905060005b81518110156126ea576040518060400160405280846001600160a01b031681526020018686848181106126b8576126b8614a4b565b905060400201602001358152508282815181106126d7576126d7614a4b565b6020908102919091010152600101612683565b509392505050565b60606001600160a01b0384163b61278b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e747261637400000000000000000000000000000000000000000000000000006064820152608401611147565b600080856001600160a01b0316856040516127a69190615556565b600060405180830381855af49150503d80600081146127e1576040519150601f19603f3d011682016040523d82523d6000602084013e6127e6565b606091505b5091509150610f9182828661356e565b600080600061280586866135c1565b6040517f582cf84b0000000000000000000000000000000000000000000000000000000081526001600160a01b038084166004830152808316602483015292945090925060009189169063582cf84b90604401602060405180830381865afa158015612875573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061289991906158ee565b90507f010000000000000000000000000000000000000000000000000000000000000060005b7fff000000000000000000000000000000000000000000000000000000000000008083169084161080159061291557507fff00000000000000000000000000000000000000000000000000000000000000821615155b15612b5c57817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168284167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603612b2e576040517f808ba8e00000000000000000000000000000000000000000000000000000000081526001600160a01b038a8116600483015289811660248301527fff000000000000000000000000000000000000000000000000000000000000008416604483015260009182918291908e169063808ba8e090606401608060405180830381865afa1580156129fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a229190615935565b935093509350506000612a34866135f2565b9050600081612a43818661598d565b612a4e9060016159d7565b612a5891906159f4565b63ffffffff1690508b612a8357612a7060038361598d565b612a809063ffffffff1682615a20565b90505b6000857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161180612ace57506000837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16115b15612b0757428111612aec57859a505050505050505050505061146d565b612af64282615406565b9a505050505050505050505061146d565b42811115612b28578515612b1b5785612b25565b612b254282615406565b95505b50505050505b6001827effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916901b91506128bf565b506000199998505050505050505050565b606061146d8484600085613401565b6060600080835185516002612b919190615a33565b612b9b9190615a20565b67ffffffffffffffff811115612bb357612bb361466d565b604051908082528060200260200182016040528015612bdc578160200160208202803683370190505b50905060005b8551811015612db65760008060005b8581108015612c075750828015612c055750815b155b15612cdc5782158015612c615750888481518110612c2757612c27614a4b565b6020026020010151600001516001600160a01b0316858281518110612c4e57612c4e614a4b565b60200260200101516001600160a01b0316145b15612c6b57600192505b81158015612cc05750888481518110612c8657612c86614a4b565b6020026020010151602001516001600160a01b0316858281518110612cad57612cad614a4b565b60200260200101516001600160a01b0316145b15612cca57600191505b80612cd481614d57565b915050612bf1565b5081612d3f57878381518110612cf457612cf4614a4b565b602002602001015160000151848680612d0c90614d57565b975081518110612d1e57612d1e614a4b565b60200260200101906001600160a01b031690816001600160a01b0316815250505b80612da157878381518110612d5657612d56614a4b565b602002602001015160200151848680612d6e90614d57565b975081518110612d8057612d80614a4b565b60200260200101906001600160a01b031690816001600160a01b0316815250505b50508080612dae90614d57565b915050612be2565b5060005b8451811015612eb5576000805b8481108015612dd4575081155b15612e3f57868381518110612deb57612deb614a4b565b6020026020010151600001516001600160a01b0316848281518110612e1257612e12614a4b565b60200260200101516001600160a01b031603612e2d57600191505b80612e3781614d57565b915050612dc7565b5080612ea257858281518110612e5757612e57614a4b565b602002602001015160000151838580612e6f90614d57565b965081518110612e8157612e81614a4b565b60200260200101906001600160a01b031690816001600160a01b0316815250505b5080612ead81614d57565b915050612dba565b508167ffffffffffffffff811115612ecf57612ecf61466d565b604051908082528060200260200182016040528015612ef8578160200160208202803683370190505b50925060005b82811015613057576000828281518110612f1a57612f1a614a4b565b6020026020010151905060005b816001600160a01b0316868281518110612f4357612f43614a4b565b60200260200101516001600160a01b0316108015612f8d575060006001600160a01b0316868281518110612f7957612f79614a4b565b60200260200101516001600160a01b031614155b15612fa45780612f9c81614d57565b915050612f27565b825b8181111561300e5786612fba600183615406565b81518110612fca57612fca614a4b565b6020026020010151878281518110612fe457612fe4614a4b565b6001600160a01b03909216602092830291909101909101528061300681615a52565b915050612fa6565b508186828151811061302257613022614a4b565b60200260200101906001600160a01b031690816001600160a01b0316815250505050808061304f90614d57565b915050612efe565b50505092915050565b60608267ffffffffffffffff81111561307b5761307b61466d565b6040519080825280602002602001820160405280156130c057816020015b60408051808201909152600080825260208201528152602001906001900390816130995790505b5090506000805b83518160ff1610156132f25760006130e0826001615a69565b90505b84518160ff1610156132df5760005b868110156132cc5787878281811061310c5761310c614a4b565b6131229260206040909202019081019150614562565b6001600160a01b0316868460ff168151811061314057613140614a4b565b60200260200101516001600160a01b03161480156131b4575087878281811061316b5761316b614a4b565b90506040020160200160208101906131839190614562565b6001600160a01b0316868360ff16815181106131a1576131a1614a4b565b60200260200101516001600160a01b0316145b8061327457508787828181106131cc576131cc614a4b565b90506040020160200160208101906131e49190614562565b6001600160a01b0316868460ff168151811061320257613202614a4b565b60200260200101516001600160a01b0316148015613274575087878281811061322d5761322d614a4b565b6132439260206040909202019081019150614562565b6001600160a01b0316868360ff168151811061326157613261614a4b565b60200260200101516001600160a01b0316145b156132ba576040805180820190915260ff808516825283166020820152858561329c81614d57565b9650815181106132ae576132ae614a4b565b60200260200101819052505b806132c481614d57565b9150506130f2565b50806132d781615a82565b9150506130e3565b50806132ea81615a82565b9150506130c7565b50509392505050565b6060815167ffffffffffffffff8111156133175761331761466d565b604051908082528060200260200182016040528015613340578160200160208202803683370190505b50905060005b8351811015610c8e5760005b84828151811061336457613364614a4b565b6020026020010151600001516001600160a01b031684828151811061338b5761338b614a4b565b60200260200101516001600160a01b0316146133b357806133ab81614d57565b915050613352565b8482815181106133c5576133c5614a4b565b6020026020010151602001518382815181106133e3576133e3614a4b565b602090810291909101015250806133f981614d57565b915050613346565b606082471015613493576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401611147565b6001600160a01b0385163b613504576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611147565b600080866001600160a01b031685876040516135209190615556565b60006040518083038185875af1925050503d806000811461355d576040519150601f19603f3d011682016040523d82523d6000602084013e613562565b606091505b50915091506109d48282865b6060831561357d575081610f96565b82511561358d5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111479190615aa1565b600080826001600160a01b0316846001600160a01b0316106135e45782846135e7565b83835b909590945092505050565b60007fff0000000000000000000000000000000000000000000000000000000000000082167f0100000000000000000000000000000000000000000000000000000000000000036136455750603c919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f020000000000000000000000000000000000000000000000000000000000000003613697575061012c919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f0400000000000000000000000000000000000000000000000000000000000000036136e95750610384919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f08000000000000000000000000000000000000000000000000000000000000000361373b5750610708919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f10000000000000000000000000000000000000000000000000000000000000000361378d5750610e10919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f2000000000000000000000000000000000000000000000000000000000000000036137df5750613840919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f400000000000000000000000000000000000000000000000000000000000000003613832575062015180919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f800000000000000000000000000000000000000000000000000000000000000003613885575062093a80919050565b6040517fbf3cad0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000602082840312156138c957600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610f9657600080fd5b6001600160a01b038116811461390e57600080fd5b50565b63ffffffff8116811461390e57600080fd5b803561392e81613911565b919050565b6000806000806080858703121561394957600080fd5b8435613954816138f9565b93506020850135925060408501359150606085013561397281613911565b939692955090935050565b803561392e816138f9565b60008060006060848603121561399d57600080fd5b83356139a8816138f9565b92506020840135915060408401356139bf816138f9565b809150509250925092565b60008083601f8401126139dc57600080fd5b50813567ffffffffffffffff8111156139f457600080fd5b6020830191508360208260051b8501011115613a0f57600080fd5b9250929050565b803560ff8116811461392e57600080fd5b60008060008060008060008060e0898b031215613a4357600080fd5b8835613a4e816138f9565b9750602089013567ffffffffffffffff811115613a6a57600080fd5b613a768b828c016139ca565b9098509650506040890135945060608901359350613a9660808a01613a16565b925060a0890135915060c089013590509295985092959890939650565b60008060408385031215613ac657600080fd5b8235613ad1816138f9565b91506020830135613ae1816138f9565b809150509250929050565b60008060008060608587031215613b0257600080fd5b8435613b0d816138f9565b9350602085013567ffffffffffffffff811115613b2957600080fd5b613b35878288016139ca565b9094509250506040850135613972816138f9565b6020808252825182820181905260009190848201906040850190845b81811015613b8157835183529284019291840191600101613b65565b50909695505050505050565b60008060208385031215613ba057600080fd5b823567ffffffffffffffff811115613bb757600080fd5b613bc3858286016139ca565b90969095509350505050565b60005b83811015613bea578181015183820152602001613bd2565b50506000910152565b60008151808452613c0b816020860160208601613bcf565b601f01601f19169290920160200192915050565b8051151582526000602082015160606020850152613c406060850182613bf3565b604093840151949093019390935250919050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613cc7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613cb5858351613c1f565b94509285019290850190600101613c7b565b5092979650505050505050565b600080600060608486031215613ce957600080fd5b8335613cf4816138f9565b92506020840135915060408401356139bf81613911565b60008083601f840112613d1d57600080fd5b50813567ffffffffffffffff811115613d3557600080fd5b6020830191508360208260061b8501011115613a0f57600080fd5b801515811461390e57600080fd5b60008083601f840112613d7057600080fd5b50813567ffffffffffffffff811115613d8857600080fd5b602083019150836020828501011115613a0f57600080fd5b60008060008060008060808789031215613db957600080fd5b8635613dc4816138f9565b9550602087013567ffffffffffffffff80821115613de157600080fd5b613ded8a838b01613d0b565b909750955060408901359150613e0282613d50565b90935060608801359080821115613e1857600080fd5b50613e2589828a01613d5e565b979a9699509497509295939492505050565b600060208083526060808401855160408085880152828251808552608094508489019150868401935060005b81811015613eb057613ea08386516001600160a01b0381511682526020810151602083015260408101516040830152606081015160608301525050565b9387019391850191600101613e63565b505088860151888203601f1901838a0152805180835290870193506000918701905b80831015613f5857845180516001600160a01b03908116845289820151168984015284810151858401528781015188840152868101518784015260a0808201519084015260c0908101517fff000000000000000000000000000000000000000000000000000000000000001690830152938701936001929092019160e090910190613ed2565b509998505050505050505050565b600080600060408486031215613f7b57600080fd5b8335613f86816138f9565b9250602084013567ffffffffffffffff811115613fa257600080fd5b613fae86828701613d0b565b9497909650939450505050565b600060208083526060808401855160408085880152828251808552608094508489019150868401935060005b81811015614034576140248386516001600160a01b0381511682526020810151602083015260408101516040830152606081015160608301525050565b9387019391850191600101613fe7565b505088860151888203601f1901838a0152805180835290870193506000918701905b80831015613f5857845180516001600160a01b039081168452898201511689840152848101518584015287810151888401528601517fff000000000000000000000000000000000000000000000000000000000000001686830152938701936001929092019160a090910190614056565b60008060008060008060a087890312156140e057600080fd5b86356140eb816138f9565b955060208701359450604087013567ffffffffffffffff81111561410e57600080fd5b61411a89828a01613d5e565b909550935050606087013561412e816138f9565b80925050608087013590509295509295509295565b6000806000806080858703121561415957600080fd5b8435614164816138f9565b935060208501359250604085013561417b816138f9565b91506060850135613972816138f9565b600080600080600080600060a0888a0312156141a657600080fd5b873567ffffffffffffffff808211156141be57600080fd5b6141ca8b838c01613d0b565b909950975060208a0135965060408a0135955060608a01359150808211156141f157600080fd5b506141fe8a828b01613d5e565b9094509250506080880135614212816138f9565b8091505092959891949750929550565b600080600080600080600060c0888a03121561423d57600080fd5b8735614248816138f9565b9650602088013567ffffffffffffffff81111561426457600080fd5b6142708a828b016139ca565b9097509550506040880135935061428960608901613a16565b92506080880135915060a0880135905092959891949750929550565b6000806000806000806000806000806101008b8d0312156142c557600080fd5b8a356142d0816138f9565b995060208b01356142e0816138f9565b985060408b01356142f0816138f9565b975060608b013561430081613911565b965060808b013561431081613911565b955061431e60a08c0161397d565b945060c08b013567ffffffffffffffff8082111561433b57600080fd5b6143478e838f016139ca565b909650945060e08d013591508082111561436057600080fd5b5061436d8d828e01613d5e565b915080935050809150509295989b9194979a5092959850565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613cc7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08886030184526143e7858351613bf3565b945092850192908501906001016143ad565b6000806000806060858703121561440f57600080fd5b843561441a816138f9565b9350602085013567ffffffffffffffff81111561443657600080fd5b61444287828801613d0b565b909450925050604085013561397281613d50565b6000806020838503121561446957600080fd5b823567ffffffffffffffff81111561448057600080fd5b613bc385828601613d5e565b600080600080600080600060c0888a0312156144a757600080fd5b87356144b2816138f9565b9650602088013595506040880135945060608801359350608088013567ffffffffffffffff8111156144e357600080fd5b6144ef8a828b01613d5e565b90945092505060a0880135614212816138f9565b600080600080600060a0868803121561451b57600080fd5b8535614526816138f9565b94506020860135935060408601359250606086013561454481613911565b91506080860135614554816138f9565b809150509295509295909350565b60006020828403121561457457600080fd5b8135610f96816138f9565b60008060008060008060008060008060006101208c8e0312156145a157600080fd5b6145ab8c356138f9565b8b359a506145bc60208d01356138f9565b60208c013599506145cf60408d0161397d565b985060608c013597506145e460808d01613923565b96506145f260a08d01613923565b955061460060c08d0161397d565b945067ffffffffffffffff8060e08e0135111561461c57600080fd5b61462c8e60e08f01358f016139ca565b90955093506101008d013581101561464357600080fd5b506146558d6101008e01358e01613d5e565b81935080925050509295989b509295989b9093969950565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156146bf576146bf61466d565b60405290565b60405160e0810167ffffffffffffffff811182821017156146bf576146bf61466d565b60405160a0810167ffffffffffffffff811182821017156146bf576146bf61466d565b6040516060810167ffffffffffffffff811182821017156146bf576146bf61466d565b604051601f8201601f1916810167ffffffffffffffff811182821017156147575761475761466d565b604052919050565b805161392e816138f9565b805161392e81613911565b80516effffffffffffffffffffffffffffff8116811461392e57600080fd5b60006101008083850312156147a857600080fd5b6040519081019067ffffffffffffffff821181831017156147cb576147cb61466d565b81604052835191506147dc826138f9565b8181526147eb6020850161475f565b60208201526147fc6040850161476a565b604082015261480d6060850161476a565b60608201526080840151608082015261482860a0850161476a565b60a082015260c084015160c082015261484360e08501614775565b60e0820152949350505050565b60006020828403121561486257600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261489e57600080fd5b830160208101925035905067ffffffffffffffff8111156148be57600080fd5b8060051b3603821315613a0f57600080fd5b60048110614907577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc183360301811261493f57600080fd5b90910192915050565b81835260006020808501808196508560051b810191508460005b878110156149fd578284038952614979828861490b565b60408086018235614989816138f9565b6001600160a01b031687526149a083890184614869565b888a019390935290829052909150606086019060005b838110156149e8578135600481106149cd57600080fd5b6149d784826148d0565b5091880191908801906001016149b6565b50509986019994505090840190600101614962565b5091979650505050505050565b60c081526000614a1e60c08301898b614948565b602083019790975250604081019490945260ff929092166060840152608083015260a09091015292915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112614aae57600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614aed57600080fd5b83018035915067ffffffffffffffff821115614b0857600080fd5b6020019150600581901b3603821315613a0f57600080fd5b60408082528181018490526000906060808401600587811b860183018986805b8b811015614bf6577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08a8503018652614b79838e61490b565b8035614b84816138f9565b6001600160a01b031685526020614b9d82820183614869565b92508a82880152828b8801527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115614bd5578485fd5b91871b918281888c0137509687019694018701939290920191600101614b40565b5050506001600160a01b0388166020880152945061146d9350505050565b600067ffffffffffffffff821115614c2e57614c2e61466d565b5060051b60200190565b60006020808385031215614c4b57600080fd5b825167ffffffffffffffff811115614c6257600080fd5b8301601f81018513614c7357600080fd5b8051614c86614c8182614c14565b61472e565b81815260059190911b82018301908381019087831115614ca557600080fd5b928401925b828410156109d457835182529284019290840190614caa565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614cf857600080fd5b83018035915067ffffffffffffffff821115614d1357600080fd5b602001915036819003821315613a0f57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006000198203614d6a57614d6a614d28565b5060010190565b600081518084526020808501945080840160005b83811015614daa5781516001600160a01b031687529582019590820190600101614d85565b509495945050505050565b600081518084526020808501945080840160005b83811015614daa578151805160ff908116895290840151168388015260409096019590820190600101614dc9565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b608081526000614e356080830188614d71565b8281036020840152614e478188614db5565b905085151560408401528281036060840152614e64818587614df7565b98975050505050505050565b6000614e7e614c8184614c14565b8381529050602080820190600785901b840186811115614e9d57600080fd5b845b81811015614f1757608080828a031215614eb95760008081fd5b604080519182019167ffffffffffffffff83118184101715614edd57614edd61466d565b918152825191614eec836138f9565b9182528285015185830152808301519082015260608083015190820152845292820192608001614e9f565b505050509392505050565b80517fff000000000000000000000000000000000000000000000000000000000000008116811461392e57600080fd5b60006020808385031215614f6557600080fd5b825167ffffffffffffffff80821115614f7d57600080fd5b81850191506040808388031215614f9357600080fd5b614f9b61469c565b835183811115614faa57600080fd5b8401601f81018913614fbb57600080fd5b614fc9898251888401614e70565b8252508484015183811115614fdd57600080fd5b80850194505087601f850112614ff257600080fd5b83519250615002614c8184614c14565b83815260e0938402850186019386820191908a86111561502157600080fd5b958701955b858710156150aa5780878c03121561503e5760008081fd5b6150466146c5565b8751615051816138f9565b815287890151615060816138f9565b818a01528786015186820152606080890151908201526080808901519082015260a0808901519082015260c0615097818a01614f22565b9082015283529586019591870191615026565b5095820195909552979650505050505050565b6040815260006150d06040830185614d71565b8281036020840152610b848185614db5565b600060208083850312156150f557600080fd5b825167ffffffffffffffff8082111561510d57600080fd5b8185019150604080838803121561512357600080fd5b61512b61469c565b83518381111561513a57600080fd5b8401601f8101891361514b57600080fd5b615159898251888401614e70565b825250848401518381111561516d57600080fd5b80850194505087601f85011261518257600080fd5b83519250615192614c8184614c14565b83815260a0938402850186019386820191908a8611156151b157600080fd5b958701955b858710156150aa5780878c0312156151ce5760008081fd5b6151d66146e8565b87516151e1816138f9565b8152878901516151f0816138f9565b818a01528786015186820152606080890151908201526080615213818a01614f22565b90820152835295860195918701916151b6565b60006020828403121561523857600080fd5b8151610f9681613d50565b6000806040838503121561525657600080fd5b505080516020909101519092909150565b60a080825281018690526000600560c08084019089831b8501018a845b8b8110156153c6577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff408784030184526152bd828e61490b565b60408085018235865260206152d481850185614869565b88830185905292839052919350606091828801858b1b890184018260005b888110156153ac577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08c840301845261532b828661490b565b8884018135615339816138f9565b6001600160a01b0316855261535082890183614869565b868a018c90529182905290915060008986015b838210156153975782356004811061537a57600080fd5b61538482826148d0565b5091890191600191909101908901615363565b968901969550505091860191506001016152f2565b505099830199985050509490940193505050600101615284565b50506020850189905260ff8816604086015292506153e2915050565b606082019390935260800152949350505050565b8183823760009101908152919050565b8181038181111561075157610751614d28565b602081526000610f966020830184613c1f565b60006001600160a01b03808b168352808a16602084015288604084015263ffffffff808916606085015280881660808501525080861660a08401525060e060c083015261547d60e083018486614948565b9a9950505050505050505050565b6001600160a01b038b811682528a81166020830152604082018a905263ffffffff898116606084015288166080830152861660a082015261010060c082018190526000906154dc8382018789614948565b905082810360e08401526154f1818587614df7565b9d9c50505050505050505050505050565b60006020828403121561551457600080fd5b8151610f96816138f9565b8381526001600160a01b03831660208201526060810161146d60408301846148d0565b60208152600061146d602083018486614df7565b60008251614aae818460208701613bcf565b6000602080838503121561557b57600080fd5b825167ffffffffffffffff8082111561559357600080fd5b90840190606082870312156155a757600080fd5b6155af61470b565b82516155ba81613d50565b815282840151828111156155cd57600080fd5b8301601f810188136155de57600080fd5b8051838111156155f0576155f061466d565b61560286601f19601f8401160161472e565b9350808452888682840101111561561857600080fd5b61562781878601888501613bcf565b505092830152604090810151908201529392505050565b60006040828403121561565057600080fd5b61565861469c565b8235615663816138f9565b81526020928301359281019290925250919050565b600081518084526020808501945080840160005b83811015614daa576156b287835180516001600160a01b03168252602090810151910152565b604096909601959082019060010161568c565b60808152600060e082018751606060808501528181518084526101008601915060209350838301925060005b8181101561572a5761571783855180516001600160a01b03168252602090810151910152565b92840192604092909201916001016156f1565b5050828a015160a086015260408a015160c086015284810383860152615750818a615678565b9250505061576960408401876001600160a01b03169052565b8281036060840152614e64818587614df7565b600061010061579f83895180516001600160a01b03168252602090810151910152565b60208801516040840152604088015160608401526157d3608084018880516001600160a01b03168252602090810151910152565b6001600160a01b03861660c08401528060e0840152614e648184018587614df7565b60006040823603121561580757600080fd5b61580f61469c565b823561581a816138f9565b815260208381013567ffffffffffffffff81111561583757600080fd5b840136601f82011261584857600080fd5b8035615856614c8182614c14565b81815260059190911b8201830190838101903683111561587557600080fd5b928401925b8284101561589c57833561588d816138f9565b8252928401929084019061587a565b938501939093525091949350505050565b6000604082840312156158bf57600080fd5b6158c761469c565b82356158d2816138f9565b815260208301356158e2816138f9565b60208201529392505050565b60006020828403121561590057600080fd5b610f9682614f22565b80517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461392e57600080fd5b6000806000806080858703121561594b57600080fd5b845161595681613911565b935061596460208601615909565b9250604085015161597481613911565b915061598260608601615909565b905092959194509250565b600063ffffffff808416806159cb577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b92169190910492915050565b63ffffffff818116838216019080821115610c8e57610c8e614d28565b600063ffffffff80831681851681830481118215151615615a1757615a17614d28565b02949350505050565b8082018082111561075157610751614d28565b6000816000190483118215151615615a4d57615a4d614d28565b500290565b600081615a6157615a61614d28565b506000190190565b60ff818116838216019081111561075157610751614d28565b600060ff821660ff8103615a9857615a98614d28565b60010192915050565b602081526000610f966020830184613bf356fe416464726573733a206c6f772d6c6576656c2063616c6c20776974682076616c7565206661696c6564416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122085524a8f6f575000dc99a0891112cb7b3cc50f61e7374973f298e53a09b025c564736f6c63430008100033000000000000000000000000227f070ed2afd8744ef059959b8a8b8e8edc6c0f000000000000000000000000227f070ed2afd8744ef059959b8a8b8e8edc6c0f000000000000000000000000ec864be26084ba3bbf3caacf8f6961a9263319c4000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3
Deployed Bytecode
0x6080604052600436106102535760003560e01c806362b850c711610138578063d9a673ef116100b0578063e43581b81161007f578063effca70511610064578063effca7051461066b578063f235757f1461068b578063fa0c9555146106ab57600080fd5b8063e43581b81461061c578063e9c040711461064b57600080fd5b8063d9a673ef146105a7578063db8266de146105ba578063df08aed5146105cd578063e3056a34146105fc57600080fd5b8063910cab1111610107578063b3b48afb116100ec578063b3b48afb14610540578063bb2871a514610574578063bcbef2061461059457600080fd5b8063910cab1114610500578063ac9650d81461052057600080fd5b806362b850c71461049357806362dd9af3146104a65780636afdd850146104b957806389352328146104ed57600080fd5b806337b0c09d116101cb578063484b35771161019a578063585cc6a51161017f578063585cc6a5146104305780635d25d6eb146104585780635f963dcf1461046b57600080fd5b8063484b3577146103d65780635684c2751461040357600080fd5b806337b0c09d1461037d5780633a79d674146103905780633ed242b4146103a357806340c5710c146103c357600080fd5b80631f66925c116102225780632b3297f9116102075780632b3297f91461032a578063340b532f1461034a57806335ac2a501461035d57600080fd5b80631f66925c146102f65780631f8b479d1461031757600080fd5b806301ffc9a71461025f57806305ce20d6146102945780630c340a24146102a957806313f6986d146102e157600080fd5b3661025a57005b600080fd5b34801561026b57600080fd5b5061027f61027a3660046138b7565b6106be565b60405190151581526020015b60405180910390f35b6102a76102a2366004613933565b610757565b005b3480156102b557600080fd5b506000546102c9906001600160a01b031681565b6040516001600160a01b03909116815260200161028b565b3480156102ed57600080fd5b506102a761088b565b610309610304366004613988565b610937565b60405190815260200161028b565b6102a7610325366004613a27565b6109df565b34801561033657600080fd5b506002546102c9906001600160a01b031681565b6102a7610358366004613ab3565b610a30565b61037061036b366004613aec565b610a3e565b60405161028b9190613b49565b6102a761038b366004613988565b610b8d565b6102a761039e366004613988565b610ba7565b6103b66103b1366004613b8d565b610bb2565b60405161028b9190613c54565b6102a76103d1366004613cd4565b610c95565b3480156103e257600080fd5b506103f66103f1366004613da0565b610e18565b60405161028b9190613e37565b34801561040f57600080fd5b5061042361041e366004613f66565b610edf565b60405161028b9190613fbb565b34801561043c57600080fd5b506102c973eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6103096104663660046140c7565b610f9d565b61047e610479366004614143565b611150565b6040805192835260208301919091520161028b565b6102a76104a136600461418b565b611205565b6102a76104b4366004614222565b611247565b3480156104c557600080fd5b506102c97f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba381565b6103096104fb3660046142a5565b6112d1565b34801561050c57600080fd5b506003546102c9906001600160a01b031681565b61053361052e366004613b8d565b61137c565b60405161028b9190614386565b34801561054c57600080fd5b506102c97f000000000000000000000000000000000000000000000000000000000000000181565b34801561058057600080fd5b5061037061058f3660046143f9565b61145f565b6102a76105a2366004614456565b611475565b6102a76105b536600461448c565b61153b565b6102a76105c8366004614503565b611574565b3480156105d957600080fd5b5061027f6105e8366004614562565b6001546001600160a01b0391821691161490565b34801561060857600080fd5b506001546102c9906001600160a01b031681565b34801561062857600080fd5b5061027f610637366004614562565b6000546001600160a01b0391821691161490565b34801561065757600080fd5b506102a7610666366004613b8d565b6115e4565b34801561067757600080fd5b506102a7610686366004613ab3565b611632565b34801561069757600080fd5b506102a76106a6366004614562565b6116bc565b6103096106b936600461457f565b61176c565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f3ed242b400000000000000000000000000000000000000000000000000000000148061075157507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b838360006107668383836118b3565b6040517f5b6fd01d000000000000000000000000000000000000000000000000000000008152600481018790526000906001600160a01b03891690635b6fd01d9060240161010060405180830381865afa1580156107c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ec9190614794565b5190506107fa8189886119bb565b6040517fded700a6000000000000000000000000000000000000000000000000000000008152600481018890526024810187905263ffffffff861660448201526001600160a01b0389169063ded700a6906064015b600060405180830381600087803b15801561086957600080fd5b505af115801561087d573d6000803e3d6000fd5b505050505050505050505050565b6001546001600160a01b031633146108cf576040517f9ba0305d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018054600080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081166001600160a01b0384161782559091169091556040517fdc57ca23c46d823853915ed5a090ca0ee9db5eb6a46f5c58e1c9158de861fd769190a1565b6000838360026109488383836118b3565b6040517f17621890000000000000000000000000000000000000000000000000000000008152600481018790526001600160a01b0386811660248301528816906317621890906044016020604051808303816000875af11580156109b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109d49190614850565b979650505050505050565b6040517f4faa38830000000000000000000000000000000000000000000000000000000081526001600160a01b03891690634faa38839061084f908a908a908a908a908a908a908a90600401614a0a565b610a3a8282611b7b565b5050565b606060005b83811015610af3576000858583818110610a5f57610a5f614a4b565b9050602002810190610a719190614a7a565b610a7f906020810190614ab8565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201829052509394505050505b8151811015610ae957610ae188838381518110610ad257610ad2614a4b565b602002602001015160026118b3565b600101610ab3565b5050600101610a43565b506040517f480b37960000000000000000000000000000000000000000000000000000000081526001600160a01b0386169063480b379690610b3d90879087908790600401614b20565b6000604051808303816000875af1158015610b5c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b849190810190614c38565b95945050505050565b610ba26001600160a01b038416338385611c3c565b505050565b610ba2838383611ced565b60608167ffffffffffffffff811115610bcd57610bcd61466d565b604051908082528060200260200182016040528015610c2457816020015b610c11604051806060016040528060001515815260200160608152602001600081525090565b815260200190600190039081610beb5790505b50905060005b82811015610c8e57610c5e848483818110610c4757610c47614a4b565b9050602002810190610c599190614cc3565b611d55565b828281518110610c7057610c70614a4b565b60200260200101819052508080610c8690614d57565b915050610c2a565b5092915050565b82826000610ca48383836118b3565b6040517f5b6fd01d000000000000000000000000000000000000000000000000000000008152600481018690526000906001600160a01b03881690635b6fd01d9060240161010060405180830381865afa158015610d06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2a9190614794565b516040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610d8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610db29190614850565b9050610dbf8289836119bb565b6040517fded700a6000000000000000000000000000000000000000000000000000000008152600481018890526024810182905263ffffffff871660448201526001600160a01b0389169063ded700a69060640161084f565b6040805180820190915260608082526020820152600080610e398888611ed5565b6040517f4997cdc300000000000000000000000000000000000000000000000000000000815291935091506001600160a01b038a1690634997cdc390610e8b90859085908b908b908b90600401614e22565b600060405180830381865afa158015610ea8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ed09190810190614f52565b925050505b9695505050505050565b6040805180820190915260608082526020820152600080610f008585611ed5565b6040517fd2d95b2d00000000000000000000000000000000000000000000000000000000815291935091506001600160a01b0387169063d2d95b2d90610f4c90859085906004016150bd565b600060405180830381865afa158015610f69573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f9191908101906150e2565b925050505b9392505050565b60006001600160a01b03871615611041576003546040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015260001960248201529088169063095ea7b3906044016020604051808303816000875af115801561101b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103f9190615226565b505b600254611059906001600160a01b0316868689611f36565b6001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611103576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156110da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110fe9190614850565b611105565b475b905081811015610ed5576040517f763dfca000000000000000000000000000000000000000000000000000000000815260048101829052602481018390526044015b60405180910390fd5b600080858560036111628383836118b3565b6040517f72ada4c5000000000000000000000000000000000000000000000000000000008152600481018990526001600160a01b03888116602483015287811660448301528a16906372ada4c59060640160408051808303816000875af11580156111d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111f59190615243565b909a909950975050505050505050565b61123e6001600160a01b037f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba31688888888888888611f81565b50505050505050565b6040517f3dff05870000000000000000000000000000000000000000000000000000000081526001600160a01b03881690633dff05879061129690899089908990899089908990600401615267565b600060405180830381600087803b1580156112b057600080fd5b505af11580156112c4573d6000803e3d6000fd5b5050505050505050505050565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009081906001600160a01b038c16906370a0823190602401602060405180830381865afa158015611333573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113579190614850565b905061136c8c8c8c848d8d8d8d8d8d8d61176c565b9c9b505050505050505050505050565b60608167ffffffffffffffff8111156113975761139761466d565b6040519080825280602002602001820160405280156113ca57816020015b60608152602001906001900390816113b55790505b50905060005b82811015610c8e5761143a308585848181106113ee576113ee614a4b565b90506020028101906114009190614cc3565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061203b92505050565b82828151811061144c5761144c614a4b565b60209081029190910101526001016113d0565b6060610b8485858585612060565b949350505050565b60005a9050600080306001600160a01b031685856040516114979291906153f6565b600060405180830381855af49150503d80600081146114d2576040519150601f19603f3d011682016040523d82523d6000602084013e6114d7565b606091505b509150915060005a6114e99085615406565b905060405180606001604052808415158152602001838152602001828152506040517f493703af0000000000000000000000000000000000000000000000000000000081526004016111479190615419565b61123e6001600160a01b037f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba31688888888888888612146565b848460016115838383836118b3565b6040517ff1accf39000000000000000000000000000000000000000000000000000000008152600481018890526024810187905263ffffffff861660448201526001600160a01b03858116606483015289169063f1accf399060840161084f565b6000546001600160a01b03163314611628576040517fe0a8b92000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a3a82826121cf565b6000546001600160a01b03163314611676576040517fe0a8b92000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280546001600160a01b039384167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161790915560038054929093169116179055565b6000546001600160a01b03163314611700576040517fe0a8b92000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f56bddfa0cee9697cebddf9acd7f23dc6583663b05e007b877056d05017994def9060200160405180910390a150565b60006117798b8d8b6119bb565b81611819576040517f6b29e1bd0000000000000000000000000000000000000000000000000000000081526001600160a01b038d1690636b29e1bd906117d1908e908e908e908e908e908e908e908e9060040161542c565b6020604051808303816000875af11580156117f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118149190614850565b61136c565b6040517fb2b513c10000000000000000000000000000000000000000000000000000000081526001600160a01b038d169063b2b513c190611870908e908e908e908e908e908e908e908e908e908e9060040161548b565b6020604051808303816000875af115801561188f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061136c9190614850565b826001600160a01b031663cc7a20496040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119159190615502565b6001600160a01b031663823abfd98333846040518463ffffffff1660e01b81526004016119449392919061551f565b602060405180830381865afa158015611961573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119859190615226565b610ba2576040517f5c427cd900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015611a24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a489190614850565b905081811015611b75578015611ae6576040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301526000602483015285169063095ea7b3906044016020604051808303816000875af1158015611ac0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ae49190615226565b505b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152600019602483015285169063095ea7b3906044016020604051808303816000875af1158015611b4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b739190615226565b505b50505050565b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611c27576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015611bfe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c229190614850565b611c29565b475b90508015610ba257610ba2838284611ced565b6040516001600160a01b0380851660248301528316604482015260648101829052611b759085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526122dd565b6001600160a01b038116611cfe5750335b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611d4157610ba26001600160a01b038216836123dc565b610ba26001600160a01b0384168284612529565b611d7b604051806060016040528060001515815260200160608152602001600081525090565b600080306001600160a01b031663bcbef20660e01b8686604051602401611da3929190615542565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051611e0e9190615556565b600060405180830381855af49150503d8060008114611e49576040519150601f19603f3d011682016040523d82523d6000602084013e611e4e565b606091505b50915091508115611ebb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f5754463f2053686f756c642068617665206661696c65642100000000000000006044820152606401611147565b60048101905080806020019051810190610b849190615568565b606080611f2a84846000604051908082528060200260200182016040528015611f2457816020015b6040805180820190915260008082526020820152815260200190600190039081611efd5790505b50612572565b50909590945092505050565b611b7383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050506001600160a01b038716919050836125f7565b851561203157876001600160a01b031663edd9444b60405180606001604052808a8a808060200260200160405190810160405280939291908181526020016000905b82821015611fef57611fe06040830286013681900381019061563e565b81526020019060010190611fc3565b505050505081526020018881526020018781525061200e8a8a8661261d565b3387876040518663ffffffff1660e01b815260040161084f9594939291906156c5565b5050505050505050565b6060610f968383604051806060016040528060278152602001615ade602791396126f2565b60608267ffffffffffffffff81111561207b5761207b61466d565b6040519080825280602002602001820160405280156120a4578160200160208202803683370190505b50905060005b8381101561213d5761210e868686848181106120c8576120c8614a4b565b6120de9260206040909202019081019150614562565b8787858181106120f0576120f0614a4b565b90506040020160200160208101906121089190614562565b866127f6565b82828151811061212057612120614a4b565b60209081029190910101528061213581614d57565b9150506120aa565b50949350505050565b6040805160a0810182526001600160a01b0389811660608301908152608083018a9052825260208083018990528284018890528351808501855285831681529081018a905292517f30f28b7a000000000000000000000000000000000000000000000000000000008152908b16926330f28b7a9261084f9290919033908990899060040161577c565b60005b81811015610ba25760008383838181106121ee576121ee614a4b565b90506020028101906122009190614a7a565b612209906157f5565b905060005b8160200151518110156122d3578160200151818151811061223157612231614a4b565b602090810291909101015182516040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201526000602482015291169063095ea7b3906044016020604051808303816000875af11580156122a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ca9190615226565b5060010161220e565b50506001016121d2565b6000612332826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612b6d9092919063ffffffff16565b805190915015610ba257808060200190518101906123509190615226565b610ba2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401611147565b80471015612446576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401611147565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612493576040519150601f19603f3d011682016040523d82523d6000602084013e612498565b606091505b5050905080610ba2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401611147565b6040516001600160a01b038316602482015260448101829052610ba29084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611c89565b60608060606125d38686808060200260200160405190810160405280939291908181526020016000905b828210156125c8576125b9604083028601368190038101906158ad565b8152602001906001019061259c565b505050505085612b7c565b92506125e0868685613060565b91506125ec84846132fb565b905093509350939050565b606061146d848484604051806060016040528060298152602001615ab560299139613401565b60608267ffffffffffffffff8111156126385761263861466d565b60405190808252806020026020018201604052801561267d57816020015b60408051808201909152600080825260208201528152602001906001900390816126565790505b50905060005b81518110156126ea576040518060400160405280846001600160a01b031681526020018686848181106126b8576126b8614a4b565b905060400201602001358152508282815181106126d7576126d7614a4b565b6020908102919091010152600101612683565b509392505050565b60606001600160a01b0384163b61278b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e747261637400000000000000000000000000000000000000000000000000006064820152608401611147565b600080856001600160a01b0316856040516127a69190615556565b600060405180830381855af49150503d80600081146127e1576040519150601f19603f3d011682016040523d82523d6000602084013e6127e6565b606091505b5091509150610f9182828661356e565b600080600061280586866135c1565b6040517f582cf84b0000000000000000000000000000000000000000000000000000000081526001600160a01b038084166004830152808316602483015292945090925060009189169063582cf84b90604401602060405180830381865afa158015612875573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061289991906158ee565b90507f010000000000000000000000000000000000000000000000000000000000000060005b7fff000000000000000000000000000000000000000000000000000000000000008083169084161080159061291557507fff00000000000000000000000000000000000000000000000000000000000000821615155b15612b5c57817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168284167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603612b2e576040517f808ba8e00000000000000000000000000000000000000000000000000000000081526001600160a01b038a8116600483015289811660248301527fff000000000000000000000000000000000000000000000000000000000000008416604483015260009182918291908e169063808ba8e090606401608060405180830381865afa1580156129fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a229190615935565b935093509350506000612a34866135f2565b9050600081612a43818661598d565b612a4e9060016159d7565b612a5891906159f4565b63ffffffff1690508b612a8357612a7060038361598d565b612a809063ffffffff1682615a20565b90505b6000857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161180612ace57506000837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16115b15612b0757428111612aec57859a505050505050505050505061146d565b612af64282615406565b9a505050505050505050505061146d565b42811115612b28578515612b1b5785612b25565b612b254282615406565b95505b50505050505b6001827effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916901b91506128bf565b506000199998505050505050505050565b606061146d8484600085613401565b6060600080835185516002612b919190615a33565b612b9b9190615a20565b67ffffffffffffffff811115612bb357612bb361466d565b604051908082528060200260200182016040528015612bdc578160200160208202803683370190505b50905060005b8551811015612db65760008060005b8581108015612c075750828015612c055750815b155b15612cdc5782158015612c615750888481518110612c2757612c27614a4b565b6020026020010151600001516001600160a01b0316858281518110612c4e57612c4e614a4b565b60200260200101516001600160a01b0316145b15612c6b57600192505b81158015612cc05750888481518110612c8657612c86614a4b565b6020026020010151602001516001600160a01b0316858281518110612cad57612cad614a4b565b60200260200101516001600160a01b0316145b15612cca57600191505b80612cd481614d57565b915050612bf1565b5081612d3f57878381518110612cf457612cf4614a4b565b602002602001015160000151848680612d0c90614d57565b975081518110612d1e57612d1e614a4b565b60200260200101906001600160a01b031690816001600160a01b0316815250505b80612da157878381518110612d5657612d56614a4b565b602002602001015160200151848680612d6e90614d57565b975081518110612d8057612d80614a4b565b60200260200101906001600160a01b031690816001600160a01b0316815250505b50508080612dae90614d57565b915050612be2565b5060005b8451811015612eb5576000805b8481108015612dd4575081155b15612e3f57868381518110612deb57612deb614a4b565b6020026020010151600001516001600160a01b0316848281518110612e1257612e12614a4b565b60200260200101516001600160a01b031603612e2d57600191505b80612e3781614d57565b915050612dc7565b5080612ea257858281518110612e5757612e57614a4b565b602002602001015160000151838580612e6f90614d57565b965081518110612e8157612e81614a4b565b60200260200101906001600160a01b031690816001600160a01b0316815250505b5080612ead81614d57565b915050612dba565b508167ffffffffffffffff811115612ecf57612ecf61466d565b604051908082528060200260200182016040528015612ef8578160200160208202803683370190505b50925060005b82811015613057576000828281518110612f1a57612f1a614a4b565b6020026020010151905060005b816001600160a01b0316868281518110612f4357612f43614a4b565b60200260200101516001600160a01b0316108015612f8d575060006001600160a01b0316868281518110612f7957612f79614a4b565b60200260200101516001600160a01b031614155b15612fa45780612f9c81614d57565b915050612f27565b825b8181111561300e5786612fba600183615406565b81518110612fca57612fca614a4b565b6020026020010151878281518110612fe457612fe4614a4b565b6001600160a01b03909216602092830291909101909101528061300681615a52565b915050612fa6565b508186828151811061302257613022614a4b565b60200260200101906001600160a01b031690816001600160a01b0316815250505050808061304f90614d57565b915050612efe565b50505092915050565b60608267ffffffffffffffff81111561307b5761307b61466d565b6040519080825280602002602001820160405280156130c057816020015b60408051808201909152600080825260208201528152602001906001900390816130995790505b5090506000805b83518160ff1610156132f25760006130e0826001615a69565b90505b84518160ff1610156132df5760005b868110156132cc5787878281811061310c5761310c614a4b565b6131229260206040909202019081019150614562565b6001600160a01b0316868460ff168151811061314057613140614a4b565b60200260200101516001600160a01b03161480156131b4575087878281811061316b5761316b614a4b565b90506040020160200160208101906131839190614562565b6001600160a01b0316868360ff16815181106131a1576131a1614a4b565b60200260200101516001600160a01b0316145b8061327457508787828181106131cc576131cc614a4b565b90506040020160200160208101906131e49190614562565b6001600160a01b0316868460ff168151811061320257613202614a4b565b60200260200101516001600160a01b0316148015613274575087878281811061322d5761322d614a4b565b6132439260206040909202019081019150614562565b6001600160a01b0316868360ff168151811061326157613261614a4b565b60200260200101516001600160a01b0316145b156132ba576040805180820190915260ff808516825283166020820152858561329c81614d57565b9650815181106132ae576132ae614a4b565b60200260200101819052505b806132c481614d57565b9150506130f2565b50806132d781615a82565b9150506130e3565b50806132ea81615a82565b9150506130c7565b50509392505050565b6060815167ffffffffffffffff8111156133175761331761466d565b604051908082528060200260200182016040528015613340578160200160208202803683370190505b50905060005b8351811015610c8e5760005b84828151811061336457613364614a4b565b6020026020010151600001516001600160a01b031684828151811061338b5761338b614a4b565b60200260200101516001600160a01b0316146133b357806133ab81614d57565b915050613352565b8482815181106133c5576133c5614a4b565b6020026020010151602001518382815181106133e3576133e3614a4b565b602090810291909101015250806133f981614d57565b915050613346565b606082471015613493576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401611147565b6001600160a01b0385163b613504576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611147565b600080866001600160a01b031685876040516135209190615556565b60006040518083038185875af1925050503d806000811461355d576040519150601f19603f3d011682016040523d82523d6000602084013e613562565b606091505b50915091506109d48282865b6060831561357d575081610f96565b82511561358d5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111479190615aa1565b600080826001600160a01b0316846001600160a01b0316106135e45782846135e7565b83835b909590945092505050565b60007fff0000000000000000000000000000000000000000000000000000000000000082167f0100000000000000000000000000000000000000000000000000000000000000036136455750603c919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f020000000000000000000000000000000000000000000000000000000000000003613697575061012c919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f0400000000000000000000000000000000000000000000000000000000000000036136e95750610384919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f08000000000000000000000000000000000000000000000000000000000000000361373b5750610708919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f10000000000000000000000000000000000000000000000000000000000000000361378d5750610e10919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f2000000000000000000000000000000000000000000000000000000000000000036137df5750613840919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f400000000000000000000000000000000000000000000000000000000000000003613832575062015180919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f800000000000000000000000000000000000000000000000000000000000000003613885575062093a80919050565b6040517fbf3cad0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000602082840312156138c957600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610f9657600080fd5b6001600160a01b038116811461390e57600080fd5b50565b63ffffffff8116811461390e57600080fd5b803561392e81613911565b919050565b6000806000806080858703121561394957600080fd5b8435613954816138f9565b93506020850135925060408501359150606085013561397281613911565b939692955090935050565b803561392e816138f9565b60008060006060848603121561399d57600080fd5b83356139a8816138f9565b92506020840135915060408401356139bf816138f9565b809150509250925092565b60008083601f8401126139dc57600080fd5b50813567ffffffffffffffff8111156139f457600080fd5b6020830191508360208260051b8501011115613a0f57600080fd5b9250929050565b803560ff8116811461392e57600080fd5b60008060008060008060008060e0898b031215613a4357600080fd5b8835613a4e816138f9565b9750602089013567ffffffffffffffff811115613a6a57600080fd5b613a768b828c016139ca565b9098509650506040890135945060608901359350613a9660808a01613a16565b925060a0890135915060c089013590509295985092959890939650565b60008060408385031215613ac657600080fd5b8235613ad1816138f9565b91506020830135613ae1816138f9565b809150509250929050565b60008060008060608587031215613b0257600080fd5b8435613b0d816138f9565b9350602085013567ffffffffffffffff811115613b2957600080fd5b613b35878288016139ca565b9094509250506040850135613972816138f9565b6020808252825182820181905260009190848201906040850190845b81811015613b8157835183529284019291840191600101613b65565b50909695505050505050565b60008060208385031215613ba057600080fd5b823567ffffffffffffffff811115613bb757600080fd5b613bc3858286016139ca565b90969095509350505050565b60005b83811015613bea578181015183820152602001613bd2565b50506000910152565b60008151808452613c0b816020860160208601613bcf565b601f01601f19169290920160200192915050565b8051151582526000602082015160606020850152613c406060850182613bf3565b604093840151949093019390935250919050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613cc7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613cb5858351613c1f565b94509285019290850190600101613c7b565b5092979650505050505050565b600080600060608486031215613ce957600080fd5b8335613cf4816138f9565b92506020840135915060408401356139bf81613911565b60008083601f840112613d1d57600080fd5b50813567ffffffffffffffff811115613d3557600080fd5b6020830191508360208260061b8501011115613a0f57600080fd5b801515811461390e57600080fd5b60008083601f840112613d7057600080fd5b50813567ffffffffffffffff811115613d8857600080fd5b602083019150836020828501011115613a0f57600080fd5b60008060008060008060808789031215613db957600080fd5b8635613dc4816138f9565b9550602087013567ffffffffffffffff80821115613de157600080fd5b613ded8a838b01613d0b565b909750955060408901359150613e0282613d50565b90935060608801359080821115613e1857600080fd5b50613e2589828a01613d5e565b979a9699509497509295939492505050565b600060208083526060808401855160408085880152828251808552608094508489019150868401935060005b81811015613eb057613ea08386516001600160a01b0381511682526020810151602083015260408101516040830152606081015160608301525050565b9387019391850191600101613e63565b505088860151888203601f1901838a0152805180835290870193506000918701905b80831015613f5857845180516001600160a01b03908116845289820151168984015284810151858401528781015188840152868101518784015260a0808201519084015260c0908101517fff000000000000000000000000000000000000000000000000000000000000001690830152938701936001929092019160e090910190613ed2565b509998505050505050505050565b600080600060408486031215613f7b57600080fd5b8335613f86816138f9565b9250602084013567ffffffffffffffff811115613fa257600080fd5b613fae86828701613d0b565b9497909650939450505050565b600060208083526060808401855160408085880152828251808552608094508489019150868401935060005b81811015614034576140248386516001600160a01b0381511682526020810151602083015260408101516040830152606081015160608301525050565b9387019391850191600101613fe7565b505088860151888203601f1901838a0152805180835290870193506000918701905b80831015613f5857845180516001600160a01b039081168452898201511689840152848101518584015287810151888401528601517fff000000000000000000000000000000000000000000000000000000000000001686830152938701936001929092019160a090910190614056565b60008060008060008060a087890312156140e057600080fd5b86356140eb816138f9565b955060208701359450604087013567ffffffffffffffff81111561410e57600080fd5b61411a89828a01613d5e565b909550935050606087013561412e816138f9565b80925050608087013590509295509295509295565b6000806000806080858703121561415957600080fd5b8435614164816138f9565b935060208501359250604085013561417b816138f9565b91506060850135613972816138f9565b600080600080600080600060a0888a0312156141a657600080fd5b873567ffffffffffffffff808211156141be57600080fd5b6141ca8b838c01613d0b565b909950975060208a0135965060408a0135955060608a01359150808211156141f157600080fd5b506141fe8a828b01613d5e565b9094509250506080880135614212816138f9565b8091505092959891949750929550565b600080600080600080600060c0888a03121561423d57600080fd5b8735614248816138f9565b9650602088013567ffffffffffffffff81111561426457600080fd5b6142708a828b016139ca565b9097509550506040880135935061428960608901613a16565b92506080880135915060a0880135905092959891949750929550565b6000806000806000806000806000806101008b8d0312156142c557600080fd5b8a356142d0816138f9565b995060208b01356142e0816138f9565b985060408b01356142f0816138f9565b975060608b013561430081613911565b965060808b013561431081613911565b955061431e60a08c0161397d565b945060c08b013567ffffffffffffffff8082111561433b57600080fd5b6143478e838f016139ca565b909650945060e08d013591508082111561436057600080fd5b5061436d8d828e01613d5e565b915080935050809150509295989b9194979a5092959850565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613cc7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08886030184526143e7858351613bf3565b945092850192908501906001016143ad565b6000806000806060858703121561440f57600080fd5b843561441a816138f9565b9350602085013567ffffffffffffffff81111561443657600080fd5b61444287828801613d0b565b909450925050604085013561397281613d50565b6000806020838503121561446957600080fd5b823567ffffffffffffffff81111561448057600080fd5b613bc385828601613d5e565b600080600080600080600060c0888a0312156144a757600080fd5b87356144b2816138f9565b9650602088013595506040880135945060608801359350608088013567ffffffffffffffff8111156144e357600080fd5b6144ef8a828b01613d5e565b90945092505060a0880135614212816138f9565b600080600080600060a0868803121561451b57600080fd5b8535614526816138f9565b94506020860135935060408601359250606086013561454481613911565b91506080860135614554816138f9565b809150509295509295909350565b60006020828403121561457457600080fd5b8135610f96816138f9565b60008060008060008060008060008060006101208c8e0312156145a157600080fd5b6145ab8c356138f9565b8b359a506145bc60208d01356138f9565b60208c013599506145cf60408d0161397d565b985060608c013597506145e460808d01613923565b96506145f260a08d01613923565b955061460060c08d0161397d565b945067ffffffffffffffff8060e08e0135111561461c57600080fd5b61462c8e60e08f01358f016139ca565b90955093506101008d013581101561464357600080fd5b506146558d6101008e01358e01613d5e565b81935080925050509295989b509295989b9093969950565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156146bf576146bf61466d565b60405290565b60405160e0810167ffffffffffffffff811182821017156146bf576146bf61466d565b60405160a0810167ffffffffffffffff811182821017156146bf576146bf61466d565b6040516060810167ffffffffffffffff811182821017156146bf576146bf61466d565b604051601f8201601f1916810167ffffffffffffffff811182821017156147575761475761466d565b604052919050565b805161392e816138f9565b805161392e81613911565b80516effffffffffffffffffffffffffffff8116811461392e57600080fd5b60006101008083850312156147a857600080fd5b6040519081019067ffffffffffffffff821181831017156147cb576147cb61466d565b81604052835191506147dc826138f9565b8181526147eb6020850161475f565b60208201526147fc6040850161476a565b604082015261480d6060850161476a565b60608201526080840151608082015261482860a0850161476a565b60a082015260c084015160c082015261484360e08501614775565b60e0820152949350505050565b60006020828403121561486257600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261489e57600080fd5b830160208101925035905067ffffffffffffffff8111156148be57600080fd5b8060051b3603821315613a0f57600080fd5b60048110614907577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc183360301811261493f57600080fd5b90910192915050565b81835260006020808501808196508560051b810191508460005b878110156149fd578284038952614979828861490b565b60408086018235614989816138f9565b6001600160a01b031687526149a083890184614869565b888a019390935290829052909150606086019060005b838110156149e8578135600481106149cd57600080fd5b6149d784826148d0565b5091880191908801906001016149b6565b50509986019994505090840190600101614962565b5091979650505050505050565b60c081526000614a1e60c08301898b614948565b602083019790975250604081019490945260ff929092166060840152608083015260a09091015292915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112614aae57600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614aed57600080fd5b83018035915067ffffffffffffffff821115614b0857600080fd5b6020019150600581901b3603821315613a0f57600080fd5b60408082528181018490526000906060808401600587811b860183018986805b8b811015614bf6577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08a8503018652614b79838e61490b565b8035614b84816138f9565b6001600160a01b031685526020614b9d82820183614869565b92508a82880152828b8801527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115614bd5578485fd5b91871b918281888c0137509687019694018701939290920191600101614b40565b5050506001600160a01b0388166020880152945061146d9350505050565b600067ffffffffffffffff821115614c2e57614c2e61466d565b5060051b60200190565b60006020808385031215614c4b57600080fd5b825167ffffffffffffffff811115614c6257600080fd5b8301601f81018513614c7357600080fd5b8051614c86614c8182614c14565b61472e565b81815260059190911b82018301908381019087831115614ca557600080fd5b928401925b828410156109d457835182529284019290840190614caa565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614cf857600080fd5b83018035915067ffffffffffffffff821115614d1357600080fd5b602001915036819003821315613a0f57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006000198203614d6a57614d6a614d28565b5060010190565b600081518084526020808501945080840160005b83811015614daa5781516001600160a01b031687529582019590820190600101614d85565b509495945050505050565b600081518084526020808501945080840160005b83811015614daa578151805160ff908116895290840151168388015260409096019590820190600101614dc9565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b608081526000614e356080830188614d71565b8281036020840152614e478188614db5565b905085151560408401528281036060840152614e64818587614df7565b98975050505050505050565b6000614e7e614c8184614c14565b8381529050602080820190600785901b840186811115614e9d57600080fd5b845b81811015614f1757608080828a031215614eb95760008081fd5b604080519182019167ffffffffffffffff83118184101715614edd57614edd61466d565b918152825191614eec836138f9565b9182528285015185830152808301519082015260608083015190820152845292820192608001614e9f565b505050509392505050565b80517fff000000000000000000000000000000000000000000000000000000000000008116811461392e57600080fd5b60006020808385031215614f6557600080fd5b825167ffffffffffffffff80821115614f7d57600080fd5b81850191506040808388031215614f9357600080fd5b614f9b61469c565b835183811115614faa57600080fd5b8401601f81018913614fbb57600080fd5b614fc9898251888401614e70565b8252508484015183811115614fdd57600080fd5b80850194505087601f850112614ff257600080fd5b83519250615002614c8184614c14565b83815260e0938402850186019386820191908a86111561502157600080fd5b958701955b858710156150aa5780878c03121561503e5760008081fd5b6150466146c5565b8751615051816138f9565b815287890151615060816138f9565b818a01528786015186820152606080890151908201526080808901519082015260a0808901519082015260c0615097818a01614f22565b9082015283529586019591870191615026565b5095820195909552979650505050505050565b6040815260006150d06040830185614d71565b8281036020840152610b848185614db5565b600060208083850312156150f557600080fd5b825167ffffffffffffffff8082111561510d57600080fd5b8185019150604080838803121561512357600080fd5b61512b61469c565b83518381111561513a57600080fd5b8401601f8101891361514b57600080fd5b615159898251888401614e70565b825250848401518381111561516d57600080fd5b80850194505087601f85011261518257600080fd5b83519250615192614c8184614c14565b83815260a0938402850186019386820191908a8611156151b157600080fd5b958701955b858710156150aa5780878c0312156151ce5760008081fd5b6151d66146e8565b87516151e1816138f9565b8152878901516151f0816138f9565b818a01528786015186820152606080890151908201526080615213818a01614f22565b90820152835295860195918701916151b6565b60006020828403121561523857600080fd5b8151610f9681613d50565b6000806040838503121561525657600080fd5b505080516020909101519092909150565b60a080825281018690526000600560c08084019089831b8501018a845b8b8110156153c6577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff408784030184526152bd828e61490b565b60408085018235865260206152d481850185614869565b88830185905292839052919350606091828801858b1b890184018260005b888110156153ac577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08c840301845261532b828661490b565b8884018135615339816138f9565b6001600160a01b0316855261535082890183614869565b868a018c90529182905290915060008986015b838210156153975782356004811061537a57600080fd5b61538482826148d0565b5091890191600191909101908901615363565b968901969550505091860191506001016152f2565b505099830199985050509490940193505050600101615284565b50506020850189905260ff8816604086015292506153e2915050565b606082019390935260800152949350505050565b8183823760009101908152919050565b8181038181111561075157610751614d28565b602081526000610f966020830184613c1f565b60006001600160a01b03808b168352808a16602084015288604084015263ffffffff808916606085015280881660808501525080861660a08401525060e060c083015261547d60e083018486614948565b9a9950505050505050505050565b6001600160a01b038b811682528a81166020830152604082018a905263ffffffff898116606084015288166080830152861660a082015261010060c082018190526000906154dc8382018789614948565b905082810360e08401526154f1818587614df7565b9d9c50505050505050505050505050565b60006020828403121561551457600080fd5b8151610f96816138f9565b8381526001600160a01b03831660208201526060810161146d60408301846148d0565b60208152600061146d602083018486614df7565b60008251614aae818460208701613bcf565b6000602080838503121561557b57600080fd5b825167ffffffffffffffff8082111561559357600080fd5b90840190606082870312156155a757600080fd5b6155af61470b565b82516155ba81613d50565b815282840151828111156155cd57600080fd5b8301601f810188136155de57600080fd5b8051838111156155f0576155f061466d565b61560286601f19601f8401160161472e565b9350808452888682840101111561561857600080fd5b61562781878601888501613bcf565b505092830152604090810151908201529392505050565b60006040828403121561565057600080fd5b61565861469c565b8235615663816138f9565b81526020928301359281019290925250919050565b600081518084526020808501945080840160005b83811015614daa576156b287835180516001600160a01b03168252602090810151910152565b604096909601959082019060010161568c565b60808152600060e082018751606060808501528181518084526101008601915060209350838301925060005b8181101561572a5761571783855180516001600160a01b03168252602090810151910152565b92840192604092909201916001016156f1565b5050828a015160a086015260408a015160c086015284810383860152615750818a615678565b9250505061576960408401876001600160a01b03169052565b8281036060840152614e64818587614df7565b600061010061579f83895180516001600160a01b03168252602090810151910152565b60208801516040840152604088015160608401526157d3608084018880516001600160a01b03168252602090810151910152565b6001600160a01b03861660c08401528060e0840152614e648184018587614df7565b60006040823603121561580757600080fd5b61580f61469c565b823561581a816138f9565b815260208381013567ffffffffffffffff81111561583757600080fd5b840136601f82011261584857600080fd5b8035615856614c8182614c14565b81815260059190911b8201830190838101903683111561587557600080fd5b928401925b8284101561589c57833561588d816138f9565b8252928401929084019061587a565b938501939093525091949350505050565b6000604082840312156158bf57600080fd5b6158c761469c565b82356158d2816138f9565b815260208301356158e2816138f9565b60208201529392505050565b60006020828403121561590057600080fd5b610f9682614f22565b80517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461392e57600080fd5b6000806000806080858703121561594b57600080fd5b845161595681613911565b935061596460208601615909565b9250604085015161597481613911565b915061598260608601615909565b905092959194509250565b600063ffffffff808416806159cb577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b92169190910492915050565b63ffffffff818116838216019080821115610c8e57610c8e614d28565b600063ffffffff80831681851681830481118215151615615a1757615a17614d28565b02949350505050565b8082018082111561075157610751614d28565b6000816000190483118215151615615a4d57615a4d614d28565b500290565b600081615a6157615a61614d28565b506000190190565b60ff818116838216019081111561075157610751614d28565b600060ff821660ff8103615a9857615a98614d28565b60010192915050565b602081526000610f966020830184613bf356fe416464726573733a206c6f772d6c6576656c2063616c6c20776974682076616c7565206661696c6564416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122085524a8f6f575000dc99a0891112cb7b3cc50f61e7374973f298e53a09b025c564736f6c63430008100033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000227f070ed2afd8744ef059959b8a8b8e8edc6c0f000000000000000000000000227f070ed2afd8744ef059959b8a8b8e8edc6c0f000000000000000000000000ec864be26084ba3bbf3caacf8f6961a9263319c4000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3
-----Decoded View---------------
Arg [0] : _swapper (address): 0x227F070ED2afd8744eF059959b8a8B8e8edC6C0f
Arg [1] : _allowanceTarget (address): 0x227F070ED2afd8744eF059959b8a8B8e8edC6C0f
Arg [2] : _governor (address): 0xEC864BE26084ba3bbF3cAAcF8F6961A9263319C4
Arg [3] : _permit2 (address): 0x000000000022D473030F116dDEE9F6B43aC78BA3
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000227f070ed2afd8744ef059959b8a8b8e8edc6c0f
Arg [1] : 000000000000000000000000227f070ed2afd8744ef059959b8a8b8e8edc6c0f
Arg [2] : 000000000000000000000000ec864be26084ba3bbf3caacf8f6961a9263319c4
Arg [3] : 000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.