Latest 15 from a total of 15 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Collect Protocol | 8181065 | 512 days ago | IN | 0 ETH | 0.00000018 | ||||
| Collect Protocol | 7575445 | 526 days ago | IN | 0 ETH | 0.00000202 | ||||
| Claim Yield All | 7467116 | 528 days ago | IN | 0 ETH | 0.00000043 | ||||
| Collect Protocol | 7159239 | 535 days ago | IN | 0 ETH | 0.00000077 | ||||
| Collect Protocol | 6599863 | 548 days ago | IN | 0 ETH | 0.00000089 | ||||
| Collect Protocol | 5760199 | 568 days ago | IN | 0 ETH | 0.00000019 | ||||
| Collect Protocol | 5161997 | 581 days ago | IN | 0 ETH | 0.00003946 | ||||
| Collect Protocol | 4866516 | 588 days ago | IN | 0 ETH | 0.0000195 | ||||
| Collect Protocol | 4601620 | 594 days ago | IN | 0 ETH | 0.00000355 | ||||
| Collect Protocol | 4200900 | 604 days ago | IN | 0 ETH | 0.00000165 | ||||
| Collect Protocol | 3661422 | 616 days ago | IN | 0 ETH | 0.00000949 | ||||
| Collect Protocol | 3174638 | 627 days ago | IN | 0 ETH | 0.0000122 | ||||
| Collect Protocol | 2908440 | 634 days ago | IN | 0 ETH | 0.00001072 | ||||
| Collect Protocol | 2169282 | 651 days ago | IN | 0 ETH | 0.00001688 | ||||
| Collect Protocol | 1411345 | 668 days ago | IN | 0 ETH | 0.0000703 |
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 463624 | 690 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
DackieV3Pool
Compiler Version
v0.7.6+commit.7338295f
Optimization Enabled:
Yes with 200 runs
Other Settings:
istanbul EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity =0.7.6;
import './interfaces/IDackieV3Pool.sol';
import "./interfaces/IBlast.sol";
import "./interfaces/IBlastPoints.sol";
import "./interfaces/IERC20Rebasing.sol";
import './libraries/FullMath.sol';
import './libraries/FixedPoint128.sol';
import './libraries/TransferHelper.sol';
import './libraries/TickMath.sol';
import './libraries/LiquidityMath.sol';
import './libraries/SqrtPriceMath.sol';
import './libraries/SwapMath.sol';
import './libraries/LowGasSafeMath.sol';
import './libraries/SafeCast.sol';
import './libraries/Tick.sol';
import './libraries/TickBitmap.sol';
import './libraries/Position.sol';
import './libraries/Oracle.sol';
import './interfaces/IDackieV3PoolDeployer.sol';
import './interfaces/IDackieV3Factory.sol';
import './interfaces/IERC20Minimal.sol';
import './interfaces/callback/IDackieV3MintCallback.sol';
import './interfaces/callback/IDackieV3SwapCallback.sol';
import './interfaces/callback/IDackieV3FlashCallback.sol';
contract DackieV3Pool is IDackieV3Pool {
using LowGasSafeMath for uint256;
using LowGasSafeMath for int256;
using SafeCast for uint256;
using SafeCast for int256;
using Tick for mapping(int24 => Tick.Info);
using TickBitmap for mapping(int16 => uint256);
using Position for mapping(bytes32 => Position.Info);
using Position for Position.Info;
using Oracle for Oracle.Observation[65535];
IBlast private constant BLAST = IBlast(0x4300000000000000000000000000000000000002);
// Mainnet
IERC20Rebasing private constant USDB = IERC20Rebasing(0x4300000000000000000000000000000000000003);
IERC20Rebasing private constant WETHB = IERC20Rebasing(0x4300000000000000000000000000000000000004);
// Testnet
// IERC20Rebasing private constant USDB = IERC20Rebasing(0x4200000000000000000000000000000000000022);
// IERC20Rebasing private constant WETHB = IERC20Rebasing(0x4200000000000000000000000000000000000023);
address private constant BLAST_POINTS = 0x2536FE9ab3F511540F2f9e2eC2A805005C3Dd800;
/// @inheritdoc IDackieV3PoolImmutables
address public immutable override factory;
/// @inheritdoc IDackieV3PoolImmutables
address public immutable override token0;
/// @inheritdoc IDackieV3PoolImmutables
address public immutable override token1;
/// @inheritdoc IDackieV3PoolImmutables
uint24 public immutable override fee;
/// @inheritdoc IDackieV3PoolImmutables
int24 public immutable override tickSpacing;
/// @inheritdoc IDackieV3PoolImmutables
uint128 public immutable override maxLiquidityPerTick;
uint32 internal constant PROTOCOL_FEE_SP = 65536;
uint256 internal constant PROTOCOL_FEE_DENOMINATOR = 10000;
struct Slot0 {
// the current price
uint160 sqrtPriceX96;
// the current tick
int24 tick;
// the most-recently updated index of the observations array
uint16 observationIndex;
// the current maximum number of observations that are being stored
uint16 observationCardinality;
// the next maximum number of observations to store, triggered in observations.write
uint16 observationCardinalityNext;
// the current protocol fee for token0 and token1,
// 2 uint32 values store in a uint32 variable (fee/PROTOCOL_FEE_DENOMINATOR)
uint32 feeProtocol;
// whether the pool is locked
bool unlocked;
}
/// @inheritdoc IDackieV3PoolState
Slot0 public override slot0;
/// @inheritdoc IDackieV3PoolState
uint256 public override feeGrowthGlobal0X128;
/// @inheritdoc IDackieV3PoolState
uint256 public override feeGrowthGlobal1X128;
// accumulated protocol fees in token0/token1 units
struct ProtocolFees {
uint128 token0;
uint128 token1;
}
/// @inheritdoc IDackieV3PoolState
ProtocolFees public override protocolFees;
/// @inheritdoc IDackieV3PoolState
uint128 public override liquidity;
/// @inheritdoc IDackieV3PoolState
mapping(int24 => Tick.Info) public override ticks;
/// @inheritdoc IDackieV3PoolState
mapping(int16 => uint256) public override tickBitmap;
/// @inheritdoc IDackieV3PoolState
mapping(bytes32 => Position.Info) public override positions;
/// @inheritdoc IDackieV3PoolState
Oracle.Observation[65535] public override observations;
/// @dev Mutually exclusive reentrancy protection into the pool to/from a method. This method also prevents entrance
/// to a function before the pool is initialized. The reentrancy guard is required throughout the contract because
/// we use balance checks to determine the payment status of interactions such as mint, swap and flash.
modifier lock() {
require(slot0.unlocked, 'LOK');
slot0.unlocked = false;
_;
slot0.unlocked = true;
}
/// @dev Prevents calling a function from anyone except the factory or its
/// owner
modifier onlyFactoryOrFactoryOwner() {
require(msg.sender == factory || msg.sender == IDackieV3Factory(factory).owner());
_;
}
constructor() {
int24 _tickSpacing;
BLAST.configureClaimableGas();
USDB.configure(YieldMode.CLAIMABLE);
WETHB.configure(YieldMode.CLAIMABLE);
(factory, token0, token1, fee, _tickSpacing) = IDackieV3PoolDeployer(msg.sender).parameters();
tickSpacing = _tickSpacing;
maxLiquidityPerTick = Tick.tickSpacingToMaxLiquidityPerTick(_tickSpacing);
}
/// @dev Common checks for valid tick inputs.
function checkTicks(int24 tickLower, int24 tickUpper) private pure {
require(tickLower < tickUpper, 'TLU');
require(tickLower >= TickMath.MIN_TICK, 'TLM');
require(tickUpper <= TickMath.MAX_TICK, 'TUM');
}
/// @dev Get the pool's balance of token0
/// @dev This function is gas optimized to avoid a redundant extcodesize check in addition to the returndatasize
/// check
function balance0() private view returns (uint256) {
(bool success, bytes memory data) = token0.staticcall(
abi.encodeWithSelector(IERC20Minimal.balanceOf.selector, address(this))
);
require(success && data.length >= 32);
return abi.decode(data, (uint256));
}
/// @dev Get the pool's balance of token1
/// @dev This function is gas optimized to avoid a redundant extcodesize check in addition to the returndatasize
/// check
function balance1() private view returns (uint256) {
(bool success, bytes memory data) = token1.staticcall(
abi.encodeWithSelector(IERC20Minimal.balanceOf.selector, address(this))
);
require(success && data.length >= 32);
return abi.decode(data, (uint256));
}
/// @inheritdoc IDackieV3PoolDerivedState
function snapshotCumulativesInside(int24 tickLower, int24 tickUpper)
external
view
override
returns (
int56 tickCumulativeInside,
uint160 secondsPerLiquidityInsideX128,
uint32 secondsInside
)
{
checkTicks(tickLower, tickUpper);
int56 tickCumulativeLower;
int56 tickCumulativeUpper;
uint160 secondsPerLiquidityOutsideLowerX128;
uint160 secondsPerLiquidityOutsideUpperX128;
uint32 secondsOutsideLower;
uint32 secondsOutsideUpper;
{
Tick.Info storage lower = ticks[tickLower];
Tick.Info storage upper = ticks[tickUpper];
bool initializedLower;
(tickCumulativeLower, secondsPerLiquidityOutsideLowerX128, secondsOutsideLower, initializedLower) = (
lower.tickCumulativeOutside,
lower.secondsPerLiquidityOutsideX128,
lower.secondsOutside,
lower.initialized
);
require(initializedLower);
bool initializedUpper;
(tickCumulativeUpper, secondsPerLiquidityOutsideUpperX128, secondsOutsideUpper, initializedUpper) = (
upper.tickCumulativeOutside,
upper.secondsPerLiquidityOutsideX128,
upper.secondsOutside,
upper.initialized
);
require(initializedUpper);
}
Slot0 memory _slot0 = slot0;
if (_slot0.tick < tickLower) {
return (
tickCumulativeLower - tickCumulativeUpper,
secondsPerLiquidityOutsideLowerX128 - secondsPerLiquidityOutsideUpperX128,
secondsOutsideLower - secondsOutsideUpper
);
} else if (_slot0.tick < tickUpper) {
uint32 time = uint32(block.timestamp);
(int56 tickCumulative, uint160 secondsPerLiquidityCumulativeX128) = observations.observeSingle(
time,
0,
_slot0.tick,
_slot0.observationIndex,
liquidity,
_slot0.observationCardinality
);
return (
tickCumulative - tickCumulativeLower - tickCumulativeUpper,
secondsPerLiquidityCumulativeX128 -
secondsPerLiquidityOutsideLowerX128 -
secondsPerLiquidityOutsideUpperX128,
time - secondsOutsideLower - secondsOutsideUpper
);
} else {
return (
tickCumulativeUpper - tickCumulativeLower,
secondsPerLiquidityOutsideUpperX128 - secondsPerLiquidityOutsideLowerX128,
secondsOutsideUpper - secondsOutsideLower
);
}
}
/// @inheritdoc IDackieV3PoolDerivedState
function observe(uint32[] calldata secondsAgos)
external
view
override
returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s)
{
return
observations.observe(
uint32(block.timestamp),
secondsAgos,
slot0.tick,
slot0.observationIndex,
liquidity,
slot0.observationCardinality
);
}
/// @inheritdoc IDackieV3PoolActions
function increaseObservationCardinalityNext(uint16 observationCardinalityNext)
external
override
lock
{
uint16 observationCardinalityNextOld = slot0.observationCardinalityNext; // for the event
uint16 observationCardinalityNextNew = observations.grow(
observationCardinalityNextOld,
observationCardinalityNext
);
slot0.observationCardinalityNext = observationCardinalityNextNew;
if (observationCardinalityNextOld != observationCardinalityNextNew)
emit IncreaseObservationCardinalityNext(observationCardinalityNextOld, observationCardinalityNextNew);
}
/// @inheritdoc IDackieV3PoolActions
/// @dev not locked because it initializes unlocked
function initialize(uint160 sqrtPriceX96) external override {
require(slot0.sqrtPriceX96 == 0, 'AI');
IBlastPoints(BLAST_POINTS).configurePointsOperator(IDackieV3Factory(factory).pointsAdmin());
int24 tick = TickMath.getTickAtSqrtRatio(sqrtPriceX96);
(uint16 cardinality, uint16 cardinalityNext) = observations.initialize(uint32(block.timestamp));
slot0 = Slot0({
sqrtPriceX96: sqrtPriceX96,
tick: tick,
observationIndex: 0,
observationCardinality: cardinality,
observationCardinalityNext: cardinalityNext,
feeProtocol: 209718400, // default value for all pools, 3200:3200, store 2 uint32 inside
unlocked: true
});
if (fee == 100) {
slot0.feeProtocol = 216272100; // value for 3300:3300, store 2 uint32 inside
} else if (fee == 500) {
slot0.feeProtocol = 222825800; // value for 3400:3400, store 2 uint32 inside
} else if (fee == 2500) {
slot0.feeProtocol = 209718400; // value for 3200:3200, store 2 uint32 inside
} else if (fee == 10000) {
slot0.feeProtocol = 209718400; // value for 3200:3200, store 2 uint32 inside
}
emit Initialize(sqrtPriceX96, tick);
}
struct ModifyPositionParams {
// the address that owns the position
address owner;
// the lower and upper tick of the position
int24 tickLower;
int24 tickUpper;
// any change in liquidity
int128 liquidityDelta;
}
/// @dev Effect some changes to a position
/// @param params the position details and the change to the position's liquidity to effect
/// @return position a storage pointer referencing the position with the given owner and tick range
/// @return amount0 the amount of token0 owed to the pool, negative if the pool should pay the recipient
/// @return amount1 the amount of token1 owed to the pool, negative if the pool should pay the recipient
function _modifyPosition(ModifyPositionParams memory params)
private
returns (
Position.Info storage position,
int256 amount0,
int256 amount1
)
{
checkTicks(params.tickLower, params.tickUpper);
Slot0 memory _slot0 = slot0; // SLOAD for gas optimization
position = _updatePosition(
params.owner,
params.tickLower,
params.tickUpper,
params.liquidityDelta,
_slot0.tick
);
if (params.liquidityDelta != 0) {
if (_slot0.tick < params.tickLower) {
// current tick is below the passed range; liquidity can only become in range by crossing from left to
// right, when we'll need _more_ token0 (it's becoming more valuable) so user must provide it
amount0 = SqrtPriceMath.getAmount0Delta(
TickMath.getSqrtRatioAtTick(params.tickLower),
TickMath.getSqrtRatioAtTick(params.tickUpper),
params.liquidityDelta
);
} else if (_slot0.tick < params.tickUpper) {
// current tick is inside the passed range
uint128 liquidityBefore = liquidity; // SLOAD for gas optimization
// write an oracle entry
(slot0.observationIndex, slot0.observationCardinality) = observations.write(
_slot0.observationIndex,
uint32(block.timestamp),
_slot0.tick,
liquidityBefore,
_slot0.observationCardinality,
_slot0.observationCardinalityNext
);
amount0 = SqrtPriceMath.getAmount0Delta(
_slot0.sqrtPriceX96,
TickMath.getSqrtRatioAtTick(params.tickUpper),
params.liquidityDelta
);
amount1 = SqrtPriceMath.getAmount1Delta(
TickMath.getSqrtRatioAtTick(params.tickLower),
_slot0.sqrtPriceX96,
params.liquidityDelta
);
liquidity = LiquidityMath.addDelta(liquidityBefore, params.liquidityDelta);
} else {
// current tick is above the passed range; liquidity can only become in range by crossing from right to
// left, when we'll need _more_ token1 (it's becoming more valuable) so user must provide it
amount1 = SqrtPriceMath.getAmount1Delta(
TickMath.getSqrtRatioAtTick(params.tickLower),
TickMath.getSqrtRatioAtTick(params.tickUpper),
params.liquidityDelta
);
}
}
}
/// @dev Gets and updates a position with the given liquidity delta
/// @param owner the owner of the position
/// @param tickLower the lower tick of the position's tick range
/// @param tickUpper the upper tick of the position's tick range
/// @param tick the current tick, passed to avoid sloads
function _updatePosition(
address owner,
int24 tickLower,
int24 tickUpper,
int128 liquidityDelta,
int24 tick
) private returns (Position.Info storage position) {
position = positions.get(owner, tickLower, tickUpper);
uint256 _feeGrowthGlobal0X128 = feeGrowthGlobal0X128; // SLOAD for gas optimization
uint256 _feeGrowthGlobal1X128 = feeGrowthGlobal1X128; // SLOAD for gas optimization
// if we need to update the ticks, do it
bool flippedLower;
bool flippedUpper;
if (liquidityDelta != 0) {
uint32 time = uint32(block.timestamp);
(int56 tickCumulative, uint160 secondsPerLiquidityCumulativeX128) = observations.observeSingle(
time,
0,
slot0.tick,
slot0.observationIndex,
liquidity,
slot0.observationCardinality
);
flippedLower = ticks.update(
tickLower,
tick,
liquidityDelta,
_feeGrowthGlobal0X128,
_feeGrowthGlobal1X128,
secondsPerLiquidityCumulativeX128,
tickCumulative,
time,
false,
maxLiquidityPerTick
);
flippedUpper = ticks.update(
tickUpper,
tick,
liquidityDelta,
_feeGrowthGlobal0X128,
_feeGrowthGlobal1X128,
secondsPerLiquidityCumulativeX128,
tickCumulative,
time,
true,
maxLiquidityPerTick
);
if (flippedLower) {
tickBitmap.flipTick(tickLower, tickSpacing);
}
if (flippedUpper) {
tickBitmap.flipTick(tickUpper, tickSpacing);
}
}
(uint256 feeGrowthInside0X128, uint256 feeGrowthInside1X128) = ticks.getFeeGrowthInside(
tickLower,
tickUpper,
tick,
_feeGrowthGlobal0X128,
_feeGrowthGlobal1X128
);
position.update(liquidityDelta, feeGrowthInside0X128, feeGrowthInside1X128);
// clear any tick data that is no longer needed
if (liquidityDelta < 0) {
if (flippedLower) {
ticks.clear(tickLower);
}
if (flippedUpper) {
ticks.clear(tickUpper);
}
}
}
/// @inheritdoc IDackieV3PoolActions
/// @dev noDelegateCall is applied indirectly via _modifyPosition
function mint(
address recipient,
int24 tickLower,
int24 tickUpper,
uint128 amount,
bytes calldata data
) external override lock returns (uint256 amount0, uint256 amount1) {
require(amount > 0);
(, int256 amount0Int, int256 amount1Int) = _modifyPosition(
ModifyPositionParams({
owner: recipient,
tickLower: tickLower,
tickUpper: tickUpper,
liquidityDelta: int256(amount).toInt128()
})
);
amount0 = uint256(amount0Int);
amount1 = uint256(amount1Int);
uint256 balance0Before;
uint256 balance1Before;
if (amount0 > 0) balance0Before = balance0();
if (amount1 > 0) balance1Before = balance1();
IDackieV3MintCallback(msg.sender).pancakeV3MintCallback(amount0, amount1, data);
if (amount0 > 0) require(balance0Before.add(amount0) <= balance0(), 'M0');
if (amount1 > 0) require(balance1Before.add(amount1) <= balance1(), 'M1');
emit Mint(msg.sender, recipient, tickLower, tickUpper, amount, amount0, amount1);
}
/// @inheritdoc IDackieV3PoolActions
function collect(
address recipient,
int24 tickLower,
int24 tickUpper,
uint128 amount0Requested,
uint128 amount1Requested
) external override lock returns (uint128 amount0, uint128 amount1) {
// we don't need to checkTicks here, because invalid positions will never have non-zero tokensOwed{0,1}
Position.Info storage position = positions.get(msg.sender, tickLower, tickUpper);
amount0 = amount0Requested > position.tokensOwed0 ? position.tokensOwed0 : amount0Requested;
amount1 = amount1Requested > position.tokensOwed1 ? position.tokensOwed1 : amount1Requested;
if (amount0 > 0) {
position.tokensOwed0 -= amount0;
TransferHelper.safeTransfer(token0, recipient, amount0);
}
if (amount1 > 0) {
position.tokensOwed1 -= amount1;
TransferHelper.safeTransfer(token1, recipient, amount1);
}
emit Collect(msg.sender, recipient, tickLower, tickUpper, amount0, amount1);
}
/// @inheritdoc IDackieV3PoolActions
/// @dev noDelegateCall is applied indirectly via _modifyPosition
function burn(
int24 tickLower,
int24 tickUpper,
uint128 amount
) external override lock returns (uint256 amount0, uint256 amount1) {
(Position.Info storage position, int256 amount0Int, int256 amount1Int) = _modifyPosition(
ModifyPositionParams({
owner: msg.sender,
tickLower: tickLower,
tickUpper: tickUpper,
liquidityDelta: - int256(amount).toInt128()
})
);
amount0 = uint256(- amount0Int);
amount1 = uint256(- amount1Int);
if (amount0 > 0 || amount1 > 0) {
(position.tokensOwed0, position.tokensOwed1) = (
position.tokensOwed0 + uint128(amount0),
position.tokensOwed1 + uint128(amount1)
);
}
emit Burn(msg.sender, tickLower, tickUpper, amount, amount0, amount1);
}
struct SwapCache {
// the protocol fee for the input token
uint32 feeProtocol;
// liquidity at the beginning of the swap
uint128 liquidityStart;
// the timestamp of the current block
uint32 blockTimestamp;
// the current value of the tick accumulator, computed only if we cross an initialized tick
int56 tickCumulative;
// the current value of seconds per liquidity accumulator, computed only if we cross an initialized tick
uint160 secondsPerLiquidityCumulativeX128;
// whether we've computed and cached the above two accumulators
bool computedLatestObservation;
}
// the top level state of the swap, the results of which are recorded in storage at the end
struct SwapState {
// the amount remaining to be swapped in/out of the input/output asset
int256 amountSpecifiedRemaining;
// the amount already swapped out/in of the output/input asset
int256 amountCalculated;
// current sqrt(price)
uint160 sqrtPriceX96;
// the tick associated with the current price
int24 tick;
// the global fee growth of the input token
uint256 feeGrowthGlobalX128;
// amount of input token paid as protocol fee
uint128 protocolFee;
// the current liquidity in range
uint128 liquidity;
}
struct StepComputations {
// the price at the beginning of the step
uint160 sqrtPriceStartX96;
// the next tick to swap to from the current tick in the swap direction
int24 tickNext;
// whether tickNext is initialized or not
bool initialized;
// sqrt(price) for the next tick (1/0)
uint160 sqrtPriceNextX96;
// how much is being swapped in in this step
uint256 amountIn;
// how much is being swapped out
uint256 amountOut;
// how much fee is being paid in
uint256 feeAmount;
}
/// @inheritdoc IDackieV3PoolActions
function swap(
address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160 sqrtPriceLimitX96,
bytes calldata data
) external override returns (int256 amount0, int256 amount1) {
require(amountSpecified != 0, 'AS');
Slot0 memory slot0Start = slot0;
require(slot0Start.unlocked, 'LOK');
require(
zeroForOne
? sqrtPriceLimitX96 < slot0Start.sqrtPriceX96 && sqrtPriceLimitX96 > TickMath.MIN_SQRT_RATIO
: sqrtPriceLimitX96 > slot0Start.sqrtPriceX96 && sqrtPriceLimitX96 < TickMath.MAX_SQRT_RATIO,
'SPL'
);
slot0.unlocked = false;
SwapCache memory cache = SwapCache({
liquidityStart: liquidity,
blockTimestamp: uint32(block.timestamp),
feeProtocol: zeroForOne ? (slot0Start.feeProtocol % PROTOCOL_FEE_SP) : (slot0Start.feeProtocol >> 16),
secondsPerLiquidityCumulativeX128: 0,
tickCumulative: 0,
computedLatestObservation: false
});
bool exactInput = amountSpecified > 0;
SwapState memory state = SwapState({
amountSpecifiedRemaining: amountSpecified,
amountCalculated: 0,
sqrtPriceX96: slot0Start.sqrtPriceX96,
tick: slot0Start.tick,
feeGrowthGlobalX128: zeroForOne ? feeGrowthGlobal0X128 : feeGrowthGlobal1X128,
protocolFee: 0,
liquidity: cache.liquidityStart
});
// continue swapping as long as we haven't used the entire input/output and haven't reached the price limit
while (state.amountSpecifiedRemaining != 0 && state.sqrtPriceX96 != sqrtPriceLimitX96) {
StepComputations memory step;
step.sqrtPriceStartX96 = state.sqrtPriceX96;
(step.tickNext, step.initialized) = tickBitmap.nextInitializedTickWithinOneWord(
state.tick,
tickSpacing,
zeroForOne
);
// ensure that we do not overshoot the min/max tick, as the tick bitmap is not aware of these bounds
if (step.tickNext < TickMath.MIN_TICK) {
step.tickNext = TickMath.MIN_TICK;
} else if (step.tickNext > TickMath.MAX_TICK) {
step.tickNext = TickMath.MAX_TICK;
}
// get the price for the next tick
step.sqrtPriceNextX96 = TickMath.getSqrtRatioAtTick(step.tickNext);
// compute values to swap to the target tick, price limit, or point where input/output amount is exhausted
(state.sqrtPriceX96, step.amountIn, step.amountOut, step.feeAmount) = SwapMath.computeSwapStep(
state.sqrtPriceX96,
(zeroForOne ? step.sqrtPriceNextX96 < sqrtPriceLimitX96 : step.sqrtPriceNextX96 > sqrtPriceLimitX96)
? sqrtPriceLimitX96
: step.sqrtPriceNextX96,
state.liquidity,
state.amountSpecifiedRemaining,
fee
);
if (exactInput) {
state.amountSpecifiedRemaining -= (step.amountIn + step.feeAmount).toInt256();
state.amountCalculated = state.amountCalculated.sub(step.amountOut.toInt256());
} else {
state.amountSpecifiedRemaining += step.amountOut.toInt256();
state.amountCalculated = state.amountCalculated.add((step.amountIn + step.feeAmount).toInt256());
}
// if the protocol fee is on, calculate how much is owed, decrement feeAmount, and increment protocolFee
if (cache.feeProtocol > 0) {
uint256 delta = (step.feeAmount.mul(cache.feeProtocol)) / PROTOCOL_FEE_DENOMINATOR;
step.feeAmount -= delta;
state.protocolFee += uint128(delta);
}
// update global fee tracker
if (state.liquidity > 0)
state.feeGrowthGlobalX128 += FullMath.mulDiv(step.feeAmount, FixedPoint128.Q128, state.liquidity);
// shift tick if we reached the next price
if (state.sqrtPriceX96 == step.sqrtPriceNextX96) {
// if the tick is initialized, run the tick transition
if (step.initialized) {
// check for the placeholder value, which we replace with the actual value the first time the swap
// crosses an initialized tick
if (!cache.computedLatestObservation) {
(cache.tickCumulative, cache.secondsPerLiquidityCumulativeX128) = observations.observeSingle(
cache.blockTimestamp,
0,
slot0Start.tick,
slot0Start.observationIndex,
cache.liquidityStart,
slot0Start.observationCardinality
);
cache.computedLatestObservation = true;
}
int128 liquidityNet = ticks.cross(
step.tickNext,
(zeroForOne ? state.feeGrowthGlobalX128 : feeGrowthGlobal0X128),
(zeroForOne ? feeGrowthGlobal1X128 : state.feeGrowthGlobalX128),
cache.secondsPerLiquidityCumulativeX128,
cache.tickCumulative,
cache.blockTimestamp
);
// if we're moving leftward, we interpret liquidityNet as the opposite sign
// safe because liquidityNet cannot be type(int128).min
if (zeroForOne) liquidityNet = - liquidityNet;
state.liquidity = LiquidityMath.addDelta(state.liquidity, liquidityNet);
}
state.tick = zeroForOne ? step.tickNext - 1 : step.tickNext;
} else if (state.sqrtPriceX96 != step.sqrtPriceStartX96) {
// recompute unless we're on a lower tick boundary (i.e. already transitioned ticks), and haven't moved
state.tick = TickMath.getTickAtSqrtRatio(state.sqrtPriceX96);
}
}
// update tick and write an oracle entry if the tick change
if (state.tick != slot0Start.tick) {
(uint16 observationIndex, uint16 observationCardinality) = observations.write(
slot0Start.observationIndex,
cache.blockTimestamp,
slot0Start.tick,
cache.liquidityStart,
slot0Start.observationCardinality,
slot0Start.observationCardinalityNext
);
(slot0.sqrtPriceX96, slot0.tick, slot0.observationIndex, slot0.observationCardinality) = (
state.sqrtPriceX96,
state.tick,
observationIndex,
observationCardinality
);
} else {
// otherwise just update the price
slot0.sqrtPriceX96 = state.sqrtPriceX96;
}
// update liquidity if it changed
if (cache.liquidityStart != state.liquidity) liquidity = state.liquidity;
uint128 protocolFeesToken0 = 0;
uint128 protocolFeesToken1 = 0;
// update fee growth global and, if necessary, protocol fees
// overflow is acceptable, protocol has to withdraw before it hits type(uint128).max fees
if (zeroForOne) {
feeGrowthGlobal0X128 = state.feeGrowthGlobalX128;
if (state.protocolFee > 0) protocolFees.token0 += state.protocolFee;
protocolFeesToken0 = state.protocolFee;
} else {
feeGrowthGlobal1X128 = state.feeGrowthGlobalX128;
if (state.protocolFee > 0) protocolFees.token1 += state.protocolFee;
protocolFeesToken1 = state.protocolFee;
}
(amount0, amount1) = zeroForOne == exactInput
? (amountSpecified - state.amountSpecifiedRemaining, state.amountCalculated)
: (state.amountCalculated, amountSpecified - state.amountSpecifiedRemaining);
// do the transfers and collect payment
if (zeroForOne) {
if (amount1 < 0) TransferHelper.safeTransfer(token1, recipient, uint256(- amount1));
uint256 balance0Before = balance0();
IDackieV3SwapCallback(msg.sender).pancakeV3SwapCallback(amount0, amount1, data);
require(balance0Before.add(uint256(amount0)) <= balance0(), 'IIA');
} else {
if (amount0 < 0) TransferHelper.safeTransfer(token0, recipient, uint256(- amount0));
uint256 balance1Before = balance1();
IDackieV3SwapCallback(msg.sender).pancakeV3SwapCallback(amount0, amount1, data);
require(balance1Before.add(uint256(amount1)) <= balance1(), 'IIA');
}
emit Swap(msg.sender, recipient, amount0, amount1, state.sqrtPriceX96, state.liquidity, state.tick, protocolFeesToken0, protocolFeesToken1);
slot0.unlocked = true;
}
/// @inheritdoc IDackieV3PoolOwnerActions
function setFeeProtocol(uint32 feeProtocol0, uint32 feeProtocol1) external override lock onlyFactoryOrFactoryOwner {
require(
(feeProtocol0 == 0 || (feeProtocol0 >= 1000 && feeProtocol0 <= 4000)) &&
(feeProtocol1 == 0 || (feeProtocol1 >= 1000 && feeProtocol1 <= 4000))
);
uint32 feeProtocolOld = slot0.feeProtocol;
slot0.feeProtocol = feeProtocol0 + (feeProtocol1 << 16);
emit SetFeeProtocol(feeProtocolOld % PROTOCOL_FEE_SP, feeProtocolOld >> 16, feeProtocol0, feeProtocol1);
}
/// @inheritdoc IDackieV3PoolOwnerActions
function collectProtocol(
address recipient,
uint128 amount0Requested,
uint128 amount1Requested
) external override lock onlyFactoryOrFactoryOwner returns (uint128 amount0, uint128 amount1) {
amount0 = amount0Requested > protocolFees.token0 ? protocolFees.token0 : amount0Requested;
amount1 = amount1Requested > protocolFees.token1 ? protocolFees.token1 : amount1Requested;
if (amount0 > 0) {
if (amount0 == protocolFees.token0) amount0--; // ensure that the slot is not cleared, for gas savings
protocolFees.token0 -= amount0;
TransferHelper.safeTransfer(token0, recipient, amount0);
}
if (amount1 > 0) {
if (amount1 == protocolFees.token1) amount1--; // ensure that the slot is not cleared, for gas savings
protocolFees.token1 -= amount1;
TransferHelper.safeTransfer(token1, recipient, amount1);
}
emit CollectProtocol(msg.sender, recipient, amount0, amount1);
}
function claimYieldAll(address _recipient, uint256 _amountWETH, uint256 _amountUSDB)
external
override
onlyFactoryOrFactoryOwner
returns (uint256 amountWETH, uint256 amountUSDB, uint256 amountGas)
{
amountWETH = IERC20Rebasing(WETHB).claim(_recipient, _amountWETH);
amountUSDB = IERC20Rebasing(USDB).claim(_recipient, _amountUSDB);
amountGas = IBlast(BLAST).claimMaxGas(address(this), _recipient);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Callback for IDackieV3PoolActions#flash
/// @notice Any contract that calls IDackieV3PoolActions#flash must implement this interface
interface IDackieV3FlashCallback {
/// @notice Called to `msg.sender` after transferring to the recipient from IDackieV3Pool#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 DackieV3Pool deployed by the canonical DackieV3Factory.
/// @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 IDackieV3PoolActions#flash call
function pancakeV3FlashCallback(
uint256 fee0,
uint256 fee1,
bytes calldata data
) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Callback for IDackieV3PoolActions#mint
/// @notice Any contract that calls IDackieV3PoolActions#mint must implement this interface
interface IDackieV3MintCallback {
/// @notice Called to `msg.sender` after minting liquidity to a position from IDackieV3Pool#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 DackieV3Pool deployed by the canonical DackieV3Factory.
/// @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 IDackieV3PoolActions#mint call
function pancakeV3MintCallback(
uint256 amount0Owed,
uint256 amount1Owed,
bytes calldata data
) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Callback for IDackieV3PoolActions#swap
/// @notice Any contract that calls IDackieV3PoolActions#swap must implement this interface
interface IDackieV3SwapCallback {
/// @notice Called to `msg.sender` after executing a swap via IDackieV3Pool#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 DackieV3Pool deployed by the canonical DackieV3Factory.
/// 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 IDackieV3PoolActions#swap call
function pancakeV3SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata data
) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
interface IBlast {
enum YieldMode {
AUTOMATIC,
VOID,
CLAIMABLE
}
enum GasMode {
VOID,
CLAIMABLE
}
// configure
function configureContract(address contractAddress, YieldMode _yield, GasMode gasMode, address governor) external;
function configure(YieldMode _yield, GasMode gasMode, address governor) external;
// base configuration options
function configureClaimableYield() external;
function configureClaimableYieldOnBehalf(address contractAddress) external;
function configureAutomaticYield() external;
function configureAutomaticYieldOnBehalf(address contractAddress) external;
function configureVoidYield() external;
function configureVoidYieldOnBehalf(address contractAddress) external;
function configureClaimableGas() external;
function configureClaimableGasOnBehalf(address contractAddress) external;
function configureVoidGas() external;
function configureVoidGasOnBehalf(address contractAddress) external;
function configureGovernor(address _governor) external;
function configureGovernorOnBehalf(address _newGovernor, address contractAddress) external;
// claim yield
function claimYield(address contractAddress, address recipientOfYield, uint256 amount) external returns (uint256);
function claimAllYield(address contractAddress, address recipientOfYield) external returns (uint256);
// claim gas
function claimAllGas(address contractAddress, address recipientOfGas) external returns (uint256);
function claimGasAtMinClaimRate(address contractAddress, address recipientOfGas, uint256 minClaimRateBips)
external
returns (uint256);
function claimMaxGas(address contractAddress, address recipientOfGas) external returns (uint256);
function claimGas(address contractAddress, address recipientOfGas, uint256 gasToClaim, uint256 gasSecondsToConsume)
external
returns (uint256);
// read functions
function readClaimableYield(address contractAddress) external view returns (uint256);
function readYieldConfiguration(address contractAddress) external view returns (uint8);
function readGasParams(address contractAddress)
external
view
returns (uint256 etherSeconds, uint256 etherBalance, uint256 lastUpdated, GasMode);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
interface IBlastPoints {
function configurePointsOperator(address operator) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title The interface for the DackieSwap V3 Factory
/// @notice The DackieSwap V3 Factory facilitates creation of DackieSwap V3 pools and control over the protocol fees
interface IDackieV3Factory {
struct TickSpacingExtraInfo {
bool whitelistRequested;
bool enabled;
}
/// @notice Emitted when the owner of the factory is changed
/// @param oldOwner The owner before the owner was changed
/// @param newOwner The owner after the owner was changed
event OwnerChanged(address indexed oldOwner, address indexed newOwner);
/// @notice Emitted when a pool is created
/// @param token0 The first token of the pool by address sort order
/// @param token1 The second token of the pool by address sort order
/// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip
/// @param tickSpacing The minimum number of ticks between initialized ticks
/// @param pool The address of the created pool
event PoolCreated(
address indexed token0,
address indexed token1,
uint24 indexed fee,
int24 tickSpacing,
address pool
);
/// @notice Emitted when a new fee amount is enabled for pool creation via the factory
/// @param fee The enabled fee, denominated in hundredths of a bip
/// @param tickSpacing The minimum number of ticks between initialized ticks for pools created with the given fee
event FeeAmountEnabled(uint24 indexed fee, int24 indexed tickSpacing);
event FeeAmountExtraInfoUpdated(uint24 indexed fee, bool whitelistRequested, bool enabled);
event WhiteListAdded(address indexed user, bool verified);
/// @notice Emitted when LM pool deployer is set
event SetLmPoolDeployer(address indexed lmPoolDeployer);
/// @notice Returns the current owner of the factory
/// @dev Can be changed by the current owner via setOwner
/// @return The address of the factory owner
function owner() external view returns (address);
/// @notice Returns the tick spacing for a given fee amount, if enabled, or 0 if not enabled
/// @dev A fee amount can never be removed, so this value should be hard coded or cached in the calling context
/// @param fee The enabled fee, denominated in hundredths of a bip. Returns 0 in case of unenabled fee
/// @return The tick spacing
function feeAmountTickSpacing(uint24 fee) external view returns (int24);
/// @notice Returns the tick spacing extra info
/// @dev A fee amount can never be removed, so this value should be hard coded or cached in the calling context
/// @param fee The enabled fee, denominated in hundredths of a bip. Returns 0 in case of unenabled fee
/// @return whitelistRequested The flag whether should be created by white list users only
function feeAmountTickSpacingExtraInfo(uint24 fee) external view returns (bool whitelistRequested, bool enabled);
/// @notice Returns the pool address for a given pair of tokens and a fee, or address 0 if it does not exist
/// @dev tokenA and tokenB may be passed in either token0/token1 or token1/token0 order
/// @param tokenA The contract address of either token0 or token1
/// @param tokenB The contract address of the other token
/// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip
/// @return pool The pool address
function getPool(
address tokenA,
address tokenB,
uint24 fee
) external view returns (address pool);
/// @notice Creates a pool for the given two tokens and fee
/// @param tokenA One of the two tokens in the desired pool
/// @param tokenB The other of the two tokens in the desired pool
/// @param fee The desired fee for the pool
/// @dev tokenA and tokenB may be passed in either order: token0/token1 or token1/token0. tickSpacing is retrieved
/// from the fee. The call will revert if the pool already exists, the fee is invalid, or the token arguments
/// are invalid.
/// @return pool The address of the newly created pool
function createPool(
address tokenA,
address tokenB,
uint24 fee
) external returns (address pool);
/// @notice Updates the owner of the factory
/// @dev Must be called by the current owner
/// @param _owner The new owner of the factory
function setOwner(address _owner) external;
/// @notice Enables a fee amount with the given tickSpacing
/// @dev Fee amounts may never be removed once enabled
/// @param fee The fee amount to enable, denominated in hundredths of a bip (i.e. 1e-6)
/// @param tickSpacing The spacing between ticks to be enforced for all pools created with the given fee amount
function enableFeeAmount(uint24 fee, int24 tickSpacing) external;
/// @notice Set an address into white list
/// @dev Address can be updated by owner with boolean value false
/// @param user The user address that add into white list
function setWhiteListAddress(address user, bool verified) external;
/// @notice Set a fee amount extra info
/// @dev Fee amounts can be updated by owner with extra info
/// @param whitelistRequested The flag whether should be created by owner only
/// @param enabled The flag is the fee is enabled or not
function setFeeAmountExtraInfo(
uint24 fee,
bool whitelistRequested,
bool enabled
) external;
function setLmPoolDeployer(address _lmPoolDeployer) external;
function setFeeProtocol(address pool, uint32 feeProtocol0, uint32 feeProtocol1) external;
function collectProtocol(
address pool,
address recipient,
uint128 amount0Requested,
uint128 amount1Requested
) external returns (uint128 amount0, uint128 amount1);
function pointsAdmin() external view returns (address);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import './pool/IDackieV3PoolImmutables.sol';
import './pool/IDackieV3PoolState.sol';
import './pool/IDackieV3PoolDerivedState.sol';
import './pool/IDackieV3PoolActions.sol';
import './pool/IDackieV3PoolOwnerActions.sol';
import './pool/IDackieV3PoolEvents.sol';
/// @title The interface for a DackieSwap V3 Pool
/// @notice A DackieSwap pool facilitates swapping and automated market making between any two assets that strictly conform
/// to the ERC20 specification
/// @dev The pool interface is broken up into many smaller pieces
interface IDackieV3Pool is
IDackieV3PoolImmutables,
IDackieV3PoolState,
IDackieV3PoolDerivedState,
IDackieV3PoolActions,
IDackieV3PoolOwnerActions,
IDackieV3PoolEvents
{
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
interface IDackieV3PoolDeployer {
function parameters()
external
view
returns (
address factory,
address token0,
address token1,
uint24 fee,
int24 tickSpacing
);
function deploy(
address factory,
address token0,
address token1,
uint24 fee,
int24 tickSpacing
) external returns (address pool);
function claimGas(address _recipient) external returns (uint256 amount);
function factoryAddress() external view returns (address);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Minimal ERC20 interface for DackieSwap
/// @notice Contains a subset of the full ERC20 interface that is used in DackieSwap V3
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;
enum YieldMode {
AUTOMATIC,
VOID,
CLAIMABLE
}
interface IERC20Rebasing {
// changes the yield mode of the caller and update the balance
// to reflect the configuration
function configure(YieldMode) external returns (uint256);
// "claimable" yield mode accounts can call this this claim their yield
// to another address
function claim(address recipient, uint256 amount) external returns (uint256);
// read the claimable amount for an account
function getClaimableAmount(address account) external view returns (uint256);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
interface IDackieV3PoolActions {
function initialize(uint160 sqrtPriceX96) external;
function mint(
address recipient,
int24 tickLower,
int24 tickUpper,
uint128 amount,
bytes calldata data
) external returns (uint256 amount0, uint256 amount1);
function collect(
address recipient,
int24 tickLower,
int24 tickUpper,
uint128 amount0Requested,
uint128 amount1Requested
) external returns (uint128 amount0, uint128 amount1);
function burn(
int24 tickLower,
int24 tickUpper,
uint128 amount
) external returns (uint256 amount0, uint256 amount1);
function swap(
address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160 sqrtPriceLimitX96,
bytes calldata data
) external returns (int256 amount0, int256 amount1);
function increaseObservationCardinalityNext(uint16 observationCardinalityNext) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
interface IDackieV3PoolDerivedState {
function observe(uint32[] calldata secondsAgos)
external
view
returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s);
function snapshotCumulativesInside(int24 tickLower, int24 tickUpper)
external
view
returns (
int56 tickCumulativeInside,
uint160 secondsPerLiquidityInsideX128,
uint32 secondsInside
);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
interface IDackieV3PoolEvents {
event Initialize(uint160 sqrtPriceX96, int24 tick);
event Mint(
address sender,
address indexed owner,
int24 indexed tickLower,
int24 indexed tickUpper,
uint128 amount,
uint256 amount0,
uint256 amount1
);
event Collect(
address indexed owner,
address recipient,
int24 indexed tickLower,
int24 indexed tickUpper,
uint128 amount0,
uint128 amount1
);
event Burn(
address indexed owner,
int24 indexed tickLower,
int24 indexed tickUpper,
uint128 amount,
uint256 amount0,
uint256 amount1
);
event Swap(
address indexed sender,
address indexed recipient,
int256 amount0,
int256 amount1,
uint160 sqrtPriceX96,
uint128 liquidity,
int24 tick,
uint128 protocolFeesToken0,
uint128 protocolFeesToken1
);
event IncreaseObservationCardinalityNext(
uint16 observationCardinalityNextOld,
uint16 observationCardinalityNextNew
);
event SetFeeProtocol(
uint32 feeProtocol0Old,
uint32 feeProtocol1Old,
uint32 feeProtocol0New,
uint32 feeProtocol1New
);
event CollectProtocol(address indexed sender, address indexed recipient, uint128 amount0, uint128 amount1);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
interface IDackieV3PoolImmutables {
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function fee() external view returns (uint24);
function tickSpacing() external view returns (int24);
function maxLiquidityPerTick() external view returns (uint128);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
interface IDackieV3PoolOwnerActions {
function setFeeProtocol(uint32 feeProtocol0, uint32 feeProtocol1) external;
function collectProtocol(
address recipient,
uint128 amount0Requested,
uint128 amount1Requested
) external returns (uint128 amount0, uint128 amount1);
function claimYieldAll(address recipient, uint256 _wethA, uint256 _usdbA)
external
returns (uint256 wethB, uint256 usdbB, uint256 gas);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
interface IDackieV3PoolState {
function slot0()
external
view
returns (
uint160 sqrtPriceX96,
int24 tick,
uint16 observationIndex,
uint16 observationCardinality,
uint16 observationCardinalityNext,
uint32 feeProtocol,
bool unlocked
);
function feeGrowthGlobal0X128() external view returns (uint256);
function feeGrowthGlobal1X128() external view returns (uint256);
function protocolFees() external view returns (uint128 token0, uint128 token1);
function liquidity() external view returns (uint128);
function ticks(int24 tick)
external
view
returns (
uint128 liquidityGross,
int128 liquidityNet,
uint256 feeGrowthOutside0X128,
uint256 feeGrowthOutside1X128,
int56 tickCumulativeOutside,
uint160 secondsPerLiquidityOutsideX128,
uint32 secondsOutside,
bool initialized
);
function tickBitmap(int16 wordPosition) external view returns (uint256);
function positions(bytes32 key)
external
view
returns (
uint128 _liquidity,
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128,
uint128 tokensOwed0,
uint128 tokensOwed1
);
function observations(uint256 index)
external
view
returns (
uint32 blockTimestamp,
int56 tickCumulative,
uint160 secondsPerLiquidityCumulativeX128,
bool initialized
);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title BitMath
/// @dev This library provides functionality for computing bit properties of an unsigned integer
library BitMath {
/// @notice Returns the index of the most significant bit of the number,
/// where the least significant bit is at index 0 and the most significant bit is at index 255
/// @dev The function satisfies the property:
/// x >= 2**mostSignificantBit(x) and x < 2**(mostSignificantBit(x)+1)
/// @param x the value for which to compute the most significant bit, must be greater than 0
/// @return r the index of the most significant bit
function mostSignificantBit(uint256 x) internal pure returns (uint8 r) {
require(x > 0);
if (x >= 0x100000000000000000000000000000000) {
x >>= 128;
r += 128;
}
if (x >= 0x10000000000000000) {
x >>= 64;
r += 64;
}
if (x >= 0x100000000) {
x >>= 32;
r += 32;
}
if (x >= 0x10000) {
x >>= 16;
r += 16;
}
if (x >= 0x100) {
x >>= 8;
r += 8;
}
if (x >= 0x10) {
x >>= 4;
r += 4;
}
if (x >= 0x4) {
x >>= 2;
r += 2;
}
if (x >= 0x2) r += 1;
}
/// @notice Returns the index of the least significant bit of the number,
/// where the least significant bit is at index 0 and the most significant bit is at index 255
/// @dev The function satisfies the property:
/// (x & 2**leastSignificantBit(x)) != 0 and (x & (2**(leastSignificantBit(x)) - 1)) == 0)
/// @param x the value for which to compute the least significant bit, must be greater than 0
/// @return r the index of the least significant bit
function leastSignificantBit(uint256 x) internal pure returns (uint8 r) {
require(x > 0);
r = 255;
if (x & type(uint128).max > 0) {
r -= 128;
} else {
x >>= 128;
}
if (x & type(uint64).max > 0) {
r -= 64;
} else {
x >>= 64;
}
if (x & type(uint32).max > 0) {
r -= 32;
} else {
x >>= 32;
}
if (x & type(uint16).max > 0) {
r -= 16;
} else {
x >>= 16;
}
if (x & type(uint8).max > 0) {
r -= 8;
} else {
x >>= 8;
}
if (x & 0xf > 0) {
r -= 4;
} else {
x >>= 4;
}
if (x & 0x3 > 0) {
r -= 2;
} else {
x >>= 2;
}
if (x & 0x1 > 0) r -= 1;
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.4.0;
/// @title FixedPoint128
/// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format)
library FixedPoint128 {
uint256 internal constant Q128 = 0x100000000000000000000000000000000;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.4.0;
/// @title FixedPoint96
/// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format)
/// @dev Used in SqrtPriceMath.sol
library FixedPoint96 {
uint8 internal constant RESOLUTION = 96;
uint256 internal constant Q96 = 0x1000000000000000000000000;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.4.0 <0.8.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; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(a, b, not(0))
prod0 := mul(a, b)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division
if (prod1 == 0) {
require(denominator > 0);
assembly {
result := div(prod0, denominator)
}
return result;
}
// Make sure the result is less than 2**256.
// Also prevents denominator == 0
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0]
// Compute remainder using mulmod
uint256 remainder;
assembly {
remainder := mulmod(a, b, denominator)
}
// Subtract 256 bit number from 512 bit number
assembly {
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 precoditions 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) {
result = mulDiv(a, b, denominator);
if (mulmod(a, b, denominator) > 0) {
require(result < type(uint256).max);
result++;
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Math library for liquidity
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
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));
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0 <0.8.0;
/// @title Oracle
/// @notice Provides price and liquidity data useful for a wide variety of system designs
/// @dev Instances of stored oracle data, "observations", are collected in the oracle array
/// Every pool is initialized with an oracle array length of 1. Anyone can pay the SSTOREs to increase the
/// maximum length of the oracle array. New slots will be added when the array is fully populated.
/// Observations are overwritten when the full length of the oracle array is populated.
/// The most recent observation is available, independent of the length of the oracle array, by passing 0 to observe()
library Oracle {
struct Observation {
// the block timestamp of the observation
uint32 blockTimestamp;
// the tick accumulator, i.e. tick * time elapsed since the pool was first initialized
int56 tickCumulative;
// the seconds per liquidity, i.e. seconds elapsed / max(1, liquidity) since the pool was first initialized
uint160 secondsPerLiquidityCumulativeX128;
// whether or not the observation is initialized
bool initialized;
}
/// @notice Transforms a previous observation into a new observation, given the passage of time and the current tick and liquidity values
/// @dev blockTimestamp _must_ be chronologically equal to or greater than last.blockTimestamp, safe for 0 or 1 overflows
/// @param last The specified observation to be transformed
/// @param blockTimestamp The timestamp of the new observation
/// @param tick The active tick at the time of the new observation
/// @param liquidity The total in-range liquidity at the time of the new observation
/// @return Observation The newly populated observation
function transform(
Observation memory last,
uint32 blockTimestamp,
int24 tick,
uint128 liquidity
) private pure returns (Observation memory) {
uint32 delta = blockTimestamp - last.blockTimestamp;
return
Observation({
blockTimestamp: blockTimestamp,
tickCumulative: last.tickCumulative + int56(tick) * delta,
secondsPerLiquidityCumulativeX128: last.secondsPerLiquidityCumulativeX128 +
((uint160(delta) << 128) / (liquidity > 0 ? liquidity : 1)),
initialized: true
});
}
/// @notice Initialize the oracle array by writing the first slot. Called once for the lifecycle of the observations array
/// @param self The stored oracle array
/// @param time The time of the oracle initialization, via block.timestamp truncated to uint32
/// @return cardinality The number of populated elements in the oracle array
/// @return cardinalityNext The new length of the oracle array, independent of population
function initialize(Observation[65535] storage self, uint32 time)
internal
returns (uint16 cardinality, uint16 cardinalityNext)
{
self[0] = Observation({
blockTimestamp: time,
tickCumulative: 0,
secondsPerLiquidityCumulativeX128: 0,
initialized: true
});
return (1, 1);
}
/// @notice Writes an oracle observation to the array
/// @dev Writable at most once per block. Index represents the most recently written element. cardinality and index must be tracked externally.
/// If the index is at the end of the allowable array length (according to cardinality), and the next cardinality
/// is greater than the current one, cardinality may be increased. This restriction is created to preserve ordering.
/// @param self The stored oracle array
/// @param index The index of the observation that was most recently written to the observations array
/// @param blockTimestamp The timestamp of the new observation
/// @param tick The active tick at the time of the new observation
/// @param liquidity The total in-range liquidity at the time of the new observation
/// @param cardinality The number of populated elements in the oracle array
/// @param cardinalityNext The new length of the oracle array, independent of population
/// @return indexUpdated The new index of the most recently written element in the oracle array
/// @return cardinalityUpdated The new cardinality of the oracle array
function write(
Observation[65535] storage self,
uint16 index,
uint32 blockTimestamp,
int24 tick,
uint128 liquidity,
uint16 cardinality,
uint16 cardinalityNext
) internal returns (uint16 indexUpdated, uint16 cardinalityUpdated) {
Observation memory last = self[index];
// early return if we've already written an observation this block
if (last.blockTimestamp == blockTimestamp) return (index, cardinality);
// if the conditions are right, we can bump the cardinality
if (cardinalityNext > cardinality && index == (cardinality - 1)) {
cardinalityUpdated = cardinalityNext;
} else {
cardinalityUpdated = cardinality;
}
indexUpdated = (index + 1) % cardinalityUpdated;
self[indexUpdated] = transform(last, blockTimestamp, tick, liquidity);
}
/// @notice Prepares the oracle array to store up to `next` observations
/// @param self The stored oracle array
/// @param current The current next cardinality of the oracle array
/// @param next The proposed next cardinality which will be populated in the oracle array
/// @return next The next cardinality which will be populated in the oracle array
function grow(
Observation[65535] storage self,
uint16 current,
uint16 next
) internal returns (uint16) {
require(current > 0, 'I');
// no-op if the passed next value isn't greater than the current next value
if (next <= current) return current;
// store in each slot to prevent fresh SSTOREs in swaps
// this data will not be used because the initialized boolean is still false
for (uint16 i = current; i < next; i++) self[i].blockTimestamp = 1;
return next;
}
/// @notice comparator for 32-bit timestamps
/// @dev safe for 0 or 1 overflows, a and b _must_ be chronologically before or equal to time
/// @param time A timestamp truncated to 32 bits
/// @param a A comparison timestamp from which to determine the relative position of `time`
/// @param b From which to determine the relative position of `time`
/// @return bool Whether `a` is chronologically <= `b`
function lte(
uint32 time,
uint32 a,
uint32 b
) private pure returns (bool) {
// if there hasn't been overflow, no need to adjust
if (a <= time && b <= time) return a <= b;
uint256 aAdjusted = a > time ? a : a + 2 ** 32;
uint256 bAdjusted = b > time ? b : b + 2 ** 32;
return aAdjusted <= bAdjusted;
}
/// @notice Fetches the observations beforeOrAt and atOrAfter a target, i.e. where [beforeOrAt, atOrAfter] is satisfied.
/// The result may be the same observation, or adjacent observations.
/// @dev The answer must be contained in the array, used when the target is located within the stored observation
/// boundaries: older than the most recent observation and younger, or the same age as, the oldest observation
/// @param self The stored oracle array
/// @param time The current block.timestamp
/// @param target The timestamp at which the reserved observation should be for
/// @param index The index of the observation that was most recently written to the observations array
/// @param cardinality The number of populated elements in the oracle array
/// @return beforeOrAt The observation recorded before, or at, the target
/// @return atOrAfter The observation recorded at, or after, the target
function binarySearch(
Observation[65535] storage self,
uint32 time,
uint32 target,
uint16 index,
uint16 cardinality
) private view returns (Observation memory beforeOrAt, Observation memory atOrAfter) {
uint256 l = (index + 1) % cardinality; // oldest observation
uint256 r = l + cardinality - 1; // newest observation
uint256 i;
while (true) {
i = (l + r) / 2;
beforeOrAt = self[i % cardinality];
// we've landed on an uninitialized tick, keep searching higher (more recently)
if (!beforeOrAt.initialized) {
l = i + 1;
continue;
}
atOrAfter = self[(i + 1) % cardinality];
bool targetAtOrAfter = lte(time, beforeOrAt.blockTimestamp, target);
// check if we've found the answer!
if (targetAtOrAfter && lte(time, target, atOrAfter.blockTimestamp)) break;
if (!targetAtOrAfter) r = i - 1;
else l = i + 1;
}
}
/// @notice Fetches the observations beforeOrAt and atOrAfter a given target, i.e. where [beforeOrAt, atOrAfter] is satisfied
/// @dev Assumes there is at least 1 initialized observation.
/// Used by observeSingle() to compute the counterfactual accumulator values as of a given block timestamp.
/// @param self The stored oracle array
/// @param time The current block.timestamp
/// @param target The timestamp at which the reserved observation should be for
/// @param tick The active tick at the time of the returned or simulated observation
/// @param index The index of the observation that was most recently written to the observations array
/// @param liquidity The total pool liquidity at the time of the call
/// @param cardinality The number of populated elements in the oracle array
/// @return beforeOrAt The observation which occurred at, or before, the given timestamp
/// @return atOrAfter The observation which occurred at, or after, the given timestamp
function getSurroundingObservations(
Observation[65535] storage self,
uint32 time,
uint32 target,
int24 tick,
uint16 index,
uint128 liquidity,
uint16 cardinality
) private view returns (Observation memory beforeOrAt, Observation memory atOrAfter) {
// optimistically set before to the newest observation
beforeOrAt = self[index];
// if the target is chronologically at or after the newest observation, we can early return
if (lte(time, beforeOrAt.blockTimestamp, target)) {
if (beforeOrAt.blockTimestamp == target) {
// if newest observation equals target, we're in the same block, so we can ignore atOrAfter
return (beforeOrAt, atOrAfter);
} else {
// otherwise, we need to transform
return (beforeOrAt, transform(beforeOrAt, target, tick, liquidity));
}
}
// now, set before to the oldest observation
beforeOrAt = self[(index + 1) % cardinality];
if (!beforeOrAt.initialized) beforeOrAt = self[0];
// ensure that the target is chronologically at or after the oldest observation
require(lte(time, beforeOrAt.blockTimestamp, target), 'OLD');
// if we've reached this point, we have to binary search
return binarySearch(self, time, target, index, cardinality);
}
/// @dev Reverts if an observation at or before the desired observation timestamp does not exist.
/// 0 may be passed as `secondsAgo' to return the current cumulative values.
/// If called with a timestamp falling between two observations, returns the counterfactual accumulator values
/// at exactly the timestamp between the two observations.
/// @param self The stored oracle array
/// @param time The current block timestamp
/// @param secondsAgo The amount of time to look back, in seconds, at which point to return an observation
/// @param tick The current tick
/// @param index The index of the observation that was most recently written to the observations array
/// @param liquidity The current in-range pool liquidity
/// @param cardinality The number of populated elements in the oracle array
/// @return tickCumulative The tick * time elapsed since the pool was first initialized, as of `secondsAgo`
/// @return secondsPerLiquidityCumulativeX128 The time elapsed / max(1, liquidity) since the pool was first initialized, as of `secondsAgo`
function observeSingle(
Observation[65535] storage self,
uint32 time,
uint32 secondsAgo,
int24 tick,
uint16 index,
uint128 liquidity,
uint16 cardinality
) internal view returns (int56 tickCumulative, uint160 secondsPerLiquidityCumulativeX128) {
if (secondsAgo == 0) {
Observation memory last = self[index];
if (last.blockTimestamp != time) last = transform(last, time, tick, liquidity);
return (last.tickCumulative, last.secondsPerLiquidityCumulativeX128);
}
uint32 target = time - secondsAgo;
(Observation memory beforeOrAt, Observation memory atOrAfter) = getSurroundingObservations(
self,
time,
target,
tick,
index,
liquidity,
cardinality
);
if (target == beforeOrAt.blockTimestamp) {
// we're at the left boundary
return (beforeOrAt.tickCumulative, beforeOrAt.secondsPerLiquidityCumulativeX128);
} else if (target == atOrAfter.blockTimestamp) {
// we're at the right boundary
return (atOrAfter.tickCumulative, atOrAfter.secondsPerLiquidityCumulativeX128);
} else {
// we're in the middle
uint32 observationTimeDelta = atOrAfter.blockTimestamp - beforeOrAt.blockTimestamp;
uint32 targetDelta = target - beforeOrAt.blockTimestamp;
return (
beforeOrAt.tickCumulative +
((atOrAfter.tickCumulative - beforeOrAt.tickCumulative) / observationTimeDelta) *
targetDelta,
beforeOrAt.secondsPerLiquidityCumulativeX128 +
uint160(
(uint256(
atOrAfter.secondsPerLiquidityCumulativeX128 - beforeOrAt.secondsPerLiquidityCumulativeX128
) * targetDelta) / observationTimeDelta
)
);
}
}
/// @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 observation
/// @param self The stored oracle array
/// @param time The current block.timestamp
/// @param secondsAgos Each amount of time to look back, in seconds, at which point to return an observation
/// @param tick The current tick
/// @param index The index of the observation that was most recently written to the observations array
/// @param liquidity The current in-range pool liquidity
/// @param cardinality The number of populated elements in the oracle array
/// @return tickCumulatives The tick * time elapsed since the pool was first initialized, as of each `secondsAgo`
/// @return secondsPerLiquidityCumulativeX128s The cumulative seconds / max(1, liquidity) since the pool was first initialized, as of each `secondsAgo`
function observe(
Observation[65535] storage self,
uint32 time,
uint32[] memory secondsAgos,
int24 tick,
uint16 index,
uint128 liquidity,
uint16 cardinality
) internal view returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s) {
require(cardinality > 0, 'I');
tickCumulatives = new int56[](secondsAgos.length);
secondsPerLiquidityCumulativeX128s = new uint160[](secondsAgos.length);
for (uint256 i = 0; i < secondsAgos.length; i++) {
(tickCumulatives[i], secondsPerLiquidityCumulativeX128s[i]) = observeSingle(
self,
time,
secondsAgos[i],
tick,
index,
liquidity,
cardinality
);
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0 <0.8.0;
import './FullMath.sol';
import './FixedPoint128.sol';
import './LiquidityMath.sol';
/// @title Position
/// @notice Positions represent an owner address' liquidity between a lower and upper tick boundary
/// @dev Positions store additional state for tracking fees owed to the position
library Position {
// info stored for each user's position
struct Info {
// the amount of liquidity owned by this position
uint128 liquidity;
// fee growth per unit of liquidity as of the last update to liquidity or fees owed
uint256 feeGrowthInside0LastX128;
uint256 feeGrowthInside1LastX128;
// the fees owed to the position owner in token0/token1
uint128 tokensOwed0;
uint128 tokensOwed1;
}
/// @notice Returns the Info struct of a position, given an owner and position boundaries
/// @param self The mapping containing all user positions
/// @param owner The address of the position owner
/// @param tickLower The lower tick boundary of the position
/// @param tickUpper The upper tick boundary of the position
/// @return position The position info struct of the given owners' position
function get(
mapping(bytes32 => Info) storage self,
address owner,
int24 tickLower,
int24 tickUpper
) internal view returns (Position.Info storage position) {
position = self[keccak256(abi.encodePacked(owner, tickLower, tickUpper))];
}
/// @notice Credits accumulated fees to a user's position
/// @param self The individual position to update
/// @param liquidityDelta The change in pool liquidity as a result of the position update
/// @param feeGrowthInside0X128 The all-time fee growth in token0, per unit of liquidity, inside the position's tick boundaries
/// @param feeGrowthInside1X128 The all-time fee growth in token1, per unit of liquidity, inside the position's tick boundaries
function update(
Info storage self,
int128 liquidityDelta,
uint256 feeGrowthInside0X128,
uint256 feeGrowthInside1X128
) internal {
Info memory _self = self;
uint128 liquidityNext;
if (liquidityDelta == 0) {
require(_self.liquidity > 0, 'NP'); // disallow pokes for 0 liquidity positions
liquidityNext = _self.liquidity;
} else {
liquidityNext = LiquidityMath.addDelta(_self.liquidity, liquidityDelta);
}
// calculate accumulated fees
uint128 tokensOwed0 = uint128(
FullMath.mulDiv(feeGrowthInside0X128 - _self.feeGrowthInside0LastX128, _self.liquidity, FixedPoint128.Q128)
);
uint128 tokensOwed1 = uint128(
FullMath.mulDiv(feeGrowthInside1X128 - _self.feeGrowthInside1LastX128, _self.liquidity, FixedPoint128.Q128)
);
// update the position
if (liquidityDelta != 0) self.liquidity = liquidityNext;
self.feeGrowthInside0LastX128 = feeGrowthInside0X128;
self.feeGrowthInside1LastX128 = feeGrowthInside1X128;
if (tokensOwed0 > 0 || tokensOwed1 > 0) {
// overflow is acceptable, have to withdraw before you hit type(uint128).max fees
self.tokensOwed0 += tokensOwed0;
self.tokensOwed1 += tokensOwed1;
}
}
}// 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
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: GPL-2.0-or-later
pragma solidity >=0.5.0;
import './LowGasSafeMath.sol';
import './SafeCast.sol';
import './FullMath.sol';
import './UnsafeMath.sol';
import './FixedPoint96.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 SqrtPriceMath {
using LowGasSafeMath for uint256;
using SafeCast for uint256;
/// @notice Gets the next sqrt price given a delta of token0
/// @dev Always rounds up, because in the exact output case (increasing price) we need to move the price at least
/// far enough to get the desired output amount, and in the exact input case (decreasing price) we need to move the
/// price less in order to not send too much output.
/// The most precise formula for this is liquidity * sqrtPX96 / (liquidity +- amount * sqrtPX96),
/// if this is impossible because of overflow, we calculate liquidity / (liquidity / sqrtPX96 +- amount).
/// @param sqrtPX96 The starting price, i.e. before accounting for the token0 delta
/// @param liquidity The amount of usable liquidity
/// @param amount How much of token0 to add or remove from virtual reserves
/// @param add Whether to add or remove the amount of token0
/// @return The price after adding or removing amount, depending on add
function getNextSqrtPriceFromAmount0RoundingUp(
uint160 sqrtPX96,
uint128 liquidity,
uint256 amount,
bool add
) internal pure returns (uint160) {
// we short circuit amount == 0 because the result is otherwise not guaranteed to equal the input price
if (amount == 0) return sqrtPX96;
uint256 numerator1 = uint256(liquidity) << FixedPoint96.RESOLUTION;
if (add) {
uint256 product;
if ((product = amount * sqrtPX96) / amount == sqrtPX96) {
uint256 denominator = numerator1 + product;
if (denominator >= numerator1)
// always fits in 160 bits
return uint160(FullMath.mulDivRoundingUp(numerator1, sqrtPX96, denominator));
}
return uint160(UnsafeMath.divRoundingUp(numerator1, (numerator1 / sqrtPX96).add(amount)));
} else {
uint256 product;
// if the product overflows, we know the denominator underflows
// in addition, we must check that the denominator does not underflow
require((product = amount * sqrtPX96) / amount == sqrtPX96 && numerator1 > product);
uint256 denominator = numerator1 - product;
return FullMath.mulDivRoundingUp(numerator1, sqrtPX96, denominator).toUint160();
}
}
/// @notice Gets the next sqrt price given a delta of token1
/// @dev Always rounds down, because in the exact output case (decreasing price) we need to move the price at least
/// far enough to get the desired output amount, and in the exact input case (increasing price) we need to move the
/// price less in order to not send too much output.
/// The formula we compute is within <1 wei of the lossless version: sqrtPX96 +- amount / liquidity
/// @param sqrtPX96 The starting price, i.e., before accounting for the token1 delta
/// @param liquidity The amount of usable liquidity
/// @param amount How much of token1 to add, or remove, from virtual reserves
/// @param add Whether to add, or remove, the amount of token1
/// @return The price after adding or removing `amount`
function getNextSqrtPriceFromAmount1RoundingDown(
uint160 sqrtPX96,
uint128 liquidity,
uint256 amount,
bool add
) internal pure returns (uint160) {
// if we're adding (subtracting), rounding down requires rounding the quotient down (up)
// in both cases, avoid a mulDiv for most inputs
if (add) {
uint256 quotient = (
amount <= type(uint160).max
? (amount << FixedPoint96.RESOLUTION) / liquidity
: FullMath.mulDiv(amount, FixedPoint96.Q96, liquidity)
);
return uint256(sqrtPX96).add(quotient).toUint160();
} else {
uint256 quotient = (
amount <= type(uint160).max
? UnsafeMath.divRoundingUp(amount << FixedPoint96.RESOLUTION, liquidity)
: FullMath.mulDivRoundingUp(amount, FixedPoint96.Q96, liquidity)
);
require(sqrtPX96 > quotient);
// always fits 160 bits
return uint160(sqrtPX96 - quotient);
}
}
/// @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 sqrtPX96 The starting price, i.e., before accounting for the input amount
/// @param liquidity The amount of usable liquidity
/// @param amountIn How much of token0, or token1, is being swapped in
/// @param zeroForOne Whether the amount in is token0 or token1
/// @return sqrtQX96 The price after adding the input amount to token0 or token1
function getNextSqrtPriceFromInput(
uint160 sqrtPX96,
uint128 liquidity,
uint256 amountIn,
bool zeroForOne
) internal pure returns (uint160 sqrtQX96) {
require(sqrtPX96 > 0);
require(liquidity > 0);
// round to make sure that we don't pass the target price
return
zeroForOne
? getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountIn, true)
: getNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountIn, 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 sqrtPX96 The starting price before accounting for the output amount
/// @param liquidity The amount of usable liquidity
/// @param amountOut How much of token0, or token1, is being swapped out
/// @param zeroForOne Whether the amount out is token0 or token1
/// @return sqrtQX96 The price after removing the output amount of token0 or token1
function getNextSqrtPriceFromOutput(
uint160 sqrtPX96,
uint128 liquidity,
uint256 amountOut,
bool zeroForOne
) internal pure returns (uint160 sqrtQX96) {
require(sqrtPX96 > 0);
require(liquidity > 0);
// round to make sure that we pass the target price
return
zeroForOne
? getNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountOut, false)
: getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountOut, false);
}
/// @notice Gets the amount0 delta between two prices
/// @dev Calculates liquidity / sqrt(lower) - liquidity / sqrt(upper),
/// i.e. liquidity * (sqrt(upper) - sqrt(lower)) / (sqrt(upper) * sqrt(lower))
/// @param sqrtRatioAX96 A sqrt price
/// @param sqrtRatioBX96 Another sqrt price
/// @param liquidity The amount of usable liquidity
/// @param roundUp Whether to round the amount up or down
/// @return amount0 Amount of token0 required to cover a position of size liquidity between the two passed prices
function getAmount0Delta(
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint128 liquidity,
bool roundUp
) internal pure returns (uint256 amount0) {
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
uint256 numerator1 = uint256(liquidity) << FixedPoint96.RESOLUTION;
uint256 numerator2 = sqrtRatioBX96 - sqrtRatioAX96;
require(sqrtRatioAX96 > 0);
return
roundUp
? UnsafeMath.divRoundingUp(
FullMath.mulDivRoundingUp(numerator1, numerator2, sqrtRatioBX96),
sqrtRatioAX96
)
: FullMath.mulDiv(numerator1, numerator2, sqrtRatioBX96) / sqrtRatioAX96;
}
/// @notice Gets the amount1 delta between two prices
/// @dev Calculates liquidity * (sqrt(upper) - sqrt(lower))
/// @param sqrtRatioAX96 A sqrt price
/// @param sqrtRatioBX96 Another sqrt price
/// @param liquidity The amount of usable liquidity
/// @param roundUp Whether to round the amount up, or down
/// @return amount1 Amount of token1 required to cover a position of size liquidity between the two passed prices
function getAmount1Delta(
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint128 liquidity,
bool roundUp
) internal pure returns (uint256 amount1) {
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
return
roundUp
? FullMath.mulDivRoundingUp(liquidity, sqrtRatioBX96 - sqrtRatioAX96, FixedPoint96.Q96)
: FullMath.mulDiv(liquidity, sqrtRatioBX96 - sqrtRatioAX96, FixedPoint96.Q96);
}
/// @notice Helper that gets signed token0 delta
/// @param sqrtRatioAX96 A sqrt price
/// @param sqrtRatioBX96 Another sqrt price
/// @param liquidity The change in liquidity for which to compute the amount0 delta
/// @return amount0 Amount of token0 corresponding to the passed liquidityDelta between the two prices
function getAmount0Delta(
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
int128 liquidity
) internal pure returns (int256 amount0) {
return
liquidity < 0
? - getAmount0Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(- liquidity), false).toInt256()
: getAmount0Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(liquidity), true).toInt256();
}
/// @notice Helper that gets signed token1 delta
/// @param sqrtRatioAX96 A sqrt price
/// @param sqrtRatioBX96 Another sqrt price
/// @param liquidity The change in liquidity for which to compute the amount1 delta
/// @return amount1 Amount of token1 corresponding to the passed liquidityDelta between the two prices
function getAmount1Delta(
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
int128 liquidity
) internal pure returns (int256 amount1) {
return
liquidity < 0
? - getAmount1Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(- liquidity), false).toInt256()
: getAmount1Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(liquidity), true).toInt256();
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import './FullMath.sol';
import './SqrtPriceMath.sol';
/// @title Computes the result of a swap within ticks
/// @notice Contains methods for computing the result of a swap within a single tick price range, i.e., a single tick.
library SwapMath {
/// @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 sqrtRatioCurrentX96 The current sqrt price of the pool
/// @param sqrtRatioTargetX96 The price that cannot be exceeded, from which the direction of the swap is inferred
/// @param liquidity The usable liquidity
/// @param amountRemaining How much input or output amount is remaining to be swapped in/out
/// @param feePips The fee taken from the input amount, expressed in hundredths of a bip
/// @return sqrtRatioNextX96 The price after swapping the amount in/out, not to exceed the price target
/// @return amountIn The amount to be swapped in, of either token0 or token1, based on the direction of the swap
/// @return amountOut 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 computeSwapStep(
uint160 sqrtRatioCurrentX96,
uint160 sqrtRatioTargetX96,
uint128 liquidity,
int256 amountRemaining,
uint24 feePips
)
internal
pure
returns (
uint160 sqrtRatioNextX96,
uint256 amountIn,
uint256 amountOut,
uint256 feeAmount
)
{
bool zeroForOne = sqrtRatioCurrentX96 >= sqrtRatioTargetX96;
bool exactIn = amountRemaining >= 0;
if (exactIn) {
uint256 amountRemainingLessFee = FullMath.mulDiv(uint256(amountRemaining), 1e6 - feePips, 1e6);
amountIn = zeroForOne
? SqrtPriceMath.getAmount0Delta(sqrtRatioTargetX96, sqrtRatioCurrentX96, liquidity, true)
: SqrtPriceMath.getAmount1Delta(sqrtRatioCurrentX96, sqrtRatioTargetX96, liquidity, true);
if (amountRemainingLessFee >= amountIn) sqrtRatioNextX96 = sqrtRatioTargetX96;
else
sqrtRatioNextX96 = SqrtPriceMath.getNextSqrtPriceFromInput(
sqrtRatioCurrentX96,
liquidity,
amountRemainingLessFee,
zeroForOne
);
} else {
amountOut = zeroForOne
? SqrtPriceMath.getAmount1Delta(sqrtRatioTargetX96, sqrtRatioCurrentX96, liquidity, false)
: SqrtPriceMath.getAmount0Delta(sqrtRatioCurrentX96, sqrtRatioTargetX96, liquidity, false);
if (uint256(- amountRemaining) >= amountOut) sqrtRatioNextX96 = sqrtRatioTargetX96;
else
sqrtRatioNextX96 = SqrtPriceMath.getNextSqrtPriceFromOutput(
sqrtRatioCurrentX96,
liquidity,
uint256(- amountRemaining),
zeroForOne
);
}
bool max = sqrtRatioTargetX96 == sqrtRatioNextX96;
// get the input/output amounts
if (zeroForOne) {
amountIn = max && exactIn
? amountIn
: SqrtPriceMath.getAmount0Delta(sqrtRatioNextX96, sqrtRatioCurrentX96, liquidity, true);
amountOut = max && !exactIn
? amountOut
: SqrtPriceMath.getAmount1Delta(sqrtRatioNextX96, sqrtRatioCurrentX96, liquidity, false);
} else {
amountIn = max && exactIn
? amountIn
: SqrtPriceMath.getAmount1Delta(sqrtRatioCurrentX96, sqrtRatioNextX96, liquidity, true);
amountOut = max && !exactIn
? amountOut
: SqrtPriceMath.getAmount0Delta(sqrtRatioCurrentX96, sqrtRatioNextX96, liquidity, false);
}
// cap the output amount to not exceed the remaining output amount
if (!exactIn && amountOut > uint256(- amountRemaining)) {
amountOut = uint256(- amountRemaining);
}
if (exactIn && sqrtRatioNextX96 != sqrtRatioTargetX96) {
// we didn't reach the target, so take the remainder of the maximum input as fee
feeAmount = uint256(amountRemaining) - amountIn;
} else {
feeAmount = FullMath.mulDivRoundingUp(amountIn, feePips, 1e6 - feePips);
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0 <0.8.0;
import './LowGasSafeMath.sol';
import './SafeCast.sol';
import './TickMath.sol';
import './LiquidityMath.sol';
/// @title Tick
/// @notice Contains functions for managing tick processes and relevant calculations
library Tick {
using LowGasSafeMath for int256;
using SafeCast for int256;
// info stored for each initialized individual tick
struct Info {
// the total position liquidity that references this tick
uint128 liquidityGross;
// amount of net liquidity added (subtracted) when tick is crossed from left to right (right to left),
int128 liquidityNet;
// 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 feeGrowthOutside0X128;
uint256 feeGrowthOutside1X128;
// the cumulative tick value on the other side of the tick
int56 tickCumulativeOutside;
// the seconds 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
uint160 secondsPerLiquidityOutsideX128;
// the seconds spent on the other side of the tick (relative to the current tick)
// only has relative meaning, not absolute — the value depends on when the tick is initialized
uint32 secondsOutside;
// true iff the tick is initialized, i.e. the value is exactly equivalent to the expression liquidityGross != 0
// these 8 bits are set to prevent fresh sstores when crossing newly initialized ticks
bool initialized;
}
/// @notice Derives max liquidity per tick from given tick spacing
/// @dev Executed within the pool constructor
/// @param tickSpacing The amount of required tick separation, realized in multiples of `tickSpacing`
/// e.g., a tickSpacing of 3 requires ticks to be initialized every 3rd tick i.e., ..., -6, -3, 0, 3, 6, ...
/// @return The max liquidity per tick
function tickSpacingToMaxLiquidityPerTick(int24 tickSpacing) internal pure returns (uint128) {
int24 minTick = (TickMath.MIN_TICK / tickSpacing) * tickSpacing;
int24 maxTick = (TickMath.MAX_TICK / tickSpacing) * tickSpacing;
uint24 numTicks = uint24((maxTick - minTick) / tickSpacing) + 1;
return type(uint128).max / numTicks;
}
/// @notice Retrieves fee growth data
/// @param self The mapping containing all tick information for initialized ticks
/// @param tickLower The lower tick boundary of the position
/// @param tickUpper The upper tick boundary of the position
/// @param tickCurrent The current tick
/// @param feeGrowthGlobal0X128 The all-time global fee growth, per unit of liquidity, in token0
/// @param feeGrowthGlobal1X128 The all-time global fee growth, per unit of liquidity, in token1
/// @return feeGrowthInside0X128 The all-time fee growth in token0, per unit of liquidity, inside the position's tick boundaries
/// @return feeGrowthInside1X128 The all-time fee growth in token1, per unit of liquidity, inside the position's tick boundaries
function getFeeGrowthInside(
mapping(int24 => Tick.Info) storage self,
int24 tickLower,
int24 tickUpper,
int24 tickCurrent,
uint256 feeGrowthGlobal0X128,
uint256 feeGrowthGlobal1X128
) internal view returns (uint256 feeGrowthInside0X128, uint256 feeGrowthInside1X128) {
Info storage lower = self[tickLower];
Info storage upper = self[tickUpper];
// calculate fee growth below
uint256 feeGrowthBelow0X128;
uint256 feeGrowthBelow1X128;
if (tickCurrent >= tickLower) {
feeGrowthBelow0X128 = lower.feeGrowthOutside0X128;
feeGrowthBelow1X128 = lower.feeGrowthOutside1X128;
} else {
feeGrowthBelow0X128 = feeGrowthGlobal0X128 - lower.feeGrowthOutside0X128;
feeGrowthBelow1X128 = feeGrowthGlobal1X128 - lower.feeGrowthOutside1X128;
}
// calculate fee growth above
uint256 feeGrowthAbove0X128;
uint256 feeGrowthAbove1X128;
if (tickCurrent < tickUpper) {
feeGrowthAbove0X128 = upper.feeGrowthOutside0X128;
feeGrowthAbove1X128 = upper.feeGrowthOutside1X128;
} else {
feeGrowthAbove0X128 = feeGrowthGlobal0X128 - upper.feeGrowthOutside0X128;
feeGrowthAbove1X128 = feeGrowthGlobal1X128 - upper.feeGrowthOutside1X128;
}
feeGrowthInside0X128 = feeGrowthGlobal0X128 - feeGrowthBelow0X128 - feeGrowthAbove0X128;
feeGrowthInside1X128 = feeGrowthGlobal1X128 - feeGrowthBelow1X128 - feeGrowthAbove1X128;
}
/// @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 tickCurrent 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 feeGrowthGlobal0X128 The all-time global fee growth, per unit of liquidity, in token0
/// @param feeGrowthGlobal1X128 The all-time global fee growth, per unit of liquidity, in token1
/// @param secondsPerLiquidityCumulativeX128 The all-time seconds per max(1, liquidity) of the pool
/// @param tickCumulative The tick * time elapsed since the pool was first initialized
/// @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
/// @param maxLiquidity The maximum liquidity allocation for a single tick
/// @return flipped Whether the tick was flipped from initialized to uninitialized, or vice versa
function update(
mapping(int24 => Tick.Info) storage self,
int24 tick,
int24 tickCurrent,
int128 liquidityDelta,
uint256 feeGrowthGlobal0X128,
uint256 feeGrowthGlobal1X128,
uint160 secondsPerLiquidityCumulativeX128,
int56 tickCumulative,
uint32 time,
bool upper,
uint128 maxLiquidity
) internal returns (bool flipped) {
Tick.Info storage info = self[tick];
uint128 liquidityGrossBefore = info.liquidityGross;
uint128 liquidityGrossAfter = LiquidityMath.addDelta(liquidityGrossBefore, liquidityDelta);
require(liquidityGrossAfter <= maxLiquidity, 'LO');
flipped = (liquidityGrossAfter == 0) != (liquidityGrossBefore == 0);
if (liquidityGrossBefore == 0) {
// by convention, we assume that all growth before a tick was initialized happened _below_ the tick
if (tick <= tickCurrent) {
info.feeGrowthOutside0X128 = feeGrowthGlobal0X128;
info.feeGrowthOutside1X128 = feeGrowthGlobal1X128;
info.secondsPerLiquidityOutsideX128 = secondsPerLiquidityCumulativeX128;
info.tickCumulativeOutside = tickCumulative;
info.secondsOutside = time;
}
info.initialized = true;
}
info.liquidityGross = liquidityGrossAfter;
// when the lower (upper) tick is crossed left to right (right to left), liquidity must be added (removed)
info.liquidityNet = upper
? int256(info.liquidityNet).sub(liquidityDelta).toInt128()
: int256(info.liquidityNet).add(liquidityDelta).toInt128();
}
/// @notice Clears tick data
/// @param self The mapping containing all initialized tick information for initialized ticks
/// @param tick The tick that will be cleared
function clear(mapping(int24 => Tick.Info) storage self, int24 tick) internal {
delete self[tick];
}
/// @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 feeGrowthGlobal0X128 The all-time global fee growth, per unit of liquidity, in token0
/// @param feeGrowthGlobal1X128 The all-time global fee growth, per unit of liquidity, in token1
/// @param secondsPerLiquidityCumulativeX128 The current seconds per liquidity
/// @param tickCumulative The tick * time elapsed since the pool was first initialized
/// @param time The current block.timestamp
/// @return liquidityNet The amount of liquidity added (subtracted) when tick is crossed from left to right (right to left)
function cross(
mapping(int24 => Tick.Info) storage self,
int24 tick,
uint256 feeGrowthGlobal0X128,
uint256 feeGrowthGlobal1X128,
uint160 secondsPerLiquidityCumulativeX128,
int56 tickCumulative,
uint32 time
) internal returns (int128 liquidityNet) {
Tick.Info storage info = self[tick];
info.feeGrowthOutside0X128 = feeGrowthGlobal0X128 - info.feeGrowthOutside0X128;
info.feeGrowthOutside1X128 = feeGrowthGlobal1X128 - info.feeGrowthOutside1X128;
info.secondsPerLiquidityOutsideX128 = secondsPerLiquidityCumulativeX128 - info.secondsPerLiquidityOutsideX128;
info.tickCumulativeOutside = tickCumulative - info.tickCumulativeOutside;
info.secondsOutside = time - info.secondsOutside;
liquidityNet = info.liquidityNet;
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import './BitMath.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 TickBitmap {
/// @notice Computes the position in the mapping where the initialized bit for a tick lives
/// @param tick The tick for which to compute the position
/// @return wordPos The key in the mapping containing the word in which the bit is stored
/// @return bitPos The bit position in the word where the flag is stored
function position(int24 tick) private pure returns (int16 wordPos, uint8 bitPos) {
wordPos = int16(tick >> 8);
bitPos = uint8(tick % 256);
}
/// @notice Flips the initialized state for a given tick from false to true, or vice versa
/// @param self The mapping in which to flip the tick
/// @param tick The tick to flip
/// @param tickSpacing The spacing between usable ticks
function flipTick(
mapping(int16 => uint256) storage self,
int24 tick,
int24 tickSpacing
) internal {
require(tick % tickSpacing == 0); // ensure that the tick is spaced
(int16 wordPos, uint8 bitPos) = position(tick / tickSpacing);
uint256 mask = 1 << bitPos;
self[wordPos] ^= mask;
}
/// @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 tickSpacing The spacing between usable ticks
/// @param lte Whether to search for the next initialized tick to the left (less than or equal to the starting tick)
/// @return next 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 nextInitializedTickWithinOneWord(
mapping(int16 => uint256) storage self,
int24 tick,
int24 tickSpacing,
bool lte
) internal view returns (int24 next, bool initialized) {
int24 compressed = tick / tickSpacing;
if (tick < 0 && tick % tickSpacing != 0) compressed--; // round towards negative infinity
if (lte) {
(int16 wordPos, uint8 bitPos) = position(compressed);
// all the 1s at or to the right of the current bitPos
uint256 mask = (1 << bitPos) - 1 + (1 << bitPos);
uint256 masked = self[wordPos] & mask;
// if there are no initialized ticks to the right of or at the current tick, return rightmost in the word
initialized = masked != 0;
// overflow/underflow is possible, but prevented externally by limiting both tickSpacing and tick
next = initialized
? (compressed - int24(bitPos - BitMath.mostSignificantBit(masked))) * tickSpacing
: (compressed - int24(bitPos)) * tickSpacing;
} else {
// start from the word of the next tick, since the current tick state doesn't matter
(int16 wordPos, uint8 bitPos) = position(compressed + 1);
// all the 1s at or to the left of the bitPos
uint256 mask = ~((1 << bitPos) - 1);
uint256 masked = self[wordPos] & mask;
// if there are no initialized ticks to the left of the current tick, return leftmost in the word
initialized = masked != 0;
// overflow/underflow is possible, but prevented externally by limiting both tickSpacing and tick
next = initialized
? (compressed + 1 + int24(BitMath.leastSignificantBit(masked) - bitPos)) * tickSpacing
: (compressed + 1 + int24(type(uint8).max - bitPos)) * tickSpacing;
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0 <0.8.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
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 sqrtPriceX96 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 sqrtPriceX96) {
uint256 absTick = tick < 0 ? uint256(- int256(tick)) : uint256(int256(tick));
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
sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));
}
/// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio
/// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may
/// ever return.
/// @param sqrtPriceX96 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 sqrtPriceX96) internal pure returns (int24 tick) {
// second inequality must be < because the price can never reach the price at the max tick
require(sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, 'R');
uint256 ratio = uint256(sqrtPriceX96) << 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) <= sqrtPriceX96 ? tickHi : tickLow;
}
}// 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
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');
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Math functions that do not check inputs or outputs
/// @notice Contains methods that perform common math functions but do not do any overflow or underflow checks
library UnsafeMath {
/// @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))
}
}
}{
"evmVersion": "istanbul",
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"bytecodeHash": "none"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"int24","name":"tickLower","type":"int24"},{"indexed":true,"internalType":"int24","name":"tickUpper","type":"int24"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"int24","name":"tickLower","type":"int24"},{"indexed":true,"internalType":"int24","name":"tickUpper","type":"int24"},{"indexed":false,"internalType":"uint128","name":"amount0","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"amount1","type":"uint128"}],"name":"Collect","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint128","name":"amount0","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"amount1","type":"uint128"}],"name":"CollectProtocol","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"observationCardinalityNextOld","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"observationCardinalityNextNew","type":"uint16"}],"name":"IncreaseObservationCardinalityNext","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint160","name":"sqrtPriceX96","type":"uint160"},{"indexed":false,"internalType":"int24","name":"tick","type":"int24"}],"name":"Initialize","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"int24","name":"tickLower","type":"int24"},{"indexed":true,"internalType":"int24","name":"tickUpper","type":"int24"},{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"feeProtocol0Old","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"feeProtocol1Old","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"feeProtocol0New","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"feeProtocol1New","type":"uint32"}],"name":"SetFeeProtocol","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"int256","name":"amount0","type":"int256"},{"indexed":false,"internalType":"int256","name":"amount1","type":"int256"},{"indexed":false,"internalType":"uint160","name":"sqrtPriceX96","type":"uint160"},{"indexed":false,"internalType":"uint128","name":"liquidity","type":"uint128"},{"indexed":false,"internalType":"int24","name":"tick","type":"int24"},{"indexed":false,"internalType":"uint128","name":"protocolFeesToken0","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"protocolFeesToken1","type":"uint128"}],"name":"Swap","type":"event"},{"inputs":[{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint128","name":"amount","type":"uint128"}],"name":"burn","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_amountWETH","type":"uint256"},{"internalType":"uint256","name":"_amountUSDB","type":"uint256"}],"name":"claimYieldAll","outputs":[{"internalType":"uint256","name":"amountWETH","type":"uint256"},{"internalType":"uint256","name":"amountUSDB","type":"uint256"},{"internalType":"uint256","name":"amountGas","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint128","name":"amount0Requested","type":"uint128"},{"internalType":"uint128","name":"amount1Requested","type":"uint128"}],"name":"collect","outputs":[{"internalType":"uint128","name":"amount0","type":"uint128"},{"internalType":"uint128","name":"amount1","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"amount0Requested","type":"uint128"},{"internalType":"uint128","name":"amount1Requested","type":"uint128"}],"name":"collectProtocol","outputs":[{"internalType":"uint128","name":"amount0","type":"uint128"},{"internalType":"uint128","name":"amount1","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fee","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeGrowthGlobal0X128","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeGrowthGlobal1X128","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"observationCardinalityNext","type":"uint16"}],"name":"increaseObservationCardinalityNext","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint160","name":"sqrtPriceX96","type":"uint160"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"liquidity","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLiquidityPerTick","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"mint","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"observations","outputs":[{"internalType":"uint32","name":"blockTimestamp","type":"uint32"},{"internalType":"int56","name":"tickCumulative","type":"int56"},{"internalType":"uint160","name":"secondsPerLiquidityCumulativeX128","type":"uint160"},{"internalType":"bool","name":"initialized","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32[]","name":"secondsAgos","type":"uint32[]"}],"name":"observe","outputs":[{"internalType":"int56[]","name":"tickCumulatives","type":"int56[]"},{"internalType":"uint160[]","name":"secondsPerLiquidityCumulativeX128s","type":"uint160[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"positions","outputs":[{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint256","name":"feeGrowthInside0LastX128","type":"uint256"},{"internalType":"uint256","name":"feeGrowthInside1LastX128","type":"uint256"},{"internalType":"uint128","name":"tokensOwed0","type":"uint128"},{"internalType":"uint128","name":"tokensOwed1","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFees","outputs":[{"internalType":"uint128","name":"token0","type":"uint128"},{"internalType":"uint128","name":"token1","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"feeProtocol0","type":"uint32"},{"internalType":"uint32","name":"feeProtocol1","type":"uint32"}],"name":"setFeeProtocol","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"slot0","outputs":[{"internalType":"uint160","name":"sqrtPriceX96","type":"uint160"},{"internalType":"int24","name":"tick","type":"int24"},{"internalType":"uint16","name":"observationIndex","type":"uint16"},{"internalType":"uint16","name":"observationCardinality","type":"uint16"},{"internalType":"uint16","name":"observationCardinalityNext","type":"uint16"},{"internalType":"uint32","name":"feeProtocol","type":"uint32"},{"internalType":"bool","name":"unlocked","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"}],"name":"snapshotCumulativesInside","outputs":[{"internalType":"int56","name":"tickCumulativeInside","type":"int56"},{"internalType":"uint160","name":"secondsPerLiquidityInsideX128","type":"uint160"},{"internalType":"uint32","name":"secondsInside","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bool","name":"zeroForOne","type":"bool"},{"internalType":"int256","name":"amountSpecified","type":"int256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"swap","outputs":[{"internalType":"int256","name":"amount0","type":"int256"},{"internalType":"int256","name":"amount1","type":"int256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int16","name":"","type":"int16"}],"name":"tickBitmap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tickSpacing","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int24","name":"","type":"int24"}],"name":"ticks","outputs":[{"internalType":"uint128","name":"liquidityGross","type":"uint128"},{"internalType":"int128","name":"liquidityNet","type":"int128"},{"internalType":"uint256","name":"feeGrowthOutside0X128","type":"uint256"},{"internalType":"uint256","name":"feeGrowthOutside1X128","type":"uint256"},{"internalType":"int56","name":"tickCumulativeOutside","type":"int56"},{"internalType":"uint160","name":"secondsPerLiquidityOutsideX128","type":"uint160"},{"internalType":"uint32","name":"secondsOutside","type":"uint32"},{"internalType":"bool","name":"initialized","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token0","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token1","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
6101406040523480156200001257600080fd5b5060007343000000000000000000000000000000000000026001600160a01b0316634e606c476040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200006557600080fd5b505af11580156200007a573d6000803e3d6000fd5b5050604051631a33757d60e01b81527343000000000000000000000000000000000000039250631a33757d915060029060040180828152602001915050602060405180830381600087803b158015620000d257600080fd5b505af1158015620000e7573d6000803e3d6000fd5b505050506040513d6020811015620000fe57600080fd5b5050604051631a33757d60e01b815273430000000000000000000000000000000000000490631a33757d9060029060040180828152602001915050602060405180830381600087803b1580156200015457600080fd5b505af115801562000169573d6000803e3d6000fd5b505050506040513d60208110156200018057600080fd5b505060408051630890357360e41b81529051339163890357309160048083019260a0929190829003018186803b158015620001ba57600080fd5b505afa158015620001cf573d6000803e3d6000fd5b505050506040513d60a0811015620001e657600080fd5b50805160208083015160408401516060808601516080968701516001600160e81b031960e892831b1660e0526001600160601b031993831b841660c05293821b831660a05294901b16909352600283810b900b90911b610100529091506200025990829062002ba762000271821b17901c565b60801b6001600160801b0319166101205250620002df565b60008082600281900b620d89e719816200028757fe5b05029050600083600281900b620d89e8816200029f57fe5b0502905060008460020b83830360020b81620002b757fe5b0560010190508062ffffff166001600160801b03801681620002d557fe5b0495945050505050565b60805160601c60a05160601c60c05160601c60e05160e81c6101005160e81c6101205160801c6155bc620003b860003980611b865280614ae45280614b1b525080610ba752806127345280614b4f5280614b81525080610c96528061277c5280612a495280612a8b5280612ad25280612b1952508061117f5280611a8c5280611e0b52806127585280613e3152508061087652806112ad5280611a265280611d855280613ce8525080611c095280611c32528061228b52806122b45280612542528061256b5280612710528061287852506155bc6000f3fe608060405234801561001057600080fd5b506004361061018e5760003560e01c806385b66729116100de578063c45a015511610097578063ddca3f4311610071578063ddca3f43146107a4578063f3058399146107c4578063f30dba93146107cc578063f637731d1461084e5761018e565b8063c45a015514610775578063d0c93a7c1461077d578063d21220a71461079c5761018e565b806385b6672914610521578063883bdbfd1461055e578063a34123a714610665578063a38807f21461069f578063ad66aeb8146106fa578063b0d0d2111461074a5761018e565b80633850c7bd1161014b5780634f1eb3d8116101255780634f1eb3d81461044f578063514ea4bf146104a05780635339c296146104f957806370cf754a146105195761018e565b80633850c7bd146103395780633c8a7d8d1461039557806346141319146104355761018e565b80630dfe168114610193578063128acb08146101b75780631a686502146102645780631ad8b03b14610288578063252c09d7146102bf57806332148f6714610316575b600080fd5b61019b610874565b604080516001600160a01b039092168252519081900360200190f35b61024b600480360360a08110156101cd57600080fd5b6001600160a01b0382358116926020810135151592604082013592606083013516919081019060a081016080820135600160201b81111561020d57600080fd5b82018360208201111561021f57600080fd5b803590602001918460018302840111600160201b8311171561024057600080fd5b509092509050610898565b6040805192835260208301919091528051918290030190f35b61026c61149e565b604080516001600160801b039092168252519081900360200190f35b6102906114ad565b60405180836001600160801b03168152602001826001600160801b031681526020019250505060405180910390f35b6102dc600480360360208110156102d557600080fd5b50356114c7565b6040805163ffffffff909516855260069390930b60208501526001600160a01b039091168383015215156060830152519081900360800190f35b6103376004803603602081101561032c57600080fd5b503561ffff1661150c565b005b6103416115fe565b604080516001600160a01b03909816885260029690960b602088015261ffff9485168787015292841660608701529216608085015263ffffffff90911660a0840152151560c0830152519081900360e00190f35b61024b600480360360a08110156103ab57600080fd5b6001600160a01b03823516916020810135600290810b92604083013590910b916001600160801b036060820135169181019060a081016080820135600160201b8111156103f757600080fd5b82018360208201111561040957600080fd5b803590602001918460018302840111600160201b8311171561042a57600080fd5b509092509050611653565b61043d611911565b60408051918252519081900360200190f35b610290600480360360a081101561046557600080fd5b506001600160a01b03813516906020810135600290810b91604081013590910b906001600160801b0360608201358116916080013516611917565b6104bd600480360360208110156104b657600080fd5b5035611b35565b604080516001600160801b0396871681526020810195909552848101939093529084166060840152909216608082015290519081900360a00190f35b61043d6004803603602081101561050f57600080fd5b503560010b611b72565b61026c611b84565b6102906004803603606081101561053757600080fd5b506001600160a01b03813516906001600160801b0360208201358116916040013516611ba8565b6105cc6004803603602081101561057457600080fd5b810190602081018135600160201b81111561058e57600080fd5b8201836020820111156105a057600080fd5b803590602001918460208302840111600160201b831117156105c157600080fd5b509092509050611ea3565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156106105781810151838201526020016105f8565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561064f578181015183820152602001610637565b5050505090500194505050505060405180910390f35b61024b6004803603606081101561067b57600080fd5b508035600290810b91602081013590910b90604001356001600160801b0316611f21565b6106c9600480360360408110156106b557600080fd5b508035600290810b9160200135900b61209d565b6040805160069490940b84526001600160a01b03909216602084015263ffffffff1682820152519081900360600190f35b61072c6004803603606081101561071057600080fd5b506001600160a01b03813516906020810135906040013561227c565b60408051938452602084019290925282820152519081900360600190f35b6103376004803603604081101561076057600080fd5b5063ffffffff813581169160200135166124e6565b61019b61270e565b610785612732565b6040805160029290920b8252519081900360200190f35b61019b612756565b6107ac61277a565b6040805162ffffff9092168252519081900360200190f35b61043d61279e565b6107ec600480360360208110156107e257600080fd5b503560020b6127a4565b604080516001600160801b039099168952600f9790970b602089015287870195909552606087019390935260069190910b60808601526001600160a01b031660a085015263ffffffff1660c0840152151560e083015251908190036101000190f35b6103376004803603602081101561086457600080fd5b50356001600160a01b0316612810565b7f000000000000000000000000000000000000000000000000000000000000000081565b600080856108d2576040805162461bcd60e51b8152602060048201526002602482015261415360f01b604482015290519081900360640190fd5b6040805160e0810182526000546001600160a01b0381168252600160a01b8104600290810b810b900b602083015261ffff600160b81b8204811693830193909352600160c81b810483166060830152600160d81b9004909116608082015260015463ffffffff811660a083015260ff600160201b90910416151560c0820181905261098a576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b876109d55780600001516001600160a01b0316866001600160a01b03161180156109d0575073fffd8963efd1fc6a506488495d951d5263988d266001600160a01b038716105b610a07565b80600001516001600160a01b0316866001600160a01b0316108015610a0757506401000276a36001600160a01b038716115b610a3e576040805162461bcd60e51b815260206004820152600360248201526214d41360ea1b604482015290519081900360640190fd5b6001805460ff60201b191690556040805160c08101909152600090808a610a735760108460a0015163ffffffff16901c610a7d565b60a084015161ffff165b63ffffffff168152602001600560009054906101000a90046001600160801b03166001600160801b031681526020014263ffffffff168152602001600060060b815260200160006001600160a01b031681526020016000151581525090506000808913905060006040518060e001604052808b81526020016000815260200185600001516001600160a01b03168152602001856020015160020b81526020018c610b2957600354610b2d565b6002545b815260200160006001600160801b0316815260200184602001516001600160801b031681525090505b805115801590610b7c5750886001600160a01b031681604001516001600160a01b031614155b15610f6057610b8961554c565b60408201516001600160a01b031681526060820151610bcc906007907f00000000000000000000000000000000000000000000000000000000000000008f612c13565b15156040830152600290810b810b60208301819052620d89e719910b1215610bfd57620d89e7196020820152610c1c565b6020810151620d89e860029190910b1315610c1c57620d89e860208201525b610c298160200151612d55565b6001600160a01b031660608201526040820151610cba908d610c63578b6001600160a01b031683606001516001600160a01b031611610c7d565b8b6001600160a01b031683606001516001600160a01b0316105b610c8b578260600151610c8d565b8b5b60c085015185517f0000000000000000000000000000000000000000000000000000000000000000613086565b60c085015260a084015260808301526001600160a01b031660408301528215610d1c57610cf08160c00151826080015101613278565b825103825260a0810151610d1290610d0790613278565b60208401519061328e565b6020830152610d57565b610d298160a00151613278565b825101825260c08101516080820151610d5191610d469101613278565b6020840151906132aa565b60208301525b835163ffffffff1615610db7576000612710610d8a866000015163ffffffff168460c001516132c090919063ffffffff16565b81610d9157fe5b60c0840180519290910491829003905260a0840180519091016001600160801b03169052505b60c08201516001600160801b031615610df657610dea8160c00151600160801b8460c001516001600160801b03166132e4565b60808301805190910190525b80606001516001600160a01b031682604001516001600160a01b03161415610f1f57806040015115610ef6578360a00151610e8057610e5e846040015160008760200151886040015188602001518a606001516009613394909695949392919063ffffffff16565b6001600160a01b03166080860152600690810b900b6060850152600160a08501525b6000610ecc82602001518e610e9757600254610e9d565b84608001515b8f610eac578560800151610eb0565b6003545b608089015160608a015160408b01516006959493929190613526565b90508c15610ed8576000035b610ee68360c00151826135e0565b6001600160801b031660c0840152505b8b610f05578060200151610f0e565b60018160200151035b600290810b900b6060830152610f5a565b80600001516001600160a01b031682604001516001600160a01b031614610f5a57610f4d8260400151613696565b600290810b900b60608301525b50610b56565b836020015160020b816060015160020b1461102e57600080610fae86604001518660400151886020015188602001518a606001518b6080015160096139b1909695949392919063ffffffff16565b604085015160608601516000805461ffff60c81b1916600160c81b61ffff958616021761ffff60b81b1916600160b81b95909416949094029290921762ffffff60a01b1916600160a01b62ffffff60029490940b9390931692909202919091176001600160a01b0319166001600160a01b03909116179055506110539050565b6040810151600080546001600160a01b0319166001600160a01b039092169190911790555b8060c001516001600160801b031683602001516001600160801b0316146110995760c0810151600580546001600160801b0319166001600160801b039092169190911790555b6000808c156110f357608083015160025560a08301516001600160801b0316156110e75760a0830151600480546001600160801b031981166001600160801b03918216909301169190911790555b8260a001519150611140565b608083015160035560a08301516001600160801b0316156111395760a0830151600480546001600160801b03808216600160801b92839004821690940116029190911790555b5060a08201515b8315158d15151461115957602083015183518d03611166565b82600001518c0383602001515b90985096508c1561129f5760008712156111a8576111a87f00000000000000000000000000000000000000000000000000000000000000008f89600003613b4c565b60006111b2613c9a565b9050336001600160a01b03166323a69e758a8a8e8e6040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b15801561123657600080fd5b505af115801561124a573d6000803e3d6000fd5b50505050611256613c9a565b611260828b613dd3565b1115611299576040805162461bcd60e51b815260206004820152600360248201526249494160e81b604482015290519081900360640190fd5b506113c9565b60008812156112d6576112d67f00000000000000000000000000000000000000000000000000000000000000008f8a600003613b4c565b60006112e0613de3565b9050336001600160a01b03166323a69e758a8a8e8e6040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b15801561136457600080fd5b505af1158015611378573d6000803e3d6000fd5b50505050611384613de3565b61138e828a613dd3565b11156113c7576040805162461bcd60e51b815260206004820152600360248201526249494160e81b604482015290519081900360640190fd5b505b8d6001600160a01b0316336001600160a01b03167f19b47279256b2a23a1665c810c8d55a1758940ee09377d4f8d26497a3577dc838a8a87604001518860c001518960600151898960405180888152602001878152602001866001600160a01b03168152602001856001600160801b031681526020018460020b8152602001836001600160801b03168152602001826001600160801b0316815260200197505050505050505060405180910390a350506001805460ff60201b1916600160201b17905550939a92995091975050505050505050565b6005546001600160801b031681565b6004546001600160801b0380821691600160801b90041682565b60098161ffff81106114d857600080fd5b015463ffffffff81169150600160201b810460060b90600160581b81046001600160a01b031690600160f81b900460ff1684565b600154600160201b900460ff16611550576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6001805460ff60201b1916905560008054600160d81b900461ffff169061157960098385613e7b565b6000805461ffff808416600160d81b810261ffff60d81b19909316929092179092559192508316146115e6576040805161ffff80851682528316602082015281517fac49e518f90a358f652e4400164f05a5d8f7e35e7747279bc3a93dbf584e125a929181900390910190a15b50506001805460ff60201b1916600160201b17905550565b6000546001546001600160a01b03821691600160a01b810460020b9161ffff600160b81b8304811692600160c81b8104821692600160d81b9091049091169063ffffffff81169060ff600160201b9091041687565b6001546000908190600160201b900460ff1661169c576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6001805460ff60201b191690556001600160801b0385166116bc57600080fd5b60008061170a60405180608001604052808c6001600160a01b031681526020018b60020b81526020018a60020b81526020016117008a6001600160801b0316613f1e565b600f0b9052613f2f565b9250925050819350809250600080600086111561172c57611729613c9a565b91505b841561173d5761173a613de3565b90505b336001600160a01b03166399eee9d087878b8b6040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b1580156117bf57600080fd5b505af11580156117d3573d6000803e3d6000fd5b50505050600086111561182a576117e8613c9a565b6117f28388613dd3565b111561182a576040805162461bcd60e51b815260206004820152600260248201526104d360f41b604482015290519081900360640190fd5b841561187a57611838613de3565b6118428287613dd3565b111561187a576040805162461bcd60e51b81526020600482015260026024820152614d3160f01b604482015290519081900360640190fd5b8960020b8b60020b8d6001600160a01b03167f7a53080ba414158be7ec69b987b5fb7d07dee101fe85488f0853ae16239d0bde338d8b8b60405180856001600160a01b03168152602001846001600160801b0316815260200183815260200182815260200194505050505060405180910390a450506001805460ff60201b1916600160201b17905550919890975095505050505050565b60035481565b6001546000908190600160201b900460ff16611960576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6001805460ff60201b19169055600061197c600833898961415f565b60038101549091506001600160801b039081169086161161199d57846119ac565b60038101546001600160801b03165b60038201549093506001600160801b03600160801b9091048116908516116119d457836119ea565b6003810154600160801b90046001600160801b03165b91506001600160801b03831615611a4f576003810180546001600160801b031981166001600160801b03918216869003821617909155611a4f907f0000000000000000000000000000000000000000000000000000000000000000908a908616613b4c565b6001600160801b03821615611ab5576003810180546001600160801b03600160801b808304821686900382160291811691909117909155611ab5907f0000000000000000000000000000000000000000000000000000000000000000908a908516613b4c565b604080516001600160a01b038a1681526001600160801b0380861660208301528416818301529051600288810b92908a900b9133917f70935338e69775456a85ddef226c395fb668b63fa0115f5f20610b388e6ca9c0919081900360600190a4506001805460ff60201b1916600160201b17905590969095509350505050565b60086020526000908152604090208054600182015460028301546003909301546001600160801b0392831693919281811691600160801b90041685565b60076020526000908152604090205481565b7f000000000000000000000000000000000000000000000000000000000000000081565b6001546000908190600160201b900460ff16611bf1576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6001805460ff60201b19169055336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480611cc157507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611c8957600080fd5b505afa158015611c9d573d6000803e3d6000fd5b505050506040513d6020811015611cb357600080fd5b50516001600160a01b031633145b611cca57600080fd5b6004546001600160801b0390811690851611611ce65783611cf3565b6004546001600160801b03165b6004549092506001600160801b03600160801b909104811690841611611d195782611d2d565b600454600160801b90046001600160801b03165b90506001600160801b03821615611dae576004546001600160801b0383811691161415611d5c57600019909101905b600480546001600160801b031981166001600160801b03918216859003821617909155611dae907f00000000000000000000000000000000000000000000000000000000000000009087908516613b4c565b6001600160801b03811615611e34576004546001600160801b03828116600160801b909204161415611ddf57600019015b600480546001600160801b03600160801b808304821685900382160291811691909117909155611e34907f00000000000000000000000000000000000000000000000000000000000000009087908416613b4c565b604080516001600160801b0380851682528316602082015281516001600160a01b0388169233927f596b573906218d3411850b26a6b437d6c4522fdb43d2d2386263f86d50b8b151929081900390910190a36001805460ff60201b1916600160201b1790559094909350915050565b606080611f1642858580806020026020016040519081016040528093929190818152602001838360200280828437600092018290525054600554600996959450600160a01b820460020b935061ffff600160b81b8304811693506001600160801b0390911691600160c81b9004166141c3565b915091509250929050565b6001546000908190600160201b900460ff16611f6a576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6001805460ff60201b1916905560408051608081018252338152600287810b602083015286900b9181019190915260009081908190611fc69060608101611fb96001600160801b038a16613f1e565b600003600f0b9052613f2f565b9250925092508160000394508060000393506000851180611fe75750600084115b15612026576003830180546001600160801b038082168089018216600160801b93849004831689019092169092029091176001600160801b0319161790555b604080516001600160801b0388168152602081018790528082018690529051600289810b92908b900b9133917f0c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c919081900360600190a450506001805460ff60201b1916600160201b179055509094909350915050565b60008060006120ac858561431d565b600285810b810b600090815260066020819052604080832088850b90940b8352822060038401549182900b93600160381b83046001600160a01b0316928492600160d81b820463ffffffff16928492909190600160f81b900460ff168061211257600080fd5b6003820154600681900b9850600160381b81046001600160a01b03169650600160d81b810463ffffffff169450600160f81b900460ff168061215357600080fd5b50506040805160e0810182526000546001600160a01b0381168252600160a01b8104600290810b810b810b6020840181905261ffff600160b81b8404811695850195909552600160c81b830485166060850152600160d81b909204909316608083015260015463ffffffff811660a084015260ff600160201b90910416151560c08301529093508e820b910b121590506121fb57509390940396509003935090039050612275565b8a60020b816020015160020b121561226657602081015160408201516005546060840151429360009384936122449360099388938793919290916001600160801b031690613394565b9a9003989098039b505094909603929092039650909103039250612275915050565b50949093039650039350900390505b9250925092565b60008080336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061234357507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561230b57600080fd5b505afa15801561231f573d6000803e3d6000fd5b505050506040513d602081101561233557600080fd5b50516001600160a01b031633145b61234c57600080fd5b60408051635569f64b60e11b81526001600160a01b03881660048201526024810187905290516004604360981b019163aad3ec969160448083019260209291908290030181600087803b1580156123a257600080fd5b505af11580156123b6573d6000803e3d6000fd5b505050506040513d60208110156123cc57600080fd5b505160408051635569f64b60e11b81526001600160a01b03891660048201526024810187905290519194506003604360981b019163aad3ec96916044808201926020929091908290030181600087803b15801561242857600080fd5b505af115801561243c573d6000803e3d6000fd5b505050506040513d602081101561245257600080fd5b50516040805163662aa11d60e01b81523060048201526001600160a01b038916602482015290519193506002604360981b019163662aa11d916044808201926020929091908290030181600087803b1580156124ad57600080fd5b505af11580156124c1573d6000803e3d6000fd5b505050506040513d60208110156124d757600080fd5b50519296919550919350915050565b600154600160201b900460ff1661252a576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6001805460ff60201b19169055336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806125fa57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156125c257600080fd5b505afa1580156125d6573d6000803e3d6000fd5b505050506040513d60208110156125ec57600080fd5b50516001600160a01b031633145b61260357600080fd5b63ffffffff8216158061263157506103e88263ffffffff16101580156126315750610fa08263ffffffff1611155b8015612666575063ffffffff8116158061266657506103e88163ffffffff16101580156126665750610fa08163ffffffff1611155b61266f57600080fd5b6001805465ffffffff0000601084901b16840163ffffffff90811663ffffffff19831617909255167fb3159fed3ddfba67bae294599eafe2d0ec98c08bb38e0e5fb87d33154b6e05aa62010000826040805163ffffffff939092068316825261ffff601086901c16602083015286831682820152918516606082015290519081900360800190a150506001805460ff60201b1916600160201b17905550565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b60025481565b60066020819052600091825260409091208054600182015460028301546003909301546001600160801b03831694600160801b909304600f0b93919281900b90600160381b81046001600160a01b031690600160d81b810463ffffffff1690600160f81b900460ff1688565b6000546001600160a01b031615612853576040805162461bcd60e51b8152602060048201526002602482015261414960f01b604482015290519081900360640190fd5b732536fe9ab3f511540f2f9e2ec2a805005c3dd8006001600160a01b03166336b91f2b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bd454fae6040518163ffffffff1660e01b815260040160206040518083038186803b1580156128cf57600080fd5b505afa1580156128e3573d6000803e3d6000fd5b505050506040513d60208110156128f957600080fd5b5051604080516001600160e01b031960e085901b1681526001600160a01b03909216600483015251602480830192600092919082900301818387803b15801561294157600080fd5b505af1158015612955573d6000803e3d6000fd5b50505050600061296482613696565b90506000806129746009426143e6565b6040805160e0810182526001600160a01b038816808252600288810b60208401819052600094840185905261ffff8781166060860181905290871660808601819052630c800c8060a08701819052600160c090970187905287546001600160a01b03191690951762ffffff60a01b1916600160a01b62ffffff9490950b8416949094029390931763ffffffff60b81b1916600160c81b9091021761ffff60d81b1916600160d81b909202919091179093558154600160201b63ffffffff1990911690911760ff60201b191617905591935091507f00000000000000000000000000000000000000000000000000000000000000001660641415612a89576001805463ffffffff1916630ce40ce4179055612b5a565b7f000000000000000000000000000000000000000000000000000000000000000062ffffff166101f41415612ad0576001805463ffffffff1916630d480d48179055612b5a565b7f000000000000000000000000000000000000000000000000000000000000000062ffffff166109c41415612b17576001805463ffffffff1916630c800c80179055612b5a565b7f000000000000000000000000000000000000000000000000000000000000000062ffffff166127101415612b5a576001805463ffffffff1916630c800c801790555b604080516001600160a01b0386168152600285900b602082015281517f98636036cb66a9c19a37435efc1e90142190214e8abeb821bdba3f2990dd4c95929181900390910190a150505050565b60008082600281900b620d89e71981612bbc57fe5b05029050600083600281900b620d89e881612bd357fe5b0502905060008460020b83830360020b81612bea57fe5b0560010190508062ffffff166001600160801b03801681612c0757fe5b0493505050505b919050565b60008060008460020b8660020b81612c2757fe5b05905060008660020b128015612c4e57508460020b8660020b81612c4757fe5b0760020b15155b15612c5857600019015b8315612ccd57600080612c6a83614432565b600182810b810b600090815260208d9052604090205460ff83169190911b80016000190190811680151597509294509092509085612caf57888360ff16860302612cc2565b88612cb982614444565b840360ff168603025b965050505050612d4b565b600080612cdc83600101614432565b91509150600060018260ff166001901b031990506000818b60008660010b60010b8152602001908152602001600020541690508060001415955085612d2e57888360ff0360ff16866001010102612d44565b8883612d39836144e3565b0360ff168660010101025b9650505050505b5094509492505050565b60008060008360020b12612d6c578260020b612d74565b8260020b6000035b9050620d89e8811115612db2576040805162461bcd60e51b81526020600482015260016024820152601560fa1b604482015290519081900360640190fd5b600060018216612dc657600160801b612dd8565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff1690506002821615612e0c576ffff97272373d413259a46990580e213a0260801c5b6004821615612e2b576ffff2e50f5f656932ef12357cf3c7fdcc0260801c5b6008821615612e4a576fffe5caca7e10e4e61c3624eaa0941cd00260801c5b6010821615612e69576fffcb9843d60f6159c9db58835c9266440260801c5b6020821615612e88576fff973b41fa98c081472e6896dfb254c00260801c5b6040821615612ea7576fff2ea16466c96a3843ec78b326b528610260801c5b6080821615612ec6576ffe5dee046a99a2a811c461f1969c30530260801c5b610100821615612ee6576ffcbe86c7900a88aedcffc83b479aa3a40260801c5b610200821615612f06576ff987a7253ac413176f2b074cf7815e540260801c5b610400821615612f26576ff3392b0822b70005940c7a398e4b70f30260801c5b610800821615612f46576fe7159475a2c29b7443b29c7fa6e889d90260801c5b611000821615612f66576fd097f3bdfd2022b8845ad8f792aa58250260801c5b612000821615612f86576fa9f746462d870fdf8a65dc1f90e061e50260801c5b614000821615612fa6576f70d869a156d2a1b890bb3df62baf32f70260801c5b618000821615612fc6576f31be135f97d08fd981231505542fcfa60260801c5b62010000821615612fe7576f09aa508b5b7a84e1c677de54f3e99bc90260801c5b62020000821615613007576e5d6af8dedb81196699c329225ee6040260801c5b62040000821615613026576d2216e584f5fa1ea926041bedfe980260801c5b62080000821615613043576b048a170391f7dc42444e8fa20260801c5b60008460020b131561305e57806000198161305a57fe5b0490505b600160201b810615613071576001613074565b60005b60ff16602082901c0192505050919050565b60008080806001600160a01b03808916908a16101581871280159061310b5760006130bf8989620f42400362ffffff16620f42406132e4565b9050826130d8576130d38c8c8c60016145cd565b6130e5565b6130e58b8d8c6001614648565b95508581106130f6578a9650613105565b6131028c8b83866146f3565b96505b50613155565b816131225761311d8b8b8b6000614648565b61312f565b61312f8a8c8b60006145cd565b935083886000031061314357899550613155565b6131528b8a8a6000038561473f565b95505b6001600160a01b038a81169087161482156131b8578080156131745750815b61318a57613185878d8c6001614648565b61318c565b855b9550808015613199575081155b6131af576131aa878d8c60006145cd565b6131b1565b845b9450613202565b8080156131c25750815b6131d8576131d38c888c60016145cd565b6131da565b855b95508080156131e7575081155b6131fd576131f88c888c6000614648565b6131ff565b845b94505b8115801561321257508860000385115b1561321e578860000394505b81801561323d57508a6001600160a01b0316876001600160a01b031614155b1561324c578589039350613269565b613266868962ffffff168a620f42400362ffffff1661478b565b93505b50505095509550955095915050565b6000600160ff1b821061328a57600080fd5b5090565b808203828113156000831215146132a457600080fd5b92915050565b818101828112156000831215146132a457600080fd5b60008215806132db575050818102818382816132d857fe5b04145b6132a457600080fd5b600080806000198587098686029250828110908390030390508061331a576000841161330f57600080fd5b50829004905061338d565b80841161332657600080fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150505b9392505050565b60008063ffffffff871661343a576000898661ffff1661ffff81106133b557fe5b60408051608081018252919092015463ffffffff808216808452600160201b8304600690810b810b900b6020850152600160581b83046001600160a01b031694840194909452600160f81b90910460ff16151560608301529092508a161461342657613423818a89886147c5565b90505b80602001518160400151925092505061351a565b86880360008061344f8c8c858c8c8c8c614868565b91509150816000015163ffffffff168363ffffffff16141561348157816020015182604001519450945050505061351a565b805163ffffffff848116911614156134a957806020015181604001519450945050505061351a565b8151815160208085015190840151918390039286039163ffffffff80841692908516910360060b816134d757fe5b05028460200151018263ffffffff168263ffffffff1686604001518660400151036001600160a01b0316028161350957fe5b048560400151019650965050505050505b97509795505050505050565b600295860b860b60009081526020979097526040909620600181018054909503909455938301805490920390915560038201805463ffffffff600160d81b6001600160a01b03600160381b808504821690960316909402600160381b600160d81b031990921691909117600681810b90960390950b66ffffffffffffff1666ffffffffffffff199095169490941782810485169095039093160263ffffffff60d81b1990931692909217905554600160801b9004600f0b90565b60008082600f0b121561364557826001600160801b03168260000384039150816001600160801b031610613640576040805162461bcd60e51b81526020600482015260026024820152614c5360f01b604482015290519081900360640190fd5b6132a4565b826001600160801b03168284019150816001600160801b031610156132a4576040805162461bcd60e51b81526020600482015260026024820152614c4160f01b604482015290519081900360640190fd5b60006401000276a36001600160a01b038316108015906136d2575073fffd8963efd1fc6a506488495d951d5263988d266001600160a01b038316105b613707576040805162461bcd60e51b81526020600482015260016024820152602960f91b604482015290519081900360640190fd5b640100000000600160c01b03602083901b166001600160801b03811160071b81811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c60ff8111600390811b91821c600f811160021b90811c918211600190811b92831c9790881196179094179092171790911717176080811061379b57607f810383901c91506137a5565b80607f0383901b91505b908002607f81811c60ff83811c9190911c800280831c81831c1c800280841c81841c1c800280851c81851c1c800280861c81861c1c800280871c81871c1c800280881c81881c1c800280891c81891c1c8002808a1c818a1c1c8002808b1c818b1c1c8002808c1c818c1c1c8002808d1c818d1c1c8002808e1c9c81901c9c909c1c80029c8d901c9e9d607f198f0160401b60c09190911c678000000000000000161760c19b909b1c674000000000000000169a909a1760c29990991c672000000000000000169890981760c39790971c671000000000000000169690961760c49590951c670800000000000000169490941760c59390931c670400000000000000169290921760c69190911c670200000000000000161760c79190911c600160381b161760c89190911c6680000000000000161760c99190911c6640000000000000161760ca9190911c6620000000000000161760cb9190911c6610000000000000161760cc9190911c6608000000000000161760cd9190911c66040000000000001617693627a301d71055774c8581026f028f6481ab7f045a5af012a19d003aa9198101608090811d906fdb2df09e81959a81455e260799a0632f8301901d600281810b9083900b146139a257886001600160a01b031661398682612d55565b6001600160a01b0316111561399b578161399d565b805b6139a4565b815b9998505050505050505050565b6000806000898961ffff1661ffff81106139c757fe5b60408051608081018252919092015463ffffffff808216808452600160201b8304600690810b810b900b6020850152600160581b83046001600160a01b031694840194909452600160f81b90910460ff161515606083015290925089161415613a36578885925092505061351a565b8461ffff168461ffff16118015613a5757506001850361ffff168961ffff16145b15613a6457839150613a68565b8491505b8161ffff168960010161ffff1681613a7c57fe5b069250613a8b818989896147c5565b8a8461ffff1661ffff8110613a9c57fe5b825191018054602084015160408501516060909501511515600160f81b026001600160f81b036001600160a01b03909616600160581b027fff0000000000000000000000000000000000000000ffffffffffffffffffffff60069390930b66ffffffffffffff16600160201b026affffffffffffff000000001963ffffffff90971663ffffffff199095169490941795909516929092171692909217929092161790555097509795505050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b60208310613bc85780518252601f199092019160209182019101613ba9565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613c2a576040519150601f19603f3d011682016040523d82523d6000602084013e613c2f565b606091505b5091509150818015613c5d575080511580613c5d5750808060200190516020811015613c5a57600080fd5b50515b613c93576040805162461bcd60e51b81526020600482015260026024820152612a2360f11b604482015290519081900360640190fd5b5050505050565b604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b17815291518151600093849384936001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001693919290918291908083835b60208310613d335780518252601f199092019160209182019101613d14565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114613d93576040519150601f19603f3d011682016040523d82523d6000602084013e613d98565b606091505b5091509150818015613dac57506020815110155b613db557600080fd5b808060200190516020811015613dca57600080fd5b50519250505090565b808201828110156132a457600080fd5b604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b17815291518151600093849384936001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016939192909182919080838360208310613d335780518252601f199092019160209182019101613d14565b6000808361ffff1611613eb9576040805162461bcd60e51b81526020600482015260016024820152604960f81b604482015290519081900360640190fd5b8261ffff168261ffff1611613ecf57508161338d565b825b8261ffff168161ffff161015613f15576001858261ffff1661ffff8110613ef457fe5b01805463ffffffff191663ffffffff92909216919091179055600101613ed1565b50909392505050565b80600f81900b8114612c0e57600080fd5b6000806000613f468460200151856040015161431d565b6040805160e0810182526000546001600160a01b0381168252600160a01b8104600290810b810b900b602080840182905261ffff600160b81b8404811685870152600160c81b84048116606080870191909152600160d81b90940416608085015260015463ffffffff811660a086015260ff600160201b90910416151560c085015288519089015194890151928901519394613fe89491939092909190614a62565b93508460600151600f0b60001461415757846020015160020b816020015160020b121561403d5761403661401f8660200151612d55565b61402c8760400151612d55565b8760600151614c09565b9250614157565b846040015160020b816020015160020b121561412d5760055460408201516020830151606084015160808501516001600160801b039094169361408993600993909242928791906139b1565b6000805461ffff60c81b1916600160c81b61ffff938416021761ffff60b81b1916600160b81b9390921692909202179055815160408701516140d991906140cf90612d55565b8860600151614c09565b93506140f76140eb8760200151612d55565b83516060890151614c4d565b92506141078187606001516135e0565b600580546001600160801b0319166001600160801b039290921691909117905550614157565b61415461413d8660200151612d55565b61414a8760400151612d55565b8760600151614c4d565b91505b509193909250565b6040805160609490941b6bffffffffffffffffffffffff1916602080860191909152600293840b60e890811b60348701529290930b90911b60378401528051808403601a018152603a90930181528251928201929092206000908152929052902090565b60608060008361ffff1611614203576040805162461bcd60e51b81526020600482015260016024820152604960f81b604482015290519081900360640190fd5b865167ffffffffffffffff8111801561421b57600080fd5b50604051908082528060200260200182016040528015614245578160200160208202803683370190505b509150865167ffffffffffffffff8111801561426057600080fd5b5060405190808252806020026020018201604052801561428a578160200160208202803683370190505b50905060005b8751811015614310576142bb8a8a8a84815181106142aa57fe5b60200260200101518a8a8a8a613394565b8483815181106142c757fe5b602002602001018484815181106142da57fe5b60200260200101826001600160a01b03166001600160a01b03168152508260060b60060b81525050508080600101915050614290565b5097509795505050505050565b8060020b8260020b1261435d576040805162461bcd60e51b8152602060048201526003602482015262544c5560e81b604482015290519081900360640190fd5b620d89e719600283900b12156143a0576040805162461bcd60e51b8152602060048201526003602482015262544c4d60e81b604482015290519081900360640190fd5b620d89e8600282900b13156143e2576040805162461bcd60e51b815260206004820152600360248201526254554d60e81b604482015290519081900360640190fd5b5050565b6040805160808101825263ffffffff9283168082526000602083018190529282019290925260016060909101819052835463ffffffff1916909117909116600160f81b17909155908190565b60020b600881901d9161010090910790565b600080821161445257600080fd5b600160801b821061446557608091821c91015b68010000000000000000821061447d57604091821c91015b600160201b821061449057602091821c91015b6201000082106144a257601091821c91015b61010082106144b357600891821c91015b601082106144c357600491821c91015b600482106144d357600291821c91015b60028210612c0e57600101919050565b60008082116144f157600080fd5b5060ff6001600160801b0382161561450c57607f1901614514565b608082901c91505b67ffffffffffffffff82161561452d57603f1901614535565b604082901c91505b63ffffffff82161561454a57601f1901614552565b602082901c91505b61ffff82161561456557600f190161456d565b601082901c91505b60ff82161561457f5760071901614587565b600882901c91505b600f82161561459957600319016145a1565b600482901c91505b60038216156145b357600119016145bb565b600282901c91505b6001821615612c0e5760001901919050565b6000836001600160a01b0316856001600160a01b031611156145ed579293925b8161461a57614615836001600160801b03168686036001600160a01b0316600160601b6132e4565b61463d565b61463d836001600160801b03168686036001600160a01b0316600160601b61478b565b90505b949350505050565b6000836001600160a01b0316856001600160a01b03161115614668579293925b600160601b600160e01b03606084901b166001600160a01b03868603811690871661469257600080fd5b836146c257866001600160a01b03166146b58383896001600160a01b03166132e4565b816146bc57fe5b046146e8565b6146e86146d98383896001600160a01b031661478b565b886001600160a01b0316614c7c565b979650505050505050565b600080856001600160a01b03161161470a57600080fd5b6000846001600160801b03161161472057600080fd5b81614732576146158585856001614c87565b61463d8585856001614d68565b600080856001600160a01b03161161475657600080fd5b6000846001600160801b03161161476c57600080fd5b8161477e576146158585856000614d68565b61463d8585856000614c87565b60006147988484846132e4565b9050600082806147a457fe5b848609111561338d5760001981106147bb57600080fd5b6001019392505050565b6147cd615588565b600085600001518503905060405180608001604052808663ffffffff1681526020018263ffffffff168660020b0288602001510160060b81526020016000856001600160801b031611614821576001614823565b845b6001600160801b031663ffffffff60801b608085901b168161484157fe5b048860400151016001600160a01b0316815260200160011515815250915050949350505050565b614870615588565b614878615588565b888561ffff1661ffff811061488957fe5b60408051608081018252919092015463ffffffff8116808352600160201b8204600690810b810b900b6020840152600160581b82046001600160a01b031693830193909352600160f81b900460ff161515606082015292506148ed90899089614e4b565b15614925578663ffffffff16826000015163ffffffff16141561490f5761351a565b8161491c838989886147c5565b9150915061351a565b888361ffff168660010161ffff168161493a57fe5b0661ffff1661ffff811061494a57fe5b60408051608081018252929091015463ffffffff81168352600160201b8104600690810b810b900b60208401526001600160a01b03600160581b8204169183019190915260ff600160f81b909104161515606082018190529092506149ff57604080516080810182528a5463ffffffff81168252600160201b8104600690810b810b900b6020830152600160581b81046001600160a01b031692820192909252600160f81b90910460ff161515606082015291505b614a0e88836000015189614e4b565b614a45576040805162461bcd60e51b815260206004820152600360248201526213d31160ea1b604482015290519081900360640190fd5b614a528989898887614f0c565b9150915097509795505050505050565b6000614a71600887878761415f565b60025460035491925090600080600f87900b15614ba957600080546005544292918291614ace9160099186918591600160a01b820460020b9161ffff600160b81b82048116926001600160801b031691600160c81b900416613394565b9092509050614b0860068d8b8d8b8b87898b60007f00000000000000000000000000000000000000000000000000000000000000006150aa565b9450614b3f60068c8b8d8b8b87898b60017f00000000000000000000000000000000000000000000000000000000000000006150aa565b93508415614b7357614b7360078d7f0000000000000000000000000000000000000000000000000000000000000000615263565b8315614ba557614ba560078c7f0000000000000000000000000000000000000000000000000000000000000000615263565b5050505b600080614bbb60068c8c8b8a8a6152c9565b9092509050614bcc878a8484615375565b600089600f0b1215614bfa578315614be957614be960068c61550a565b8215614bfa57614bfa60068b61550a565b50505050505095945050505050565b60008082600f0b12614c2f57614c2a614c258585856001614648565b613278565b614640565b614c42614c258585856000036000614648565b600003949350505050565b60008082600f0b12614c6957614c2a614c2585858560016145cd565b614c42614c2585858560000360006145cd565b808204910615150190565b60008115614cfa5760006001600160a01b03841115614cbd57614cb884600160601b876001600160801b03166132e4565b614cd5565b6001600160801b038516606085901b81614cd357fe5b045b9050614cf2614ced6001600160a01b03881683613dd3565b615536565b915050614640565b60006001600160a01b03841115614d2857614d2384600160601b876001600160801b031661478b565b614d3f565b614d3f606085901b6001600160801b038716614c7c565b905080866001600160a01b031611614d5657600080fd5b6001600160a01b038616039050614640565b600082614d76575083614640565b600160601b600160e01b03606085901b168215614e04576001600160a01b03861684810290858281614da457fe5b041415614dd557818101828110614dd357614dc983896001600160a01b03168361478b565b9350505050614640565b505b614dfb82614df6878a6001600160a01b03168681614def57fe5b0490613dd3565b614c7c565b92505050614640565b6001600160a01b03861684810290858281614e1b57fe5b04148015614e2857508082115b614e3157600080fd5b808203614dc9614ced846001600160a01b038b168461478b565b60008363ffffffff168363ffffffff1611158015614e7557508363ffffffff168263ffffffff1611155b15614e91578163ffffffff168363ffffffff161115905061338d565b60008463ffffffff168463ffffffff1611614eb8578363ffffffff16600160201b01614ec0565b8363ffffffff165b64ffffffffff16905060008563ffffffff168463ffffffff1611614ef0578363ffffffff16600160201b01614ef8565b8363ffffffff165b64ffffffffff169091111595945050505050565b614f14615588565b614f1c615588565b60008361ffff168560010161ffff1681614f3257fe5b0661ffff169050600060018561ffff16830103905060005b506002818301048961ffff87168281614f5f57fe5b0661ffff8110614f6b57fe5b60408051608081018252929091015463ffffffff81168352600160201b8104600690810b810b900b60208401526001600160a01b03600160581b8204169183019190915260ff600160f81b90910416151560608201819052909550614fd557806001019250614f4a565b898661ffff168260010181614fe657fe5b0661ffff8110614ff257fe5b60408051608081018252929091015463ffffffff81168352600160201b8104600690810b810b900b60208401526001600160a01b03600160581b8204169183019190915260ff600160f81b9091041615156060820152855190945060009061505c908b908b614e4b565b905080801561507557506150758a8a8760000151614e4b565b15615080575061509d565b8061509057600182039250615097565b8160010193505b50614f4a565b5050509550959350505050565b60028a810b900b600090815260208c90526040812080546001600160801b0316826150d5828d6135e0565b9050846001600160801b0316816001600160801b03161115615123576040805162461bcd60e51b81526020600482015260026024820152614c4f60f01b604482015290519081900360640190fd5b6001600160801b0382811615908216158114159450156151c8578c60020b8e60020b136151b057600183018b9055600283018a9055600383018054600160381b600160d81b031916600160381b6001600160a01b038c16021766ffffffffffffff191666ffffffffffffff60068b900b161763ffffffff60d81b1916600160d81b63ffffffff8a16021790555b6003830180546001600160f81b0316600160f81b1790555b82546001600160801b0319166001600160801b0382161783558561521157825461520c9061520790600160801b9004600f90810b810b908f900b6132aa565b613f1e565b615232565b82546152329061520790600160801b9004600f90810b810b908f900b61328e565b8354600f9190910b6001600160801b03908116600160801b0291161790925550909c9b505050505050505050505050565b8060020b8260020b8161527257fe5b0760020b1561528057600080fd5b60008061529b8360020b8560020b8161529557fe5b05614432565b600191820b820b60009081526020979097526040909620805460ff9097169190911b90951890945550505050565b600285810b80820b60009081526020899052604080822088850b850b83529082209193849391929184918291908a900b1261530f57505060018201546002830154615322565b8360010154880391508360020154870390505b6000808b60020b8b60020b121561534457505060018301546002840154615357565b84600101548a0391508460020154890390505b92909803979097039b96909503949094039850939650505050505050565b6040805160a08101825285546001600160801b0390811682526001870154602083015260028701549282019290925260038601548083166060830152600160801b900490911660808201526000600f85900b6154145781516001600160801b031661540c576040805162461bcd60e51b815260206004820152600260248201526104e560f41b604482015290519081900360640190fd5b508051615423565b815161542090866135e0565b90505b60006154478360200151860384600001516001600160801b0316600160801b6132e4565b9050600061546d8460400151860385600001516001600160801b0316600160801b6132e4565b905086600f0b6000146154945787546001600160801b0319166001600160801b0384161788555b60018801869055600288018590556001600160801b0382161515806154c257506000816001600160801b0316115b15615500576003880180546001600160801b031981166001600160801b039182168501821617808216600160801b9182900483168501909216021790555b5050505050505050565b600290810b810b6000908152602092909252604082208281556001810183905590810182905560030155565b806001600160a01b0381168114612c0e57600080fd5b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b6040805160808101825260008082526020820181905291810182905260608101919091529056fea164736f6c6343000706000a
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061018e5760003560e01c806385b66729116100de578063c45a015511610097578063ddca3f4311610071578063ddca3f43146107a4578063f3058399146107c4578063f30dba93146107cc578063f637731d1461084e5761018e565b8063c45a015514610775578063d0c93a7c1461077d578063d21220a71461079c5761018e565b806385b6672914610521578063883bdbfd1461055e578063a34123a714610665578063a38807f21461069f578063ad66aeb8146106fa578063b0d0d2111461074a5761018e565b80633850c7bd1161014b5780634f1eb3d8116101255780634f1eb3d81461044f578063514ea4bf146104a05780635339c296146104f957806370cf754a146105195761018e565b80633850c7bd146103395780633c8a7d8d1461039557806346141319146104355761018e565b80630dfe168114610193578063128acb08146101b75780631a686502146102645780631ad8b03b14610288578063252c09d7146102bf57806332148f6714610316575b600080fd5b61019b610874565b604080516001600160a01b039092168252519081900360200190f35b61024b600480360360a08110156101cd57600080fd5b6001600160a01b0382358116926020810135151592604082013592606083013516919081019060a081016080820135600160201b81111561020d57600080fd5b82018360208201111561021f57600080fd5b803590602001918460018302840111600160201b8311171561024057600080fd5b509092509050610898565b6040805192835260208301919091528051918290030190f35b61026c61149e565b604080516001600160801b039092168252519081900360200190f35b6102906114ad565b60405180836001600160801b03168152602001826001600160801b031681526020019250505060405180910390f35b6102dc600480360360208110156102d557600080fd5b50356114c7565b6040805163ffffffff909516855260069390930b60208501526001600160a01b039091168383015215156060830152519081900360800190f35b6103376004803603602081101561032c57600080fd5b503561ffff1661150c565b005b6103416115fe565b604080516001600160a01b03909816885260029690960b602088015261ffff9485168787015292841660608701529216608085015263ffffffff90911660a0840152151560c0830152519081900360e00190f35b61024b600480360360a08110156103ab57600080fd5b6001600160a01b03823516916020810135600290810b92604083013590910b916001600160801b036060820135169181019060a081016080820135600160201b8111156103f757600080fd5b82018360208201111561040957600080fd5b803590602001918460018302840111600160201b8311171561042a57600080fd5b509092509050611653565b61043d611911565b60408051918252519081900360200190f35b610290600480360360a081101561046557600080fd5b506001600160a01b03813516906020810135600290810b91604081013590910b906001600160801b0360608201358116916080013516611917565b6104bd600480360360208110156104b657600080fd5b5035611b35565b604080516001600160801b0396871681526020810195909552848101939093529084166060840152909216608082015290519081900360a00190f35b61043d6004803603602081101561050f57600080fd5b503560010b611b72565b61026c611b84565b6102906004803603606081101561053757600080fd5b506001600160a01b03813516906001600160801b0360208201358116916040013516611ba8565b6105cc6004803603602081101561057457600080fd5b810190602081018135600160201b81111561058e57600080fd5b8201836020820111156105a057600080fd5b803590602001918460208302840111600160201b831117156105c157600080fd5b509092509050611ea3565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156106105781810151838201526020016105f8565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561064f578181015183820152602001610637565b5050505090500194505050505060405180910390f35b61024b6004803603606081101561067b57600080fd5b508035600290810b91602081013590910b90604001356001600160801b0316611f21565b6106c9600480360360408110156106b557600080fd5b508035600290810b9160200135900b61209d565b6040805160069490940b84526001600160a01b03909216602084015263ffffffff1682820152519081900360600190f35b61072c6004803603606081101561071057600080fd5b506001600160a01b03813516906020810135906040013561227c565b60408051938452602084019290925282820152519081900360600190f35b6103376004803603604081101561076057600080fd5b5063ffffffff813581169160200135166124e6565b61019b61270e565b610785612732565b6040805160029290920b8252519081900360200190f35b61019b612756565b6107ac61277a565b6040805162ffffff9092168252519081900360200190f35b61043d61279e565b6107ec600480360360208110156107e257600080fd5b503560020b6127a4565b604080516001600160801b039099168952600f9790970b602089015287870195909552606087019390935260069190910b60808601526001600160a01b031660a085015263ffffffff1660c0840152151560e083015251908190036101000190f35b6103376004803603602081101561086457600080fd5b50356001600160a01b0316612810565b7f000000000000000000000000430000000000000000000000000000000000000381565b600080856108d2576040805162461bcd60e51b8152602060048201526002602482015261415360f01b604482015290519081900360640190fd5b6040805160e0810182526000546001600160a01b0381168252600160a01b8104600290810b810b900b602083015261ffff600160b81b8204811693830193909352600160c81b810483166060830152600160d81b9004909116608082015260015463ffffffff811660a083015260ff600160201b90910416151560c0820181905261098a576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b876109d55780600001516001600160a01b0316866001600160a01b03161180156109d0575073fffd8963efd1fc6a506488495d951d5263988d266001600160a01b038716105b610a07565b80600001516001600160a01b0316866001600160a01b0316108015610a0757506401000276a36001600160a01b038716115b610a3e576040805162461bcd60e51b815260206004820152600360248201526214d41360ea1b604482015290519081900360640190fd5b6001805460ff60201b191690556040805160c08101909152600090808a610a735760108460a0015163ffffffff16901c610a7d565b60a084015161ffff165b63ffffffff168152602001600560009054906101000a90046001600160801b03166001600160801b031681526020014263ffffffff168152602001600060060b815260200160006001600160a01b031681526020016000151581525090506000808913905060006040518060e001604052808b81526020016000815260200185600001516001600160a01b03168152602001856020015160020b81526020018c610b2957600354610b2d565b6002545b815260200160006001600160801b0316815260200184602001516001600160801b031681525090505b805115801590610b7c5750886001600160a01b031681604001516001600160a01b031614155b15610f6057610b8961554c565b60408201516001600160a01b031681526060820151610bcc906007907f000000000000000000000000000000000000000000000000000000000000000a8f612c13565b15156040830152600290810b810b60208301819052620d89e719910b1215610bfd57620d89e7196020820152610c1c565b6020810151620d89e860029190910b1315610c1c57620d89e860208201525b610c298160200151612d55565b6001600160a01b031660608201526040820151610cba908d610c63578b6001600160a01b031683606001516001600160a01b031611610c7d565b8b6001600160a01b031683606001516001600160a01b0316105b610c8b578260600151610c8d565b8b5b60c085015185517f00000000000000000000000000000000000000000000000000000000000001f4613086565b60c085015260a084015260808301526001600160a01b031660408301528215610d1c57610cf08160c00151826080015101613278565b825103825260a0810151610d1290610d0790613278565b60208401519061328e565b6020830152610d57565b610d298160a00151613278565b825101825260c08101516080820151610d5191610d469101613278565b6020840151906132aa565b60208301525b835163ffffffff1615610db7576000612710610d8a866000015163ffffffff168460c001516132c090919063ffffffff16565b81610d9157fe5b60c0840180519290910491829003905260a0840180519091016001600160801b03169052505b60c08201516001600160801b031615610df657610dea8160c00151600160801b8460c001516001600160801b03166132e4565b60808301805190910190525b80606001516001600160a01b031682604001516001600160a01b03161415610f1f57806040015115610ef6578360a00151610e8057610e5e846040015160008760200151886040015188602001518a606001516009613394909695949392919063ffffffff16565b6001600160a01b03166080860152600690810b900b6060850152600160a08501525b6000610ecc82602001518e610e9757600254610e9d565b84608001515b8f610eac578560800151610eb0565b6003545b608089015160608a015160408b01516006959493929190613526565b90508c15610ed8576000035b610ee68360c00151826135e0565b6001600160801b031660c0840152505b8b610f05578060200151610f0e565b60018160200151035b600290810b900b6060830152610f5a565b80600001516001600160a01b031682604001516001600160a01b031614610f5a57610f4d8260400151613696565b600290810b900b60608301525b50610b56565b836020015160020b816060015160020b1461102e57600080610fae86604001518660400151886020015188602001518a606001518b6080015160096139b1909695949392919063ffffffff16565b604085015160608601516000805461ffff60c81b1916600160c81b61ffff958616021761ffff60b81b1916600160b81b95909416949094029290921762ffffff60a01b1916600160a01b62ffffff60029490940b9390931692909202919091176001600160a01b0319166001600160a01b03909116179055506110539050565b6040810151600080546001600160a01b0319166001600160a01b039092169190911790555b8060c001516001600160801b031683602001516001600160801b0316146110995760c0810151600580546001600160801b0319166001600160801b039092169190911790555b6000808c156110f357608083015160025560a08301516001600160801b0316156110e75760a0830151600480546001600160801b031981166001600160801b03918216909301169190911790555b8260a001519150611140565b608083015160035560a08301516001600160801b0316156111395760a0830151600480546001600160801b03808216600160801b92839004821690940116029190911790555b5060a08201515b8315158d15151461115957602083015183518d03611166565b82600001518c0383602001515b90985096508c1561129f5760008712156111a8576111a87f00000000000000000000000043000000000000000000000000000000000000048f89600003613b4c565b60006111b2613c9a565b9050336001600160a01b03166323a69e758a8a8e8e6040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b15801561123657600080fd5b505af115801561124a573d6000803e3d6000fd5b50505050611256613c9a565b611260828b613dd3565b1115611299576040805162461bcd60e51b815260206004820152600360248201526249494160e81b604482015290519081900360640190fd5b506113c9565b60008812156112d6576112d67f00000000000000000000000043000000000000000000000000000000000000038f8a600003613b4c565b60006112e0613de3565b9050336001600160a01b03166323a69e758a8a8e8e6040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b15801561136457600080fd5b505af1158015611378573d6000803e3d6000fd5b50505050611384613de3565b61138e828a613dd3565b11156113c7576040805162461bcd60e51b815260206004820152600360248201526249494160e81b604482015290519081900360640190fd5b505b8d6001600160a01b0316336001600160a01b03167f19b47279256b2a23a1665c810c8d55a1758940ee09377d4f8d26497a3577dc838a8a87604001518860c001518960600151898960405180888152602001878152602001866001600160a01b03168152602001856001600160801b031681526020018460020b8152602001836001600160801b03168152602001826001600160801b0316815260200197505050505050505060405180910390a350506001805460ff60201b1916600160201b17905550939a92995091975050505050505050565b6005546001600160801b031681565b6004546001600160801b0380821691600160801b90041682565b60098161ffff81106114d857600080fd5b015463ffffffff81169150600160201b810460060b90600160581b81046001600160a01b031690600160f81b900460ff1684565b600154600160201b900460ff16611550576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6001805460ff60201b1916905560008054600160d81b900461ffff169061157960098385613e7b565b6000805461ffff808416600160d81b810261ffff60d81b19909316929092179092559192508316146115e6576040805161ffff80851682528316602082015281517fac49e518f90a358f652e4400164f05a5d8f7e35e7747279bc3a93dbf584e125a929181900390910190a15b50506001805460ff60201b1916600160201b17905550565b6000546001546001600160a01b03821691600160a01b810460020b9161ffff600160b81b8304811692600160c81b8104821692600160d81b9091049091169063ffffffff81169060ff600160201b9091041687565b6001546000908190600160201b900460ff1661169c576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6001805460ff60201b191690556001600160801b0385166116bc57600080fd5b60008061170a60405180608001604052808c6001600160a01b031681526020018b60020b81526020018a60020b81526020016117008a6001600160801b0316613f1e565b600f0b9052613f2f565b9250925050819350809250600080600086111561172c57611729613c9a565b91505b841561173d5761173a613de3565b90505b336001600160a01b03166399eee9d087878b8b6040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b1580156117bf57600080fd5b505af11580156117d3573d6000803e3d6000fd5b50505050600086111561182a576117e8613c9a565b6117f28388613dd3565b111561182a576040805162461bcd60e51b815260206004820152600260248201526104d360f41b604482015290519081900360640190fd5b841561187a57611838613de3565b6118428287613dd3565b111561187a576040805162461bcd60e51b81526020600482015260026024820152614d3160f01b604482015290519081900360640190fd5b8960020b8b60020b8d6001600160a01b03167f7a53080ba414158be7ec69b987b5fb7d07dee101fe85488f0853ae16239d0bde338d8b8b60405180856001600160a01b03168152602001846001600160801b0316815260200183815260200182815260200194505050505060405180910390a450506001805460ff60201b1916600160201b17905550919890975095505050505050565b60035481565b6001546000908190600160201b900460ff16611960576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6001805460ff60201b19169055600061197c600833898961415f565b60038101549091506001600160801b039081169086161161199d57846119ac565b60038101546001600160801b03165b60038201549093506001600160801b03600160801b9091048116908516116119d457836119ea565b6003810154600160801b90046001600160801b03165b91506001600160801b03831615611a4f576003810180546001600160801b031981166001600160801b03918216869003821617909155611a4f907f0000000000000000000000004300000000000000000000000000000000000003908a908616613b4c565b6001600160801b03821615611ab5576003810180546001600160801b03600160801b808304821686900382160291811691909117909155611ab5907f0000000000000000000000004300000000000000000000000000000000000004908a908516613b4c565b604080516001600160a01b038a1681526001600160801b0380861660208301528416818301529051600288810b92908a900b9133917f70935338e69775456a85ddef226c395fb668b63fa0115f5f20610b388e6ca9c0919081900360600190a4506001805460ff60201b1916600160201b17905590969095509350505050565b60086020526000908152604090208054600182015460028301546003909301546001600160801b0392831693919281811691600160801b90041685565b60076020526000908152604090205481565b7f0000000000000000000000000000000000005e8b2285f864419ac400be90719681565b6001546000908190600160201b900460ff16611bf1576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6001805460ff60201b19169055336001600160a01b037f000000000000000000000000d1575b2e0c82fba9eddc3de9c9aaf923afa670cc161480611cc157507f000000000000000000000000d1575b2e0c82fba9eddc3de9c9aaf923afa670cc6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611c8957600080fd5b505afa158015611c9d573d6000803e3d6000fd5b505050506040513d6020811015611cb357600080fd5b50516001600160a01b031633145b611cca57600080fd5b6004546001600160801b0390811690851611611ce65783611cf3565b6004546001600160801b03165b6004549092506001600160801b03600160801b909104811690841611611d195782611d2d565b600454600160801b90046001600160801b03165b90506001600160801b03821615611dae576004546001600160801b0383811691161415611d5c57600019909101905b600480546001600160801b031981166001600160801b03918216859003821617909155611dae907f00000000000000000000000043000000000000000000000000000000000000039087908516613b4c565b6001600160801b03811615611e34576004546001600160801b03828116600160801b909204161415611ddf57600019015b600480546001600160801b03600160801b808304821685900382160291811691909117909155611e34907f00000000000000000000000043000000000000000000000000000000000000049087908416613b4c565b604080516001600160801b0380851682528316602082015281516001600160a01b0388169233927f596b573906218d3411850b26a6b437d6c4522fdb43d2d2386263f86d50b8b151929081900390910190a36001805460ff60201b1916600160201b1790559094909350915050565b606080611f1642858580806020026020016040519081016040528093929190818152602001838360200280828437600092018290525054600554600996959450600160a01b820460020b935061ffff600160b81b8304811693506001600160801b0390911691600160c81b9004166141c3565b915091509250929050565b6001546000908190600160201b900460ff16611f6a576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6001805460ff60201b1916905560408051608081018252338152600287810b602083015286900b9181019190915260009081908190611fc69060608101611fb96001600160801b038a16613f1e565b600003600f0b9052613f2f565b9250925092508160000394508060000393506000851180611fe75750600084115b15612026576003830180546001600160801b038082168089018216600160801b93849004831689019092169092029091176001600160801b0319161790555b604080516001600160801b0388168152602081018790528082018690529051600289810b92908b900b9133917f0c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c919081900360600190a450506001805460ff60201b1916600160201b179055509094909350915050565b60008060006120ac858561431d565b600285810b810b600090815260066020819052604080832088850b90940b8352822060038401549182900b93600160381b83046001600160a01b0316928492600160d81b820463ffffffff16928492909190600160f81b900460ff168061211257600080fd5b6003820154600681900b9850600160381b81046001600160a01b03169650600160d81b810463ffffffff169450600160f81b900460ff168061215357600080fd5b50506040805160e0810182526000546001600160a01b0381168252600160a01b8104600290810b810b810b6020840181905261ffff600160b81b8404811695850195909552600160c81b830485166060850152600160d81b909204909316608083015260015463ffffffff811660a084015260ff600160201b90910416151560c08301529093508e820b910b121590506121fb57509390940396509003935090039050612275565b8a60020b816020015160020b121561226657602081015160408201516005546060840151429360009384936122449360099388938793919290916001600160801b031690613394565b9a9003989098039b505094909603929092039650909103039250612275915050565b50949093039650039350900390505b9250925092565b60008080336001600160a01b037f000000000000000000000000d1575b2e0c82fba9eddc3de9c9aaf923afa670cc16148061234357507f000000000000000000000000d1575b2e0c82fba9eddc3de9c9aaf923afa670cc6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561230b57600080fd5b505afa15801561231f573d6000803e3d6000fd5b505050506040513d602081101561233557600080fd5b50516001600160a01b031633145b61234c57600080fd5b60408051635569f64b60e11b81526001600160a01b03881660048201526024810187905290516004604360981b019163aad3ec969160448083019260209291908290030181600087803b1580156123a257600080fd5b505af11580156123b6573d6000803e3d6000fd5b505050506040513d60208110156123cc57600080fd5b505160408051635569f64b60e11b81526001600160a01b03891660048201526024810187905290519194506003604360981b019163aad3ec96916044808201926020929091908290030181600087803b15801561242857600080fd5b505af115801561243c573d6000803e3d6000fd5b505050506040513d602081101561245257600080fd5b50516040805163662aa11d60e01b81523060048201526001600160a01b038916602482015290519193506002604360981b019163662aa11d916044808201926020929091908290030181600087803b1580156124ad57600080fd5b505af11580156124c1573d6000803e3d6000fd5b505050506040513d60208110156124d757600080fd5b50519296919550919350915050565b600154600160201b900460ff1661252a576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6001805460ff60201b19169055336001600160a01b037f000000000000000000000000d1575b2e0c82fba9eddc3de9c9aaf923afa670cc1614806125fa57507f000000000000000000000000d1575b2e0c82fba9eddc3de9c9aaf923afa670cc6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156125c257600080fd5b505afa1580156125d6573d6000803e3d6000fd5b505050506040513d60208110156125ec57600080fd5b50516001600160a01b031633145b61260357600080fd5b63ffffffff8216158061263157506103e88263ffffffff16101580156126315750610fa08263ffffffff1611155b8015612666575063ffffffff8116158061266657506103e88163ffffffff16101580156126665750610fa08163ffffffff1611155b61266f57600080fd5b6001805465ffffffff0000601084901b16840163ffffffff90811663ffffffff19831617909255167fb3159fed3ddfba67bae294599eafe2d0ec98c08bb38e0e5fb87d33154b6e05aa62010000826040805163ffffffff939092068316825261ffff601086901c16602083015286831682820152918516606082015290519081900360800190a150506001805460ff60201b1916600160201b17905550565b7f000000000000000000000000d1575b2e0c82fba9eddc3de9c9aaf923afa670cc81565b7f000000000000000000000000000000000000000000000000000000000000000a81565b7f000000000000000000000000430000000000000000000000000000000000000481565b7f00000000000000000000000000000000000000000000000000000000000001f481565b60025481565b60066020819052600091825260409091208054600182015460028301546003909301546001600160801b03831694600160801b909304600f0b93919281900b90600160381b81046001600160a01b031690600160d81b810463ffffffff1690600160f81b900460ff1688565b6000546001600160a01b031615612853576040805162461bcd60e51b8152602060048201526002602482015261414960f01b604482015290519081900360640190fd5b732536fe9ab3f511540f2f9e2ec2a805005c3dd8006001600160a01b03166336b91f2b7f000000000000000000000000d1575b2e0c82fba9eddc3de9c9aaf923afa670cc6001600160a01b031663bd454fae6040518163ffffffff1660e01b815260040160206040518083038186803b1580156128cf57600080fd5b505afa1580156128e3573d6000803e3d6000fd5b505050506040513d60208110156128f957600080fd5b5051604080516001600160e01b031960e085901b1681526001600160a01b03909216600483015251602480830192600092919082900301818387803b15801561294157600080fd5b505af1158015612955573d6000803e3d6000fd5b50505050600061296482613696565b90506000806129746009426143e6565b6040805160e0810182526001600160a01b038816808252600288810b60208401819052600094840185905261ffff8781166060860181905290871660808601819052630c800c8060a08701819052600160c090970187905287546001600160a01b03191690951762ffffff60a01b1916600160a01b62ffffff9490950b8416949094029390931763ffffffff60b81b1916600160c81b9091021761ffff60d81b1916600160d81b909202919091179093558154600160201b63ffffffff1990911690911760ff60201b191617905591935091507f00000000000000000000000000000000000000000000000000000000000001f41660641415612a89576001805463ffffffff1916630ce40ce4179055612b5a565b7f00000000000000000000000000000000000000000000000000000000000001f462ffffff166101f41415612ad0576001805463ffffffff1916630d480d48179055612b5a565b7f00000000000000000000000000000000000000000000000000000000000001f462ffffff166109c41415612b17576001805463ffffffff1916630c800c80179055612b5a565b7f00000000000000000000000000000000000000000000000000000000000001f462ffffff166127101415612b5a576001805463ffffffff1916630c800c801790555b604080516001600160a01b0386168152600285900b602082015281517f98636036cb66a9c19a37435efc1e90142190214e8abeb821bdba3f2990dd4c95929181900390910190a150505050565b60008082600281900b620d89e71981612bbc57fe5b05029050600083600281900b620d89e881612bd357fe5b0502905060008460020b83830360020b81612bea57fe5b0560010190508062ffffff166001600160801b03801681612c0757fe5b0493505050505b919050565b60008060008460020b8660020b81612c2757fe5b05905060008660020b128015612c4e57508460020b8660020b81612c4757fe5b0760020b15155b15612c5857600019015b8315612ccd57600080612c6a83614432565b600182810b810b600090815260208d9052604090205460ff83169190911b80016000190190811680151597509294509092509085612caf57888360ff16860302612cc2565b88612cb982614444565b840360ff168603025b965050505050612d4b565b600080612cdc83600101614432565b91509150600060018260ff166001901b031990506000818b60008660010b60010b8152602001908152602001600020541690508060001415955085612d2e57888360ff0360ff16866001010102612d44565b8883612d39836144e3565b0360ff168660010101025b9650505050505b5094509492505050565b60008060008360020b12612d6c578260020b612d74565b8260020b6000035b9050620d89e8811115612db2576040805162461bcd60e51b81526020600482015260016024820152601560fa1b604482015290519081900360640190fd5b600060018216612dc657600160801b612dd8565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff1690506002821615612e0c576ffff97272373d413259a46990580e213a0260801c5b6004821615612e2b576ffff2e50f5f656932ef12357cf3c7fdcc0260801c5b6008821615612e4a576fffe5caca7e10e4e61c3624eaa0941cd00260801c5b6010821615612e69576fffcb9843d60f6159c9db58835c9266440260801c5b6020821615612e88576fff973b41fa98c081472e6896dfb254c00260801c5b6040821615612ea7576fff2ea16466c96a3843ec78b326b528610260801c5b6080821615612ec6576ffe5dee046a99a2a811c461f1969c30530260801c5b610100821615612ee6576ffcbe86c7900a88aedcffc83b479aa3a40260801c5b610200821615612f06576ff987a7253ac413176f2b074cf7815e540260801c5b610400821615612f26576ff3392b0822b70005940c7a398e4b70f30260801c5b610800821615612f46576fe7159475a2c29b7443b29c7fa6e889d90260801c5b611000821615612f66576fd097f3bdfd2022b8845ad8f792aa58250260801c5b612000821615612f86576fa9f746462d870fdf8a65dc1f90e061e50260801c5b614000821615612fa6576f70d869a156d2a1b890bb3df62baf32f70260801c5b618000821615612fc6576f31be135f97d08fd981231505542fcfa60260801c5b62010000821615612fe7576f09aa508b5b7a84e1c677de54f3e99bc90260801c5b62020000821615613007576e5d6af8dedb81196699c329225ee6040260801c5b62040000821615613026576d2216e584f5fa1ea926041bedfe980260801c5b62080000821615613043576b048a170391f7dc42444e8fa20260801c5b60008460020b131561305e57806000198161305a57fe5b0490505b600160201b810615613071576001613074565b60005b60ff16602082901c0192505050919050565b60008080806001600160a01b03808916908a16101581871280159061310b5760006130bf8989620f42400362ffffff16620f42406132e4565b9050826130d8576130d38c8c8c60016145cd565b6130e5565b6130e58b8d8c6001614648565b95508581106130f6578a9650613105565b6131028c8b83866146f3565b96505b50613155565b816131225761311d8b8b8b6000614648565b61312f565b61312f8a8c8b60006145cd565b935083886000031061314357899550613155565b6131528b8a8a6000038561473f565b95505b6001600160a01b038a81169087161482156131b8578080156131745750815b61318a57613185878d8c6001614648565b61318c565b855b9550808015613199575081155b6131af576131aa878d8c60006145cd565b6131b1565b845b9450613202565b8080156131c25750815b6131d8576131d38c888c60016145cd565b6131da565b855b95508080156131e7575081155b6131fd576131f88c888c6000614648565b6131ff565b845b94505b8115801561321257508860000385115b1561321e578860000394505b81801561323d57508a6001600160a01b0316876001600160a01b031614155b1561324c578589039350613269565b613266868962ffffff168a620f42400362ffffff1661478b565b93505b50505095509550955095915050565b6000600160ff1b821061328a57600080fd5b5090565b808203828113156000831215146132a457600080fd5b92915050565b818101828112156000831215146132a457600080fd5b60008215806132db575050818102818382816132d857fe5b04145b6132a457600080fd5b600080806000198587098686029250828110908390030390508061331a576000841161330f57600080fd5b50829004905061338d565b80841161332657600080fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150505b9392505050565b60008063ffffffff871661343a576000898661ffff1661ffff81106133b557fe5b60408051608081018252919092015463ffffffff808216808452600160201b8304600690810b810b900b6020850152600160581b83046001600160a01b031694840194909452600160f81b90910460ff16151560608301529092508a161461342657613423818a89886147c5565b90505b80602001518160400151925092505061351a565b86880360008061344f8c8c858c8c8c8c614868565b91509150816000015163ffffffff168363ffffffff16141561348157816020015182604001519450945050505061351a565b805163ffffffff848116911614156134a957806020015181604001519450945050505061351a565b8151815160208085015190840151918390039286039163ffffffff80841692908516910360060b816134d757fe5b05028460200151018263ffffffff168263ffffffff1686604001518660400151036001600160a01b0316028161350957fe5b048560400151019650965050505050505b97509795505050505050565b600295860b860b60009081526020979097526040909620600181018054909503909455938301805490920390915560038201805463ffffffff600160d81b6001600160a01b03600160381b808504821690960316909402600160381b600160d81b031990921691909117600681810b90960390950b66ffffffffffffff1666ffffffffffffff199095169490941782810485169095039093160263ffffffff60d81b1990931692909217905554600160801b9004600f0b90565b60008082600f0b121561364557826001600160801b03168260000384039150816001600160801b031610613640576040805162461bcd60e51b81526020600482015260026024820152614c5360f01b604482015290519081900360640190fd5b6132a4565b826001600160801b03168284019150816001600160801b031610156132a4576040805162461bcd60e51b81526020600482015260026024820152614c4160f01b604482015290519081900360640190fd5b60006401000276a36001600160a01b038316108015906136d2575073fffd8963efd1fc6a506488495d951d5263988d266001600160a01b038316105b613707576040805162461bcd60e51b81526020600482015260016024820152602960f91b604482015290519081900360640190fd5b640100000000600160c01b03602083901b166001600160801b03811160071b81811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c60ff8111600390811b91821c600f811160021b90811c918211600190811b92831c9790881196179094179092171790911717176080811061379b57607f810383901c91506137a5565b80607f0383901b91505b908002607f81811c60ff83811c9190911c800280831c81831c1c800280841c81841c1c800280851c81851c1c800280861c81861c1c800280871c81871c1c800280881c81881c1c800280891c81891c1c8002808a1c818a1c1c8002808b1c818b1c1c8002808c1c818c1c1c8002808d1c818d1c1c8002808e1c9c81901c9c909c1c80029c8d901c9e9d607f198f0160401b60c09190911c678000000000000000161760c19b909b1c674000000000000000169a909a1760c29990991c672000000000000000169890981760c39790971c671000000000000000169690961760c49590951c670800000000000000169490941760c59390931c670400000000000000169290921760c69190911c670200000000000000161760c79190911c600160381b161760c89190911c6680000000000000161760c99190911c6640000000000000161760ca9190911c6620000000000000161760cb9190911c6610000000000000161760cc9190911c6608000000000000161760cd9190911c66040000000000001617693627a301d71055774c8581026f028f6481ab7f045a5af012a19d003aa9198101608090811d906fdb2df09e81959a81455e260799a0632f8301901d600281810b9083900b146139a257886001600160a01b031661398682612d55565b6001600160a01b0316111561399b578161399d565b805b6139a4565b815b9998505050505050505050565b6000806000898961ffff1661ffff81106139c757fe5b60408051608081018252919092015463ffffffff808216808452600160201b8304600690810b810b900b6020850152600160581b83046001600160a01b031694840194909452600160f81b90910460ff161515606083015290925089161415613a36578885925092505061351a565b8461ffff168461ffff16118015613a5757506001850361ffff168961ffff16145b15613a6457839150613a68565b8491505b8161ffff168960010161ffff1681613a7c57fe5b069250613a8b818989896147c5565b8a8461ffff1661ffff8110613a9c57fe5b825191018054602084015160408501516060909501511515600160f81b026001600160f81b036001600160a01b03909616600160581b027fff0000000000000000000000000000000000000000ffffffffffffffffffffff60069390930b66ffffffffffffff16600160201b026affffffffffffff000000001963ffffffff90971663ffffffff199095169490941795909516929092171692909217929092161790555097509795505050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b60208310613bc85780518252601f199092019160209182019101613ba9565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613c2a576040519150601f19603f3d011682016040523d82523d6000602084013e613c2f565b606091505b5091509150818015613c5d575080511580613c5d5750808060200190516020811015613c5a57600080fd5b50515b613c93576040805162461bcd60e51b81526020600482015260026024820152612a2360f11b604482015290519081900360640190fd5b5050505050565b604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b17815291518151600093849384936001600160a01b037f00000000000000000000000043000000000000000000000000000000000000031693919290918291908083835b60208310613d335780518252601f199092019160209182019101613d14565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114613d93576040519150601f19603f3d011682016040523d82523d6000602084013e613d98565b606091505b5091509150818015613dac57506020815110155b613db557600080fd5b808060200190516020811015613dca57600080fd5b50519250505090565b808201828110156132a457600080fd5b604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b17815291518151600093849384936001600160a01b037f000000000000000000000000430000000000000000000000000000000000000416939192909182919080838360208310613d335780518252601f199092019160209182019101613d14565b6000808361ffff1611613eb9576040805162461bcd60e51b81526020600482015260016024820152604960f81b604482015290519081900360640190fd5b8261ffff168261ffff1611613ecf57508161338d565b825b8261ffff168161ffff161015613f15576001858261ffff1661ffff8110613ef457fe5b01805463ffffffff191663ffffffff92909216919091179055600101613ed1565b50909392505050565b80600f81900b8114612c0e57600080fd5b6000806000613f468460200151856040015161431d565b6040805160e0810182526000546001600160a01b0381168252600160a01b8104600290810b810b900b602080840182905261ffff600160b81b8404811685870152600160c81b84048116606080870191909152600160d81b90940416608085015260015463ffffffff811660a086015260ff600160201b90910416151560c085015288519089015194890151928901519394613fe89491939092909190614a62565b93508460600151600f0b60001461415757846020015160020b816020015160020b121561403d5761403661401f8660200151612d55565b61402c8760400151612d55565b8760600151614c09565b9250614157565b846040015160020b816020015160020b121561412d5760055460408201516020830151606084015160808501516001600160801b039094169361408993600993909242928791906139b1565b6000805461ffff60c81b1916600160c81b61ffff938416021761ffff60b81b1916600160b81b9390921692909202179055815160408701516140d991906140cf90612d55565b8860600151614c09565b93506140f76140eb8760200151612d55565b83516060890151614c4d565b92506141078187606001516135e0565b600580546001600160801b0319166001600160801b039290921691909117905550614157565b61415461413d8660200151612d55565b61414a8760400151612d55565b8760600151614c4d565b91505b509193909250565b6040805160609490941b6bffffffffffffffffffffffff1916602080860191909152600293840b60e890811b60348701529290930b90911b60378401528051808403601a018152603a90930181528251928201929092206000908152929052902090565b60608060008361ffff1611614203576040805162461bcd60e51b81526020600482015260016024820152604960f81b604482015290519081900360640190fd5b865167ffffffffffffffff8111801561421b57600080fd5b50604051908082528060200260200182016040528015614245578160200160208202803683370190505b509150865167ffffffffffffffff8111801561426057600080fd5b5060405190808252806020026020018201604052801561428a578160200160208202803683370190505b50905060005b8751811015614310576142bb8a8a8a84815181106142aa57fe5b60200260200101518a8a8a8a613394565b8483815181106142c757fe5b602002602001018484815181106142da57fe5b60200260200101826001600160a01b03166001600160a01b03168152508260060b60060b81525050508080600101915050614290565b5097509795505050505050565b8060020b8260020b1261435d576040805162461bcd60e51b8152602060048201526003602482015262544c5560e81b604482015290519081900360640190fd5b620d89e719600283900b12156143a0576040805162461bcd60e51b8152602060048201526003602482015262544c4d60e81b604482015290519081900360640190fd5b620d89e8600282900b13156143e2576040805162461bcd60e51b815260206004820152600360248201526254554d60e81b604482015290519081900360640190fd5b5050565b6040805160808101825263ffffffff9283168082526000602083018190529282019290925260016060909101819052835463ffffffff1916909117909116600160f81b17909155908190565b60020b600881901d9161010090910790565b600080821161445257600080fd5b600160801b821061446557608091821c91015b68010000000000000000821061447d57604091821c91015b600160201b821061449057602091821c91015b6201000082106144a257601091821c91015b61010082106144b357600891821c91015b601082106144c357600491821c91015b600482106144d357600291821c91015b60028210612c0e57600101919050565b60008082116144f157600080fd5b5060ff6001600160801b0382161561450c57607f1901614514565b608082901c91505b67ffffffffffffffff82161561452d57603f1901614535565b604082901c91505b63ffffffff82161561454a57601f1901614552565b602082901c91505b61ffff82161561456557600f190161456d565b601082901c91505b60ff82161561457f5760071901614587565b600882901c91505b600f82161561459957600319016145a1565b600482901c91505b60038216156145b357600119016145bb565b600282901c91505b6001821615612c0e5760001901919050565b6000836001600160a01b0316856001600160a01b031611156145ed579293925b8161461a57614615836001600160801b03168686036001600160a01b0316600160601b6132e4565b61463d565b61463d836001600160801b03168686036001600160a01b0316600160601b61478b565b90505b949350505050565b6000836001600160a01b0316856001600160a01b03161115614668579293925b600160601b600160e01b03606084901b166001600160a01b03868603811690871661469257600080fd5b836146c257866001600160a01b03166146b58383896001600160a01b03166132e4565b816146bc57fe5b046146e8565b6146e86146d98383896001600160a01b031661478b565b886001600160a01b0316614c7c565b979650505050505050565b600080856001600160a01b03161161470a57600080fd5b6000846001600160801b03161161472057600080fd5b81614732576146158585856001614c87565b61463d8585856001614d68565b600080856001600160a01b03161161475657600080fd5b6000846001600160801b03161161476c57600080fd5b8161477e576146158585856000614d68565b61463d8585856000614c87565b60006147988484846132e4565b9050600082806147a457fe5b848609111561338d5760001981106147bb57600080fd5b6001019392505050565b6147cd615588565b600085600001518503905060405180608001604052808663ffffffff1681526020018263ffffffff168660020b0288602001510160060b81526020016000856001600160801b031611614821576001614823565b845b6001600160801b031663ffffffff60801b608085901b168161484157fe5b048860400151016001600160a01b0316815260200160011515815250915050949350505050565b614870615588565b614878615588565b888561ffff1661ffff811061488957fe5b60408051608081018252919092015463ffffffff8116808352600160201b8204600690810b810b900b6020840152600160581b82046001600160a01b031693830193909352600160f81b900460ff161515606082015292506148ed90899089614e4b565b15614925578663ffffffff16826000015163ffffffff16141561490f5761351a565b8161491c838989886147c5565b9150915061351a565b888361ffff168660010161ffff168161493a57fe5b0661ffff1661ffff811061494a57fe5b60408051608081018252929091015463ffffffff81168352600160201b8104600690810b810b900b60208401526001600160a01b03600160581b8204169183019190915260ff600160f81b909104161515606082018190529092506149ff57604080516080810182528a5463ffffffff81168252600160201b8104600690810b810b900b6020830152600160581b81046001600160a01b031692820192909252600160f81b90910460ff161515606082015291505b614a0e88836000015189614e4b565b614a45576040805162461bcd60e51b815260206004820152600360248201526213d31160ea1b604482015290519081900360640190fd5b614a528989898887614f0c565b9150915097509795505050505050565b6000614a71600887878761415f565b60025460035491925090600080600f87900b15614ba957600080546005544292918291614ace9160099186918591600160a01b820460020b9161ffff600160b81b82048116926001600160801b031691600160c81b900416613394565b9092509050614b0860068d8b8d8b8b87898b60007f0000000000000000000000000000000000005e8b2285f864419ac400be9071966150aa565b9450614b3f60068c8b8d8b8b87898b60017f0000000000000000000000000000000000005e8b2285f864419ac400be9071966150aa565b93508415614b7357614b7360078d7f000000000000000000000000000000000000000000000000000000000000000a615263565b8315614ba557614ba560078c7f000000000000000000000000000000000000000000000000000000000000000a615263565b5050505b600080614bbb60068c8c8b8a8a6152c9565b9092509050614bcc878a8484615375565b600089600f0b1215614bfa578315614be957614be960068c61550a565b8215614bfa57614bfa60068b61550a565b50505050505095945050505050565b60008082600f0b12614c2f57614c2a614c258585856001614648565b613278565b614640565b614c42614c258585856000036000614648565b600003949350505050565b60008082600f0b12614c6957614c2a614c2585858560016145cd565b614c42614c2585858560000360006145cd565b808204910615150190565b60008115614cfa5760006001600160a01b03841115614cbd57614cb884600160601b876001600160801b03166132e4565b614cd5565b6001600160801b038516606085901b81614cd357fe5b045b9050614cf2614ced6001600160a01b03881683613dd3565b615536565b915050614640565b60006001600160a01b03841115614d2857614d2384600160601b876001600160801b031661478b565b614d3f565b614d3f606085901b6001600160801b038716614c7c565b905080866001600160a01b031611614d5657600080fd5b6001600160a01b038616039050614640565b600082614d76575083614640565b600160601b600160e01b03606085901b168215614e04576001600160a01b03861684810290858281614da457fe5b041415614dd557818101828110614dd357614dc983896001600160a01b03168361478b565b9350505050614640565b505b614dfb82614df6878a6001600160a01b03168681614def57fe5b0490613dd3565b614c7c565b92505050614640565b6001600160a01b03861684810290858281614e1b57fe5b04148015614e2857508082115b614e3157600080fd5b808203614dc9614ced846001600160a01b038b168461478b565b60008363ffffffff168363ffffffff1611158015614e7557508363ffffffff168263ffffffff1611155b15614e91578163ffffffff168363ffffffff161115905061338d565b60008463ffffffff168463ffffffff1611614eb8578363ffffffff16600160201b01614ec0565b8363ffffffff165b64ffffffffff16905060008563ffffffff168463ffffffff1611614ef0578363ffffffff16600160201b01614ef8565b8363ffffffff165b64ffffffffff169091111595945050505050565b614f14615588565b614f1c615588565b60008361ffff168560010161ffff1681614f3257fe5b0661ffff169050600060018561ffff16830103905060005b506002818301048961ffff87168281614f5f57fe5b0661ffff8110614f6b57fe5b60408051608081018252929091015463ffffffff81168352600160201b8104600690810b810b900b60208401526001600160a01b03600160581b8204169183019190915260ff600160f81b90910416151560608201819052909550614fd557806001019250614f4a565b898661ffff168260010181614fe657fe5b0661ffff8110614ff257fe5b60408051608081018252929091015463ffffffff81168352600160201b8104600690810b810b900b60208401526001600160a01b03600160581b8204169183019190915260ff600160f81b9091041615156060820152855190945060009061505c908b908b614e4b565b905080801561507557506150758a8a8760000151614e4b565b15615080575061509d565b8061509057600182039250615097565b8160010193505b50614f4a565b5050509550959350505050565b60028a810b900b600090815260208c90526040812080546001600160801b0316826150d5828d6135e0565b9050846001600160801b0316816001600160801b03161115615123576040805162461bcd60e51b81526020600482015260026024820152614c4f60f01b604482015290519081900360640190fd5b6001600160801b0382811615908216158114159450156151c8578c60020b8e60020b136151b057600183018b9055600283018a9055600383018054600160381b600160d81b031916600160381b6001600160a01b038c16021766ffffffffffffff191666ffffffffffffff60068b900b161763ffffffff60d81b1916600160d81b63ffffffff8a16021790555b6003830180546001600160f81b0316600160f81b1790555b82546001600160801b0319166001600160801b0382161783558561521157825461520c9061520790600160801b9004600f90810b810b908f900b6132aa565b613f1e565b615232565b82546152329061520790600160801b9004600f90810b810b908f900b61328e565b8354600f9190910b6001600160801b03908116600160801b0291161790925550909c9b505050505050505050505050565b8060020b8260020b8161527257fe5b0760020b1561528057600080fd5b60008061529b8360020b8560020b8161529557fe5b05614432565b600191820b820b60009081526020979097526040909620805460ff9097169190911b90951890945550505050565b600285810b80820b60009081526020899052604080822088850b850b83529082209193849391929184918291908a900b1261530f57505060018201546002830154615322565b8360010154880391508360020154870390505b6000808b60020b8b60020b121561534457505060018301546002840154615357565b84600101548a0391508460020154890390505b92909803979097039b96909503949094039850939650505050505050565b6040805160a08101825285546001600160801b0390811682526001870154602083015260028701549282019290925260038601548083166060830152600160801b900490911660808201526000600f85900b6154145781516001600160801b031661540c576040805162461bcd60e51b815260206004820152600260248201526104e560f41b604482015290519081900360640190fd5b508051615423565b815161542090866135e0565b90505b60006154478360200151860384600001516001600160801b0316600160801b6132e4565b9050600061546d8460400151860385600001516001600160801b0316600160801b6132e4565b905086600f0b6000146154945787546001600160801b0319166001600160801b0384161788555b60018801869055600288018590556001600160801b0382161515806154c257506000816001600160801b0316115b15615500576003880180546001600160801b031981166001600160801b039182168501821617808216600160801b9182900483168501909216021790555b5050505050505050565b600290810b810b6000908152602092909252604082208281556001810183905590810182905560030155565b806001600160a01b0381168114612c0e57600080fd5b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b6040805160808101825260008082526020820181905291810182905260608101919091529056fea164736f6c6343000706000a
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.