Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 74 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Multicall | 17854605 | 507 days ago | IN | 0 ETH | 0.00249225 | ||||
Multicall | 17854599 | 507 days ago | IN | 0.01 ETH | 0.00386191 | ||||
Multicall | 17853779 | 507 days ago | IN | 0 ETH | 0.00240272 | ||||
Multicall | 17853649 | 507 days ago | IN | 0.1 ETH | 0.00332079 | ||||
Multicall | 17853569 | 507 days ago | IN | 0.15 ETH | 0.0049096 | ||||
Multicall | 17835153 | 509 days ago | IN | 0.02 ETH | 0.01235493 | ||||
Multicall | 17833793 | 509 days ago | IN | 0 ETH | 0.00264309 | ||||
Multicall | 17808804 | 513 days ago | IN | 0.02 ETH | 0.00374235 | ||||
Multicall | 17807530 | 513 days ago | IN | 0.0054 ETH | 0.0038722 | ||||
Multicall | 17804702 | 513 days ago | IN | 0 ETH | 0.0037104 | ||||
Multicall | 17777435 | 517 days ago | IN | 0.03 ETH | 0.0123468 | ||||
Multicall | 17774709 | 518 days ago | IN | 0 ETH | 0.00438426 | ||||
Multicall | 17753082 | 521 days ago | IN | 0.004 ETH | 0.00347749 | ||||
Multicall | 17751601 | 521 days ago | IN | 0.02355 ETH | 0.00347381 | ||||
Multicall | 17742252 | 522 days ago | IN | 0 ETH | 0.00752081 | ||||
Multicall | 17710930 | 527 days ago | IN | 0 ETH | 0.00276381 | ||||
Multicall | 17710868 | 527 days ago | IN | 0 ETH | 0.00202302 | ||||
Multicall | 17706931 | 527 days ago | IN | 0 ETH | 0.00428148 | ||||
Multicall | 17694361 | 529 days ago | IN | 0.01 ETH | 0.00476707 | ||||
Multicall | 17693977 | 529 days ago | IN | 0 ETH | 0.00465088 | ||||
Multicall | 17669439 | 532 days ago | IN | 0 ETH | 0.00243659 | ||||
Multicall | 17669432 | 532 days ago | IN | 0.008 ETH | 0.00409098 | ||||
Multicall | 17669157 | 533 days ago | IN | 0 ETH | 0.00347379 | ||||
Multicall | 17666730 | 533 days ago | IN | 0 ETH | 0.00475372 | ||||
Multicall | 17620401 | 539 days ago | IN | 0 ETH | 0.00301444 |
Latest 23 internal transactions
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
17854599 | 507 days ago | 0.01 ETH | ||||
17853649 | 507 days ago | 0.1 ETH | ||||
17853569 | 507 days ago | 0.15 ETH | ||||
17835153 | 509 days ago | 0.02 ETH | ||||
17808804 | 513 days ago | 0.02 ETH | ||||
17807530 | 513 days ago | 0.0054 ETH | ||||
17777435 | 517 days ago | 0.03 ETH | ||||
17753082 | 521 days ago | 0.004 ETH | ||||
17751601 | 521 days ago | 0.02355 ETH | ||||
17694361 | 529 days ago | 0.01 ETH | ||||
17669432 | 532 days ago | 0.008 ETH | ||||
17620358 | 539 days ago | 0.002555 ETH | ||||
17615603 | 540 days ago | 0.0194297 ETH | ||||
17607350 | 541 days ago | 0.01 ETH | ||||
17564409 | 547 days ago | 0.03 ETH | ||||
17563138 | 547 days ago | 0.0027 ETH | ||||
17536498 | 551 days ago | 1.47792987 ETH | ||||
17512771 | 554 days ago | 0.005 ETH | ||||
17501943 | 556 days ago | 0.021 ETH | ||||
17499532 | 556 days ago | 0.01 ETH | ||||
17422964 | 567 days ago | 0.05 ETH | ||||
17368828 | 575 days ago | 0.02982515 ETH | ||||
17094763 | 613 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
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 _swapperRegistry, address _governor) BaseCompanion(_swapperRegistry, _governor) {} }
// 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 '../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/swappers/solidity/contracts/extensions/GetBalances.sol'; import '@mean-finance/swappers/solidity/contracts/extensions/RevokableWithGovernor.sol'; import '@mean-finance/swappers/solidity/contracts/extensions/RunSwap.sol'; import '@mean-finance/swappers/solidity/contracts/extensions/PayableMulticall.sol'; import '@mean-finance/swappers/solidity/contracts/extensions/TokenPermit.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 RunSwap, RevokableWithGovernor, GetBalances, PayableMulticall, TokenPermit { constructor(address _swapperRegistry, address _governor) SwapAdapter(_swapperRegistry) Governable(_governor) {} /** * @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) external payable { _takeFromMsgSender(_token, _amount); } /** * @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); } }
// 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 '@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 '@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 '@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; /// @notice A pair of tokens struct Pair { address tokenA; address tokenB; }
// 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: 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: 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: 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.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; import './Shared.sol'; import '../SwapAdapter.sol'; abstract contract GetBalances is SwapAdapter { /// @notice The balance of a given token struct TokenBalance { address token; uint256 balance; } /** * @notice Returns the balance of each of the given tokens * @dev Meant to be used for off-chain queries * @param _tokens The tokens to check the balance for, can be ERC20s or the protocol token * @return _balances The balances for the given tokens */ function getBalances(address[] calldata _tokens) external view returns (TokenBalance[] memory _balances) { _balances = new TokenBalance[](_tokens.length); for (uint256 i = 0; i < _tokens.length; ) { uint256 _balance = _tokens[i] == PROTOCOL_TOKEN ? address(this).balance : IERC20(_tokens[i]).balanceOf(address(this)); _balances[i] = TokenBalance({token: _tokens[i], balance: _balance}); unchecked { i++; } } } }
// 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.7 <0.9.0; import '../SwapAdapter.sol'; abstract contract RunSwap is SwapAdapter { /// @notice The parameters to execute the call struct RunSwapParams { // The swapper that will execute the call address swapper; // The account that needs to be approved for token transfers address allowanceTarget; // The actual swap execution bytes swapData; // The token that will be swapped address tokenIn; // The amount of "token in" that will be spent uint256 amountIn; } /** * @notice Executes a swap with the given swapper. The input tokens are expected to be on the contract before * this function is executed. If the swap doesn't include a transfer, then the swapped tokens will be left * on the contract * @dev This function can only be executed with swappers that are allowlisted * @param _parameters The parameters for the swap */ function runSwap(RunSwapParams calldata _parameters) public payable virtual onlyAllowlisted(_parameters.swapper) { if (_parameters.tokenIn == PROTOCOL_TOKEN) { _executeSwap(_parameters.swapper, _parameters.swapData, _parameters.amountIn); } else { _maxApproveSpenderIfNeeded( IERC20(_parameters.tokenIn), _parameters.allowanceTarget, _parameters.swapper == _parameters.allowanceTarget, // If target is a swapper, then it's ok as allowance target _parameters.amountIn ); _executeSwap(_parameters.swapper, _parameters.swapData, 0); } } }
// 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.7 <0.9.0; import '@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol'; abstract contract TokenPermit { /** * @notice Executes a permit on a ERC20 token that supports it * @param _token The token that will execute the permit * @param _owner The account that signed the permite * @param _spender The account that is being approved * @param _value The amount that is being approved * @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( IERC20Permit _token, address _owner, address _spender, uint256 _value, uint256 _deadline, uint8 _v, bytes32 _r, bytes32 _s ) external payable { _token.permit(_owner, _spender, _value, _deadline, _v, _r, _s); } }
// 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; import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; /// @notice An amount to take form the caller struct TakeFromCaller { // The token that will be taken from the caller IERC20 token; // The amount that will be taken uint256 amount; } /// @notice An allowance to provide for the swaps to work struct Allowance { // The token that should be approved IERC20 token; // The spender address allowanceTarget; // The minimum allowance needed uint256 minAllowance; } /// @notice A swap to execute struct Swap { // The index of the swapper in the list of swappers uint8 swapperIndex; // The data to send to the swapper bytes swapData; } /// @notice A token that was left on the contract and should be transferred out struct TransferOutBalance { // The token to transfer address token; // The recipient of those tokens address recipient; } /// @notice Context necessary for the swap execution struct SwapContext { // The index of the swapper that should execute each swap. This might look strange but it's way cheaper than alternatives uint8 swapperIndex; // The ETH/MATIC/BNB to send as part of the swap uint256 value; }
// 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: 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: 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 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); }
// 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: 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; /** * @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; }
{ "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":"_swapperRegistry","type":"address"},{"internalType":"address","name":"_governor","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":"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":"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":[{"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":"address[]","name":"_tokens","type":"address[]"}],"name":"getBalances","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"}],"internalType":"struct GetBalances.TokenBalance[]","name":"_balances","type":"tuple[]"}],"stateMutability":"view","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":"contract IERC20Permit","name":"_token","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_value","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":"permit","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":[{"components":[{"internalType":"address","name":"swapper","type":"address"},{"internalType":"address","name":"allowanceTarget","type":"address"},{"internalType":"bytes","name":"swapData","type":"bytes"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"}],"internalType":"struct RunSwap.RunSwapParams","name":"_parameters","type":"tuple"}],"name":"runSwap","outputs":[],"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":"contract IERC20","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"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
60a06040523480156200001157600080fd5b5060405162005469380380620054698339810160408190526200003491620000d6565b818180826001600160a01b038116620000605760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0390811660805281166200008e5760405163e6250e3360e01b815260040160405180910390fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055506200010e92505050565b80516001600160a01b0381168114620000d157600080fd5b919050565b60008060408385031215620000ea57600080fd5b620000f583620000b9565b91506200010560208401620000b9565b90509250929050565b608051615331620001386000396000818161041b01528181611a360152611c1c01526153316000f3fe6080604052600436106101c65760003560e01c80635f963dcf116100f7578063d339056d11610095578063e43581b811610064578063e43581b8146104e2578063e9c0407114610511578063f235757f14610531578063fa0c95551461055157600080fd5b8063d339056d1461045d578063db8266de14610470578063df08aed514610483578063e3056a34146104c257600080fd5b806389352328116100d157806389352328146103d6578063ac9650d8146103e9578063b3b48afb14610409578063bb2871a51461043d57600080fd5b80635f963dcf1461038857806362dd9af3146103b057806385f44632146103c357600080fd5b8063340b532f1161016457806340c5710c1161013e57806340c5710c146102f3578063484b3577146103065780635684c27514610333578063585cc6a51461036057600080fd5b8063340b532f146102ad57806335ac2a50146102c05780633a79d674146102e057600080fd5b806313f6986d116101a057806313f6986d146102375780631f66925c1461024c5780631f8b479d1461026d5780632d2ae1c11461028057600080fd5b806305ce20d6146101d25780630c340a24146101e757806312b17e351461022457600080fd5b366101cd57005b600080fd5b6101e56101e03660046135fa565b610564565b005b3480156101f357600080fd5b50600054610207906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101e5610232366004613644565b610698565b34801561024357600080fd5b506101e56106a6565b61025f61025a36600461367b565b610752565b60405190815260200161021b565b6101e561027b36600461371a565b6107fa565b34801561028c57600080fd5b506102a061029b3660046137a6565b61084b565b60405161021b91906137e8565b6101e56102bb366004613840565b610a29565b6102d36102ce366004613879565b610a33565b60405161021b91906138d6565b6101e56102ee36600461367b565b610b82565b6101e561030136600461391a565b610b92565b34801561031257600080fd5b506103266103213660046139e6565b610d15565b60405161021b9190613a7d565b34801561033f57600080fd5b5061035361034e366004613bac565b610dda565b60405161021b9190613c01565b34801561036c57600080fd5b5061020773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b61039b610396366004613d0d565b610e98565b6040805192835260208301919091520161021b565b6101e56103be366004613d55565b610f4d565b6101e56103d1366004613dd8565b610fd7565b61025f6103e4366004613e13565b6110c8565b6103fc6103f73660046137a6565b611173565b60405161021b9190613f44565b34801561041557600080fd5b506102077f000000000000000000000000000000000000000000000000000000000000000081565b34801561044957600080fd5b506102d3610458366004613fc4565b61125c565b6101e561046b366004614021565b611272565b6101e561047e3660046140a2565b6112e6565b34801561048f57600080fd5b506104b261049e366004614101565b6001546001600160a01b0391821691161490565b604051901515815260200161021b565b3480156104ce57600080fd5b50600154610207906001600160a01b031681565b3480156104ee57600080fd5b506104b26104fd366004614101565b6000546001600160a01b0391821691161490565b34801561051d57600080fd5b506101e561052c3660046137a6565b611356565b34801561053d57600080fd5b506101e561054c366004614101565b6113a4565b61025f61055f36600461411e565b611454565b8383600061057383838361159b565b6040517f5b6fd01d000000000000000000000000000000000000000000000000000000008152600481018790526000906001600160a01b03891690635b6fd01d9060240161010060405180830381865afa1580156105d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f99190614310565b5190506106078189886116a3565b6040517fded700a6000000000000000000000000000000000000000000000000000000008152600481018890526024810187905263ffffffff861660448201526001600160a01b0389169063ded700a6906064015b600060405180830381600087803b15801561067657600080fd5b505af115801561068a573d6000803e3d6000fd5b505050505050505050505050565b6106a28282611863565b5050565b6001546001600160a01b031633146106ea576040517f9ba0305d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018054600080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081166001600160a01b0384161782559091169091556040517fdc57ca23c46d823853915ed5a090ca0ee9db5eb6a46f5c58e1c9158de861fd769190a1565b60008383600261076383838361159b565b6040517f17621890000000000000000000000000000000000000000000000000000000008152600481018790526001600160a01b0386811660248301528816906317621890906044016020604051808303816000875af11580156107cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ef91906143cc565b979650505050505050565b6040517f4faa38830000000000000000000000000000000000000000000000000000000081526001600160a01b03891690634faa38839061065c908a908a908a908a908a908a908a90600401614579565b60608167ffffffffffffffff8111156108665761086661420c565b6040519080825280602002602001820160405280156108ab57816020015b60408051808201909152600080825260208201528152602001906001900390816108845790505b50905060005b82811015610a2257600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8585848181106108e2576108e26145ba565b90506020020160208101906108f79190614101565b6001600160a01b0316146109b457848483818110610917576109176145ba565b905060200201602081019061092c9190614101565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa15801561098b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109af91906143cc565b6109b6565b475b905060405180604001604052808686858181106109d5576109d56145ba565b90506020020160208101906109ea9190614101565b6001600160a01b0316815260200182815250838381518110610a0e57610a0e6145ba565b6020908102919091010152506001016108b1565b5092915050565b6106a28282611878565b606060005b83811015610ae8576000858583818110610a5457610a546145ba565b9050602002810190610a6691906145e9565b610a74906020810190614627565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201829052509394505050505b8151811015610ade57610ad688838381518110610ac757610ac76145ba565b6020026020010151600261159b565b600101610aa8565b5050600101610a38565b506040517f480b37960000000000000000000000000000000000000000000000000000000081526001600160a01b0386169063480b379690610b329087908790879060040161468f565b6000604051808303816000875af1158015610b51573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b7991908101906147a7565b95945050505050565b610b8d838383611935565b505050565b82826000610ba183838361159b565b6040517f5b6fd01d000000000000000000000000000000000000000000000000000000008152600481018690526000906001600160a01b03881690635b6fd01d9060240161010060405180830381865afa158015610c03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c279190614310565b516040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610c8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610caf91906143cc565b9050610cbc8289836116a3565b6040517fded700a6000000000000000000000000000000000000000000000000000000008152600481018890526024810182905263ffffffff871660448201526001600160a01b0389169063ded700a69060640161065c565b6040805180820190915260608082526020820152600080610d36888861199d565b6040517f4997cdc300000000000000000000000000000000000000000000000000000000815291935091506001600160a01b038a1690634997cdc390610d8890859085908b908b908b906004016148e3565b600060405180830381865afa158015610da5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610dcd9190810190614a13565b9998505050505050505050565b6040805180820190915260608082526020820152600080610dfb858561199d565b6040517fd2d95b2d00000000000000000000000000000000000000000000000000000000815291935091506001600160a01b0387169063d2d95b2d90610e479085908590600401614b7e565b600060405180830381865afa158015610e64573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e8c9190810190614ba3565b925050505b9392505050565b60008085856003610eaa83838361159b565b6040517f72ada4c5000000000000000000000000000000000000000000000000000000008152600481018990526001600160a01b03888116602483015287811660448301528a16906372ada4c59060640160408051808303816000875af1158015610f19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3d9190614ce7565b909a909950975050505050505050565b6040517f3dff05870000000000000000000000000000000000000000000000000000000081526001600160a01b03881690633dff058790610f9c90899089908990899089908990600401614d0b565b600060405180830381600087803b158015610fb657600080fd5b505af1158015610fca573d6000803e3d6000fd5b5050505050505050505050565b610fe46020820182614101565b610fed816119fe565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6110126080840160608501614101565b6001600160a01b031603611047576106a26110306020840184614101565b61103d6040850185614dc8565b8560800135611aea565b6110a461105a6080840160608501614101565b61106a6040850160208601614101565b61107a6040860160208701614101565b6001600160a01b03166110906020870187614101565b6001600160a01b0316148560800135611b35565b6106a26110b46020840184614101565b6110c16040850185614dc8565b6000611aea565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009081906001600160a01b038c16906370a0823190602401602060405180830381865afa15801561112a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114e91906143cc565b90506111638c8c8c848d8d8d8d8d8d8d611454565b9c9b505050505050505050505050565b60608167ffffffffffffffff81111561118e5761118e61420c565b6040519080825280602002602001820160405280156111c157816020015b60608152602001906001900390816111ac5790505b50905060005b82811015610a2257611231308585848181106111e5576111e56145ba565b90506020028101906111f79190614dc8565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611df492505050565b828281518110611243576112436145ba565b60209081029190910101526001016111c7565b92915050565b6060610b7985858585611e19565b949350505050565b6040517fd505accf0000000000000000000000000000000000000000000000000000000081526001600160a01b0388811660048301528781166024830152604482018790526064820186905260ff8516608483015260a4820184905260c4820183905289169063d505accf9060e40161065c565b848460016112f583838361159b565b6040517ff1accf39000000000000000000000000000000000000000000000000000000008152600481018890526024810187905263ffffffff861660448201526001600160a01b03858116606483015289169063f1accf399060840161065c565b6000546001600160a01b0316331461139a576040517fe0a8b92000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6106a28282611eff565b6000546001600160a01b031633146113e8576040517fe0a8b92000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f56bddfa0cee9697cebddf9acd7f23dc6583663b05e007b877056d05017994def9060200160405180910390a150565b60006114618b8d8b6116a3565b81611501576040517f6b29e1bd0000000000000000000000000000000000000000000000000000000081526001600160a01b038d1690636b29e1bd906114b9908e908e908e908e908e908e908e908e90600401614e2d565b6020604051808303816000875af11580156114d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114fc91906143cc565b611163565b6040517fb2b513c10000000000000000000000000000000000000000000000000000000081526001600160a01b038d169063b2b513c190611558908e908e908e908e908e908e908e908e908e908e90600401614e8c565b6020604051808303816000875af1158015611577573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116391906143cc565b826001600160a01b031663cc7a20496040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115fd9190614f03565b6001600160a01b031663823abfd98333846040518463ffffffff1660e01b815260040161162c93929190614f20565b602060405180830381865afa158015611649573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061166d9190614f43565b610b8d576040517f5c427cd900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa15801561170c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061173091906143cc565b90508181101561185d5780156117ce576040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301526000602483015285169063095ea7b3906044016020604051808303816000875af11580156117a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117cc9190614f43565b505b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152600019602483015285169063095ea7b3906044016020604051808303816000875af1158015611837573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185b9190614f43565b505b50505050565b6106a26001600160a01b03831633308461200d565b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611924576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156118fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061191f91906143cc565b611926565b475b90508015610b8d57610b8d8382845b6001600160a01b0381166119465750335b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161198957610b8d6001600160a01b038216836120be565b610b8d6001600160a01b038416828461220b565b6060806119f2848460006040519080825280602002602001820160405280156119ec57816020015b60408051808201909152600080825260208201528152602001906001900390816119c55790505b50612254565b50909590945092505050565b6040517fcb00d85f0000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063cb00d85f90602401602060405180830381865afa158015611a7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa19190614f43565b611ae7576040517f220d24fd0000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024015b60405180910390fd5b50565b61185b83838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050506001600160a01b038716919050836122d9565b6001600160a01b0383161561185d576040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0384811660248301526000919086169063dd62ed3e90604401602060405180830381865afa158015611bad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd191906143cc565b90508181101561185b5782158015611c8957506040517f344cb9cd0000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063344cb9cd90602401602060405180830381865afa158015611c63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c879190614f43565b155b15611ccb576040517f1f0b33c30000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611ade565b8015611d5f576040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301526000602483015286169063095ea7b3906044016020604051808303816000875af1158015611d39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d5d9190614f43565b505b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b038581166004830152600019602483015286169063095ea7b3906044016020604051808303816000875af1158015611dc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dec9190614f43565b505050505050565b6060610e9183836040518060600160405280602781526020016152d5602791396122ff565b60608267ffffffffffffffff811115611e3457611e3461420c565b604051908082528060200260200182016040528015611e5d578160200160208202803683370190505b50905060005b83811015611ef657611ec786868684818110611e8157611e816145ba565b611e979260206040909202019081019150614101565b878785818110611ea957611ea96145ba565b9050604002016020016020810190611ec19190614101565b86612403565b828281518110611ed957611ed96145ba565b602090810291909101015280611eee81614f8f565b915050611e63565b50949350505050565b60005b81811015610b8d576000838383818110611f1e57611f1e6145ba565b9050602002810190611f3091906145e9565b611f3990614fa9565b905060005b8160200151518110156120035781602001518181518110611f6157611f616145ba565b602090810291909101015182516040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201526000602482015291169063095ea7b3906044016020604051808303816000875af1158015611fd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ffa9190614f43565b50600101611f3e565b5050600101611f02565b6040516001600160a01b038085166024830152831660448201526064810182905261185d9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915261277a565b80471015612128576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401611ade565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612175576040519150601f19603f3d011682016040523d82523d6000602084013e61217a565b606091505b5050905080610b8d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401611ade565b6040516001600160a01b038316602482015260448101829052610b8d9084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161205a565b60608060606122b58686808060200260200160405190810160405280939291908181526020016000905b828210156122aa5761229b60408302860136819003810190615061565b8152602001906001019061227e565b505050505085612879565b92506122c2868685612d5d565b91506122ce8484612ff8565b905093509350939050565b606061126a8484846040518060600160405280602981526020016152ac602991396130fe565b60606001600160a01b0384163b612398576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e747261637400000000000000000000000000000000000000000000000000006064820152608401611ade565b600080856001600160a01b0316856040516123b391906150c0565b600060405180830381855af49150503d80600081146123ee576040519150601f19603f3d011682016040523d82523d6000602084013e6123f3565b606091505b5091509150610e8c82828661326b565b600080600061241286866132be565b6040517f582cf84b0000000000000000000000000000000000000000000000000000000081526001600160a01b038084166004830152808316602483015292945090925060009189169063582cf84b90604401602060405180830381865afa158015612482573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124a691906150d2565b90507f010000000000000000000000000000000000000000000000000000000000000060005b7fff000000000000000000000000000000000000000000000000000000000000008083169084161080159061252257507fff00000000000000000000000000000000000000000000000000000000000000821615155b1561276957817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168284167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361273b576040517f808ba8e00000000000000000000000000000000000000000000000000000000081526001600160a01b038a8116600483015289811660248301527fff000000000000000000000000000000000000000000000000000000000000008416604483015260009182918291908e169063808ba8e090606401608060405180830381865afa15801561260b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061262f9190615119565b935093509350506000612641866132ef565b90506000816126508186615171565b61265b9060016151bb565b61266591906151d8565b63ffffffff1690508b6126905761267d600383615171565b61268d9063ffffffff1682615204565b90505b6000857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1611806126db57506000837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16115b15612714574281116126f957859a505050505050505050505061126a565b6127034282615217565b9a505050505050505050505061126a565b428111156127355785156127285785612732565b6127324282615217565b95505b50505050505b6001827effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916901b91506124cc565b506000199998505050505050505050565b60006127cf826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166135b49092919063ffffffff16565b805190915015610b8d57808060200190518101906127ed9190614f43565b610b8d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401611ade565b606060008083518551600261288e919061522a565b6128989190615204565b67ffffffffffffffff8111156128b0576128b061420c565b6040519080825280602002602001820160405280156128d9578160200160208202803683370190505b50905060005b8551811015612ab35760008060005b858110801561290457508280156129025750815b155b156129d9578215801561295e5750888481518110612924576129246145ba565b6020026020010151600001516001600160a01b031685828151811061294b5761294b6145ba565b60200260200101516001600160a01b0316145b1561296857600192505b811580156129bd5750888481518110612983576129836145ba565b6020026020010151602001516001600160a01b03168582815181106129aa576129aa6145ba565b60200260200101516001600160a01b0316145b156129c757600191505b806129d181614f8f565b9150506128ee565b5081612a3c578783815181106129f1576129f16145ba565b602002602001015160000151848680612a0990614f8f565b975081518110612a1b57612a1b6145ba565b60200260200101906001600160a01b031690816001600160a01b0316815250505b80612a9e57878381518110612a5357612a536145ba565b602002602001015160200151848680612a6b90614f8f565b975081518110612a7d57612a7d6145ba565b60200260200101906001600160a01b031690816001600160a01b0316815250505b50508080612aab90614f8f565b9150506128df565b5060005b8451811015612bb2576000805b8481108015612ad1575081155b15612b3c57868381518110612ae857612ae86145ba565b6020026020010151600001516001600160a01b0316848281518110612b0f57612b0f6145ba565b60200260200101516001600160a01b031603612b2a57600191505b80612b3481614f8f565b915050612ac4565b5080612b9f57858281518110612b5457612b546145ba565b602002602001015160000151838580612b6c90614f8f565b965081518110612b7e57612b7e6145ba565b60200260200101906001600160a01b031690816001600160a01b0316815250505b5080612baa81614f8f565b915050612ab7565b508167ffffffffffffffff811115612bcc57612bcc61420c565b604051908082528060200260200182016040528015612bf5578160200160208202803683370190505b50925060005b82811015612d54576000828281518110612c1757612c176145ba565b6020026020010151905060005b816001600160a01b0316868281518110612c4057612c406145ba565b60200260200101516001600160a01b0316108015612c8a575060006001600160a01b0316868281518110612c7657612c766145ba565b60200260200101516001600160a01b031614155b15612ca15780612c9981614f8f565b915050612c24565b825b81811115612d0b5786612cb7600183615217565b81518110612cc757612cc76145ba565b6020026020010151878281518110612ce157612ce16145ba565b6001600160a01b039092166020928302919091019091015280612d0381615249565b915050612ca3565b5081868281518110612d1f57612d1f6145ba565b60200260200101906001600160a01b031690816001600160a01b03168152505050508080612d4c90614f8f565b915050612bfb565b50505092915050565b60608267ffffffffffffffff811115612d7857612d7861420c565b604051908082528060200260200182016040528015612dbd57816020015b6040805180820190915260008082526020820152815260200190600190039081612d965790505b5090506000805b83518160ff161015612fef576000612ddd826001615260565b90505b84518160ff161015612fdc5760005b86811015612fc957878782818110612e0957612e096145ba565b612e1f9260206040909202019081019150614101565b6001600160a01b0316868460ff1681518110612e3d57612e3d6145ba565b60200260200101516001600160a01b0316148015612eb15750878782818110612e6857612e686145ba565b9050604002016020016020810190612e809190614101565b6001600160a01b0316868360ff1681518110612e9e57612e9e6145ba565b60200260200101516001600160a01b0316145b80612f715750878782818110612ec957612ec96145ba565b9050604002016020016020810190612ee19190614101565b6001600160a01b0316868460ff1681518110612eff57612eff6145ba565b60200260200101516001600160a01b0316148015612f715750878782818110612f2a57612f2a6145ba565b612f409260206040909202019081019150614101565b6001600160a01b0316868360ff1681518110612f5e57612f5e6145ba565b60200260200101516001600160a01b0316145b15612fb7576040805180820190915260ff8085168252831660208201528585612f9981614f8f565b965081518110612fab57612fab6145ba565b60200260200101819052505b80612fc181614f8f565b915050612def565b5080612fd481615279565b915050612de0565b5080612fe781615279565b915050612dc4565b50509392505050565b6060815167ffffffffffffffff8111156130145761301461420c565b60405190808252806020026020018201604052801561303d578160200160208202803683370190505b50905060005b8351811015610a225760005b848281518110613061576130616145ba565b6020026020010151600001516001600160a01b0316848281518110613088576130886145ba565b60200260200101516001600160a01b0316146130b057806130a881614f8f565b91505061304f565b8482815181106130c2576130c26145ba565b6020026020010151602001518382815181106130e0576130e06145ba565b602090810291909101015250806130f681614f8f565b915050613043565b606082471015613190576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401611ade565b6001600160a01b0385163b613201576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611ade565b600080866001600160a01b0316858760405161321d91906150c0565b60006040518083038185875af1925050503d806000811461325a576040519150601f19603f3d011682016040523d82523d6000602084013e61325f565b606091505b50915091506107ef8282865b6060831561327a575081610e91565b82511561328a5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ade9190615298565b600080826001600160a01b0316846001600160a01b0316106132e15782846132e4565b83835b909590945092505050565b60007fff0000000000000000000000000000000000000000000000000000000000000082167f0100000000000000000000000000000000000000000000000000000000000000036133425750603c919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f020000000000000000000000000000000000000000000000000000000000000003613394575061012c919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f0400000000000000000000000000000000000000000000000000000000000000036133e65750610384919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f0800000000000000000000000000000000000000000000000000000000000000036134385750610708919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f10000000000000000000000000000000000000000000000000000000000000000361348a5750610e10919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f2000000000000000000000000000000000000000000000000000000000000000036134dc5750613840919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f40000000000000000000000000000000000000000000000000000000000000000361352f575062015180919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f800000000000000000000000000000000000000000000000000000000000000003613582575062093a80919050565b6040517fbf3cad0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606061126a84846000856130fe565b6001600160a01b0381168114611ae757600080fd5b63ffffffff81168114611ae757600080fd5b80356135f5816135d8565b919050565b6000806000806080858703121561361057600080fd5b843561361b816135c3565b935060208501359250604085013591506060850135613639816135d8565b939692955090935050565b6000806040838503121561365757600080fd5b8235613662816135c3565b946020939093013593505050565b80356135f5816135c3565b60008060006060848603121561369057600080fd5b833561369b816135c3565b92506020840135915060408401356136b2816135c3565b809150509250925092565b60008083601f8401126136cf57600080fd5b50813567ffffffffffffffff8111156136e757600080fd5b6020830191508360208260051b850101111561370257600080fd5b9250929050565b803560ff811681146135f557600080fd5b60008060008060008060008060e0898b03121561373657600080fd5b8835613741816135c3565b9750602089013567ffffffffffffffff81111561375d57600080fd5b6137698b828c016136bd565b909850965050604089013594506060890135935061378960808a01613709565b925060a0890135915060c089013590509295985092959890939650565b600080602083850312156137b957600080fd5b823567ffffffffffffffff8111156137d057600080fd5b6137dc858286016136bd565b90969095509350505050565b602080825282518282018190526000919060409081850190868401855b8281101561383357815180516001600160a01b03168552860151868501529284019290850190600101613805565b5091979650505050505050565b6000806040838503121561385357600080fd5b823561385e816135c3565b9150602083013561386e816135c3565b809150509250929050565b6000806000806060858703121561388f57600080fd5b843561389a816135c3565b9350602085013567ffffffffffffffff8111156138b657600080fd5b6138c2878288016136bd565b9094509250506040850135613639816135c3565b6020808252825182820181905260009190848201906040850190845b8181101561390e578351835292840192918401916001016138f2565b50909695505050505050565b60008060006060848603121561392f57600080fd5b833561393a816135c3565b92506020840135915060408401356136b2816135d8565b60008083601f84011261396357600080fd5b50813567ffffffffffffffff81111561397b57600080fd5b6020830191508360208260061b850101111561370257600080fd5b8015158114611ae757600080fd5b60008083601f8401126139b657600080fd5b50813567ffffffffffffffff8111156139ce57600080fd5b60208301915083602082850101111561370257600080fd5b600080600080600080608087890312156139ff57600080fd5b8635613a0a816135c3565b9550602087013567ffffffffffffffff80821115613a2757600080fd5b613a338a838b01613951565b909750955060408901359150613a4882613996565b90935060608801359080821115613a5e57600080fd5b50613a6b89828a016139a4565b979a9699509497509295939492505050565b600060208083526060808401855160408085880152828251808552608094508489019150868401935060005b81811015613af657613ae68386516001600160a01b0381511682526020810151602083015260408101516040830152606081015160608301525050565b9387019391850191600101613aa9565b505088860151888203601f1901838a0152805180835290870193506000918701905b80831015613b9e57845180516001600160a01b03908116845289820151168984015284810151858401528781015188840152868101518784015260a0808201519084015260c0908101517fff000000000000000000000000000000000000000000000000000000000000001690830152938701936001929092019160e090910190613b18565b509998505050505050505050565b600080600060408486031215613bc157600080fd5b8335613bcc816135c3565b9250602084013567ffffffffffffffff811115613be857600080fd5b613bf486828701613951565b9497909650939450505050565b600060208083526060808401855160408085880152828251808552608094508489019150868401935060005b81811015613c7a57613c6a8386516001600160a01b0381511682526020810151602083015260408101516040830152606081015160608301525050565b9387019391850191600101613c2d565b505088860151888203601f1901838a0152805180835290870193506000918701905b80831015613b9e57845180516001600160a01b039081168452898201511689840152848101518584015287810151888401528601517fff000000000000000000000000000000000000000000000000000000000000001686830152938701936001929092019160a090910190613c9c565b60008060008060808587031215613d2357600080fd5b8435613d2e816135c3565b9350602085013592506040850135613d45816135c3565b91506060850135613639816135c3565b600080600080600080600060c0888a031215613d7057600080fd5b8735613d7b816135c3565b9650602088013567ffffffffffffffff811115613d9757600080fd5b613da38a828b016136bd565b90975095505060408801359350613dbc60608901613709565b92506080880135915060a0880135905092959891949750929550565b600060208284031215613dea57600080fd5b813567ffffffffffffffff811115613e0157600080fd5b820160a08185031215610e9157600080fd5b6000806000806000806000806000806101008b8d031215613e3357600080fd5b8a35613e3e816135c3565b995060208b0135613e4e816135c3565b985060408b0135613e5e816135c3565b975060608b0135613e6e816135d8565b965060808b0135613e7e816135d8565b9550613e8c60a08c01613670565b945060c08b013567ffffffffffffffff80821115613ea957600080fd5b613eb58e838f016136bd565b909650945060e08d0135915080821115613ece57600080fd5b50613edb8d828e016139a4565b915080935050809150509295989b9194979a5092959850565b60005b83811015613f0f578181015183820152602001613ef7565b50506000910152565b60008151808452613f30816020860160208601613ef4565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613fb7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613fa5858351613f18565b94509285019290850190600101613f6b565b5092979650505050505050565b60008060008060608587031215613fda57600080fd5b8435613fe5816135c3565b9350602085013567ffffffffffffffff81111561400157600080fd5b61400d87828801613951565b909450925050604085013561363981613996565b600080600080600080600080610100898b03121561403e57600080fd5b8835614049816135c3565b97506020890135614059816135c3565b96506040890135614069816135c3565b9550606089013594506080890135935061408560a08a01613709565b925060c0890135915060e089013590509295985092959890939650565b600080600080600060a086880312156140ba57600080fd5b85356140c5816135c3565b9450602086013593506040860135925060608601356140e3816135d8565b915060808601356140f3816135c3565b809150509295509295909350565b60006020828403121561411357600080fd5b8135610e91816135c3565b60008060008060008060008060008060006101208c8e03121561414057600080fd5b61414a8c356135c3565b8b359a5061415b60208d01356135c3565b60208c0135995061416e60408d01613670565b985060608c0135975061418360808d016135ea565b965061419160a08d016135ea565b955061419f60c08d01613670565b945067ffffffffffffffff8060e08e013511156141bb57600080fd5b6141cb8e60e08f01358f016136bd565b90955093506101008d01358110156141e257600080fd5b506141f48d6101008e01358e016139a4565b81935080925050509295989b509295989b9093969950565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561425e5761425e61420c565b60405290565b60405160e0810167ffffffffffffffff8111828210171561425e5761425e61420c565b60405160a0810167ffffffffffffffff8111828210171561425e5761425e61420c565b604051601f8201601f1916810167ffffffffffffffff811182821017156142d3576142d361420c565b604052919050565b80516135f5816135c3565b80516135f5816135d8565b80516effffffffffffffffffffffffffffff811681146135f557600080fd5b600061010080838503121561432457600080fd5b6040519081019067ffffffffffffffff821181831017156143475761434761420c565b8160405283519150614358826135c3565b818152614367602085016142db565b6020820152614378604085016142e6565b6040820152614389606085016142e6565b6060820152608084015160808201526143a460a085016142e6565b60a082015260c084015160c08201526143bf60e085016142f1565b60e0820152949350505050565b6000602082840312156143de57600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261441a57600080fd5b830160208101925035905067ffffffffffffffff81111561443a57600080fd5b8060051b360382131561370257600080fd5b60048110614483577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18336030181126144bb57600080fd5b90910192915050565b81835260006020808501808196508560051b810191508460005b878110156138335782840389526144f58288614487565b60408086018235614505816135c3565b6001600160a01b0316875261451c838901846143e5565b888a019390935290829052909150606086019060005b838110156145645781356004811061454957600080fd5b614553848261444c565b509188019190880190600101614532565b505099860199945050908401906001016144de565b60c08152600061458d60c08301898b6144c4565b602083019790975250604081019490945260ff929092166060840152608083015260a09091015292915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc183360301811261461d57600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261465c57600080fd5b83018035915067ffffffffffffffff82111561467757600080fd5b6020019150600581901b360382131561370257600080fd5b60408082528181018490526000906060808401600587811b860183018986805b8b811015614765577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08a85030186526146e8838e614487565b80356146f3816135c3565b6001600160a01b03168552602061470c828201836143e5565b92508a82880152828b8801527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115614744578485fd5b91871b918281888c01375096870196940187019392909201916001016146af565b5050506001600160a01b0388166020880152945061126a9350505050565b600067ffffffffffffffff82111561479d5761479d61420c565b5060051b60200190565b600060208083850312156147ba57600080fd5b825167ffffffffffffffff8111156147d157600080fd5b8301601f810185136147e257600080fd5b80516147f56147f082614783565b6142aa565b81815260059190911b8201830190838101908783111561481457600080fd5b928401925b828410156107ef57835182529284019290840190614819565b600081518084526020808501945080840160005b8381101561486b5781516001600160a01b031687529582019590820190600101614846565b509495945050505050565b600081518084526020808501945080840160005b8381101561486b578151805160ff90811689529084015116838801526040909601959082019060010161488a565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b6080815260006148f66080830188614832565b82810360208401526149088188614876565b9050851515604084015282810360608401526149258185876148b8565b98975050505050505050565b600061493f6147f084614783565b8381529050602080820190600785901b84018681111561495e57600080fd5b845b818110156149d857608080828a03121561497a5760008081fd5b604080519182019167ffffffffffffffff8311818410171561499e5761499e61420c565b9181528251916149ad836135c3565b9182528285015185830152808301519082015260608083015190820152845292820192608001614960565b505050509392505050565b80517fff00000000000000000000000000000000000000000000000000000000000000811681146135f557600080fd5b60006020808385031215614a2657600080fd5b825167ffffffffffffffff80821115614a3e57600080fd5b81850191506040808388031215614a5457600080fd5b614a5c61423b565b835183811115614a6b57600080fd5b8401601f81018913614a7c57600080fd5b614a8a898251888401614931565b8252508484015183811115614a9e57600080fd5b80850194505087601f850112614ab357600080fd5b83519250614ac36147f084614783565b83815260e0938402850186019386820191908a861115614ae257600080fd5b958701955b85871015614b6b5780878c031215614aff5760008081fd5b614b07614264565b8751614b12816135c3565b815287890151614b21816135c3565b818a01528786015186820152606080890151908201526080808901519082015260a0808901519082015260c0614b58818a016149e3565b9082015283529586019591870191614ae7565b5095820195909552979650505050505050565b604081526000614b916040830185614832565b8281036020840152610b798185614876565b60006020808385031215614bb657600080fd5b825167ffffffffffffffff80821115614bce57600080fd5b81850191506040808388031215614be457600080fd5b614bec61423b565b835183811115614bfb57600080fd5b8401601f81018913614c0c57600080fd5b614c1a898251888401614931565b8252508484015183811115614c2e57600080fd5b80850194505087601f850112614c4357600080fd5b83519250614c536147f084614783565b83815260a0938402850186019386820191908a861115614c7257600080fd5b958701955b85871015614b6b5780878c031215614c8f5760008081fd5b614c97614287565b8751614ca2816135c3565b815287890151614cb1816135c3565b818a01528786015186820152606080890151908201526080614cd4818a016149e3565b9082015283529586019591870191614c77565b60008060408385031215614cfa57600080fd5b505080516020909101519092909150565b60a08082528101869052600060c0600588901b8301810190830189835b8a811015614d9f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff40868503018352614d61828d614487565b6040813586526020614d75818401846143e5565b93508282890152614d8983890185836144c4565b9750509485019493909301925050600101614d28565b5050506020830187905260ff861660408401529050606082019390935260800152949350505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614dfd57600080fd5b83018035915067ffffffffffffffff821115614e1857600080fd5b60200191503681900382131561370257600080fd5b60006001600160a01b03808b168352808a16602084015288604084015263ffffffff808916606085015280881660808501525080861660a08401525060e060c0830152614e7e60e0830184866144c4565b9a9950505050505050505050565b6001600160a01b038b811682528a81166020830152604082018a905263ffffffff898116606084015288166080830152861660a082015261010060c08201819052600090614edd83820187896144c4565b905082810360e0840152614ef28185876148b8565b9d9c50505050505050505050505050565b600060208284031215614f1557600080fd5b8151610e91816135c3565b8381526001600160a01b03831660208201526060810161126a604083018461444c565b600060208284031215614f5557600080fd5b8151610e9181613996565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006000198203614fa257614fa2614f60565b5060010190565b600060408236031215614fbb57600080fd5b614fc361423b565b8235614fce816135c3565b815260208381013567ffffffffffffffff811115614feb57600080fd5b840136601f820112614ffc57600080fd5b803561500a6147f082614783565b81815260059190911b8201830190838101903683111561502957600080fd5b928401925b82841015615050578335615041816135c3565b8252928401929084019061502e565b938501939093525091949350505050565b60006040828403121561507357600080fd5b6040516040810181811067ffffffffffffffff821117156150965761509661420c565b60405282356150a4816135c3565b815260208301356150b4816135c3565b60208201529392505050565b6000825161461d818460208701613ef4565b6000602082840312156150e457600080fd5b610e91826149e3565b80517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681146135f557600080fd5b6000806000806080858703121561512f57600080fd5b845161513a816135d8565b9350615148602086016150ed565b92506040850151615158816135d8565b9150615166606086016150ed565b905092959194509250565b600063ffffffff808416806151af577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b92169190910492915050565b63ffffffff818116838216019080821115610a2257610a22614f60565b600063ffffffff808316818516818304811182151516156151fb576151fb614f60565b02949350505050565b8082018082111561125657611256614f60565b8181038181111561125657611256614f60565b600081600019048311821515161561524457615244614f60565b500290565b60008161525857615258614f60565b506000190190565b60ff818116838216019081111561125657611256614f60565b600060ff821660ff810361528f5761528f614f60565b60010192915050565b602081526000610e916020830184613f1856fe416464726573733a206c6f772d6c6576656c2063616c6c20776974682076616c7565206661696c6564416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220c76d8001a5c6954cc4414f5a78ee7f4ca6cbae120c7c9e6ae4337c2b67b01cc264736f6c63430008100033000000000000000000000000d6c8fd8100252f0a314407c26e7a47286f7fda24000000000000000000000000ec864be26084ba3bbf3caacf8f6961a9263319c4
Deployed Bytecode
0x6080604052600436106101c65760003560e01c80635f963dcf116100f7578063d339056d11610095578063e43581b811610064578063e43581b8146104e2578063e9c0407114610511578063f235757f14610531578063fa0c95551461055157600080fd5b8063d339056d1461045d578063db8266de14610470578063df08aed514610483578063e3056a34146104c257600080fd5b806389352328116100d157806389352328146103d6578063ac9650d8146103e9578063b3b48afb14610409578063bb2871a51461043d57600080fd5b80635f963dcf1461038857806362dd9af3146103b057806385f44632146103c357600080fd5b8063340b532f1161016457806340c5710c1161013e57806340c5710c146102f3578063484b3577146103065780635684c27514610333578063585cc6a51461036057600080fd5b8063340b532f146102ad57806335ac2a50146102c05780633a79d674146102e057600080fd5b806313f6986d116101a057806313f6986d146102375780631f66925c1461024c5780631f8b479d1461026d5780632d2ae1c11461028057600080fd5b806305ce20d6146101d25780630c340a24146101e757806312b17e351461022457600080fd5b366101cd57005b600080fd5b6101e56101e03660046135fa565b610564565b005b3480156101f357600080fd5b50600054610207906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101e5610232366004613644565b610698565b34801561024357600080fd5b506101e56106a6565b61025f61025a36600461367b565b610752565b60405190815260200161021b565b6101e561027b36600461371a565b6107fa565b34801561028c57600080fd5b506102a061029b3660046137a6565b61084b565b60405161021b91906137e8565b6101e56102bb366004613840565b610a29565b6102d36102ce366004613879565b610a33565b60405161021b91906138d6565b6101e56102ee36600461367b565b610b82565b6101e561030136600461391a565b610b92565b34801561031257600080fd5b506103266103213660046139e6565b610d15565b60405161021b9190613a7d565b34801561033f57600080fd5b5061035361034e366004613bac565b610dda565b60405161021b9190613c01565b34801561036c57600080fd5b5061020773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b61039b610396366004613d0d565b610e98565b6040805192835260208301919091520161021b565b6101e56103be366004613d55565b610f4d565b6101e56103d1366004613dd8565b610fd7565b61025f6103e4366004613e13565b6110c8565b6103fc6103f73660046137a6565b611173565b60405161021b9190613f44565b34801561041557600080fd5b506102077f000000000000000000000000d6c8fd8100252f0a314407c26e7a47286f7fda2481565b34801561044957600080fd5b506102d3610458366004613fc4565b61125c565b6101e561046b366004614021565b611272565b6101e561047e3660046140a2565b6112e6565b34801561048f57600080fd5b506104b261049e366004614101565b6001546001600160a01b0391821691161490565b604051901515815260200161021b565b3480156104ce57600080fd5b50600154610207906001600160a01b031681565b3480156104ee57600080fd5b506104b26104fd366004614101565b6000546001600160a01b0391821691161490565b34801561051d57600080fd5b506101e561052c3660046137a6565b611356565b34801561053d57600080fd5b506101e561054c366004614101565b6113a4565b61025f61055f36600461411e565b611454565b8383600061057383838361159b565b6040517f5b6fd01d000000000000000000000000000000000000000000000000000000008152600481018790526000906001600160a01b03891690635b6fd01d9060240161010060405180830381865afa1580156105d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f99190614310565b5190506106078189886116a3565b6040517fded700a6000000000000000000000000000000000000000000000000000000008152600481018890526024810187905263ffffffff861660448201526001600160a01b0389169063ded700a6906064015b600060405180830381600087803b15801561067657600080fd5b505af115801561068a573d6000803e3d6000fd5b505050505050505050505050565b6106a28282611863565b5050565b6001546001600160a01b031633146106ea576040517f9ba0305d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018054600080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081166001600160a01b0384161782559091169091556040517fdc57ca23c46d823853915ed5a090ca0ee9db5eb6a46f5c58e1c9158de861fd769190a1565b60008383600261076383838361159b565b6040517f17621890000000000000000000000000000000000000000000000000000000008152600481018790526001600160a01b0386811660248301528816906317621890906044016020604051808303816000875af11580156107cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ef91906143cc565b979650505050505050565b6040517f4faa38830000000000000000000000000000000000000000000000000000000081526001600160a01b03891690634faa38839061065c908a908a908a908a908a908a908a90600401614579565b60608167ffffffffffffffff8111156108665761086661420c565b6040519080825280602002602001820160405280156108ab57816020015b60408051808201909152600080825260208201528152602001906001900390816108845790505b50905060005b82811015610a2257600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8585848181106108e2576108e26145ba565b90506020020160208101906108f79190614101565b6001600160a01b0316146109b457848483818110610917576109176145ba565b905060200201602081019061092c9190614101565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa15801561098b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109af91906143cc565b6109b6565b475b905060405180604001604052808686858181106109d5576109d56145ba565b90506020020160208101906109ea9190614101565b6001600160a01b0316815260200182815250838381518110610a0e57610a0e6145ba565b6020908102919091010152506001016108b1565b5092915050565b6106a28282611878565b606060005b83811015610ae8576000858583818110610a5457610a546145ba565b9050602002810190610a6691906145e9565b610a74906020810190614627565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201829052509394505050505b8151811015610ade57610ad688838381518110610ac757610ac76145ba565b6020026020010151600261159b565b600101610aa8565b5050600101610a38565b506040517f480b37960000000000000000000000000000000000000000000000000000000081526001600160a01b0386169063480b379690610b329087908790879060040161468f565b6000604051808303816000875af1158015610b51573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b7991908101906147a7565b95945050505050565b610b8d838383611935565b505050565b82826000610ba183838361159b565b6040517f5b6fd01d000000000000000000000000000000000000000000000000000000008152600481018690526000906001600160a01b03881690635b6fd01d9060240161010060405180830381865afa158015610c03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c279190614310565b516040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610c8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610caf91906143cc565b9050610cbc8289836116a3565b6040517fded700a6000000000000000000000000000000000000000000000000000000008152600481018890526024810182905263ffffffff871660448201526001600160a01b0389169063ded700a69060640161065c565b6040805180820190915260608082526020820152600080610d36888861199d565b6040517f4997cdc300000000000000000000000000000000000000000000000000000000815291935091506001600160a01b038a1690634997cdc390610d8890859085908b908b908b906004016148e3565b600060405180830381865afa158015610da5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610dcd9190810190614a13565b9998505050505050505050565b6040805180820190915260608082526020820152600080610dfb858561199d565b6040517fd2d95b2d00000000000000000000000000000000000000000000000000000000815291935091506001600160a01b0387169063d2d95b2d90610e479085908590600401614b7e565b600060405180830381865afa158015610e64573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e8c9190810190614ba3565b925050505b9392505050565b60008085856003610eaa83838361159b565b6040517f72ada4c5000000000000000000000000000000000000000000000000000000008152600481018990526001600160a01b03888116602483015287811660448301528a16906372ada4c59060640160408051808303816000875af1158015610f19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3d9190614ce7565b909a909950975050505050505050565b6040517f3dff05870000000000000000000000000000000000000000000000000000000081526001600160a01b03881690633dff058790610f9c90899089908990899089908990600401614d0b565b600060405180830381600087803b158015610fb657600080fd5b505af1158015610fca573d6000803e3d6000fd5b5050505050505050505050565b610fe46020820182614101565b610fed816119fe565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6110126080840160608501614101565b6001600160a01b031603611047576106a26110306020840184614101565b61103d6040850185614dc8565b8560800135611aea565b6110a461105a6080840160608501614101565b61106a6040850160208601614101565b61107a6040860160208701614101565b6001600160a01b03166110906020870187614101565b6001600160a01b0316148560800135611b35565b6106a26110b46020840184614101565b6110c16040850185614dc8565b6000611aea565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009081906001600160a01b038c16906370a0823190602401602060405180830381865afa15801561112a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114e91906143cc565b90506111638c8c8c848d8d8d8d8d8d8d611454565b9c9b505050505050505050505050565b60608167ffffffffffffffff81111561118e5761118e61420c565b6040519080825280602002602001820160405280156111c157816020015b60608152602001906001900390816111ac5790505b50905060005b82811015610a2257611231308585848181106111e5576111e56145ba565b90506020028101906111f79190614dc8565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611df492505050565b828281518110611243576112436145ba565b60209081029190910101526001016111c7565b92915050565b6060610b7985858585611e19565b949350505050565b6040517fd505accf0000000000000000000000000000000000000000000000000000000081526001600160a01b0388811660048301528781166024830152604482018790526064820186905260ff8516608483015260a4820184905260c4820183905289169063d505accf9060e40161065c565b848460016112f583838361159b565b6040517ff1accf39000000000000000000000000000000000000000000000000000000008152600481018890526024810187905263ffffffff861660448201526001600160a01b03858116606483015289169063f1accf399060840161065c565b6000546001600160a01b0316331461139a576040517fe0a8b92000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6106a28282611eff565b6000546001600160a01b031633146113e8576040517fe0a8b92000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f56bddfa0cee9697cebddf9acd7f23dc6583663b05e007b877056d05017994def9060200160405180910390a150565b60006114618b8d8b6116a3565b81611501576040517f6b29e1bd0000000000000000000000000000000000000000000000000000000081526001600160a01b038d1690636b29e1bd906114b9908e908e908e908e908e908e908e908e90600401614e2d565b6020604051808303816000875af11580156114d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114fc91906143cc565b611163565b6040517fb2b513c10000000000000000000000000000000000000000000000000000000081526001600160a01b038d169063b2b513c190611558908e908e908e908e908e908e908e908e908e908e90600401614e8c565b6020604051808303816000875af1158015611577573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061116391906143cc565b826001600160a01b031663cc7a20496040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115fd9190614f03565b6001600160a01b031663823abfd98333846040518463ffffffff1660e01b815260040161162c93929190614f20565b602060405180830381865afa158015611649573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061166d9190614f43565b610b8d576040517f5c427cd900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa15801561170c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061173091906143cc565b90508181101561185d5780156117ce576040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301526000602483015285169063095ea7b3906044016020604051808303816000875af11580156117a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117cc9190614f43565b505b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152600019602483015285169063095ea7b3906044016020604051808303816000875af1158015611837573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185b9190614f43565b505b50505050565b6106a26001600160a01b03831633308461200d565b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611924576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156118fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061191f91906143cc565b611926565b475b90508015610b8d57610b8d8382845b6001600160a01b0381166119465750335b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161198957610b8d6001600160a01b038216836120be565b610b8d6001600160a01b038416828461220b565b6060806119f2848460006040519080825280602002602001820160405280156119ec57816020015b60408051808201909152600080825260208201528152602001906001900390816119c55790505b50612254565b50909590945092505050565b6040517fcb00d85f0000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301527f000000000000000000000000d6c8fd8100252f0a314407c26e7a47286f7fda24169063cb00d85f90602401602060405180830381865afa158015611a7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa19190614f43565b611ae7576040517f220d24fd0000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024015b60405180910390fd5b50565b61185b83838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050506001600160a01b038716919050836122d9565b6001600160a01b0383161561185d576040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0384811660248301526000919086169063dd62ed3e90604401602060405180830381865afa158015611bad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd191906143cc565b90508181101561185b5782158015611c8957506040517f344cb9cd0000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301527f000000000000000000000000d6c8fd8100252f0a314407c26e7a47286f7fda24169063344cb9cd90602401602060405180830381865afa158015611c63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c879190614f43565b155b15611ccb576040517f1f0b33c30000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611ade565b8015611d5f576040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301526000602483015286169063095ea7b3906044016020604051808303816000875af1158015611d39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d5d9190614f43565b505b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b038581166004830152600019602483015286169063095ea7b3906044016020604051808303816000875af1158015611dc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dec9190614f43565b505050505050565b6060610e9183836040518060600160405280602781526020016152d5602791396122ff565b60608267ffffffffffffffff811115611e3457611e3461420c565b604051908082528060200260200182016040528015611e5d578160200160208202803683370190505b50905060005b83811015611ef657611ec786868684818110611e8157611e816145ba565b611e979260206040909202019081019150614101565b878785818110611ea957611ea96145ba565b9050604002016020016020810190611ec19190614101565b86612403565b828281518110611ed957611ed96145ba565b602090810291909101015280611eee81614f8f565b915050611e63565b50949350505050565b60005b81811015610b8d576000838383818110611f1e57611f1e6145ba565b9050602002810190611f3091906145e9565b611f3990614fa9565b905060005b8160200151518110156120035781602001518181518110611f6157611f616145ba565b602090810291909101015182516040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201526000602482015291169063095ea7b3906044016020604051808303816000875af1158015611fd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ffa9190614f43565b50600101611f3e565b5050600101611f02565b6040516001600160a01b038085166024830152831660448201526064810182905261185d9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915261277a565b80471015612128576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401611ade565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612175576040519150601f19603f3d011682016040523d82523d6000602084013e61217a565b606091505b5050905080610b8d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401611ade565b6040516001600160a01b038316602482015260448101829052610b8d9084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161205a565b60608060606122b58686808060200260200160405190810160405280939291908181526020016000905b828210156122aa5761229b60408302860136819003810190615061565b8152602001906001019061227e565b505050505085612879565b92506122c2868685612d5d565b91506122ce8484612ff8565b905093509350939050565b606061126a8484846040518060600160405280602981526020016152ac602991396130fe565b60606001600160a01b0384163b612398576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e747261637400000000000000000000000000000000000000000000000000006064820152608401611ade565b600080856001600160a01b0316856040516123b391906150c0565b600060405180830381855af49150503d80600081146123ee576040519150601f19603f3d011682016040523d82523d6000602084013e6123f3565b606091505b5091509150610e8c82828661326b565b600080600061241286866132be565b6040517f582cf84b0000000000000000000000000000000000000000000000000000000081526001600160a01b038084166004830152808316602483015292945090925060009189169063582cf84b90604401602060405180830381865afa158015612482573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124a691906150d2565b90507f010000000000000000000000000000000000000000000000000000000000000060005b7fff000000000000000000000000000000000000000000000000000000000000008083169084161080159061252257507fff00000000000000000000000000000000000000000000000000000000000000821615155b1561276957817effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168284167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361273b576040517f808ba8e00000000000000000000000000000000000000000000000000000000081526001600160a01b038a8116600483015289811660248301527fff000000000000000000000000000000000000000000000000000000000000008416604483015260009182918291908e169063808ba8e090606401608060405180830381865afa15801561260b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061262f9190615119565b935093509350506000612641866132ef565b90506000816126508186615171565b61265b9060016151bb565b61266591906151d8565b63ffffffff1690508b6126905761267d600383615171565b61268d9063ffffffff1682615204565b90505b6000857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1611806126db57506000837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16115b15612714574281116126f957859a505050505050505050505061126a565b6127034282615217565b9a505050505050505050505061126a565b428111156127355785156127285785612732565b6127324282615217565b95505b50505050505b6001827effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916901b91506124cc565b506000199998505050505050505050565b60006127cf826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166135b49092919063ffffffff16565b805190915015610b8d57808060200190518101906127ed9190614f43565b610b8d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401611ade565b606060008083518551600261288e919061522a565b6128989190615204565b67ffffffffffffffff8111156128b0576128b061420c565b6040519080825280602002602001820160405280156128d9578160200160208202803683370190505b50905060005b8551811015612ab35760008060005b858110801561290457508280156129025750815b155b156129d9578215801561295e5750888481518110612924576129246145ba565b6020026020010151600001516001600160a01b031685828151811061294b5761294b6145ba565b60200260200101516001600160a01b0316145b1561296857600192505b811580156129bd5750888481518110612983576129836145ba565b6020026020010151602001516001600160a01b03168582815181106129aa576129aa6145ba565b60200260200101516001600160a01b0316145b156129c757600191505b806129d181614f8f565b9150506128ee565b5081612a3c578783815181106129f1576129f16145ba565b602002602001015160000151848680612a0990614f8f565b975081518110612a1b57612a1b6145ba565b60200260200101906001600160a01b031690816001600160a01b0316815250505b80612a9e57878381518110612a5357612a536145ba565b602002602001015160200151848680612a6b90614f8f565b975081518110612a7d57612a7d6145ba565b60200260200101906001600160a01b031690816001600160a01b0316815250505b50508080612aab90614f8f565b9150506128df565b5060005b8451811015612bb2576000805b8481108015612ad1575081155b15612b3c57868381518110612ae857612ae86145ba565b6020026020010151600001516001600160a01b0316848281518110612b0f57612b0f6145ba565b60200260200101516001600160a01b031603612b2a57600191505b80612b3481614f8f565b915050612ac4565b5080612b9f57858281518110612b5457612b546145ba565b602002602001015160000151838580612b6c90614f8f565b965081518110612b7e57612b7e6145ba565b60200260200101906001600160a01b031690816001600160a01b0316815250505b5080612baa81614f8f565b915050612ab7565b508167ffffffffffffffff811115612bcc57612bcc61420c565b604051908082528060200260200182016040528015612bf5578160200160208202803683370190505b50925060005b82811015612d54576000828281518110612c1757612c176145ba565b6020026020010151905060005b816001600160a01b0316868281518110612c4057612c406145ba565b60200260200101516001600160a01b0316108015612c8a575060006001600160a01b0316868281518110612c7657612c766145ba565b60200260200101516001600160a01b031614155b15612ca15780612c9981614f8f565b915050612c24565b825b81811115612d0b5786612cb7600183615217565b81518110612cc757612cc76145ba565b6020026020010151878281518110612ce157612ce16145ba565b6001600160a01b039092166020928302919091019091015280612d0381615249565b915050612ca3565b5081868281518110612d1f57612d1f6145ba565b60200260200101906001600160a01b031690816001600160a01b03168152505050508080612d4c90614f8f565b915050612bfb565b50505092915050565b60608267ffffffffffffffff811115612d7857612d7861420c565b604051908082528060200260200182016040528015612dbd57816020015b6040805180820190915260008082526020820152815260200190600190039081612d965790505b5090506000805b83518160ff161015612fef576000612ddd826001615260565b90505b84518160ff161015612fdc5760005b86811015612fc957878782818110612e0957612e096145ba565b612e1f9260206040909202019081019150614101565b6001600160a01b0316868460ff1681518110612e3d57612e3d6145ba565b60200260200101516001600160a01b0316148015612eb15750878782818110612e6857612e686145ba565b9050604002016020016020810190612e809190614101565b6001600160a01b0316868360ff1681518110612e9e57612e9e6145ba565b60200260200101516001600160a01b0316145b80612f715750878782818110612ec957612ec96145ba565b9050604002016020016020810190612ee19190614101565b6001600160a01b0316868460ff1681518110612eff57612eff6145ba565b60200260200101516001600160a01b0316148015612f715750878782818110612f2a57612f2a6145ba565b612f409260206040909202019081019150614101565b6001600160a01b0316868360ff1681518110612f5e57612f5e6145ba565b60200260200101516001600160a01b0316145b15612fb7576040805180820190915260ff8085168252831660208201528585612f9981614f8f565b965081518110612fab57612fab6145ba565b60200260200101819052505b80612fc181614f8f565b915050612def565b5080612fd481615279565b915050612de0565b5080612fe781615279565b915050612dc4565b50509392505050565b6060815167ffffffffffffffff8111156130145761301461420c565b60405190808252806020026020018201604052801561303d578160200160208202803683370190505b50905060005b8351811015610a225760005b848281518110613061576130616145ba565b6020026020010151600001516001600160a01b0316848281518110613088576130886145ba565b60200260200101516001600160a01b0316146130b057806130a881614f8f565b91505061304f565b8482815181106130c2576130c26145ba565b6020026020010151602001518382815181106130e0576130e06145ba565b602090810291909101015250806130f681614f8f565b915050613043565b606082471015613190576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401611ade565b6001600160a01b0385163b613201576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611ade565b600080866001600160a01b0316858760405161321d91906150c0565b60006040518083038185875af1925050503d806000811461325a576040519150601f19603f3d011682016040523d82523d6000602084013e61325f565b606091505b50915091506107ef8282865b6060831561327a575081610e91565b82511561328a5782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ade9190615298565b600080826001600160a01b0316846001600160a01b0316106132e15782846132e4565b83835b909590945092505050565b60007fff0000000000000000000000000000000000000000000000000000000000000082167f0100000000000000000000000000000000000000000000000000000000000000036133425750603c919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f020000000000000000000000000000000000000000000000000000000000000003613394575061012c919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f0400000000000000000000000000000000000000000000000000000000000000036133e65750610384919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f0800000000000000000000000000000000000000000000000000000000000000036134385750610708919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f10000000000000000000000000000000000000000000000000000000000000000361348a5750610e10919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f2000000000000000000000000000000000000000000000000000000000000000036134dc5750613840919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f40000000000000000000000000000000000000000000000000000000000000000361352f575062015180919050565b7fff0000000000000000000000000000000000000000000000000000000000000082167f800000000000000000000000000000000000000000000000000000000000000003613582575062093a80919050565b6040517fbf3cad0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606061126a84846000856130fe565b6001600160a01b0381168114611ae757600080fd5b63ffffffff81168114611ae757600080fd5b80356135f5816135d8565b919050565b6000806000806080858703121561361057600080fd5b843561361b816135c3565b935060208501359250604085013591506060850135613639816135d8565b939692955090935050565b6000806040838503121561365757600080fd5b8235613662816135c3565b946020939093013593505050565b80356135f5816135c3565b60008060006060848603121561369057600080fd5b833561369b816135c3565b92506020840135915060408401356136b2816135c3565b809150509250925092565b60008083601f8401126136cf57600080fd5b50813567ffffffffffffffff8111156136e757600080fd5b6020830191508360208260051b850101111561370257600080fd5b9250929050565b803560ff811681146135f557600080fd5b60008060008060008060008060e0898b03121561373657600080fd5b8835613741816135c3565b9750602089013567ffffffffffffffff81111561375d57600080fd5b6137698b828c016136bd565b909850965050604089013594506060890135935061378960808a01613709565b925060a0890135915060c089013590509295985092959890939650565b600080602083850312156137b957600080fd5b823567ffffffffffffffff8111156137d057600080fd5b6137dc858286016136bd565b90969095509350505050565b602080825282518282018190526000919060409081850190868401855b8281101561383357815180516001600160a01b03168552860151868501529284019290850190600101613805565b5091979650505050505050565b6000806040838503121561385357600080fd5b823561385e816135c3565b9150602083013561386e816135c3565b809150509250929050565b6000806000806060858703121561388f57600080fd5b843561389a816135c3565b9350602085013567ffffffffffffffff8111156138b657600080fd5b6138c2878288016136bd565b9094509250506040850135613639816135c3565b6020808252825182820181905260009190848201906040850190845b8181101561390e578351835292840192918401916001016138f2565b50909695505050505050565b60008060006060848603121561392f57600080fd5b833561393a816135c3565b92506020840135915060408401356136b2816135d8565b60008083601f84011261396357600080fd5b50813567ffffffffffffffff81111561397b57600080fd5b6020830191508360208260061b850101111561370257600080fd5b8015158114611ae757600080fd5b60008083601f8401126139b657600080fd5b50813567ffffffffffffffff8111156139ce57600080fd5b60208301915083602082850101111561370257600080fd5b600080600080600080608087890312156139ff57600080fd5b8635613a0a816135c3565b9550602087013567ffffffffffffffff80821115613a2757600080fd5b613a338a838b01613951565b909750955060408901359150613a4882613996565b90935060608801359080821115613a5e57600080fd5b50613a6b89828a016139a4565b979a9699509497509295939492505050565b600060208083526060808401855160408085880152828251808552608094508489019150868401935060005b81811015613af657613ae68386516001600160a01b0381511682526020810151602083015260408101516040830152606081015160608301525050565b9387019391850191600101613aa9565b505088860151888203601f1901838a0152805180835290870193506000918701905b80831015613b9e57845180516001600160a01b03908116845289820151168984015284810151858401528781015188840152868101518784015260a0808201519084015260c0908101517fff000000000000000000000000000000000000000000000000000000000000001690830152938701936001929092019160e090910190613b18565b509998505050505050505050565b600080600060408486031215613bc157600080fd5b8335613bcc816135c3565b9250602084013567ffffffffffffffff811115613be857600080fd5b613bf486828701613951565b9497909650939450505050565b600060208083526060808401855160408085880152828251808552608094508489019150868401935060005b81811015613c7a57613c6a8386516001600160a01b0381511682526020810151602083015260408101516040830152606081015160608301525050565b9387019391850191600101613c2d565b505088860151888203601f1901838a0152805180835290870193506000918701905b80831015613b9e57845180516001600160a01b039081168452898201511689840152848101518584015287810151888401528601517fff000000000000000000000000000000000000000000000000000000000000001686830152938701936001929092019160a090910190613c9c565b60008060008060808587031215613d2357600080fd5b8435613d2e816135c3565b9350602085013592506040850135613d45816135c3565b91506060850135613639816135c3565b600080600080600080600060c0888a031215613d7057600080fd5b8735613d7b816135c3565b9650602088013567ffffffffffffffff811115613d9757600080fd5b613da38a828b016136bd565b90975095505060408801359350613dbc60608901613709565b92506080880135915060a0880135905092959891949750929550565b600060208284031215613dea57600080fd5b813567ffffffffffffffff811115613e0157600080fd5b820160a08185031215610e9157600080fd5b6000806000806000806000806000806101008b8d031215613e3357600080fd5b8a35613e3e816135c3565b995060208b0135613e4e816135c3565b985060408b0135613e5e816135c3565b975060608b0135613e6e816135d8565b965060808b0135613e7e816135d8565b9550613e8c60a08c01613670565b945060c08b013567ffffffffffffffff80821115613ea957600080fd5b613eb58e838f016136bd565b909650945060e08d0135915080821115613ece57600080fd5b50613edb8d828e016139a4565b915080935050809150509295989b9194979a5092959850565b60005b83811015613f0f578181015183820152602001613ef7565b50506000910152565b60008151808452613f30816020860160208601613ef4565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613fb7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452613fa5858351613f18565b94509285019290850190600101613f6b565b5092979650505050505050565b60008060008060608587031215613fda57600080fd5b8435613fe5816135c3565b9350602085013567ffffffffffffffff81111561400157600080fd5b61400d87828801613951565b909450925050604085013561363981613996565b600080600080600080600080610100898b03121561403e57600080fd5b8835614049816135c3565b97506020890135614059816135c3565b96506040890135614069816135c3565b9550606089013594506080890135935061408560a08a01613709565b925060c0890135915060e089013590509295985092959890939650565b600080600080600060a086880312156140ba57600080fd5b85356140c5816135c3565b9450602086013593506040860135925060608601356140e3816135d8565b915060808601356140f3816135c3565b809150509295509295909350565b60006020828403121561411357600080fd5b8135610e91816135c3565b60008060008060008060008060008060006101208c8e03121561414057600080fd5b61414a8c356135c3565b8b359a5061415b60208d01356135c3565b60208c0135995061416e60408d01613670565b985060608c0135975061418360808d016135ea565b965061419160a08d016135ea565b955061419f60c08d01613670565b945067ffffffffffffffff8060e08e013511156141bb57600080fd5b6141cb8e60e08f01358f016136bd565b90955093506101008d01358110156141e257600080fd5b506141f48d6101008e01358e016139a4565b81935080925050509295989b509295989b9093969950565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561425e5761425e61420c565b60405290565b60405160e0810167ffffffffffffffff8111828210171561425e5761425e61420c565b60405160a0810167ffffffffffffffff8111828210171561425e5761425e61420c565b604051601f8201601f1916810167ffffffffffffffff811182821017156142d3576142d361420c565b604052919050565b80516135f5816135c3565b80516135f5816135d8565b80516effffffffffffffffffffffffffffff811681146135f557600080fd5b600061010080838503121561432457600080fd5b6040519081019067ffffffffffffffff821181831017156143475761434761420c565b8160405283519150614358826135c3565b818152614367602085016142db565b6020820152614378604085016142e6565b6040820152614389606085016142e6565b6060820152608084015160808201526143a460a085016142e6565b60a082015260c084015160c08201526143bf60e085016142f1565b60e0820152949350505050565b6000602082840312156143de57600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261441a57600080fd5b830160208101925035905067ffffffffffffffff81111561443a57600080fd5b8060051b360382131561370257600080fd5b60048110614483577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18336030181126144bb57600080fd5b90910192915050565b81835260006020808501808196508560051b810191508460005b878110156138335782840389526144f58288614487565b60408086018235614505816135c3565b6001600160a01b0316875261451c838901846143e5565b888a019390935290829052909150606086019060005b838110156145645781356004811061454957600080fd5b614553848261444c565b509188019190880190600101614532565b505099860199945050908401906001016144de565b60c08152600061458d60c08301898b6144c4565b602083019790975250604081019490945260ff929092166060840152608083015260a09091015292915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc183360301811261461d57600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261465c57600080fd5b83018035915067ffffffffffffffff82111561467757600080fd5b6020019150600581901b360382131561370257600080fd5b60408082528181018490526000906060808401600587811b860183018986805b8b811015614765577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08a85030186526146e8838e614487565b80356146f3816135c3565b6001600160a01b03168552602061470c828201836143e5565b92508a82880152828b8801527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115614744578485fd5b91871b918281888c01375096870196940187019392909201916001016146af565b5050506001600160a01b0388166020880152945061126a9350505050565b600067ffffffffffffffff82111561479d5761479d61420c565b5060051b60200190565b600060208083850312156147ba57600080fd5b825167ffffffffffffffff8111156147d157600080fd5b8301601f810185136147e257600080fd5b80516147f56147f082614783565b6142aa565b81815260059190911b8201830190838101908783111561481457600080fd5b928401925b828410156107ef57835182529284019290840190614819565b600081518084526020808501945080840160005b8381101561486b5781516001600160a01b031687529582019590820190600101614846565b509495945050505050565b600081518084526020808501945080840160005b8381101561486b578151805160ff90811689529084015116838801526040909601959082019060010161488a565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b6080815260006148f66080830188614832565b82810360208401526149088188614876565b9050851515604084015282810360608401526149258185876148b8565b98975050505050505050565b600061493f6147f084614783565b8381529050602080820190600785901b84018681111561495e57600080fd5b845b818110156149d857608080828a03121561497a5760008081fd5b604080519182019167ffffffffffffffff8311818410171561499e5761499e61420c565b9181528251916149ad836135c3565b9182528285015185830152808301519082015260608083015190820152845292820192608001614960565b505050509392505050565b80517fff00000000000000000000000000000000000000000000000000000000000000811681146135f557600080fd5b60006020808385031215614a2657600080fd5b825167ffffffffffffffff80821115614a3e57600080fd5b81850191506040808388031215614a5457600080fd5b614a5c61423b565b835183811115614a6b57600080fd5b8401601f81018913614a7c57600080fd5b614a8a898251888401614931565b8252508484015183811115614a9e57600080fd5b80850194505087601f850112614ab357600080fd5b83519250614ac36147f084614783565b83815260e0938402850186019386820191908a861115614ae257600080fd5b958701955b85871015614b6b5780878c031215614aff5760008081fd5b614b07614264565b8751614b12816135c3565b815287890151614b21816135c3565b818a01528786015186820152606080890151908201526080808901519082015260a0808901519082015260c0614b58818a016149e3565b9082015283529586019591870191614ae7565b5095820195909552979650505050505050565b604081526000614b916040830185614832565b8281036020840152610b798185614876565b60006020808385031215614bb657600080fd5b825167ffffffffffffffff80821115614bce57600080fd5b81850191506040808388031215614be457600080fd5b614bec61423b565b835183811115614bfb57600080fd5b8401601f81018913614c0c57600080fd5b614c1a898251888401614931565b8252508484015183811115614c2e57600080fd5b80850194505087601f850112614c4357600080fd5b83519250614c536147f084614783565b83815260a0938402850186019386820191908a861115614c7257600080fd5b958701955b85871015614b6b5780878c031215614c8f5760008081fd5b614c97614287565b8751614ca2816135c3565b815287890151614cb1816135c3565b818a01528786015186820152606080890151908201526080614cd4818a016149e3565b9082015283529586019591870191614c77565b60008060408385031215614cfa57600080fd5b505080516020909101519092909150565b60a08082528101869052600060c0600588901b8301810190830189835b8a811015614d9f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff40868503018352614d61828d614487565b6040813586526020614d75818401846143e5565b93508282890152614d8983890185836144c4565b9750509485019493909301925050600101614d28565b5050506020830187905260ff861660408401529050606082019390935260800152949350505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614dfd57600080fd5b83018035915067ffffffffffffffff821115614e1857600080fd5b60200191503681900382131561370257600080fd5b60006001600160a01b03808b168352808a16602084015288604084015263ffffffff808916606085015280881660808501525080861660a08401525060e060c0830152614e7e60e0830184866144c4565b9a9950505050505050505050565b6001600160a01b038b811682528a81166020830152604082018a905263ffffffff898116606084015288166080830152861660a082015261010060c08201819052600090614edd83820187896144c4565b905082810360e0840152614ef28185876148b8565b9d9c50505050505050505050505050565b600060208284031215614f1557600080fd5b8151610e91816135c3565b8381526001600160a01b03831660208201526060810161126a604083018461444c565b600060208284031215614f5557600080fd5b8151610e9181613996565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006000198203614fa257614fa2614f60565b5060010190565b600060408236031215614fbb57600080fd5b614fc361423b565b8235614fce816135c3565b815260208381013567ffffffffffffffff811115614feb57600080fd5b840136601f820112614ffc57600080fd5b803561500a6147f082614783565b81815260059190911b8201830190838101903683111561502957600080fd5b928401925b82841015615050578335615041816135c3565b8252928401929084019061502e565b938501939093525091949350505050565b60006040828403121561507357600080fd5b6040516040810181811067ffffffffffffffff821117156150965761509661420c565b60405282356150a4816135c3565b815260208301356150b4816135c3565b60208201529392505050565b6000825161461d818460208701613ef4565b6000602082840312156150e457600080fd5b610e91826149e3565b80517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681146135f557600080fd5b6000806000806080858703121561512f57600080fd5b845161513a816135d8565b9350615148602086016150ed565b92506040850151615158816135d8565b9150615166606086016150ed565b905092959194509250565b600063ffffffff808416806151af577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b92169190910492915050565b63ffffffff818116838216019080821115610a2257610a22614f60565b600063ffffffff808316818516818304811182151516156151fb576151fb614f60565b02949350505050565b8082018082111561125657611256614f60565b8181038181111561125657611256614f60565b600081600019048311821515161561524457615244614f60565b500290565b60008161525857615258614f60565b506000190190565b60ff818116838216019081111561125657611256614f60565b600060ff821660ff810361528f5761528f614f60565b60010192915050565b602081526000610e916020830184613f1856fe416464726573733a206c6f772d6c6576656c2063616c6c20776974682076616c7565206661696c6564416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220c76d8001a5c6954cc4414f5a78ee7f4ca6cbae120c7c9e6ae4337c2b67b01cc264736f6c63430008100033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000d6c8fd8100252f0a314407c26e7a47286f7fda24000000000000000000000000ec864be26084ba3bbf3caacf8f6961a9263319c4
-----Decoded View---------------
Arg [0] : _swapperRegistry (address): 0xd6C8fd8100252F0a314407C26e7A47286F7Fda24
Arg [1] : _governor (address): 0xEC864BE26084ba3bbF3cAAcF8F6961A9263319C4
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000d6c8fd8100252f0a314407c26e7a47286f7fda24
Arg [1] : 000000000000000000000000ec864be26084ba3bbf3caacf8f6961a9263319c4
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.