More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 105 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Withdraw Swapped | 19117427 | 325 days ago | IN | 0 ETH | 0.00097474 | ||||
Terminate | 14340547 | 1019 days ago | IN | 0 ETH | 0.00305977 | ||||
Withdraw Swapped | 14289056 | 1027 days ago | IN | 0 ETH | 0.00276712 | ||||
Withdraw Swapped | 14134663 | 1051 days ago | IN | 0 ETH | 0.00977879 | ||||
Withdraw Swapped | 14134656 | 1051 days ago | IN | 0 ETH | 0.00951139 | ||||
Withdraw Swapped | 14134652 | 1051 days ago | IN | 0 ETH | 0.00789605 | ||||
Withdraw Swapped | 14134646 | 1051 days ago | IN | 0 ETH | 0.00728266 | ||||
Withdraw Swapped | 14134638 | 1051 days ago | IN | 0 ETH | 0.00823421 | ||||
Withdraw Swapped | 14134630 | 1051 days ago | IN | 0 ETH | 0.00965191 | ||||
Withdraw Swapped | 14134626 | 1051 days ago | IN | 0 ETH | 0.00941577 | ||||
Withdraw Swapped | 14134623 | 1051 days ago | IN | 0 ETH | 0.00810641 | ||||
Withdraw Swapped | 14134618 | 1051 days ago | IN | 0 ETH | 0.00939786 | ||||
Withdraw Swapped | 14134614 | 1051 days ago | IN | 0 ETH | 0.00944478 | ||||
Terminate | 14042419 | 1065 days ago | IN | 0 ETH | 0.00499367 | ||||
Set Approval For... | 13984947 | 1074 days ago | IN | 0 ETH | 0.00688972 | ||||
Terminate | 13968368 | 1077 days ago | IN | 0 ETH | 0.00808927 | ||||
Deposit | 13958520 | 1078 days ago | IN | 0 ETH | 0.01431994 | ||||
Deposit | 13946869 | 1080 days ago | IN | 0 ETH | 0.04034328 | ||||
Deposit | 13946538 | 1080 days ago | IN | 0 ETH | 0.02645636 | ||||
Deposit | 13946244 | 1080 days ago | IN | 0 ETH | 0.03345599 | ||||
Deposit | 13945801 | 1080 days ago | IN | 0 ETH | 0.02462665 | ||||
Deposit | 13923107 | 1084 days ago | IN | 0 ETH | 0.02454957 | ||||
Terminate | 13906571 | 1086 days ago | IN | 0 ETH | 0.00802221 | ||||
Terminate | 13906405 | 1086 days ago | IN | 0 ETH | 0.00852381 | ||||
Deposit | 13902530 | 1087 days ago | IN | 0 ETH | 0.01545939 |
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
12949842 | 1236 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
DCAPair
Compiler Version
v0.8.6+commit.11564f7e
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.6; pragma abicoder v2; import './DCAPairParameters.sol'; import './DCAPairPositionHandler.sol'; import './DCAPairSwapHandler.sol'; import './DCAPairLoanHandler.sol'; contract DCAPair is DCAPairParameters, DCAPairSwapHandler, DCAPairPositionHandler, DCAPairLoanHandler, IDCAPair { constructor( IDCAGlobalParameters _globalParameters, IERC20Metadata _tokenA, IERC20Metadata _tokenB ) DCAPairParameters(_globalParameters, _tokenA, _tokenB) DCAPairPositionHandler(_tokenA, _tokenB) {} }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.6; import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; import '@openzeppelin/contracts/utils/structs/EnumerableSet.sol'; import '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol'; import '../interfaces/IDCAGlobalParameters.sol'; import '../interfaces/IDCAPair.sol'; import '../libraries/CommonErrors.sol'; import './utils/Math.sol'; abstract contract DCAPairParameters is IDCAPairParameters { using EnumerableSet for EnumerableSet.UintSet; // Internal constants uint112 internal _magnitudeA; uint112 internal _magnitudeB; uint24 internal _feePrecision; // Basic setup IDCAGlobalParameters public override globalParameters; IERC20Metadata public override tokenA; IERC20Metadata public override tokenB; // Tracking mapping(uint32 => mapping(address => mapping(uint32 => int256))) public override swapAmountDelta; // swap interval => from token => swap number => delta mapping(uint32 => uint32) public override performedSwaps; // swap interval => performed swaps mapping(uint32 => mapping(address => mapping(uint32 => uint256))) internal _accumRatesPerUnit; // swap interval => from token => swap number => accum mapping(address => uint256) internal _balances; EnumerableSet.UintSet internal _activeSwapIntervals; constructor( IDCAGlobalParameters _globalParameters, IERC20Metadata _tokenA, IERC20Metadata _tokenB ) { if (address(_globalParameters) == address(0) || address(_tokenA) == address(0) || address(_tokenB) == address(0)) revert CommonErrors.ZeroAddress(); globalParameters = _globalParameters; _feePrecision = globalParameters.FEE_PRECISION(); tokenA = _tokenA; tokenB = _tokenB; _magnitudeA = uint112(10**_tokenA.decimals()); _magnitudeB = uint112(10**_tokenB.decimals()); } function isSwapIntervalActive(uint32 _activeSwapInterval) external view override returns (bool _isIntervalActive) { _isIntervalActive = _activeSwapIntervals.contains(_activeSwapInterval); } function _getFeeFromAmount(uint32 _feeAmount, uint256 _amount) internal view returns (uint256) { return (_amount * _feeAmount) / _feePrecision / 100; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.6; import '@openzeppelin/contracts/token/ERC721/ERC721.sol'; import '@openzeppelin/contracts/security/ReentrancyGuard.sol'; import './DCAPairParameters.sol'; abstract contract DCAPairPositionHandler is ReentrancyGuard, DCAPairParameters, IDCAPairPositionHandler, ERC721 { struct DCA { uint32 lastWithdrawSwap; uint32 lastSwap; uint32 swapInterval; uint160 rate; bool fromTokenA; uint248 swappedBeforeModified; } using SafeERC20 for IERC20Metadata; using EnumerableSet for EnumerableSet.UintSet; mapping(uint256 => DCA) internal _userPositions; uint256 internal _idCounter; constructor(IERC20Metadata _tokenA, IERC20Metadata _tokenB) ERC721(string(abi.encodePacked('DCA: ', _tokenA.symbol(), ' - ', _tokenB.symbol())), 'DCA') {} function userPosition(uint256 _dcaId) external view override returns (UserPosition memory _userPosition) { DCA memory _position = _userPositions[_dcaId]; _userPosition.from = _position.fromTokenA ? tokenA : tokenB; _userPosition.to = _position.fromTokenA ? tokenB : tokenA; _userPosition.swapInterval = _position.swapInterval; _userPosition.swapsExecuted = _position.swapInterval > 0 ? performedSwaps[_position.swapInterval] - _position.lastWithdrawSwap : 0; _userPosition.swapped = _calculateSwapped(_dcaId); _userPosition.swapsLeft = _position.lastSwap > performedSwaps[_position.swapInterval] ? _position.lastSwap - performedSwaps[_position.swapInterval] : 0; _userPosition.remaining = _calculateUnswapped(_dcaId); _userPosition.rate = _position.rate; } function deposit( address _tokenAddress, uint160 _rate, uint32 _amountOfSwaps, uint32 _swapInterval ) external override nonReentrant returns (uint256) { if (_tokenAddress != address(tokenA) && _tokenAddress != address(tokenB)) revert InvalidToken(); if (_amountOfSwaps == 0) revert ZeroSwaps(); if (!_activeSwapIntervals.contains(_swapInterval) && !globalParameters.isSwapIntervalAllowed(_swapInterval)) revert InvalidInterval(); IERC20Metadata _from = _tokenAddress == address(tokenA) ? tokenA : tokenB; uint256 _amount = _rate * _amountOfSwaps; _from.safeTransferFrom(msg.sender, address(this), _amount); _balances[_tokenAddress] += _amount; _idCounter += 1; _safeMint(msg.sender, _idCounter); _activeSwapIntervals.add(_swapInterval); (uint32 _startingSwap, uint32 _lastSwap) = _addPosition(_idCounter, _tokenAddress, _rate, _amountOfSwaps, 0, _swapInterval); emit Deposited(msg.sender, _idCounter, _tokenAddress, _rate, _startingSwap, _swapInterval, _lastSwap); return _idCounter; } function withdrawSwapped(uint256 _dcaId) external override nonReentrant returns (uint256 _swapped) { _assertPositionExistsAndCanBeOperatedByCaller(_dcaId); _swapped = _calculateSwapped(_dcaId); _userPositions[_dcaId].lastWithdrawSwap = performedSwaps[_userPositions[_dcaId].swapInterval]; _userPositions[_dcaId].swappedBeforeModified = 0; IERC20Metadata _to = _getTo(_dcaId); _balances[address(_to)] -= _swapped; _to.safeTransfer(msg.sender, _swapped); emit Withdrew(msg.sender, _dcaId, address(_to), _swapped); } function withdrawSwappedMany(uint256[] calldata _dcaIds) external override nonReentrant returns (uint256 _swappedTokenA, uint256 _swappedTokenB) { for (uint256 i; i < _dcaIds.length; i++) { uint256 _dcaId = _dcaIds[i]; _assertPositionExistsAndCanBeOperatedByCaller(_dcaId); uint256 _swappedDCA = _calculateSwapped(_dcaId); if (_userPositions[_dcaId].fromTokenA) { _swappedTokenB += _swappedDCA; } else { _swappedTokenA += _swappedDCA; } _userPositions[_dcaId].lastWithdrawSwap = performedSwaps[_userPositions[_dcaId].swapInterval]; _userPositions[_dcaId].swappedBeforeModified = 0; } if (_swappedTokenA > 0) { _balances[address(tokenA)] -= _swappedTokenA; tokenA.safeTransfer(msg.sender, _swappedTokenA); } if (_swappedTokenB > 0) { _balances[address(tokenB)] -= _swappedTokenB; tokenB.safeTransfer(msg.sender, _swappedTokenB); } emit WithdrewMany(msg.sender, _dcaIds, _swappedTokenA, _swappedTokenB); } function terminate(uint256 _dcaId) external override nonReentrant { _assertPositionExistsAndCanBeOperatedByCaller(_dcaId); uint256 _swapped = _calculateSwapped(_dcaId); uint256 _unswapped = _calculateUnswapped(_dcaId); IERC20Metadata _from = _getFrom(_dcaId); IERC20Metadata _to = _getTo(_dcaId); _removePosition(_dcaId); _burn(_dcaId); if (_swapped > 0) { _balances[address(_to)] -= _swapped; _to.safeTransfer(msg.sender, _swapped); } if (_unswapped > 0) { _balances[address(_from)] -= _unswapped; _from.safeTransfer(msg.sender, _unswapped); } emit Terminated(msg.sender, _dcaId, _unswapped, _swapped); } function modifyRate(uint256 _dcaId, uint160 _newRate) external override nonReentrant { _assertPositionExistsAndCanBeOperatedByCaller(_dcaId); uint32 _swapsLeft = _userPositions[_dcaId].lastSwap - performedSwaps[_userPositions[_dcaId].swapInterval]; if (_swapsLeft == 0) revert PositionCompleted(); _modifyRateAndSwaps(_dcaId, _newRate, _swapsLeft); } function modifySwaps(uint256 _dcaId, uint32 _newSwaps) external override nonReentrant { _modifyRateAndSwaps(_dcaId, _userPositions[_dcaId].rate, _newSwaps); } function modifyRateAndSwaps( uint256 _dcaId, uint160 _newRate, uint32 _newAmountOfSwaps ) external override nonReentrant { _modifyRateAndSwaps(_dcaId, _newRate, _newAmountOfSwaps); } function addFundsToPosition( uint256 _dcaId, uint256 _amount, uint32 _newSwaps ) external override nonReentrant { if (_amount == 0) revert ZeroAmount(); if (_newSwaps == 0) revert ZeroSwaps(); uint256 _unswapped = _calculateUnswapped(_dcaId); uint256 _total = _unswapped + _amount; _modifyPosition(_dcaId, _total, _unswapped, uint160(_total / _newSwaps), _newSwaps); } function tokenURI(uint256 tokenId) public view override returns (string memory) { return globalParameters.nftDescriptor().tokenURI(this, tokenId); } /** Helper function to modify a position */ function _modifyRateAndSwaps( uint256 _dcaId, uint160 _newRate, uint32 _newAmountOfSwaps ) internal { _modifyPosition(_dcaId, _newRate * _newAmountOfSwaps, _calculateUnswapped(_dcaId), _newRate, _newAmountOfSwaps); } function _modifyPosition( uint256 _dcaId, uint256 _totalNecessary, uint256 _unswapped, uint160 _newRate, uint32 _newAmountOfSwaps ) internal { _assertPositionExistsAndCanBeOperatedByCaller(_dcaId); IERC20Metadata _from = _getFrom(_dcaId); uint256 _swapped = _calculateSwapped(_dcaId); if (_swapped > type(uint248).max) revert MandatoryWithdraw(); // You should withdraw before modifying, to avoid losing funds uint32 _swapInterval = _userPositions[_dcaId].swapInterval; _removePosition(_dcaId); (uint32 _startingSwap, uint32 _lastSwap) = _addPosition( _dcaId, address(_from), _newRate, _newAmountOfSwaps, uint248(_swapped), _swapInterval ); if (_totalNecessary > _unswapped) { // We need to ask for more funds _from.safeTransferFrom(msg.sender, address(this), _totalNecessary - _unswapped); _balances[address(_from)] += _totalNecessary - _unswapped; } else if (_totalNecessary < _unswapped) { // We need to return to the owner the amount that won't be used anymore _balances[address(_from)] -= _unswapped - _totalNecessary; _from.safeTransfer(msg.sender, _unswapped - _totalNecessary); } emit Modified(msg.sender, _dcaId, _newRate, _startingSwap, _lastSwap); } function _assertPositionExistsAndCanBeOperatedByCaller(uint256 _dcaId) internal view { if (_userPositions[_dcaId].rate == 0) revert InvalidPosition(); if (!_isApprovedOrOwner(msg.sender, _dcaId)) revert UnauthorizedCaller(); } function _addPosition( uint256 _dcaId, address _from, uint160 _rate, uint32 _amountOfSwaps, uint248 _swappedBeforeModified, uint32 _swapInterval ) internal returns (uint32 _startingSwap, uint32 _lastSwap) { if (_rate == 0) revert ZeroRate(); uint32 _performedSwaps = performedSwaps[_swapInterval]; _startingSwap = _performedSwaps + 1; _lastSwap = _performedSwaps + _amountOfSwaps; swapAmountDelta[_swapInterval][_from][_startingSwap] += int160(_rate); swapAmountDelta[_swapInterval][_from][_lastSwap + 1] -= int160(_rate); _userPositions[_dcaId] = DCA(_performedSwaps, _lastSwap, _swapInterval, _rate, _from == address(tokenA), _swappedBeforeModified); } function _removePosition(uint256 _dcaId) internal { uint32 _swapInterval = _userPositions[_dcaId].swapInterval; uint32 _lastSwap = _userPositions[_dcaId].lastSwap; uint32 _performedSwaps = performedSwaps[_swapInterval]; if (_lastSwap > _performedSwaps) { int160 _rate = int160(_userPositions[_dcaId].rate); address _from = address(_getFrom(_dcaId)); swapAmountDelta[_swapInterval][_from][_performedSwaps + 1] -= _rate; swapAmountDelta[_swapInterval][_from][_lastSwap + 1] += _rate; } delete _userPositions[_dcaId]; } /** Returns the amount of tokens swapped in TO */ function _calculateSwapped(uint256 _dcaId) internal view returns (uint256 _swapped) { DCA memory _userDCA = _userPositions[_dcaId]; address _from = _userDCA.fromTokenA ? address(tokenA) : address(tokenB); uint256 _accumRatesLastSwap = _accumRatesPerUnit[_userDCA.swapInterval][_from][ performedSwaps[_userDCA.swapInterval] < _userDCA.lastSwap ? performedSwaps[_userDCA.swapInterval] : _userDCA.lastSwap ]; uint256 _accumPerUnit = _accumRatesLastSwap - _accumRatesPerUnit[_userDCA.swapInterval][_from][_userDCA.lastWithdrawSwap]; uint256 _magnitude = _userDCA.fromTokenA ? _magnitudeA : _magnitudeB; (bool _ok, uint256 _mult) = Math.tryMul(_accumPerUnit, _userDCA.rate); uint256 _swappedInCurrentPosition = _ok ? _mult / _magnitude : (_accumPerUnit / _magnitude) * _userDCA.rate; _swapped = _swappedInCurrentPosition + _userDCA.swappedBeforeModified; } /** Returns how many FROM remains unswapped */ function _calculateUnswapped(uint256 _dcaId) internal view returns (uint256 _unswapped) { uint32 _performedSwaps = performedSwaps[_userPositions[_dcaId].swapInterval]; uint32 _lastSwap = _userPositions[_dcaId].lastSwap; if (_lastSwap <= _performedSwaps) return 0; _unswapped = (_lastSwap - _performedSwaps) * _userPositions[_dcaId].rate; } function _getFrom(uint256 _dcaId) internal view returns (IERC20Metadata _from) { _from = _userPositions[_dcaId].fromTokenA ? tokenA : tokenB; } function _getTo(uint256 _dcaId) internal view returns (IERC20Metadata _to) { _to = _userPositions[_dcaId].fromTokenA ? tokenB : tokenA; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.6; pragma abicoder v2; import '@openzeppelin/contracts/security/ReentrancyGuard.sol'; import '../interfaces/IDCAPairSwapCallee.sol'; import '../libraries/CommonErrors.sol'; import './DCAPairParameters.sol'; abstract contract DCAPairSwapHandler is ReentrancyGuard, DCAPairParameters, IDCAPairSwapHandler { using SafeERC20 for IERC20Metadata; using EnumerableSet for EnumerableSet.UintSet; mapping(uint32 => mapping(address => uint256)) public override swapAmountAccumulator; // swap interval => from token => swap amount accum mapping(uint32 => uint32) public override nextSwapAvailable; // swap interval => timestamp function _addNewRatePerUnit( uint32 _swapInterval, address _address, uint32 _performedSwap, uint256 _ratePerUnit ) internal { uint256 _accumRatesPerUnitPreviousSwap = _accumRatesPerUnit[_swapInterval][_address][_performedSwap - 1]; _accumRatesPerUnit[_swapInterval][_address][_performedSwap] = _accumRatesPerUnitPreviousSwap + _ratePerUnit; } function _registerSwap( uint32 _swapInterval, address _token, uint256 _internalAmountUsedToSwap, uint256 _ratePerUnit, uint32 _swapToRegister ) internal { swapAmountAccumulator[_swapInterval][_token] = _internalAmountUsedToSwap; _addNewRatePerUnit(_swapInterval, _token, _swapToRegister, _ratePerUnit); delete swapAmountDelta[_swapInterval][_token][_swapToRegister]; } function _getAmountToSwap( uint32 _swapInterval, address _address, uint32 _swapToPerform ) internal view returns (uint256 _swapAmountAccumulator) { unchecked { _swapAmountAccumulator = swapAmountAccumulator[_swapInterval][_address] + uint256(swapAmountDelta[_swapInterval][_address][_swapToPerform]); } } function _convertTo( uint256 _fromTokenMagnitude, uint256 _amountFrom, uint256 _rateFromTo ) internal pure returns (uint256 _amountTo) { _amountTo = (_amountFrom * _rateFromTo) / _fromTokenMagnitude; } function _getNextSwapsToPerform() internal view virtual returns (SwapInformation[] memory _swapsToPerform, uint8 _amountOfSwapsToPerform) { uint256 _activeSwapIntervalsLength = _activeSwapIntervals.length(); _swapsToPerform = new SwapInformation[](_activeSwapIntervalsLength); for (uint256 i; i < _activeSwapIntervalsLength; i++) { uint32 _swapInterval = uint32(_activeSwapIntervals.at(i)); if (nextSwapAvailable[_swapInterval] <= _getTimestamp()) { uint32 _swapToPerform = performedSwaps[_swapInterval] + 1; _swapsToPerform[_amountOfSwapsToPerform++] = SwapInformation({ interval: _swapInterval, swapToPerform: _swapToPerform, amountToSwapTokenA: _getAmountToSwap(_swapInterval, address(tokenA), _swapToPerform), amountToSwapTokenB: _getAmountToSwap(_swapInterval, address(tokenB), _swapToPerform) }); } } } function secondsUntilNextSwap() external view override returns (uint32 _secondsUntil) { _secondsUntil = type(uint32).max; uint32 _timestamp = _getTimestamp(); for (uint256 i; i < _activeSwapIntervals.length(); i++) { uint32 _swapInterval = uint32(_activeSwapIntervals.at(i)); if (nextSwapAvailable[_swapInterval] <= _timestamp) { _secondsUntil = 0; break; } else { uint32 _diff = nextSwapAvailable[_swapInterval] - _timestamp; if (_diff < _secondsUntil) { _secondsUntil = _diff; } } } } function getNextSwapInfo() external view override returns (NextSwapInformation memory _nextSwapInformation) { IDCAGlobalParameters.SwapParameters memory _swapParameters = globalParameters.swapParameters(); (_nextSwapInformation, , ) = _getNextSwapInfo(_swapParameters.swapFee, _swapParameters.oracle); } function _getNextSwapInfo(uint32 _swapFee, ITimeWeightedOracle _oracle) internal view virtual returns ( NextSwapInformation memory _nextSwapInformation, uint256 _ratePerUnitBToAWithFee, uint256 _ratePerUnitAToBWithFee ) { uint256 _amountToSwapTokenA; uint256 _amountToSwapTokenB; { (SwapInformation[] memory _swapsToPerform, uint8 _amountOfSwaps) = _getNextSwapsToPerform(); for (uint256 i; i < _amountOfSwaps; i++) { _amountToSwapTokenA += _swapsToPerform[i].amountToSwapTokenA; _amountToSwapTokenB += _swapsToPerform[i].amountToSwapTokenB; } _nextSwapInformation.swapsToPerform = _swapsToPerform; _nextSwapInformation.amountOfSwaps = _amountOfSwaps; } _nextSwapInformation.ratePerUnitBToA = _oracle.quote(address(tokenB), _magnitudeB, address(tokenA)); _nextSwapInformation.ratePerUnitAToB = (uint256(_magnitudeB) * _magnitudeA) / _nextSwapInformation.ratePerUnitBToA; _ratePerUnitBToAWithFee = _nextSwapInformation.ratePerUnitBToA - _getFeeFromAmount(_swapFee, _nextSwapInformation.ratePerUnitBToA); _ratePerUnitAToBWithFee = _nextSwapInformation.ratePerUnitAToB - _getFeeFromAmount(_swapFee, _nextSwapInformation.ratePerUnitAToB); uint256 _finalNeededTokenA = _convertTo(_magnitudeB, _amountToSwapTokenB, _ratePerUnitBToAWithFee); uint256 _finalNeededTokenB = _convertTo(_magnitudeA, _amountToSwapTokenA, _ratePerUnitAToBWithFee); uint256 _amountOfTokenAIfTokenBSwapped = _convertTo(_magnitudeB, _amountToSwapTokenB, _nextSwapInformation.ratePerUnitBToA); if (_amountOfTokenAIfTokenBSwapped < _amountToSwapTokenA) { _nextSwapInformation.tokenToBeProvidedBySwapper = tokenB; _nextSwapInformation.tokenToRewardSwapperWith = tokenA; _nextSwapInformation.platformFeeTokenA = _getFeeFromAmount(_swapFee, _amountOfTokenAIfTokenBSwapped); _nextSwapInformation.platformFeeTokenB = _getFeeFromAmount(_swapFee, _amountToSwapTokenB); _nextSwapInformation.amountToBeProvidedBySwapper = _finalNeededTokenB + _nextSwapInformation.platformFeeTokenB - _amountToSwapTokenB; _nextSwapInformation.amountToRewardSwapperWith = _amountToSwapTokenA - _finalNeededTokenA - _nextSwapInformation.platformFeeTokenA; _nextSwapInformation.availableToBorrowTokenA = _balances[address(tokenA)] - _nextSwapInformation.amountToRewardSwapperWith; _nextSwapInformation.availableToBorrowTokenB = _balances[address(tokenB)]; } else if (_amountOfTokenAIfTokenBSwapped > _amountToSwapTokenA) { _nextSwapInformation.tokenToBeProvidedBySwapper = tokenA; _nextSwapInformation.tokenToRewardSwapperWith = tokenB; _nextSwapInformation.platformFeeTokenA = _getFeeFromAmount(_swapFee, _amountToSwapTokenA); _nextSwapInformation.platformFeeTokenB = _getFeeFromAmount( _swapFee, (_amountToSwapTokenA * _magnitudeB) / _nextSwapInformation.ratePerUnitBToA ); _nextSwapInformation.amountToBeProvidedBySwapper = _finalNeededTokenA + _nextSwapInformation.platformFeeTokenA - _amountToSwapTokenA; _nextSwapInformation.amountToRewardSwapperWith = _amountToSwapTokenB - _finalNeededTokenB - _nextSwapInformation.platformFeeTokenB; _nextSwapInformation.availableToBorrowTokenA = _balances[address(tokenA)]; _nextSwapInformation.availableToBorrowTokenB = _balances[address(tokenB)] - _nextSwapInformation.amountToRewardSwapperWith; } else { _nextSwapInformation.platformFeeTokenA = _getFeeFromAmount(_swapFee, _amountToSwapTokenA); _nextSwapInformation.platformFeeTokenB = _getFeeFromAmount(_swapFee, _amountToSwapTokenB); _nextSwapInformation.availableToBorrowTokenA = _balances[address(tokenA)]; _nextSwapInformation.availableToBorrowTokenB = _balances[address(tokenB)]; } } function swap() external override { swap(0, 0, msg.sender, ''); } function swap( uint256 _amountToBorrowTokenA, uint256 _amountToBorrowTokenB, address _to, bytes memory _data ) public override nonReentrant { IDCAGlobalParameters.SwapParameters memory _swapParameters = globalParameters.swapParameters(); if (_swapParameters.isPaused) revert CommonErrors.Paused(); NextSwapInformation memory _nextSwapInformation; { uint256 _ratePerUnitBToAWithFee; uint256 _ratePerUnitAToBWithFee; (_nextSwapInformation, _ratePerUnitBToAWithFee, _ratePerUnitAToBWithFee) = _getNextSwapInfo( _swapParameters.swapFee, _swapParameters.oracle ); if (_nextSwapInformation.amountOfSwaps == 0) revert NoSwapsToExecute(); uint32 _timestamp = _getTimestamp(); for (uint256 i; i < _nextSwapInformation.amountOfSwaps; i++) { uint32 _swapInterval = _nextSwapInformation.swapsToPerform[i].interval; uint32 _swapToPerform = _nextSwapInformation.swapsToPerform[i].swapToPerform; if (_nextSwapInformation.swapsToPerform[i].amountToSwapTokenA > 0 || _nextSwapInformation.swapsToPerform[i].amountToSwapTokenB > 0) { _registerSwap( _swapInterval, address(tokenA), _nextSwapInformation.swapsToPerform[i].amountToSwapTokenA, _ratePerUnitAToBWithFee, _swapToPerform ); _registerSwap( _swapInterval, address(tokenB), _nextSwapInformation.swapsToPerform[i].amountToSwapTokenB, _ratePerUnitBToAWithFee, _swapToPerform ); performedSwaps[_swapInterval] = _swapToPerform; nextSwapAvailable[_swapInterval] = ((_timestamp / _swapInterval) + 1) * _swapInterval; } else { _activeSwapIntervals.remove(_swapInterval); } } } if ( _amountToBorrowTokenA > _nextSwapInformation.availableToBorrowTokenA || _amountToBorrowTokenB > _nextSwapInformation.availableToBorrowTokenB ) revert CommonErrors.InsufficientLiquidity(); uint256 _finalAmountToHaveTokenA = _nextSwapInformation.availableToBorrowTokenA - _nextSwapInformation.platformFeeTokenA; uint256 _finalAmountToHaveTokenB = _nextSwapInformation.availableToBorrowTokenB - _nextSwapInformation.platformFeeTokenB; { // scope for _amountToSendToken{A,B}, avoids stack too deep errors uint256 _amountToSendTokenA = _amountToBorrowTokenA; uint256 _amountToSendTokenB = _amountToBorrowTokenB; if (_nextSwapInformation.tokenToRewardSwapperWith == tokenA) { _amountToSendTokenA += _nextSwapInformation.amountToRewardSwapperWith; _finalAmountToHaveTokenB += _nextSwapInformation.amountToBeProvidedBySwapper; } else { _amountToSendTokenB += _nextSwapInformation.amountToRewardSwapperWith; _finalAmountToHaveTokenA += _nextSwapInformation.amountToBeProvidedBySwapper; } // Optimistically transfer tokens if (_amountToSendTokenA > 0) tokenA.safeTransfer(_to, _amountToSendTokenA); if (_amountToSendTokenB > 0) tokenB.safeTransfer(_to, _amountToSendTokenB); } if (_data.length > 0) { // Make call IDCAPairSwapCallee(_to).DCAPairSwapCall( msg.sender, tokenA, tokenB, _amountToBorrowTokenA, _amountToBorrowTokenB, _nextSwapInformation.tokenToRewardSwapperWith == tokenA, _nextSwapInformation.amountToRewardSwapperWith, _nextSwapInformation.amountToBeProvidedBySwapper, _data ); } uint256 _balanceTokenA = tokenA.balanceOf(address(this)); uint256 _balanceTokenB = tokenB.balanceOf(address(this)); // Make sure that they sent the tokens back if ( _balanceTokenA < (_finalAmountToHaveTokenA + _nextSwapInformation.platformFeeTokenA) || _balanceTokenB < (_finalAmountToHaveTokenB + _nextSwapInformation.platformFeeTokenB) ) revert CommonErrors.LiquidityNotReturned(); // Update balances _balances[address(tokenA)] = _finalAmountToHaveTokenA; _balances[address(tokenB)] = _finalAmountToHaveTokenB; // Send fees and extra uint256 _toFeeRecipientTokenA = _balanceTokenA - _finalAmountToHaveTokenA; uint256 _toFeeRecipientTokenB = _balanceTokenB - _finalAmountToHaveTokenB; if (_toFeeRecipientTokenA > 0) tokenA.safeTransfer(_swapParameters.feeRecipient, _toFeeRecipientTokenA); if (_toFeeRecipientTokenB > 0) tokenB.safeTransfer(_swapParameters.feeRecipient, _toFeeRecipientTokenB); // Emit event emit Swapped(msg.sender, _to, _amountToBorrowTokenA, _amountToBorrowTokenB, _swapParameters.swapFee, _nextSwapInformation); } function _getTimestamp() internal view virtual returns (uint32 _blockTimestamp) { _blockTimestamp = uint32(block.timestamp); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.6; import '@openzeppelin/contracts/security/ReentrancyGuard.sol'; import '../interfaces/IDCAPairLoanCallee.sol'; import '../libraries/CommonErrors.sol'; import './DCAPairParameters.sol'; abstract contract DCAPairLoanHandler is ReentrancyGuard, DCAPairParameters, IDCAPairLoanHandler { using SafeERC20 for IERC20Metadata; function availableToBorrow() external view override returns (uint256 _amountToBorrowTokenA, uint256 _amountToBorrowTokenB) { _amountToBorrowTokenA = _balances[address(tokenA)]; _amountToBorrowTokenB = _balances[address(tokenB)]; } function loan( uint256 _amountToBorrowTokenA, uint256 _amountToBorrowTokenB, address _to, bytes calldata _data ) external override nonReentrant { if (_amountToBorrowTokenA == 0 && _amountToBorrowTokenB == 0) revert ZeroLoan(); IDCAGlobalParameters.LoanParameters memory _loanParameters = globalParameters.loanParameters(); if (_loanParameters.isPaused) revert CommonErrors.Paused(); uint256 _beforeBalanceTokenA = _balances[address(tokenA)]; uint256 _beforeBalanceTokenB = _balances[address(tokenB)]; if (_amountToBorrowTokenA > _beforeBalanceTokenA || _amountToBorrowTokenB > _beforeBalanceTokenB) revert CommonErrors.InsufficientLiquidity(); // Calculate fees uint256 _feeTokenA = _amountToBorrowTokenA > 0 ? _getFeeFromAmount(_loanParameters.loanFee, _amountToBorrowTokenA) : 0; uint256 _feeTokenB = _amountToBorrowTokenB > 0 ? _getFeeFromAmount(_loanParameters.loanFee, _amountToBorrowTokenB) : 0; if (_amountToBorrowTokenA > 0) tokenA.safeTransfer(_to, _amountToBorrowTokenA); if (_amountToBorrowTokenB > 0) tokenB.safeTransfer(_to, _amountToBorrowTokenB); // Make call IDCAPairLoanCallee(_to).DCAPairLoanCall( msg.sender, tokenA, tokenB, _amountToBorrowTokenA, _amountToBorrowTokenB, _feeTokenA, _feeTokenB, _data ); uint256 _afterBalanceTokenA = tokenA.balanceOf(address(this)); uint256 _afterBalanceTokenB = tokenB.balanceOf(address(this)); // Make sure that they sent the tokens back if (_afterBalanceTokenA < (_beforeBalanceTokenA + _feeTokenA) || _afterBalanceTokenB < (_beforeBalanceTokenB + _feeTokenB)) revert CommonErrors.LiquidityNotReturned(); { // Send fees and extra (if any) uint256 _toFeeRecipientTokenA = _afterBalanceTokenA - _beforeBalanceTokenA; uint256 _toFeeRecipientTokenB = _afterBalanceTokenB - _beforeBalanceTokenB; if (_toFeeRecipientTokenA > 0) tokenA.safeTransfer(_loanParameters.feeRecipient, _toFeeRecipientTokenA); if (_toFeeRecipientTokenB > 0) tokenB.safeTransfer(_loanParameters.feeRecipient, _toFeeRecipientTokenB); } // Emit event emit Loaned(msg.sender, _to, _amountToBorrowTokenA, _amountToBorrowTokenB, _loanParameters.loanFee); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC20.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)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastvalue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastvalue; // Update the index for the moved value set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } }
// SPDX-License-Identifier: MIT 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.8.6; import './ITimeWeightedOracle.sol'; import './IDCATokenDescriptor.sol'; /// @title The interface for handling parameters the affect the whole DCA ecosystem /// @notice This contract will manage configuration that affects all pairs, swappers, etc interface IDCAGlobalParameters { /// @notice A compilation of all parameters that affect a swap struct SwapParameters { // The address of the fee recipient address feeRecipient; // Whether swaps are paused or not bool isPaused; // The swap fee uint32 swapFee; // The oracle contract ITimeWeightedOracle oracle; } /// @notice A compilation of all parameters that affect a loan struct LoanParameters { // The address of the fee recipient address feeRecipient; // Whether loans are paused or not bool isPaused; // The loan fee uint32 loanFee; } /// @notice Emitted when a new fee recipient is set /// @param _feeRecipient The address of the new fee recipient event FeeRecipientSet(address _feeRecipient); /// @notice Emitted when a new NFT descriptor is set /// @param _descriptor The new NFT descriptor contract event NFTDescriptorSet(IDCATokenDescriptor _descriptor); /// @notice Emitted when a new oracle is set /// @param _oracle The new oracle contract event OracleSet(ITimeWeightedOracle _oracle); /// @notice Emitted when a new swap fee is set /// @param _feeSet The new swap fee event SwapFeeSet(uint32 _feeSet); /// @notice Emitted when a new loan fee is set /// @param _feeSet The new loan fee event LoanFeeSet(uint32 _feeSet); /// @notice Emitted when new swap intervals are allowed /// @param _swapIntervals The new swap intervals /// @param _descriptions The descriptions for each swap interval event SwapIntervalsAllowed(uint32[] _swapIntervals, string[] _descriptions); /// @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 Thrown when trying to set a fee higher than the maximum allowed error HighFee(); /// @notice Thrown when trying to support new swap intervals, but the amount of descriptions doesn't match error InvalidParams(); /// @notice Thrown when trying to support a new swap interval of value zero error ZeroInterval(); /// @notice Thrown when trying a description for a new swap interval is empty error EmptyDescription(); /// @notice Returns the address of the fee recipient /// @return _feeRecipient The address of the fee recipient function feeRecipient() external view returns (address _feeRecipient); /// @notice Returns fee charged on swaps /// @return _swapFee The fee itself function swapFee() external view returns (uint32 _swapFee); /// @notice Returns fee charged on loans /// @return _loanFee The fee itself function loanFee() external view returns (uint32 _loanFee); /// @notice Returns the NFT descriptor contract /// @return _nftDescriptor The contract itself function nftDescriptor() external view returns (IDCATokenDescriptor _nftDescriptor); /// @notice Returns the time-weighted oracle contract /// @return _oracle The contract itself function oracle() external view returns (ITimeWeightedOracle _oracle); /// @notice Returns the precision used for fees /// @dev Cannot be modified /// @return _precision The precision used for fees // solhint-disable-next-line func-name-mixedcase function FEE_PRECISION() external view returns (uint24 _precision); /// @notice Returns the max fee that can be set for either swap or loans /// @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 list of all the allowed swap intervals /// @return _allowedSwapIntervals An array with all allowed swap intervals function allowedSwapIntervals() external view returns (uint32[] memory _allowedSwapIntervals); /// @notice Returns the description for a given swap interval /// @return _description The swap interval's description function intervalDescription(uint32 _swapInterval) external view returns (string memory _description); /// @notice Returns whether a swap interval is currently allowed /// @return _isAllowed Whether the given swap interval is currently allowed function isSwapIntervalAllowed(uint32 _swapInterval) external view returns (bool _isAllowed); /// @notice Returns whether swaps and loans are currently paused /// @return _isPaused Whether swaps and loans are currently paused function paused() external view returns (bool _isPaused); /// @notice Returns a compilation of all parameters that affect a swap /// @return _swapParameters All parameters that affect a swap function swapParameters() external view returns (SwapParameters memory _swapParameters); /// @notice Returns a compilation of all parameters that affect a loan /// @return _loanParameters All parameters that affect a loan function loanParameters() external view returns (LoanParameters memory _loanParameters); /// @notice Sets a new fee recipient address /// @dev Will revert with ZeroAddress if the zero address is passed /// @param _feeRecipient The new fee recipient address function setFeeRecipient(address _feeRecipient) external; /// @notice Sets a new swap fee /// @dev Will rever with HighFee if the fee is higher than the maximum /// @param _fee The new swap fee function setSwapFee(uint32 _fee) external; /// @notice Sets a new loan fee /// @dev Will rever with HighFee if the fee is higher than the maximum /// @param _fee The new loan fee function setLoanFee(uint32 _fee) external; /// @notice Sets a new NFT descriptor /// @dev Will revert with ZeroAddress if the zero address is passed /// @param _descriptor The new descriptor contract function setNFTDescriptor(IDCATokenDescriptor _descriptor) external; /// @notice Sets a new time-weighted oracle /// @dev Will revert with ZeroAddress if the zero address is passed /// @param _oracle The new oracle contract function setOracle(ITimeWeightedOracle _oracle) external; /// @notice Adds new swap intervals to the allowed list /// @dev Will revert with: /// InvalidParams if the amount of swap intervals is different from the amount of descriptions passed /// ZeroInterval if any of the swap intervals is zero /// EmptyDescription if any of the descriptions is empty /// @param _swapIntervals The new swap intervals /// @param _descriptions Their descriptions function addSwapIntervalsToAllowedList(uint32[] calldata _swapIntervals, string[] calldata _descriptions) 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 loans function pause() external; /// @notice Unpauses all swaps and loans function unpause() external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.6; import '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol'; import './IDCAGlobalParameters.sol'; /// @title The interface for all state related queries /// @notice These methods allow users to read the pair's current values interface IDCAPairParameters { /// @notice Returns the global parameters contract /// @dev Global parameters has information about swaps and pairs, like swap intervals, fees charged, etc. /// @return The Global Parameters contract function globalParameters() external view returns (IDCAGlobalParameters); /// @notice Returns the token A contract /// @return The contract for token A function tokenA() external view returns (IERC20Metadata); /// @notice Returns the token B contract /// @return The contract for token B function tokenB() external view returns (IERC20Metadata); /// @notice Returns how much will the amount to swap differ from the previous swap /// @dev f.e. if the returned value is -100, then the amount to swap will be 100 less than the swap just before it /// @param _swapInterval The swap interval to check /// @param _from The 'from' token of the deposits /// @param _swap The swap number to check /// @return _delta How much will the amount to swap differ, when compared to the swap just before this one function swapAmountDelta( uint32 _swapInterval, address _from, uint32 _swap ) external view returns (int256 _delta); /// @notice Returns if a certain swap interval is active or not /// @dev We consider a swap interval to be active if there is at least one active position on that interval /// @param _swapInterval The swap interval to check /// @return _isActive Whether the given swap interval is currently active function isSwapIntervalActive(uint32 _swapInterval) external view returns (bool _isActive); /// @notice Returns the amount of swaps executed for a certain interval /// @param _swapInterval The swap interval to check /// @return _swaps The amount of swaps performed on the given interval function performedSwaps(uint32 _swapInterval) external view returns (uint32 _swaps); } /// @title The interface for all position related matters in a DCA pair /// @notice These methods allow users to create, modify and terminate their positions interface IDCAPairPositionHandler is IDCAPairParameters { /// @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 uint160 rate; } /// @notice Emitted when a position is terminated /// @param _user The address of the user that terminated the position /// @param _dcaId 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, uint256 _dcaId, uint256 _returnedUnswapped, uint256 _returnedSwapped); /// @notice Emitted when a position is created /// @param _user The address of the user that created the position /// @param _dcaId The id of the position that was created /// @param _fromToken The address of the "from" token /// @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 _swapInterval How frequently the position's swaps should be executed /// @param _lastSwap The number of the swap when the position will be executed for the last time event Deposited( address indexed _user, uint256 _dcaId, address _fromToken, uint160 _rate, uint32 _startingSwap, uint32 _swapInterval, uint32 _lastSwap ); /// @notice Emitted when a user withdraws all swapped tokens from a position /// @param _user The address of the user that executed the withdraw /// @param _dcaId 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 _user, uint256 _dcaId, address _token, uint256 _amount); /// @notice Emitted when a user withdraws all swapped tokens from many positions /// @param _user The address of the user that executed the withdraw /// @param _dcaIds The ids of the positions that were affected /// @param _swappedTokenA The total amount that was withdrawn in token A /// @param _swappedTokenB The total amount that was withdrawn in token B event WithdrewMany(address indexed _user, uint256[] _dcaIds, uint256 _swappedTokenA, uint256 _swappedTokenB); /// @notice Emitted when a position is modified /// @param _user The address of the user that modified the position /// @param _dcaId 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 _dcaId, uint160 _rate, uint32 _startingSwap, uint32 _lastSwap); /// @notice Thrown when a user tries to create a position with a token that is neither token A nor token B error InvalidToken(); /// @notice Thrown when a user tries to create that a position with an unsupported swap interval error InvalidInterval(); /// @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 or modify a position by setting the rate to be zero error ZeroRate(); /// @notice Thrown when a user tries to create a position with zero swaps error ZeroSwaps(); /// @notice Thrown when a user tries to add zero funds to their position error ZeroAmount(); /// @notice Thrown when a user tries to modify the rate of a position that has already been completed error PositionCompleted(); /// @notice Thrown when a user tries to modify a position that has too much swapped balance. This error /// is thrown so that the user doesn't lose any funds. The error indicates that the user must perform a withdraw /// before modifying their position error MandatoryWithdraw(); /// @notice Returns a DCA position /// @param _dcaId The id of the position /// @return _position The position itself function userPosition(uint256 _dcaId) external view returns (UserPosition memory _position); /// @notice Creates a new position /// @dev Will revert: /// With InvalidToken if _tokenAddress is neither token A nor token B /// With ZeroRate if _rate is zero /// With ZeroSwaps if _amountOfSwaps is zero /// With InvalidInterval if _swapInterval is not a valid swap interval /// @param _tokenAddress The address of the token that will be deposited /// @param _rate How many "from" tokens need to be traded in each swap /// @param _amountOfSwaps How many swaps to execute for this position /// @param _swapInterval How frequently the position's swaps should be executed /// @return _dcaId The id of the created position function deposit( address _tokenAddress, uint160 _rate, uint32 _amountOfSwaps, uint32 _swapInterval ) external returns (uint256 _dcaId); /// @notice Withdraws all swapped tokens from a position /// @dev Will revert: /// With InvalidPosition if _dcaId is invalid /// With UnauthorizedCaller if the caller doesn't have access to the position /// @param _dcaId The position's id /// @return _swapped How much was withdrawn function withdrawSwapped(uint256 _dcaId) external returns (uint256 _swapped); /// @notice Withdraws all swapped tokens from many positions /// @dev Will revert: /// With InvalidPosition if any of the ids in _dcaIds is invalid /// With UnauthorizedCaller if the caller doesn't have access to any of the positions in _dcaIds /// @param _dcaIds The positions' ids /// @return _swappedTokenA How much was withdrawn in token A /// @return _swappedTokenB How much was withdrawn in token B function withdrawSwappedMany(uint256[] calldata _dcaIds) external returns (uint256 _swappedTokenA, uint256 _swappedTokenB); /// @notice Modifies the rate of a position. Could request more funds or return deposited funds /// depending on whether the new rate is greater than the previous one. /// @dev Will revert: /// With InvalidPosition if _dcaId is invalid /// With UnauthorizedCaller if the caller doesn't have access to the position /// With PositionCompleted if position has already been completed /// With ZeroRate if _newRate is zero /// With MandatoryWithdraw if the user must execute a withdraw before modifying their position /// @param _dcaId The position's id /// @param _newRate The new rate to set function modifyRate(uint256 _dcaId, uint160 _newRate) external; /// @notice Modifies the amount of swaps of a position. Could request more funds or return /// deposited funds depending on whether the new amount of swaps is greater than the swaps left. /// @dev Will revert: /// With InvalidPosition if _dcaId is invalid /// With UnauthorizedCaller if the caller doesn't have access to the position /// With MandatoryWithdraw if the user must execute a withdraw before modifying their position /// @param _dcaId The position's id /// @param _newSwaps The new amount of swaps function modifySwaps(uint256 _dcaId, uint32 _newSwaps) external; /// @notice Modifies both the rate and amount of swaps of a position. Could request more funds or return /// deposited funds depending on whether the new parameters require more or less than the the unswapped funds. /// @dev Will revert: /// With InvalidPosition if _dcaId is invalid /// With UnauthorizedCaller if the caller doesn't have access to the position /// With ZeroRate if _newRate is zero /// With MandatoryWithdraw if the user must execute a withdraw before modifying their position /// @param _dcaId The position's id /// @param _newRate The new rate to set /// @param _newSwaps The new amount of swaps function modifyRateAndSwaps( uint256 _dcaId, uint160 _newRate, uint32 _newSwaps ) external; /// @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 _dcaId is invalid /// With UnauthorizedCaller if the caller doesn't have access to the position /// With ZeroAmount if _amount is zero /// With ZeroSwaps if _newSwaps is zero /// With MandatoryWithdraw if the user must execute a withdraw before modifying their position /// @param _dcaId The position's id /// @param _amount Amounts of funds to add to the position /// @param _newSwaps The new amount of swaps function addFundsToPosition( uint256 _dcaId, uint256 _amount, uint32 _newSwaps ) external; /// @notice Terminates the position and sends all unswapped and swapped balance to the caller /// @dev Will revert: /// With InvalidPosition if _dcaId is invalid /// With UnauthorizedCaller if the caller doesn't have access to the position /// @param _dcaId The position's id function terminate(uint256 _dcaId) external; } /// @title The interface for all swap related matters in a DCA pair /// @notice These methods allow users to get information about the next swap, and how to execute it interface IDCAPairSwapHandler { /// @notice Information about an available swap for a specific swap interval struct SwapInformation { // The affected swap interval uint32 interval; // The number of the swap that will be performed uint32 swapToPerform; // The amount of token A that needs swapping uint256 amountToSwapTokenA; // The amount of token B that needs swapping uint256 amountToSwapTokenB; } /// @notice All information about the next swap struct NextSwapInformation { // All swaps that can be executed SwapInformation[] swapsToPerform; // How many entries of the swapsToPerform array are valid uint8 amountOfSwaps; // How much can be borrowed in token A during a flash swap uint256 availableToBorrowTokenA; // How much can be borrowed in token B during a flash swap uint256 availableToBorrowTokenB; // How much 10**decimals(tokenB) is when converted to token A uint256 ratePerUnitBToA; // How much 10**decimals(tokenA) is when converted to token B uint256 ratePerUnitAToB; // How much token A will be sent to the platform in terms of fee uint256 platformFeeTokenA; // How much token B will be sent to the platform in terms of fee uint256 platformFeeTokenB; // The amount of tokens that need to be provided by the swapper uint256 amountToBeProvidedBySwapper; // The amount of tokens that will be sent to the swapper optimistically uint256 amountToRewardSwapperWith; // The token that needs to be provided by the swapper IERC20Metadata tokenToBeProvidedBySwapper; // The token that will be sent to the swapper optimistically IERC20Metadata tokenToRewardSwapperWith; } /// @notice Emitted when a swap is executed /// @param _sender The address of the user that initiated the swap /// @param _to The address that received the reward + loan /// @param _amountBorrowedTokenA How much was borrowed in token A /// @param _amountBorrowedTokenB How much was borrowed in token B /// @param _fee How much was charged as a swap fee to position owners /// @param _nextSwapInformation All information related to the swap event Swapped( address indexed _sender, address indexed _to, uint256 _amountBorrowedTokenA, uint256 _amountBorrowedTokenB, uint32 _fee, NextSwapInformation _nextSwapInformation ); /// @notice Thrown when trying to execute a swap, but none is available error NoSwapsToExecute(); /// @notice Returns when the next swap will be available for a given swap interval /// @param _swapInterval The swap interval to check /// @return _when The moment when the next swap will be available. Take into account that if the swap is already available, this result could /// be in the past function nextSwapAvailable(uint32 _swapInterval) external view returns (uint32 _when); /// @notice Returns the amount of tokens that needed swapping in the last swap, for all positions in the given swap interval that were deposited in the given token /// @param _swapInterval The swap interval to check /// @param _from The address of the token that all positions used to deposit /// @return _amount The amount that needed swapping in the last swap function swapAmountAccumulator(uint32 _swapInterval, address _from) external view returns (uint256); /// @notice Returns all information related to the next swap /// @return _nextSwapInformation The information about the next swap function getNextSwapInfo() external view returns (NextSwapInformation memory _nextSwapInformation); /// @notice Executes a swap /// @dev This method assumes that the required amount has already been sent. Will revert with: /// Paused if swaps are paused by protocol /// NoSwapsToExecute if there are no swaps to execute /// LiquidityNotReturned if the required tokens were not sent before calling the function function swap() external; /// @notice Executes a flash swap /// @dev Will revert with: /// Paused if swaps are paused by protocol /// NoSwapsToExecute if there are no swaps to execute /// InsufficientLiquidity if asked to borrow more than the actual reserves /// LiquidityNotReturned if the required tokens were not back during the callback /// @param _amountToBorrowTokenA How much to borrow in token A /// @param _amountToBorrowTokenB How much to borrow in token B /// @param _to Address to send the reward + the borrowed tokens /// @param _data Bytes to send to the caller during the callback. If this parameter is empty, the callback won't be executed function swap( uint256 _amountToBorrowTokenA, uint256 _amountToBorrowTokenB, address _to, bytes calldata _data ) external; /// @notice Returns how many seconds left until the next swap is available /// @return _secondsUntilNextSwap The amount of seconds until next swap. Returns 0 if a swap can already be executed function secondsUntilNextSwap() external view returns (uint32 _secondsUntilNextSwap); } /// @title The interface for all loan related matters in a DCA pair /// @notice These methods allow users to ask how much is available for loans, and also to execute them interface IDCAPairLoanHandler { /// @notice Emitted when a flash loan is executed /// @param _sender The address of the user that initiated the loan /// @param _to The address that received the loan /// @param _amountBorrowedTokenA How much was borrowed in token A /// @param _amountBorrowedTokenB How much was borrowed in token B /// @param _loanFee How much was charged as a fee event Loaned(address indexed _sender, address indexed _to, uint256 _amountBorrowedTokenA, uint256 _amountBorrowedTokenB, uint32 _loanFee); // @notice Thrown when trying to execute a flash loan but without actually asking for tokens error ZeroLoan(); /// @notice Returns the amount of tokens that can be asked for during a flash loan /// @return _amountToBorrowTokenA The amount of token A that is available for borrowing /// @return _amountToBorrowTokenB The amount of token B that is available for borrowing function availableToBorrow() external view returns (uint256 _amountToBorrowTokenA, uint256 _amountToBorrowTokenB); /// @notice Executes a flash loan, sending the required amounts to the specified loan recipient /// @dev Will revert: /// With ZeroLoan if both _amountToBorrowTokenA & _amountToBorrowTokenB are 0 /// With Paused if loans are paused by protocol /// With InsufficientLiquidity if asked for more that reserves /// @param _amountToBorrowTokenA The amount to borrow in token A /// @param _amountToBorrowTokenB The amount to borrow in token B /// @param _to Address that will receive the loan. This address should be a contract that implements IDCAPairLoanCallee /// @param _data Any data that should be passed through to the callback function loan( uint256 _amountToBorrowTokenA, uint256 _amountToBorrowTokenB, address _to, bytes calldata _data ) external; } interface IDCAPair is IDCAPairParameters, IDCAPairSwapHandler, IDCAPairPositionHandler, IDCAPairLoanHandler {}
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.6; library CommonErrors { error ZeroAddress(); error Paused(); error InsufficientLiquidity(); error LiquidityNotReturned(); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.6; library Math { function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @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 * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 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); } function _verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) private 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 assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol'; /// @title The interface for an oracle that provies TWAP quotes /// @notice These methods allow users to add support for pairs, and then ask for quotes interface ITimeWeightedOracle { /// @notice Emitted when the oracle add supports for a new pair /// @param _tokenA One of the pair's tokens /// @param _tokenB The other of the pair's tokens event AddedSupportForPair(address _tokenA, address _tokenB); /// @notice Returns whether this oracle can support this 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 _canSupport Whether the given pair of tokens can be supported by the oracle function canSupportPair(address _tokenA, address _tokenB) external view returns (bool _canSupport); /// @notice Returns a quote, based on the given tokens and amount /// @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 /// @return _amountOut How much _tokenOut will be returned in exchange for _amountIn amount of _tokenIn function quote( address _tokenIn, uint128 _amountIn, address _tokenOut ) external view returns (uint256 _amountOut); /// @notice Add support for a given pair to the contract. This function will let the oracle take some actions to /// configure the pair for future quotes. Could be called more than one 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 function addSupportForPair(address _tokenA, address _tokenB) external; } /// @title An implementation of ITimeWeightedOracle that uses Uniswap V3 pool oracles /// @notice This oracle will attempt to use all fee tiers of the same pair when calculating quotes interface IUniswapV3OracleAggregator is ITimeWeightedOracle { /// @notice Emitted when a new fee tier is added /// @return _feeTier The added fee tier event AddedFeeTier(uint24 _feeTier); /// @notice Emitted when a new period is set /// @return _period The new period event PeriodChanged(uint32 _period); /// @notice Returns the Uniswap V3 Factory /// @return _factory The Uniswap V3 Factory function factory() external view returns (IUniswapV3Factory _factory); /// @notice Returns a list of all supported Uniswap V3 fee tiers /// @return _feeTiers An array of all supported fee tiers function supportedFeeTiers() external view returns (uint24[] memory _feeTiers); /// @notice Returns a list of all Uniswap V3 pools used for a given pair /// @dev _tokenA and _tokenB may be passed in either tokenA/tokenB or tokenB/tokenA order /// @return _pools An array with all pools used for quoting the given pair function poolsUsedForPair(address _tokenA, address _tokenB) external view returns (address[] memory _pools); /// @notice Returns the period used for the TWAP calculation /// @return _period The period used for the TWAP function period() external view returns (uint16 _period); /// @notice Returns minimum possible period /// @dev Cannot be modified /// @return The minimum possible period // solhint-disable-next-line func-name-mixedcase function MINIMUM_PERIOD() external view returns (uint16); /// @notice Returns maximum possible period /// @dev Cannot be modified /// @return The maximum possible period // solhint-disable-next-line func-name-mixedcase function MAXIMUM_PERIOD() external view returns (uint16); /// @notice Returns the minimum liquidity that a pool needs to have in order to be used for a pair's quote /// @dev This check is only performed when adding support for a pair. If the pool's liquidity then /// goes below the threshold, then it will still be used for the quote calculation /// @return The minimum liquidity threshold // solhint-disable-next-line func-name-mixedcase function MINIMUM_LIQUIDITY_THRESHOLD() external view returns (uint16); /// @notice Adds support for a new Uniswap V3 fee tier /// @dev Will revert if the provided fee tier is not supported by Uniswap V3 /// @param _feeTier The new fee tier function addFeeTier(uint24 _feeTier) external; /// @notice Sets the period to be used for the TWAP calculation /// @dev Will revert it is lower than MINIMUM_PERIOD or greater than MAXIMUM_PERIOD /// WARNING: increasing the period could cause big problems, because Uniswap V3 pools might not support a TWAP so old. /// @param _period The new period function setPeriod(uint16 _period) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.6; import './IDCAPair.sol'; /// @title The interface for generating a token's description /// @notice Contracts that implement this interface must return a base64 JSON with the entire description interface IDCATokenDescriptor { /// @notice Generates a token's description, both the JSON and the image inside /// @param _positionHandler The pair where the position was created /// @param _tokenId The token/position id /// @return _description The position's description function tokenURI(IDCAPairPositionHandler _positionHandler, uint256 _tokenId) external view returns (string memory _description); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title The interface for the Uniswap V3 Factory /// @notice The Uniswap V3 Factory facilitates creation of Uniswap V3 pools and control over the protocol fees interface IUniswapV3Factory { /// @notice Emitted when the owner of the factory is changed /// @param oldOwner The owner before the owner was changed /// @param newOwner The owner after the owner was changed event OwnerChanged(address indexed oldOwner, address indexed newOwner); /// @notice Emitted when a pool is created /// @param token0 The first token of the pool by address sort order /// @param token1 The second token of the pool by address sort order /// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip /// @param tickSpacing The minimum number of ticks between initialized ticks /// @param pool The address of the created pool event PoolCreated( address indexed token0, address indexed token1, uint24 indexed fee, int24 tickSpacing, address pool ); /// @notice Emitted when a new fee amount is enabled for pool creation via the factory /// @param fee The enabled fee, denominated in hundredths of a bip /// @param tickSpacing The minimum number of ticks between initialized ticks for pools created with the given fee event FeeAmountEnabled(uint24 indexed fee, int24 indexed tickSpacing); /// @notice Returns the current owner of the factory /// @dev Can be changed by the current owner via setOwner /// @return The address of the factory owner function owner() external view returns (address); /// @notice Returns the tick spacing for a given fee amount, if enabled, or 0 if not enabled /// @dev A fee amount can never be removed, so this value should be hard coded or cached in the calling context /// @param fee The enabled fee, denominated in hundredths of a bip. Returns 0 in case of unenabled fee /// @return The tick spacing function feeAmountTickSpacing(uint24 fee) external view returns (int24); /// @notice Returns the pool address for a given pair of tokens and a fee, or address 0 if it does not exist /// @dev tokenA and tokenB may be passed in either token0/token1 or token1/token0 order /// @param tokenA The contract address of either token0 or token1 /// @param tokenB The contract address of the other token /// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip /// @return pool The pool address function getPool( address tokenA, address tokenB, uint24 fee ) external view returns (address pool); /// @notice Creates a pool for the given two tokens and fee /// @param tokenA One of the two tokens in the desired pool /// @param tokenB The other of the two tokens in the desired pool /// @param fee The desired fee for the pool /// @dev tokenA and tokenB may be passed in either order: token0/token1 or token1/token0. tickSpacing is retrieved /// from the fee. The call will revert if the pool already exists, the fee is invalid, or the token arguments /// are invalid. /// @return pool The address of the newly created pool function createPool( address tokenA, address tokenB, uint24 fee ) external returns (address pool); /// @notice Updates the owner of the factory /// @dev Must be called by the current owner /// @param _owner The new owner of the factory function setOwner(address _owner) external; /// @notice Enables a fee amount with the given tickSpacing /// @dev Fee amounts may never be removed once enabled /// @param fee The fee amount to enable, denominated in hundredths of a bip (i.e. 1e-6) /// @param tickSpacing The spacing between ticks to be enforced for all pools created with the given fee amount function enableFeeAmount(uint24 fee, int24 tickSpacing) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IERC721.sol"; import "./IERC721Receiver.sol"; import "./extensions/IERC721Metadata.sol"; import "../../utils/Address.sol"; import "../../utils/Context.sol"; import "../../utils/Strings.sol"; import "../../utils/introspection/ERC165.sol"; /** * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including * the Metadata extension, but not including the Enumerable extension, which is available separately as * {ERC721Enumerable}. */ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { using Address for address; using Strings for uint256; // Token name string private _name; // Token symbol string private _symbol; // Mapping from token ID to owner address mapping(uint256 => address) private _owners; // Mapping owner address to token count mapping(address => uint256) private _balances; // Mapping from token ID to approved address mapping(uint256 => address) private _tokenApprovals; // Mapping from owner to operator approvals mapping(address => mapping(address => bool)) private _operatorApprovals; /** * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721-balanceOf}. */ function balanceOf(address owner) public view virtual override returns (uint256) { require(owner != address(0), "ERC721: balance query for the zero address"); return _balances[owner]; } /** * @dev See {IERC721-ownerOf}. */ function ownerOf(uint256 tokenId) public view virtual override returns (address) { address owner = _owners[tokenId]; require(owner != address(0), "ERC721: owner query for nonexistent token"); return owner; } /** * @dev See {IERC721Metadata-name}. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev See {IERC721Metadata-symbol}. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; } /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. Empty * by default, can be overriden in child contracts. */ function _baseURI() internal view virtual returns (string memory) { return ""; } /** * @dev See {IERC721-approve}. */ function approve(address to, uint256 tokenId) public virtual override { address owner = ERC721.ownerOf(tokenId); require(to != owner, "ERC721: approval to current owner"); require( _msgSender() == owner || isApprovedForAll(owner, _msgSender()), "ERC721: approve caller is not owner nor approved for all" ); _approve(to, tokenId); } /** * @dev See {IERC721-getApproved}. */ function getApproved(uint256 tokenId) public view virtual override returns (address) { require(_exists(tokenId), "ERC721: approved query for nonexistent token"); return _tokenApprovals[tokenId]; } /** * @dev See {IERC721-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual override { require(operator != _msgSender(), "ERC721: approve to caller"); _operatorApprovals[_msgSender()][operator] = approved; emit ApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. */ function transferFrom( address from, address to, uint256 tokenId ) public virtual override { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); _transfer(from, to, tokenId); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId ) public virtual override { safeTransferFrom(from, to, tokenId, ""); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory _data ) public virtual override { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); _safeTransfer(from, to, tokenId, _data); } /** * @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. * * `_data` is additional data, it has no specified format and it is sent in call to `to`. * * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. * implement alternative mechanisms to perform token transfer, such as signature-based. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeTransfer( address from, address to, uint256 tokenId, bytes memory _data ) internal virtual { _transfer(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Returns whether `tokenId` exists. * * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. * * Tokens start existing when they are minted (`_mint`), * and stop existing when they are burned (`_burn`). */ function _exists(uint256 tokenId) internal view virtual returns (bool) { return _owners[tokenId] != address(0); } /** * @dev Returns whether `spender` is allowed to manage `tokenId`. * * Requirements: * * - `tokenId` must exist. */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { require(_exists(tokenId), "ERC721: operator query for nonexistent token"); address owner = ERC721.ownerOf(tokenId); return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); } /** * @dev Safely mints `tokenId` and transfers it to `to`. * * Requirements: * * - `tokenId` must not exist. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeMint(address to, uint256 tokenId) internal virtual { _safeMint(to, tokenId, ""); } /** * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. */ function _safeMint( address to, uint256 tokenId, bytes memory _data ) internal virtual { _mint(to, tokenId); require( _checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer" ); } /** * @dev Mints `tokenId` and transfers it to `to`. * * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible * * Requirements: * * - `tokenId` must not exist. * - `to` cannot be the zero address. * * Emits a {Transfer} event. */ function _mint(address to, uint256 tokenId) internal virtual { require(to != address(0), "ERC721: mint to the zero address"); require(!_exists(tokenId), "ERC721: token already minted"); _beforeTokenTransfer(address(0), to, tokenId); _balances[to] += 1; _owners[tokenId] = to; emit Transfer(address(0), to, tokenId); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId) internal virtual { address owner = ERC721.ownerOf(tokenId); _beforeTokenTransfer(owner, address(0), tokenId); // Clear approvals _approve(address(0), tokenId); _balances[owner] -= 1; delete _owners[tokenId]; emit Transfer(owner, address(0), tokenId); } /** * @dev Transfers `tokenId` from `from` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * * Emits a {Transfer} event. */ function _transfer( address from, address to, uint256 tokenId ) internal virtual { require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); require(to != address(0), "ERC721: transfer to the zero address"); _beforeTokenTransfer(from, to, tokenId); // Clear approvals from the previous owner _approve(address(0), tokenId); _balances[from] -= 1; _balances[to] += 1; _owners[tokenId] = to; emit Transfer(from, to, tokenId); } /** * @dev Approve `to` to operate on `tokenId` * * Emits a {Approval} event. */ function _approve(address to, uint256 tokenId) internal virtual { _tokenApprovals[tokenId] = to; emit Approval(ERC721.ownerOf(tokenId), to, tokenId); } /** * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. * The call is not executed if the target address is not a contract. * * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param _data bytes optional data to send along with the call * @return bool whether the call correctly returned the expected magic value */ function _checkOnERC721Received( address from, address to, uint256 tokenId, bytes memory _data ) private returns (bool) { if (to.isContract()) { try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { return retval == IERC721Receiver(to).onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert("ERC721: transfer to non ERC721Receiver implementer"); } else { assembly { revert(add(32, reason), mload(reason)) } } } } else { return true; } } /** * @dev Hook that is called before any token transfer. This includes minting * and burning. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be * transferred to `to`. * - When `from` is zero, `tokenId` will be minted for `to`. * - When `to` is zero, ``from``'s `tokenId` will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 tokenId ) internal virtual {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: MIT 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`, 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 be 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 Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @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 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); /** * @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; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT 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.8.6; import '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol'; /// @title The interface for handling flash swaps /// @notice Users that want to execute flash swaps must implement this interface interface IDCAPairSwapCallee { /// @notice Handles the flash swap callback /// @param _sender The swap originator /// @param _tokenA Address for token A /// @param _tokenB Address for token B /// @param _amountBorrowedTokenA Amount borrowed in token A /// @param _amountBorrowedTokenB Amount borrowed in token B /// @param _isRewardTokenA Determines which token is the reward and which to provide to the pair /// @param _rewardAmount How much was sent to this contract optimistically /// @param _amountToProvide How much needs to be sent back to the pair /// @param _data Arbitrary bytes sent to the pair when initiating the swap // solhint-disable-next-line func-name-mixedcase function DCAPairSwapCall( address _sender, IERC20Metadata _tokenA, IERC20Metadata _tokenB, uint256 _amountBorrowedTokenA, uint256 _amountBorrowedTokenB, bool _isRewardTokenA, uint256 _rewardAmount, uint256 _amountToProvide, bytes calldata _data ) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.6; import '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol'; /// @title The interface for handling flash loans /// @notice Users that want to execute flash loans must implement this interface interface IDCAPairLoanCallee { /// @notice Handles the flash loan callback /// @param _sender The loan originator /// @param _tokenA Address for token A /// @param _tokenB Address for token B /// @param _amountBorrowedTokenA Amount borrowed in token A /// @param _amountBorrowedTokenB Amount borrowed in token B /// @param _feeTokenA How much extra to return in fees in token A /// @param _feeTokenB How much extra to return in fees in token B /// @param _data Arbitrary bytes sent to the pair when initiating the loan // solhint-disable-next-line func-name-mixedcase function DCAPairLoanCall( address _sender, IERC20Metadata _tokenA, IERC20Metadata _tokenB, uint256 _amountBorrowedTokenA, uint256 _amountBorrowedTokenB, uint256 _feeTokenA, uint256 _feeTokenB, bytes calldata _data ) external; }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract IDCAGlobalParameters","name":"_globalParameters","type":"address"},{"internalType":"contract IERC20Metadata","name":"_tokenA","type":"address"},{"internalType":"contract IERC20Metadata","name":"_tokenB","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InsufficientLiquidity","type":"error"},{"inputs":[],"name":"InvalidInterval","type":"error"},{"inputs":[],"name":"InvalidPosition","type":"error"},{"inputs":[],"name":"InvalidToken","type":"error"},{"inputs":[],"name":"LiquidityNotReturned","type":"error"},{"inputs":[],"name":"MandatoryWithdraw","type":"error"},{"inputs":[],"name":"NoSwapsToExecute","type":"error"},{"inputs":[],"name":"Paused","type":"error"},{"inputs":[],"name":"PositionCompleted","type":"error"},{"inputs":[],"name":"UnauthorizedCaller","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"inputs":[],"name":"ZeroLoan","type":"error"},{"inputs":[],"name":"ZeroRate","type":"error"},{"inputs":[],"name":"ZeroSwaps","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"uint256","name":"_dcaId","type":"uint256"},{"indexed":false,"internalType":"address","name":"_fromToken","type":"address"},{"indexed":false,"internalType":"uint160","name":"_rate","type":"uint160"},{"indexed":false,"internalType":"uint32","name":"_startingSwap","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"_swapInterval","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"_lastSwap","type":"uint32"}],"name":"Deposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_sender","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amountBorrowedTokenA","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amountBorrowedTokenB","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"_loanFee","type":"uint32"}],"name":"Loaned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"uint256","name":"_dcaId","type":"uint256"},{"indexed":false,"internalType":"uint160","name":"_rate","type":"uint160"},{"indexed":false,"internalType":"uint32","name":"_startingSwap","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"_lastSwap","type":"uint32"}],"name":"Modified","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_sender","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amountBorrowedTokenA","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amountBorrowedTokenB","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"_fee","type":"uint32"},{"components":[{"components":[{"internalType":"uint32","name":"interval","type":"uint32"},{"internalType":"uint32","name":"swapToPerform","type":"uint32"},{"internalType":"uint256","name":"amountToSwapTokenA","type":"uint256"},{"internalType":"uint256","name":"amountToSwapTokenB","type":"uint256"}],"internalType":"struct IDCAPairSwapHandler.SwapInformation[]","name":"swapsToPerform","type":"tuple[]"},{"internalType":"uint8","name":"amountOfSwaps","type":"uint8"},{"internalType":"uint256","name":"availableToBorrowTokenA","type":"uint256"},{"internalType":"uint256","name":"availableToBorrowTokenB","type":"uint256"},{"internalType":"uint256","name":"ratePerUnitBToA","type":"uint256"},{"internalType":"uint256","name":"ratePerUnitAToB","type":"uint256"},{"internalType":"uint256","name":"platformFeeTokenA","type":"uint256"},{"internalType":"uint256","name":"platformFeeTokenB","type":"uint256"},{"internalType":"uint256","name":"amountToBeProvidedBySwapper","type":"uint256"},{"internalType":"uint256","name":"amountToRewardSwapperWith","type":"uint256"},{"internalType":"contract IERC20Metadata","name":"tokenToBeProvidedBySwapper","type":"address"},{"internalType":"contract IERC20Metadata","name":"tokenToRewardSwapperWith","type":"address"}],"indexed":false,"internalType":"struct IDCAPairSwapHandler.NextSwapInformation","name":"_nextSwapInformation","type":"tuple"}],"name":"Swapped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"uint256","name":"_dcaId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_returnedUnswapped","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_returnedSwapped","type":"uint256"}],"name":"Terminated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"uint256","name":"_dcaId","type":"uint256"},{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Withdrew","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"_dcaIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"_swappedTokenA","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_swappedTokenB","type":"uint256"}],"name":"WithdrewMany","type":"event"},{"inputs":[{"internalType":"uint256","name":"_dcaId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint32","name":"_newSwaps","type":"uint32"}],"name":"addFundsToPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"availableToBorrow","outputs":[{"internalType":"uint256","name":"_amountToBorrowTokenA","type":"uint256"},{"internalType":"uint256","name":"_amountToBorrowTokenB","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint160","name":"_rate","type":"uint160"},{"internalType":"uint32","name":"_amountOfSwaps","type":"uint32"},{"internalType":"uint32","name":"_swapInterval","type":"uint32"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNextSwapInfo","outputs":[{"components":[{"components":[{"internalType":"uint32","name":"interval","type":"uint32"},{"internalType":"uint32","name":"swapToPerform","type":"uint32"},{"internalType":"uint256","name":"amountToSwapTokenA","type":"uint256"},{"internalType":"uint256","name":"amountToSwapTokenB","type":"uint256"}],"internalType":"struct IDCAPairSwapHandler.SwapInformation[]","name":"swapsToPerform","type":"tuple[]"},{"internalType":"uint8","name":"amountOfSwaps","type":"uint8"},{"internalType":"uint256","name":"availableToBorrowTokenA","type":"uint256"},{"internalType":"uint256","name":"availableToBorrowTokenB","type":"uint256"},{"internalType":"uint256","name":"ratePerUnitBToA","type":"uint256"},{"internalType":"uint256","name":"ratePerUnitAToB","type":"uint256"},{"internalType":"uint256","name":"platformFeeTokenA","type":"uint256"},{"internalType":"uint256","name":"platformFeeTokenB","type":"uint256"},{"internalType":"uint256","name":"amountToBeProvidedBySwapper","type":"uint256"},{"internalType":"uint256","name":"amountToRewardSwapperWith","type":"uint256"},{"internalType":"contract IERC20Metadata","name":"tokenToBeProvidedBySwapper","type":"address"},{"internalType":"contract IERC20Metadata","name":"tokenToRewardSwapperWith","type":"address"}],"internalType":"struct IDCAPairSwapHandler.NextSwapInformation","name":"_nextSwapInformation","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"globalParameters","outputs":[{"internalType":"contract IDCAGlobalParameters","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_activeSwapInterval","type":"uint32"}],"name":"isSwapIntervalActive","outputs":[{"internalType":"bool","name":"_isIntervalActive","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountToBorrowTokenA","type":"uint256"},{"internalType":"uint256","name":"_amountToBorrowTokenB","type":"uint256"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"loan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_dcaId","type":"uint256"},{"internalType":"uint160","name":"_newRate","type":"uint160"}],"name":"modifyRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_dcaId","type":"uint256"},{"internalType":"uint160","name":"_newRate","type":"uint160"},{"internalType":"uint32","name":"_newAmountOfSwaps","type":"uint32"}],"name":"modifyRateAndSwaps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_dcaId","type":"uint256"},{"internalType":"uint32","name":"_newSwaps","type":"uint32"}],"name":"modifySwaps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"nextSwapAvailable","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"performedSwaps","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"secondsUntilNextSwap","outputs":[{"internalType":"uint32","name":"_secondsUntil","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountToBorrowTokenA","type":"uint256"},{"internalType":"uint256","name":"_amountToBorrowTokenB","type":"uint256"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"swap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"address","name":"","type":"address"}],"name":"swapAmountAccumulator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint32","name":"","type":"uint32"}],"name":"swapAmountDelta","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_dcaId","type":"uint256"}],"name":"terminate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tokenA","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenB","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_dcaId","type":"uint256"}],"name":"userPosition","outputs":[{"components":[{"internalType":"contract IERC20Metadata","name":"from","type":"address"},{"internalType":"contract IERC20Metadata","name":"to","type":"address"},{"internalType":"uint32","name":"swapInterval","type":"uint32"},{"internalType":"uint32","name":"swapsExecuted","type":"uint32"},{"internalType":"uint256","name":"swapped","type":"uint256"},{"internalType":"uint32","name":"swapsLeft","type":"uint32"},{"internalType":"uint256","name":"remaining","type":"uint256"},{"internalType":"uint160","name":"rate","type":"uint160"}],"internalType":"struct IDCAPairPositionHandler.UserPosition","name":"_userPosition","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_dcaId","type":"uint256"}],"name":"withdrawSwapped","outputs":[{"internalType":"uint256","name":"_swapped","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_dcaIds","type":"uint256[]"}],"name":"withdrawSwappedMany","outputs":[{"internalType":"uint256","name":"_swappedTokenA","type":"uint256"},{"internalType":"uint256","name":"_swappedTokenB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b50604051620056da380380620056da8339810160408190526200003491620004c9565b8181816001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b1580156200007057600080fd5b505afa15801562000085573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620000af91908101906200051d565b816001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015620000e957600080fd5b505afa158015620000fe573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200012891908101906200051d565b6040516020016200013b92919062000628565b60408051601f19818403018152828201909152600382526244434160e81b60208301526001600055908686866001600160a01b03831615806200018557506001600160a01b038216155b806200019857506001600160a01b038116155b15620001b75760405163d92e233d60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0385169081179091556040805163e63a391f60e01b8152905163e63a391f91600480820192602092909190829003018186803b1580156200020c57600080fd5b505afa15801562000221573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002479190620005d5565b6001805462ffffff92909216600160e01b0262ffffff60e01b19909216919091179055600380546001600160a01b038085166001600160a01b0319928316811790935560048054918516919092161781556040805163313ce56760e01b8152905163313ce56792828101926020929190829003018186803b158015620002cc57600080fd5b505afa158015620002e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000307919062000603565b6200031490600a620006c4565b600160006101000a8154816001600160701b0302191690836001600160701b03160217905550806001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156200037457600080fd5b505afa15801562000389573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003af919062000603565b620003bc90600a620006c4565b600180546001600160701b0392909216600160701b02600160701b600160e01b031990921691909117905550508251620003ff9150600d90602085019062000423565b5080516200041590600e90602084019062000423565b50505050505050506200083a565b8280546200043190620007b8565b90600052602060002090601f016020900481019282620004555760008555620004a0565b82601f106200047057805160ff1916838001178555620004a0565b82800160010185558215620004a0579182015b82811115620004a057825182559160200191906001019062000483565b50620004ae929150620004b2565b5090565b5b80821115620004ae5760008155600101620004b3565b600080600060608486031215620004df57600080fd5b8351620004ec8162000821565b6020850151909350620004ff8162000821565b6040850151909250620005128162000821565b809150509250925092565b6000602082840312156200053057600080fd5b81516001600160401b03808211156200054857600080fd5b818401915084601f8301126200055d57600080fd5b8151818111156200057257620005726200080b565b604051601f8201601f19908116603f011681019083821181831017156200059d576200059d6200080b565b81604052828152876020848701011115620005b757600080fd5b620005ca83602083016020880162000785565b979650505050505050565b600060208284031215620005e857600080fd5b815162ffffff81168114620005fc57600080fd5b9392505050565b6000602082840312156200061657600080fd5b815160ff81168114620005fc57600080fd5b6402221a09d160dd1b8152600083516200064a81600585016020880162000785565b6201016960ed1b60059184019182015283516200066f81600884016020880162000785565b01600801949350505050565b600181815b80851115620006bc578160001904821115620006a057620006a0620007f5565b80851615620006ae57918102915b93841c939080029062000680565b509250929050565b6000620005fc60ff841683600082620006e0575060016200077f565b81620006ef575060006200077f565b8160018114620007085760028114620007135762000733565b60019150506200077f565b60ff841115620007275762000727620007f5565b50506001821b6200077f565b5060208310610133831016604e8410600b841016171562000758575081810a6200077f565b6200076483836200067b565b80600019048211156200077b576200077b620007f5565b0290505b92915050565b60005b83811015620007a257818101518382015260200162000788565b83811115620007b2576000848401525b50505050565b600181811c90821680620007cd57607f821691505b60208210811415620007ef57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146200083757600080fd5b50565b614e90806200084a6000396000f3fe608060405234801561001057600080fd5b506004361061021c5760003560e01c80635f64b55b11610125578063a57351f9116100ad578063c96ed6391161007c578063c96ed63914610521578063e111e3e714610534578063e985e9c514610547578063eb391aa81461055a578063f8fd31001461056d57600080fd5b8063a57351f9146104c8578063b0d2847c146104d0578063b88d4fde146104fb578063c87b56dd1461050e57600080fd5b80637e29e8a4116100f45780637e29e8a41461046a5780638119c06514610492578063833e46181461049a57806395d89b41146104ad578063a22cb465146104b557600080fd5b80635f64b55b1461041e5780636352211e1461043157806370a08231146104445780637a828b281461045757600080fd5b806323b872dd116101a857806332e8af461161017757806332e8af46146103865780633d783717146103c55780633fcf01e6146103d857806342842e0e146103eb5780635b6fd01d146103fe57600080fd5b806323b872dd1461032557806326742bed146103385780632a52803e1461034b5780632f84cbf51461037157600080fd5b8063095ea7b3116101ef578063095ea7b31461029e5780630ad82b2f146102b15780630b74e852146102c45780630f7d0f2b146102d75780630fc63d101461031257600080fd5b806301ffc9a714610221578063022c0d9f1461024957806306fdde031461025e578063081812fc14610273575b600080fd5b61023461022f366004614294565b61059b565b60405190151581526020015b60405180910390f35b61025c610257366004614588565b6105ed565b005b610266610cff565b604051610240919061495a565b610286610281366004614459565b610d91565b6040516001600160a01b039091168152602001610240565b61025c6102ac3660046141d6565b610e26565b600254610286906001600160a01b031681565b61025c6102d236600461448b565b610f3c565b6102fd6102e5366004614626565b60066020526000908152604090205463ffffffff1681565b60405163ffffffff9091168152602001610240565b600354610286906001600160a01b031681565b61025c61033336600461409f565b610fee565b61025c6103463660046144b0565b61101f565b6102fd610359366004614626565b600c6020526000908152604090205463ffffffff1681565b610379611052565b6040516102409190614a47565b6103b7610394366004614661565b600560209081526000938452604080852082529284528284209052825290205481565b604051908152602001610240565b61025c6103d33660046144f2565b6110f4565b61025c6103e6366004614601565b611545565b61025c6103f936600461409f565b6115a1565b61041161040c366004614459565b6115bc565b6040516102409190614a5a565b600454610286906001600160a01b031681565b61028661043f366004614459565b6117da565b6103b7610452366004614049565b611851565b61025c610465366004614459565b6118d8565b61047d610478366004614202565b611a2e565b60408051928352602083019190915201610240565b61025c611c1f565b6102346104a8366004614626565b611c3d565b610266611c53565b61025c6104c336600461414c565b611c62565b6102fd611d27565b6103b76104de366004614643565b600b60209081526000928352604080842090915290825290205481565b61025c6105093660046140e0565b611dd4565b61026661051c366004614459565b611e0c565b61025c61052f3660046145d3565b611f0d565b6103b7610542366004614459565b611fba565b610234610555366004614066565b6120ea565b6103b761056836600461417a565b612118565b6003546001600160a01b0390811660009081526008602052604080822054600454909316825290205461047d565b60006001600160e01b031982166380ac58cd60e01b14806105cc57506001600160e01b03198216635b5e139f60e01b145b806105e757506301ffc9a760e01b6001600160e01b03198316145b92915050565b600260005414156106195760405162461bcd60e51b815260040161061090614a10565b60405180910390fd5b600260008181559054604080516303956f4760e21b815290516001600160a01b0390921691630e55bd1c91600480820192608092909190829003018186803b15801561066457600080fd5b505afa158015610678573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061069c91906143d4565b90508060200151156106c1576040516313d0ff5960e31b815260040160405180910390fd5b6106c9613f7d565b6000806106de846040015185606001516123d5565b6020830151929550909350915060ff1661070b576040516346f8d7b160e11b815260040160405180910390fd5b4260005b846020015160ff168110156108d95760008560000151828151811061073657610736614de3565b602002602001015160000151905060008660000151838151811061075c5761075c614de3565b602002602001015160200151905060008760000151848151811061078257610782614de3565b60200260200101516040015111806107bb57506000876000015184815181106107ad576107ad614de3565b602002602001015160600151115b156108ae57600354875180516107fc9285926001600160a01b0390911691879081106107e9576107e9614de3565b602002602001015160400151888561282b565b600454875180516108389285926001600160a01b03909116918790811061082557610825614de3565b602002602001015160600151898561282b565b63ffffffff8281166000908152600660205260409020805463ffffffff19169183169190911790558161086b8186614bf0565b610876906001614bb4565b6108809190614c61565b63ffffffff8381166000908152600c60205260409020805463ffffffff1916929091169190911790556108c4565b6108c2600963ffffffff8085169061289e16565b505b505080806108d190614d66565b91505061070f565b5050505080604001518611806108f25750806060015185115b156109105760405163bb55fd2760e01b815260040160405180910390fd5b60008160c0015182604001516109269190614cc3565b905060008260e00151836060015161093e9190614cc3565b600354610160850151919250899189916001600160a01b039182169116141561098b576101208501516109719083614b9c565b9150846101000151836109849190614b9c565b92506109b1565b61012085015161099b9082614b9c565b9050846101000151846109ae9190614b9c565b93505b81156109ce576003546109ce906001600160a01b031689846128b1565b80156109eb576004546109eb906001600160a01b031689836128b1565b5050845115610ac557856001600160a01b0316633d33803c33600360009054906101000a90046001600160a01b0316600460009054906101000a90046001600160a01b03168c8c600360009054906101000a90046001600160a01b03166001600160a01b03168a61016001516001600160a01b0316148a61012001518b61010001518e6040518a63ffffffff1660e01b8152600401610a9299989796959493929190614836565b600060405180830381600087803b158015610aac57600080fd5b505af1158015610ac0573d6000803e3d6000fd5b505050505b6003546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b158015610b0957600080fd5b505afa158015610b1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b419190614472565b600480546040516370a0823160e01b815230928101929092529192506000916001600160a01b0316906370a082319060240160206040518083038186803b158015610b8b57600080fd5b505afa158015610b9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc39190614472565b90508460c0015184610bd59190614b9c565b821080610bef575060e0850151610bec9084614b9c565b81105b15610c0d5760405163d562e29f60e01b815260040160405180910390fd5b6003546001600160a01b039081166000908152600860205260408082208790556004549092168152908120849055610c458584614cc3565b90506000610c538584614cc3565b90508115610c76578751600354610c76916001600160a01b0390911690846128b1565b8015610c97578751600454610c97916001600160a01b0390911690836128b1565b896001600160a01b0316336001600160a01b03167f985cca3348e25076ac7404c08e594a15b8529496ecbf6b08af7fa24c5d4e742b8e8e8c604001518c604051610ce49493929190614ad7565b60405180910390a35050600160005550505050505050505050565b6060600d8054610d0e90614d2b565b80601f0160208091040260200160405190810160405280929190818152602001828054610d3a90614d2b565b8015610d875780601f10610d5c57610100808354040283529160200191610d87565b820191906000526020600020905b815481529060010190602001808311610d6a57829003601f168201915b5050505050905090565b6000818152600f60205260408120546001600160a01b0316610e0a5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610610565b506000908152601160205260409020546001600160a01b031690565b6000610e31826117da565b9050806001600160a01b0316836001600160a01b03161415610e9f5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608401610610565b336001600160a01b0382161480610ebb5750610ebb81336120ea565b610f2d5760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610610565b610f378383612914565b505050565b60026000541415610f5f5760405162461bcd60e51b815260040161061090614a10565b6002600055610f6d82612982565b60008281526013602081815260408084205463ffffffff600160401b820481168652600684529185205487865293909252610fb392811691640100000000900416614cda565b905063ffffffff8116610fd95760405163d43195c360e01b815260040160405180910390fd5b610fe48383836129e8565b5050600160005550565b610ff83382612a15565b6110145760405162461bcd60e51b8152600401610610906149bf565b610f37838383612aec565b600260005414156110425760405162461bcd60e51b815260040161061090614a10565b6002600055610fe48383836129e8565b61105a613f7d565b600254604080516303956f4760e21b815290516000926001600160a01b031691630e55bd1c916004808301926080929190829003018186803b15801561109f57600080fd5b505afa1580156110b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110d791906143d4565b90506110eb816040015182606001516123d5565b50909392505050565b600260005414156111175760405162461bcd60e51b815260040161061090614a10565b600260005584158015611128575083155b156111465760405163125f2a8360e21b815260040160405180910390fd5b6002546040805163b1d0a33760e01b815290516000926001600160a01b03169163b1d0a337916004808301926060929190829003018186803b15801561118b57600080fd5b505afa15801561119f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111c39190614362565b90508060200151156111e8576040516313d0ff5960e31b815260040160405180910390fd5b6003546001600160a01b039081166000908152600860205260408082205460045490931682529020548188118061121e57508087115b1561123c5760405163bb55fd2760e01b815260040160405180910390fd5b600080891161124c57600061125a565b61125a84604001518a612c8c565b9050600080891161126c57600061127a565b61127a85604001518a612c8c565b9050891561129957600354611299906001600160a01b0316898c6128b1565b88156112b6576004546112b6906001600160a01b0316898b6128b1565b876001600160a01b031663f62c404133600360009054906101000a90046001600160a01b0316600460009054906101000a90046001600160a01b03168e8e88888f8f6040518a63ffffffff1660e01b815260040161131c9998979695949392919061489b565b600060405180830381600087803b15801561133657600080fd5b505af115801561134a573d6000803e3d6000fd5b50506003546040516370a0823160e01b8152306004820152600093506001600160a01b0390911691506370a082319060240160206040518083038186803b15801561139457600080fd5b505afa1580156113a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113cc9190614472565b600480546040516370a0823160e01b815230928101929092529192506000916001600160a01b0316906370a082319060240160206040518083038186803b15801561141657600080fd5b505afa15801561142a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061144e9190614472565b905061145a8487614b9c565b82108061146f575061146c8386614b9c565b81105b1561148d5760405163d562e29f60e01b815260040160405180910390fd5b60006114998784614cc3565b905060006114a78784614cc3565b905081156114ca5788516003546114ca916001600160a01b0390911690846128b1565b80156114eb5788516004546114eb916001600160a01b0390911690836128b1565b505060408088015181518e8152602081018e905263ffffffff909116918101919091526001600160a01b038b169033907f891529dc768bd9c3ee9afa282dfdaf4ddffed309e6dae2af016a804e1d05473390606001610ce4565b600260005414156115685760405162461bcd60e51b815260040161061090614a10565b6002600090815582815260136020526040902054611598908390600160601b90046001600160a01b0316836129e8565b50506001600055565b610f3783838360405180602001604052806000815250611dd4565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810191909152600082815260136020908152604091829020825160c081018452815463ffffffff80821683526401000000008204811694830194909452600160401b810490931693810193909352600160601b9091046001600160a01b031660608301526001015460ff81161515608083018190526101009091046001600160f81b031660a0830152611695576004546001600160a01b03166116a2565b6003546001600160a01b03165b6001600160a01b0316825260808101516116c7576003546001600160a01b03166116d4565b6004546001600160a01b03165b6001600160a01b031660208301526040808201805163ffffffff90811692850192909252511661170557600061172f565b805160408083015163ffffffff90811660009081526006602052919091205461172f929116614cda565b63ffffffff16606083015261174383612cc5565b608083015260408082015163ffffffff908116600090815260066020908152929020549183015191811691161161177b5760006117aa565b60408082015163ffffffff90811660009081526006602090815292902054918301516117aa9290911690614cda565b63ffffffff1660a08301526117be83612efd565b60c0830152606001516001600160a01b031660e0820152919050565b6000818152600f60205260408120546001600160a01b0316806105e75760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201526832b73a103a37b5b2b760b91b6064820152608401610610565b60006001600160a01b0382166118bc5760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604482015269726f206164647265737360b01b6064820152608401610610565b506001600160a01b031660009081526010602052604090205490565b600260005414156118fb5760405162461bcd60e51b815260040161061090614a10565b600260005561190981612982565b600061191482612cc5565b9050600061192183612efd565b9050600061192e84612f97565b9050600061193b85612fd2565b90506119468561300d565b61194f8561316a565b8315611997576001600160a01b0381166000908152600860205260408120805486929061197d908490614cc3565b9091555061199790506001600160a01b03821633866128b1565b82156119df576001600160a01b038216600090815260086020526040812080548592906119c5908490614cc3565b909155506119df90506001600160a01b03831633856128b1565b604080518681526020810185905290810185905233907f9b863fe095959050c7ed1d85b45c0922e5667da8f82299a3eebf4cbc584f79ec9060600160405180910390a250506001600055505050565b60008060026000541415611a545760405162461bcd60e51b815260040161061090614a10565b600260009081555b83811015611b31576000858583818110611a7857611a78614de3565b905060200201359050611a8a81612982565b6000611a9582612cc5565b60008381526013602052604090206001015490915060ff1615611ac357611abc8185614b9c565b9350611ad0565b611acd8186614b9c565b94505b5060008181526013602081815260408084208054600160401b810463ffffffff9081168752600685529286205496909552929091529290921663ffffffff19909116178155600101805460ff16905580611b2981614d66565b915050611a5c565b508115611b7e576003546001600160a01b031660009081526008602052604081208054849290611b62908490614cc3565b9091555050600354611b7e906001600160a01b031633846128b1565b8015611bca576004546001600160a01b031660009081526008602052604081208054839290611bae908490614cc3565b9091555050600454611bca906001600160a01b031633836128b1565b336001600160a01b03167f4fd01d816751d768469443eeebd391cbef7fae3c437c75730c0e1b9a3c174eee85858585604051611c099493929190614911565b60405180910390a2600160005590939092509050565b611c3b60008033604051806020016040528060008152506105ed565b565b60006105e7600963ffffffff8085169061320516565b6060600e8054610d0e90614d2b565b6001600160a01b038216331415611cbb5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610610565b3360008181526012602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b63ffffffff4260005b611d3a600961321d565b811015611dcf576000611d4e600983613227565b63ffffffff8082166000908152600c6020526040902054919250808516911611611d7c576000935050505090565b63ffffffff8082166000908152600c60205260408120549091611da191869116614cda565b90508463ffffffff168163ffffffff161015611dbb578094505b505080611dc781614d66565b915050611d30565b505090565b611dde3383612a15565b611dfa5760405162461bcd60e51b8152600401610610906149bf565b611e0684848484613233565b50505050565b60025460408051630442675760e41b815290516060926001600160a01b0316916344267570916004808301926020929190829003018186803b158015611e5157600080fd5b505afa158015611e65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8991906142ce565b60405163e9dc637560e01b8152306004820152602481018490526001600160a01b03919091169063e9dc63759060440160006040518083038186803b158015611ed157600080fd5b505afa158015611ee5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526105e791908101906142eb565b60026000541415611f305760405162461bcd60e51b815260040161061090614a10565b600260005581611f5357604051631f2a200560e01b815260040160405180910390fd5b63ffffffff8116611f7757604051633c92196b60e11b815260040160405180910390fd5b6000611f8284612efd565b90506000611f908483614b9c565b9050611fae858284611fa863ffffffff881683614bdc565b87613266565b50506001600055505050565b600060026000541415611fdf5760405162461bcd60e51b815260040161061090614a10565b6002600055611fed82612982565b611ff682612cc5565b60008381526013602081815260408084208054600160401b810463ffffffff9081168752600685529286205489875294909352921663ffffffff19909116178155600101805460ff16905590915061204d83612fd2565b6001600160a01b03811660009081526008602052604081208054929350849290919061207a908490614cc3565b9091555061209490506001600160a01b03821633846128b1565b604080518481526001600160a01b038316602082015290810183905233907f7d3fe0088fc0b393d0c7629c8d9df3043bd33e8fc1a953dfa251ab201c6ebc389060600160405180910390a2506001600055919050565b6001600160a01b03918216600090815260126020908152604080832093909416825291909152205460ff1690565b60006002600054141561213d5760405162461bcd60e51b815260040161061090614a10565b60026000556003546001600160a01b0386811691161480159061216e57506004546001600160a01b03868116911614155b1561218c5760405163c1ab6dc160e01b815260040160405180910390fd5b63ffffffff83166121b057604051633c92196b60e11b815260040160405180910390fd5b6121c4600963ffffffff8085169061320516565b15801561224f5750600254604051639eceefe160e01b815263ffffffff841660048201526001600160a01b0390911690639eceefe19060240160206040518083038186803b15801561221557600080fd5b505afa158015612229573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061224d9190614277565b155b1561226d576040516305fabb6160e41b815260040160405180910390fd5b6003546000906001600160a01b03878116911614612296576004546001600160a01b03166122a3565b6003546001600160a01b03165b905060006122b763ffffffff861687614c13565b6001600160a01b0390811691506122d2908316333084613414565b6001600160a01b038716600090815260086020526040812080548392906122fa908490614b9c565b925050819055506001601460008282546123149190614b9c565b925050819055506123273360145461344c565b61233b600963ffffffff8087169061346a16565b506000806123506014548a8a8a60008b613476565b601454604080519182526001600160a01b038d811660208401528c169082015263ffffffff8084166060830152808a166080830152821660a0820152919350915033907f7bd589f2fd6a39318e78fbbbadbcd21ce8c1306fc0ecb4d7a49a7e4be9c67e639060c00160405180910390a250506014546001600055979650505050505050565b6123dd613f7d565b6000806000806000806123ee61367d565b9150915060005b8160ff168110156124685782818151811061241257612412614de3565b602002602001015160400151856124299190614b9c565b945082818151811061243d5761243d614de3565b602002602001015160600151846124549190614b9c565b93508061246081614d66565b9150506123f5565b5090865260ff1660208601526004805460015460035460405163a513355f60e01b81526001600160a01b0393841694810194909452600160701b9091046001600160701b031660248401528116604483015287169063a513355f9060640160206040518083038186803b1580156124de57600080fd5b505afa1580156124f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125169190614472565b6080860181905260015461253d906001600160701b0380821691600160701b900416614c42565b6125479190614bdc565b60a0860152608085015161255c908890612c8c565b856080015161256b9190614cc3565b935061257b878660a00151612c8c565b8560a0015161258a9190614cc3565b6001549093506000906125ae90600160701b90046001600160701b03168387613800565b6001549091506000906125cb906001600160701b03168587613800565b905060006125fc6001600e9054906101000a90046001600160701b03166001600160701b0316858a60800151613800565b9050848110156126d1576004546001600160a01b039081166101408a01526003541661016089015261262e8a82612c8c565b60c089015261263d8a85612c8c565b60e0890181905284906126509084614b9c565b61265a9190614cc3565b61010089015260c088015161266f8487614cc3565b6126799190614cc3565b61012089018190526003546001600160a01b03166000908152600860205260409020546126a69190614cc3565b6040808a01919091526004546001600160a01b0316600090815260086020522054606089015261281f565b848111156127cc576003546001600160a01b039081166101408a0152600454166101608901526127018a86612c8c565b60c0890152608088015160015461273d918c9161272e90600160701b90046001600160701b031689614c42565b6127389190614bdc565b612c8c565b60e089015260c088015185906127539085614b9c565b61275d9190614cc3565b61010089015260e08801516127728386614cc3565b61277c9190614cc3565b61012089019081526003546001600160a01b03908116600090815260086020818152604080842054818f0152945160045490941683525291909120546127c29190614cc3565b606089015261281f565b6127d68a86612c8c565b60c08901526127e58a85612c8c565b60e08901526003546001600160a01b03908116600090815260086020818152604080842054818e0152600454909416835252205460608901525b50505050509250925092565b63ffffffff85166000908152600b602090815260408083206001600160a01b0388168452909152902083905561286385858385613817565b63ffffffff94851660009081526005602090815260408083206001600160a01b03909716835295815285822092909616815294525050812055565b60006128aa83836138ab565b9392505050565b6040516001600160a01b038316602482015260448101829052610f3790849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526139a5565b600081815260116020526040902080546001600160a01b0319166001600160a01b0384169081179091558190612949826117da565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600081815260136020526040902054600160601b90046001600160a01b03166129be5760405163673f032f60e11b815260040160405180910390fd5b6129c83382612a15565b6129e557604051635c427cd960e01b815260040160405180910390fd5b50565b610f37836129fc63ffffffff841685614c13565b6001600160a01b0316612a0e86612efd565b8585613266565b6000818152600f60205260408120546001600160a01b0316612a8e5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610610565b6000612a99836117da565b9050806001600160a01b0316846001600160a01b03161480612ad45750836001600160a01b0316612ac984610d91565b6001600160a01b0316145b80612ae45750612ae481856120ea565b949350505050565b826001600160a01b0316612aff826117da565b6001600160a01b031614612b675760405162461bcd60e51b815260206004820152602960248201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960448201526839903737ba1037bbb760b91b6064820152608401610610565b6001600160a01b038216612bc95760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610610565b612bd4600082612914565b6001600160a01b0383166000908152601060205260408120805460019290612bfd908490614cc3565b90915550506001600160a01b0382166000908152601060205260408120805460019290612c2b908490614b9c565b90915550506000818152600f602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b600154600090606490600160e01b900462ffffff16612cb163ffffffff861685614c42565b612cbb9190614bdc565b6128aa9190614bdc565b6000818152601360209081526040808320815160c081018352815463ffffffff80821683526401000000008204811695830195909552600160401b810490941692810192909252600160601b9092046001600160a01b0316606082015260019091015460ff81161515608083018190526101009091046001600160f81b031660a08301528290612d60576004546001600160a01b0316612d6d565b6003546001600160a01b03165b6040808401805163ffffffff9081166000908152600760209081528482206001600160a01b03871683528152848220818901519451841683526006909152938120549495509384928216911610612dc8578460200151612de7565b60408086015163ffffffff908116600090815260066020529190912054165b63ffffffff908116825260208083019390935260409182016000908120548784015183168252600785528382206001600160a01b03881683528552838220885190931682529190935290822054909250612e419083614cc3565b905060008460800151612e6657600154600160701b90046001600160701b0316612e73565b6001546001600160701b03165b6001600160701b03169050600080612e988488606001516001600160a01b0316613a77565b91509150600082612eca5760608801516001600160a01b0316612ebb8587614bdc565b612ec59190614c42565b612ed4565b612ed48483614bdc565b90508760a001516001600160f81b031681612eef9190614b9c565b9a9950505050505050505050565b60008181526013602081815260408084205463ffffffff600160401b8204811686526006845291852054868652939092529182169164010000000090910416818111612f4d575060009392505050565b600084815260136020526040902054600160601b90046001600160a01b0316612f768383614cda565b63ffffffff16612f869190614c13565b6001600160a01b0316949350505050565b60008181526013602052604081206001015460ff16612fc1576004546001600160a01b03166105e7565b50506003546001600160a01b031690565b60008181526013602052604081206001015460ff16612ffc576003546001600160a01b03166105e7565b50506004546001600160a01b031690565b60008181526013602090815260408083205463ffffffff600160401b820481168086526006909452919093205491926401000000009004811691168082111561315057600084815260136020526040812054600160601b90046001600160a01b03169061307986612f97565b63ffffffff861660009081526005602090815260408083206001600160a01b03851684529091528120919250601384900b91906130b7866001614bb4565b63ffffffff1663ffffffff16815260200190815260200160002060008282546130e09190614c84565b909155505063ffffffff851660009081526005602090815260408083206001600160a01b03851684529091528120601384900b9161311f876001614bb4565b63ffffffff1663ffffffff16815260200190815260200160002060008282546131489190614b5b565b909155505050505b505050600090815260136020526040812081815560010155565b6000613175826117da565b9050613182600083612914565b6001600160a01b03811660009081526010602052604081208054600192906131ab908490614cc3565b90915550506000828152600f602052604080822080546001600160a01b0319169055518391906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b600081815260018301602052604081205415156128aa565b60006105e7825490565b60006128aa8383613abf565b61323e848484612aec565b61324a84848484613ae9565b611e065760405162461bcd60e51b81526004016106109061496d565b61326f85612982565b600061327a86612f97565b9050600061328787612cc5565b90506001600160f81b038111156132b157604051630930608960e11b815260040160405180910390fd5b600087815260136020526040902054600160401b900463ffffffff166132d68861300d565b6000806132e78a8689898888613476565b91509150878911156133515761331433306133028b8d614cc3565b6001600160a01b038916929190613414565b61331e888a614cc3565b6001600160a01b03861660009081526008602052604081208054909190613346908490614b9c565b909155506133b09050565b878910156133b0576133638989614cc3565b6001600160a01b0386166000908152600860205260408120805490919061338b908490614cc3565b909155506133b090503361339f8b8b614cc3565b6001600160a01b03881691906128b1565b604080518b81526001600160a01b038916602082015263ffffffff8481168284015283166060820152905133917ffa7c989fea93eb42545a9e7a74f2b8d966813e216a1dd7b59562af10dba259b4919081900360800190a250505050505050505050565b6040516001600160a01b0380851660248301528316604482015260648101829052611e069085906323b872dd60e01b906084016128dd565b613466828260405180602001604052806000815250613bf6565b5050565b60006128aa8383613c29565b6000806001600160a01b0386166134a0576040516314cee7cd60e11b815260040160405180910390fd5b63ffffffff808416600090815260066020526040902054166134c3816001614bb4565b92506134cf8682614bb4565b63ffffffff80861660009081526005602090815260408083206001600160a01b038e16845282528083209388168352929052908120805492945060138a900b9290919061351d908490614b5b565b909155505063ffffffff841660009081526005602090815260408083206001600160a01b038c1684529091528120601389900b9161355c856001614bb4565b63ffffffff1663ffffffff16815260200190815260200160002060008282546135859190614c84565b90915550506040805160c08101825263ffffffff928316815283831660208083019182529684168284019081526001600160a01b039a8b16606084019081526003549c8c169c8c169c909c14608084019081526001600160f81b03998a1660a0850190815260009e8f52601390995293909c209151825491519c519b51909a16600160601b026bffffffffffffffffffffffff9b8516600160401b029b909b1667ffffffffffffffff9c85166401000000000267ffffffffffffffff199092169a90941699909917989098179990991617969096178555955190519091166101000290151560ff161760019290920191909155509091565b606060008061368c600961321d565b90508067ffffffffffffffff8111156136a7576136a7614df9565b6040519080825280602002602001820160405280156136f957816020015b6040805160808101825260008082526020808301829052928201819052606082015282526000199092019101816136c55790505b50925060005b818110156137fa576000613714600983613227565b90504263ffffffff8281166000908152600c60205260409020549181169116116137e75763ffffffff808216600090815260066020526040812054909161375d91166001614bb4565b6040805160808101825263ffffffff80861682528316602082015260035492935091908201906137989085906001600160a01b031685613c78565b81526004546020909101906137b89085906001600160a01b031685613c78565b905286866137c581614d81565b975060ff16815181106137da576137da614de3565b6020026020010181905250505b50806137f281614d66565b9150506136ff565b50509091565b60008361380d8385614c42565b612ae49190614bdc565b63ffffffff841660009081526007602090815260408083206001600160a01b038716845290915281208161384c600186614cda565b63ffffffff168152602081019190915260400160002054905061386f8282614b9c565b63ffffffff95861660009081526007602090815260408083206001600160a01b0390981683529681528682209590971681529390955250502055565b600081815260018301602052604081205480156139945760006138cf600183614cc3565b85549091506000906138e390600190614cc3565b905081811461394857600086600001828154811061390357613903614de3565b906000526020600020015490508087600001848154811061392657613926614de3565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061395957613959614dcd565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506105e7565b60009150506105e7565b5092915050565b60006139fa826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613ccb9092919063ffffffff16565b805190915015610f375780806020019051810190613a189190614277565b610f375760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610610565b60008083613a8b5750600190506000613ab8565b83830283858281613a9e57613a9e614db7565b0414613ab1576000809250925050613ab8565b6001925090505b9250929050565b6000826000018281548110613ad657613ad6614de3565b9060005260206000200154905092915050565b60006001600160a01b0384163b15613beb57604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290613b2d9033908990889088906004016147f9565b602060405180830381600087803b158015613b4757600080fd5b505af1925050508015613b77575060408051601f3d908101601f19168201909252613b74918101906142b1565b60015b613bd1573d808015613ba5576040519150601f19603f3d011682016040523d82523d6000602084013e613baa565b606091505b508051613bc95760405162461bcd60e51b81526004016106109061496d565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050612ae4565b506001949350505050565b613c008383613cda565b613c0d6000848484613ae9565b610f375760405162461bcd60e51b81526004016106109061496d565b6000818152600183016020526040812054613c70575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556105e7565b5060006105e7565b63ffffffff92831660008181526005602090815260408083206001600160a01b0390961680845295825280832094909616825292835284812054918152600b835284812093815292909152919020540190565b6060612ae48484600085613e1c565b6001600160a01b038216613d305760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610610565b6000818152600f60205260409020546001600160a01b031615613d955760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610610565b6001600160a01b0382166000908152601060205260408120805460019290613dbe908490614b9c565b90915550506000818152600f602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b606082471015613e7d5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610610565b843b613ecb5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610610565b600080866001600160a01b03168587604051613ee791906147dd565b60006040518083038185875af1925050503d8060008114613f24576040519150601f19603f3d011682016040523d82523d6000602084013e613f29565b606091505b5091509150613f39828286613f44565b979650505050505050565b60608315613f535750816128aa565b825115613f635782518084602001fd5b8160405162461bcd60e51b8152600401610610919061495a565b60405180610180016040528060608152602001600060ff168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b031681525090565b600082601f83011261400457600080fd5b813561401761401282614b33565b614b02565b81815284602083860101111561402c57600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561405b57600080fd5b81356128aa81614e0f565b6000806040838503121561407957600080fd5b823561408481614e0f565b9150602083013561409481614e0f565b809150509250929050565b6000806000606084860312156140b457600080fd5b83356140bf81614e0f565b925060208401356140cf81614e0f565b929592945050506040919091013590565b600080600080608085870312156140f657600080fd5b843561410181614e0f565b9350602085013561411181614e0f565b925060408501359150606085013567ffffffffffffffff81111561413457600080fd5b61414087828801613ff3565b91505092959194509250565b6000806040838503121561415f57600080fd5b823561416a81614e0f565b9150602083013561409481614e24565b6000806000806080858703121561419057600080fd5b843561419b81614e0f565b935060208501356141ab81614e0f565b925060408501356141bb81614e48565b915060608501356141cb81614e48565b939692955090935050565b600080604083850312156141e957600080fd5b82356141f481614e0f565b946020939093013593505050565b6000806020838503121561421557600080fd5b823567ffffffffffffffff8082111561422d57600080fd5b818501915085601f83011261424157600080fd5b81358181111561425057600080fd5b8660208260051b850101111561426557600080fd5b60209290920196919550909350505050565b60006020828403121561428957600080fd5b81516128aa81614e24565b6000602082840312156142a657600080fd5b81356128aa81614e32565b6000602082840312156142c357600080fd5b81516128aa81614e32565b6000602082840312156142e057600080fd5b81516128aa81614e0f565b6000602082840312156142fd57600080fd5b815167ffffffffffffffff81111561431457600080fd5b8201601f8101841361432557600080fd5b805161433361401282614b33565b81815285602083850101111561434857600080fd5b614359826020830160208601614cff565b95945050505050565b60006060828403121561437457600080fd5b6040516060810181811067ffffffffffffffff8211171561439757614397614df9565b60405282516143a581614e0f565b815260208301516143b581614e24565b602082015260408301516143c881614e48565b60408201529392505050565b6000608082840312156143e657600080fd5b6040516080810181811067ffffffffffffffff8211171561440957614409614df9565b604052825161441781614e0f565b8152602083015161442781614e24565b6020820152604083015161443a81614e48565b6040820152606083015161444d81614e0f565b60608201529392505050565b60006020828403121561446b57600080fd5b5035919050565b60006020828403121561448457600080fd5b5051919050565b6000806040838503121561449e57600080fd5b82359150602083013561409481614e0f565b6000806000606084860312156144c557600080fd5b8335925060208401356144d781614e0f565b915060408401356144e781614e48565b809150509250925092565b60008060008060006080868803121561450a57600080fd5b8535945060208601359350604086013561452381614e0f565b9250606086013567ffffffffffffffff8082111561454057600080fd5b818801915088601f83011261455457600080fd5b81358181111561456357600080fd5b89602082850101111561457557600080fd5b9699959850939650602001949392505050565b6000806000806080858703121561459e57600080fd5b843593506020850135925060408501356145b781614e0f565b9150606085013567ffffffffffffffff81111561413457600080fd5b6000806000606084860312156145e857600080fd5b833592506020840135915060408401356144e781614e48565b6000806040838503121561461457600080fd5b82359150602083013561409481614e48565b60006020828403121561463857600080fd5b81356128aa81614e48565b6000806040838503121561465657600080fd5b823561408481614e48565b60008060006060848603121561467657600080fd5b833561468181614e48565b925060208401356144d781614e0f565b600081518084526020808501945080840160005b838110156146ea578151805163ffffffff90811689528482015116848901526040808201519089015260609081015190880152608090960195908201906001016146a5565b509495945050505050565b6000815180845261470d816020860160208601614cff565b601f01601f19169290920160200192915050565b6000610180825181855261473782860182614691565b915050602083015161474e602086018260ff169052565b5060408301516040850152606083015160608501526080830151608085015260a083015160a085015260c083015160c085015260e083015160e0850152610100808401518186015250610120808401518186015250610140808401516147be828701826001600160a01b03169052565b5050610160928301516001600160a01b03169390920192909252919050565b600082516147ef818460208701614cff565b9190910192915050565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061482c908301846146f5565b9695505050505050565b600061012060018060a01b03808d168452808c166020850152808b1660408501525088606084015287608084015286151560a08401528560c08401528460e08401528061010084015261488b818401856146f5565b9c9b505050505050505050505050565b6001600160a01b038a81168252898116602083015288166040820152606081018790526080810186905260a0810185905260c0810184905261010060e08201819052810182905260006101208385828501376000838501820152601f909301601f19169091019091019998505050505050505050565b6060808252810184905260006001600160fb1b0385111561493157600080fd5b8460051b8087608085013760009083016080019081526020830194909452506040015292915050565b6020815260006128aa60208301846146f5565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6020815260006128aa6020830184614721565b60006101008201905060018060a01b0380845116835280602085015116602084015250604083015163ffffffff8082166040850152806060860151166060850152608085015160808501528060a08601511660a0850152505060c083015160c083015260e083015161399e60e08401826001600160a01b03169052565b84815283602082015263ffffffff8316604082015260806060820152600061482c6080830184614721565b604051601f8201601f1916810167ffffffffffffffff81118282101715614b2b57614b2b614df9565b604052919050565b600067ffffffffffffffff821115614b4d57614b4d614df9565b50601f01601f191660200190565b600080821280156001600160ff1b0384900385131615614b7d57614b7d614da1565b600160ff1b8390038412811615614b9657614b96614da1565b50500190565b60008219821115614baf57614baf614da1565b500190565b600063ffffffff808316818516808303821115614bd357614bd3614da1565b01949350505050565b600082614beb57614beb614db7565b500490565b600063ffffffff80841680614c0757614c07614db7565b92169190910492915050565b60006001600160a01b0382811684821681151582840482111615614c3957614c39614da1565b02949350505050565b6000816000190483118215151615614c5c57614c5c614da1565b500290565b600063ffffffff80831681851681830481118215151615614c3957614c39614da1565b60008083128015600160ff1b850184121615614ca257614ca2614da1565b6001600160ff1b0384018313811615614cbd57614cbd614da1565b50500390565b600082821015614cd557614cd5614da1565b500390565b600063ffffffff83811690831681811015614cf757614cf7614da1565b039392505050565b60005b83811015614d1a578181015183820152602001614d02565b83811115611e065750506000910152565b600181811c90821680614d3f57607f821691505b60208210811415614d6057634e487b7160e01b600052602260045260246000fd5b50919050565b6000600019821415614d7a57614d7a614da1565b5060010190565b600060ff821660ff811415614d9857614d98614da1565b60010192915050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146129e557600080fd5b80151581146129e557600080fd5b6001600160e01b0319811681146129e557600080fd5b63ffffffff811681146129e557600080fdfea2646970667358221220da0ad3258994f7770df48129c19337805ef590f1281c528c08c5b258ec87a40964736f6c634300080600330000000000000000000000000dbcca406b622ed1f455abc9560d51aa0c81560f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061021c5760003560e01c80635f64b55b11610125578063a57351f9116100ad578063c96ed6391161007c578063c96ed63914610521578063e111e3e714610534578063e985e9c514610547578063eb391aa81461055a578063f8fd31001461056d57600080fd5b8063a57351f9146104c8578063b0d2847c146104d0578063b88d4fde146104fb578063c87b56dd1461050e57600080fd5b80637e29e8a4116100f45780637e29e8a41461046a5780638119c06514610492578063833e46181461049a57806395d89b41146104ad578063a22cb465146104b557600080fd5b80635f64b55b1461041e5780636352211e1461043157806370a08231146104445780637a828b281461045757600080fd5b806323b872dd116101a857806332e8af461161017757806332e8af46146103865780633d783717146103c55780633fcf01e6146103d857806342842e0e146103eb5780635b6fd01d146103fe57600080fd5b806323b872dd1461032557806326742bed146103385780632a52803e1461034b5780632f84cbf51461037157600080fd5b8063095ea7b3116101ef578063095ea7b31461029e5780630ad82b2f146102b15780630b74e852146102c45780630f7d0f2b146102d75780630fc63d101461031257600080fd5b806301ffc9a714610221578063022c0d9f1461024957806306fdde031461025e578063081812fc14610273575b600080fd5b61023461022f366004614294565b61059b565b60405190151581526020015b60405180910390f35b61025c610257366004614588565b6105ed565b005b610266610cff565b604051610240919061495a565b610286610281366004614459565b610d91565b6040516001600160a01b039091168152602001610240565b61025c6102ac3660046141d6565b610e26565b600254610286906001600160a01b031681565b61025c6102d236600461448b565b610f3c565b6102fd6102e5366004614626565b60066020526000908152604090205463ffffffff1681565b60405163ffffffff9091168152602001610240565b600354610286906001600160a01b031681565b61025c61033336600461409f565b610fee565b61025c6103463660046144b0565b61101f565b6102fd610359366004614626565b600c6020526000908152604090205463ffffffff1681565b610379611052565b6040516102409190614a47565b6103b7610394366004614661565b600560209081526000938452604080852082529284528284209052825290205481565b604051908152602001610240565b61025c6103d33660046144f2565b6110f4565b61025c6103e6366004614601565b611545565b61025c6103f936600461409f565b6115a1565b61041161040c366004614459565b6115bc565b6040516102409190614a5a565b600454610286906001600160a01b031681565b61028661043f366004614459565b6117da565b6103b7610452366004614049565b611851565b61025c610465366004614459565b6118d8565b61047d610478366004614202565b611a2e565b60408051928352602083019190915201610240565b61025c611c1f565b6102346104a8366004614626565b611c3d565b610266611c53565b61025c6104c336600461414c565b611c62565b6102fd611d27565b6103b76104de366004614643565b600b60209081526000928352604080842090915290825290205481565b61025c6105093660046140e0565b611dd4565b61026661051c366004614459565b611e0c565b61025c61052f3660046145d3565b611f0d565b6103b7610542366004614459565b611fba565b610234610555366004614066565b6120ea565b6103b761056836600461417a565b612118565b6003546001600160a01b0390811660009081526008602052604080822054600454909316825290205461047d565b60006001600160e01b031982166380ac58cd60e01b14806105cc57506001600160e01b03198216635b5e139f60e01b145b806105e757506301ffc9a760e01b6001600160e01b03198316145b92915050565b600260005414156106195760405162461bcd60e51b815260040161061090614a10565b60405180910390fd5b600260008181559054604080516303956f4760e21b815290516001600160a01b0390921691630e55bd1c91600480820192608092909190829003018186803b15801561066457600080fd5b505afa158015610678573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061069c91906143d4565b90508060200151156106c1576040516313d0ff5960e31b815260040160405180910390fd5b6106c9613f7d565b6000806106de846040015185606001516123d5565b6020830151929550909350915060ff1661070b576040516346f8d7b160e11b815260040160405180910390fd5b4260005b846020015160ff168110156108d95760008560000151828151811061073657610736614de3565b602002602001015160000151905060008660000151838151811061075c5761075c614de3565b602002602001015160200151905060008760000151848151811061078257610782614de3565b60200260200101516040015111806107bb57506000876000015184815181106107ad576107ad614de3565b602002602001015160600151115b156108ae57600354875180516107fc9285926001600160a01b0390911691879081106107e9576107e9614de3565b602002602001015160400151888561282b565b600454875180516108389285926001600160a01b03909116918790811061082557610825614de3565b602002602001015160600151898561282b565b63ffffffff8281166000908152600660205260409020805463ffffffff19169183169190911790558161086b8186614bf0565b610876906001614bb4565b6108809190614c61565b63ffffffff8381166000908152600c60205260409020805463ffffffff1916929091169190911790556108c4565b6108c2600963ffffffff8085169061289e16565b505b505080806108d190614d66565b91505061070f565b5050505080604001518611806108f25750806060015185115b156109105760405163bb55fd2760e01b815260040160405180910390fd5b60008160c0015182604001516109269190614cc3565b905060008260e00151836060015161093e9190614cc3565b600354610160850151919250899189916001600160a01b039182169116141561098b576101208501516109719083614b9c565b9150846101000151836109849190614b9c565b92506109b1565b61012085015161099b9082614b9c565b9050846101000151846109ae9190614b9c565b93505b81156109ce576003546109ce906001600160a01b031689846128b1565b80156109eb576004546109eb906001600160a01b031689836128b1565b5050845115610ac557856001600160a01b0316633d33803c33600360009054906101000a90046001600160a01b0316600460009054906101000a90046001600160a01b03168c8c600360009054906101000a90046001600160a01b03166001600160a01b03168a61016001516001600160a01b0316148a61012001518b61010001518e6040518a63ffffffff1660e01b8152600401610a9299989796959493929190614836565b600060405180830381600087803b158015610aac57600080fd5b505af1158015610ac0573d6000803e3d6000fd5b505050505b6003546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b158015610b0957600080fd5b505afa158015610b1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b419190614472565b600480546040516370a0823160e01b815230928101929092529192506000916001600160a01b0316906370a082319060240160206040518083038186803b158015610b8b57600080fd5b505afa158015610b9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bc39190614472565b90508460c0015184610bd59190614b9c565b821080610bef575060e0850151610bec9084614b9c565b81105b15610c0d5760405163d562e29f60e01b815260040160405180910390fd5b6003546001600160a01b039081166000908152600860205260408082208790556004549092168152908120849055610c458584614cc3565b90506000610c538584614cc3565b90508115610c76578751600354610c76916001600160a01b0390911690846128b1565b8015610c97578751600454610c97916001600160a01b0390911690836128b1565b896001600160a01b0316336001600160a01b03167f985cca3348e25076ac7404c08e594a15b8529496ecbf6b08af7fa24c5d4e742b8e8e8c604001518c604051610ce49493929190614ad7565b60405180910390a35050600160005550505050505050505050565b6060600d8054610d0e90614d2b565b80601f0160208091040260200160405190810160405280929190818152602001828054610d3a90614d2b565b8015610d875780601f10610d5c57610100808354040283529160200191610d87565b820191906000526020600020905b815481529060010190602001808311610d6a57829003601f168201915b5050505050905090565b6000818152600f60205260408120546001600160a01b0316610e0a5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610610565b506000908152601160205260409020546001600160a01b031690565b6000610e31826117da565b9050806001600160a01b0316836001600160a01b03161415610e9f5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608401610610565b336001600160a01b0382161480610ebb5750610ebb81336120ea565b610f2d5760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610610565b610f378383612914565b505050565b60026000541415610f5f5760405162461bcd60e51b815260040161061090614a10565b6002600055610f6d82612982565b60008281526013602081815260408084205463ffffffff600160401b820481168652600684529185205487865293909252610fb392811691640100000000900416614cda565b905063ffffffff8116610fd95760405163d43195c360e01b815260040160405180910390fd5b610fe48383836129e8565b5050600160005550565b610ff83382612a15565b6110145760405162461bcd60e51b8152600401610610906149bf565b610f37838383612aec565b600260005414156110425760405162461bcd60e51b815260040161061090614a10565b6002600055610fe48383836129e8565b61105a613f7d565b600254604080516303956f4760e21b815290516000926001600160a01b031691630e55bd1c916004808301926080929190829003018186803b15801561109f57600080fd5b505afa1580156110b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110d791906143d4565b90506110eb816040015182606001516123d5565b50909392505050565b600260005414156111175760405162461bcd60e51b815260040161061090614a10565b600260005584158015611128575083155b156111465760405163125f2a8360e21b815260040160405180910390fd5b6002546040805163b1d0a33760e01b815290516000926001600160a01b03169163b1d0a337916004808301926060929190829003018186803b15801561118b57600080fd5b505afa15801561119f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111c39190614362565b90508060200151156111e8576040516313d0ff5960e31b815260040160405180910390fd5b6003546001600160a01b039081166000908152600860205260408082205460045490931682529020548188118061121e57508087115b1561123c5760405163bb55fd2760e01b815260040160405180910390fd5b600080891161124c57600061125a565b61125a84604001518a612c8c565b9050600080891161126c57600061127a565b61127a85604001518a612c8c565b9050891561129957600354611299906001600160a01b0316898c6128b1565b88156112b6576004546112b6906001600160a01b0316898b6128b1565b876001600160a01b031663f62c404133600360009054906101000a90046001600160a01b0316600460009054906101000a90046001600160a01b03168e8e88888f8f6040518a63ffffffff1660e01b815260040161131c9998979695949392919061489b565b600060405180830381600087803b15801561133657600080fd5b505af115801561134a573d6000803e3d6000fd5b50506003546040516370a0823160e01b8152306004820152600093506001600160a01b0390911691506370a082319060240160206040518083038186803b15801561139457600080fd5b505afa1580156113a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113cc9190614472565b600480546040516370a0823160e01b815230928101929092529192506000916001600160a01b0316906370a082319060240160206040518083038186803b15801561141657600080fd5b505afa15801561142a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061144e9190614472565b905061145a8487614b9c565b82108061146f575061146c8386614b9c565b81105b1561148d5760405163d562e29f60e01b815260040160405180910390fd5b60006114998784614cc3565b905060006114a78784614cc3565b905081156114ca5788516003546114ca916001600160a01b0390911690846128b1565b80156114eb5788516004546114eb916001600160a01b0390911690836128b1565b505060408088015181518e8152602081018e905263ffffffff909116918101919091526001600160a01b038b169033907f891529dc768bd9c3ee9afa282dfdaf4ddffed309e6dae2af016a804e1d05473390606001610ce4565b600260005414156115685760405162461bcd60e51b815260040161061090614a10565b6002600090815582815260136020526040902054611598908390600160601b90046001600160a01b0316836129e8565b50506001600055565b610f3783838360405180602001604052806000815250611dd4565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810191909152600082815260136020908152604091829020825160c081018452815463ffffffff80821683526401000000008204811694830194909452600160401b810490931693810193909352600160601b9091046001600160a01b031660608301526001015460ff81161515608083018190526101009091046001600160f81b031660a0830152611695576004546001600160a01b03166116a2565b6003546001600160a01b03165b6001600160a01b0316825260808101516116c7576003546001600160a01b03166116d4565b6004546001600160a01b03165b6001600160a01b031660208301526040808201805163ffffffff90811692850192909252511661170557600061172f565b805160408083015163ffffffff90811660009081526006602052919091205461172f929116614cda565b63ffffffff16606083015261174383612cc5565b608083015260408082015163ffffffff908116600090815260066020908152929020549183015191811691161161177b5760006117aa565b60408082015163ffffffff90811660009081526006602090815292902054918301516117aa9290911690614cda565b63ffffffff1660a08301526117be83612efd565b60c0830152606001516001600160a01b031660e0820152919050565b6000818152600f60205260408120546001600160a01b0316806105e75760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201526832b73a103a37b5b2b760b91b6064820152608401610610565b60006001600160a01b0382166118bc5760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604482015269726f206164647265737360b01b6064820152608401610610565b506001600160a01b031660009081526010602052604090205490565b600260005414156118fb5760405162461bcd60e51b815260040161061090614a10565b600260005561190981612982565b600061191482612cc5565b9050600061192183612efd565b9050600061192e84612f97565b9050600061193b85612fd2565b90506119468561300d565b61194f8561316a565b8315611997576001600160a01b0381166000908152600860205260408120805486929061197d908490614cc3565b9091555061199790506001600160a01b03821633866128b1565b82156119df576001600160a01b038216600090815260086020526040812080548592906119c5908490614cc3565b909155506119df90506001600160a01b03831633856128b1565b604080518681526020810185905290810185905233907f9b863fe095959050c7ed1d85b45c0922e5667da8f82299a3eebf4cbc584f79ec9060600160405180910390a250506001600055505050565b60008060026000541415611a545760405162461bcd60e51b815260040161061090614a10565b600260009081555b83811015611b31576000858583818110611a7857611a78614de3565b905060200201359050611a8a81612982565b6000611a9582612cc5565b60008381526013602052604090206001015490915060ff1615611ac357611abc8185614b9c565b9350611ad0565b611acd8186614b9c565b94505b5060008181526013602081815260408084208054600160401b810463ffffffff9081168752600685529286205496909552929091529290921663ffffffff19909116178155600101805460ff16905580611b2981614d66565b915050611a5c565b508115611b7e576003546001600160a01b031660009081526008602052604081208054849290611b62908490614cc3565b9091555050600354611b7e906001600160a01b031633846128b1565b8015611bca576004546001600160a01b031660009081526008602052604081208054839290611bae908490614cc3565b9091555050600454611bca906001600160a01b031633836128b1565b336001600160a01b03167f4fd01d816751d768469443eeebd391cbef7fae3c437c75730c0e1b9a3c174eee85858585604051611c099493929190614911565b60405180910390a2600160005590939092509050565b611c3b60008033604051806020016040528060008152506105ed565b565b60006105e7600963ffffffff8085169061320516565b6060600e8054610d0e90614d2b565b6001600160a01b038216331415611cbb5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610610565b3360008181526012602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b63ffffffff4260005b611d3a600961321d565b811015611dcf576000611d4e600983613227565b63ffffffff8082166000908152600c6020526040902054919250808516911611611d7c576000935050505090565b63ffffffff8082166000908152600c60205260408120549091611da191869116614cda565b90508463ffffffff168163ffffffff161015611dbb578094505b505080611dc781614d66565b915050611d30565b505090565b611dde3383612a15565b611dfa5760405162461bcd60e51b8152600401610610906149bf565b611e0684848484613233565b50505050565b60025460408051630442675760e41b815290516060926001600160a01b0316916344267570916004808301926020929190829003018186803b158015611e5157600080fd5b505afa158015611e65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8991906142ce565b60405163e9dc637560e01b8152306004820152602481018490526001600160a01b03919091169063e9dc63759060440160006040518083038186803b158015611ed157600080fd5b505afa158015611ee5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526105e791908101906142eb565b60026000541415611f305760405162461bcd60e51b815260040161061090614a10565b600260005581611f5357604051631f2a200560e01b815260040160405180910390fd5b63ffffffff8116611f7757604051633c92196b60e11b815260040160405180910390fd5b6000611f8284612efd565b90506000611f908483614b9c565b9050611fae858284611fa863ffffffff881683614bdc565b87613266565b50506001600055505050565b600060026000541415611fdf5760405162461bcd60e51b815260040161061090614a10565b6002600055611fed82612982565b611ff682612cc5565b60008381526013602081815260408084208054600160401b810463ffffffff9081168752600685529286205489875294909352921663ffffffff19909116178155600101805460ff16905590915061204d83612fd2565b6001600160a01b03811660009081526008602052604081208054929350849290919061207a908490614cc3565b9091555061209490506001600160a01b03821633846128b1565b604080518481526001600160a01b038316602082015290810183905233907f7d3fe0088fc0b393d0c7629c8d9df3043bd33e8fc1a953dfa251ab201c6ebc389060600160405180910390a2506001600055919050565b6001600160a01b03918216600090815260126020908152604080832093909416825291909152205460ff1690565b60006002600054141561213d5760405162461bcd60e51b815260040161061090614a10565b60026000556003546001600160a01b0386811691161480159061216e57506004546001600160a01b03868116911614155b1561218c5760405163c1ab6dc160e01b815260040160405180910390fd5b63ffffffff83166121b057604051633c92196b60e11b815260040160405180910390fd5b6121c4600963ffffffff8085169061320516565b15801561224f5750600254604051639eceefe160e01b815263ffffffff841660048201526001600160a01b0390911690639eceefe19060240160206040518083038186803b15801561221557600080fd5b505afa158015612229573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061224d9190614277565b155b1561226d576040516305fabb6160e41b815260040160405180910390fd5b6003546000906001600160a01b03878116911614612296576004546001600160a01b03166122a3565b6003546001600160a01b03165b905060006122b763ffffffff861687614c13565b6001600160a01b0390811691506122d2908316333084613414565b6001600160a01b038716600090815260086020526040812080548392906122fa908490614b9c565b925050819055506001601460008282546123149190614b9c565b925050819055506123273360145461344c565b61233b600963ffffffff8087169061346a16565b506000806123506014548a8a8a60008b613476565b601454604080519182526001600160a01b038d811660208401528c169082015263ffffffff8084166060830152808a166080830152821660a0820152919350915033907f7bd589f2fd6a39318e78fbbbadbcd21ce8c1306fc0ecb4d7a49a7e4be9c67e639060c00160405180910390a250506014546001600055979650505050505050565b6123dd613f7d565b6000806000806000806123ee61367d565b9150915060005b8160ff168110156124685782818151811061241257612412614de3565b602002602001015160400151856124299190614b9c565b945082818151811061243d5761243d614de3565b602002602001015160600151846124549190614b9c565b93508061246081614d66565b9150506123f5565b5090865260ff1660208601526004805460015460035460405163a513355f60e01b81526001600160a01b0393841694810194909452600160701b9091046001600160701b031660248401528116604483015287169063a513355f9060640160206040518083038186803b1580156124de57600080fd5b505afa1580156124f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125169190614472565b6080860181905260015461253d906001600160701b0380821691600160701b900416614c42565b6125479190614bdc565b60a0860152608085015161255c908890612c8c565b856080015161256b9190614cc3565b935061257b878660a00151612c8c565b8560a0015161258a9190614cc3565b6001549093506000906125ae90600160701b90046001600160701b03168387613800565b6001549091506000906125cb906001600160701b03168587613800565b905060006125fc6001600e9054906101000a90046001600160701b03166001600160701b0316858a60800151613800565b9050848110156126d1576004546001600160a01b039081166101408a01526003541661016089015261262e8a82612c8c565b60c089015261263d8a85612c8c565b60e0890181905284906126509084614b9c565b61265a9190614cc3565b61010089015260c088015161266f8487614cc3565b6126799190614cc3565b61012089018190526003546001600160a01b03166000908152600860205260409020546126a69190614cc3565b6040808a01919091526004546001600160a01b0316600090815260086020522054606089015261281f565b848111156127cc576003546001600160a01b039081166101408a0152600454166101608901526127018a86612c8c565b60c0890152608088015160015461273d918c9161272e90600160701b90046001600160701b031689614c42565b6127389190614bdc565b612c8c565b60e089015260c088015185906127539085614b9c565b61275d9190614cc3565b61010089015260e08801516127728386614cc3565b61277c9190614cc3565b61012089019081526003546001600160a01b03908116600090815260086020818152604080842054818f0152945160045490941683525291909120546127c29190614cc3565b606089015261281f565b6127d68a86612c8c565b60c08901526127e58a85612c8c565b60e08901526003546001600160a01b03908116600090815260086020818152604080842054818e0152600454909416835252205460608901525b50505050509250925092565b63ffffffff85166000908152600b602090815260408083206001600160a01b0388168452909152902083905561286385858385613817565b63ffffffff94851660009081526005602090815260408083206001600160a01b03909716835295815285822092909616815294525050812055565b60006128aa83836138ab565b9392505050565b6040516001600160a01b038316602482015260448101829052610f3790849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526139a5565b600081815260116020526040902080546001600160a01b0319166001600160a01b0384169081179091558190612949826117da565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600081815260136020526040902054600160601b90046001600160a01b03166129be5760405163673f032f60e11b815260040160405180910390fd5b6129c83382612a15565b6129e557604051635c427cd960e01b815260040160405180910390fd5b50565b610f37836129fc63ffffffff841685614c13565b6001600160a01b0316612a0e86612efd565b8585613266565b6000818152600f60205260408120546001600160a01b0316612a8e5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610610565b6000612a99836117da565b9050806001600160a01b0316846001600160a01b03161480612ad45750836001600160a01b0316612ac984610d91565b6001600160a01b0316145b80612ae45750612ae481856120ea565b949350505050565b826001600160a01b0316612aff826117da565b6001600160a01b031614612b675760405162461bcd60e51b815260206004820152602960248201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960448201526839903737ba1037bbb760b91b6064820152608401610610565b6001600160a01b038216612bc95760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610610565b612bd4600082612914565b6001600160a01b0383166000908152601060205260408120805460019290612bfd908490614cc3565b90915550506001600160a01b0382166000908152601060205260408120805460019290612c2b908490614b9c565b90915550506000818152600f602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b600154600090606490600160e01b900462ffffff16612cb163ffffffff861685614c42565b612cbb9190614bdc565b6128aa9190614bdc565b6000818152601360209081526040808320815160c081018352815463ffffffff80821683526401000000008204811695830195909552600160401b810490941692810192909252600160601b9092046001600160a01b0316606082015260019091015460ff81161515608083018190526101009091046001600160f81b031660a08301528290612d60576004546001600160a01b0316612d6d565b6003546001600160a01b03165b6040808401805163ffffffff9081166000908152600760209081528482206001600160a01b03871683528152848220818901519451841683526006909152938120549495509384928216911610612dc8578460200151612de7565b60408086015163ffffffff908116600090815260066020529190912054165b63ffffffff908116825260208083019390935260409182016000908120548784015183168252600785528382206001600160a01b03881683528552838220885190931682529190935290822054909250612e419083614cc3565b905060008460800151612e6657600154600160701b90046001600160701b0316612e73565b6001546001600160701b03165b6001600160701b03169050600080612e988488606001516001600160a01b0316613a77565b91509150600082612eca5760608801516001600160a01b0316612ebb8587614bdc565b612ec59190614c42565b612ed4565b612ed48483614bdc565b90508760a001516001600160f81b031681612eef9190614b9c565b9a9950505050505050505050565b60008181526013602081815260408084205463ffffffff600160401b8204811686526006845291852054868652939092529182169164010000000090910416818111612f4d575060009392505050565b600084815260136020526040902054600160601b90046001600160a01b0316612f768383614cda565b63ffffffff16612f869190614c13565b6001600160a01b0316949350505050565b60008181526013602052604081206001015460ff16612fc1576004546001600160a01b03166105e7565b50506003546001600160a01b031690565b60008181526013602052604081206001015460ff16612ffc576003546001600160a01b03166105e7565b50506004546001600160a01b031690565b60008181526013602090815260408083205463ffffffff600160401b820481168086526006909452919093205491926401000000009004811691168082111561315057600084815260136020526040812054600160601b90046001600160a01b03169061307986612f97565b63ffffffff861660009081526005602090815260408083206001600160a01b03851684529091528120919250601384900b91906130b7866001614bb4565b63ffffffff1663ffffffff16815260200190815260200160002060008282546130e09190614c84565b909155505063ffffffff851660009081526005602090815260408083206001600160a01b03851684529091528120601384900b9161311f876001614bb4565b63ffffffff1663ffffffff16815260200190815260200160002060008282546131489190614b5b565b909155505050505b505050600090815260136020526040812081815560010155565b6000613175826117da565b9050613182600083612914565b6001600160a01b03811660009081526010602052604081208054600192906131ab908490614cc3565b90915550506000828152600f602052604080822080546001600160a01b0319169055518391906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b600081815260018301602052604081205415156128aa565b60006105e7825490565b60006128aa8383613abf565b61323e848484612aec565b61324a84848484613ae9565b611e065760405162461bcd60e51b81526004016106109061496d565b61326f85612982565b600061327a86612f97565b9050600061328787612cc5565b90506001600160f81b038111156132b157604051630930608960e11b815260040160405180910390fd5b600087815260136020526040902054600160401b900463ffffffff166132d68861300d565b6000806132e78a8689898888613476565b91509150878911156133515761331433306133028b8d614cc3565b6001600160a01b038916929190613414565b61331e888a614cc3565b6001600160a01b03861660009081526008602052604081208054909190613346908490614b9c565b909155506133b09050565b878910156133b0576133638989614cc3565b6001600160a01b0386166000908152600860205260408120805490919061338b908490614cc3565b909155506133b090503361339f8b8b614cc3565b6001600160a01b03881691906128b1565b604080518b81526001600160a01b038916602082015263ffffffff8481168284015283166060820152905133917ffa7c989fea93eb42545a9e7a74f2b8d966813e216a1dd7b59562af10dba259b4919081900360800190a250505050505050505050565b6040516001600160a01b0380851660248301528316604482015260648101829052611e069085906323b872dd60e01b906084016128dd565b613466828260405180602001604052806000815250613bf6565b5050565b60006128aa8383613c29565b6000806001600160a01b0386166134a0576040516314cee7cd60e11b815260040160405180910390fd5b63ffffffff808416600090815260066020526040902054166134c3816001614bb4565b92506134cf8682614bb4565b63ffffffff80861660009081526005602090815260408083206001600160a01b038e16845282528083209388168352929052908120805492945060138a900b9290919061351d908490614b5b565b909155505063ffffffff841660009081526005602090815260408083206001600160a01b038c1684529091528120601389900b9161355c856001614bb4565b63ffffffff1663ffffffff16815260200190815260200160002060008282546135859190614c84565b90915550506040805160c08101825263ffffffff928316815283831660208083019182529684168284019081526001600160a01b039a8b16606084019081526003549c8c169c8c169c909c14608084019081526001600160f81b03998a1660a0850190815260009e8f52601390995293909c209151825491519c519b51909a16600160601b026bffffffffffffffffffffffff9b8516600160401b029b909b1667ffffffffffffffff9c85166401000000000267ffffffffffffffff199092169a90941699909917989098179990991617969096178555955190519091166101000290151560ff161760019290920191909155509091565b606060008061368c600961321d565b90508067ffffffffffffffff8111156136a7576136a7614df9565b6040519080825280602002602001820160405280156136f957816020015b6040805160808101825260008082526020808301829052928201819052606082015282526000199092019101816136c55790505b50925060005b818110156137fa576000613714600983613227565b90504263ffffffff8281166000908152600c60205260409020549181169116116137e75763ffffffff808216600090815260066020526040812054909161375d91166001614bb4565b6040805160808101825263ffffffff80861682528316602082015260035492935091908201906137989085906001600160a01b031685613c78565b81526004546020909101906137b89085906001600160a01b031685613c78565b905286866137c581614d81565b975060ff16815181106137da576137da614de3565b6020026020010181905250505b50806137f281614d66565b9150506136ff565b50509091565b60008361380d8385614c42565b612ae49190614bdc565b63ffffffff841660009081526007602090815260408083206001600160a01b038716845290915281208161384c600186614cda565b63ffffffff168152602081019190915260400160002054905061386f8282614b9c565b63ffffffff95861660009081526007602090815260408083206001600160a01b0390981683529681528682209590971681529390955250502055565b600081815260018301602052604081205480156139945760006138cf600183614cc3565b85549091506000906138e390600190614cc3565b905081811461394857600086600001828154811061390357613903614de3565b906000526020600020015490508087600001848154811061392657613926614de3565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061395957613959614dcd565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506105e7565b60009150506105e7565b5092915050565b60006139fa826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613ccb9092919063ffffffff16565b805190915015610f375780806020019051810190613a189190614277565b610f375760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610610565b60008083613a8b5750600190506000613ab8565b83830283858281613a9e57613a9e614db7565b0414613ab1576000809250925050613ab8565b6001925090505b9250929050565b6000826000018281548110613ad657613ad6614de3565b9060005260206000200154905092915050565b60006001600160a01b0384163b15613beb57604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290613b2d9033908990889088906004016147f9565b602060405180830381600087803b158015613b4757600080fd5b505af1925050508015613b77575060408051601f3d908101601f19168201909252613b74918101906142b1565b60015b613bd1573d808015613ba5576040519150601f19603f3d011682016040523d82523d6000602084013e613baa565b606091505b508051613bc95760405162461bcd60e51b81526004016106109061496d565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050612ae4565b506001949350505050565b613c008383613cda565b613c0d6000848484613ae9565b610f375760405162461bcd60e51b81526004016106109061496d565b6000818152600183016020526040812054613c70575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556105e7565b5060006105e7565b63ffffffff92831660008181526005602090815260408083206001600160a01b0390961680845295825280832094909616825292835284812054918152600b835284812093815292909152919020540190565b6060612ae48484600085613e1c565b6001600160a01b038216613d305760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610610565b6000818152600f60205260409020546001600160a01b031615613d955760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610610565b6001600160a01b0382166000908152601060205260408120805460019290613dbe908490614b9c565b90915550506000818152600f602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b606082471015613e7d5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610610565b843b613ecb5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610610565b600080866001600160a01b03168587604051613ee791906147dd565b60006040518083038185875af1925050503d8060008114613f24576040519150601f19603f3d011682016040523d82523d6000602084013e613f29565b606091505b5091509150613f39828286613f44565b979650505050505050565b60608315613f535750816128aa565b825115613f635782518084602001fd5b8160405162461bcd60e51b8152600401610610919061495a565b60405180610180016040528060608152602001600060ff168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b031681525090565b600082601f83011261400457600080fd5b813561401761401282614b33565b614b02565b81815284602083860101111561402c57600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561405b57600080fd5b81356128aa81614e0f565b6000806040838503121561407957600080fd5b823561408481614e0f565b9150602083013561409481614e0f565b809150509250929050565b6000806000606084860312156140b457600080fd5b83356140bf81614e0f565b925060208401356140cf81614e0f565b929592945050506040919091013590565b600080600080608085870312156140f657600080fd5b843561410181614e0f565b9350602085013561411181614e0f565b925060408501359150606085013567ffffffffffffffff81111561413457600080fd5b61414087828801613ff3565b91505092959194509250565b6000806040838503121561415f57600080fd5b823561416a81614e0f565b9150602083013561409481614e24565b6000806000806080858703121561419057600080fd5b843561419b81614e0f565b935060208501356141ab81614e0f565b925060408501356141bb81614e48565b915060608501356141cb81614e48565b939692955090935050565b600080604083850312156141e957600080fd5b82356141f481614e0f565b946020939093013593505050565b6000806020838503121561421557600080fd5b823567ffffffffffffffff8082111561422d57600080fd5b818501915085601f83011261424157600080fd5b81358181111561425057600080fd5b8660208260051b850101111561426557600080fd5b60209290920196919550909350505050565b60006020828403121561428957600080fd5b81516128aa81614e24565b6000602082840312156142a657600080fd5b81356128aa81614e32565b6000602082840312156142c357600080fd5b81516128aa81614e32565b6000602082840312156142e057600080fd5b81516128aa81614e0f565b6000602082840312156142fd57600080fd5b815167ffffffffffffffff81111561431457600080fd5b8201601f8101841361432557600080fd5b805161433361401282614b33565b81815285602083850101111561434857600080fd5b614359826020830160208601614cff565b95945050505050565b60006060828403121561437457600080fd5b6040516060810181811067ffffffffffffffff8211171561439757614397614df9565b60405282516143a581614e0f565b815260208301516143b581614e24565b602082015260408301516143c881614e48565b60408201529392505050565b6000608082840312156143e657600080fd5b6040516080810181811067ffffffffffffffff8211171561440957614409614df9565b604052825161441781614e0f565b8152602083015161442781614e24565b6020820152604083015161443a81614e48565b6040820152606083015161444d81614e0f565b60608201529392505050565b60006020828403121561446b57600080fd5b5035919050565b60006020828403121561448457600080fd5b5051919050565b6000806040838503121561449e57600080fd5b82359150602083013561409481614e0f565b6000806000606084860312156144c557600080fd5b8335925060208401356144d781614e0f565b915060408401356144e781614e48565b809150509250925092565b60008060008060006080868803121561450a57600080fd5b8535945060208601359350604086013561452381614e0f565b9250606086013567ffffffffffffffff8082111561454057600080fd5b818801915088601f83011261455457600080fd5b81358181111561456357600080fd5b89602082850101111561457557600080fd5b9699959850939650602001949392505050565b6000806000806080858703121561459e57600080fd5b843593506020850135925060408501356145b781614e0f565b9150606085013567ffffffffffffffff81111561413457600080fd5b6000806000606084860312156145e857600080fd5b833592506020840135915060408401356144e781614e48565b6000806040838503121561461457600080fd5b82359150602083013561409481614e48565b60006020828403121561463857600080fd5b81356128aa81614e48565b6000806040838503121561465657600080fd5b823561408481614e48565b60008060006060848603121561467657600080fd5b833561468181614e48565b925060208401356144d781614e0f565b600081518084526020808501945080840160005b838110156146ea578151805163ffffffff90811689528482015116848901526040808201519089015260609081015190880152608090960195908201906001016146a5565b509495945050505050565b6000815180845261470d816020860160208601614cff565b601f01601f19169290920160200192915050565b6000610180825181855261473782860182614691565b915050602083015161474e602086018260ff169052565b5060408301516040850152606083015160608501526080830151608085015260a083015160a085015260c083015160c085015260e083015160e0850152610100808401518186015250610120808401518186015250610140808401516147be828701826001600160a01b03169052565b5050610160928301516001600160a01b03169390920192909252919050565b600082516147ef818460208701614cff565b9190910192915050565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061482c908301846146f5565b9695505050505050565b600061012060018060a01b03808d168452808c166020850152808b1660408501525088606084015287608084015286151560a08401528560c08401528460e08401528061010084015261488b818401856146f5565b9c9b505050505050505050505050565b6001600160a01b038a81168252898116602083015288166040820152606081018790526080810186905260a0810185905260c0810184905261010060e08201819052810182905260006101208385828501376000838501820152601f909301601f19169091019091019998505050505050505050565b6060808252810184905260006001600160fb1b0385111561493157600080fd5b8460051b8087608085013760009083016080019081526020830194909452506040015292915050565b6020815260006128aa60208301846146f5565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6020815260006128aa6020830184614721565b60006101008201905060018060a01b0380845116835280602085015116602084015250604083015163ffffffff8082166040850152806060860151166060850152608085015160808501528060a08601511660a0850152505060c083015160c083015260e083015161399e60e08401826001600160a01b03169052565b84815283602082015263ffffffff8316604082015260806060820152600061482c6080830184614721565b604051601f8201601f1916810167ffffffffffffffff81118282101715614b2b57614b2b614df9565b604052919050565b600067ffffffffffffffff821115614b4d57614b4d614df9565b50601f01601f191660200190565b600080821280156001600160ff1b0384900385131615614b7d57614b7d614da1565b600160ff1b8390038412811615614b9657614b96614da1565b50500190565b60008219821115614baf57614baf614da1565b500190565b600063ffffffff808316818516808303821115614bd357614bd3614da1565b01949350505050565b600082614beb57614beb614db7565b500490565b600063ffffffff80841680614c0757614c07614db7565b92169190910492915050565b60006001600160a01b0382811684821681151582840482111615614c3957614c39614da1565b02949350505050565b6000816000190483118215151615614c5c57614c5c614da1565b500290565b600063ffffffff80831681851681830481118215151615614c3957614c39614da1565b60008083128015600160ff1b850184121615614ca257614ca2614da1565b6001600160ff1b0384018313811615614cbd57614cbd614da1565b50500390565b600082821015614cd557614cd5614da1565b500390565b600063ffffffff83811690831681811015614cf757614cf7614da1565b039392505050565b60005b83811015614d1a578181015183820152602001614d02565b83811115611e065750506000910152565b600181811c90821680614d3f57607f821691505b60208210811415614d6057634e487b7160e01b600052602260045260246000fd5b50919050565b6000600019821415614d7a57614d7a614da1565b5060010190565b600060ff821660ff811415614d9857614d98614da1565b60010192915050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146129e557600080fd5b80151581146129e557600080fd5b6001600160e01b0319811681146129e557600080fd5b63ffffffff811681146129e557600080fdfea2646970667358221220da0ad3258994f7770df48129c19337805ef590f1281c528c08c5b258ec87a40964736f6c63430008060033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000dbcca406b622ed1f455abc9560d51aa0c81560f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
-----Decoded View---------------
Arg [0] : _globalParameters (address): 0x0dBCcA406b622ed1f455abC9560d51Aa0C81560F
Arg [1] : _tokenA (address): 0x6B175474E89094C44Da98b954EedeAC495271d0F
Arg [2] : _tokenB (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000000dbcca406b622ed1f455abc9560d51aa0c81560f
Arg [1] : 0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f
Arg [2] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Loading...
Loading
Loading...
Loading
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.