Overview
ETH Balance
0 ETH
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 internal transactions (View All)
Loading...
Loading
Contract Name:
AlgebraPoolDeployer
Compiler Version
v0.7.6+commit.7338295f
Optimization Enabled:
Yes with 0 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.7.6; import './interfaces/IAlgebraPoolDeployer.sol'; import './AlgebraPool.sol'; contract AlgebraPoolDeployer is IAlgebraPoolDeployer { struct Parameters { address dataStorage; address factory; address token0; address token1; } /// @inheritdoc IAlgebraPoolDeployer Parameters public override parameters; address private factory; address private owner; modifier onlyFactory() { require(msg.sender == factory); _; } modifier onlyOwner() { require(msg.sender == owner); _; } constructor() { owner = msg.sender; } /// @inheritdoc IAlgebraPoolDeployer function setFactory(address _factory) external override onlyOwner { require(_factory != address(0)); require(factory == address(0)); emit Factory(_factory); factory = _factory; } /// @inheritdoc IAlgebraPoolDeployer function deploy( address dataStorage, address _factory, address token0, address token1 ) external override onlyFactory returns (address pool) { parameters = Parameters({dataStorage: dataStorage, factory: _factory, token0: token0, token1: token1}); pool = address(new AlgebraPool{salt: keccak256(abi.encode(token0, token1))}()); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.7.6; import './interfaces/IAlgebraPool.sol'; import './interfaces/IDataStorageOperator.sol'; import './interfaces/IAlgebraVirtualPool.sol'; import './base/PoolState.sol'; import './base/PoolImmutables.sol'; import './libraries/TokenDeltaMath.sol'; import './libraries/PriceMovementMath.sol'; import './libraries/TickManager.sol'; import './libraries/TickTable.sol'; import './libraries/LowGasSafeMath.sol'; import './libraries/SafeCast.sol'; import './libraries/FullMath.sol'; import './libraries/Constants.sol'; import './libraries/TransferHelper.sol'; import './libraries/TickMath.sol'; import './libraries/LiquidityMath.sol'; import './interfaces/IAlgebraPoolDeployer.sol'; import './interfaces/IAlgebraFactory.sol'; import './interfaces/IERC20Minimal.sol'; import './interfaces/callback/IAlgebraMintCallback.sol'; import './interfaces/callback/IAlgebraSwapCallback.sol'; import './interfaces/callback/IAlgebraFlashCallback.sol'; contract AlgebraPool is PoolState, PoolImmutables, IAlgebraPool { using LowGasSafeMath for uint256; using LowGasSafeMath for int256; using LowGasSafeMath for uint128; using SafeCast for uint256; using SafeCast for int256; using TickTable for mapping(int16 => uint256); using TickManager for mapping(int24 => TickManager.Tick); struct Position { uint128 liquidity; // The amount of liquidity concentrated in the range uint32 lastLiquidityAddTimestamp; // Timestamp of last adding of liquidity uint256 innerFeeGrowth0Token; // The last updated fee growth per unit of liquidity uint256 innerFeeGrowth1Token; uint128 fees0; // The amount of token0 owed to a LP uint128 fees1; // The amount of token1 owed to a LP } /// @inheritdoc IAlgebraPoolState mapping(bytes32 => Position) public override positions; /// @dev Restricts everyone calling a function except factory owner modifier onlyFactoryOwner() { require(msg.sender == IAlgebraFactory(factory).owner()); _; } modifier onlyValidTicks(int24 bottomTick, int24 topTick) { require(topTick < TickMath.MAX_TICK + 1, 'TUM'); require(topTick > bottomTick, 'TLU'); require(bottomTick > TickMath.MIN_TICK - 1, 'TLM'); _; } constructor() PoolImmutables(msg.sender) { globalState.fee = Constants.BASE_FEE; } function balanceToken0() private view returns (uint256) { return IERC20Minimal(token0).balanceOf(address(this)); } function balanceToken1() private view returns (uint256) { return IERC20Minimal(token1).balanceOf(address(this)); } /// @inheritdoc IAlgebraPoolState function timepoints(uint256 index) external view override returns ( bool initialized, uint32 blockTimestamp, int56 tickCumulative, uint160 secondsPerLiquidityCumulative, uint88 volatilityCumulative, int24 averageTick, uint144 volumePerLiquidityCumulative ) { return IDataStorageOperator(dataStorageOperator).timepoints(index); } struct Cumulatives { int56 tickCumulative; uint160 outerSecondPerLiquidity; uint32 outerSecondsSpent; } /// @inheritdoc IAlgebraPoolDerivedState function getInnerCumulatives(int24 bottomTick, int24 topTick) external view override onlyValidTicks(bottomTick, topTick) returns ( int56 innerTickCumulative, uint160 innerSecondsSpentPerLiquidity, uint32 innerSecondsSpent ) { Cumulatives memory lower; { TickManager.Tick storage _lower = ticks[bottomTick]; (lower.tickCumulative, lower.outerSecondPerLiquidity, lower.outerSecondsSpent) = ( _lower.outerTickCumulative, _lower.outerSecondsPerLiquidity, _lower.outerSecondsSpent ); require(_lower.initialized); } Cumulatives memory upper; { TickManager.Tick storage _upper = ticks[topTick]; (upper.tickCumulative, upper.outerSecondPerLiquidity, upper.outerSecondsSpent) = ( _upper.outerTickCumulative, _upper.outerSecondsPerLiquidity, _upper.outerSecondsSpent ); require(_upper.initialized); } (int24 currentTick, uint16 currentTimepointIndex) = (globalState.tick, globalState.timepointIndex); if (currentTick < bottomTick) { return ( lower.tickCumulative - upper.tickCumulative, lower.outerSecondPerLiquidity - upper.outerSecondPerLiquidity, lower.outerSecondsSpent - upper.outerSecondsSpent ); } if (currentTick < topTick) { uint32 globalTime = _blockTimestamp(); (int56 globalTickCumulative, uint160 globalSecondsPerLiquidityCumulative, , ) = _getSingleTimepoint( globalTime, 0, currentTick, currentTimepointIndex, liquidity ); return ( globalTickCumulative - lower.tickCumulative - upper.tickCumulative, globalSecondsPerLiquidityCumulative - lower.outerSecondPerLiquidity - upper.outerSecondPerLiquidity, globalTime - lower.outerSecondsSpent - upper.outerSecondsSpent ); } return ( upper.tickCumulative - lower.tickCumulative, upper.outerSecondPerLiquidity - lower.outerSecondPerLiquidity, upper.outerSecondsSpent - lower.outerSecondsSpent ); } /// @inheritdoc IAlgebraPoolDerivedState function getTimepoints(uint32[] calldata secondsAgos) external view override returns ( int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulatives, uint112[] memory volatilityCumulatives, uint256[] memory volumePerAvgLiquiditys ) { return IDataStorageOperator(dataStorageOperator).getTimepoints( _blockTimestamp(), secondsAgos, globalState.tick, globalState.timepointIndex, liquidity ); } /// @inheritdoc IAlgebraPoolActions function initialize(uint160 initialPrice) external override { require(globalState.price == 0, 'AI'); // getTickAtSqrtRatio checks validity of initialPrice inside int24 tick = TickMath.getTickAtSqrtRatio(initialPrice); uint32 timestamp = _blockTimestamp(); IDataStorageOperator(dataStorageOperator).initialize(timestamp, tick); globalState.price = initialPrice; globalState.unlocked = true; globalState.tick = tick; emit Initialize(initialPrice, tick); } /** * @notice Increases amounts of tokens owed to owner of the position * @param _position The position object to operate with * @param liquidityDelta The amount on which to increase\decrease the liquidity * @param innerFeeGrowth0Token Total fee token0 fee growth per 1/liquidity between position's lower and upper ticks * @param innerFeeGrowth1Token Total fee token1 fee growth per 1/liquidity between position's lower and upper ticks */ function _recalculatePosition( Position storage _position, int128 liquidityDelta, uint256 innerFeeGrowth0Token, uint256 innerFeeGrowth1Token ) internal { (uint128 currentLiquidity, uint32 lastLiquidityAddTimestamp) = (_position.liquidity, _position.lastLiquidityAddTimestamp); if (liquidityDelta == 0) { require(currentLiquidity > 0, 'NP'); // Do not recalculate the empty ranges } else { if (liquidityDelta < 0) { uint32 _liquidityCooldown = liquidityCooldown; if (_liquidityCooldown > 0) { require((_blockTimestamp() - lastLiquidityAddTimestamp) >= _liquidityCooldown); } } // change position liquidity uint128 liquidityNext = LiquidityMath.addDelta(currentLiquidity, liquidityDelta); (_position.liquidity, _position.lastLiquidityAddTimestamp) = ( liquidityNext, liquidityNext > 0 ? (liquidityDelta > 0 ? _blockTimestamp() : lastLiquidityAddTimestamp) : 0 ); } // update the position uint256 _innerFeeGrowth0Token = _position.innerFeeGrowth0Token; uint256 _innerFeeGrowth1Token = _position.innerFeeGrowth1Token; uint128 fees0; if (innerFeeGrowth0Token != _innerFeeGrowth0Token) { _position.innerFeeGrowth0Token = innerFeeGrowth0Token; fees0 = uint128(FullMath.mulDiv(innerFeeGrowth0Token - _innerFeeGrowth0Token, currentLiquidity, Constants.Q128)); } uint128 fees1; if (innerFeeGrowth1Token != _innerFeeGrowth1Token) { _position.innerFeeGrowth1Token = innerFeeGrowth1Token; fees1 = uint128(FullMath.mulDiv(innerFeeGrowth1Token - _innerFeeGrowth1Token, currentLiquidity, Constants.Q128)); } // To avoid overflow owner has to collect fee before it if (fees0 | fees1 != 0) { _position.fees0 += fees0; _position.fees1 += fees1; } } struct UpdatePositionCache { uint160 price; // The square root of the current price in Q64.96 format int24 tick; // The current tick uint16 timepointIndex; // The index of the last written timepoint } /** * @dev Updates position's ticks and its fees * @return position The Position object to operate with * @return amount0 The amount of token0 the caller needs to send, negative if the pool needs to send it * @return amount1 The amount of token1 the caller needs to send, negative if the pool needs to send it */ function _updatePositionTicksAndFees( address owner, int24 bottomTick, int24 topTick, int128 liquidityDelta ) private returns ( Position storage position, int256 amount0, int256 amount1 ) { UpdatePositionCache memory cache = UpdatePositionCache(globalState.price, globalState.tick, globalState.timepointIndex); position = getOrCreatePosition(owner, bottomTick, topTick); (uint256 _totalFeeGrowth0Token, uint256 _totalFeeGrowth1Token) = (totalFeeGrowth0Token, totalFeeGrowth1Token); bool toggledBottom; bool toggledTop; if (liquidityDelta != 0) { uint32 time = _blockTimestamp(); (int56 tickCumulative, uint160 secondsPerLiquidityCumulative, , ) = _getSingleTimepoint(time, 0, cache.tick, cache.timepointIndex, liquidity); if ( ticks.update( bottomTick, cache.tick, liquidityDelta, _totalFeeGrowth0Token, _totalFeeGrowth1Token, secondsPerLiquidityCumulative, tickCumulative, time, false // isTopTick ) ) { toggledBottom = true; tickTable.toggleTick(bottomTick); } if ( ticks.update( topTick, cache.tick, liquidityDelta, _totalFeeGrowth0Token, _totalFeeGrowth1Token, secondsPerLiquidityCumulative, tickCumulative, time, true // isTopTick ) ) { toggledTop = true; tickTable.toggleTick(topTick); } } (uint256 feeGrowthInside0X128, uint256 feeGrowthInside1X128) = ticks.getInnerFeeGrowth( bottomTick, topTick, cache.tick, _totalFeeGrowth0Token, _totalFeeGrowth1Token ); _recalculatePosition(position, liquidityDelta, feeGrowthInside0X128, feeGrowthInside1X128); if (liquidityDelta != 0) { // if liquidityDelta is negative and the tick was toggled, it means that it should not be initialized anymore, so we delete it if (liquidityDelta < 0) { if (toggledBottom) delete ticks[bottomTick]; if (toggledTop) delete ticks[topTick]; } int128 globalLiquidityDelta; (amount0, amount1, globalLiquidityDelta) = _getAmountsForLiquidity(bottomTick, topTick, liquidityDelta, cache.tick, cache.price); if (globalLiquidityDelta != 0) { uint128 liquidityBefore = liquidity; uint16 newTimepointIndex = _writeTimepoint(cache.timepointIndex, _blockTimestamp(), cache.tick, liquidityBefore, volumePerLiquidityInBlock); if (cache.timepointIndex != newTimepointIndex) { globalState.fee = _getNewFee(_blockTimestamp(), cache.tick, newTimepointIndex, liquidityBefore); globalState.timepointIndex = newTimepointIndex; volumePerLiquidityInBlock = 0; } liquidity = LiquidityMath.addDelta(liquidityBefore, liquidityDelta); } } } function _getAmountsForLiquidity( int24 bottomTick, int24 topTick, int128 liquidityDelta, int24 currentTick, uint160 currentPrice ) private pure returns ( int256 amount0, int256 amount1, int128 globalLiquidityDelta ) { // If current tick is less than the provided bottom one then only the token0 has to be provided if (currentTick < bottomTick) { amount0 = TokenDeltaMath.getToken0Delta(TickMath.getSqrtRatioAtTick(bottomTick), TickMath.getSqrtRatioAtTick(topTick), liquidityDelta); } else if (currentTick < topTick) { amount0 = TokenDeltaMath.getToken0Delta(currentPrice, TickMath.getSqrtRatioAtTick(topTick), liquidityDelta); amount1 = TokenDeltaMath.getToken1Delta(TickMath.getSqrtRatioAtTick(bottomTick), currentPrice, liquidityDelta); globalLiquidityDelta = liquidityDelta; } // If current tick is greater than the provided top one then only the token1 has to be provided else { amount1 = TokenDeltaMath.getToken1Delta(TickMath.getSqrtRatioAtTick(bottomTick), TickMath.getSqrtRatioAtTick(topTick), liquidityDelta); } } /** * @notice This function fetches certain position object * @param owner The address owing the position * @param bottomTick The position's bottom tick * @param topTick The position's top tick * @return position The Position object */ function getOrCreatePosition( address owner, int24 bottomTick, int24 topTick ) private view returns (Position storage) { bytes32 key; assembly { key := or(shl(24, or(shl(24, owner), and(bottomTick, 0xFFFFFF))), and(topTick, 0xFFFFFF)) } return positions[key]; } /// @inheritdoc IAlgebraPoolActions function mint( address sender, address recipient, int24 bottomTick, int24 topTick, uint128 liquidityDesired, bytes calldata data ) external override lock onlyValidTicks(bottomTick, topTick) returns ( uint256 amount0, uint256 amount1, uint128 liquidityActual ) { require(liquidityDesired > 0, 'IL'); { (int256 amount0Int, int256 amount1Int, ) = _getAmountsForLiquidity( bottomTick, topTick, int256(liquidityDesired).toInt128(), globalState.tick, globalState.price ); amount0 = uint256(amount0Int); amount1 = uint256(amount1Int); } uint256 receivedAmount0; uint256 receivedAmount1; { if (amount0 > 0) receivedAmount0 = balanceToken0(); if (amount1 > 0) receivedAmount1 = balanceToken1(); IAlgebraMintCallback(msg.sender).algebraMintCallback(amount0, amount1, data); if (amount0 > 0) require((receivedAmount0 = balanceToken0() - receivedAmount0) > 0, 'IIAM'); if (amount1 > 0) require((receivedAmount1 = balanceToken1() - receivedAmount1) > 0, 'IIAM'); } liquidityActual = liquidityDesired; if (receivedAmount0 < amount0) { liquidityActual = uint128(FullMath.mulDiv(uint256(liquidityActual), receivedAmount0, amount0)); } if (receivedAmount1 < amount1) { uint128 liquidityForRA1 = uint128(FullMath.mulDiv(uint256(liquidityActual), receivedAmount1, amount1)); if (liquidityForRA1 < liquidityActual) { liquidityActual = liquidityForRA1; } } require(liquidityActual > 0, 'IIL2'); { (, int256 amount0Int, int256 amount1Int) = _updatePositionTicksAndFees(recipient, bottomTick, topTick, int256(liquidityActual).toInt128()); require((amount0 = uint256(amount0Int)) <= receivedAmount0, 'IIAM2'); require((amount1 = uint256(amount1Int)) <= receivedAmount1, 'IIAM2'); } if (receivedAmount0 > amount0) { TransferHelper.safeTransfer(token0, sender, receivedAmount0 - amount0); } if (receivedAmount1 > amount1) { TransferHelper.safeTransfer(token1, sender, receivedAmount1 - amount1); } emit Mint(msg.sender, recipient, bottomTick, topTick, liquidityActual, amount0, amount1); } /// @inheritdoc IAlgebraPoolActions function collect( address recipient, int24 bottomTick, int24 topTick, uint128 amount0Requested, uint128 amount1Requested ) external override lock returns (uint128 amount0, uint128 amount1) { Position storage position = getOrCreatePosition(msg.sender, bottomTick, topTick); (uint128 positionFees0, uint128 positionFees1) = (position.fees0, position.fees1); amount0 = amount0Requested > positionFees0 ? positionFees0 : amount0Requested; amount1 = amount1Requested > positionFees1 ? positionFees1 : amount1Requested; if (amount0 | amount1 != 0) { position.fees0 = positionFees0 - amount0; position.fees1 = positionFees1 - amount1; if (amount0 > 0) TransferHelper.safeTransfer(token0, recipient, amount0); if (amount1 > 0) TransferHelper.safeTransfer(token1, recipient, amount1); } emit Collect(msg.sender, recipient, bottomTick, topTick, amount0, amount1); } /// @inheritdoc IAlgebraPoolActions function burn( int24 bottomTick, int24 topTick, uint128 amount ) external override lock onlyValidTicks(bottomTick, topTick) returns (uint256 amount0, uint256 amount1) { (Position storage position, int256 amount0Int, int256 amount1Int) = _updatePositionTicksAndFees( msg.sender, bottomTick, topTick, -int256(amount).toInt128() ); amount0 = uint256(-amount0Int); amount1 = uint256(-amount1Int); if (amount0 | amount1 != 0) { (position.fees0, position.fees1) = (position.fees0.add128(uint128(amount0)), position.fees1.add128(uint128(amount1))); } emit Burn(msg.sender, bottomTick, topTick, amount, amount0, amount1); } /// @dev Returns new fee according combination of sigmoids function _getNewFee( uint32 _time, int24 _tick, uint16 _index, uint128 _liquidity ) private returns (uint16 newFee) { newFee = IDataStorageOperator(dataStorageOperator).getFee(_time, _tick, _index, _liquidity); emit Fee(newFee); } function _payCommunityFee(address token, uint256 amount) private { address vault = IAlgebraFactory(factory).vaultAddress(); TransferHelper.safeTransfer(token, vault, amount); } function _writeTimepoint( uint16 timepointIndex, uint32 blockTimestamp, int24 tick, uint128 liquidity, uint128 volumePerLiquidityInBlock ) private returns (uint16 newTimepointIndex) { return IDataStorageOperator(dataStorageOperator).write(timepointIndex, blockTimestamp, tick, liquidity, volumePerLiquidityInBlock); } function _getSingleTimepoint( uint32 blockTimestamp, uint32 secondsAgo, int24 startTick, uint16 timepointIndex, uint128 liquidityStart ) private view returns ( int56 tickCumulative, uint160 secondsPerLiquidityCumulative, uint112 volatilityCumulative, uint256 volumePerAvgLiquidity ) { return IDataStorageOperator(dataStorageOperator).getSingleTimepoint(blockTimestamp, secondsAgo, startTick, timepointIndex, liquidityStart); } function _swapCallback( int256 amount0, int256 amount1, bytes calldata data ) private { IAlgebraSwapCallback(msg.sender).algebraSwapCallback(amount0, amount1, data); } /// @inheritdoc IAlgebraPoolActions function swap( address recipient, bool zeroToOne, int256 amountRequired, uint160 limitSqrtPrice, bytes calldata data ) external override returns (int256 amount0, int256 amount1) { uint160 currentPrice; int24 currentTick; uint128 currentLiquidity; uint256 communityFee; // function _calculateSwapAndLock locks globalState.unlocked and does not release (amount0, amount1, currentPrice, currentTick, currentLiquidity, communityFee) = _calculateSwapAndLock(zeroToOne, amountRequired, limitSqrtPrice); if (zeroToOne) { if (amount1 < 0) TransferHelper.safeTransfer(token1, recipient, uint256(-amount1)); // transfer to recipient uint256 balance0Before = balanceToken0(); _swapCallback(amount0, amount1, data); // callback to get tokens from the caller require(balance0Before.add(uint256(amount0)) <= balanceToken0(), 'IIA'); } else { if (amount0 < 0) TransferHelper.safeTransfer(token0, recipient, uint256(-amount0)); // transfer to recipient uint256 balance1Before = balanceToken1(); _swapCallback(amount0, amount1, data); // callback to get tokens from the caller require(balance1Before.add(uint256(amount1)) <= balanceToken1(), 'IIA'); } if (communityFee > 0) { _payCommunityFee(zeroToOne ? token0 : token1, communityFee); } emit Swap(msg.sender, recipient, amount0, amount1, currentPrice, currentLiquidity, currentTick); globalState.unlocked = true; // release after lock in _calculateSwapAndLock } /// @inheritdoc IAlgebraPoolActions function swapSupportingFeeOnInputTokens( address sender, address recipient, bool zeroToOne, int256 amountRequired, uint160 limitSqrtPrice, bytes calldata data ) external override returns (int256 amount0, int256 amount1) { // Since the pool can get less tokens then sent, firstly we are getting tokens from the // original caller of the transaction. And change the _amountRequired_ require(globalState.unlocked, 'LOK'); globalState.unlocked = false; if (zeroToOne) { uint256 balance0Before = balanceToken0(); _swapCallback(amountRequired, 0, data); require((amountRequired = int256(balanceToken0().sub(balance0Before))) > 0, 'IIA'); } else { uint256 balance1Before = balanceToken1(); _swapCallback(0, amountRequired, data); require((amountRequired = int256(balanceToken1().sub(balance1Before))) > 0, 'IIA'); } globalState.unlocked = true; uint160 currentPrice; int24 currentTick; uint128 currentLiquidity; uint256 communityFee; // function _calculateSwapAndLock locks 'globalState.unlocked' and does not release (amount0, amount1, currentPrice, currentTick, currentLiquidity, communityFee) = _calculateSwapAndLock(zeroToOne, amountRequired, limitSqrtPrice); // only transfer to the recipient if (zeroToOne) { if (amount1 < 0) TransferHelper.safeTransfer(token1, recipient, uint256(-amount1)); // return the leftovers if (amount0 < amountRequired) TransferHelper.safeTransfer(token0, sender, uint256(amountRequired.sub(amount0))); } else { if (amount0 < 0) TransferHelper.safeTransfer(token0, recipient, uint256(-amount0)); // return the leftovers if (amount1 < amountRequired) TransferHelper.safeTransfer(token1, sender, uint256(amountRequired.sub(amount1))); } if (communityFee > 0) { _payCommunityFee(zeroToOne ? token0 : token1, communityFee); } emit Swap(msg.sender, recipient, amount0, amount1, currentPrice, currentLiquidity, currentTick); globalState.unlocked = true; // release after lock in _calculateSwapAndLock } struct SwapCalculationCache { uint256 communityFee; // The community fee of the selling token, uint256 to minimize casts uint128 volumePerLiquidityInBlock; int56 tickCumulative; // The global tickCumulative at the moment uint160 secondsPerLiquidityCumulative; // The global secondPerLiquidity at the moment bool computedLatestTimepoint; // if we have already fetched _tickCumulative_ and _secondPerLiquidity_ from the DataOperator int256 amountRequiredInitial; // The initial value of the exact input\output amount int256 amountCalculated; // The additive amount of total output\input calculated trough the swap uint256 totalFeeGrowth; // The initial totalFeeGrowth + the fee growth during a swap uint256 totalFeeGrowthB; IAlgebraVirtualPool.Status incentiveStatus; // If there is an active incentive at the moment bool exactInput; // Whether the exact input or output is specified uint16 fee; // The current dynamic fee int24 startTick; // The tick at the start of a swap uint16 timepointIndex; // The index of last written timepoint } struct PriceMovementCache { uint160 stepSqrtPrice; // The Q64.96 sqrt of the price at the start of the step int24 nextTick; // The tick till the current step goes bool initialized; // True if the _nextTick is initialized uint160 nextTickPrice; // The Q64.96 sqrt of the price calculated from the _nextTick uint256 input; // The additive amount of tokens that have been provided uint256 output; // The additive amount of token that have been withdrawn uint256 feeAmount; // The total amount of fee earned within a current step } /// @notice For gas optimization, locks 'globalState.unlocked' and does not release. function _calculateSwapAndLock( bool zeroToOne, int256 amountRequired, uint160 limitSqrtPrice ) private returns ( int256 amount0, int256 amount1, uint160 currentPrice, int24 currentTick, uint128 currentLiquidity, uint256 communityFeeAmount ) { uint32 blockTimestamp; SwapCalculationCache memory cache; { // load from one storage slot currentPrice = globalState.price; currentTick = globalState.tick; cache.fee = globalState.fee; cache.timepointIndex = globalState.timepointIndex; uint256 _communityFeeToken0 = globalState.communityFeeToken0; uint256 _communityFeeToken1 = globalState.communityFeeToken1; bool unlocked = globalState.unlocked; globalState.unlocked = false; // lock will not be released in this function require(unlocked, 'LOK'); require(amountRequired != 0, 'AS'); (cache.amountRequiredInitial, cache.exactInput) = (amountRequired, amountRequired > 0); (currentLiquidity, cache.volumePerLiquidityInBlock) = (liquidity, volumePerLiquidityInBlock); if (zeroToOne) { require(limitSqrtPrice < currentPrice && limitSqrtPrice > TickMath.MIN_SQRT_RATIO, 'SPL'); cache.totalFeeGrowth = totalFeeGrowth0Token; cache.communityFee = _communityFeeToken0; } else { require(limitSqrtPrice > currentPrice && limitSqrtPrice < TickMath.MAX_SQRT_RATIO, 'SPL'); cache.totalFeeGrowth = totalFeeGrowth1Token; cache.communityFee = _communityFeeToken1; } cache.startTick = currentTick; blockTimestamp = _blockTimestamp(); if (activeIncentive != address(0)) { IAlgebraVirtualPool.Status _status = IAlgebraVirtualPool(activeIncentive).increaseCumulative(blockTimestamp); if (_status == IAlgebraVirtualPool.Status.NOT_EXIST) { activeIncentive = address(0); } else if (_status == IAlgebraVirtualPool.Status.ACTIVE) { cache.incentiveStatus = IAlgebraVirtualPool.Status.ACTIVE; } else if (_status == IAlgebraVirtualPool.Status.NOT_STARTED) { cache.incentiveStatus = IAlgebraVirtualPool.Status.NOT_STARTED; } } uint16 newTimepointIndex = _writeTimepoint( cache.timepointIndex, blockTimestamp, cache.startTick, currentLiquidity, cache.volumePerLiquidityInBlock ); // new timepoint appears only for first swap in block if (newTimepointIndex != cache.timepointIndex) { cache.timepointIndex = newTimepointIndex; cache.volumePerLiquidityInBlock = 0; cache.fee = _getNewFee(blockTimestamp, currentTick, newTimepointIndex, currentLiquidity); } } PriceMovementCache memory step; // swap until there is remaining input or output tokens or we reach the price limit while (true) { step.stepSqrtPrice = currentPrice; (step.nextTick, step.initialized) = tickTable.nextTickInTheSameRow(currentTick, zeroToOne); step.nextTickPrice = TickMath.getSqrtRatioAtTick(step.nextTick); // calculate the amounts needed to move the price to the next target if it is possible or as much as possible (currentPrice, step.input, step.output, step.feeAmount) = PriceMovementMath.movePriceTowardsTarget( zeroToOne, currentPrice, (zeroToOne == (step.nextTickPrice < limitSqrtPrice)) // move the price to the target or to the limit ? limitSqrtPrice : step.nextTickPrice, currentLiquidity, amountRequired, cache.fee ); if (cache.exactInput) { amountRequired -= (step.input + step.feeAmount).toInt256(); // decrease remaining input amount cache.amountCalculated = cache.amountCalculated.sub(step.output.toInt256()); // decrease calculated output amount } else { amountRequired += step.output.toInt256(); // increase remaining output amount (since its negative) cache.amountCalculated = cache.amountCalculated.add((step.input + step.feeAmount).toInt256()); // increase calculated input amount } if (cache.communityFee > 0) { uint256 delta = (step.feeAmount.mul(cache.communityFee)) / Constants.COMMUNITY_FEE_DENOMINATOR; step.feeAmount -= delta; communityFeeAmount += delta; } if (currentLiquidity > 0) cache.totalFeeGrowth += FullMath.mulDiv(step.feeAmount, Constants.Q128, currentLiquidity); if (currentPrice == step.nextTickPrice) { // if the reached tick is initialized then we need to cross it if (step.initialized) { // once at a swap we have to get the last timepoint of the observation if (!cache.computedLatestTimepoint) { (cache.tickCumulative, cache.secondsPerLiquidityCumulative, , ) = _getSingleTimepoint( blockTimestamp, 0, cache.startTick, cache.timepointIndex, currentLiquidity // currentLiquidity can be changed only after computedLatestTimepoint ); cache.computedLatestTimepoint = true; cache.totalFeeGrowthB = zeroToOne ? totalFeeGrowth1Token : totalFeeGrowth0Token; } // every tick cross is needed to be duplicated in a virtual pool if (cache.incentiveStatus != IAlgebraVirtualPool.Status.NOT_EXIST) { IAlgebraVirtualPool(activeIncentive).cross(step.nextTick, zeroToOne); } int128 liquidityDelta; if (zeroToOne) { liquidityDelta = -ticks.cross( step.nextTick, cache.totalFeeGrowth, // A == 0 cache.totalFeeGrowthB, // B == 1 cache.secondsPerLiquidityCumulative, cache.tickCumulative, blockTimestamp ); } else { liquidityDelta = ticks.cross( step.nextTick, cache.totalFeeGrowthB, // B == 0 cache.totalFeeGrowth, // A == 1 cache.secondsPerLiquidityCumulative, cache.tickCumulative, blockTimestamp ); } currentLiquidity = LiquidityMath.addDelta(currentLiquidity, liquidityDelta); } currentTick = zeroToOne ? step.nextTick - 1 : step.nextTick; } else if (currentPrice != step.stepSqrtPrice) { // if the price has changed but hasn't reached the target currentTick = TickMath.getTickAtSqrtRatio(currentPrice); break; // since the price hasn't reached the target, amountRequired should be 0 } // check stop condition if (amountRequired == 0 || currentPrice == limitSqrtPrice) { break; } } (amount0, amount1) = zeroToOne == cache.exactInput // the amount to provide could be less then initially specified (e.g. reached limit) ? (cache.amountRequiredInitial - amountRequired, cache.amountCalculated) // the amount to get could be less then initially specified (e.g. reached limit) : (cache.amountCalculated, cache.amountRequiredInitial - amountRequired); (globalState.price, globalState.tick, globalState.fee, globalState.timepointIndex) = (currentPrice, currentTick, cache.fee, cache.timepointIndex); (liquidity, volumePerLiquidityInBlock) = ( currentLiquidity, cache.volumePerLiquidityInBlock + IDataStorageOperator(dataStorageOperator).calculateVolumePerLiquidity(currentLiquidity, amount0, amount1) ); if (zeroToOne) { totalFeeGrowth0Token = cache.totalFeeGrowth; } else { totalFeeGrowth1Token = cache.totalFeeGrowth; } } /// @inheritdoc IAlgebraPoolActions function flash( address recipient, uint256 amount0, uint256 amount1, bytes calldata data ) external override lock { uint128 _liquidity = liquidity; require(_liquidity > 0, 'L'); uint16 _fee = globalState.fee; uint256 fee0; uint256 balance0Before = balanceToken0(); if (amount0 > 0) { fee0 = FullMath.mulDivRoundingUp(amount0, _fee, 1e6); TransferHelper.safeTransfer(token0, recipient, amount0); } uint256 fee1; uint256 balance1Before = balanceToken1(); if (amount1 > 0) { fee1 = FullMath.mulDivRoundingUp(amount1, _fee, 1e6); TransferHelper.safeTransfer(token1, recipient, amount1); } IAlgebraFlashCallback(msg.sender).algebraFlashCallback(fee0, fee1, data); address vault = IAlgebraFactory(factory).vaultAddress(); uint256 paid0 = balanceToken0(); require(balance0Before.add(fee0) <= paid0, 'F0'); paid0 -= balance0Before; if (paid0 > 0) { uint8 _communityFeeToken0 = globalState.communityFeeToken0; uint256 fees0; if (_communityFeeToken0 > 0) { fees0 = (paid0 * _communityFeeToken0) / Constants.COMMUNITY_FEE_DENOMINATOR; TransferHelper.safeTransfer(token0, vault, fees0); } totalFeeGrowth0Token += FullMath.mulDiv(paid0 - fees0, Constants.Q128, _liquidity); } uint256 paid1 = balanceToken1(); require(balance1Before.add(fee1) <= paid1, 'F1'); paid1 -= balance1Before; if (paid1 > 0) { uint8 _communityFeeToken1 = globalState.communityFeeToken1; uint256 fees1; if (_communityFeeToken1 > 0) { fees1 = (paid1 * _communityFeeToken1) / Constants.COMMUNITY_FEE_DENOMINATOR; TransferHelper.safeTransfer(token1, vault, fees1); } totalFeeGrowth1Token += FullMath.mulDiv(paid1 - fees1, Constants.Q128, _liquidity); } emit Flash(msg.sender, recipient, amount0, amount1, paid0, paid1); } /// @inheritdoc IAlgebraPoolPermissionedActions function setCommunityFee(uint8 communityFee0, uint8 communityFee1) external override lock onlyFactoryOwner { require((communityFee0 <= Constants.MAX_COMMUNITY_FEE) && (communityFee1 <= Constants.MAX_COMMUNITY_FEE)); (globalState.communityFeeToken0, globalState.communityFeeToken1) = (communityFee0, communityFee1); emit CommunityFee(communityFee0, communityFee1); } /// @inheritdoc IAlgebraPoolPermissionedActions function setIncentive(address virtualPoolAddress) external override { require(msg.sender == IAlgebraFactory(factory).farmingAddress()); activeIncentive = virtualPoolAddress; emit Incentive(virtualPoolAddress); } /// @inheritdoc IAlgebraPoolPermissionedActions function setLiquidityCooldown(uint32 newLiquidityCooldown) external override onlyFactoryOwner { require(newLiquidityCooldown <= Constants.MAX_LIQUIDITY_COOLDOWN && liquidityCooldown != newLiquidityCooldown); liquidityCooldown = newLiquidityCooldown; emit LiquidityCooldown(newLiquidityCooldown); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.7.6; import '../interfaces/pool/IAlgebraPoolImmutables.sol'; import '../interfaces/IAlgebraPoolDeployer.sol'; import '../libraries/Constants.sol'; abstract contract PoolImmutables is IAlgebraPoolImmutables { /// @inheritdoc IAlgebraPoolImmutables address public immutable override dataStorageOperator; /// @inheritdoc IAlgebraPoolImmutables address public immutable override factory; /// @inheritdoc IAlgebraPoolImmutables address public immutable override token0; /// @inheritdoc IAlgebraPoolImmutables address public immutable override token1; /// @inheritdoc IAlgebraPoolImmutables function tickSpacing() external pure override returns (int24) { return Constants.TICK_SPACING; } /// @inheritdoc IAlgebraPoolImmutables function maxLiquidityPerTick() external pure override returns (uint128) { return Constants.MAX_LIQUIDITY_PER_TICK; } constructor(address deployer) { (dataStorageOperator, factory, token0, token1) = IAlgebraPoolDeployer(deployer).parameters(); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.7.6; import '../interfaces/pool/IAlgebraPoolState.sol'; import '../libraries/TickManager.sol'; abstract contract PoolState is IAlgebraPoolState { struct GlobalState { uint160 price; // The square root of the current price in Q64.96 format int24 tick; // The current tick uint16 fee; // The current fee in hundredths of a bip, i.e. 1e-6 uint16 timepointIndex; // The index of the last written timepoint uint8 communityFeeToken0; // The community fee represented as a percent of all collected fee in thousandths (1e-3) uint8 communityFeeToken1; bool unlocked; // True if the contract is unlocked, otherwise - false } /// @inheritdoc IAlgebraPoolState uint256 public override totalFeeGrowth0Token; /// @inheritdoc IAlgebraPoolState uint256 public override totalFeeGrowth1Token; /// @inheritdoc IAlgebraPoolState GlobalState public override globalState; /// @inheritdoc IAlgebraPoolState uint128 public override liquidity; uint128 internal volumePerLiquidityInBlock; /// @inheritdoc IAlgebraPoolState uint32 public override liquidityCooldown; /// @inheritdoc IAlgebraPoolState address public override activeIncentive; /// @inheritdoc IAlgebraPoolState mapping(int24 => TickManager.Tick) public override ticks; /// @inheritdoc IAlgebraPoolState mapping(int16 => uint256) public override tickTable; /// @dev Reentrancy protection. Implemented in every function of the contract since there are checks of balances. modifier lock() { require(globalState.unlocked, 'LOK'); globalState.unlocked = false; _; globalState.unlocked = true; } /// @dev This function is created for testing by overriding it. /// @return A timestamp converted to uint32 function _blockTimestamp() internal view virtual returns (uint32) { return uint32(block.timestamp); // truncation is desired } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /** * @title Callback for IAlgebraPoolActions#flash * @notice Any contract that calls IAlgebraPoolActions#flash must implement this interface * @dev Credit to Uniswap Labs under GPL-2.0-or-later license: * https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces */ interface IAlgebraFlashCallback { /** * @notice Called to `msg.sender` after transferring to the recipient from IAlgebraPool#flash. * @dev In the implementation you must repay the pool the tokens sent by flash plus the computed fee amounts. * The caller of this method must be checked to be a AlgebraPool deployed by the canonical AlgebraFactory. * @param fee0 The fee amount in token0 due to the pool by the end of the flash * @param fee1 The fee amount in token1 due to the pool by the end of the flash * @param data Any data passed through by the caller via the IAlgebraPoolActions#flash call */ function algebraFlashCallback( uint256 fee0, uint256 fee1, bytes calldata data ) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title Callback for IAlgebraPoolActions#mint /// @notice Any contract that calls IAlgebraPoolActions#mint must implement this interface /// @dev Credit to Uniswap Labs under GPL-2.0-or-later license: /// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces interface IAlgebraMintCallback { /// @notice Called to `msg.sender` after minting liquidity to a position from IAlgebraPool#mint. /// @dev In the implementation you must pay the pool tokens owed for the minted liquidity. /// The caller of this method must be checked to be a AlgebraPool deployed by the canonical AlgebraFactory. /// @param amount0Owed The amount of token0 due to the pool for the minted liquidity /// @param amount1Owed The amount of token1 due to the pool for the minted liquidity /// @param data Any data passed through by the caller via the IAlgebraPoolActions#mint call function algebraMintCallback( uint256 amount0Owed, uint256 amount1Owed, bytes calldata data ) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title Callback for IAlgebraPoolActions#swap /// @notice Any contract that calls IAlgebraPoolActions#swap must implement this interface /// @dev Credit to Uniswap Labs under GPL-2.0-or-later license: /// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces interface IAlgebraSwapCallback { /// @notice Called to `msg.sender` after executing a swap via IAlgebraPool#swap. /// @dev In the implementation you must pay the pool tokens owed for the swap. /// The caller of this method must be checked to be a AlgebraPool deployed by the canonical AlgebraFactory. /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped. /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by /// the end of the swap. If positive, the callback must send that amount of token0 to the pool. /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by /// the end of the swap. If positive, the callback must send that amount of token1 to the pool. /// @param data Any data passed through by the caller via the IAlgebraPoolActions#swap call function algebraSwapCallback( int256 amount0Delta, int256 amount1Delta, bytes calldata data ) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /** * @title The interface for the Algebra Factory * @dev Credit to Uniswap Labs under GPL-2.0-or-later license: * https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces */ interface IAlgebraFactory { /** * @notice Emitted when the owner of the factory is changed * @param newOwner The owner after the owner was changed */ event Owner(address indexed newOwner); /** * @notice Emitted when the vault address is changed * @param newVaultAddress The vault address after the address was changed */ event VaultAddress(address indexed newVaultAddress); /** * @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 pool The address of the created pool */ event Pool(address indexed token0, address indexed token1, address pool); /** * @notice Emitted when the farming address is changed * @param newFarmingAddress The farming address after the address was changed */ event FarmingAddress(address indexed newFarmingAddress); event FeeConfiguration( uint16 alpha1, uint16 alpha2, uint32 beta1, uint32 beta2, uint16 gamma1, uint16 gamma2, uint32 volumeBeta, uint16 volumeGamma, uint16 baseFee ); /** * @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 current poolDeployerAddress * @return The address of the poolDeployer */ function poolDeployer() external view returns (address); /** * @dev Is retrieved from the pools to restrict calling * certain functions not by a tokenomics contract * @return The tokenomics contract address */ function farmingAddress() external view returns (address); function vaultAddress() external view returns (address); /** * @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 * @return pool The pool address */ function poolByPair(address tokenA, address tokenB) 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 * @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) 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; /** * @dev updates tokenomics address on the factory * @param _farmingAddress The new tokenomics contract address */ function setFarmingAddress(address _farmingAddress) external; /** * @dev updates vault address on the factory * @param _vaultAddress The new vault contract address */ function setVaultAddress(address _vaultAddress) external; /** * @notice Changes initial fee configuration for new pools * @dev changes coefficients for sigmoids: α / (1 + e^( (β-x) / γ)) * alpha1 + alpha2 + baseFee (max possible fee) must be <= type(uint16).max * gammas must be > 0 * @param alpha1 max value of the first sigmoid * @param alpha2 max value of the second sigmoid * @param beta1 shift along the x-axis for the first sigmoid * @param beta2 shift along the x-axis for the second sigmoid * @param gamma1 horizontal stretch factor for the first sigmoid * @param gamma2 horizontal stretch factor for the second sigmoid * @param volumeBeta shift along the x-axis for the outer volume-sigmoid * @param volumeGamma horizontal stretch factor the outer volume-sigmoid * @param baseFee minimum possible fee */ function setBaseFeeConfiguration( uint16 alpha1, uint16 alpha2, uint32 beta1, uint32 beta2, uint16 gamma1, uint16 gamma2, uint32 volumeBeta, uint16 volumeGamma, uint16 baseFee ) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; import './pool/IAlgebraPoolImmutables.sol'; import './pool/IAlgebraPoolState.sol'; import './pool/IAlgebraPoolDerivedState.sol'; import './pool/IAlgebraPoolActions.sol'; import './pool/IAlgebraPoolPermissionedActions.sol'; import './pool/IAlgebraPoolEvents.sol'; /** * @title The interface for a Algebra Pool * @dev The pool interface is broken up into many smaller pieces. * Credit to Uniswap Labs under GPL-2.0-or-later license: * https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces */ interface IAlgebraPool is IAlgebraPoolImmutables, IAlgebraPoolState, IAlgebraPoolDerivedState, IAlgebraPoolActions, IAlgebraPoolPermissionedActions, IAlgebraPoolEvents { // used only for combining interfaces }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /** * @title An interface for a contract that is capable of deploying Algebra Pools * @notice A contract that constructs a pool must implement this to pass arguments to the pool * @dev This is used to avoid having constructor arguments in the pool contract, which results in the init code hash * of the pool being constant allowing the CREATE2 address of the pool to be cheaply computed on-chain. * Credit to Uniswap Labs under GPL-2.0-or-later license: * https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces */ interface IAlgebraPoolDeployer { /** * @notice Emitted when the factory address is changed * @param factory The factory address after the address was changed */ event Factory(address indexed factory); /** * @notice Get the parameters to be used in constructing the pool, set transiently during pool creation. * @dev Called by the pool constructor to fetch the parameters of the pool * Returns dataStorage The pools associated dataStorage * Returns factory The factory address * Returns token0 The first token of the pool by address sort order * Returns token1 The second token of the pool by address sort order */ function parameters() external view returns ( address dataStorage, address factory, address token0, address token1 ); /** * @dev Deploys a pool with the given parameters by transiently setting the parameters storage slot and then * clearing it after deploying the pool. * @param dataStorage The pools associated dataStorage * @param factory The contract address of the Algebra factory * @param token0 The first token of the pool by address sort order * @param token1 The second token of the pool by address sort order * @return pool The deployed pool's address */ function deploy( address dataStorage, address factory, address token0, address token1 ) external returns (address pool); /** * @dev Sets the factory address to the poolDeployer for permissioned actions * @param factory The address of the Algebra factory */ function setFactory(address factory) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; interface IAlgebraVirtualPool { enum Status { NOT_EXIST, ACTIVE, NOT_STARTED } /** * @dev This function is called by the main pool when an initialized tick is crossed there. * If the tick is also initialized in a virtual pool it should be crossed too * @param nextTick The crossed tick * @param zeroToOne The direction */ function cross(int24 nextTick, bool zeroToOne) external; /** * @dev This function is called from the main pool before every swap To increase seconds per liquidity * cumulative considering previous timestamp and liquidity. The liquidity is stored in a virtual pool * @param currentTimestamp The timestamp of the current swap * @return Status The status of virtual pool */ function increaseCumulative(uint32 currentTimestamp) external returns (Status); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; pragma abicoder v2; import '../libraries/AdaptiveFee.sol'; interface IDataStorageOperator { event FeeConfiguration(AdaptiveFee.Configuration feeConfig); /** * @notice Returns data belonging to a certain timepoint * @param index The index of timepoint in the array * @dev There is more convenient function to fetch a timepoint: observe(). Which requires not an index but seconds * @return initialized Whether the timepoint has been initialized and the values are safe to use, * blockTimestamp The timestamp of the observation, * tickCumulative The tick multiplied by seconds elapsed for the life of the pool as of the timepoint timestamp, * secondsPerLiquidityCumulative The seconds per in range liquidity for the life of the pool as of the timepoint timestamp, * volatilityCumulative Cumulative standard deviation for the life of the pool as of the timepoint timestamp, * averageTick Time-weighted average tick, * volumePerLiquidityCumulative Cumulative swap volume per liquidity for the life of the pool as of the timepoint timestamp */ function timepoints(uint256 index) external view returns ( bool initialized, uint32 blockTimestamp, int56 tickCumulative, uint160 secondsPerLiquidityCumulative, uint88 volatilityCumulative, int24 averageTick, uint144 volumePerLiquidityCumulative ); /// @notice Initialize the dataStorage array by writing the first slot. Called once for the lifecycle of the timepoints array /// @param time The time of the dataStorage initialization, via block.timestamp truncated to uint32 /// @param tick Initial tick function initialize(uint32 time, int24 tick) external; /// @dev Reverts if an timepoint at or before the desired timepoint timestamp does not exist. /// 0 may be passed as `secondsAgo' to return the current cumulative values. /// If called with a timestamp falling between two timepoints, returns the counterfactual accumulator values /// at exactly the timestamp between the two timepoints. /// @param time The current block timestamp /// @param secondsAgo The amount of time to look back, in seconds, at which point to return an timepoint /// @param tick The current tick /// @param index The index of the timepoint that was most recently written to the timepoints array /// @param liquidity The current in-range pool liquidity /// @return tickCumulative The cumulative tick since the pool was first initialized, as of `secondsAgo` /// @return secondsPerLiquidityCumulative The cumulative seconds / max(1, liquidity) since the pool was first initialized, as of `secondsAgo` /// @return volatilityCumulative The cumulative volatility value since the pool was first initialized, as of `secondsAgo` /// @return volumePerAvgLiquidity The cumulative volume per liquidity value since the pool was first initialized, as of `secondsAgo` function getSingleTimepoint( uint32 time, uint32 secondsAgo, int24 tick, uint16 index, uint128 liquidity ) external view returns ( int56 tickCumulative, uint160 secondsPerLiquidityCumulative, uint112 volatilityCumulative, uint256 volumePerAvgLiquidity ); /// @notice Returns the accumulator values as of each time seconds ago from the given time in the array of `secondsAgos` /// @dev Reverts if `secondsAgos` > oldest timepoint /// @param time The current block.timestamp /// @param secondsAgos Each amount of time to look back, in seconds, at which point to return an timepoint /// @param tick The current tick /// @param index The index of the timepoint that was most recently written to the timepoints array /// @param liquidity The current in-range pool liquidity /// @return tickCumulatives The cumulative tick since the pool was first initialized, as of each `secondsAgo` /// @return secondsPerLiquidityCumulatives The cumulative seconds / max(1, liquidity) since the pool was first initialized, as of each `secondsAgo` /// @return volatilityCumulatives The cumulative volatility values since the pool was first initialized, as of each `secondsAgo` /// @return volumePerAvgLiquiditys The cumulative volume per liquidity values since the pool was first initialized, as of each `secondsAgo` function getTimepoints( uint32 time, uint32[] memory secondsAgos, int24 tick, uint16 index, uint128 liquidity ) external view returns ( int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulatives, uint112[] memory volatilityCumulatives, uint256[] memory volumePerAvgLiquiditys ); /// @notice Returns average volatility in the range from time-WINDOW to time /// @param time The current block.timestamp /// @param tick The current tick /// @param index The index of the timepoint that was most recently written to the timepoints array /// @param liquidity The current in-range pool liquidity /// @return TWVolatilityAverage The average volatility in the recent range /// @return TWVolumePerLiqAverage The average volume per liquidity in the recent range function getAverages( uint32 time, int24 tick, uint16 index, uint128 liquidity ) external view returns (uint112 TWVolatilityAverage, uint256 TWVolumePerLiqAverage); /// @notice Writes an dataStorage timepoint to the array /// @dev Writable at most once per block. Index represents the most recently written element. index must be tracked externally. /// @param index The index of the timepoint that was most recently written to the timepoints array /// @param blockTimestamp The timestamp of the new timepoint /// @param tick The active tick at the time of the new timepoint /// @param liquidity The total in-range liquidity at the time of the new timepoint /// @param volumePerLiquidity The gmean(volumes)/liquidity at the time of the new timepoint /// @return indexUpdated The new index of the most recently written element in the dataStorage array function write( uint16 index, uint32 blockTimestamp, int24 tick, uint128 liquidity, uint128 volumePerLiquidity ) external returns (uint16 indexUpdated); /// @notice Changes fee configuration for the pool function changeFeeConfiguration(AdaptiveFee.Configuration calldata feeConfig) external; /// @notice Calculates gmean(volume/liquidity) for block /// @param liquidity The current in-range pool liquidity /// @param amount0 Total amount of swapped token0 /// @param amount1 Total amount of swapped token1 /// @return volumePerLiquidity gmean(volume/liquidity) capped by 100000 << 64 function calculateVolumePerLiquidity( uint128 liquidity, int256 amount0, int256 amount1 ) external pure returns (uint128 volumePerLiquidity); /// @return windowLength Length of window used to calculate averages function window() external view returns (uint32 windowLength); /// @notice Calculates fee based on combination of sigmoids /// @param time The current block.timestamp /// @param tick The current tick /// @param index The index of the timepoint that was most recently written to the timepoints array /// @param liquidity The current in-range pool liquidity /// @return fee The fee in hundredths of a bip, i.e. 1e-6 function getFee( uint32 time, int24 tick, uint16 index, uint128 liquidity ) external view returns (uint16 fee); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title Minimal ERC20 interface for Algebra /// @notice Contains a subset of the full ERC20 interface that is used in Algebra /// @dev Credit to Uniswap Labs under GPL-2.0-or-later license: /// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces interface IERC20Minimal { /// @notice Returns the balance of a token /// @param account The account for which to look up the number of tokens it has, i.e. its balance /// @return The number of tokens held by the account function balanceOf(address account) external view returns (uint256); /// @notice Transfers the amount of token from the `msg.sender` to the recipient /// @param recipient The account that will receive the amount transferred /// @param amount The number of tokens to send from the sender to the recipient /// @return Returns true for a successful transfer, false for an unsuccessful transfer function transfer(address recipient, uint256 amount) external returns (bool); /// @notice Returns the current allowance given to a spender by an owner /// @param owner The account of the token owner /// @param spender The account of the token spender /// @return The current allowance granted by `owner` to `spender` function allowance(address owner, address spender) external view returns (uint256); /// @notice Sets the allowance of a spender from the `msg.sender` to the value `amount` /// @param spender The account which will be allowed to spend a given amount of the owners tokens /// @param amount The amount of tokens allowed to be used by `spender` /// @return Returns true for a successful approval, false for unsuccessful function approve(address spender, uint256 amount) external returns (bool); /// @notice Transfers `amount` tokens from `sender` to `recipient` up to the allowance given to the `msg.sender` /// @param sender The account from which the transfer will be initiated /// @param recipient The recipient of the transfer /// @param amount The amount of the transfer /// @return Returns true for a successful transfer, false for unsuccessful function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /// @notice Event emitted when tokens are transferred from one address to another, either via `#transfer` or `#transferFrom`. /// @param from The account from which the tokens were sent, i.e. the balance decreased /// @param to The account to which the tokens were sent, i.e. the balance increased /// @param value The amount of tokens that were transferred event Transfer(address indexed from, address indexed to, uint256 value); /// @notice Event emitted when the approval amount for the spender of a given owner's tokens changes. /// @param owner The account that approved spending of its tokens /// @param spender The account for which the spending allowance was modified /// @param value The new allowance from the owner to the spender event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title Permissionless pool actions /// @dev Credit to Uniswap Labs under GPL-2.0-or-later license: /// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces interface IAlgebraPoolActions { /** * @notice Sets the initial price for the pool * @dev Price is represented as a sqrt(amountToken1/amountToken0) Q64.96 value * @param price the initial sqrt price of the pool as a Q64.96 */ function initialize(uint160 price) external; /** * @notice Adds liquidity for the given recipient/bottomTick/topTick position * @dev The caller of this method receives a callback in the form of IAlgebraMintCallback# AlgebraMintCallback * in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends * on bottomTick, topTick, the amount of liquidity, and the current price. * @param sender The address which will receive potential surplus of paid tokens * @param recipient The address for which the liquidity will be created * @param bottomTick The lower tick of the position in which to add liquidity * @param topTick The upper tick of the position in which to add liquidity * @param amount The desired amount of liquidity to mint * @param data Any data that should be passed through to the callback * @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback * @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback * @return liquidityActual The actual minted amount of liquidity */ function mint( address sender, address recipient, int24 bottomTick, int24 topTick, uint128 amount, bytes calldata data ) external returns ( uint256 amount0, uint256 amount1, uint128 liquidityActual ); /** * @notice Collects tokens owed to a position * @dev Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity. * Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or * amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the * actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity. * @param recipient The address which should receive the fees collected * @param bottomTick The lower tick of the position for which to collect fees * @param topTick The upper tick of the position for which to collect fees * @param amount0Requested How much token0 should be withdrawn from the fees owed * @param amount1Requested How much token1 should be withdrawn from the fees owed * @return amount0 The amount of fees collected in token0 * @return amount1 The amount of fees collected in token1 */ function collect( address recipient, int24 bottomTick, int24 topTick, uint128 amount0Requested, uint128 amount1Requested ) external returns (uint128 amount0, uint128 amount1); /** * @notice Burn liquidity from the sender and account tokens owed for the liquidity to the position * @dev Can be used to trigger a recalculation of fees owed to a position by calling with an amount of 0 * @dev Fees must be collected separately via a call to #collect * @param bottomTick The lower tick of the position for which to burn liquidity * @param topTick The upper tick of the position for which to burn liquidity * @param amount How much liquidity to burn * @return amount0 The amount of token0 sent to the recipient * @return amount1 The amount of token1 sent to the recipient */ function burn( int24 bottomTick, int24 topTick, uint128 amount ) external returns (uint256 amount0, uint256 amount1); /** * @notice Swap token0 for token1, or token1 for token0 * @dev The caller of this method receives a callback in the form of IAlgebraSwapCallback# AlgebraSwapCallback * @param recipient The address to receive the output of the swap * @param zeroToOne The direction of the swap, true for token0 to token1, false for token1 to token0 * @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative) * @param limitSqrtPrice The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this * value after the swap. If one for zero, the price cannot be greater than this value after the swap * @param data Any data to be passed through to the callback. If using the Router it should contain * SwapRouter#SwapCallbackData * @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive * @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive */ function swap( address recipient, bool zeroToOne, int256 amountSpecified, uint160 limitSqrtPrice, bytes calldata data ) external returns (int256 amount0, int256 amount1); /** * @notice Swap token0 for token1, or token1 for token0 (tokens that have fee on transfer) * @dev The caller of this method receives a callback in the form of I AlgebraSwapCallback# AlgebraSwapCallback * @param sender The address called this function (Comes from the Router) * @param recipient The address to receive the output of the swap * @param zeroToOne The direction of the swap, true for token0 to token1, false for token1 to token0 * @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative) * @param limitSqrtPrice The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this * value after the swap. If one for zero, the price cannot be greater than this value after the swap * @param data Any data to be passed through to the callback. If using the Router it should contain * SwapRouter#SwapCallbackData * @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive * @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive */ function swapSupportingFeeOnInputTokens( address sender, address recipient, bool zeroToOne, int256 amountSpecified, uint160 limitSqrtPrice, bytes calldata data ) external returns (int256 amount0, int256 amount1); /** * @notice Receive token0 and/or token1 and pay it back, plus a fee, in the callback * @dev The caller of this method receives a callback in the form of IAlgebraFlashCallback# AlgebraFlashCallback * @dev All excess tokens paid in the callback are distributed to liquidity providers as an additional fee. So this method can be used * to donate underlying tokens to currently in-range liquidity providers by calling with 0 amount{0,1} and sending * the donation amount(s) from the callback * @param recipient The address which will receive the token0 and token1 amounts * @param amount0 The amount of token0 to send * @param amount1 The amount of token1 to send * @param data Any data to be passed through to the callback */ function flash( address recipient, uint256 amount0, uint256 amount1, bytes calldata data ) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /** * @title Pool state that is not stored * @notice Contains view functions to provide information about the pool that is computed rather than stored on the * blockchain. The functions here may have variable gas costs. * @dev Credit to Uniswap Labs under GPL-2.0-or-later license: * https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces */ interface IAlgebraPoolDerivedState { /** * @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp * @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing * the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick, * you must call it with secondsAgos = [3600, 0]. * @dev The time weighted average tick represents the geometric time weighted average price of the pool, in * log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio. * @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned * @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp * @return secondsPerLiquidityCumulatives Cumulative seconds per liquidity-in-range value as of each `secondsAgos` * from the current block timestamp * @return volatilityCumulatives Cumulative standard deviation as of each `secondsAgos` * @return volumePerAvgLiquiditys Cumulative swap volume per liquidity as of each `secondsAgos` */ function getTimepoints(uint32[] calldata secondsAgos) external view returns ( int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulatives, uint112[] memory volatilityCumulatives, uint256[] memory volumePerAvgLiquiditys ); /** * @notice Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range * @dev Snapshots must only be compared to other snapshots, taken over a period for which a position existed. * I.e., snapshots cannot be compared if a position is not held for the entire period between when the first * snapshot is taken and the second snapshot is taken. * @param bottomTick The lower tick of the range * @param topTick The upper tick of the range * @return innerTickCumulative The snapshot of the tick accumulator for the range * @return innerSecondsSpentPerLiquidity The snapshot of seconds per liquidity for the range * @return innerSecondsSpent The snapshot of the number of seconds during which the price was in this range */ function getInnerCumulatives(int24 bottomTick, int24 topTick) external view returns ( int56 innerTickCumulative, uint160 innerSecondsSpentPerLiquidity, uint32 innerSecondsSpent ); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title Events emitted by a pool /// @dev Credit to Uniswap Labs under GPL-2.0-or-later license: /// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces interface IAlgebraPoolEvents { /** * @notice Emitted exactly once by a pool when #initialize is first called on the pool * @dev Mint/Burn/Swap cannot be emitted by the pool before Initialize * @param price The initial sqrt price of the pool, as a Q64.96 * @param tick The initial tick of the pool, i.e. log base 1.0001 of the starting price of the pool */ event Initialize(uint160 price, int24 tick); /** * @notice Emitted when liquidity is minted for a given position * @param sender The address that minted the liquidity * @param owner The owner of the position and recipient of any minted liquidity * @param bottomTick The lower tick of the position * @param topTick The upper tick of the position * @param liquidityAmount The amount of liquidity minted to the position range * @param amount0 How much token0 was required for the minted liquidity * @param amount1 How much token1 was required for the minted liquidity */ event Mint( address sender, address indexed owner, int24 indexed bottomTick, int24 indexed topTick, uint128 liquidityAmount, uint256 amount0, uint256 amount1 ); /** * @notice Emitted when fees are collected by the owner of a position * @dev Collect events may be emitted with zero amount0 and amount1 when the caller chooses not to collect fees * @param owner The owner of the position for which fees are collected * @param recipient The address that received fees * @param bottomTick The lower tick of the position * @param topTick The upper tick of the position * @param amount0 The amount of token0 fees collected * @param amount1 The amount of token1 fees collected */ event Collect(address indexed owner, address recipient, int24 indexed bottomTick, int24 indexed topTick, uint128 amount0, uint128 amount1); /** * @notice Emitted when a position's liquidity is removed * @dev Does not withdraw any fees earned by the liquidity position, which must be withdrawn via #collect * @param owner The owner of the position for which liquidity is removed * @param bottomTick The lower tick of the position * @param topTick The upper tick of the position * @param liquidityAmount The amount of liquidity to remove * @param amount0 The amount of token0 withdrawn * @param amount1 The amount of token1 withdrawn */ event Burn(address indexed owner, int24 indexed bottomTick, int24 indexed topTick, uint128 liquidityAmount, uint256 amount0, uint256 amount1); /** * @notice Emitted by the pool for any swaps between token0 and token1 * @param sender The address that initiated the swap call, and that received the callback * @param recipient The address that received the output of the swap * @param amount0 The delta of the token0 balance of the pool * @param amount1 The delta of the token1 balance of the pool * @param price The sqrt(price) of the pool after the swap, as a Q64.96 * @param liquidity The liquidity of the pool after the swap * @param tick The log base 1.0001 of price of the pool after the swap */ event Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 price, uint128 liquidity, int24 tick); /** * @notice Emitted by the pool for any flashes of token0/token1 * @param sender The address that initiated the swap call, and that received the callback * @param recipient The address that received the tokens from flash * @param amount0 The amount of token0 that was flashed * @param amount1 The amount of token1 that was flashed * @param paid0 The amount of token0 paid for the flash, which can exceed the amount0 plus the fee * @param paid1 The amount of token1 paid for the flash, which can exceed the amount1 plus the fee */ event Flash(address indexed sender, address indexed recipient, uint256 amount0, uint256 amount1, uint256 paid0, uint256 paid1); /** * @notice Emitted when the community fee is changed by the pool * @param communityFee0New The updated value of the token0 community fee percent * @param communityFee1New The updated value of the token1 community fee percent */ event CommunityFee(uint8 communityFee0New, uint8 communityFee1New); /** * @notice Emitted when new activeIncentive is set * @param virtualPoolAddress The address of a virtual pool associated with the current active incentive */ event Incentive(address indexed virtualPoolAddress); /** * @notice Emitted when the fee changes * @param fee The value of the token fee */ event Fee(uint16 fee); /** * @notice Emitted when the LiquidityCooldown changes * @param liquidityCooldown The value of locktime for added liquidity */ event LiquidityCooldown(uint32 liquidityCooldown); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; import '../IDataStorageOperator.sol'; /// @title Pool state that never changes /// @dev Credit to Uniswap Labs under GPL-2.0-or-later license: /// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces interface IAlgebraPoolImmutables { /** * @notice The contract that stores all the timepoints and can perform actions with them * @return The operator address */ function dataStorageOperator() external view returns (address); /** * @notice The contract that deployed the pool, which must adhere to the IAlgebraFactory interface * @return The contract address */ function factory() external view returns (address); /** * @notice The first of the two tokens of the pool, sorted by address * @return The token contract address */ function token0() external view returns (address); /** * @notice The second of the two tokens of the pool, sorted by address * @return The token contract address */ function token1() external view returns (address); /** * @notice The pool tick spacing * @dev Ticks can only be used at multiples of this value * e.g.: a tickSpacing of 60 means ticks can be initialized every 60th tick, i.e., ..., -120, -60, 0, 60, 120, ... * This value is an int24 to avoid casting even though it is always positive. * @return The tick spacing */ function tickSpacing() external view returns (int24); /** * @notice The maximum amount of position liquidity that can use any tick in the range * @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and * also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool * @return The max amount of liquidity per tick */ function maxLiquidityPerTick() external view returns (uint128); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /** * @title Permissioned pool actions * @notice Contains pool methods that may only be called by the factory owner or tokenomics * @dev Credit to Uniswap Labs under GPL-2.0-or-later license: * https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces */ interface IAlgebraPoolPermissionedActions { /** * @notice Set the community's % share of the fees. Cannot exceed 25% (250) * @param communityFee0 new community fee percent for token0 of the pool in thousandths (1e-3) * @param communityFee1 new community fee percent for token1 of the pool in thousandths (1e-3) */ function setCommunityFee(uint8 communityFee0, uint8 communityFee1) external; /** * @notice Sets an active incentive * @param virtualPoolAddress The address of a virtual pool associated with the incentive */ function setIncentive(address virtualPoolAddress) external; /** * @notice Sets new lock time for added liquidity * @param newLiquidityCooldown The time in seconds */ function setLiquidityCooldown(uint32 newLiquidityCooldown) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title Pool state that can change /// @dev Credit to Uniswap Labs under GPL-2.0-or-later license: /// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces interface IAlgebraPoolState { /** * @notice The globalState structure in the pool stores many values but requires only one slot * and is exposed as a single method to save gas when accessed externally. * @return price The current price of the pool as a sqrt(token1/token0) Q64.96 value; * Returns tick The current tick of the pool, i.e. according to the last tick transition that was run; * Returns This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(price) if the price is on a tick * boundary; * Returns fee The last pool fee value in hundredths of a bip, i.e. 1e-6; * Returns timepointIndex The index of the last written timepoint; * Returns communityFeeToken0 The community fee percentage of the swap fee in thousandths (1e-3) for token0; * Returns communityFeeToken1 The community fee percentage of the swap fee in thousandths (1e-3) for token1; * Returns unlocked Whether the pool is currently locked to reentrancy; */ function globalState() external view returns ( uint160 price, int24 tick, uint16 fee, uint16 timepointIndex, uint8 communityFeeToken0, uint8 communityFeeToken1, bool unlocked ); /** * @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool * @dev This value can overflow the uint256 */ function totalFeeGrowth0Token() external view returns (uint256); /** * @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool * @dev This value can overflow the uint256 */ function totalFeeGrowth1Token() external view returns (uint256); /** * @notice The currently in range liquidity available to the pool * @dev This value has no relationship to the total liquidity across all ticks. * Returned value cannot exceed type(uint128).max */ function liquidity() external view returns (uint128); /** * @notice Look up information about a specific tick in the pool * @dev This is a public structure, so the `return` natspec tags are omitted. * @param tick The tick to look up * @return liquidityTotal the total amount of position liquidity that uses the pool either as tick lower or * tick upper; * Returns liquidityDelta how much liquidity changes when the pool price crosses the tick; * Returns outerFeeGrowth0Token the fee growth on the other side of the tick from the current tick in token0; * Returns outerFeeGrowth1Token the fee growth on the other side of the tick from the current tick in token1; * Returns outerTickCumulative the cumulative tick value on the other side of the tick from the current tick; * Returns outerSecondsPerLiquidity the seconds spent per liquidity on the other side of the tick from the current tick; * Returns outerSecondsSpent the seconds spent on the other side of the tick from the current tick; * Returns initialized Set to true if the tick is initialized, i.e. liquidityTotal is greater than 0 * otherwise equal to false. Outside values can only be used if the tick is initialized. * In addition, these values are only relative and must be used only in comparison to previous snapshots for * a specific position. */ function ticks(int24 tick) external view returns ( uint128 liquidityTotal, int128 liquidityDelta, uint256 outerFeeGrowth0Token, uint256 outerFeeGrowth1Token, int56 outerTickCumulative, uint160 outerSecondsPerLiquidity, uint32 outerSecondsSpent, bool initialized ); /** @notice Returns 256 packed tick initialized boolean values. See TickTable for more information */ function tickTable(int16 wordPosition) external view returns (uint256); /** * @notice Returns the information about a position by the position's key * @dev This is a public mapping of structures, so the `return` natspec tags are omitted. * @param key The position's key is a hash of a preimage composed by the owner, bottomTick and topTick * @return liquidityAmount The amount of liquidity in the position; * Returns lastLiquidityAddTimestamp Timestamp of last adding of liquidity; * Returns innerFeeGrowth0Token Fee growth of token0 inside the tick range as of the last mint/burn/poke; * Returns innerFeeGrowth1Token Fee growth of token1 inside the tick range as of the last mint/burn/poke; * Returns fees0 The computed amount of token0 owed to the position as of the last mint/burn/poke; * Returns fees1 The computed amount of token1 owed to the position as of the last mint/burn/poke */ function positions(bytes32 key) external view returns ( uint128 liquidityAmount, uint32 lastLiquidityAddTimestamp, uint256 innerFeeGrowth0Token, uint256 innerFeeGrowth1Token, uint128 fees0, uint128 fees1 ); /** * @notice Returns data about a specific timepoint index * @param index The element of the timepoints array to fetch * @dev You most likely want to use #getTimepoints() instead of this method to get an timepoint as of some amount of time * ago, rather than at a specific index in the array. * This is a public mapping of structures, so the `return` natspec tags are omitted. * @return initialized whether the timepoint has been initialized and the values are safe to use; * Returns blockTimestamp The timestamp of the timepoint; * Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the timepoint timestamp; * Returns secondsPerLiquidityCumulative the seconds per in range liquidity for the life of the pool as of the timepoint timestamp; * Returns volatilityCumulative Cumulative standard deviation for the life of the pool as of the timepoint timestamp; * Returns averageTick Time-weighted average tick; * Returns volumePerLiquidityCumulative Cumulative swap volume per liquidity for the life of the pool as of the timepoint timestamp; */ function timepoints(uint256 index) external view returns ( bool initialized, uint32 blockTimestamp, int56 tickCumulative, uint160 secondsPerLiquidityCumulative, uint88 volatilityCumulative, int24 averageTick, uint144 volumePerLiquidityCumulative ); /** * @notice Returns the information about active incentive * @dev if there is no active incentive at the moment, virtualPool,endTimestamp,startTimestamp would be equal to 0 * @return virtualPool The address of a virtual pool associated with the current active incentive */ function activeIncentive() external view returns (address virtualPool); /** * @notice Returns the lock time for added liquidity */ function liquidityCooldown() external view returns (uint32 cooldownInSeconds); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.7.6; import './Constants.sol'; /// @title AdaptiveFee /// @notice Calculates fee based on combination of sigmoids library AdaptiveFee { // alpha1 + alpha2 + baseFee must be <= type(uint16).max struct Configuration { uint16 alpha1; // max value of the first sigmoid uint16 alpha2; // max value of the second sigmoid uint32 beta1; // shift along the x-axis for the first sigmoid uint32 beta2; // shift along the x-axis for the second sigmoid uint16 gamma1; // horizontal stretch factor for the first sigmoid uint16 gamma2; // horizontal stretch factor for the second sigmoid uint32 volumeBeta; // shift along the x-axis for the outer volume-sigmoid uint16 volumeGamma; // horizontal stretch factor the outer volume-sigmoid uint16 baseFee; // minimum possible fee } /// @notice Calculates fee based on formula: /// baseFee + sigmoidVolume(sigmoid1(volatility, volumePerLiquidity) + sigmoid2(volatility, volumePerLiquidity)) /// maximum value capped by baseFee + alpha1 + alpha2 function getFee( uint88 volatility, uint256 volumePerLiquidity, Configuration memory config ) internal pure returns (uint16 fee) { uint256 sumOfSigmoids = sigmoid(volatility, config.gamma1, config.alpha1, config.beta1) + sigmoid(volatility, config.gamma2, config.alpha2, config.beta2); if (sumOfSigmoids > type(uint16).max) { // should be impossible, just in case sumOfSigmoids = type(uint16).max; } return uint16(config.baseFee + sigmoid(volumePerLiquidity, config.volumeGamma, uint16(sumOfSigmoids), config.volumeBeta)); // safe since alpha1 + alpha2 + baseFee _must_ be <= type(uint16).max } /// @notice calculates α / (1 + e^( (β-x) / γ)) /// that is a sigmoid with a maximum value of α, x-shifted by β, and stretched by γ /// @dev returns uint256 for fuzzy testing. Guaranteed that the result is not greater than alpha function sigmoid( uint256 x, uint16 g, uint16 alpha, uint256 beta ) internal pure returns (uint256 res) { if (x > beta) { x = x - beta; if (x >= 6 * uint256(g)) return alpha; // so x < 19 bits uint256 g8 = uint256(g)**8; // < 128 bits (8*16) uint256 ex = exp(x, g, g8); // < 155 bits res = (alpha * ex) / (g8 + ex); // in worst case: (16 + 155 bits) / 155 bits // so res <= alpha } else { x = beta - x; if (x >= 6 * uint256(g)) return 0; // so x < 19 bits uint256 g8 = uint256(g)**8; // < 128 bits (8*16) uint256 ex = g8 + exp(x, g, g8); // < 156 bits res = (alpha * g8) / ex; // in worst case: (16 + 128 bits) / 156 bits // g8 <= ex, so res <= alpha } } /// @notice calculates e^(x/g) * g^8 in a series, since (around zero): /// e^x = 1 + x + x^2/2 + ... + x^n/n! + ... /// e^(x/g) = 1 + x/g + x^2/(2*g^2) + ... + x^(n)/(g^n * n!) + ... function exp( uint256 x, uint16 g, uint256 gHighestDegree ) internal pure returns (uint256 res) { // calculating: // g**8 + x * g**7 + (x**2 * g**6) / 2 + (x**3 * g**5) / 6 + (x**4 * g**4) / 24 + (x**5 * g**3) / 120 + (x**6 * g^2) / 720 + x**7 * g / 5040 + x**8 / 40320 // x**8 < 152 bits (19*8) and g**8 < 128 bits (8*16) // so each summand < 152 bits and res < 155 bits uint256 xLowestDegree = x; res = gHighestDegree; // g**8 gHighestDegree /= g; // g**7 res += xLowestDegree * gHighestDegree; gHighestDegree /= g; // g**6 xLowestDegree *= x; // x**2 res += (xLowestDegree * gHighestDegree) / 2; gHighestDegree /= g; // g**5 xLowestDegree *= x; // x**3 res += (xLowestDegree * gHighestDegree) / 6; gHighestDegree /= g; // g**4 xLowestDegree *= x; // x**4 res += (xLowestDegree * gHighestDegree) / 24; gHighestDegree /= g; // g**3 xLowestDegree *= x; // x**5 res += (xLowestDegree * gHighestDegree) / 120; gHighestDegree /= g; // g**2 xLowestDegree *= x; // x**6 res += (xLowestDegree * gHighestDegree) / 720; xLowestDegree *= x; // x**7 res += (xLowestDegree * g) / 5040 + (xLowestDegree * x) / (40320); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity =0.7.6; library Constants { uint8 internal constant RESOLUTION = 96; uint256 internal constant Q96 = 0x1000000000000000000000000; uint256 internal constant Q128 = 0x100000000000000000000000000000000; // fee value in hundredths of a bip, i.e. 1e-6 uint16 internal constant BASE_FEE = 100; int24 internal constant TICK_SPACING = 60; // max(uint128) / ( (MAX_TICK - MIN_TICK) / TICK_SPACING ) uint128 internal constant MAX_LIQUIDITY_PER_TICK = 11505743598341114571880798222544994; uint32 internal constant MAX_LIQUIDITY_COOLDOWN = 1 days; uint8 internal constant MAX_COMMUNITY_FEE = 250; uint256 internal constant COMMUNITY_FEE_DENOMINATOR = 1000; }
// SPDX-License-Identifier: MIT pragma solidity ^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.0; /// @title Contains 512-bit math functions /// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision /// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits library FullMath { /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return result The 256-bit result /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv function mulDiv( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256 result) { // 512-bit multiply [prod1 prod0] = a * b // Compute the product mod 2**256 and mod 2**256 - 1 // then use the Chinese Remainder Theorem to reconstruct // the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2**256 + prod0 uint256 prod0 = a * b; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(a, b, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Make sure the result is less than 2**256. // Also prevents denominator == 0 require(denominator > prod1); // Handle non-overflow cases, 256 by 256 division if (prod1 == 0) { assembly { result := div(prod0, denominator) } return result; } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0] // Compute remainder using mulmod // Subtract 256 bit remainder from 512 bit number assembly { let remainder := mulmod(a, b, denominator) prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator // Compute largest power of two divisor of denominator. // Always >= 1. uint256 twos = -denominator & denominator; // Divide denominator by power of two assembly { denominator := div(denominator, twos) } // Divide [prod1 prod0] by the factors of two assembly { prod0 := div(prod0, twos) } // Shift in bits from prod1 into prod0. For this we need // to flip `twos` such that it is 2**256 / twos. // If twos is zero, then it becomes one assembly { twos := add(div(sub(0, twos), twos), 1) } prod0 |= prod1 * twos; // Invert denominator mod 2**256 // Now that denominator is an odd number, it has an inverse // modulo 2**256 such that denominator * inv = 1 mod 2**256. // Compute the inverse by starting with a seed that is correct // correct for four bits. That is, denominator * inv = 1 mod 2**4 uint256 inv = (3 * denominator) ^ 2; // Now use Newton-Raphson iteration to improve the precision. // Thanks to Hensel's lifting lemma, this also works in modular // arithmetic, doubling the correct bits in each step. inv *= 2 - denominator * inv; // inverse mod 2**8 inv *= 2 - denominator * inv; // inverse mod 2**16 inv *= 2 - denominator * inv; // inverse mod 2**32 inv *= 2 - denominator * inv; // inverse mod 2**64 inv *= 2 - denominator * inv; // inverse mod 2**128 inv *= 2 - denominator * inv; // inverse mod 2**256 // Because the division is now exact we can divide by multiplying // with the modular inverse of denominator. This will give us the // correct result modulo 2**256. Since the preconditions guarantee // that the outcome is less than 2**256, this is the final result. // We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inv; return result; } /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return result The 256-bit result function mulDivRoundingUp( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256 result) { if (a == 0 || ((result = a * b) / a == b)) { require(denominator > 0); assembly { result := add(div(result, denominator), gt(mod(result, denominator), 0)) } } else { result = mulDiv(a, b, denominator); if (mulmod(a, b, denominator) > 0) { require(result < type(uint256).max); result++; } } } /// @notice Returns ceil(x / y) /// @dev division by 0 has unspecified behavior, and must be checked externally /// @param x The dividend /// @param y The divisor /// @return z The quotient, ceil(x / y) function divRoundingUp(uint256 x, uint256 y) internal pure returns (uint256 z) { assembly { z := add(div(x, y), gt(mod(x, y), 0)) } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title Math library for liquidity /// @dev Credit to Uniswap Labs under GPL-2.0-or-later license: /// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries library LiquidityMath { /// @notice Add a signed liquidity delta to liquidity and revert if it overflows or underflows /// @param x The liquidity before change /// @param y The delta by which liquidity should be changed /// @return z The liquidity delta function addDelta(uint128 x, int128 y) internal pure returns (uint128 z) { if (y < 0) { require((z = x - uint128(-y)) < x, 'LS'); } else { require((z = x + uint128(y)) >= x, 'LA'); } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.7.0; /// @title Optimized overflow and underflow safe math operations /// @notice Contains methods for doing math operations that revert on overflow or underflow for minimal gas cost /// @dev Credit to Uniswap Labs under GPL-2.0-or-later license: /// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries library LowGasSafeMath { /// @notice Returns x + y, reverts if sum overflows uint256 /// @param x The augend /// @param y The addend /// @return z The sum of x and y function add(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x); } /// @notice Returns x - y, reverts if underflows /// @param x The minuend /// @param y The subtrahend /// @return z The difference of x and y function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x - y) <= x); } /// @notice Returns x * y, reverts if overflows /// @param x The multiplicand /// @param y The multiplier /// @return z The product of x and y function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(x == 0 || (z = x * y) / x == y); } /// @notice Returns x + y, reverts if overflows or underflows /// @param x The augend /// @param y The addend /// @return z The sum of x and y function add(int256 x, int256 y) internal pure returns (int256 z) { require((z = x + y) >= x == (y >= 0)); } /// @notice Returns x - y, reverts if overflows or underflows /// @param x The minuend /// @param y The subtrahend /// @return z The difference of x and y function sub(int256 x, int256 y) internal pure returns (int256 z) { require((z = x - y) <= x == (y >= 0)); } /// @notice Returns x + y, reverts if overflows or underflows /// @param x The augend /// @param y The addend /// @return z The sum of x and y function add128(uint128 x, uint128 y) internal pure returns (uint128 z) { require((z = x + y) >= x); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.7.6; import './FullMath.sol'; import './TokenDeltaMath.sol'; /// @title Computes the result of price movement /// @notice Contains methods for computing the result of price movement within a single tick price range. library PriceMovementMath { using LowGasSafeMath for uint256; using SafeCast for uint256; /// @notice Gets the next sqrt price given an input amount of token0 or token1 /// @dev Throws if price or liquidity are 0, or if the next price is out of bounds /// @param price The starting Q64.96 sqrt price, i.e., before accounting for the input amount /// @param liquidity The amount of usable liquidity /// @param input How much of token0, or token1, is being swapped in /// @param zeroToOne Whether the amount in is token0 or token1 /// @return resultPrice The Q64.96 sqrt price after adding the input amount to token0 or token1 function getNewPriceAfterInput( uint160 price, uint128 liquidity, uint256 input, bool zeroToOne ) internal pure returns (uint160 resultPrice) { return getNewPrice(price, liquidity, input, zeroToOne, true); } /// @notice Gets the next sqrt price given an output amount of token0 or token1 /// @dev Throws if price or liquidity are 0 or the next price is out of bounds /// @param price The starting Q64.96 sqrt price before accounting for the output amount /// @param liquidity The amount of usable liquidity /// @param output How much of token0, or token1, is being swapped out /// @param zeroToOne Whether the amount out is token0 or token1 /// @return resultPrice The Q64.96 sqrt price after removing the output amount of token0 or token1 function getNewPriceAfterOutput( uint160 price, uint128 liquidity, uint256 output, bool zeroToOne ) internal pure returns (uint160 resultPrice) { return getNewPrice(price, liquidity, output, zeroToOne, false); } function getNewPrice( uint160 price, uint128 liquidity, uint256 amount, bool zeroToOne, bool fromInput ) internal pure returns (uint160 resultPrice) { require(price > 0); require(liquidity > 0); if (zeroToOne == fromInput) { // rounding up or down if (amount == 0) return price; uint256 liquidityShifted = uint256(liquidity) << Constants.RESOLUTION; if (fromInput) { uint256 product; if ((product = amount * price) / amount == price) { uint256 denominator = liquidityShifted + product; if (denominator >= liquidityShifted) return uint160(FullMath.mulDivRoundingUp(liquidityShifted, price, denominator)); // always fits in 160 bits } return uint160(FullMath.divRoundingUp(liquidityShifted, (liquidityShifted / price).add(amount))); } else { uint256 product; require((product = amount * price) / amount == price); // if the product overflows, we know the denominator underflows require(liquidityShifted > product); // in addition, we must check that the denominator does not underflow return FullMath.mulDivRoundingUp(liquidityShifted, price, liquidityShifted - product).toUint160(); } } else { // if we're adding (subtracting), rounding down requires rounding the quotient down (up) // in both cases, avoid a mulDiv for most inputs if (fromInput) { return uint256(price) .add(amount <= type(uint160).max ? (amount << Constants.RESOLUTION) / liquidity : FullMath.mulDiv(amount, Constants.Q96, liquidity)) .toUint160(); } else { uint256 quotient = amount <= type(uint160).max ? FullMath.divRoundingUp(amount << Constants.RESOLUTION, liquidity) : FullMath.mulDivRoundingUp(amount, Constants.Q96, liquidity); require(price > quotient); return uint160(price - quotient); // always fits 160 bits } } } function getTokenADelta01( uint160 to, uint160 from, uint128 liquidity ) internal pure returns (uint256) { return TokenDeltaMath.getToken0Delta(to, from, liquidity, true); } function getTokenADelta10( uint160 to, uint160 from, uint128 liquidity ) internal pure returns (uint256) { return TokenDeltaMath.getToken1Delta(from, to, liquidity, true); } function getTokenBDelta01( uint160 to, uint160 from, uint128 liquidity ) internal pure returns (uint256) { return TokenDeltaMath.getToken1Delta(to, from, liquidity, false); } function getTokenBDelta10( uint160 to, uint160 from, uint128 liquidity ) internal pure returns (uint256) { return TokenDeltaMath.getToken0Delta(from, to, liquidity, false); } /// @notice Computes the result of swapping some amount in, or amount out, given the parameters of the swap /// @dev The fee, plus the amount in, will never exceed the amount remaining if the swap's `amountSpecified` is positive /// @param currentPrice The current Q64.96 sqrt price of the pool /// @param targetPrice The Q64.96 sqrt price that cannot be exceeded, from which the direction of the swap is inferred /// @param liquidity The usable liquidity /// @param amountAvailable How much input or output amount is remaining to be swapped in/out /// @param fee The fee taken from the input amount, expressed in hundredths of a bip /// @return resultPrice The Q64.96 sqrt price after swapping the amount in/out, not to exceed the price target /// @return input The amount to be swapped in, of either token0 or token1, based on the direction of the swap /// @return output The amount to be received, of either token0 or token1, based on the direction of the swap /// @return feeAmount The amount of input that will be taken as a fee function movePriceTowardsTarget( bool zeroToOne, uint160 currentPrice, uint160 targetPrice, uint128 liquidity, int256 amountAvailable, uint16 fee ) internal pure returns ( uint160 resultPrice, uint256 input, uint256 output, uint256 feeAmount ) { function(uint160, uint160, uint128) pure returns (uint256) getAmountA = zeroToOne ? getTokenADelta01 : getTokenADelta10; if (amountAvailable >= 0) { // exactIn or not uint256 amountAvailableAfterFee = FullMath.mulDiv(uint256(amountAvailable), 1e6 - fee, 1e6); input = getAmountA(targetPrice, currentPrice, liquidity); if (amountAvailableAfterFee >= input) { resultPrice = targetPrice; feeAmount = FullMath.mulDivRoundingUp(input, fee, 1e6 - fee); } else { resultPrice = getNewPriceAfterInput(currentPrice, liquidity, amountAvailableAfterFee, zeroToOne); if (targetPrice != resultPrice) { input = getAmountA(resultPrice, currentPrice, liquidity); // we didn't reach the target, so take the remainder of the maximum input as fee feeAmount = uint256(amountAvailable) - input; } else { feeAmount = FullMath.mulDivRoundingUp(input, fee, 1e6 - fee); } } output = (zeroToOne ? getTokenBDelta01 : getTokenBDelta10)(resultPrice, currentPrice, liquidity); } else { function(uint160, uint160, uint128) pure returns (uint256) getAmountB = zeroToOne ? getTokenBDelta01 : getTokenBDelta10; output = getAmountB(targetPrice, currentPrice, liquidity); amountAvailable = -amountAvailable; if (uint256(amountAvailable) >= output) resultPrice = targetPrice; else { resultPrice = getNewPriceAfterOutput(currentPrice, liquidity, uint256(amountAvailable), zeroToOne); if (targetPrice != resultPrice) { output = getAmountB(resultPrice, currentPrice, liquidity); } // cap the output amount to not exceed the remaining output amount if (output > uint256(amountAvailable)) { output = uint256(amountAvailable); } } input = getAmountA(resultPrice, currentPrice, liquidity); feeAmount = FullMath.mulDivRoundingUp(input, fee, 1e6 - fee); } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title Safe casting methods /// @notice Contains methods for safely casting between types /// @dev Credit to Uniswap Labs under GPL-2.0-or-later license: /// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries library SafeCast { /// @notice Cast a uint256 to a uint160, revert on overflow /// @param y The uint256 to be downcasted /// @return z The downcasted integer, now type uint160 function toUint160(uint256 y) internal pure returns (uint160 z) { require((z = uint160(y)) == y); } /// @notice Cast a int256 to a int128, revert on overflow or underflow /// @param y The int256 to be downcasted /// @return z The downcasted integer, now type int128 function toInt128(int256 y) internal pure returns (int128 z) { require((z = int128(y)) == y); } /// @notice Cast a uint256 to a int256, revert on overflow /// @param y The uint256 to be casted /// @return z The casted integer, now type int256 function toInt256(uint256 y) internal pure returns (int256 z) { require(y < 2**255); z = int256(y); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.7.6; import './LowGasSafeMath.sol'; import './SafeCast.sol'; import './LiquidityMath.sol'; import './Constants.sol'; /// @title TickManager /// @notice Contains functions for managing tick processes and relevant calculations library TickManager { using LowGasSafeMath for int256; using SafeCast for int256; // info stored for each initialized individual tick struct Tick { uint128 liquidityTotal; // the total position liquidity that references this tick int128 liquidityDelta; // amount of net liquidity added (subtracted) when tick is crossed left-right (right-left), // fee growth per unit of liquidity on the _other_ side of this tick (relative to the current tick) // only has relative meaning, not absolute — the value depends on when the tick is initialized uint256 outerFeeGrowth0Token; uint256 outerFeeGrowth1Token; int56 outerTickCumulative; // the cumulative tick value on the other side of the tick uint160 outerSecondsPerLiquidity; // the seconds per unit of liquidity on the _other_ side of current tick, (relative meaning) uint32 outerSecondsSpent; // the seconds spent on the other side of the current tick, only has relative meaning bool initialized; // these 8 bits are set to prevent fresh sstores when crossing newly initialized ticks } /// @notice Retrieves fee growth data /// @param self The mapping containing all tick information for initialized ticks /// @param bottomTick The lower tick boundary of the position /// @param topTick The upper tick boundary of the position /// @param currentTick The current tick /// @param totalFeeGrowth0Token The all-time global fee growth, per unit of liquidity, in token0 /// @param totalFeeGrowth1Token The all-time global fee growth, per unit of liquidity, in token1 /// @return innerFeeGrowth0Token The all-time fee growth in token0, per unit of liquidity, inside the position's tick boundaries /// @return innerFeeGrowth1Token The all-time fee growth in token1, per unit of liquidity, inside the position's tick boundaries function getInnerFeeGrowth( mapping(int24 => Tick) storage self, int24 bottomTick, int24 topTick, int24 currentTick, uint256 totalFeeGrowth0Token, uint256 totalFeeGrowth1Token ) internal view returns (uint256 innerFeeGrowth0Token, uint256 innerFeeGrowth1Token) { Tick storage lower = self[bottomTick]; Tick storage upper = self[topTick]; if (currentTick < topTick) { if (currentTick >= bottomTick) { innerFeeGrowth0Token = totalFeeGrowth0Token - lower.outerFeeGrowth0Token; innerFeeGrowth1Token = totalFeeGrowth1Token - lower.outerFeeGrowth1Token; } else { innerFeeGrowth0Token = lower.outerFeeGrowth0Token; innerFeeGrowth1Token = lower.outerFeeGrowth1Token; } innerFeeGrowth0Token -= upper.outerFeeGrowth0Token; innerFeeGrowth1Token -= upper.outerFeeGrowth1Token; } else { innerFeeGrowth0Token = upper.outerFeeGrowth0Token - lower.outerFeeGrowth0Token; innerFeeGrowth1Token = upper.outerFeeGrowth1Token - lower.outerFeeGrowth1Token; } } /// @notice Updates a tick and returns true if the tick was flipped from initialized to uninitialized, or vice versa /// @param self The mapping containing all tick information for initialized ticks /// @param tick The tick that will be updated /// @param currentTick The current tick /// @param liquidityDelta A new amount of liquidity to be added (subtracted) when tick is crossed from left to right (right to left) /// @param totalFeeGrowth0Token The all-time global fee growth, per unit of liquidity, in token0 /// @param totalFeeGrowth1Token The all-time global fee growth, per unit of liquidity, in token1 /// @param secondsPerLiquidityCumulative The all-time seconds per max(1, liquidity) of the pool /// @param tickCumulative The all-time global cumulative tick /// @param time The current block timestamp cast to a uint32 /// @param upper true for updating a position's upper tick, or false for updating a position's lower tick /// @return flipped Whether the tick was flipped from initialized to uninitialized, or vice versa function update( mapping(int24 => Tick) storage self, int24 tick, int24 currentTick, int128 liquidityDelta, uint256 totalFeeGrowth0Token, uint256 totalFeeGrowth1Token, uint160 secondsPerLiquidityCumulative, int56 tickCumulative, uint32 time, bool upper ) internal returns (bool flipped) { Tick storage data = self[tick]; int128 liquidityDeltaBefore = data.liquidityDelta; uint128 liquidityTotalBefore = data.liquidityTotal; uint128 liquidityTotalAfter = LiquidityMath.addDelta(liquidityTotalBefore, liquidityDelta); require(liquidityTotalAfter < Constants.MAX_LIQUIDITY_PER_TICK + 1, 'LO'); // when the lower (upper) tick is crossed left to right (right to left), liquidity must be added (removed) data.liquidityDelta = upper ? int256(liquidityDeltaBefore).sub(liquidityDelta).toInt128() : int256(liquidityDeltaBefore).add(liquidityDelta).toInt128(); data.liquidityTotal = liquidityTotalAfter; flipped = (liquidityTotalAfter == 0); if (liquidityTotalBefore == 0) { flipped = !flipped; // by convention, we assume that all growth before a tick was initialized happened _below_ the tick if (tick <= currentTick) { data.outerFeeGrowth0Token = totalFeeGrowth0Token; data.outerFeeGrowth1Token = totalFeeGrowth1Token; data.outerSecondsPerLiquidity = secondsPerLiquidityCumulative; data.outerTickCumulative = tickCumulative; data.outerSecondsSpent = time; } data.initialized = true; } } /// @notice Transitions to next tick as needed by price movement /// @param self The mapping containing all tick information for initialized ticks /// @param tick The destination tick of the transition /// @param totalFeeGrowth0Token The all-time global fee growth, per unit of liquidity, in token0 /// @param totalFeeGrowth1Token The all-time global fee growth, per unit of liquidity, in token1 /// @param secondsPerLiquidityCumulative The current seconds per liquidity /// @param tickCumulative The all-time global cumulative tick /// @param time The current block.timestamp /// @return liquidityDelta The amount of liquidity added (subtracted) when tick is crossed from left to right (right to left) function cross( mapping(int24 => Tick) storage self, int24 tick, uint256 totalFeeGrowth0Token, uint256 totalFeeGrowth1Token, uint160 secondsPerLiquidityCumulative, int56 tickCumulative, uint32 time ) internal returns (int128 liquidityDelta) { Tick storage data = self[tick]; data.outerSecondsSpent = time - data.outerSecondsSpent; data.outerSecondsPerLiquidity = secondsPerLiquidityCumulative - data.outerSecondsPerLiquidity; data.outerTickCumulative = tickCumulative - data.outerTickCumulative; data.outerFeeGrowth1Token = totalFeeGrowth1Token - data.outerFeeGrowth1Token; data.outerFeeGrowth0Token = totalFeeGrowth0Token - data.outerFeeGrowth0Token; return data.liquidityDelta; } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title Math library for computing sqrt prices from ticks and vice versa /// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports /// prices between 2**-128 and 2**128 /// @dev Credit to Uniswap Labs under GPL-2.0-or-later license: /// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries library TickMath { /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128 int24 internal constant MIN_TICK = -887272; /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128 int24 internal constant MAX_TICK = -MIN_TICK; /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK) uint160 internal constant MIN_SQRT_RATIO = 4295128739; /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK) uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342; /// @notice Calculates sqrt(1.0001^tick) * 2^96 /// @dev Throws if |tick| > max tick /// @param tick The input tick for the above formula /// @return price A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0) /// at the given tick function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 price) { // get abs value int24 mask = tick >> (24 - 1); uint256 absTick = uint256((tick ^ mask) - mask); require(absTick <= uint256(MAX_TICK), 'T'); uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000; if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128; if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128; if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128; if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128; if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128; if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128; if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128; if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128; if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128; if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128; if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128; if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128; if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128; if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128; if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128; if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128; if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128; if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128; if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128; if (tick > 0) ratio = type(uint256).max / ratio; // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96. // we then downcast because we know the result always fits within 160 bits due to our tick input constraint // we round up in the division so getTickAtSqrtRatio of the output price is always consistent price = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1)); } /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio /// @dev Throws in case price < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may /// ever return. /// @param price The sqrt ratio for which to compute the tick as a Q64.96 /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio function getTickAtSqrtRatio(uint160 price) internal pure returns (int24 tick) { // second inequality must be < because the price can never reach the price at the max tick require(price >= MIN_SQRT_RATIO && price < MAX_SQRT_RATIO, 'R'); uint256 ratio = uint256(price) << 32; uint256 r = ratio; uint256 msb = 0; assembly { let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(5, gt(r, 0xFFFFFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(4, gt(r, 0xFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(3, gt(r, 0xFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(2, gt(r, 0xF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(1, gt(r, 0x3)) msb := or(msb, f) r := shr(f, r) } assembly { let f := gt(r, 0x1) msb := or(msb, f) } if (msb >= 128) r = ratio >> (msb - 127); else r = ratio << (127 - msb); int256 log_2 = (int256(msb) - 128) << 64; assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(63, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(62, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(61, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(60, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(59, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(58, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(57, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(56, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(55, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(54, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(53, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(52, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(51, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(50, f)) } int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128); int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128); tick = tickLow == tickHi ? tickLow : getSqrtRatioAtTick(tickHi) <= price ? tickHi : tickLow; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.7.6; import './Constants.sol'; import './TickMath.sol'; /// @title Packed tick initialized state library /// @notice Stores a packed mapping of tick index to its initialized state /// @dev The mapping uses int16 for keys since ticks are represented as int24 and there are 256 (2^8) values per word. library TickTable { /// @notice Toggles the initialized state for a given tick from false to true, or vice versa /// @param self The mapping in which to toggle the tick /// @param tick The tick to toggle function toggleTick(mapping(int16 => uint256) storage self, int24 tick) internal { require(tick % Constants.TICK_SPACING == 0, 'tick is not spaced'); // ensure that the tick is spaced tick /= Constants.TICK_SPACING; // compress tick int16 rowNumber; uint8 bitNumber; assembly { bitNumber := and(tick, 0xFF) rowNumber := shr(8, tick) } self[rowNumber] ^= 1 << bitNumber; } /// @notice get position of single 1-bit /// @dev it is assumed that word contains exactly one 1-bit, otherwise the result will be incorrect /// @param word The word containing only one 1-bit function getSingleSignificantBit(uint256 word) internal pure returns (uint8 singleBitPos) { assembly { singleBitPos := iszero(and(word, 0x5555555555555555555555555555555555555555555555555555555555555555)) singleBitPos := or(singleBitPos, shl(7, iszero(and(word, 0x00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)))) singleBitPos := or(singleBitPos, shl(6, iszero(and(word, 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF)))) singleBitPos := or(singleBitPos, shl(5, iszero(and(word, 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF)))) singleBitPos := or(singleBitPos, shl(4, iszero(and(word, 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF)))) singleBitPos := or(singleBitPos, shl(3, iszero(and(word, 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF)))) singleBitPos := or(singleBitPos, shl(2, iszero(and(word, 0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F)))) singleBitPos := or(singleBitPos, shl(1, iszero(and(word, 0x3333333333333333333333333333333333333333333333333333333333333333)))) } } /// @notice get position of most significant 1-bit (leftmost) /// @dev it is assumed that before the call, a check will be made that the argument (word) is not equal to zero /// @param word The word containing at least one 1-bit function getMostSignificantBit(uint256 word) internal pure returns (uint8 mostBitPos) { assembly { word := or(word, shr(1, word)) word := or(word, shr(2, word)) word := or(word, shr(4, word)) word := or(word, shr(8, word)) word := or(word, shr(16, word)) word := or(word, shr(32, word)) word := or(word, shr(64, word)) word := or(word, shr(128, word)) word := sub(word, shr(1, word)) } return (getSingleSignificantBit(word)); } /// @notice Returns the next initialized tick contained in the same word (or adjacent word) as the tick that is either /// to the left (less than or equal to) or right (greater than) of the given tick /// @param self The mapping in which to compute the next initialized tick /// @param tick The starting tick /// @param lte Whether to search for the next initialized tick to the left (less than or equal to the starting tick) /// @return nextTick The next initialized or uninitialized tick up to 256 ticks away from the current tick /// @return initialized Whether the next tick is initialized, as the function only searches within up to 256 ticks function nextTickInTheSameRow( mapping(int16 => uint256) storage self, int24 tick, bool lte ) internal view returns (int24 nextTick, bool initialized) { { int24 tickSpacing = Constants.TICK_SPACING; // compress and round towards negative infinity if negative assembly { tick := sub(sdiv(tick, tickSpacing), and(slt(tick, 0), not(iszero(smod(tick, tickSpacing))))) } } if (lte) { // unpacking not made into a separate function for gas and contract size savings int16 rowNumber; uint8 bitNumber; assembly { bitNumber := and(tick, 0xFF) rowNumber := shr(8, tick) } uint256 _row = self[rowNumber] << (255 - bitNumber); // all the 1s at or to the right of the current bitNumber if (_row != 0) { tick -= int24(255 - getMostSignificantBit(_row)); return (uncompressAndBoundTick(tick), true); } else { tick -= int24(bitNumber); return (uncompressAndBoundTick(tick), false); } } else { // start from the word of the next tick, since the current tick state doesn't matter tick += 1; int16 rowNumber; uint8 bitNumber; assembly { bitNumber := and(tick, 0xFF) rowNumber := shr(8, tick) } // all the 1s at or to the left of the bitNumber uint256 _row = self[rowNumber] >> (bitNumber); if (_row != 0) { tick += int24(getSingleSignificantBit(-_row & _row)); // least significant bit return (uncompressAndBoundTick(tick), true); } else { tick += int24(255 - bitNumber); return (uncompressAndBoundTick(tick), false); } } } function uncompressAndBoundTick(int24 tick) private pure returns (int24 boundedTick) { boundedTick = tick * Constants.TICK_SPACING; if (boundedTick < TickMath.MIN_TICK) { boundedTick = TickMath.MIN_TICK; } else if (boundedTick > TickMath.MAX_TICK) { boundedTick = TickMath.MAX_TICK; } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.7.6; import './LowGasSafeMath.sol'; import './SafeCast.sol'; import './FullMath.sol'; import './Constants.sol'; /// @title Functions based on Q64.96 sqrt price and liquidity /// @notice Contains the math that uses square root of price as a Q64.96 and liquidity to compute deltas library TokenDeltaMath { using LowGasSafeMath for uint256; using SafeCast for uint256; /// @notice Gets the token0 delta between two prices /// @dev Calculates liquidity / sqrt(lower) - liquidity / sqrt(upper) /// @param priceLower A Q64.96 sqrt price /// @param priceUpper Another Q64.96 sqrt price /// @param liquidity The amount of usable liquidity /// @param roundUp Whether to round the amount up or down /// @return token0Delta Amount of token0 required to cover a position of size liquidity between the two passed prices function getToken0Delta( uint160 priceLower, uint160 priceUpper, uint128 liquidity, bool roundUp ) internal pure returns (uint256 token0Delta) { uint256 priceDelta = priceUpper - priceLower; require(priceDelta < priceUpper); // forbids underflow and 0 priceLower uint256 liquidityShifted = uint256(liquidity) << Constants.RESOLUTION; token0Delta = roundUp ? FullMath.divRoundingUp(FullMath.mulDivRoundingUp(priceDelta, liquidityShifted, priceUpper), priceLower) : FullMath.mulDiv(priceDelta, liquidityShifted, priceUpper) / priceLower; } /// @notice Gets the token1 delta between two prices /// @dev Calculates liquidity * (sqrt(upper) - sqrt(lower)) /// @param priceLower A Q64.96 sqrt price /// @param priceUpper Another Q64.96 sqrt price /// @param liquidity The amount of usable liquidity /// @param roundUp Whether to round the amount up, or down /// @return token1Delta Amount of token1 required to cover a position of size liquidity between the two passed prices function getToken1Delta( uint160 priceLower, uint160 priceUpper, uint128 liquidity, bool roundUp ) internal pure returns (uint256 token1Delta) { require(priceUpper >= priceLower); uint256 priceDelta = priceUpper - priceLower; token1Delta = roundUp ? FullMath.mulDivRoundingUp(priceDelta, liquidity, Constants.Q96) : FullMath.mulDiv(priceDelta, liquidity, Constants.Q96); } /// @notice Helper that gets signed token0 delta /// @param priceLower A Q64.96 sqrt price /// @param priceUpper Another Q64.96 sqrt price /// @param liquidity The change in liquidity for which to compute the token0 delta /// @return token0Delta Amount of token0 corresponding to the passed liquidityDelta between the two prices function getToken0Delta( uint160 priceLower, uint160 priceUpper, int128 liquidity ) internal pure returns (int256 token0Delta) { token0Delta = liquidity >= 0 ? getToken0Delta(priceLower, priceUpper, uint128(liquidity), true).toInt256() : -getToken0Delta(priceLower, priceUpper, uint128(-liquidity), false).toInt256(); } /// @notice Helper that gets signed token1 delta /// @param priceLower A Q64.96 sqrt price /// @param priceUpper Another Q64.96 sqrt price /// @param liquidity The change in liquidity for which to compute the token1 delta /// @return token1Delta Amount of token1 corresponding to the passed liquidityDelta between the two prices function getToken1Delta( uint160 priceLower, uint160 priceUpper, int128 liquidity ) internal pure returns (int256 token1Delta) { token1Delta = liquidity >= 0 ? getToken1Delta(priceLower, priceUpper, uint128(liquidity), true).toInt256() : -getToken1Delta(priceLower, priceUpper, uint128(-liquidity), false).toInt256(); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.6.0; import '../interfaces/IERC20Minimal.sol'; /// @title TransferHelper /// @notice Contains helper methods for interacting with ERC20 tokens that do not consistently return true/false /// @dev Credit to Uniswap Labs under GPL-2.0-or-later license: /// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries library TransferHelper { /// @notice Transfers tokens from msg.sender to a recipient /// @dev Calls transfer on token contract, errors with TF if transfer fails /// @param token The contract address of the token which will be transferred /// @param to The recipient of the transfer /// @param value The value of the transfer function safeTransfer( address token, address to, uint256 value ) internal { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20Minimal.transfer.selector, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TF'); } }
{ "optimizer": { "enabled": true, "runs": 0 }, "metadata": { "bytecodeHash": "none", "useLiteralContent": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"factory","type":"address"}],"name":"Factory","type":"event"},{"inputs":[{"internalType":"address","name":"dataStorage","type":"address"},{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"name":"deploy","outputs":[{"internalType":"address","name":"pool","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"parameters","outputs":[{"internalType":"address","name":"dataStorage","type":"address"},{"internalType":"address","name":"factory","type":"address"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_factory","type":"address"}],"name":"setFactory","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50600580546001600160a01b03191633179055615969806100326000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80635bb4780814610046578063890357301461006e578063fd82b73a146100aa575b600080fd5b61006c6004803603602081101561005c57600080fd5b50356001600160a01b0316610104565b005b61007661019a565b604080516001600160a01b039586168152938516602085015291841683830152909216606082015290519081900360800190f35b6100e8600480360360808110156100c057600080fd5b506001600160a01b0381358116916020810135821691604082013581169160600135166101be565b604080516001600160a01b039092168252519081900360200190f35b6005546001600160a01b0316331461011b57600080fd5b6001600160a01b03811661012e57600080fd5b6004546001600160a01b03161561014457600080fd5b6040516001600160a01b038216907f194d5292f3fd797c05e95926ce4b1d4d7f7f10c7dd0c467e55a42d82006bbc6990600090a2600480546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001546002546003546001600160a01b039384169392831692918216911684565b6004546000906001600160a01b031633146101d857600080fd5b604080516080810182526001600160a01b0380881680835287821660208085018290528884168587018190529388166060958601819052600080546001600160a01b03199081169095179055600180548516909317909255600280548416851790556003805490931682179092558451808301939093528285015283518083038501815291909201928390528051910120906102739061029d565b8190604051809103906000f5905080158015610293573d6000803e3d6000fd5b5095945050505050565b6156b2806102ab8339019056fe6101006040523480156200001257600080fd5b5033806001600160a01b031663890357306040518163ffffffff1660e01b815260040160806040518083038186803b1580156200004e57600080fd5b505afa15801562000063573d6000803e3d6000fd5b505050506040513d60808110156200007a57600080fd5b508051602082015160408301516060938401516001600160601b031990851b811660e05290841b811660c05290831b811660a052911b166080525060028054601960ba1b61ffff60b81b1990911617905560805160601c60a05160601c60c05160601c60e05160601c61550a620001a860003980610a4a5280610b885280610ec15280611150528061136b52806115f252806116a052806116da52806127bf52806128bd52806136b15250806109f15280610aea5280610bae5280610e6f528061108752806113285280611628528061166a528061278a528061355b525080610c6c5280610f8552806118b652806119e452806128825280613720525080610d8052806117875280611d905280612a005280613332528061396852806140dd52806141a9525061550a6000f3fe608060405234801561001057600080fd5b50600436106101545760003560e01c80630dfe168114610159578063128acb081461017d57806317e25b3c1461022a5780631a6865021461024b578063289fe9b01461026f57806329047dfa14610294578063490e6cbc1461029c5780634f1eb3d814610326578063514ea4bf146103a65780636378ae441461040b57806370cf754a14610425578063713346941461042d57806374eceae6146104ca5780637c0112b7146105465780637c1fe0c81461056e578063920c34e5146105945780639d3a5241146105ef578063a34123a714610780578063aafe29c0146107ba578063c45a01551461088c578063c677e3e014610894578063d0c93a7c146108b4578063d21220a7146108d3578063e76c01e4146108db578063ecdecf4214610937578063f30dba931461093f578063f637731d146109c1578063facb0eb1146109e7575b600080fd5b6101616109ef565b604080516001600160a01b039092168252519081900360200190f35b610211600480360360a081101561019357600080fd5b6001600160a01b0382358116926020810135151592604082013592606083013516919081019060a081016080820135600160201b8111156101d357600080fd5b8201836020820111156101e557600080fd5b803590602001918460018302840111600160201b8311171561020657600080fd5b509092509050610a13565b6040805192835260208301919091528051918290030190f35b610232610c4f565b6040805163ffffffff9092168252519081900360200190f35b610253610c5b565b604080516001600160801b039092168252519081900360200190f35b6102926004803603602081101561028557600080fd5b503563ffffffff16610c6a565b005b610161610d7e565b610292600480360360808110156102b257600080fd5b6001600160a01b038235169160208101359160408201359190810190608081016060820135600160201b8111156102e857600080fd5b8201836020820111156102fa57600080fd5b803590602001918460018302840111600160201b8311171561031b57600080fd5b509092509050610da2565b610377600480360360a081101561033c57600080fd5b506001600160a01b03813516906020810135600290810b91604081013590910b906001600160801b0360608201358116916080013516611222565b60405180836001600160801b03168152602001826001600160801b031681526020019250505060405180910390f35b6103c3600480360360208110156103bc57600080fd5b503561141c565b604080516001600160801b03978816815263ffffffff90961660208701528581019490945260608501929092528416608084015290921660a082015290519081900360c00190f35b610413611465565b60408051918252519081900360200190f35b61025361146b565b610211600480360360c081101561044357600080fd5b6001600160a01b0382358116926020810135821692604082013515159260608301359260808101359091169181019060c0810160a0820135600160201b81111561048c57600080fd5b82018360208201111561049e57600080fd5b803590602001918460018302840111600160201b831117156104bf57600080fd5b50909250905061147e565b6104e7600480360360208110156104e057600080fd5b503561177a565b60408051971515885263ffffffff909616602088015260069490940b868601526001600160a01b0390921660608601526001600160581b0316608085015260020b60a08401526001600160901b031660c0830152519081900360e00190f35b6102926004803603604081101561055c57600080fd5b5060ff8135811691602001351661184b565b6102926004803603602081101561058457600080fd5b50356001600160a01b03166119e2565b6105be600480360360408110156105aa57600080fd5b508035600290810b9160200135900b611ad1565b6040805160069490940b84526001600160a01b03909216602084015263ffffffff1682820152519081900360600190f35b61065d6004803603602081101561060557600080fd5b810190602081018135600160201b81111561061f57600080fd5b82018360208201111561063157600080fd5b803590602001918460208302840111600160201b8311171561065257600080fd5b509092509050611d88565b6040518080602001806020018060200180602001858103855289818151815260200191508051906020019060200280838360005b838110156106a9578181015183820152602001610691565b50505050905001858103845288818151815260200191508051906020019060200280838360005b838110156106e85781810151838201526020016106d0565b50505050905001858103835287818151815260200191508051906020019060200280838360005b8381101561072757818101518382015260200161070f565b50505050905001858103825286818151815260200191508051906020019060200280838360005b8381101561076657818101518382015260200161074e565b505050509050019850505050505050505060405180910390f35b6102116004803603606081101561079657600080fd5b508035600290810b91602081013590910b90604001356001600160801b03166120ed565b610865600480360360c08110156107d057600080fd5b6001600160a01b0382358116926020810135909116916040820135600290810b92606081013590910b916001600160801b03608083013516919081019060c0810160a0820135600160201b81111561082757600080fd5b82018360208201111561083957600080fd5b803590602001918460018302840111600160201b8311171561085a57600080fd5b509092509050612329565b6040805193845260208401929092526001600160801b031682820152519081900360600190f35b610161612880565b610413600480360360208110156108aa57600080fd5b503560010b6128a4565b6108bc6128b6565b6040805160029290920b8252519081900360200190f35b6101616128bb565b6108e36128df565b604080516001600160a01b03909816885260029690960b602088015261ffff9485168787015292909316606086015260ff90811660808601529190911660a0840152151560c0830152519081900360e00190f35b610413612932565b61095f6004803603602081101561095557600080fd5b503560020b612938565b604080516001600160801b039099168952600f9790970b602089015287870195909552606087019390935260069190910b60808601526001600160a01b031660a085015263ffffffff1660c0840152151560e083015251908190036101000190f35b610292600480360360208110156109d757600080fd5b50356001600160a01b03166129a2565b610161612b13565b7f000000000000000000000000000000000000000000000000000000000000000081565b600080600080600080610a278b8b8b612b29565b949a509298509096509450925090508a15610adc576000851215610a7357610a737f00000000000000000000000000000000000000000000000000000000000000008d87600003613409565b6000610a7d613557565b9050610a8b87878b8b6135f7565b610a93613557565b610a9d8289613697565b1115610ad6576040805162461bcd60e51b815260206004820152600360248201526249494160e81b604482015290519081900360640190fd5b50610b78565b6000861215610b1357610b137f00000000000000000000000000000000000000000000000000000000000000008d88600003613409565b6000610b1d6136ad565b9050610b2b87878b8b6135f7565b610b336136ad565b610b3d8288613697565b1115610b76576040805162461bcd60e51b815260206004820152600360248201526249494160e81b604482015290519081900360640190fd5b505b8015610bd457610bd48b610bac577f0000000000000000000000000000000000000000000000000000000000000000610bce565b7f00000000000000000000000000000000000000000000000000000000000000005b8261371c565b60408051878152602081018790526001600160a01b03868116828401526001600160801b0385166060830152600286900b60808301529151918e169133916000805160206154de833981519152919081900360a00190a350506002805460ff60e81b1916600160e81b17905550919890975095505050505050565b60045463ffffffff1681565b6003546001600160801b031681565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610cc357600080fd5b505afa158015610cd7573d6000803e3d6000fd5b505050506040513d6020811015610ced57600080fd5b50516001600160a01b03163314610d0357600080fd5b6201518063ffffffff821611801590610d27575060045463ffffffff828116911614155b610d3057600080fd5b6004805463ffffffff831663ffffffff19909116811790915560408051918252517fb5e51602371b0e74f991b6e965cd7d32b4b14c7e6ede6d1298037650a0e1405f9181900360200190a150565b7f000000000000000000000000000000000000000000000000000000000000000081565b600254600160e81b900460ff16610de6576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6002805460ff60e81b191690556003546001600160801b031680610e35576040805162461bcd60e51b81526020600482015260016024820152601360fa1b604482015290519081900360640190fd5b600254600160b81b900461ffff16600080610e4e613557565b90508715610e9557610e68888461ffff16620f42406137b5565b9150610e957f00000000000000000000000000000000000000000000000000000000000000008a8a613409565b600080610ea06136ad565b90508815610ee757610eba898661ffff16620f42406137b5565b9150610ee77f00000000000000000000000000000000000000000000000000000000000000008c8b613409565b336001600160a01b031663a60b0d3c85848b8b6040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b158015610f6957600080fd5b505af1158015610f7d573d6000803e3d6000fd5b5050505060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663430bf08a6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fdc57600080fd5b505afa158015610ff0573d6000803e3d6000fd5b505050506040513d602081101561100657600080fd5b505190506000611014613557565b9050806110218688613697565b1115611059576040805162461bcd60e51b8152602060048201526002602482015261046360f41b604482015290519081900360640190fd5b84900380156110d357600254600160d81b900460ff16600081156110ad57506103e860ff82168302046110ad7f00000000000000000000000000000000000000000000000000000000000000008583613409565b6110c7818403600160801b8c6001600160801b031661382a565b60008054909101905550505b60006110dd6136ad565b9050806110ea8587613697565b1115611122576040805162461bcd60e51b8152602060048201526002602482015261463160f01b604482015290519081900360640190fd5b839003801561119c57600254600160e01b900460ff166000811561117657506103e860ff82168302046111767f00000000000000000000000000000000000000000000000000000000000000008683613409565b611190818403600160801b8d6001600160801b031661382a565b60018054909101905550505b8d6001600160a01b0316336001600160a01b03167fbdbdb71d7860376ba52b25a5028beea23581364a40522f6bcfb86bb1f2dca6338f8f86866040518085815260200184815260200183815260200182815260200194505050505060405180910390a350506002805460ff60e81b1916600160e81b179055505050505050505050505050565b6002546000908190600160e81b900460ff1661126b576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6002805460ff60e81b1916905560006112853388886138c0565b60038101549091506001600160801b0380821691600160801b9004811690871682106112b157866112b3565b815b9450806001600160801b0316866001600160801b0316116112d457856112d6565b805b93506001600160801b03858517161561139a576003830180546001600160801b0319168684036001600160801b03908116919091178116600160801b87850383160217909155851615611357576113577f00000000000000000000000000000000000000000000000000000000000000008b876001600160801b0316613409565b6001600160801b0384161561139a5761139a7f00000000000000000000000000000000000000000000000000000000000000008b866001600160801b0316613409565b604080516001600160a01b038c1681526001600160801b038088166020830152861681830152905160028a810b92908c900b9133917f70935338e69775456a85ddef226c395fb668b63fa0115f5f20610b388e6ca9c0919081900360600190a450506002805460ff60e81b1916600160e81b1790555090969095509350505050565b60076020526000908152604090208054600182015460028301546003909301546001600160801b038084169463ffffffff600160801b9586900416949092808316929190041686565b60005481565b6e023746e6a58dcb13d4af821b93f06290565b6002546000908190600160e81b900460ff166114c7576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6002805460ff60e81b1916905586156115485760006114e4613557565b90506114f387600087876135f7565b600061150782611501613557565b906138e4565b97508713611542576040805162461bcd60e51b815260206004820152600360248201526249494160e81b604482015290519081900360640190fd5b506115ac565b60006115526136ad565b905061156160008887876135f7565b600061156f826115016136ad565b975087136115aa576040805162461bcd60e51b815260206004820152600360248201526249494160e81b604482015290519081900360640190fd5b505b6002805460ff60e81b1916600160e81b17905560008080806115cf8b8b8b612b29565b949a509298509096509450925090508a1561165c57600085121561161b5761161b7f00000000000000000000000000000000000000000000000000000000000000008d87600003613409565b89861215611657576116577f00000000000000000000000000000000000000000000000000000000000000008e6116528d8a6138f4565b613409565b6116ca565b6000861215611693576116937f00000000000000000000000000000000000000000000000000000000000000008d88600003613409565b898512156116ca576116ca7f00000000000000000000000000000000000000000000000000000000000000008e6116528d896138f4565b80156116fe576116fe8b610bac577f0000000000000000000000000000000000000000000000000000000000000000610bce565b60408051878152602081018790526001600160a01b03868116828401526001600160801b0385166060830152600286900b60808301529151918e169133916000805160206154de833981519152919081900360a00190a350506002805460ff60e81b1916600160e81b1790555091999098509650505050505050565b60008060008060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166374eceae6896040518263ffffffff1660e01b81526004018082815260200191505060e06040518083038186803b1580156117e957600080fd5b505afa1580156117fd573d6000803e3d6000fd5b505050506040513d60e081101561181357600080fd5b508051602082015160408301516060840151608085015160a086015160c090960151949e939d50919b50995097509195509350915050565b600254600160e81b900460ff1661188f576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6002805460ff60e81b1916905560408051638da5cb5b60e01b815290516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691638da5cb5b916004808301926020929190829003018186803b1580156118fc57600080fd5b505afa158015611910573d6000803e3d6000fd5b505050506040513d602081101561192657600080fd5b50516001600160a01b0316331461193c57600080fd5b60fa60ff831611801590611954575060fa60ff821611155b61195d57600080fd5b6002805460ff60e01b1916600160e01b60ff8481169182029290921760ff60d81b1916600160d81b9286169283021790925560408051918252602082019290925281517f9e22b964b08e25c3aaa72102bb0071c089258fb82d51271a8ddf5c24921356ee929181900390910190a150506002805460ff60e81b1916600160e81b179055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638a2ade586040518163ffffffff1660e01b815260040160206040518083038186803b158015611a3b57600080fd5b505afa158015611a4f573d6000803e3d6000fd5b505050506040513d6020811015611a6557600080fd5b50516001600160a01b03163314611a7b57600080fd5b60048054600160201b600160c01b031916600160201b6001600160a01b038416908102919091179091556040517f915c5369e6580733735d1c2e30ca20dcaa395697a041033c9f35f80f53525e8490600090a250565b600080808484620d89e9600282900b12611b18576040805162461bcd60e51b815260206004820152600360248201526254554d60e81b604482015290519081900360640190fd5b8160020b8160020b13611b58576040805162461bcd60e51b8152602060048201526003602482015262544c5560e81b604482015290519081900360640190fd5b620d89e819600283900b13611b9a576040805162461bcd60e51b8152602060048201526003602482015262544c4d60e81b604482015290519081900360640190fd5b611ba261540e565b600288810b900b6000908152600560209081526040918290206003810154600160d81b810463ffffffff1693850193909352600160381b83046001600160a01b031691840191909152600682810b810b900b835290600160f81b900460ff16611c0a57600080fd5b50611c1361540e565b600288810b900b6000908152600560209081526040918290206003810154600160d81b810463ffffffff1693850193909352600160381b83046001600160a01b031691840191909152600682810b810b900b835290600160f81b900460ff16611c7b57600080fd5b5060028054600160a01b8104820b91600160c81b90910461ffff16908b810b9083900b1215611cd45782600001518460000151038360200151856020015103846040015186604001510398509850985050505050611d7f565b8960020b8260020b1215611d53576000611cec61390a565b9050600080611d148360008787600360009054906101000a90046001600160801b031661390e565b5050915091508560000151876000015183030386602001518860200151830303876040015189604001518603039b509b509b5050505050505050611d7f565b836000015183600001510384602001518460200151038560400151856040015103985098509850505050505b50509250925092565b6060806060807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fd31e988611dc561390a565b6002805460035460405160e086901b6001600160e01b031916815263ffffffff851660048201908152600160a01b8404850b9485900b6044830152600160c81b90930461ffff16606482018190526001600160801b039092166084820181905260a06024830190815260a483018e90528e958e9590949390919060c401876020880280828437600081840152601f19601f82011690508083019250505097505050505050505060006040518083038186803b158015611e8357600080fd5b505afa158015611e97573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526080811015611ec057600080fd5b8101908080516040519392919084600160201b821115611edf57600080fd5b908301906020820185811115611ef457600080fd5b82518660208202830111600160201b82111715611f1057600080fd5b82525081516020918201928201910280838360005b83811015611f3d578181015183820152602001611f25565b5050505090500160405260200180516040519392919084600160201b821115611f6557600080fd5b908301906020820185811115611f7a57600080fd5b82518660208202830111600160201b82111715611f9657600080fd5b82525081516020918201928201910280838360005b83811015611fc3578181015183820152602001611fab565b5050505090500160405260200180516040519392919084600160201b821115611feb57600080fd5b90830190602082018581111561200057600080fd5b82518660208202830111600160201b8211171561201c57600080fd5b82525081516020918201928201910280838360005b83811015612049578181015183820152602001612031565b5050505090500160405260200180516040519392919084600160201b82111561207157600080fd5b90830190602082018581111561208657600080fd5b82518660208202830111600160201b821117156120a257600080fd5b82525081516020918201928201910280838360005b838110156120cf5781810151838201526020016120b7565b50505050905001604052505050935093509350935092959194509250565b6002546000908190600160e81b900460ff16612136576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6002805460ff60e81b1916815585908590620d89e99082900b12612187576040805162461bcd60e51b815260206004820152600360248201526254554d60e81b604482015290519081900360640190fd5b8160020b8160020b136121c7576040805162461bcd60e51b8152602060048201526003602482015262544c5560e81b604482015290519081900360640190fd5b620d89e819600283900b13612209576040805162461bcd60e51b8152602060048201526003602482015262544c4d60e81b604482015290519081900360640190fd5b600080600061222e338b8b6122268c6001600160801b03166139fe565b600003613a14565b9250925092508160000396508060000395508587176000146122af576003830154612262906001600160801b031688613cea565b600384015461228190600160801b90046001600160801b031688613cea565b6003850180546001600160801b03938416928416600160801b029316929092176001600160801b0319161790555b604080516001600160801b038a16815260208101899052808201889052905160028b810b92908d900b9133917f0c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c919081900360600190a450506002805460ff60e81b1916600160e81b179055509296919550909350505050565b60025460009081908190600160e81b900460ff16612374576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6002805460ff60e81b1916815588908890620d89e99082900b126123c5576040805162461bcd60e51b815260206004820152600360248201526254554d60e81b604482015290519081900360640190fd5b8160020b8160020b13612405576040805162461bcd60e51b8152602060048201526003602482015262544c5560e81b604482015290519081900360640190fd5b620d89e819600283900b13612447576040805162461bcd60e51b8152602060048201526003602482015262544c4d60e81b604482015290519081900360640190fd5b6000886001600160801b03161161248a576040805162461bcd60e51b8152602060048201526002602482015261125360f21b604482015290519081900360640190fd5b6000806124c18c8c6124a48d6001600160801b03166139fe565b60028054600160a01b810490910b906001600160a01b0316613d06565b5090975095506000915081905086156124df576124dc613557565b91505b85156124f0576124ed6136ad565b90505b336001600160a01b0316633dd657c588888c8c6040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b15801561257257600080fd5b505af1158015612586573d6000803e3d6000fd5b5050505060008711156125dd5760008261259e613557565b03925082116125dd576040805162461bcd60e51b815260206004808301919091526024820152634949414d60e01b604482015290519081900360640190fd5b851561262d576000816125ee6136ad565b039150811161262d576040805162461bcd60e51b815260206004808301919091526024820152634949414d60e01b604482015290519081900360640190fd5b8994508682101561264f5761264c856001600160801b0316838961382a565b94505b8581101561268f57600061266d866001600160801b0316838961382a565b9050856001600160801b0316816001600160801b0316101561268d578095505b505b6000856001600160801b0316116126d6576040805162461bcd60e51b8152602060048083019190915260248201526324a4a61960e11b604482015290519081900360640190fd5b6000806126f68f8f8f6126f18b6001600160801b03166139fe565b613a14565b92509250508382995089111561273b576040805162461bcd60e51b815260206004820152600560248201526424a4a0a69960d91b604482015290519081900360640190fd5b8281985088111561277b576040805162461bcd60e51b815260206004820152600560248201526424a4a0a69960d91b604482015290519081900360640190fd5b5050868211156127b2576127b27f00000000000000000000000000000000000000000000000000000000000000008f898503613409565b858111156127e7576127e77f00000000000000000000000000000000000000000000000000000000000000008f888403613409565b8a60020b8c60020b8e6001600160a01b03167f7a53080ba414158be7ec69b987b5fb7d07dee101fe85488f0853ae16239d0bde33898c8c60405180856001600160a01b03168152602001846001600160801b0316815260200183815260200182815260200194505050505060405180910390a450506002805460ff60e81b1916600160e81b17905550929a919950975095505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60066020526000908152604090205481565b603c90565b7f000000000000000000000000000000000000000000000000000000000000000081565b600280546001600160a01b03811691600160a01b8204900b9061ffff600160b81b8204811691600160c81b81049091169060ff600160d81b8204811691600160e01b8104821691600160e81b9091041687565b60015481565b60056020526000908152604090208054600182015460028301546003909301546001600160801b03831693600160801b909304600f0b9290600681900b90600160381b81046001600160a01b031690600160d81b810463ffffffff1690600160f81b900460ff1688565b6002546001600160a01b0316156129e5576040805162461bcd60e51b8152602060048201526002602482015261414960f01b604482015290519081900360640190fd5b60006129f082613d9e565b905060006129fc61390a565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663475fb80c82846040518363ffffffff1660e01b8152600401808363ffffffff1681526020018260020b815260200192505050600060405180830381600087803b158015612a7557600080fd5b505af1158015612a89573d6000803e3d6000fd5b50506002805485820b62ffffff8116600160a01b0262ffffff60a01b1960ff60e81b196001600160a01b038b166001600160a01b0319909516851716600160e81b17161790925560408051918252602082019290925281517f98636036cb66a9c19a37435efc1e90142190214e8abeb821bdba3f2990dd4c959450908190039091019150a1505050565b600454600160201b90046001600160a01b031681565b6000806000806000806000612b3c61542e565b6002805461ffff600160b81b82048116610160850152600160c81b8204166101a084015260ff60e81b19811682556001600160a01b0381169750600160a01b810490910b955060ff600160d81b8204811691600160e01b8104821691600160e81b9091041680612bd9576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b8c612c10576040805162461bcd60e51b8152602060048201526002602482015261415360f01b604482015290519081900360640190fd5b60008d1361014085015260a084018d90526003546001600160801b03600160801b8204811660208701521696508d15612cb857886001600160a01b03168c6001600160a01b0316108015612c7157506401000276a36001600160a01b038d16115b612ca8576040805162461bcd60e51b815260206004820152600360248201526214d41360ea1b604482015290519081900360640190fd5b60005460e0850152828452612d38565b886001600160a01b03168c6001600160a01b0316118015612cf5575073fffd8963efd1fc6a506488495d951d5263988d266001600160a01b038d16105b612d2c576040805162461bcd60e51b815260206004820152600360248201526214d41360ea1b604482015290519081900360640190fd5b60015460e08501528184525b600288810b900b610180850152612d4d61390a565b600454909550600160201b90046001600160a01b031615612e6357600060048054906101000a90046001600160a01b03166001600160a01b0316637f376059876040518263ffffffff1660e01b8152600401808263ffffffff168152602001915050602060405180830381600087803b158015612dc957600080fd5b505af1158015612ddd573d6000803e3d6000fd5b505050506040513d6020811015612df357600080fd5b505190506000816002811115612e0557fe5b1415612e235760048054600160201b600160c01b0319169055612e61565b6001816002811115612e3157fe5b1415612e44576001610120860152612e61565b6002816002811115612e5257fe5b1415612e615760026101208601525b505b6000612e80856101a00151878761018001518b8960200151614089565b9050846101a0015161ffff168161ffff1614612ebf5761ffff81166101a086015260006020860152612eb4868a838b61415d565b61ffff166101608601525b50505050612ecb61549f565b6001600160a01b0387168152612ee36006878e61425f565b15156040830152600290810b900b60208201819052612f019061435f565b6001600160a01b0390811660608301819052612f3f918e918a918e161182151514612f30578360600151612f32565b8c5b888f876101600151614679565b60c085015260a0840152608083015261014083015190975015612f9857612f6f8160c0015182608001510161483d565b8b039a50612f8e612f838260a0015161483d565b60c0840151906138f4565b60c0830152612fd0565b612fa58160a0015161483d565b8b019a50612fca612fbf8260c0015183608001510161483d565b60c084015190614853565b60c08301525b81511561300c57815160c08201516000916103e891612fee91614869565b81612ff557fe5b60c084018051929091049182900390529490940193505b6001600160801b03851615613043576130378160c00151600160801b876001600160801b031661382a565b60e08301805190910190525b80606001516001600160a01b0316876001600160a01b0316141561320a578060400151156131eb5781608001516130c75761308c836000846101800151856101a001518961390e565b50506001600160a01b03166060840152600690810b900b6040830152600160808301528b6130bc576000546130c0565b6001545b6101008301525b600082610120015160028111156130da57fe5b146131625760048054906101000a90046001600160a01b03166001600160a01b03166301342b1982602001518e6040518363ffffffff1660e01b8152600401808360020b8152602001821515815260200192505050600060405180830381600087803b15801561314957600080fd5b505af115801561315d573d6000803e3d6000fd5b505050505b60008c156131a75761319d82602001518460e001518561010001518660600151876040015189600561488d909695949392919063ffffffff16565b60000390506131dd565b6131da82602001518461010001518560e001518660600151876040015189600561488d909695949392919063ffffffff16565b90505b6131e78682614941565b9550505b8b6131fa578060200151613203565b60018160200151035b955061322e565b80516001600160a01b0388811691161461322e5761322787613d9e565b955061325b565b8a158061324c5750896001600160a01b0316876001600160a01b0316145b156132565761325b565b612ecb565b81610140015115158c15151461327c578160c001518b8360a0015103613289565b8a8260a00151038260c001515b6101608401516101a08501516002805461ffff60c81b1916600160c81b61ffff938416021761ffff60b81b1916600160b81b92909316919091029190911762ffffff60a01b1916600160a01b62ffffff8b840b1602176001600160a01b0319166001600160a01b038b81169190911790915560408051631b7297f760e11b81526001600160801b038a16600482015260248101859052604481018490529051939c50919a5087927f0000000000000000000000000000000000000000000000000000000000000000909116916336e52fee916064808301926020929190829003018186803b15801561337a57600080fd5b505afa15801561338e573d6000803e3d6000fd5b505050506040513d60208110156133a457600080fd5b50516020840151600380546001600160801b03948516929093018416600160801b0293909216929092176001600160801b0319169190911790558b156133f15760e08201516000556133fa565b60e08201516001555b50505093975093979195509350565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b602083106134855780518252601f199092019160209182019101613466565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146134e7576040519150601f19603f3d011682016040523d82523d6000602084013e6134ec565b606091505b509150915081801561351a57508051158061351a575080806020019051602081101561351757600080fd5b50515b613550576040805162461bcd60e51b81526020600482015260026024820152612a2360f11b604482015290519081900360640190fd5b5050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156135c657600080fd5b505afa1580156135da573d6000803e3d6000fd5b505050506040513d60208110156135f057600080fd5b5051905090565b336001600160a01b0316632c8958f6858585856040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b15801561367957600080fd5b505af115801561368d573d6000803e3d6000fd5b5050505050505050565b808201828110156136a757600080fd5b92915050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156135c657600080fd5b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663430bf08a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561377757600080fd5b505afa15801561378b573d6000803e3d6000fd5b505050506040513d60208110156137a157600080fd5b505190506137b0838284613409565b505050565b60008315806137d0575050828202828482816137cd57fe5b04145b156137f157600082116137e257600080fd5b81810490829006151501613823565b6137fc84848461382a565b90506000828061380857fe5b848609111561382357600019811061381f57600080fd5b6001015b9392505050565b6000838302816000198587098281108382030391505080841161384c57600080fd5b8061385c57508290049050613823565b8385870960008581038616958690049560026003880281188089028203028089028203028089028203028089028203028089028203028089029091030291819003819004600101858411909403939093029190930391909104170290509392505050565b62ffffff9081169116601892831b1790911b17600090815260076020526040902090565b808203828111156136a757600080fd5b808203828113156000831215146136a757600080fd5b4290565b604080516314c5407960e01b815263ffffffff808816600483015286166024820152600285900b604482015261ffff841660648201526001600160801b038316608482015290516000918291829182916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916314c540799160a4808301926080929190829003018186803b1580156139ae57600080fd5b505afa1580156139c2573d6000803e3d6000fd5b505050506040513d60808110156139d857600080fd5b50805160208201516040830151606090930151919c909b50919950975095505050505050565b80600f81900b8114613a0f57600080fd5b919050565b60408051606081018252600280546001600160a01b0381168352600160a01b8104820b90910b6020830152600160c81b900461ffff169181019190915260009081908190613a638888886138c0565b60008054600154929650919080600f89900b15613b2a576000613a8461390a565b9050600080613ab48360008a602001518b60400151600360009054906101000a90046001600160801b031661390e565b505091509150613ae38e89602001518e8a8a86888a600060056149f7909998979695949392919063ffffffff16565b15613af75760019450613af760068f614b92565b6020880151613b12906005908f908f8b8b87898b60016149f7565b15613b265760019350613b2660068e614b92565b5050505b60208501516000908190613b46906005908f908f908a8a614c19565b91509150613b568a8c8484614cbb565b8a600f0b600014613cd95760008b600f0b1215613bd1578315613b9f5760028d810b810b6000908152600560205260408120818155600181018290559182018190556003909101555b8215613bd15760028c810b810b6000908152600560205260408120818155600181018290559182018190556003909101555b6000613be88e8e8e8b602001518c60000151613d06565b919b5099509050600f81900b15613cd75760035460408901516001600160801b0390911690600090613c3b90613c1c61390a565b60208d01516003548690600160801b90046001600160801b0316614089565b90508061ffff168a6040015161ffff1614613caa57613c67613c5b61390a565b8b60200151838561415d565b6002805461ffff60b81b1916600160b81b61ffff938416021761ffff60c81b1916600160c81b92841692909202919091179055600380546001600160801b031690555b613cb4828f614941565b600380546001600160801b0319166001600160801b039290921691909117905550505b505b505050505050509450945094915050565b8082016001600160801b0380841690821610156136a757600080fd5b60008060008760020b8560020b1215613d3b57613d34613d258961435f565b613d2e8961435f565b88614e99565b9250613d93565b8660020b8560020b1215613d7557613d5684613d2e8961435f565b9250613d6b613d648961435f565b8588614ede565b9150859050613d93565b613d90613d818961435f565b613d8a8961435f565b88614ede565b91505b955095509592505050565b60006401000276a36001600160a01b03831610801590613dda575073fffd8963efd1fc6a506488495d951d5263988d266001600160a01b038316105b613e0f576040805162461bcd60e51b81526020600482015260016024820152602960f91b604482015290519081900360640190fd5b600160201b600160c01b03602083901b166001600160801b03811160071b81811c6001600160401b03811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c60ff8111600390811b91821c600f811160021b90811c918211600190811b92831c97908811961790941790921717909117171760808110613ea157607f810383901c9150613eab565b80607f0383901b91505b908002607f81811c60ff83811c9190911c800280831c81831c1c800280841c81841c1c800280851c81851c1c800280861c81861c1c800280871c81871c1c800280881c81881c1c800280891c81891c1c8002808a1c818a1c1c8002808b1c818b1c1c8002808c1c818c1c1c8002808d1c818d1c1c8002808e1c9c81901c9c909c1c80029c8d901c9e9d607f198f0160401b60c09190911c6001603f1b161760c19b909b1c6001603e1b169a909a1760c29990991c6001603d1b169890981760c39790971c6001603c1b169690961760c49590951c6001603b1b169490941760c59390931c6001603a1b169290921760c69190911c600160391b161760c79190911c600160381b161760c89190911c600160371b161760c99190911c600160361b161760ca9190911c600160351b161760cb9190911c600160341b161760cc9190911c600160331b161760cd9190911c600160321b1617693627a301d71055774c8581026f028f6481ab7f045a5af012a19d003aa9198101608090811d906fdb2df09e81959a81455e260799a0632f8301901d600281810b9083900b1461407a57886001600160a01b031661405e8261435f565b6001600160a01b031611156140735781614075565b805b61407c565b815b9998505050505050505050565b60408051630eea437960e11b815261ffff8716600482015263ffffffff86166024820152600285900b60448201526001600160801b0380851660648301528316608482015290516000916001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691631dd486f29160a48082019260209290919082900301818787803b15801561412557600080fd5b505af1158015614139573d6000803e3d6000fd5b505050506040513d602081101561414f57600080fd5b505190505b95945050505050565b6040805163c53a182f60e01b815263ffffffff86166004820152600285900b602482015261ffff841660448201526001600160801b038316606482015290516000916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163c53a182f91608480820192602092909190829003018186803b1580156141f057600080fd5b505afa158015614204573d6000803e3d6000fd5b505050506040513d602081101561421a57600080fd5b50516040805161ffff8316815290519192507f598b9f043c813aa6be3426ca60d1c65d17256312890be5118dab55b0775ebe2a919081900360200190a1949350505050565b6000806000603c9050808507151960008612168186050394505082156142f657600884901c600181810b900b60009081526020879052604090205460ff868116918282039091161b80156142d7576142b681614f0e565b60ff0360ff16870396506142c987614f51565b600194509450505050614357565b8160ff16870396506142e887614f51565b600094509450505050614357565b6001938401600881901c80860b90950b60009081526020879052604090205490949060ff861690811c801561434357614333818260000316614f89565b60ff16870196506142c987614f51565b8160ff0360ff16870196506142e887614f51565b935093915050565b6000600282810b60171d90818418829003900b620d89e88111156143ae576040805162461bcd60e51b81526020600482015260016024820152601560fa1b604482015290519081900360640190fd5b6000600182166143c257600160801b6143d4565b6ffffcb933bd6fad37aa2d162d1a5940015b6001600160881b0316905060028216156143fe576ffff97272373d413259a46990580e213a0260801c5b600482161561441d576ffff2e50f5f656932ef12357cf3c7fdcc0260801c5b600882161561443c576fffe5caca7e10e4e61c3624eaa0941cd00260801c5b601082161561445b576fffcb9843d60f6159c9db58835c9266440260801c5b602082161561447a576fff973b41fa98c081472e6896dfb254c00260801c5b6040821615614499576fff2ea16466c96a3843ec78b326b528610260801c5b60808216156144b8576ffe5dee046a99a2a811c461f1969c30530260801c5b6101008216156144d8576ffcbe86c7900a88aedcffc83b479aa3a40260801c5b6102008216156144f8576ff987a7253ac413176f2b074cf7815e540260801c5b610400821615614518576ff3392b0822b70005940c7a398e4b70f30260801c5b610800821615614538576fe7159475a2c29b7443b29c7fa6e889d90260801c5b611000821615614558576fd097f3bdfd2022b8845ad8f792aa58250260801c5b612000821615614578576fa9f746462d870fdf8a65dc1f90e061e50260801c5b614000821615614598576f70d869a156d2a1b890bb3df62baf32f70260801c5b6180008216156145b8576f31be135f97d08fd981231505542fcfa60260801c5b620100008216156145d9576f09aa508b5b7a84e1c677de54f3e99bc90260801c5b620200008216156145f9576e5d6af8dedb81196699c329225ee6040260801c5b62040000821615614618576d2216e584f5fa1ea926041bedfe980260801c5b62080000821615614635576b048a170391f7dc42444e8fa20260801c5b60008560020b131561465057806000198161464c57fe5b0490505b600160201b810615614663576001614666565b60005b60ff16602082901c019350505050919050565b6000806000806154db8a61468f5761509d614693565b6150ac5b90506000871261477f5760006146bb888861ffff16620f42400362ffffff16620f424061382a565b90506146cc8a8c8b8563ffffffff16565b94508481106146f9578995506146f28561ffff891662ffffff620f4240829003166137b5565b9250614758565b6147058b8a838f6150bb565b9550856001600160a01b03168a6001600160a01b03161461473b5761472f868c8b8563ffffffff16565b94508488039250614758565b6147558561ffff891662ffffff620f4240829003166137b5565b92505b614777868c8b8f61476b576150cb61476f565b6150da5b63ffffffff16565b93505061482f565b6154db8b61478f576150cb614793565b6150da5b90506147a48a8c8b8463ffffffff16565b93508760000397508388106147bb57899550614800565b6147c78b8a8a8f6150e9565b9550856001600160a01b03168a6001600160a01b0316146147f4576147f1868c8b8463ffffffff16565b93505b87841115614800578793505b61480f868c8b8563ffffffff16565b945061482b8561ffff891662ffffff620f4240829003166137b5565b9250505b509650965096509692505050565b6000600160ff1b821061484f57600080fd5b5090565b818101828112156000831215146136a757600080fd5b60008215806148845750508181028183828161488157fe5b04145b6136a757600080fd5b600286810b810b60009081526020899052604090206003810180546001600160a01b03600160381b63ffffffff600160d81b808504821689039091160263ffffffff60d81b199093169290921782810482168903909116909102600160381b600160d81b031990911617600681810b8703900b66ffffffffffffff1666ffffffffffffff199091161790559081018054860390556001810180548703905554600160801b9004600f0b979650505050505050565b60008082600f0b12156149a657826001600160801b03168260000384039150816001600160801b0316106149a1576040805162461bcd60e51b81526020600482015260026024820152614c5360f01b604482015290519081900360640190fd5b6136a7565b826001600160801b03168284019150816001600160801b031610156136a7576040805162461bcd60e51b81526020600482015260026024820152614c4160f01b604482015290519081900360640190fd5b600289810b900b600090815260208b9052604081208054600160801b8104600f0b906001600160801b031683614a2d828d614941565b90506e023746e6a58dcb13d4af821b93f0636001600160801b03821610614a80576040805162461bcd60e51b81526020600482015260026024820152614c4f60f01b604482015290519081900360640190fd5b85614aa357614a9e614a99600f85810b908f900b614853565b6139fe565b614ab7565b614ab7614a99600f85810b908f900b6138f4565b84546001600160801b03838116600f9390930b8116600160801b02918116919091176001600160801b03191682178655901595508216614b8057841594508c60020b8e60020b13614b6857600184018b9055600284018a9055600384018054600160381b600160d81b031916600160381b6001600160a01b038c16021766ffffffffffffff191666ffffffffffffff60068b900b161763ffffffff60d81b1916600160d81b63ffffffff8a16021790555b6003840180546001600160f81b0316600160f81b1790555b505050509a9950505050505050505050565b603c600282900b0760020b15614be4576040805162461bcd60e51b81526020600482015260126024820152711d1a58dac81a5cc81b9bdd081cdc1858d95960721b604482015290519081900360640190fd5b603c60029190910b05600881901c600190810b810b60009081526020939093526040909220805460ff9092169290921b189055565b600285810b810b60009081526020889052604080822087840b80850b84529183209293849391929088900b1215614c93578860020b8760020b12614c6e57816001015486039350816002015485039250614c7d565b81600101549350816002015492505b6001810154600282015494039390920391614cae565b81600101548160010154039350816002015481600201540392505b5050965096945050505050565b83546001600160801b03811690600160801b900463ffffffff16600f85900b614d26576000826001600160801b031611614d21576040805162461bcd60e51b815260206004820152600260248201526104e560f41b604482015290519081900360640190fd5b614ddf565b600085600f0b1215614d655760045463ffffffff168015614d63578063ffffffff1682614d5161390a565b0363ffffffff161015614d6357600080fd5b505b6000614d718387614941565b9050806000826001600160801b031611614d8c576000614da5565b600087600f0b13614d9d5782614da5565b614da561390a565b88546001600160801b039092166001600160801b031963ffffffff909216600160801b0263ffffffff60801b199093169290921716178755505b600186015460028701546000868314614e165760018901879055614e138388036001600160801b038716600160801b61382a565b90505b6000828714614e435760028a01879055614e408388036001600160801b038816600160801b61382a565b90505b6001600160801b038282171615614e8d5760038a0180546001600160801b031981166001600160801b039182168501821617808216600160801b9182900483168501909216021790555b50505050505050505050565b60008082600f0b1215614ec657614ebe614eb985858560000360006150f9565b61483d565b600003614ed6565b614ed6614eb985858560016150f9565b949350505050565b60008082600f0b1215614efe57614ebe614eb98585856000036000615188565b614ed6614eb98585856001615188565b600181811c909117600281901c17600481901c17600881901c17601081901c17602081901c17604081901c17608081901c179081901c900360006136a782614f89565b603c8102620d89e719600282900b1215614f705750620d89e719613a0f565b620d89e8600282900b1315613a0f5750620d89e8919050565b7f55555555555555555555555555555555555555555555555555555555555555558116156001600160801b0382161560071b176001600160401b03600160801b03600160c01b0382161560061b177bffffffff00000000ffffffff00000000ffffffff00000000ffffffff82161560051b177dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff82161560041b177eff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff82161560031b177f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f82161560021b177f3333333333333333333333333333333333333333333333333333333333333333919091161560011b1790565b6000614ed68385846001615188565b6000614ed684848460016150f9565b60006141548585858560016151f9565b6000614ed683858460006150f9565b6000614ed68484846000615188565b60006141548585858560006151f9565b60006001600160a01b038585038116908516811061511657600080fd5b600160601b600160e01b03606085901b168361515757866001600160a01b031661514a8383896001600160a01b031661382a565b8161515157fe5b0461517d565b61517d61516e8383896001600160a01b03166137b5565b886001600160a01b03166153ed565b979650505050505050565b6000846001600160a01b0316846001600160a01b031610156151a957600080fd5b6001600160a01b0385850316826151d7576151d281856001600160801b0316600160601b61382a565b6151ef565b6151ef81856001600160801b0316600160601b6137b5565b9695505050505050565b600080866001600160a01b03161161521057600080fd5b6000856001600160801b03161161522657600080fd5b8115158315151415615318578361523e575084614154565b600160601b600160e01b03606086901b1682156152cc576001600160a01b0387168581029086828161526c57fe5b04141561529d5781810182811061529b57615291838a6001600160a01b0316836137b5565b9350505050614154565b505b6152c3826152be888b6001600160a01b031686816152b757fe5b0490613697565b6153ed565b92505050614154565b6001600160a01b038716858102908682816152e357fe5b04146152ee57600080fd5b8082116152fa57600080fd5b6152c3615313838a6001600160a01b03168486036137b5565b6153f8565b811561537f576153786153136001600160a01b038611156153505761534b86600160601b896001600160801b031661382a565b615368565b6001600160801b038716606087901b8161536657fe5b045b6001600160a01b03891690613697565b9050614154565b60006001600160a01b038511156153ad576153a885600160601b886001600160801b03166137b5565b6153c4565b6153c4606086901b6001600160801b0388166153ed565b905080876001600160a01b0316116153db57600080fd5b6001600160a01b038716039050614154565b808204910615150190565b806001600160a01b0381168114613a0f57600080fd5b604080516060810182526000808252602082018190529181019190915290565b604080516101c081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052906101208201908152600060208201819052604082018190526060820181905260809091015290565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565bfefec42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67a164736f6c6343000706000aa164736f6c6343000706000a
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100415760003560e01c80635bb4780814610046578063890357301461006e578063fd82b73a146100aa575b600080fd5b61006c6004803603602081101561005c57600080fd5b50356001600160a01b0316610104565b005b61007661019a565b604080516001600160a01b039586168152938516602085015291841683830152909216606082015290519081900360800190f35b6100e8600480360360808110156100c057600080fd5b506001600160a01b0381358116916020810135821691604082013581169160600135166101be565b604080516001600160a01b039092168252519081900360200190f35b6005546001600160a01b0316331461011b57600080fd5b6001600160a01b03811661012e57600080fd5b6004546001600160a01b03161561014457600080fd5b6040516001600160a01b038216907f194d5292f3fd797c05e95926ce4b1d4d7f7f10c7dd0c467e55a42d82006bbc6990600090a2600480546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001546002546003546001600160a01b039384169392831692918216911684565b6004546000906001600160a01b031633146101d857600080fd5b604080516080810182526001600160a01b0380881680835287821660208085018290528884168587018190529388166060958601819052600080546001600160a01b03199081169095179055600180548516909317909255600280548416851790556003805490931682179092558451808301939093528285015283518083038501815291909201928390528051910120906102739061029d565b8190604051809103906000f5905080158015610293573d6000803e3d6000fd5b5095945050505050565b6156b2806102ab8339019056fe6101006040523480156200001257600080fd5b5033806001600160a01b031663890357306040518163ffffffff1660e01b815260040160806040518083038186803b1580156200004e57600080fd5b505afa15801562000063573d6000803e3d6000fd5b505050506040513d60808110156200007a57600080fd5b508051602082015160408301516060938401516001600160601b031990851b811660e05290841b811660c05290831b811660a052911b166080525060028054601960ba1b61ffff60b81b1990911617905560805160601c60a05160601c60c05160601c60e05160601c61550a620001a860003980610a4a5280610b885280610ec15280611150528061136b52806115f252806116a052806116da52806127bf52806128bd52806136b15250806109f15280610aea5280610bae5280610e6f528061108752806113285280611628528061166a528061278a528061355b525080610c6c5280610f8552806118b652806119e452806128825280613720525080610d8052806117875280611d905280612a005280613332528061396852806140dd52806141a9525061550a6000f3fe608060405234801561001057600080fd5b50600436106101545760003560e01c80630dfe168114610159578063128acb081461017d57806317e25b3c1461022a5780631a6865021461024b578063289fe9b01461026f57806329047dfa14610294578063490e6cbc1461029c5780634f1eb3d814610326578063514ea4bf146103a65780636378ae441461040b57806370cf754a14610425578063713346941461042d57806374eceae6146104ca5780637c0112b7146105465780637c1fe0c81461056e578063920c34e5146105945780639d3a5241146105ef578063a34123a714610780578063aafe29c0146107ba578063c45a01551461088c578063c677e3e014610894578063d0c93a7c146108b4578063d21220a7146108d3578063e76c01e4146108db578063ecdecf4214610937578063f30dba931461093f578063f637731d146109c1578063facb0eb1146109e7575b600080fd5b6101616109ef565b604080516001600160a01b039092168252519081900360200190f35b610211600480360360a081101561019357600080fd5b6001600160a01b0382358116926020810135151592604082013592606083013516919081019060a081016080820135600160201b8111156101d357600080fd5b8201836020820111156101e557600080fd5b803590602001918460018302840111600160201b8311171561020657600080fd5b509092509050610a13565b6040805192835260208301919091528051918290030190f35b610232610c4f565b6040805163ffffffff9092168252519081900360200190f35b610253610c5b565b604080516001600160801b039092168252519081900360200190f35b6102926004803603602081101561028557600080fd5b503563ffffffff16610c6a565b005b610161610d7e565b610292600480360360808110156102b257600080fd5b6001600160a01b038235169160208101359160408201359190810190608081016060820135600160201b8111156102e857600080fd5b8201836020820111156102fa57600080fd5b803590602001918460018302840111600160201b8311171561031b57600080fd5b509092509050610da2565b610377600480360360a081101561033c57600080fd5b506001600160a01b03813516906020810135600290810b91604081013590910b906001600160801b0360608201358116916080013516611222565b60405180836001600160801b03168152602001826001600160801b031681526020019250505060405180910390f35b6103c3600480360360208110156103bc57600080fd5b503561141c565b604080516001600160801b03978816815263ffffffff90961660208701528581019490945260608501929092528416608084015290921660a082015290519081900360c00190f35b610413611465565b60408051918252519081900360200190f35b61025361146b565b610211600480360360c081101561044357600080fd5b6001600160a01b0382358116926020810135821692604082013515159260608301359260808101359091169181019060c0810160a0820135600160201b81111561048c57600080fd5b82018360208201111561049e57600080fd5b803590602001918460018302840111600160201b831117156104bf57600080fd5b50909250905061147e565b6104e7600480360360208110156104e057600080fd5b503561177a565b60408051971515885263ffffffff909616602088015260069490940b868601526001600160a01b0390921660608601526001600160581b0316608085015260020b60a08401526001600160901b031660c0830152519081900360e00190f35b6102926004803603604081101561055c57600080fd5b5060ff8135811691602001351661184b565b6102926004803603602081101561058457600080fd5b50356001600160a01b03166119e2565b6105be600480360360408110156105aa57600080fd5b508035600290810b9160200135900b611ad1565b6040805160069490940b84526001600160a01b03909216602084015263ffffffff1682820152519081900360600190f35b61065d6004803603602081101561060557600080fd5b810190602081018135600160201b81111561061f57600080fd5b82018360208201111561063157600080fd5b803590602001918460208302840111600160201b8311171561065257600080fd5b509092509050611d88565b6040518080602001806020018060200180602001858103855289818151815260200191508051906020019060200280838360005b838110156106a9578181015183820152602001610691565b50505050905001858103845288818151815260200191508051906020019060200280838360005b838110156106e85781810151838201526020016106d0565b50505050905001858103835287818151815260200191508051906020019060200280838360005b8381101561072757818101518382015260200161070f565b50505050905001858103825286818151815260200191508051906020019060200280838360005b8381101561076657818101518382015260200161074e565b505050509050019850505050505050505060405180910390f35b6102116004803603606081101561079657600080fd5b508035600290810b91602081013590910b90604001356001600160801b03166120ed565b610865600480360360c08110156107d057600080fd5b6001600160a01b0382358116926020810135909116916040820135600290810b92606081013590910b916001600160801b03608083013516919081019060c0810160a0820135600160201b81111561082757600080fd5b82018360208201111561083957600080fd5b803590602001918460018302840111600160201b8311171561085a57600080fd5b509092509050612329565b6040805193845260208401929092526001600160801b031682820152519081900360600190f35b610161612880565b610413600480360360208110156108aa57600080fd5b503560010b6128a4565b6108bc6128b6565b6040805160029290920b8252519081900360200190f35b6101616128bb565b6108e36128df565b604080516001600160a01b03909816885260029690960b602088015261ffff9485168787015292909316606086015260ff90811660808601529190911660a0840152151560c0830152519081900360e00190f35b610413612932565b61095f6004803603602081101561095557600080fd5b503560020b612938565b604080516001600160801b039099168952600f9790970b602089015287870195909552606087019390935260069190910b60808601526001600160a01b031660a085015263ffffffff1660c0840152151560e083015251908190036101000190f35b610292600480360360208110156109d757600080fd5b50356001600160a01b03166129a2565b610161612b13565b7f000000000000000000000000000000000000000000000000000000000000000081565b600080600080600080610a278b8b8b612b29565b949a509298509096509450925090508a15610adc576000851215610a7357610a737f00000000000000000000000000000000000000000000000000000000000000008d87600003613409565b6000610a7d613557565b9050610a8b87878b8b6135f7565b610a93613557565b610a9d8289613697565b1115610ad6576040805162461bcd60e51b815260206004820152600360248201526249494160e81b604482015290519081900360640190fd5b50610b78565b6000861215610b1357610b137f00000000000000000000000000000000000000000000000000000000000000008d88600003613409565b6000610b1d6136ad565b9050610b2b87878b8b6135f7565b610b336136ad565b610b3d8288613697565b1115610b76576040805162461bcd60e51b815260206004820152600360248201526249494160e81b604482015290519081900360640190fd5b505b8015610bd457610bd48b610bac577f0000000000000000000000000000000000000000000000000000000000000000610bce565b7f00000000000000000000000000000000000000000000000000000000000000005b8261371c565b60408051878152602081018790526001600160a01b03868116828401526001600160801b0385166060830152600286900b60808301529151918e169133916000805160206154de833981519152919081900360a00190a350506002805460ff60e81b1916600160e81b17905550919890975095505050505050565b60045463ffffffff1681565b6003546001600160801b031681565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610cc357600080fd5b505afa158015610cd7573d6000803e3d6000fd5b505050506040513d6020811015610ced57600080fd5b50516001600160a01b03163314610d0357600080fd5b6201518063ffffffff821611801590610d27575060045463ffffffff828116911614155b610d3057600080fd5b6004805463ffffffff831663ffffffff19909116811790915560408051918252517fb5e51602371b0e74f991b6e965cd7d32b4b14c7e6ede6d1298037650a0e1405f9181900360200190a150565b7f000000000000000000000000000000000000000000000000000000000000000081565b600254600160e81b900460ff16610de6576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6002805460ff60e81b191690556003546001600160801b031680610e35576040805162461bcd60e51b81526020600482015260016024820152601360fa1b604482015290519081900360640190fd5b600254600160b81b900461ffff16600080610e4e613557565b90508715610e9557610e68888461ffff16620f42406137b5565b9150610e957f00000000000000000000000000000000000000000000000000000000000000008a8a613409565b600080610ea06136ad565b90508815610ee757610eba898661ffff16620f42406137b5565b9150610ee77f00000000000000000000000000000000000000000000000000000000000000008c8b613409565b336001600160a01b031663a60b0d3c85848b8b6040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b158015610f6957600080fd5b505af1158015610f7d573d6000803e3d6000fd5b5050505060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663430bf08a6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fdc57600080fd5b505afa158015610ff0573d6000803e3d6000fd5b505050506040513d602081101561100657600080fd5b505190506000611014613557565b9050806110218688613697565b1115611059576040805162461bcd60e51b8152602060048201526002602482015261046360f41b604482015290519081900360640190fd5b84900380156110d357600254600160d81b900460ff16600081156110ad57506103e860ff82168302046110ad7f00000000000000000000000000000000000000000000000000000000000000008583613409565b6110c7818403600160801b8c6001600160801b031661382a565b60008054909101905550505b60006110dd6136ad565b9050806110ea8587613697565b1115611122576040805162461bcd60e51b8152602060048201526002602482015261463160f01b604482015290519081900360640190fd5b839003801561119c57600254600160e01b900460ff166000811561117657506103e860ff82168302046111767f00000000000000000000000000000000000000000000000000000000000000008683613409565b611190818403600160801b8d6001600160801b031661382a565b60018054909101905550505b8d6001600160a01b0316336001600160a01b03167fbdbdb71d7860376ba52b25a5028beea23581364a40522f6bcfb86bb1f2dca6338f8f86866040518085815260200184815260200183815260200182815260200194505050505060405180910390a350506002805460ff60e81b1916600160e81b179055505050505050505050505050565b6002546000908190600160e81b900460ff1661126b576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6002805460ff60e81b1916905560006112853388886138c0565b60038101549091506001600160801b0380821691600160801b9004811690871682106112b157866112b3565b815b9450806001600160801b0316866001600160801b0316116112d457856112d6565b805b93506001600160801b03858517161561139a576003830180546001600160801b0319168684036001600160801b03908116919091178116600160801b87850383160217909155851615611357576113577f00000000000000000000000000000000000000000000000000000000000000008b876001600160801b0316613409565b6001600160801b0384161561139a5761139a7f00000000000000000000000000000000000000000000000000000000000000008b866001600160801b0316613409565b604080516001600160a01b038c1681526001600160801b038088166020830152861681830152905160028a810b92908c900b9133917f70935338e69775456a85ddef226c395fb668b63fa0115f5f20610b388e6ca9c0919081900360600190a450506002805460ff60e81b1916600160e81b1790555090969095509350505050565b60076020526000908152604090208054600182015460028301546003909301546001600160801b038084169463ffffffff600160801b9586900416949092808316929190041686565b60005481565b6e023746e6a58dcb13d4af821b93f06290565b6002546000908190600160e81b900460ff166114c7576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6002805460ff60e81b1916905586156115485760006114e4613557565b90506114f387600087876135f7565b600061150782611501613557565b906138e4565b97508713611542576040805162461bcd60e51b815260206004820152600360248201526249494160e81b604482015290519081900360640190fd5b506115ac565b60006115526136ad565b905061156160008887876135f7565b600061156f826115016136ad565b975087136115aa576040805162461bcd60e51b815260206004820152600360248201526249494160e81b604482015290519081900360640190fd5b505b6002805460ff60e81b1916600160e81b17905560008080806115cf8b8b8b612b29565b949a509298509096509450925090508a1561165c57600085121561161b5761161b7f00000000000000000000000000000000000000000000000000000000000000008d87600003613409565b89861215611657576116577f00000000000000000000000000000000000000000000000000000000000000008e6116528d8a6138f4565b613409565b6116ca565b6000861215611693576116937f00000000000000000000000000000000000000000000000000000000000000008d88600003613409565b898512156116ca576116ca7f00000000000000000000000000000000000000000000000000000000000000008e6116528d896138f4565b80156116fe576116fe8b610bac577f0000000000000000000000000000000000000000000000000000000000000000610bce565b60408051878152602081018790526001600160a01b03868116828401526001600160801b0385166060830152600286900b60808301529151918e169133916000805160206154de833981519152919081900360a00190a350506002805460ff60e81b1916600160e81b1790555091999098509650505050505050565b60008060008060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166374eceae6896040518263ffffffff1660e01b81526004018082815260200191505060e06040518083038186803b1580156117e957600080fd5b505afa1580156117fd573d6000803e3d6000fd5b505050506040513d60e081101561181357600080fd5b508051602082015160408301516060840151608085015160a086015160c090960151949e939d50919b50995097509195509350915050565b600254600160e81b900460ff1661188f576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6002805460ff60e81b1916905560408051638da5cb5b60e01b815290516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691638da5cb5b916004808301926020929190829003018186803b1580156118fc57600080fd5b505afa158015611910573d6000803e3d6000fd5b505050506040513d602081101561192657600080fd5b50516001600160a01b0316331461193c57600080fd5b60fa60ff831611801590611954575060fa60ff821611155b61195d57600080fd5b6002805460ff60e01b1916600160e01b60ff8481169182029290921760ff60d81b1916600160d81b9286169283021790925560408051918252602082019290925281517f9e22b964b08e25c3aaa72102bb0071c089258fb82d51271a8ddf5c24921356ee929181900390910190a150506002805460ff60e81b1916600160e81b179055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638a2ade586040518163ffffffff1660e01b815260040160206040518083038186803b158015611a3b57600080fd5b505afa158015611a4f573d6000803e3d6000fd5b505050506040513d6020811015611a6557600080fd5b50516001600160a01b03163314611a7b57600080fd5b60048054600160201b600160c01b031916600160201b6001600160a01b038416908102919091179091556040517f915c5369e6580733735d1c2e30ca20dcaa395697a041033c9f35f80f53525e8490600090a250565b600080808484620d89e9600282900b12611b18576040805162461bcd60e51b815260206004820152600360248201526254554d60e81b604482015290519081900360640190fd5b8160020b8160020b13611b58576040805162461bcd60e51b8152602060048201526003602482015262544c5560e81b604482015290519081900360640190fd5b620d89e819600283900b13611b9a576040805162461bcd60e51b8152602060048201526003602482015262544c4d60e81b604482015290519081900360640190fd5b611ba261540e565b600288810b900b6000908152600560209081526040918290206003810154600160d81b810463ffffffff1693850193909352600160381b83046001600160a01b031691840191909152600682810b810b900b835290600160f81b900460ff16611c0a57600080fd5b50611c1361540e565b600288810b900b6000908152600560209081526040918290206003810154600160d81b810463ffffffff1693850193909352600160381b83046001600160a01b031691840191909152600682810b810b900b835290600160f81b900460ff16611c7b57600080fd5b5060028054600160a01b8104820b91600160c81b90910461ffff16908b810b9083900b1215611cd45782600001518460000151038360200151856020015103846040015186604001510398509850985050505050611d7f565b8960020b8260020b1215611d53576000611cec61390a565b9050600080611d148360008787600360009054906101000a90046001600160801b031661390e565b5050915091508560000151876000015183030386602001518860200151830303876040015189604001518603039b509b509b5050505050505050611d7f565b836000015183600001510384602001518460200151038560400151856040015103985098509850505050505b50509250925092565b6060806060807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fd31e988611dc561390a565b6002805460035460405160e086901b6001600160e01b031916815263ffffffff851660048201908152600160a01b8404850b9485900b6044830152600160c81b90930461ffff16606482018190526001600160801b039092166084820181905260a06024830190815260a483018e90528e958e9590949390919060c401876020880280828437600081840152601f19601f82011690508083019250505097505050505050505060006040518083038186803b158015611e8357600080fd5b505afa158015611e97573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526080811015611ec057600080fd5b8101908080516040519392919084600160201b821115611edf57600080fd5b908301906020820185811115611ef457600080fd5b82518660208202830111600160201b82111715611f1057600080fd5b82525081516020918201928201910280838360005b83811015611f3d578181015183820152602001611f25565b5050505090500160405260200180516040519392919084600160201b821115611f6557600080fd5b908301906020820185811115611f7a57600080fd5b82518660208202830111600160201b82111715611f9657600080fd5b82525081516020918201928201910280838360005b83811015611fc3578181015183820152602001611fab565b5050505090500160405260200180516040519392919084600160201b821115611feb57600080fd5b90830190602082018581111561200057600080fd5b82518660208202830111600160201b8211171561201c57600080fd5b82525081516020918201928201910280838360005b83811015612049578181015183820152602001612031565b5050505090500160405260200180516040519392919084600160201b82111561207157600080fd5b90830190602082018581111561208657600080fd5b82518660208202830111600160201b821117156120a257600080fd5b82525081516020918201928201910280838360005b838110156120cf5781810151838201526020016120b7565b50505050905001604052505050935093509350935092959194509250565b6002546000908190600160e81b900460ff16612136576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6002805460ff60e81b1916815585908590620d89e99082900b12612187576040805162461bcd60e51b815260206004820152600360248201526254554d60e81b604482015290519081900360640190fd5b8160020b8160020b136121c7576040805162461bcd60e51b8152602060048201526003602482015262544c5560e81b604482015290519081900360640190fd5b620d89e819600283900b13612209576040805162461bcd60e51b8152602060048201526003602482015262544c4d60e81b604482015290519081900360640190fd5b600080600061222e338b8b6122268c6001600160801b03166139fe565b600003613a14565b9250925092508160000396508060000395508587176000146122af576003830154612262906001600160801b031688613cea565b600384015461228190600160801b90046001600160801b031688613cea565b6003850180546001600160801b03938416928416600160801b029316929092176001600160801b0319161790555b604080516001600160801b038a16815260208101899052808201889052905160028b810b92908d900b9133917f0c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c919081900360600190a450506002805460ff60e81b1916600160e81b179055509296919550909350505050565b60025460009081908190600160e81b900460ff16612374576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6002805460ff60e81b1916815588908890620d89e99082900b126123c5576040805162461bcd60e51b815260206004820152600360248201526254554d60e81b604482015290519081900360640190fd5b8160020b8160020b13612405576040805162461bcd60e51b8152602060048201526003602482015262544c5560e81b604482015290519081900360640190fd5b620d89e819600283900b13612447576040805162461bcd60e51b8152602060048201526003602482015262544c4d60e81b604482015290519081900360640190fd5b6000886001600160801b03161161248a576040805162461bcd60e51b8152602060048201526002602482015261125360f21b604482015290519081900360640190fd5b6000806124c18c8c6124a48d6001600160801b03166139fe565b60028054600160a01b810490910b906001600160a01b0316613d06565b5090975095506000915081905086156124df576124dc613557565b91505b85156124f0576124ed6136ad565b90505b336001600160a01b0316633dd657c588888c8c6040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b15801561257257600080fd5b505af1158015612586573d6000803e3d6000fd5b5050505060008711156125dd5760008261259e613557565b03925082116125dd576040805162461bcd60e51b815260206004808301919091526024820152634949414d60e01b604482015290519081900360640190fd5b851561262d576000816125ee6136ad565b039150811161262d576040805162461bcd60e51b815260206004808301919091526024820152634949414d60e01b604482015290519081900360640190fd5b8994508682101561264f5761264c856001600160801b0316838961382a565b94505b8581101561268f57600061266d866001600160801b0316838961382a565b9050856001600160801b0316816001600160801b0316101561268d578095505b505b6000856001600160801b0316116126d6576040805162461bcd60e51b8152602060048083019190915260248201526324a4a61960e11b604482015290519081900360640190fd5b6000806126f68f8f8f6126f18b6001600160801b03166139fe565b613a14565b92509250508382995089111561273b576040805162461bcd60e51b815260206004820152600560248201526424a4a0a69960d91b604482015290519081900360640190fd5b8281985088111561277b576040805162461bcd60e51b815260206004820152600560248201526424a4a0a69960d91b604482015290519081900360640190fd5b5050868211156127b2576127b27f00000000000000000000000000000000000000000000000000000000000000008f898503613409565b858111156127e7576127e77f00000000000000000000000000000000000000000000000000000000000000008f888403613409565b8a60020b8c60020b8e6001600160a01b03167f7a53080ba414158be7ec69b987b5fb7d07dee101fe85488f0853ae16239d0bde33898c8c60405180856001600160a01b03168152602001846001600160801b0316815260200183815260200182815260200194505050505060405180910390a450506002805460ff60e81b1916600160e81b17905550929a919950975095505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60066020526000908152604090205481565b603c90565b7f000000000000000000000000000000000000000000000000000000000000000081565b600280546001600160a01b03811691600160a01b8204900b9061ffff600160b81b8204811691600160c81b81049091169060ff600160d81b8204811691600160e01b8104821691600160e81b9091041687565b60015481565b60056020526000908152604090208054600182015460028301546003909301546001600160801b03831693600160801b909304600f0b9290600681900b90600160381b81046001600160a01b031690600160d81b810463ffffffff1690600160f81b900460ff1688565b6002546001600160a01b0316156129e5576040805162461bcd60e51b8152602060048201526002602482015261414960f01b604482015290519081900360640190fd5b60006129f082613d9e565b905060006129fc61390a565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663475fb80c82846040518363ffffffff1660e01b8152600401808363ffffffff1681526020018260020b815260200192505050600060405180830381600087803b158015612a7557600080fd5b505af1158015612a89573d6000803e3d6000fd5b50506002805485820b62ffffff8116600160a01b0262ffffff60a01b1960ff60e81b196001600160a01b038b166001600160a01b0319909516851716600160e81b17161790925560408051918252602082019290925281517f98636036cb66a9c19a37435efc1e90142190214e8abeb821bdba3f2990dd4c959450908190039091019150a1505050565b600454600160201b90046001600160a01b031681565b6000806000806000806000612b3c61542e565b6002805461ffff600160b81b82048116610160850152600160c81b8204166101a084015260ff60e81b19811682556001600160a01b0381169750600160a01b810490910b955060ff600160d81b8204811691600160e01b8104821691600160e81b9091041680612bd9576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b8c612c10576040805162461bcd60e51b8152602060048201526002602482015261415360f01b604482015290519081900360640190fd5b60008d1361014085015260a084018d90526003546001600160801b03600160801b8204811660208701521696508d15612cb857886001600160a01b03168c6001600160a01b0316108015612c7157506401000276a36001600160a01b038d16115b612ca8576040805162461bcd60e51b815260206004820152600360248201526214d41360ea1b604482015290519081900360640190fd5b60005460e0850152828452612d38565b886001600160a01b03168c6001600160a01b0316118015612cf5575073fffd8963efd1fc6a506488495d951d5263988d266001600160a01b038d16105b612d2c576040805162461bcd60e51b815260206004820152600360248201526214d41360ea1b604482015290519081900360640190fd5b60015460e08501528184525b600288810b900b610180850152612d4d61390a565b600454909550600160201b90046001600160a01b031615612e6357600060048054906101000a90046001600160a01b03166001600160a01b0316637f376059876040518263ffffffff1660e01b8152600401808263ffffffff168152602001915050602060405180830381600087803b158015612dc957600080fd5b505af1158015612ddd573d6000803e3d6000fd5b505050506040513d6020811015612df357600080fd5b505190506000816002811115612e0557fe5b1415612e235760048054600160201b600160c01b0319169055612e61565b6001816002811115612e3157fe5b1415612e44576001610120860152612e61565b6002816002811115612e5257fe5b1415612e615760026101208601525b505b6000612e80856101a00151878761018001518b8960200151614089565b9050846101a0015161ffff168161ffff1614612ebf5761ffff81166101a086015260006020860152612eb4868a838b61415d565b61ffff166101608601525b50505050612ecb61549f565b6001600160a01b0387168152612ee36006878e61425f565b15156040830152600290810b900b60208201819052612f019061435f565b6001600160a01b0390811660608301819052612f3f918e918a918e161182151514612f30578360600151612f32565b8c5b888f876101600151614679565b60c085015260a0840152608083015261014083015190975015612f9857612f6f8160c0015182608001510161483d565b8b039a50612f8e612f838260a0015161483d565b60c0840151906138f4565b60c0830152612fd0565b612fa58160a0015161483d565b8b019a50612fca612fbf8260c0015183608001510161483d565b60c084015190614853565b60c08301525b81511561300c57815160c08201516000916103e891612fee91614869565b81612ff557fe5b60c084018051929091049182900390529490940193505b6001600160801b03851615613043576130378160c00151600160801b876001600160801b031661382a565b60e08301805190910190525b80606001516001600160a01b0316876001600160a01b0316141561320a578060400151156131eb5781608001516130c75761308c836000846101800151856101a001518961390e565b50506001600160a01b03166060840152600690810b900b6040830152600160808301528b6130bc576000546130c0565b6001545b6101008301525b600082610120015160028111156130da57fe5b146131625760048054906101000a90046001600160a01b03166001600160a01b03166301342b1982602001518e6040518363ffffffff1660e01b8152600401808360020b8152602001821515815260200192505050600060405180830381600087803b15801561314957600080fd5b505af115801561315d573d6000803e3d6000fd5b505050505b60008c156131a75761319d82602001518460e001518561010001518660600151876040015189600561488d909695949392919063ffffffff16565b60000390506131dd565b6131da82602001518461010001518560e001518660600151876040015189600561488d909695949392919063ffffffff16565b90505b6131e78682614941565b9550505b8b6131fa578060200151613203565b60018160200151035b955061322e565b80516001600160a01b0388811691161461322e5761322787613d9e565b955061325b565b8a158061324c5750896001600160a01b0316876001600160a01b0316145b156132565761325b565b612ecb565b81610140015115158c15151461327c578160c001518b8360a0015103613289565b8a8260a00151038260c001515b6101608401516101a08501516002805461ffff60c81b1916600160c81b61ffff938416021761ffff60b81b1916600160b81b92909316919091029190911762ffffff60a01b1916600160a01b62ffffff8b840b1602176001600160a01b0319166001600160a01b038b81169190911790915560408051631b7297f760e11b81526001600160801b038a16600482015260248101859052604481018490529051939c50919a5087927f0000000000000000000000000000000000000000000000000000000000000000909116916336e52fee916064808301926020929190829003018186803b15801561337a57600080fd5b505afa15801561338e573d6000803e3d6000fd5b505050506040513d60208110156133a457600080fd5b50516020840151600380546001600160801b03948516929093018416600160801b0293909216929092176001600160801b0319169190911790558b156133f15760e08201516000556133fa565b60e08201516001555b50505093975093979195509350565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b602083106134855780518252601f199092019160209182019101613466565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146134e7576040519150601f19603f3d011682016040523d82523d6000602084013e6134ec565b606091505b509150915081801561351a57508051158061351a575080806020019051602081101561351757600080fd5b50515b613550576040805162461bcd60e51b81526020600482015260026024820152612a2360f11b604482015290519081900360640190fd5b5050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156135c657600080fd5b505afa1580156135da573d6000803e3d6000fd5b505050506040513d60208110156135f057600080fd5b5051905090565b336001600160a01b0316632c8958f6858585856040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b15801561367957600080fd5b505af115801561368d573d6000803e3d6000fd5b5050505050505050565b808201828110156136a757600080fd5b92915050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156135c657600080fd5b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663430bf08a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561377757600080fd5b505afa15801561378b573d6000803e3d6000fd5b505050506040513d60208110156137a157600080fd5b505190506137b0838284613409565b505050565b60008315806137d0575050828202828482816137cd57fe5b04145b156137f157600082116137e257600080fd5b81810490829006151501613823565b6137fc84848461382a565b90506000828061380857fe5b848609111561382357600019811061381f57600080fd5b6001015b9392505050565b6000838302816000198587098281108382030391505080841161384c57600080fd5b8061385c57508290049050613823565b8385870960008581038616958690049560026003880281188089028203028089028203028089028203028089028203028089028203028089029091030291819003819004600101858411909403939093029190930391909104170290509392505050565b62ffffff9081169116601892831b1790911b17600090815260076020526040902090565b808203828111156136a757600080fd5b808203828113156000831215146136a757600080fd5b4290565b604080516314c5407960e01b815263ffffffff808816600483015286166024820152600285900b604482015261ffff841660648201526001600160801b038316608482015290516000918291829182916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916314c540799160a4808301926080929190829003018186803b1580156139ae57600080fd5b505afa1580156139c2573d6000803e3d6000fd5b505050506040513d60808110156139d857600080fd5b50805160208201516040830151606090930151919c909b50919950975095505050505050565b80600f81900b8114613a0f57600080fd5b919050565b60408051606081018252600280546001600160a01b0381168352600160a01b8104820b90910b6020830152600160c81b900461ffff169181019190915260009081908190613a638888886138c0565b60008054600154929650919080600f89900b15613b2a576000613a8461390a565b9050600080613ab48360008a602001518b60400151600360009054906101000a90046001600160801b031661390e565b505091509150613ae38e89602001518e8a8a86888a600060056149f7909998979695949392919063ffffffff16565b15613af75760019450613af760068f614b92565b6020880151613b12906005908f908f8b8b87898b60016149f7565b15613b265760019350613b2660068e614b92565b5050505b60208501516000908190613b46906005908f908f908a8a614c19565b91509150613b568a8c8484614cbb565b8a600f0b600014613cd95760008b600f0b1215613bd1578315613b9f5760028d810b810b6000908152600560205260408120818155600181018290559182018190556003909101555b8215613bd15760028c810b810b6000908152600560205260408120818155600181018290559182018190556003909101555b6000613be88e8e8e8b602001518c60000151613d06565b919b5099509050600f81900b15613cd75760035460408901516001600160801b0390911690600090613c3b90613c1c61390a565b60208d01516003548690600160801b90046001600160801b0316614089565b90508061ffff168a6040015161ffff1614613caa57613c67613c5b61390a565b8b60200151838561415d565b6002805461ffff60b81b1916600160b81b61ffff938416021761ffff60c81b1916600160c81b92841692909202919091179055600380546001600160801b031690555b613cb4828f614941565b600380546001600160801b0319166001600160801b039290921691909117905550505b505b505050505050509450945094915050565b8082016001600160801b0380841690821610156136a757600080fd5b60008060008760020b8560020b1215613d3b57613d34613d258961435f565b613d2e8961435f565b88614e99565b9250613d93565b8660020b8560020b1215613d7557613d5684613d2e8961435f565b9250613d6b613d648961435f565b8588614ede565b9150859050613d93565b613d90613d818961435f565b613d8a8961435f565b88614ede565b91505b955095509592505050565b60006401000276a36001600160a01b03831610801590613dda575073fffd8963efd1fc6a506488495d951d5263988d266001600160a01b038316105b613e0f576040805162461bcd60e51b81526020600482015260016024820152602960f91b604482015290519081900360640190fd5b600160201b600160c01b03602083901b166001600160801b03811160071b81811c6001600160401b03811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c60ff8111600390811b91821c600f811160021b90811c918211600190811b92831c97908811961790941790921717909117171760808110613ea157607f810383901c9150613eab565b80607f0383901b91505b908002607f81811c60ff83811c9190911c800280831c81831c1c800280841c81841c1c800280851c81851c1c800280861c81861c1c800280871c81871c1c800280881c81881c1c800280891c81891c1c8002808a1c818a1c1c8002808b1c818b1c1c8002808c1c818c1c1c8002808d1c818d1c1c8002808e1c9c81901c9c909c1c80029c8d901c9e9d607f198f0160401b60c09190911c6001603f1b161760c19b909b1c6001603e1b169a909a1760c29990991c6001603d1b169890981760c39790971c6001603c1b169690961760c49590951c6001603b1b169490941760c59390931c6001603a1b169290921760c69190911c600160391b161760c79190911c600160381b161760c89190911c600160371b161760c99190911c600160361b161760ca9190911c600160351b161760cb9190911c600160341b161760cc9190911c600160331b161760cd9190911c600160321b1617693627a301d71055774c8581026f028f6481ab7f045a5af012a19d003aa9198101608090811d906fdb2df09e81959a81455e260799a0632f8301901d600281810b9083900b1461407a57886001600160a01b031661405e8261435f565b6001600160a01b031611156140735781614075565b805b61407c565b815b9998505050505050505050565b60408051630eea437960e11b815261ffff8716600482015263ffffffff86166024820152600285900b60448201526001600160801b0380851660648301528316608482015290516000916001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691631dd486f29160a48082019260209290919082900301818787803b15801561412557600080fd5b505af1158015614139573d6000803e3d6000fd5b505050506040513d602081101561414f57600080fd5b505190505b95945050505050565b6040805163c53a182f60e01b815263ffffffff86166004820152600285900b602482015261ffff841660448201526001600160801b038316606482015290516000916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163c53a182f91608480820192602092909190829003018186803b1580156141f057600080fd5b505afa158015614204573d6000803e3d6000fd5b505050506040513d602081101561421a57600080fd5b50516040805161ffff8316815290519192507f598b9f043c813aa6be3426ca60d1c65d17256312890be5118dab55b0775ebe2a919081900360200190a1949350505050565b6000806000603c9050808507151960008612168186050394505082156142f657600884901c600181810b900b60009081526020879052604090205460ff868116918282039091161b80156142d7576142b681614f0e565b60ff0360ff16870396506142c987614f51565b600194509450505050614357565b8160ff16870396506142e887614f51565b600094509450505050614357565b6001938401600881901c80860b90950b60009081526020879052604090205490949060ff861690811c801561434357614333818260000316614f89565b60ff16870196506142c987614f51565b8160ff0360ff16870196506142e887614f51565b935093915050565b6000600282810b60171d90818418829003900b620d89e88111156143ae576040805162461bcd60e51b81526020600482015260016024820152601560fa1b604482015290519081900360640190fd5b6000600182166143c257600160801b6143d4565b6ffffcb933bd6fad37aa2d162d1a5940015b6001600160881b0316905060028216156143fe576ffff97272373d413259a46990580e213a0260801c5b600482161561441d576ffff2e50f5f656932ef12357cf3c7fdcc0260801c5b600882161561443c576fffe5caca7e10e4e61c3624eaa0941cd00260801c5b601082161561445b576fffcb9843d60f6159c9db58835c9266440260801c5b602082161561447a576fff973b41fa98c081472e6896dfb254c00260801c5b6040821615614499576fff2ea16466c96a3843ec78b326b528610260801c5b60808216156144b8576ffe5dee046a99a2a811c461f1969c30530260801c5b6101008216156144d8576ffcbe86c7900a88aedcffc83b479aa3a40260801c5b6102008216156144f8576ff987a7253ac413176f2b074cf7815e540260801c5b610400821615614518576ff3392b0822b70005940c7a398e4b70f30260801c5b610800821615614538576fe7159475a2c29b7443b29c7fa6e889d90260801c5b611000821615614558576fd097f3bdfd2022b8845ad8f792aa58250260801c5b612000821615614578576fa9f746462d870fdf8a65dc1f90e061e50260801c5b614000821615614598576f70d869a156d2a1b890bb3df62baf32f70260801c5b6180008216156145b8576f31be135f97d08fd981231505542fcfa60260801c5b620100008216156145d9576f09aa508b5b7a84e1c677de54f3e99bc90260801c5b620200008216156145f9576e5d6af8dedb81196699c329225ee6040260801c5b62040000821615614618576d2216e584f5fa1ea926041bedfe980260801c5b62080000821615614635576b048a170391f7dc42444e8fa20260801c5b60008560020b131561465057806000198161464c57fe5b0490505b600160201b810615614663576001614666565b60005b60ff16602082901c019350505050919050565b6000806000806154db8a61468f5761509d614693565b6150ac5b90506000871261477f5760006146bb888861ffff16620f42400362ffffff16620f424061382a565b90506146cc8a8c8b8563ffffffff16565b94508481106146f9578995506146f28561ffff891662ffffff620f4240829003166137b5565b9250614758565b6147058b8a838f6150bb565b9550856001600160a01b03168a6001600160a01b03161461473b5761472f868c8b8563ffffffff16565b94508488039250614758565b6147558561ffff891662ffffff620f4240829003166137b5565b92505b614777868c8b8f61476b576150cb61476f565b6150da5b63ffffffff16565b93505061482f565b6154db8b61478f576150cb614793565b6150da5b90506147a48a8c8b8463ffffffff16565b93508760000397508388106147bb57899550614800565b6147c78b8a8a8f6150e9565b9550856001600160a01b03168a6001600160a01b0316146147f4576147f1868c8b8463ffffffff16565b93505b87841115614800578793505b61480f868c8b8563ffffffff16565b945061482b8561ffff891662ffffff620f4240829003166137b5565b9250505b509650965096509692505050565b6000600160ff1b821061484f57600080fd5b5090565b818101828112156000831215146136a757600080fd5b60008215806148845750508181028183828161488157fe5b04145b6136a757600080fd5b600286810b810b60009081526020899052604090206003810180546001600160a01b03600160381b63ffffffff600160d81b808504821689039091160263ffffffff60d81b199093169290921782810482168903909116909102600160381b600160d81b031990911617600681810b8703900b66ffffffffffffff1666ffffffffffffff199091161790559081018054860390556001810180548703905554600160801b9004600f0b979650505050505050565b60008082600f0b12156149a657826001600160801b03168260000384039150816001600160801b0316106149a1576040805162461bcd60e51b81526020600482015260026024820152614c5360f01b604482015290519081900360640190fd5b6136a7565b826001600160801b03168284019150816001600160801b031610156136a7576040805162461bcd60e51b81526020600482015260026024820152614c4160f01b604482015290519081900360640190fd5b600289810b900b600090815260208b9052604081208054600160801b8104600f0b906001600160801b031683614a2d828d614941565b90506e023746e6a58dcb13d4af821b93f0636001600160801b03821610614a80576040805162461bcd60e51b81526020600482015260026024820152614c4f60f01b604482015290519081900360640190fd5b85614aa357614a9e614a99600f85810b908f900b614853565b6139fe565b614ab7565b614ab7614a99600f85810b908f900b6138f4565b84546001600160801b03838116600f9390930b8116600160801b02918116919091176001600160801b03191682178655901595508216614b8057841594508c60020b8e60020b13614b6857600184018b9055600284018a9055600384018054600160381b600160d81b031916600160381b6001600160a01b038c16021766ffffffffffffff191666ffffffffffffff60068b900b161763ffffffff60d81b1916600160d81b63ffffffff8a16021790555b6003840180546001600160f81b0316600160f81b1790555b505050509a9950505050505050505050565b603c600282900b0760020b15614be4576040805162461bcd60e51b81526020600482015260126024820152711d1a58dac81a5cc81b9bdd081cdc1858d95960721b604482015290519081900360640190fd5b603c60029190910b05600881901c600190810b810b60009081526020939093526040909220805460ff9092169290921b189055565b600285810b810b60009081526020889052604080822087840b80850b84529183209293849391929088900b1215614c93578860020b8760020b12614c6e57816001015486039350816002015485039250614c7d565b81600101549350816002015492505b6001810154600282015494039390920391614cae565b81600101548160010154039350816002015481600201540392505b5050965096945050505050565b83546001600160801b03811690600160801b900463ffffffff16600f85900b614d26576000826001600160801b031611614d21576040805162461bcd60e51b815260206004820152600260248201526104e560f41b604482015290519081900360640190fd5b614ddf565b600085600f0b1215614d655760045463ffffffff168015614d63578063ffffffff1682614d5161390a565b0363ffffffff161015614d6357600080fd5b505b6000614d718387614941565b9050806000826001600160801b031611614d8c576000614da5565b600087600f0b13614d9d5782614da5565b614da561390a565b88546001600160801b039092166001600160801b031963ffffffff909216600160801b0263ffffffff60801b199093169290921716178755505b600186015460028701546000868314614e165760018901879055614e138388036001600160801b038716600160801b61382a565b90505b6000828714614e435760028a01879055614e408388036001600160801b038816600160801b61382a565b90505b6001600160801b038282171615614e8d5760038a0180546001600160801b031981166001600160801b039182168501821617808216600160801b9182900483168501909216021790555b50505050505050505050565b60008082600f0b1215614ec657614ebe614eb985858560000360006150f9565b61483d565b600003614ed6565b614ed6614eb985858560016150f9565b949350505050565b60008082600f0b1215614efe57614ebe614eb98585856000036000615188565b614ed6614eb98585856001615188565b600181811c909117600281901c17600481901c17600881901c17601081901c17602081901c17604081901c17608081901c179081901c900360006136a782614f89565b603c8102620d89e719600282900b1215614f705750620d89e719613a0f565b620d89e8600282900b1315613a0f5750620d89e8919050565b7f55555555555555555555555555555555555555555555555555555555555555558116156001600160801b0382161560071b176001600160401b03600160801b03600160c01b0382161560061b177bffffffff00000000ffffffff00000000ffffffff00000000ffffffff82161560051b177dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff82161560041b177eff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff82161560031b177f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f82161560021b177f3333333333333333333333333333333333333333333333333333333333333333919091161560011b1790565b6000614ed68385846001615188565b6000614ed684848460016150f9565b60006141548585858560016151f9565b6000614ed683858460006150f9565b6000614ed68484846000615188565b60006141548585858560006151f9565b60006001600160a01b038585038116908516811061511657600080fd5b600160601b600160e01b03606085901b168361515757866001600160a01b031661514a8383896001600160a01b031661382a565b8161515157fe5b0461517d565b61517d61516e8383896001600160a01b03166137b5565b886001600160a01b03166153ed565b979650505050505050565b6000846001600160a01b0316846001600160a01b031610156151a957600080fd5b6001600160a01b0385850316826151d7576151d281856001600160801b0316600160601b61382a565b6151ef565b6151ef81856001600160801b0316600160601b6137b5565b9695505050505050565b600080866001600160a01b03161161521057600080fd5b6000856001600160801b03161161522657600080fd5b8115158315151415615318578361523e575084614154565b600160601b600160e01b03606086901b1682156152cc576001600160a01b0387168581029086828161526c57fe5b04141561529d5781810182811061529b57615291838a6001600160a01b0316836137b5565b9350505050614154565b505b6152c3826152be888b6001600160a01b031686816152b757fe5b0490613697565b6153ed565b92505050614154565b6001600160a01b038716858102908682816152e357fe5b04146152ee57600080fd5b8082116152fa57600080fd5b6152c3615313838a6001600160a01b03168486036137b5565b6153f8565b811561537f576153786153136001600160a01b038611156153505761534b86600160601b896001600160801b031661382a565b615368565b6001600160801b038716606087901b8161536657fe5b045b6001600160a01b03891690613697565b9050614154565b60006001600160a01b038511156153ad576153a885600160601b886001600160801b03166137b5565b6153c4565b6153c4606086901b6001600160801b0388166153ed565b905080876001600160a01b0316116153db57600080fd5b6001600160a01b038716039050614154565b808204910615150190565b806001600160a01b0381168114613a0f57600080fd5b604080516060810182526000808252602082018190529181019190915290565b604080516101c081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052906101208201908152600060208201819052604082018190526060820181905260809091015290565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565bfefec42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67a164736f6c6343000706000aa164736f6c6343000706000a
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
POL | 99.93% | $0.425768 | 124,285,663.3005 | $52,916,889.93 | |
POL | <0.01% | $0.424388 | 7,139.5553 | $3,029.94 | |
POL | <0.01% | $1 | 1,083.5173 | $1,084.6 | |
POL | <0.01% | $1 | 1,046.9978 | $1,048.04 | |
POL | <0.01% | $0.482061 | 380.5839 | $183.46 | |
POL | <0.01% | $1 | 151.2316 | $151.38 | |
POL | <0.01% | $0.834573 | 80.114 | $66.86 | |
POL | <0.01% | $0.055355 | 500 | $27.68 | |
POL | <0.01% | $0.034572 | 330.9302 | $11.44 | |
POL | <0.01% | $0.00175 | 5,000 | $8.75 | |
POL | <0.01% | $0.041574 | 100 | $4.16 | |
POL | <0.01% | $0.03816 | 50 | $1.91 | |
POL | <0.01% | $2,350.12 | 0.00050761 | $1.19 | |
POL | <0.01% | $0.01933 | 50.4035 | $0.9743 | |
POL | <0.01% | $0.094484 | 1.168 | $0.1103 | |
BSC | 0.03% | $549.6 | 26.89 | $14,778.66 | |
BSC | <0.01% | $0.046323 | 10,000 | $463.23 | |
BSC | <0.01% | $1 | 120 | $120.24 | |
BSC | <0.01% | $0.418064 | 274.5804 | $114.79 | |
ETH | <0.01% | $0.426092 | 10,603.2188 | $4,517.95 | |
ETH | <0.01% | $2,363.33 | 1.7055 | $4,030.57 | |
ETH | <0.01% | $0.132842 | 216.8033 | $28.8 | |
ETH | <0.01% | $1 | 20 | $20.02 | |
ETH | <0.01% | $1 | 2.9996 | $3 | |
ETH | <0.01% | $0.001944 | 1,495.0887 | $2.91 | |
ARB | 0.01% | $2,343.31 | 2.7401 | $6,420.93 | |
AVAX | <0.01% | $2,359.72 | 0.3401 | $802.65 | |
AVAX | <0.01% | $24.19 | 1.4511 | $35.1 | |
OP | <0.01% | $2,361.4 | 0.2013 | $475.28 | |
OP | <0.01% | $1 | 15.0071 | $15.02 | |
FTM | <0.01% | $0.479604 | 101.7 | $48.78 | |
MOVR | <0.01% | $9.38 | 0.3444 | $3.23 | |
CRONOS | <0.01% | $0.08107 | 39 | $3.16 | |
MANTLE | <0.01% | $0.565134 | 5 | $2.83 | |
ARBNOVA | <0.01% | $2,360.2 | 0.001 | $2.36 | |
GNO | <0.01% | $0.999983 | 1 | $0.999983 | |
CELO | <0.01% | $0.440595 | 0.73 | $0.321635 | |
BASE | <0.01% | $2,343.39 | 0.00011 | $0.257773 |
[ 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.