More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 112 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Collect Fee Char... | 50625246 | 2 days ago | IN | 0 ETH | 0.00000449 | ||||
Collect Fee Char... | 50625233 | 2 days ago | IN | 0 ETH | 0.00000773 | ||||
Collect Fee Char... | 49751360 | 13 days ago | IN | 0 ETH | 0.00001017 | ||||
Collect Fee Char... | 47813256 | 38 days ago | IN | 0 ETH | 0.00000668 | ||||
Collect Fee Char... | 43446148 | 94 days ago | IN | 0 ETH | 0.00000622 | ||||
Modify Fee Charg... | 42888588 | 101 days ago | IN | 0 ETH | 0.000005 | ||||
Collect Fee Char... | 38721296 | 151 days ago | IN | 0 ETH | 0.00000435 | ||||
Collect Fee Char... | 37958179 | 160 days ago | IN | 0 ETH | 0.00000255 | ||||
Collect Fee Char... | 37371481 | 167 days ago | IN | 0 ETH | 0.00000254 | ||||
Collect Fee Char... | 36932675 | 173 days ago | IN | 0 ETH | 0.00000375 | ||||
Collect Fee Char... | 36796196 | 174 days ago | IN | 0 ETH | 0.00000507 | ||||
Collect Fee Char... | 36452442 | 178 days ago | IN | 0 ETH | 0.00000406 | ||||
Collect Fee Char... | 35699646 | 187 days ago | IN | 0 ETH | 0.00000511 | ||||
Collect Fee Char... | 35103928 | 195 days ago | IN | 0 ETH | 0.0000055 | ||||
Collect Fee Char... | 34778910 | 198 days ago | IN | 0 ETH | 0.00000502 | ||||
Collect Fee Char... | 34695616 | 199 days ago | IN | 0 ETH | 0.00000477 | ||||
Collect Fee Char... | 34531494 | 201 days ago | IN | 0 ETH | 0.00000541 | ||||
Collect Fee Char... | 34189653 | 205 days ago | IN | 0 ETH | 0.00000453 | ||||
Collect Fee Char... | 34029821 | 207 days ago | IN | 0 ETH | 0.00000468 | ||||
Collect Fee Char... | 33765985 | 211 days ago | IN | 0 ETH | 0.0000046 | ||||
Collect Fee Char... | 32934292 | 221 days ago | IN | 0 ETH | 0.00000483 | ||||
Collect Fee Char... | 32784183 | 222 days ago | IN | 0 ETH | 0.0000051 | ||||
Collect Fee Char... | 32699072 | 223 days ago | IN | 0 ETH | 0.00000507 | ||||
Collect Fee Char... | 32114817 | 231 days ago | IN | 0 ETH | 0.00000501 | ||||
Collect Fee Char... | 31871359 | 233 days ago | IN | 0 ETH | 0.00000515 |
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
8843184 | 510 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0x6ac81d4c...1c2C16b97 The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
iZiSwapPool
Compiler Version
v0.8.17+commit.8df45f5f
ZkSolc Version
v1.3.5
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.16; import "./interfaces/IiZiSwapPool.sol"; import "./interfaces/IiZiSwapFactory.sol"; import "./interfaces/IiZiSwapFlashCallback.sol"; import "./interfaces/IiZiSwapCallback.sol"; import "./interfaces/IOwnable.sol"; import "./libraries/Liquidity.sol"; import "./libraries/Point.sol"; import "./libraries/PointBitmap.sol"; import "./libraries/LogPowMath.sol"; import "./libraries/MulDivMath.sol"; import "./libraries/TwoPower.sol"; import "./libraries/LimitOrder.sol"; import "./libraries/AmountMath.sol"; import "./libraries/UserEarn.sol"; import "./libraries/TokenTransfer.sol"; import "./libraries/State.sol"; import "./libraries/Oracle.sol"; import "./libraries/OrderOrEndpoint.sol"; import "./libraries/SwapMathY2X.sol"; import "./libraries/SwapMathX2Y.sol"; contract iZiSwapPool is IiZiSwapPool { using Liquidity for mapping(bytes32 =>Liquidity.Data); using Liquidity for Liquidity.Data; using Point for mapping(int24 =>Point.Data); using Point for Point.Data; using PointBitmap for mapping(int16 =>uint256); using LimitOrder for LimitOrder.Data; using UserEarn for UserEarn.Data; using UserEarn for mapping(bytes32 =>UserEarn.Data); using Oracle for Oracle.Observation[65535]; using OrderOrEndpoint for mapping(int24 =>int24); int24 internal constant LEFT_MOST_PT = -800000; int24 internal constant RIGHT_MOST_PT = 800000; /// @notice left most point regularized by pointDelta int24 public leftMostPt; /// @notice right most point regularized by pointDelta int24 public rightMostPt; /// @notice maximum liquidSum for each point, see points() in IiZiSwapPool or library Point uint128 public maxLiquidPt; /// @notice address of iZiSwapFactory address public factory; /// @notice address of tokenX address public tokenX; /// @notice address of tokenY address public tokenY; /// @notice fee amount of this swap pool, 3000 means 0.3% uint24 public fee; /// @notice minimum number of distance between initialized or limitorder points int24 public pointDelta; /// @notice the fee growth as a 128-bit fixpoing fees of tokenX collected per 1 liquidity of the pool uint256 public feeScaleX_128; /// @notice the fee growth as a 128-bit fixpoint fees of tokenY collected per 1 liquidity of the pool uint256 public feeScaleY_128; /// @notice sqrt(1.0001), 96 bit fixpoint number uint160 public override sqrtRate_96; /// @notice state of pool, see library State or IiZiSwapPool#state for more infomation State public override state; /// @notice the information about a liquidity by the liquidity's key mapping(bytes32 =>Liquidity.Data) public override liquidity; /// @notice 256 packed point (orderOrEndpoint>0) boolean values. See PointBitmap for more information mapping(int16 =>uint256) public override pointBitmap; /// @notice returns infomation of a point in the pool, see Point library of IiZiSwapPool#poitns for more information mapping(int24 =>Point.Data) public override points; /// @notice infomation about a point whether has limit order and whether as an liquidity's endpoint mapping(int24 =>int24) public override orderOrEndpoint; /// @notice limitOrder info on a given point mapping(int24 =>LimitOrder.Data) public override limitOrderData; /// @notice information about a user's limit order (sell tokenY and earn tokenX) mapping(bytes32 => UserEarn.Data) public override userEarnX; /// @notice information about a user's limit order (sell tokenX and earn tokenY) mapping(bytes32 => UserEarn.Data) public override userEarnY; /// @notice observation data array Oracle.Observation[65535] public override observations; uint256 public override totalFeeXCharged; uint256 public override totalFeeYCharged; address private original; address private swapModuleX2Y; address private swapModuleY2X; address private liquidityModule; address private limitOrderModule; address private flashModule; /// @notice percent to charge from miner's fee uint24 public override feeChargePercent; modifier lock() { require(!state.locked, 'LKD'); state.locked = true; _; state.locked = false; } modifier noDelegateCall() { require(address(this) == original); _; } function _setRange(int24 pd) private { rightMostPt = RIGHT_MOST_PT / pd * pd; leftMostPt = - rightMostPt; uint24 pointNum = uint24((rightMostPt - leftMostPt) / pd) + 1; maxLiquidPt = type(uint128).max / pointNum; } /// @notice Construct a pool constructor() { (address _tokenX, address _tokenY, uint24 _fee, int24 currentPoint, int24 _pointDelta, uint24 _feeChargePercent) = IiZiSwapFactory(msg.sender).deployPoolParams(); require(_tokenX < _tokenY, 'x<y'); require(_pointDelta > 0, 'pd0'); original = address(this); factory = msg.sender; swapModuleX2Y = IiZiSwapFactory(msg.sender).swapX2YModule(); swapModuleY2X = IiZiSwapFactory(msg.sender).swapY2XModule(); liquidityModule = IiZiSwapFactory(msg.sender).liquidityModule(); limitOrderModule = IiZiSwapFactory(msg.sender).limitOrderModule(); flashModule = IiZiSwapFactory(msg.sender).flashModule(); tokenX = _tokenX; tokenY = _tokenY; fee = _fee; pointDelta = _pointDelta; _setRange(_pointDelta); require(currentPoint >= leftMostPt, "LO"); require(currentPoint <= rightMostPt, "HO"); // current state state.currentPoint = currentPoint; state.sqrtPrice_96 = LogPowMath.getSqrtPrice(currentPoint); state.liquidity = 0; state.liquidityX = 0; sqrtRate_96 = LogPowMath.getSqrtPrice(1); (state.observationQueueLen, state.observationNextQueueLen) = observations.init(uint32(block.timestamp)); state.observationCurrentIndex = 0; feeChargePercent = _feeChargePercent; } function balanceX() private view returns (uint256) { (bool success, bytes memory data) = tokenX.staticcall(abi.encodeWithSelector(IERC20Minimal.balanceOf.selector, address(this))); require(success && data.length >= 32); return abi.decode(data, (uint256)); } function balanceY() private view returns (uint256) { (bool success, bytes memory data) = tokenY.staticcall(abi.encodeWithSelector(IERC20Minimal.balanceOf.selector, address(this))); require(success && data.length >= 32); return abi.decode(data, (uint256)); } function revertDCData(bytes memory data) private pure { if (data.length != 64) { if (data.length < 68) revert('dc'); assembly { data := add(data, 0x04) } revert(abi.decode(data, (string))); } assembly { data:= add(data, 0x20) let w := mload(data) let t := mload(0x40) mstore(t, w) let w2 := mload(add(data, 0x20)) mstore(add(t, 0x20), w2) revert(t, 64) } } /// @inheritdoc IiZiSwapPool function assignLimOrderEarnY( int24 point, uint128 assignY, bool fromLegacy ) external override noDelegateCall lock returns (uint128 actualAssignY) { (bool success, bytes memory d) = limitOrderModule.delegatecall( abi.encodeWithSignature("assignLimOrderEarnY(int24,uint128,bool)", point, assignY, fromLegacy) ); if (success) { actualAssignY = abi.decode(d, (uint128)); } else { revertDCData(d); } } /// @inheritdoc IiZiSwapPool function assignLimOrderEarnX( int24 point, uint128 assignX, bool fromLegacy ) external override noDelegateCall lock returns (uint128 actualAssignX) { (bool success, bytes memory d) = limitOrderModule.delegatecall( abi.encodeWithSignature("assignLimOrderEarnX(int24,uint128,bool)", point, assignX, fromLegacy) ); if (success) { actualAssignX = abi.decode(d, (uint128)); } else { revertDCData(d); } } /// @inheritdoc IiZiSwapPool function decLimOrderWithX( int24 point, uint128 deltaX ) external override noDelegateCall lock returns (uint128 actualDeltaX, uint256 legacyAccEarn) { (bool success, bytes memory d) = limitOrderModule.delegatecall( abi.encodeWithSignature("decLimOrderWithX(int24,uint128)", point, deltaX) ); if (success) { uint128 claimSold; uint128 claimEarn; (actualDeltaX, legacyAccEarn, claimSold, claimEarn) = abi.decode(d, (uint128, uint256, uint128, uint128)); emit DecLimitOrder(msg.sender, actualDeltaX, point, claimSold, claimEarn, true); } else { revertDCData(d); } } /// @inheritdoc IiZiSwapPool function decLimOrderWithY( int24 point, uint128 deltaY ) external override noDelegateCall lock returns (uint128 actualDeltaY, uint256 legacyAccEarn) { (bool success, bytes memory d) = limitOrderModule.delegatecall( abi.encodeWithSignature("decLimOrderWithY(int24,uint128)", point, deltaY) ); if (success) { uint128 claimSold; uint128 claimEarn; (actualDeltaY, legacyAccEarn, claimSold, claimEarn) = abi.decode(d, (uint128, uint256, uint128, uint128)); emit DecLimitOrder(msg.sender, actualDeltaY, point, claimSold, claimEarn, false); } else { revertDCData(d); } } /// @inheritdoc IiZiSwapPool function addLimOrderWithX( address recipient, int24 point, uint128 amountX, bytes calldata data ) external override noDelegateCall lock returns (uint128 orderX, uint128 acquireY) { (bool success, bytes memory d) = limitOrderModule.delegatecall( abi.encodeWithSignature("addLimOrderWithX(address,int24,uint128,bytes)", recipient, point, amountX, data) ); if (success) { uint128 claimSold; uint128 claimEarn; (orderX, acquireY, claimSold, claimEarn) = abi.decode(d, (uint128, uint128, uint128, uint128)); emit AddLimitOrder(recipient, orderX, acquireY, point, claimSold, claimEarn, true); } else { revertDCData(d); } } /// @inheritdoc IiZiSwapPool function addLimOrderWithY( address recipient, int24 point, uint128 amountY, bytes calldata data ) external override noDelegateCall lock returns (uint128 orderY, uint128 acquireX) { (bool success, bytes memory d) = limitOrderModule.delegatecall( abi.encodeWithSignature("addLimOrderWithY(address,int24,uint128,bytes)", recipient, point, amountY, data) ); if (success) { uint128 claimSold; uint128 claimEarn; (orderY, acquireX, claimSold, claimEarn) = abi.decode(d, (uint128, uint128, uint128, uint128)); emit AddLimitOrder(recipient, orderY, acquireX, point, claimSold, claimEarn, false); } else { revertDCData(d); } } /// @inheritdoc IiZiSwapPool function collectLimOrder( address recipient, int24 point, uint128 collectDec, uint128 collectEarn, bool isEarnY ) external override noDelegateCall lock returns(uint128 actualCollectDec, uint128 actualCollectEarn) { (bool success, bytes memory d) = limitOrderModule.delegatecall( abi.encodeWithSignature("collectLimOrder(address,int24,uint128,uint128,bool)", recipient, point, collectDec, collectEarn, isEarnY) ); if (success) { (actualCollectDec, actualCollectEarn) = abi.decode(d, (uint128, uint128)); emit CollectLimitOrder(msg.sender, recipient, point, actualCollectDec, actualCollectEarn, isEarnY); } else { revertDCData(d); } } /// @inheritdoc IiZiSwapPool function mint( address recipient, int24 leftPt, int24 rightPt, uint128 liquidDelta, bytes calldata data ) external override noDelegateCall lock returns (uint256 amountX, uint256 amountY) { (bool success, bytes memory d) = liquidityModule.delegatecall( abi.encodeWithSignature("mint(address,int24,int24,uint128,bytes)", recipient, leftPt, rightPt,liquidDelta,data) ); if (success) { (amountX, amountY) = abi.decode(d, (uint256, uint256)); emit Mint(msg.sender, recipient, leftPt, rightPt, liquidDelta, amountX, amountY); } else { revertDCData(d); } } /// @inheritdoc IiZiSwapPool function burn( int24 leftPt, int24 rightPt, uint128 liquidDelta ) external override noDelegateCall lock returns (uint256 amountX, uint256 amountY) { (bool success, bytes memory d) = liquidityModule.delegatecall( abi.encodeWithSignature("burn(int24,int24,uint128)", leftPt, rightPt, liquidDelta) ); if (success) { (amountX, amountY) = abi.decode(d, (uint256, uint256)); emit Burn(msg.sender, leftPt, rightPt, liquidDelta, amountX, amountY); } else { revertDCData(d); } } /// @inheritdoc IiZiSwapPool function collect( address recipient, int24 leftPt, int24 rightPt, uint256 amountXLim, uint256 amountYLim ) external override noDelegateCall lock returns (uint256 actualAmountX, uint256 actualAmountY) { (bool success, bytes memory d) = liquidityModule.delegatecall( abi.encodeWithSignature("collect(address,int24,int24,uint256,uint256)", recipient, leftPt, rightPt, amountXLim, amountYLim) ); if (success) { (actualAmountX, actualAmountY) = abi.decode(d, (uint256, uint256)); emit CollectLiquidity(msg.sender, recipient, leftPt, rightPt, actualAmountX, actualAmountY); } else { revertDCData(d); } } /// @inheritdoc IiZiSwapPool function swapY2X( address recipient, uint128 amount, int24 highPt, bytes calldata data ) external override noDelegateCall lock returns (uint256 amountX, uint256 amountY) { (bool success, bytes memory d) = swapModuleY2X.delegatecall( abi.encodeWithSignature("swapY2X(address,uint128,int24,bytes)", recipient, amount, highPt, data) ); if (success) { (amountX, amountY) = abi.decode(d, (uint256, uint256)); emit Swap(tokenX, tokenY, fee, false, amountX, amountY); } else { revertDCData(d); } } /// @inheritdoc IiZiSwapPool function swapY2XDesireX( address recipient, uint128 desireX, int24 highPt, bytes calldata data ) external override noDelegateCall lock returns (uint256 amountX, uint256 amountY) { (bool success, bytes memory d) = swapModuleY2X.delegatecall( abi.encodeWithSignature("swapY2XDesireX(address,uint128,int24,bytes)", recipient, desireX, highPt, data) ); if (success) { (amountX, amountY) = abi.decode(d, (uint256, uint256)); emit Swap(tokenX, tokenY, fee, false, amountX, amountY); } else { revertDCData(d); } } /// @inheritdoc IiZiSwapPool function swapX2Y( address recipient, uint128 amount, int24 lowPt, bytes calldata data ) external override noDelegateCall lock returns (uint256 amountX, uint256 amountY) { (bool success, bytes memory d) = swapModuleX2Y.delegatecall( abi.encodeWithSignature("swapX2Y(address,uint128,int24,bytes)", recipient, amount, lowPt, data) ); if (success) { (amountX, amountY) = abi.decode(d, (uint256, uint256)); emit Swap(tokenX, tokenY, fee, true, amountX, amountY); } else { revertDCData(d); } } /// @inheritdoc IiZiSwapPool function swapX2YDesireY( address recipient, uint128 desireY, int24 lowPt, bytes calldata data ) external override noDelegateCall lock returns (uint256 amountX, uint256 amountY) { (bool success, bytes memory d) = swapModuleX2Y.delegatecall( abi.encodeWithSignature("swapX2YDesireY(address,uint128,int24,bytes)", recipient, desireY, lowPt,data) ); if (success) { (amountX, amountY) = abi.decode(d, (uint256, uint256)); emit Swap(tokenX, tokenY, fee, true, amountX, amountY); } else { revertDCData(d); } } /// @inheritdoc IiZiSwapPool function observe(uint32[] calldata secondsAgos) external view override noDelegateCall returns (int56[] memory accPoints) { return observations.observe( uint32(block.timestamp), secondsAgos, state.currentPoint, state.observationCurrentIndex, state.observationQueueLen ); } /// @inheritdoc IiZiSwapPool function expandObservationQueue(uint16 newNextQueueLen) external override noDelegateCall lock { uint16 oldNextQueueLen = state.observationNextQueueLen; if (newNextQueueLen > oldNextQueueLen) { observations.expand(oldNextQueueLen, newNextQueueLen); state.observationNextQueueLen = newNextQueueLen; } } /// @inheritdoc IiZiSwapPool function liquiditySnapshot(int24 leftPoint, int24 rightPoint) external override view returns(int128[] memory deltaLiquidities) { require(leftPoint < rightPoint, "L<R"); require(leftPoint >= leftMostPt, "LO"); require(rightPoint <= rightMostPt, "RO"); require(leftPoint % pointDelta == 0, "LD0"); require(rightPoint % pointDelta == 0, "RD0"); uint256 len = uint256(int256((rightPoint - leftPoint) / pointDelta)); deltaLiquidities = new int128[](len); uint256 idx = 0; for (int24 i = leftPoint; i < rightPoint; i += pointDelta) { deltaLiquidities[idx] = points[i].liquidDelta; idx ++; } } /// @inheritdoc IiZiSwapPool function limitOrderSnapshot(int24 leftPoint, int24 rightPoint) external override view returns(LimitOrderStruct[] memory limitOrders) { require(leftPoint < rightPoint, "L<R"); require(leftPoint >= leftMostPt, "LO"); require(rightPoint <= rightMostPt, "RO"); require(leftPoint % pointDelta == 0, "LD0"); require(rightPoint % pointDelta == 0, "RD0"); uint256 len = uint256(int256((rightPoint - leftPoint) / pointDelta)); limitOrders = new LimitOrderStruct[](len); uint256 idx = 0; for (int24 i = leftPoint; i < rightPoint; i += pointDelta) { limitOrders[idx] = LimitOrderStruct({ sellingX: limitOrderData[i].sellingX, earnY: limitOrderData[i].earnY, accEarnY: limitOrderData[i].accEarnY, sellingY: limitOrderData[i].sellingY, earnX: limitOrderData[i].earnX, accEarnX: limitOrderData[i].accEarnX }); idx ++; } } /// @inheritdoc IiZiSwapPool function collectFeeCharged() external override noDelegateCall lock { require(msg.sender == IiZiSwapFactory(factory).chargeReceiver(), "NR"); TokenTransfer.transferToken(tokenX, msg.sender, totalFeeXCharged); TokenTransfer.transferToken(tokenY, msg.sender, totalFeeYCharged); totalFeeXCharged = 0; totalFeeYCharged = 0; } /// @inheritdoc IiZiSwapPool function modifyFeeChargePercent(uint24 newFeeChargePercent) external override noDelegateCall lock { require(msg.sender == IOwnable(factory).owner(), "NON"); require(newFeeChargePercent >= 0, "FP0"); require(newFeeChargePercent <= 100, "FP0"); feeChargePercent = newFeeChargePercent; } /// @inheritdoc IiZiSwapPool function flash( address recipient, uint256 amountX, uint256 amountY, bytes calldata data ) external override noDelegateCall lock { (bool success, bytes memory d) = flashModule.delegatecall( abi.encodeWithSignature("flash(address,uint256,uint256,bytes)", recipient, amountX, amountY, data) ); if (success) { (uint256 actualAmountX, uint256 actualAmountY, uint256 paidX, uint256 paidY) = abi.decode(d, (uint256, uint256, uint256, uint256)); emit Flash(msg.sender, recipient, actualAmountX, actualAmountY, paidX, paidY); } else { revertDCData(d); } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.16; /// @title Minimal ERC20 interface for Uniswap /// @notice Contains a subset of the full ERC20 interface that is used in Uniswap 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: BUSL-1.1 pragma solidity ^0.8.16; interface IOwnable { /** * @dev Returns the address of the current owner. */ function owner() external view returns (address); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.16; interface IiZiSwapMintCallback { /// @notice Called to msg.sender in iZiSwapPool#mint call /// @param x Amount of tokenX need to pay from miner /// @param y Amount of tokenY need to pay from miner /// @param data Any data passed through by the msg.sender via the iZiSwapPool#mint call function mintDepositCallback( uint256 x, uint256 y, bytes calldata data ) external; } interface IiZiSwapCallback { /// @notice Called to msg.sender in iZiSwapPool#swapY2X(DesireX) call /// @param x Amount of tokenX trader will acquire /// @param y Amount of tokenY trader will pay /// @param data Any dadta passed though by the msg.sender via the iZiSwapPool#swapY2X(DesireX) call function swapY2XCallback( uint256 x, uint256 y, bytes calldata data ) external; /// @notice Called to msg.sender in iZiSwapPool#swapX2Y(DesireY) call /// @param x Amount of tokenX trader will pay /// @param y Amount of tokenY trader will require /// @param data Any dadta passed though by the msg.sender via the iZiSwapPool#swapX2Y(DesireY) call function swapX2YCallback( uint256 x, uint256 y, bytes calldata data ) external; } interface IiZiSwapAddLimOrderCallback { /// @notice Called to msg.sender in iZiSwapPool#addLimOrderWithX(Y) call /// @param x Amount of tokenX seller will pay /// @param y Amount of tokenY seller will pay /// @param data Any dadta passed though by the msg.sender via the iZiSwapPool#addLimOrderWithX(Y) call function payCallback( uint256 x, uint256 y, bytes calldata data ) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.16; interface IiZiSwapFactory { /// @notice emit when successfuly create a new pool (calling iZiSwapFactory#newPool) /// @param tokenX address of erc-20 tokenX /// @param tokenY address of erc-20 tokenY /// @param fee fee amount of swap (3000 means 0.3%) /// @param pointDelta minimum number of distance between initialized or limitorder points /// @param pool address of swap pool event NewPool( address indexed tokenX, address indexed tokenY, uint24 indexed fee, uint24 pointDelta, address pool ); /// @notice module to support swap from tokenX to tokenY /// @return swapX2YModule address function swapX2YModule() external returns (address); /// @notice module to support swap from tokenY to tokenX /// @return swapY2XModule address function swapY2XModule() external returns (address); /// @notice module to support mint/burn/collect function of pool /// @return liquidityModule address function liquidityModule() external returns (address); /// @notice address of module for user to manage limit orders /// @return limitOrderModule address function limitOrderModule() external returns (address); /// @notice address of module for flash loan /// @return flashModule address function flashModule() external returns (address); /// @notice default fee rate from miner's fee gain /// @return defaultFeeChargePercent default fee rate * 100 function defaultFeeChargePercent() external returns (uint24); /// @notice Enables a fee amount with the given pointDelta /// @dev Fee amounts may never be removed once enabled /// @param fee fee amount (3000 means 0.3%) /// @param pointDelta The spacing between points to be enforced for all pools created with the given fee amount function enableFeeAmount(uint24 fee, uint24 pointDelta) external; /// @notice Create a new pool which not exists. /// @param tokenX address of tokenX /// @param tokenY address of tokenY /// @param fee fee amount /// @param currentPoint initial point (log 1.0001 of price) /// @return address of newly created pool function newPool( address tokenX, address tokenY, uint24 fee, int24 currentPoint ) external returns (address); /// @notice Charge receiver of all pools. /// @return address of charge receiver function chargeReceiver() external view returns(address); /// @notice Get pool of (tokenX, tokenY, fee), address(0) for not exists. /// @param tokenX address of tokenX /// @param tokenY address of tokenY /// @param fee fee amount /// @return address of pool function pool( address tokenX, address tokenY, uint24 fee ) external view returns(address); /// @notice Get point delta of a given fee amount. /// @param fee fee amount /// @return pointDelta the point delta function fee2pointDelta(uint24 fee) external view returns (int24 pointDelta); /// @notice Change charge receiver, only owner of factory can call. /// @param _chargeReceiver address of new receiver function modifyChargeReceiver(address _chargeReceiver) external; /// @notice Change defaultFeeChargePercent /// @param _defaultFeeChargePercent new charge percent function modifyDefaultFeeChargePercent(uint24 _defaultFeeChargePercent) external; function deployPoolParams() external view returns( address tokenX, address tokenY, uint24 fee, int24 currentPoint, int24 pointDelta, uint24 feeChargePercent ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; interface IiZiSwapFlashCallback { /// @notice Call the msg.sender after sending tokens in IiZiSwapPool#flash. /// @dev Must repay the tokens to the pool within one call. /// @param feeX the fee amount in tokenX due to the pool by the end of the flash /// @param feeY the fee amount in tokenY due to the pool by the end of the flash /// @param data any data passed through by the caller function flashCallback( uint256 feeX, uint256 feeY, bytes calldata data ) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.16; interface IiZiSwapPool { /// @notice Emitted when miner successfully add liquidity (mint). /// @param sender the address that minted the liquidity /// @param owner the owner who will benefit from this liquidity /// @param leftPoint left endpoint of the liquidity /// @param rightPoint right endpoint of the liquidity /// @param liquidity the amount of liquidity minted to the range [leftPoint, rightPoint) /// @param amountX amount of tokenX deposit /// @param amountY amount of tokenY deposit event Mint( address sender, address indexed owner, int24 indexed leftPoint, int24 indexed rightPoint, uint128 liquidity, uint256 amountX, uint256 amountY ); /// @notice Emitted when miner successfully decrease liquidity (withdraw). /// @param owner owner address of liquidity /// @param leftPoint left endpoint of liquidity /// @param rightPoint right endpoint of liquidity /// @param liquidity amount of liquidity decreased /// @param amountX amount of tokenX withdrawed /// @param amountY amount of tokenY withdrawed event Burn( address indexed owner, int24 indexed leftPoint, int24 indexed rightPoint, uint128 liquidity, uint256 amountX, uint256 amountY ); /// @notice Emitted when fees and withdrawed liquidity are collected /// @param owner The owner of the Liquidity /// @param recipient recipient of those token /// @param leftPoint The left point of the liquidity /// @param rightPoint The right point of the liquidity /// @param amountX The amount of tokenX (fees and withdrawed tokenX from liquidity) /// @param amountY The amount of tokenY (fees and withdrawed tokenY from liquidity) event CollectLiquidity( address indexed owner, address recipient, int24 indexed leftPoint, int24 indexed rightPoint, uint256 amountX, uint256 amountY ); /// @notice Emitted when a trader successfully exchange. /// @param tokenX tokenX of pool /// @param tokenY tokenY of pool /// @param fee fee amount of pool /// @param sellXEarnY true for selling tokenX, false for buying tokenX /// @param amountX amount of tokenX in this exchange /// @param amountY amount of tokenY in this exchange event Swap( address indexed tokenX, address indexed tokenY, uint24 indexed fee, bool sellXEarnY, uint256 amountX, uint256 amountY ); /// @notice Emitted by the pool for any flashes of tokenX/tokenY. /// @param sender the address that initiated the swap call, and that received the callback /// @param recipient the address that received the tokens from flash /// @param amountX the amount of tokenX that was flashed /// @param amountY the amount of tokenY that was flashed /// @param paidX the amount of tokenX paid for the flash, which can exceed the amountX plus the fee /// @param paidY the amount of tokenY paid for the flash, which can exceed the amountY plus the fee event Flash( address indexed sender, address indexed recipient, uint256 amountX, uint256 amountY, uint256 paidX, uint256 paidY ); /// @notice Emitted when a seller successfully add a limit order. /// @param owner owner of limit order /// @param addAmount amount of token to sell the seller added /// @param acquireAmount amount of earn-token acquired, if there exists some opposite order before /// @param point point of limit order /// @param claimSold claimed sold sell-token, if this owner has order with same direction on this point before /// @param claimEarn claimed earned earn-token, if this owner has order with same direction on this point before /// @param sellXEarnY direction of limit order, etc. sell tokenX or sell tokenY event AddLimitOrder( address indexed owner, uint128 addAmount, uint128 acquireAmount, int24 indexed point, uint128 claimSold, uint128 claimEarn, bool sellXEarnY ); /// @notice Emitted when a seller successfully decrease a limit order. /// @param owner owner of limit order /// @param decreaseAmount amount of token to sell the seller decreased /// @param point point of limit order /// @param claimSold claimed sold sell-token /// @param claimEarn claimed earned earn-token /// @param sellXEarnY direction of limit order, etc. sell tokenX or sell tokenY event DecLimitOrder( address indexed owner, uint128 decreaseAmount, int24 indexed point, uint128 claimSold, uint128 claimEarn, bool sellXEarnY ); /// @notice Emitted when collect from a limit order /// @param owner The owner of the Liquidity /// @param recipient recipient of those token /// @param point The point of the limit order /// @param collectDec The amount of decreased sell token collected /// @param collectEarn The amount of earn token collected /// @param sellXEarnY direction of limit order, etc. sell tokenX or sell tokenY event CollectLimitOrder( address indexed owner, address recipient, int24 indexed point, uint128 collectDec, uint128 collectEarn, bool sellXEarnY ); /// @notice Returns the information about a liquidity by the liquidity's key. /// @param key the liquidity's key is a hash of a preimage composed by the miner(owner), pointLeft and pointRight /// @return liquidity the amount of liquidity, /// @return lastFeeScaleX_128 fee growth of tokenX inside the range as of the last mint/burn/collect, /// @return lastFeeScaleY_128 fee growth of tokenY inside the range as of the last mint/burn/collect, /// @return tokenOwedX the computed amount of tokenX miner can collect as of the last mint/burn/collect, /// @return tokenOwedY the computed amount of tokenY miner can collect as of the last mint/burn/collect function liquidity(bytes32 key) external view returns ( uint128 liquidity, uint256 lastFeeScaleX_128, uint256 lastFeeScaleY_128, uint256 tokenOwedX, uint256 tokenOwedY ); /// @notice Returns the information about a user's limit order (sell tokenY and earn tokenX). /// @param key the limit order's key is a hash of a preimage composed by the seller, point /// @return lastAccEarn total amount of tokenX earned by all users at this point as of the last add/dec/collect /// @return sellingRemain amount of tokenY not selled in this limit order /// @return sellingDec amount of tokenY decreased by seller from this limit order /// @return earn amount of unlegacy earned tokenX in this limit order not assigned /// @return legacyEarn amount of legacy earned tokenX in this limit order not assgined /// @return earnAssign assigned amount of tokenX earned (both legacy and unlegacy) in this limit order function userEarnX(bytes32 key) external view returns ( uint256 lastAccEarn, uint128 sellingRemain, uint128 sellingDec, uint128 earn, uint128 legacyEarn, uint128 earnAssign ); /// @notice Returns the information about a user's limit order (sell tokenX and earn tokenY). /// @param key the limit order's key is a hash of a preimage composed by the seller, point /// @return lastAccEarn total amount of tokenY earned by all users at this point as of the last add/dec/collect /// @return sellingRemain amount of tokenX not selled in this limit order /// @return sellingDec amount of tokenX decreased by seller from this limit order /// @return earn amount of unlegacy earned tokenY in this limit order not assigned /// @return legacyEarn amount of legacy earned tokenY in this limit order not assgined /// @return earnAssign assigned amount of tokenY earned (both legacy and unlegacy) in this limit order function userEarnY(bytes32 key) external view returns ( uint256 lastAccEarn, uint128 sellingRemain, uint128 sellingDec, uint128 earn, uint128 legacyEarn, uint128 earnAssign ); /// @notice Mark a given amount of tokenY in a limitorder(sellx and earn y) as assigned. /// @param point point (log Price) of seller's limit order,be sure to be times of pointDelta /// @param assignY max amount of tokenY to mark assigned /// @param fromLegacy true for assigning earned token from legacyEarnY /// @return actualAssignY actual amount of tokenY marked function assignLimOrderEarnY( int24 point, uint128 assignY, bool fromLegacy ) external returns(uint128 actualAssignY); /// @notice Mark a given amount of tokenX in a limitorder(selly and earn x) as assigned. /// @param point point (log Price) of seller's limit order,be sure to be times of pointDelta /// @param assignX max amount of tokenX to mark assigned /// @param fromLegacy true for assigning earned token from legacyEarnX /// @return actualAssignX actual amount of tokenX marked function assignLimOrderEarnX( int24 point, uint128 assignX, bool fromLegacy ) external returns(uint128 actualAssignX); /// @notice Decrease limitorder of selling X. /// @param point point of seller's limit order, be sure to be times of pointDelta /// @param deltaX max amount of tokenX seller wants to decrease /// @return actualDeltaX actual amount of tokenX decreased /// @return legacyAccEarn legacyAccEarnY of pointOrder at point when calling this interface function decLimOrderWithX( int24 point, uint128 deltaX ) external returns (uint128 actualDeltaX, uint256 legacyAccEarn); /// @notice Decrease limitorder of selling Y. /// @param point point of seller's limit order, be sure to be times of pointDelta /// @param deltaY max amount of tokenY seller wants to decrease /// @return actualDeltaY actual amount of tokenY decreased /// @return legacyAccEarn legacyAccEarnX of pointOrder at point when calling this interface function decLimOrderWithY( int24 point, uint128 deltaY ) external returns (uint128 actualDeltaY, uint256 legacyAccEarn); /// @notice Add a limit order (selling x) in the pool. /// @param recipient owner of the limit order /// @param point point of the order, be sure to be times of pointDelta /// @param amountX amount of tokenX to sell /// @param data any data that should be passed through to the callback /// @return orderX actual added amount of tokenX /// @return acquireY amount of tokenY acquired if there is a limit order to sell y before adding function addLimOrderWithX( address recipient, int24 point, uint128 amountX, bytes calldata data ) external returns (uint128 orderX, uint128 acquireY); /// @notice Add a limit order (selling y) in the pool. /// @param recipient owner of the limit order /// @param point point of the order, be sure to be times of pointDelta /// @param amountY amount of tokenY to sell /// @param data any data that should be passed through to the callback /// @return orderY actual added amount of tokenY /// @return acquireX amount of tokenX acquired if there exists a limit order to sell x before adding function addLimOrderWithY( address recipient, int24 point, uint128 amountY, bytes calldata data ) external returns (uint128 orderY, uint128 acquireX); /// @notice Collect earned or decreased token from limit order. /// @param recipient address to benefit /// @param point point of limit order, be sure to be times of pointDelta /// @param collectDec max amount of decreased selling token to collect /// @param collectEarn max amount of earned token to collect /// @param isEarnY direction of this limit order, true for sell y, false for sell x /// @return actualCollectDec actual amount of decresed selling token collected /// @return actualCollectEarn actual amount of earned token collected function collectLimOrder( address recipient, int24 point, uint128 collectDec, uint128 collectEarn, bool isEarnY ) external returns(uint128 actualCollectDec, uint128 actualCollectEarn); /// @notice Add liquidity to the pool. /// @param recipient newly created liquidity will belong to this address /// @param leftPt left endpoint of the liquidity, be sure to be times of pointDelta /// @param rightPt right endpoint of the liquidity, be sure to be times of pointDelta /// @param liquidDelta amount of liquidity to add /// @param data any data that should be passed through to the callback /// @return amountX The amount of tokenX that was paid for the liquidity. Matches the value in the callback /// @return amountY The amount of tokenY that was paid for the liquidity. Matches the value in the callback function mint( address recipient, int24 leftPt, int24 rightPt, uint128 liquidDelta, bytes calldata data ) external returns (uint256 amountX, uint256 amountY); /// @notice Decrease a given amount of liquidity from msg.sender's liquidities. /// @param leftPt left endpoint of the liquidity /// @param rightPt right endpoint of the liquidity /// @param liquidDelta amount of liquidity to burn /// @return amountX The amount of tokenX should be refund after burn /// @return amountY The amount of tokenY should be refund after burn function burn( int24 leftPt, int24 rightPt, uint128 liquidDelta ) external returns (uint256 amountX, uint256 amountY); /// @notice Collect tokens (fee or refunded after burn) from a liquidity. /// @param recipient the address which should receive the collected tokens /// @param leftPt left endpoint of the liquidity /// @param rightPt right endpoint of the liquidity /// @param amountXLim max amount of tokenX the owner wants to collect /// @param amountYLim max amount of tokenY the owner wants to collect /// @return actualAmountX the amount tokenX collected /// @return actualAmountY the amount tokenY collected function collect( address recipient, int24 leftPt, int24 rightPt, uint256 amountXLim, uint256 amountYLim ) external returns (uint256 actualAmountX, uint256 actualAmountY); /// @notice Swap tokenY for tokenX, given max amount of tokenY user willing to pay. /// @param recipient the address to receive tokenX /// @param amount the max amount of tokenY user willing to pay /// @param highPt the highest point(price) of x/y during swap /// @param data any data to be passed through to the callback /// @return amountX amount of tokenX payed /// @return amountY amount of tokenY acquired function swapY2X( address recipient, uint128 amount, int24 highPt, bytes calldata data ) external returns (uint256 amountX, uint256 amountY); /// @notice Swap tokenY for tokenX, given amount of tokenX user desires. /// @param recipient the address to receive tokenX /// @param desireX the amount of tokenX user desires /// @param highPt the highest point(price) of x/y during swap /// @param data any data to be passed through to the callback /// @return amountX amount of tokenX payed /// @return amountY amount of tokenY acquired function swapY2XDesireX( address recipient, uint128 desireX, int24 highPt, bytes calldata data ) external returns (uint256 amountX, uint256 amountY); /// @notice Swap tokenX for tokenY, given max amount of tokenX user willing to pay. /// @param recipient the address to receive tokenY /// @param amount the max amount of tokenX user willing to pay /// @param lowPt the lowest point(price) of x/y during swap /// @param data any data to be passed through to the callback /// @return amountX amount of tokenX acquired /// @return amountY amount of tokenY payed function swapX2Y( address recipient, uint128 amount, int24 lowPt, bytes calldata data ) external returns (uint256 amountX, uint256 amountY); /// @notice Swap tokenX for tokenY, given amount of tokenY user desires. /// @param recipient the address to receive tokenY /// @param desireY the amount of tokenY user desires /// @param lowPt the lowest point(price) of x/y during swap /// @param data any data to be passed through to the callback /// @return amountX amount of tokenX acquired /// @return amountY amount of tokenY payed function swapX2YDesireY( address recipient, uint128 desireY, int24 lowPt, bytes calldata data ) external returns (uint256 amountX, uint256 amountY); /// @notice Returns sqrt(1.0001), in 96 bit fixpoint number. function sqrtRate_96() external view returns(uint160); /// @notice State values of pool. /// @return sqrtPrice_96 a 96 fixpoing number describe the sqrt value of current price(tokenX/tokenY) /// @return currentPoint the current point of the pool, 1.0001 ^ currentPoint = price /// @return observationCurrentIndex the index of the last oracle observation that was written, /// @return observationQueueLen the current maximum number of observations stored in the pool, /// @return observationNextQueueLen the next maximum number of observations, to be updated when the observation. /// @return locked whether the pool is locked (only used for checking reentrance) /// @return liquidity liquidity on the currentPoint (currX * sqrtPrice + currY / sqrtPrice) /// @return liquidityX liquidity of tokenX function state() external view returns( uint160 sqrtPrice_96, int24 currentPoint, uint16 observationCurrentIndex, uint16 observationQueueLen, uint16 observationNextQueueLen, bool locked, uint128 liquidity, uint128 liquidityX ); /// @notice LimitOrder info on a given point. /// @param point the given point /// @return sellingX total amount of tokenX selling on the point /// @return earnY total amount of unclaimed earned tokenY for unlegacy sellingX /// @return accEarnY total amount of earned tokenY(via selling tokenX) by all users at this point as of the last swap /// @return legacyAccEarnY latest recorded 'accEarnY' value when sellingX is clear (legacy) /// @return legacyEarnY total amount of unclaimed earned tokenY for legacy (cleared during swap) sellingX /// @return sellingY total amount of tokenYselling on the point /// @return earnX total amount of unclaimed earned tokenX for unlegacy sellingY /// @return legacyEarnX total amount of unclaimed earned tokenX for legacy (cleared during swap) sellingY /// @return accEarnX total amount of earned tokenX(via selling tokenY) by all users at this point as of the last swap /// @return legacyAccEarnX latest recorded 'accEarnX' value when sellingY is clear (legacy) function limitOrderData(int24 point) external view returns( uint128 sellingX, uint128 earnY, uint256 accEarnY, uint256 legacyAccEarnY, uint128 legacyEarnY, uint128 sellingY, uint128 earnX, uint128 legacyEarnX, uint256 accEarnX, uint256 legacyAccEarnX ); /// @notice Query infomation about a point whether has limit order or is an liquidity's endpoint. /// @param point point to query /// @return val endpoint for val&1>0 and has limit order for val&2 > 0 function orderOrEndpoint(int24 point) external returns(int24 val); /// @notice Returns observation data about a specific index. /// @param index the index of observation array /// @return timestamp the timestamp of the observation, /// @return accPoint the point multiplied by seconds elapsed for the life of the pool as of the observation timestamp, /// @return init whether the observation has been initialized and the above values are safe to use function observations(uint256 index) external view returns ( uint32 timestamp, int56 accPoint, bool init ); /// @notice Point status in the pool. /// @param point the point /// @return liquidSum the total amount of liquidity that uses the point either as left endpoint or right endpoint /// @return liquidDelta how much liquidity changes when the pool price crosses the point from left to right /// @return accFeeXOut_128 the fee growth on the other side of the point from the current point in tokenX /// @return accFeeYOut_128 the fee growth on the other side of the point from the current point in tokenY /// @return isEndpt whether the point is an endpoint of a some miner's liquidity, true if liquidSum > 0 function points(int24 point) external view returns ( uint128 liquidSum, int128 liquidDelta, uint256 accFeeXOut_128, uint256 accFeeYOut_128, bool isEndpt ); /// @notice Returns 256 packed point (statusVal>0) boolean values. See PointBitmap for more information. function pointBitmap(int16 wordPosition) external view returns (uint256); /// @notice Returns the integral value of point(time) and integral value of 1/liquidity(time) /// at some target timestamps (block.timestamp - secondsAgo[i]) /// @dev Reverts if target timestamp is early than oldest observation in the queue /// @dev If you call this method with secondsAgos = [3600, 0]. the average point of this pool during recent hour is /// (accPoints[1] - accPoints[0]) / 3600 /// @param secondsAgos describe the target timestamp , targetTimestimp[i] = block.timestamp - secondsAgo[i] /// @return accPoints integral value of point(time) from 0 to each target timestamp function observe(uint32[] calldata secondsAgos) external view returns (int56[] memory accPoints); /// @notice Expand max-length of observation queue. /// @param newNextQueueLen new value of observationNextQueueLen, which should be greater than current observationNextQueueLen function expandObservationQueue(uint16 newNextQueueLen) external; /// @notice Borrow tokenX and/or tokenY and pay it back within a block. /// @dev The caller needs to implement a IiZiSwapPool#flashCallback callback function /// @param recipient the address which will receive the tokenY and/or tokenX /// @param amountX the amount of tokenX to borrow /// @param amountY the amount of tokenY to borrow /// @param data Any data to be passed through to the callback function flash( address recipient, uint256 amountX, uint256 amountY, bytes calldata data ) external; /// @notice Returns a snapshot infomation of Liquidity in [leftPoint, rightPoint). /// @param leftPoint left endpoint of range, should be times of pointDelta /// @param rightPoint right endpoint of range, should be times of pointDelta /// @return deltaLiquidities an array of delta liquidity for points in the range /// note 1. delta liquidity here is amount of liquidity changed when cross a point from left to right /// note 2. deltaLiquidities only contains points which are times of pointDelta /// note 3. this function may cost a ENORMOUS amount of gas, be careful to call function liquiditySnapshot(int24 leftPoint, int24 rightPoint) external view returns(int128[] memory deltaLiquidities); struct LimitOrderStruct { uint128 sellingX; uint128 earnY; uint256 accEarnY; uint128 sellingY; uint128 earnX; uint256 accEarnX; } /// @notice Returns a snapshot infomation of Limit Order in [leftPoint, rightPoint). /// @param leftPoint left endpoint of range, should be times of pointDelta /// @param rightPoint right endpoint of range, should be times of pointDelta /// @return limitOrders an array of Limit Orders for points in the range /// note 1. this function may cost a HUGE amount of gas, be careful to call function limitOrderSnapshot(int24 leftPoint, int24 rightPoint) external view returns(LimitOrderStruct[] memory limitOrders); /// @notice Amount of charged fee on tokenX. function totalFeeXCharged() external view returns(uint256); /// @notice Amount of charged fee on tokenY. function totalFeeYCharged() external view returns(uint256); /// @notice Percent to charge from miner's fee. function feeChargePercent() external view returns(uint24); /// @notice Collect charged fee, only factory's chargeReceiver can call. function collectFeeCharged() external; /// @notice modify 'feeChargePercent', only owner has authority. /// @param newFeeChargePercent new value of feeChargePercent, a nature number range in [0, 100], function modifyFeeChargePercent(uint24 newFeeChargePercent) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.16; import "./MulDivMath.sol"; import "./TwoPower.sol"; import "./LogPowMath.sol"; library AmountMath { function getAmountY( uint128 liquidity, uint160 sqrtPriceL_96, uint160 sqrtPriceR_96, uint160 sqrtRate_96, bool upper ) internal pure returns (uint256 amount) { uint160 numerator = sqrtPriceR_96 - sqrtPriceL_96; uint160 denominator = sqrtRate_96 - uint160(TwoPower.Pow96); if (!upper) { amount = MulDivMath.mulDivFloor(liquidity, numerator, denominator); } else { amount = MulDivMath.mulDivCeil(liquidity, numerator, denominator); } } function getAmountX( uint128 liquidity, int24 leftPt, int24 rightPt, uint160 sqrtPriceR_96, uint160 sqrtRate_96, bool upper ) internal pure returns (uint256 amount) { // rightPt - (leftPt - 1), pc = leftPt - 1 uint160 sqrtPricePrPl_96 = LogPowMath.getSqrtPrice(rightPt - leftPt); // 1. sqrtPriceR_96 * 2^96 < 2^256 // 2. sqrtRate_96 > 2^96, so sqrtPricePrM1_96 < sqrtPriceR_96 < 2^160 uint160 sqrtPricePrM1_96 = uint160(uint256(sqrtPriceR_96) * TwoPower.Pow96 / sqrtRate_96); uint160 numerator = sqrtPricePrPl_96 - uint160(TwoPower.Pow96); uint160 denominator = sqrtPriceR_96 - sqrtPricePrM1_96; if (!upper) { amount = MulDivMath.mulDivFloor(liquidity, numerator, denominator); } else { amount = MulDivMath.mulDivCeil(liquidity, numerator, denominator); } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.16; library Converter { function toUint128(uint256 a) internal pure returns (uint128 b){ b = uint128(a); require(a == b, 'C128'); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.16; library LimitOrder { struct Data { uint128 sellingX; uint128 earnY; uint256 accEarnY; uint256 legacyAccEarnY; uint128 legacyEarnY; uint128 sellingY; uint128 earnX; uint128 legacyEarnX; uint256 accEarnX; uint256 legacyAccEarnX; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.16; import "./MulDivMath.sol"; import "./TwoPower.sol"; library Liquidity { struct Data { uint128 liquidity; uint256 lastFeeScaleX_128; uint256 lastFeeScaleY_128; uint256 tokenOwedX; uint256 tokenOwedY; } // delta cannot be int128.min and liquidDelta of any one point will not be int128.min function liquidityAddDelta(uint128 l, int128 delta) internal pure returns (uint128 nl) { if (delta < 0) { // in the pool, max(liquidity) < 2 ** 127 // so, -delta > -2**127, -delta <= int128.max nl = l - uint128(-delta); } else { nl = l + uint128(delta); } } function get( mapping(bytes32 => Data) storage self, address minter, int24 tl, int24 tr ) internal view returns (Liquidity.Data storage data) { data = self[keccak256(abi.encodePacked(minter, tl, tr))]; } function update( Liquidity.Data storage self, int128 delta, uint256 feeScaleX_128, uint256 feeScaleY_128 ) internal { Data memory data = self; uint128 liquidity; if (delta == 0) { require(data.liquidity > 0, "L>0"); liquidity = data.liquidity; } else { liquidity = liquidityAddDelta(data.liquidity, delta); } uint256 deltaScaleX = data.lastFeeScaleX_128; uint256 deltaScaleY = data.lastFeeScaleY_128; // use assembly to prevent revert if overflow // data.lastFeeScaleX(Y)_128 may be "negative" (>=2^255) assembly { deltaScaleX := sub(feeScaleX_128, deltaScaleX) deltaScaleY := sub(feeScaleY_128, deltaScaleY) } uint256 feeX = MulDivMath.mulDivFloor(deltaScaleX, data.liquidity, TwoPower.Pow128); uint256 feeY = MulDivMath.mulDivFloor(deltaScaleY, data.liquidity, TwoPower.Pow128); data.liquidity = liquidity; // update the position if (delta != 0) self.liquidity = liquidity; self.lastFeeScaleX_128 = feeScaleX_128; self.lastFeeScaleY_128 = feeScaleY_128; if (feeX > 0 || feeY > 0) { // need to withdraw before overflow self.tokenOwedX += feeX; self.tokenOwedY += feeY; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; library LogPowMath { int24 internal constant MIN_POINT = -887272; int24 internal constant MAX_POINT = -MIN_POINT; uint160 internal constant MIN_SQRT_PRICE = 4295128739; uint160 internal constant MAX_SQRT_PRICE = 1461446703485210103287273052203988822378723970342; /// @notice sqrt(1.0001^point) in form oy 96-bit fix point num function getSqrtPrice(int24 point) internal pure returns (uint160 sqrtPrice_96) { uint256 absIdx = point < 0 ? uint256(-int256(point)) : uint256(int256(point)); require(absIdx <= uint256(int256(MAX_POINT)), 'T'); uint256 value = absIdx & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000; if (absIdx & 0x2 != 0) value = (value * 0xfff97272373d413259a46990580e213a) >> 128; if (absIdx & 0x4 != 0) value = (value * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128; if (absIdx & 0x8 != 0) value = (value * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128; if (absIdx & 0x10 != 0) value = (value * 0xffcb9843d60f6159c9db58835c926644) >> 128; if (absIdx & 0x20 != 0) value = (value * 0xff973b41fa98c081472e6896dfb254c0) >> 128; if (absIdx & 0x40 != 0) value = (value * 0xff2ea16466c96a3843ec78b326b52861) >> 128; if (absIdx & 0x80 != 0) value = (value * 0xfe5dee046a99a2a811c461f1969c3053) >> 128; if (absIdx & 0x100 != 0) value = (value * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128; if (absIdx & 0x200 != 0) value = (value * 0xf987a7253ac413176f2b074cf7815e54) >> 128; if (absIdx & 0x400 != 0) value = (value * 0xf3392b0822b70005940c7a398e4b70f3) >> 128; if (absIdx & 0x800 != 0) value = (value * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128; if (absIdx & 0x1000 != 0) value = (value * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128; if (absIdx & 0x2000 != 0) value = (value * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128; if (absIdx & 0x4000 != 0) value = (value * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128; if (absIdx & 0x8000 != 0) value = (value * 0x31be135f97d08fd981231505542fcfa6) >> 128; if (absIdx & 0x10000 != 0) value = (value * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128; if (absIdx & 0x20000 != 0) value = (value * 0x5d6af8dedb81196699c329225ee604) >> 128; if (absIdx & 0x40000 != 0) value = (value * 0x2216e584f5fa1ea926041bedfe98) >> 128; if (absIdx & 0x80000 != 0) value = (value * 0x48a170391f7dc42444e8fa2) >> 128; if (point > 0) value = type(uint256).max / value; sqrtPrice_96 = uint160((value >> 32) + (value % (1 << 32) == 0 ? 0 : 1)); } // floor(log1.0001(sqrtPrice_96)) function getLogSqrtPriceFloor(uint160 sqrtPrice_96) internal pure returns (int24 logValue) { // second inequality must be < because the price can nevex reach the price at the max tick require(sqrtPrice_96 >= MIN_SQRT_PRICE && sqrtPrice_96 < MAX_SQRT_PRICE, 'R'); uint256 sqrtPrice_128 = uint256(sqrtPrice_96) << 32; uint256 x = sqrtPrice_128; uint256 m = 0; assembly { let y := shl(7, gt(x, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) m := or(m, y) x := shr(y, x) } assembly { let y := shl(6, gt(x, 0xFFFFFFFFFFFFFFFF)) m := or(m, y) x := shr(y, x) } assembly { let y := shl(5, gt(x, 0xFFFFFFFF)) m := or(m, y) x := shr(y, x) } assembly { let y := shl(4, gt(x, 0xFFFF)) m := or(m, y) x := shr(y, x) } assembly { let y := shl(3, gt(x, 0xFF)) m := or(m, y) x := shr(y, x) } assembly { let y := shl(2, gt(x, 0xF)) m := or(m, y) x := shr(y, x) } assembly { let y := shl(1, gt(x, 0x3)) m := or(m, y) x := shr(y, x) } assembly { let y := gt(x, 0x1) m := or(m, y) } if (m >= 128) x = sqrtPrice_128 >> (m - 127); else x = sqrtPrice_128 << (127 - m); int256 l2 = (int256(m) - 128) << 64; assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(63, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(62, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(61, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(60, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(59, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(58, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(57, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(56, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(55, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(54, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(53, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(52, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(51, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(50, y)) } int256 ls10001 = l2 * 255738958999603826347141; int24 logFloor = int24((ls10001 - 3402992956809132418596140100660247210) >> 128); int24 logUpper = int24((ls10001 + 291339464771989622907027621153398088495) >> 128); logValue = logFloor == logUpper ? logFloor : getSqrtPrice(logUpper) <= sqrtPrice_96 ? logUpper : logFloor; } function getLogSqrtPriceFU(uint160 sqrtPrice_96) internal pure returns (int24 logFloor, int24 logUpper) { // second inequality must be < because the price can nevex reach the price at the max tick require(sqrtPrice_96 >= MIN_SQRT_PRICE && sqrtPrice_96 < MAX_SQRT_PRICE, 'R'); uint256 sqrtPrice_128 = uint256(sqrtPrice_96) << 32; uint256 x = sqrtPrice_128; uint256 m = 0; assembly { let y := shl(7, gt(x, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) m := or(m, y) x := shr(y, x) } assembly { let y := shl(6, gt(x, 0xFFFFFFFFFFFFFFFF)) m := or(m, y) x := shr(y, x) } assembly { let y := shl(5, gt(x, 0xFFFFFFFF)) m := or(m, y) x := shr(y, x) } assembly { let y := shl(4, gt(x, 0xFFFF)) m := or(m, y) x := shr(y, x) } assembly { let y := shl(3, gt(x, 0xFF)) m := or(m, y) x := shr(y, x) } assembly { let y := shl(2, gt(x, 0xF)) m := or(m, y) x := shr(y, x) } assembly { let y := shl(1, gt(x, 0x3)) m := or(m, y) x := shr(y, x) } assembly { let y := gt(x, 0x1) m := or(m, y) } if (m >= 128) x = sqrtPrice_128 >> (m - 127); else x = sqrtPrice_128 << (127 - m); int256 l2 = (int256(m) - 128) << 64; assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(63, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(62, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(61, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(60, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(59, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(58, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(57, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(56, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(55, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(54, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(53, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(52, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(51, y)) x := shr(y, x) } assembly { x := shr(127, mul(x, x)) let y := shr(128, x) l2 := or(l2, shl(50, y)) } int256 ls10001 = l2 * 255738958999603826347141; logFloor = int24((ls10001 - 3402992956809132418596140100660247210) >> 128); logUpper = int24((ls10001 + 291339464771989622907027621153398088495) >> 128); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.16; library MaxMinMath { function max(int24 a, int24 b) internal pure returns (int24) { if (a > b) { return a; } return b; } function min(int24 a, int24 b) internal pure returns (int24) { if (a < b) { return a; } return b; } function min(uint128 a, uint128 b) internal pure returns (uint128) { if (a < b) { return a; } return b; } function min256(uint256 a, uint256 b) internal pure returns (uint256) { if (a < b) { return a; } return b; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; library MulDivMath { // compute res = floor(a * b / c), assuming res < 2^256 function mulDivFloor( uint256 a, uint256 b, uint256 c ) internal pure returns (uint256 res) { // let prodMod2_256 = a * b % 2^256 uint256 prodMod2_256; // let prodDiv2_256 = a * b / 2^256 uint256 prodDiv2_256; assembly { let prodModM1 := mulmod(a, b, not(0)) prodMod2_256 := mul(a, b) prodDiv2_256 := sub(sub(prodModM1, prodMod2_256), lt(prodModM1, prodMod2_256)) } if (prodDiv2_256 == 0) { require(c > 0); assembly { res := div(prodMod2_256, c) } return res; } // we should ensure that a * b /c < 2^256 before calling require(c > prodDiv2_256); uint256 resMod; assembly { resMod := mulmod(a, b, c) // a * b - resMod prodDiv2_256 := sub(prodDiv2_256, gt(resMod, prodMod2_256)) prodMod2_256 := sub(prodMod2_256, resMod) // compute lowbit of c let lowbit := not(c) lowbit := add(lowbit, 1) lowbit := and(lowbit, c) // c / lowbit c := div(c, lowbit) // a * b / lowbit prodMod2_256 := div(prodMod2_256, lowbit) lowbit := add(div(sub(0, lowbit), lowbit), 1) prodDiv2_256 := mul(prodDiv2_256, lowbit) prodMod2_256 := or(prodMod2_256, prodDiv2_256) // get inv of c // cInv * c = 1 (mod 2^4) let cInv := xor(mul(3, c), 2) cInv := mul(cInv, sub(2, mul(c, cInv))) // shift to 2^8 cInv := mul(cInv, sub(2, mul(c, cInv))) // shift to 2^16 cInv := mul(cInv, sub(2, mul(c, cInv))) // shift to 2^32 cInv := mul(cInv, sub(2, mul(c, cInv))) // shift to 2^64 cInv := mul(cInv, sub(2, mul(c, cInv))) // shift to 2^128 cInv := mul(cInv, sub(2, mul(c, cInv))) // shift to 2^256 // a * b / c = prodMod2_256 * cInv (mod 2^256) res := mul(prodMod2_256, cInv) } } // compute res = ceil(a * b / c), assuming res < 2^256 function mulDivCeil( uint256 a, uint256 b, uint256 c ) internal pure returns (uint256 res) { res = mulDivFloor(a, b, c); if (mulmod(a, b, c) > 0) { require(res < type(uint256).max); res++; } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.16; library Oracle { struct Observation { uint32 timestamp; // sigma (point_i * time_i - time_(i-1)) int56 accPoint; // true if this observation is inited bool init; } /// @notice Record a new observation with a circular queue. /// @param last the specified observation to be updated /// @param timestamp the timestamp of the new observation, > last.timestamp /// @param currentPoint log 1.0001 of price /// @return observation generated function newObservation( Observation memory last, uint32 timestamp, int24 currentPoint ) private pure returns (Observation memory) { uint56 delta = uint56(timestamp - last.timestamp); return Observation({ timestamp: timestamp, accPoint: last.accPoint + int56(currentPoint) * int56(delta), init: true }); } function init(Observation[65535] storage self, uint32 timestamp) internal returns (uint16 queueLen, uint16 nextQueueLen) { self[0] = Observation({ timestamp: timestamp, accPoint: 0, init: true }); return (1, 1); } /// @notice Append a price oracle observation data in the pool /// @param self circular-queue of observation data in array form /// @param currentIndex the index of the last observation in the array /// @param timestamp timestamp of new observation /// @param currentPoint current point of new observation (usually we append the point value just-before exchange) /// @param queueLen max-length of circular queue /// @param nextQueueLen next max-length of circular queue, if length of queue increase over queueLen, queueLen will become nextQueueLen /// @return newIndex index of new observation /// @return newQueueLen queueLen value after appending function append( Observation[65535] storage self, uint16 currentIndex, uint32 timestamp, int24 currentPoint, uint16 queueLen, uint16 nextQueueLen ) internal returns (uint16 newIndex, uint16 newQueueLen) { Observation memory last = self[currentIndex]; if (last.timestamp == timestamp) return (currentIndex, queueLen); // if the conditions are right, we can bump the cardinality if (nextQueueLen > queueLen && currentIndex == (queueLen - 1)) { newQueueLen = nextQueueLen; } else { newQueueLen = queueLen; } newIndex = (currentIndex + 1) % newQueueLen; self[newIndex] = newObservation(last, timestamp, currentPoint); } /// @notice Expand the max-length of observation queue /// @param queueLen current max-length of queue /// @param nextQueueLen next max-length /// @return next max-length function expand( Observation[65535] storage self, uint16 queueLen, uint16 nextQueueLen ) internal returns (uint16) { require(queueLen > 0, 'LEN'); if (nextQueueLen <= queueLen) return queueLen; for (uint16 i = queueLen; i < nextQueueLen; i++) self[i].timestamp = 1; return nextQueueLen; } function lte( uint32 time, uint32 a, uint32 b ) private pure returns (bool) { 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 Binary search to find two neighbor observations for a target timestamp /// @param self observation queue in array form /// @param timestamp timestamp of current block /// @param targetTimestamp target time stamp /// @param currentIdx The index of the last observation in the array /// @param queueLen current max-length of queue /// @return beforeNeighbor before-or-at observation neighbor to target timestamp /// @return afterNeighbor after-or-at observation neighbor to target timestamp function findNeighbor( Observation[65535] storage self, uint32 timestamp, uint32 targetTimestamp, uint16 currentIdx, uint16 queueLen ) private view returns (Observation memory beforeNeighbor, Observation memory afterNeighbor) { uint256 l = (currentIdx + 1) % queueLen; // oldest observation uint256 r = l + queueLen - 1; // newest observation uint256 i; while (true) { i = (l + r) / 2; beforeNeighbor = self[i % queueLen]; if (!beforeNeighbor.init) { l = i + 1; continue; } afterNeighbor = self[(i + 1) % queueLen]; bool leftLessOrEq = lte(timestamp, beforeNeighbor.timestamp, targetTimestamp); if (leftLessOrEq && lte(timestamp, targetTimestamp, afterNeighbor.timestamp)) break; if (!leftLessOrEq) r = i - 1; else l = i + 1; } } /// @notice Find two neighbor observations for a target timestamp /// @param self observation queue in array form /// @param timestamp timestamp of current block /// @param targetTimestamp target time stamp /// @param currentPoint current point of swap /// @param currentIndex the index of the last observation in the array /// @param queueLen current max-length of queue /// @return beforeNeighbor before-or-at observation neighbor to target timestamp /// @return afterNeighbor after-or-at observation neighbor to target timestamp, if the targetTimestamp is later than last observation in queue, /// the afterNeighbor observation does not exist in the queue function getTwoNeighborObservation( Observation[65535] storage self, uint32 timestamp, uint32 targetTimestamp, int24 currentPoint, uint16 currentIndex, uint16 queueLen ) private view returns (Observation memory beforeNeighbor, Observation memory afterNeighbor) { beforeNeighbor = self[currentIndex]; if (lte(timestamp, beforeNeighbor.timestamp, targetTimestamp)) { if (beforeNeighbor.timestamp == targetTimestamp) { return (beforeNeighbor, beforeNeighbor); } else { return (beforeNeighbor, newObservation(beforeNeighbor, targetTimestamp, currentPoint)); } } beforeNeighbor = self[(currentIndex + 1) % queueLen]; if (!beforeNeighbor.init) beforeNeighbor = self[0]; require(lte(timestamp, beforeNeighbor.timestamp, targetTimestamp), 'OLD'); return findNeighbor(self, timestamp, targetTimestamp, currentIndex, queueLen); } /// @dev Revert if secondsAgo too large. /// @param self the observation circular queue in array form /// @param timestamp the current block timestamp /// @param secondsAgo target timestamp is timestamp-secondsAg, 0 to return the current cumulative values. /// @param currentPoint the current point of pool /// @param currentIndex the index of the last observation in the array /// @param queueLen max-length of circular queue /// @return accPoint integral value of point(time) from 0 to each timestamp function observeSingle( Observation[65535] storage self, uint32 timestamp, uint32 secondsAgo, int24 currentPoint, uint16 currentIndex, uint16 queueLen ) internal view returns (int56 accPoint ) { if (secondsAgo == 0) { Observation memory last = self[currentIndex]; if (last.timestamp != timestamp) last = newObservation(last, timestamp, currentPoint); return last.accPoint; } uint32 targetTimestamp = timestamp - secondsAgo; (Observation memory beforeNeighbor, Observation memory afterNeighbor) = getTwoNeighborObservation(self, timestamp, targetTimestamp, currentPoint, currentIndex, queueLen); if (targetTimestamp == beforeNeighbor.timestamp) { // we're at the left boundary return beforeNeighbor.accPoint; } else if (targetTimestamp == afterNeighbor.timestamp) { // we're at the right boundary return afterNeighbor.accPoint; } else { // we're in the middle uint56 leftRightTimeDelta = afterNeighbor.timestamp - beforeNeighbor.timestamp; uint56 targetTimeDelta = targetTimestamp - beforeNeighbor.timestamp; return beforeNeighbor.accPoint + (afterNeighbor.accPoint - beforeNeighbor.accPoint) / int56(leftRightTimeDelta) * int56(targetTimeDelta); } } /// @notice Returns the integral value of point with time /// @dev Reverts if target timestamp is early than oldest observation in the queue /// @dev If you call this method with secondsAgos = [3600, 0]. the average point of this pool during recent hour is (accPoints[1] - accPoints[0]) / 3600 /// @param self the observation circular queue in array form /// @param timestamp the current block timestamp /// @param secondsAgos describe the target timestamp , targetTimestimp[i] = block.timestamp - secondsAgo[i] /// @param currentPoint the current point of pool /// @param currentIndex the index of the last observation in the array /// @param queueLen max-length of circular queue /// @return accPoints integral value of point(time) from 0 to each timestamp function observe( Observation[65535] storage self, uint32 timestamp, uint32[] memory secondsAgos, int24 currentPoint, uint16 currentIndex, uint16 queueLen ) internal view returns (int56[] memory accPoints ) { require(queueLen > 0, 'I'); accPoints = new int56[](secondsAgos.length); for (uint256 i = 0; i < secondsAgos.length; i++) { accPoints[i] = observeSingle( self, timestamp, secondsAgos[i], currentPoint, currentIndex, queueLen ); } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.16; library OrderOrEndpoint { function getOrderOrEndptVal(mapping(int24 =>int24) storage self, int24 point, int24 pd) internal view returns(int24 val) { if (point % pd != 0) { return 0; } val = self[point / pd]; } function setOrderOrEndptVal(mapping(int24 =>int24) storage self, int24 point, int24 pd, int24 val) internal { self[point / pd] = val; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.16; library Point { struct Data { uint128 liquidSum; // value to add when pass this slot from left to right // value to dec when pass this slot from right to left int128 liquidDelta; // if pointPrice < currPrice // value = sigma(feeScaleX(p)), which p < pointPrice // if pointPrice >= currPrice // value = sigma(feeScaleX(p)), which p >= pointPrice uint256 accFeeXOut_128; // similar to accFeeXOut_128 uint256 accFeeYOut_128; // whether the point is endpoint of a liquid segment bool isEndpt; } function _getFeeScaleL( int24 endpt, int24 currpt, uint256 feeScale_128, uint256 feeScaleBeyond_128 ) internal pure returns (uint256 feeScaleL_128) { if (endpt <= currpt) { feeScaleL_128 = feeScaleBeyond_128; } else { assembly { feeScaleL_128:= sub(feeScale_128, feeScaleBeyond_128) } } } function _getFeeScaleGE( int24 endpt, int24 currpt, uint256 feeScale_128, uint256 feeScaleBeyond_128 ) internal pure returns (uint256 feeScaleGE_128) { if (endpt > currpt) { feeScaleGE_128 = feeScaleBeyond_128; } else { assembly { feeScaleGE_128:= sub(feeScale_128, feeScaleBeyond_128) } } } /// @dev Calculate fee scale within range [pl, pr). /// @param axies collection of points of liquidities /// @param pl left endpoint of the segment /// @param pr right endpoint of the segment /// @param currpt point of the curr price /// @param feeScaleX_128 total fee scale of token x accummulated of the exchange /// @param feeScaleY_128 similar to feeScaleX_128 /// @return accFeeXIn_128 accFeeYIn_128 fee scale of token x and token y within range [pl, pr) function getSubFeeScale( mapping(int24 =>Point.Data) storage axies, int24 pl, int24 pr, int24 currpt, uint256 feeScaleX_128, uint256 feeScaleY_128 ) internal view returns (uint256 accFeeXIn_128, uint256 accFeeYIn_128) { Point.Data storage plData = axies[pl]; Point.Data storage prData = axies[pr]; // tot fee scale of token x for price < pl uint256 feeScaleLX_128 = _getFeeScaleL(pl, currpt, feeScaleX_128, plData.accFeeXOut_128); // to fee scale of token x for price >= pr uint256 feeScaleGEX_128 = _getFeeScaleGE(pr, currpt, feeScaleX_128, prData.accFeeXOut_128); uint256 feeScaleLY_128 = _getFeeScaleL(pl, currpt, feeScaleY_128, plData.accFeeYOut_128); uint256 feeScaleGEY_128 = _getFeeScaleGE(pr, currpt, feeScaleY_128, prData.accFeeYOut_128); assembly{ accFeeXIn_128 := sub(sub(feeScaleX_128, feeScaleLX_128), feeScaleGEX_128) accFeeYIn_128 := sub(sub(feeScaleY_128, feeScaleLY_128), feeScaleGEY_128) } } /// @dev Update and endpoint of a liquidity segment. /// @param axies collections of points /// @param endpt endpoint of a segment /// @param isLeft left or right endpoint /// @param currpt point of current price /// @param delta >0 for add liquidity and <0 for dec /// @param liquidLimPt liquid limit per point /// @param feeScaleX_128 total fee scale of token x /// @param feeScaleY_128 total fee scale of token y function updateEndpoint( mapping(int24 =>Point.Data) storage axies, int24 endpt, bool isLeft, int24 currpt, int128 delta, uint128 liquidLimPt, uint256 feeScaleX_128, uint256 feeScaleY_128 ) internal returns (bool) { Point.Data storage data = axies[endpt]; uint128 liquidAccBefore = data.liquidSum; // delta cannot be 0 require(delta!=0, "D0"); // liquide acc cannot overflow uint128 liquidAccAfter; if (delta > 0) { liquidAccAfter = liquidAccBefore + uint128(delta); require(liquidAccAfter > liquidAccBefore, "LAAO"); } else { liquidAccAfter = liquidAccBefore - uint128(-delta); require(liquidAccAfter < liquidAccBefore, "LASO"); } require(liquidAccAfter <= liquidLimPt, "L LIM PT"); data.liquidSum = liquidAccAfter; if (isLeft) { data.liquidDelta = data.liquidDelta + delta; } else { data.liquidDelta = data.liquidDelta - delta; } bool new_or_erase = false; if (liquidAccBefore == 0) { // a new endpoint of certain segment new_or_erase = true; data.isEndpt = true; // for either left point or right point of the liquide segment // the feeScaleBeyond can be initialized to arbitrary value // we here set the initial val to total feeScale to delay overflow if (endpt >= currpt) { data.accFeeXOut_128 = feeScaleX_128; data.accFeeYOut_128 = feeScaleY_128; } } else if (liquidAccAfter == 0) { // no segment use this endpoint new_or_erase = true; data.isEndpt = false; } return new_or_erase; } /// @dev Pass the endpoint, change the feescale beyond the price. /// @param endpt endpoint to change /// @param feeScaleX_128 total fee scale of token x /// @param feeScaleY_128 total fee scale of token y function passEndpoint( Point.Data storage endpt, uint256 feeScaleX_128, uint256 feeScaleY_128 ) internal { uint256 accFeeXOut_128 = endpt.accFeeXOut_128; uint256 accFeeYOut_128 = endpt.accFeeYOut_128; assembly { accFeeXOut_128 := sub(feeScaleX_128, accFeeXOut_128) accFeeYOut_128 := sub(feeScaleY_128, accFeeYOut_128) } endpt.accFeeXOut_128 = accFeeXOut_128; endpt.accFeeYOut_128 = accFeeYOut_128; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.16; library PointBitmap { function MSB(uint256 number) internal pure returns (uint8 msb) { require(number > 0); if (number >= 0x100000000000000000000000000000000) { number >>= 128; msb += 128; } if (number >= 0x10000000000000000) { number >>= 64; msb += 64; } if (number >= 0x100000000) { number >>= 32; msb += 32; } if (number >= 0x10000) { number >>= 16; msb += 16; } if (number >= 0x100) { number >>= 8; msb += 8; } if (number >= 0x10) { number >>= 4; msb += 4; } if (number >= 0x4) { number >>= 2; msb += 2; } if (number >= 0x2) msb += 1; } function LSB(uint256 number) internal pure returns (uint8 msb) { require(number > 0); msb = 255; if (number & type(uint128).max > 0) { msb -= 128; } else { number >>= 128; } if (number & type(uint64).max > 0) { msb -= 64; } else { number >>= 64; } if (number & type(uint32).max > 0) { msb -= 32; } else { number >>= 32; } if (number & type(uint16).max > 0) { msb -= 16; } else { number >>= 16; } if (number & type(uint8).max > 0) { msb -= 8; } else { number >>= 8; } if (number & 0xf > 0) { msb -= 4; } else { number >>= 4; } if (number & 0x3 > 0) { msb -= 2; } else { number >>= 2; } if (number & 0x1 > 0) msb -= 1; } /// @notice Flips the initialized state for a given point from false to true, or vice versa /// @param self The mapping in which to flip the point /// @param point The point to flip /// @param pointDelta The spacing between usable points function flipPoint( mapping(int16 => uint256) storage self, int24 point, int24 pointDelta ) internal { require(point % pointDelta == 0); int24 mapPt = point / pointDelta; int16 wordIdx = int16(mapPt >> 8); uint8 bitIdx = uint8(uint24(mapPt % 256)); self[wordIdx] ^= 1 << bitIdx; } function setOne( mapping(int16 => uint256) storage self, int24 point, int24 pointDelta ) internal { require(point % pointDelta == 0); int24 mapPt = point / pointDelta; int16 wordIdx = int16(mapPt >> 8); uint8 bitIdx = uint8(uint24(mapPt % 256)); self[wordIdx] |= 1 << bitIdx; } function setZero( mapping(int16 => uint256) storage self, int24 point, int24 pointDelta ) internal { require(point % pointDelta == 0); int24 mapPt = point / pointDelta; int16 wordIdx = int16(mapPt >> 8); uint8 bitIdx = uint8(uint24(mapPt % 256)); self[wordIdx] &= ~(1 << bitIdx); } // find nearest one from point, or boundary in the same word function nearestLeftOneOrBoundary( mapping(int16 => uint256) storage self, int24 point, int24 pointDelta ) internal view returns (int24 left) { int24 mapPt = point / pointDelta; if (point < 0 && point % pointDelta != 0) mapPt--; // round towards negative infinity int16 wordIdx = int16(mapPt >> 8); uint8 bitIdx = uint8(uint24(mapPt % 256)); uint256 ones = self[wordIdx] & ((1 << bitIdx) - 1 + (1 << bitIdx)); left = (ones != 0) ? (mapPt - int24(uint24(bitIdx - MSB(ones)))) * pointDelta : (mapPt - int24(uint24(bitIdx))) * pointDelta; } // find nearest one from point, or boundary in the same word function nearestRightOneOrBoundary( mapping(int16 => uint256) storage self, int24 point, int24 pointDelta ) internal view returns (int24 right) { int24 mapPt = point / pointDelta; if (point < 0 && point % pointDelta != 0) mapPt--; // round towards negative infinity mapPt += 1; int16 wordIdx = int16(mapPt >> 8); uint8 bitIdx = uint8(uint24(mapPt % 256)); uint256 ones = self[wordIdx] & (~((1 << bitIdx) - 1)); right = (ones != 0) ? (mapPt + int24(uint24(LSB(ones) - bitIdx))) * pointDelta : (mapPt + int24(uint24(type(uint8).max - bitIdx))) * pointDelta; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.16; struct State { // a 96 fixpoing number describe the sqrt value of current price(tokenX/tokenY) uint160 sqrtPrice_96; // The current point of the pool, 1.0001 ^ currentPoint = price int24 currentPoint; // The index of the last oracle observation that was written, uint16 observationCurrentIndex; // The current maximum number of observations stored in the pool, uint16 observationQueueLen; // The next maximum number of observations, to be updated when the observation. uint16 observationNextQueueLen; // whether the pool is locked (only used for checking reentrance) bool locked; // total liquidity on the currentPoint (currX * sqrtPrice + currY / sqrtPrice) uint128 liquidity; // liquidity of tokenX, liquidity of tokenY is liquidity - liquidityX uint128 liquidityX; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.16; import "./MulDivMath.sol"; import "./TwoPower.sol"; import "./AmountMath.sol"; import "./State.sol"; import "./MaxMinMath.sol"; import "./Converter.sol"; library SwapMathX2Y { // group returned values of x2YRange to avoid stake too deep struct RangeRetState { // whether user run out of amountX bool finished; // actual cost of tokenX to buy tokenY uint128 costX; // amount of acquired tokenY uint256 acquireY; // final point after this swap int24 finalPt; // sqrt price on final point uint160 sqrtFinalPrice_96; // liquidity of tokenX at finalPt uint128 liquidityX; } function x2YAtPrice( uint128 amountX, uint160 sqrtPrice_96, uint128 currY ) internal pure returns (uint128 costX, uint128 acquireY) { uint256 l = MulDivMath.mulDivFloor(amountX, sqrtPrice_96, TwoPower.Pow96); acquireY = Converter.toUint128(MulDivMath.mulDivFloor(l, sqrtPrice_96, TwoPower.Pow96)); if (acquireY > currY) { acquireY = currY; } l = MulDivMath.mulDivCeil(acquireY, TwoPower.Pow96, sqrtPrice_96); uint256 cost = MulDivMath.mulDivCeil(l, TwoPower.Pow96, sqrtPrice_96); // costX <= amountX <= uint128.max costX = uint128(cost); } function mulDivCeil(uint256 a, uint256 b, uint256 c) internal pure returns (uint256) { uint256 v = a * b; if (v % c == 0) { return v / c; } return v / c + 1; } function x2YAtPriceLiquidity( uint128 amountX, uint160 sqrtPrice_96, uint128 liquidity, uint128 liquidityX ) internal pure returns (uint128 costX, uint256 acquireY, uint128 newLiquidityX) { uint256 liquidityY = uint256(liquidity - liquidityX); uint256 maxTransformLiquidityX = MulDivMath.mulDivFloor(amountX, sqrtPrice_96, TwoPower.Pow96); // transformLiquidityX <= liquidityY <= uint128.max uint128 transformLiquidityX = uint128(MaxMinMath.min256(maxTransformLiquidityX, liquidityY)); // 1. transformLiquidityX * TwoPower.Pow96 < 2^128 * 2^96 < 2^224 < 2^256 // 2. transformLiquidityX <= floor(amountX * sqrtPrice_96 / TwoPower.Pow96) // ceil(transformLiquidityX * sqrtPrice_96 / TwoPower.Pow96) <= // ceil(floor(amountX * sqrtPrice_96 / TwoPower.Pow96) * sqrtPrice_96 / TwoPower.Pow96) <= // ceil(amountX * sqrtPrice_96 / TwoPower.Pow96 * sqrtPrice_96 / TwoPower.Pow96) = // ceil(amountX) = amountX <= uint128.max costX = uint128(mulDivCeil(transformLiquidityX, TwoPower.Pow96, sqrtPrice_96)); acquireY = MulDivMath.mulDivFloor(transformLiquidityX, sqrtPrice_96, TwoPower.Pow96); newLiquidityX = liquidityX + transformLiquidityX; } struct Range { uint128 liquidity; uint160 sqrtPriceL_96; int24 leftPt; uint160 sqrtPriceR_96; int24 rightPt; uint160 sqrtRate_96; } struct RangeCompRet { uint128 costX; uint256 acquireY; bool completeLiquidity; int24 locPt; uint160 sqrtLoc_96; } /// @dev Move from rightPt to leftPt, the range is [leftPt, rightPt). function x2YRangeComplete( Range memory rg, uint128 amountX ) internal pure returns ( RangeCompRet memory ret ) { // rg.sqrtPriceR_96 * 2^96 < 2^160 * 2^96 = 2^256 uint160 sqrtPricePrM1_96 = uint160(mulDivCeil(rg.sqrtPriceR_96, TwoPower.Pow96, rg.sqrtRate_96)); uint160 sqrtPricePrMl_96 = LogPowMath.getSqrtPrice(rg.rightPt - rg.leftPt); // rg.rightPt - rg.leftPt <= 256 * 100 // 1.0001 ** 25600 < 13 // 13 * 2^96 - 2^96 < 2^100 // rg.liquidity * (sqrtPricePrMl_96 - TwoPower.Pow96) < 2^228 < 2^256 uint256 maxX = mulDivCeil(rg.liquidity, sqrtPricePrMl_96 - TwoPower.Pow96, rg.sqrtPriceR_96 - sqrtPricePrM1_96); if (maxX <= amountX) { // maxX <= amountX <= uint128.max ret.costX = uint128(maxX); ret.acquireY = AmountMath.getAmountY(rg.liquidity, rg.sqrtPriceL_96, rg.sqrtPriceR_96, rg.sqrtRate_96, false); ret.completeLiquidity = true; } else { // we should locate lowest price // 1. amountX * (rg.sqrtPriceR_96 - sqrtPricePrM1_96) // < maxX * (rg.sqrtPriceR_96 - sqrtPricePrM1_96) // < rg.liquidity * (sqrtPricePrMl_96 - TwoPower.Pow96) + (rg.sqrtPriceR_96 - sqrtPricePrM1_96) // < 2^228 + 2^160 < 2^256 // 2. sqrtValue_96 = amountX * (rg.sqrtPriceR_96 - sqrtPricePrM1_96) // rg.liquidity + 2^96 // <= amountX * (rg.sqrtPriceR_96 - sqrtPricePrM1_96) / rg.liquidity + 2^96 // <= (maxX - 1) * (rg.sqrtPriceR_96 - sqrtPricePrM1_96) / rg.liquidity + 2^96 // < rg.liquidity * (sqrtPricePrMl_96 - 2^96) / (rg.sqrtPriceR_96 - sqrtPricePrM1_96) * (rg.sqrtPriceR_96 - sqrtPricePrM1_96) / rg.liquidity + 2^96 // = sqrtPricePrMl_96 < 2^160 uint160 sqrtValue_96 = uint160(uint256(amountX) * (uint256(rg.sqrtPriceR_96) - sqrtPricePrM1_96) / uint256(rg.liquidity) + TwoPower.Pow96); int24 logValue = LogPowMath.getLogSqrtPriceFloor(sqrtValue_96); ret.locPt = rg.rightPt - logValue; ret.locPt = MaxMinMath.min(ret.locPt, rg.rightPt); ret.locPt = MaxMinMath.max(ret.locPt, rg.leftPt + 1); ret.completeLiquidity = false; if (ret.locPt == rg.rightPt) { ret.costX = 0; ret.acquireY = 0; ret.locPt = ret.locPt - 1; ret.sqrtLoc_96 = LogPowMath.getSqrtPrice(ret.locPt); } else { uint160 sqrtPricePrMloc_96 = LogPowMath.getSqrtPrice(rg.rightPt - ret.locPt); // rg.rightPt - ret.locPt <= 256 * 100 // 1.0001 ** 25600 < 13 // 13 * 2^96 - 2^96 < 2^100 // rg.liquidity * (sqrtPricePrMloc_96 - TwoPower.Pow96) < 2^228 < 2^256 uint256 costX256 = mulDivCeil(rg.liquidity, sqrtPricePrMloc_96 - TwoPower.Pow96, rg.sqrtPriceR_96 - sqrtPricePrM1_96); // ret.costX <= amountX <= uint128.max ret.costX = uint128(MaxMinMath.min256(costX256, amountX)); ret.locPt = ret.locPt - 1; ret.sqrtLoc_96 = LogPowMath.getSqrtPrice(ret.locPt); uint160 sqrtLocA1_96 = uint160( uint256(ret.sqrtLoc_96) + uint256(ret.sqrtLoc_96) * (uint256(rg.sqrtRate_96) - TwoPower.Pow96) / TwoPower.Pow96 ); ret.acquireY = AmountMath.getAmountY(rg.liquidity, sqrtLocA1_96, rg.sqrtPriceR_96, rg.sqrtRate_96, false); } } } /// @notice Compute amount of tokens exchanged during swapX2Y and some amount values (currX, currY, allX) on final point /// after this swap. /// @param currentState state values containing (currX, currY, allX) of start point /// @param leftPt left most point during this swap /// @param sqrtRate_96 sqrt(1.0001) /// @param amountX max amount of tokenX user willing to pay /// @return retState amount of token acquired and some values on final point function x2YRange( State memory currentState, int24 leftPt, uint160 sqrtRate_96, uint128 amountX ) internal pure returns ( RangeRetState memory retState ) { retState.costX = 0; retState.acquireY = 0; retState.finished = false; bool currentHasY = (currentState.liquidityX < currentState.liquidity); if (currentHasY && (currentState.liquidityX > 0 || leftPt == currentState.currentPoint)) { (retState.costX, retState.acquireY, retState.liquidityX) = x2YAtPriceLiquidity( amountX, currentState.sqrtPrice_96, currentState.liquidity, currentState.liquidityX ); if (retState.liquidityX < currentState.liquidity || retState.costX >= amountX) { // remaining x is not enough to down current price to price / 1.0001 // but x may remain, so we cannot simply use (costX == amountX) retState.finished = true; retState.finalPt = currentState.currentPoint; retState.sqrtFinalPrice_96 = currentState.sqrtPrice_96; } else { amountX -= retState.costX; } } else if (currentHasY) { // all y currentState.currentPoint = currentState.currentPoint + 1; // sqrt(price) + sqrt(price) * (1.0001 - 1) == sqrt(price) * 1.0001 currentState.sqrtPrice_96 = uint160( uint256(currentState.sqrtPrice_96) + uint256(currentState.sqrtPrice_96) * (uint256(sqrtRate_96) - TwoPower.Pow96) / TwoPower.Pow96 ); } else { retState.liquidityX = currentState.liquidityX; } if (retState.finished) { return retState; } if (leftPt < currentState.currentPoint) { uint160 sqrtPriceL_96 = LogPowMath.getSqrtPrice(leftPt); RangeCompRet memory ret = x2YRangeComplete( Range({ liquidity: currentState.liquidity, sqrtPriceL_96: sqrtPriceL_96, leftPt: leftPt, sqrtPriceR_96: currentState.sqrtPrice_96, rightPt: currentState.currentPoint, sqrtRate_96: sqrtRate_96 }), amountX ); retState.costX += ret.costX; amountX -= ret.costX; retState.acquireY += ret.acquireY; if (ret.completeLiquidity) { retState.finished = (amountX == 0); retState.finalPt = leftPt; retState.sqrtFinalPrice_96 = sqrtPriceL_96; retState.liquidityX = currentState.liquidity; } else { uint128 locCostX; uint256 locAcquireY; (locCostX, locAcquireY, retState.liquidityX) = x2YAtPriceLiquidity(amountX, ret.sqrtLoc_96, currentState.liquidity, 0); retState.costX += locCostX; retState.acquireY += locAcquireY; retState.finished = true; retState.sqrtFinalPrice_96 = ret.sqrtLoc_96; retState.finalPt = ret.locPt; } } else { // finishd must be false // retState.finished == false; // liquidityX has been set retState.finalPt = currentState.currentPoint; retState.sqrtFinalPrice_96 = currentState.sqrtPrice_96; } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.16; import './MulDivMath.sol'; import './TwoPower.sol'; import './AmountMath.sol'; import './State.sol'; import './MaxMinMath.sol'; import './Converter.sol'; library SwapMathY2X { struct RangeRetState { // whether user has run out of tokenY bool finished; // actual cost of tokenY to buy tokenX uint128 costY; // actual amount of tokenX acquired uint256 acquireX; // final point after this swap int24 finalPt; // sqrt price on final point uint160 sqrtFinalPrice_96; // liquidity of tokenX at finalPt // if finalPt is not rightPt, liquidityX is meaningless uint128 liquidityX; } function y2XAtPrice( uint128 amountY, uint160 sqrtPrice_96, uint128 currX ) internal pure returns (uint128 costY, uint128 acquireX) { uint256 l = MulDivMath.mulDivFloor(amountY, TwoPower.Pow96, sqrtPrice_96); // acquireX <= currX <= uint128.max acquireX = uint128(MaxMinMath.min256(MulDivMath.mulDivFloor(l, TwoPower.Pow96, sqrtPrice_96), currX)); l = MulDivMath.mulDivCeil(acquireX, sqrtPrice_96, TwoPower.Pow96); uint256 cost = MulDivMath.mulDivCeil(l, sqrtPrice_96, TwoPower.Pow96); // costY = cost <= amountY <= uint128.max costY = uint128(cost); } function y2XAtPriceLiquidity( uint128 amountY, uint160 sqrtPrice_96, uint128 liquidityX ) internal pure returns (uint128 costY, uint256 acquireX, uint128 newLiquidityX) { // amountY * TwoPower.Pow96 < 2^128 * 2^96 = 2^224 < 2^256 uint256 maxTransformLiquidityY = uint256(amountY) * TwoPower.Pow96 / sqrtPrice_96; // transformLiquidityY <= liquidityX uint128 transformLiquidityY = uint128(MaxMinMath.min256(maxTransformLiquidityY, liquidityX)); // costY <= amountY costY = uint128(MulDivMath.mulDivCeil(transformLiquidityY, sqrtPrice_96, TwoPower.Pow96)); // transformLiquidityY * 2^96 < 2^224 < 2^256 acquireX = uint256(transformLiquidityY) * TwoPower.Pow96 / sqrtPrice_96; newLiquidityX = liquidityX - transformLiquidityY; } struct Range { uint128 liquidity; uint160 sqrtPriceL_96; int24 leftPt; uint160 sqrtPriceR_96; int24 rightPt; uint160 sqrtRate_96; } struct RangeCompRet { uint128 costY; uint256 acquireX; bool completeLiquidity; int24 locPt; uint160 sqrtLoc_96; } function y2XRangeComplete( Range memory rg, uint128 amountY ) internal pure returns ( RangeCompRet memory ret ) { uint256 maxY = AmountMath.getAmountY(rg.liquidity, rg.sqrtPriceL_96, rg.sqrtPriceR_96, rg.sqrtRate_96, true); if (maxY <= amountY) { // ret.costY <= maxY <= uint128.max ret.costY = uint128(maxY); ret.acquireX = AmountMath.getAmountX(rg.liquidity, rg.leftPt, rg.rightPt, rg.sqrtPriceR_96, rg.sqrtRate_96, false); // we complete this liquidity segment ret.completeLiquidity = true; } else { // we should locate highest price // uint160 is enough for muldiv and adding, because amountY < maxY uint160 sqrtLoc_96 = uint160(MulDivMath.mulDivFloor( amountY, rg.sqrtRate_96 - TwoPower.Pow96, rg.liquidity ) + rg.sqrtPriceL_96); ret.locPt = LogPowMath.getLogSqrtPriceFloor(sqrtLoc_96); ret.locPt = MaxMinMath.max(rg.leftPt, ret.locPt); ret.locPt = MaxMinMath.min(rg.rightPt - 1, ret.locPt); ret.completeLiquidity = false; ret.sqrtLoc_96 = LogPowMath.getSqrtPrice(ret.locPt); if (ret.locPt == rg.leftPt) { ret.costY = 0; ret.acquireX = 0; return ret; } uint256 costY256 = AmountMath.getAmountY( rg.liquidity, rg.sqrtPriceL_96, ret.sqrtLoc_96, rg.sqrtRate_96, true ); // ret.costY <= amountY <= uint128.max ret.costY = uint128(MaxMinMath.min256(costY256, amountY)); // costY <= amountY even if the costY is the upperbound of the result // because amountY is not a real and sqrtLoc_96 <= sqrtLoc256_96 ret.acquireX = AmountMath.getAmountX( rg.liquidity, rg.leftPt, ret.locPt, ret.sqrtLoc_96, rg.sqrtRate_96, false ); } } /// @notice Compute amount of tokens exchanged during swapY2X and some amount values (currX, currY, allX) on final point /// after this swap. /// @param currentState state values containing (currX, currY, allX) of start point /// @param rightPt right most point during this swap /// @param sqrtRate_96 sqrt(1.0001) /// @param amountY max amount of Y user willing to pay /// @return retState amount of token acquired and some values on final point function y2XRange( State memory currentState, int24 rightPt, uint160 sqrtRate_96, uint128 amountY ) internal pure returns ( RangeRetState memory retState ) { retState.costY = 0; retState.acquireX = 0; retState.finished = false; // first, if current point is not all x, we can not move right directly bool startHasY = (currentState.liquidityX < currentState.liquidity); if (startHasY) { (retState.costY, retState.acquireX, retState.liquidityX) = y2XAtPriceLiquidity( amountY, currentState.sqrtPrice_96, currentState.liquidityX ); if (retState.liquidityX > 0 || retState.costY >= amountY) { // it means remaining y is not enough to rise current price to price*1.0001 // but y may remain, so we cannot simply use (costY == amountY) retState.finished = true; retState.finalPt = currentState.currentPoint; retState.sqrtFinalPrice_96 = currentState.sqrtPrice_96; return retState; } else { // y not run out // not finsihed amountY -= retState.costY; currentState.currentPoint += 1; if (currentState.currentPoint == rightPt) { retState.finalPt = currentState.currentPoint; // get fixed sqrt price to reduce accumulated error retState.sqrtFinalPrice_96 = LogPowMath.getSqrtPrice(rightPt); return retState; } // sqrt(price) + sqrt(price) * (1.0001 - 1) == sqrt(price) * 1.0001 currentState.sqrtPrice_96 = uint160( uint256(currentState.sqrtPrice_96) + uint256(currentState.sqrtPrice_96) * (uint256(sqrtRate_96) - TwoPower.Pow96) / TwoPower.Pow96 ); } } uint160 sqrtPriceR_96 = LogPowMath.getSqrtPrice(rightPt); // (uint128 liquidCostY, uint256 liquidAcquireX, bool liquidComplete, int24 locPt, uint160 sqrtLoc_96) RangeCompRet memory ret = y2XRangeComplete( Range({ liquidity: currentState.liquidity, sqrtPriceL_96: currentState.sqrtPrice_96, leftPt: currentState.currentPoint, sqrtPriceR_96: sqrtPriceR_96, rightPt: rightPt, sqrtRate_96: sqrtRate_96 }), amountY ); retState.costY += ret.costY; amountY -= ret.costY; retState.acquireX += ret.acquireX; if (ret.completeLiquidity) { retState.finished = (amountY == 0); retState.finalPt = rightPt; retState.sqrtFinalPrice_96 = sqrtPriceR_96; } else { // trade at locPt uint128 locCostY; uint256 locAcquireX; (locCostY, locAcquireX, retState.liquidityX) = y2XAtPriceLiquidity(amountY, ret.sqrtLoc_96, currentState.liquidity); retState.costY += locCostY; retState.acquireX += locAcquireX; retState.finished = true; retState.sqrtFinalPrice_96 = ret.sqrtLoc_96; retState.finalPt = ret.locPt; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import "../interfaces/IERC20Minimal.sol"; library TokenTransfer { function transferToken( address tokenAddr, address toAddr, uint256 amount ) internal { (bool ok, bytes memory retData) = tokenAddr.call(abi.encodeWithSelector(IERC20Minimal.transfer.selector, toAddr, amount)); require(ok && (retData.length == 0 || abi.decode(retData, (bool))), 'TNS'); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; library TwoPower { uint256 internal constant Pow128 = 0x100000000000000000000000000000000; uint256 internal constant Pow96 = 0x1000000000000000000000000; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.16; import "./MulDivMath.sol"; import "./TwoPower.sol"; import "./Converter.sol"; import "./MaxMinMath.sol"; library UserEarn { // describe user's earning info for a limit order struct Data { // total amount of earned token by all users at this point // with same direction (sell x or sell y) as of the last update(add/dec) uint256 lastAccEarn; // remaing amount of token on sale in this limit order uint128 sellingRemain; // uncollected decreased token uint128 sellingDec; // unassigned and unlegacy earned token // earned token before collected need to be assigned uint128 earn; // unassigned and legacy earned token uint128 legacyEarn; // assigned but uncollected earned token (both unlegacy and legacy) uint128 earnAssign; } function get( mapping(bytes32 => Data) storage self, address user, int24 point ) internal view returns (UserEarn.Data storage data) { data = self[keccak256(abi.encodePacked(user, point))]; } /// @notice update UserEarn info for an unlegacy (uncleared during swap) limit order. /// update strategy is 'first claim first earn', etc, earned token will be transformed for /// limit orders which is update first /// @param self UserEarn storage object of target limit order /// @param currAccEarn 'accEarn' value of corresponding point order on swap pool. /// accumulate amount of earned token /// @param sqrtPrice_96 describe price of limit order /// @param totalEarn remained(undistributed) amount of earned token of unlegacy limit order on corresponding point /// @param isEarnY direction of corresponding limit order. function updateUnlegacyOrder( UserEarn.Data storage self, uint256 currAccEarn, uint160 sqrtPrice_96, uint128 totalEarn, bool isEarnY ) internal returns (uint128 totalEarnRemain, uint128 claimSold, uint128 claimEarn) { Data memory data = self; // first, we compute how many earned token remained on the point order uint256 earn = currAccEarn - data.lastAccEarn; if (earn > totalEarn) { earn = totalEarn; } // second, compute how many sold token according to the 'first claim first earn' strategy, // etc, for earnY, sold = min(sellingRemain, earn / price) // for earnX, sold = min(sellingRemain, earn * price) uint256 sold; if (isEarnY) { uint256 l = MulDivMath.mulDivCeil(earn, TwoPower.Pow96, sqrtPrice_96); sold = MulDivMath.mulDivCeil(l, TwoPower.Pow96, sqrtPrice_96); } else { uint256 l = MulDivMath.mulDivCeil(earn, sqrtPrice_96, TwoPower.Pow96); sold = MulDivMath.mulDivCeil(l, sqrtPrice_96, TwoPower.Pow96); } if (sold > data.sellingRemain) { sold = data.sellingRemain; if (isEarnY) { uint256 l = MulDivMath.mulDivFloor(sold, sqrtPrice_96, TwoPower.Pow96); earn = MulDivMath.mulDivFloor(l, sqrtPrice_96, TwoPower.Pow96); } else { uint256 l = MulDivMath.mulDivFloor(sold, TwoPower.Pow96, sqrtPrice_96); earn = MulDivMath.mulDivFloor(l, TwoPower.Pow96, sqrtPrice_96); } } // sold1 = ceil(ceil(earn1 * Q / P) * Q / P) // if sold1 <= data.sellingRemain, earn = earn1 <= totalEarn, sold=sold1 <= data.sellingRemain // if sold1 > data.sellingRemain, sold = data.sellingRemain // sold1 - 1 < ceil(ceil(earn1 * Q / P) * Q / P) // => sold1 - 1 < ceil(earn1 * Q / P) * Q / P // => floor((sold1 - 1) * P / Q) < ceil(earn1 * Q / P) // => floor((sold1 - 1) * P / Q) < earn1 * Q / P // => earn = floor(floor((sold1 - 1) * P / Q) * P / Q) < earn1 <= totalEarn // thirdly, update info of userEarn object // earn <= totalEarn data.earn += uint128(earn); // sold <= data.sellingRemain data.sellingRemain -= uint128(sold); self.lastAccEarn = currAccEarn; if (earn > 0) { self.earn = data.earn; } if (sold > 0) { self.sellingRemain = data.sellingRemain; } claimSold = uint128(sold); claimEarn = uint128(earn); // earn <= totalEarn totalEarnRemain = totalEarn - claimEarn; } /// @notice update UserEarn info for an unlegacy (uncleared during swap) limit order. /// and then add some amount of selling token /// update strategy is 'first claim first earn', etc, earned token will be transformed for /// limit orders which is update first /// @param self UserEarn storage object of target limit order /// @param currAccEarn 'accEarn' value of corresponding point order on swap pool. /// accumulate amount of earned token /// @param sqrtPrice_96 describe price of limit order /// @param totalEarn remained(undistributed) amount of earned token of unlegacy limit order on corresponding point /// @param isEarnY direction of corresponding limit order. function addUnlegacyOrder( UserEarn.Data storage self, uint128 delta, uint256 currAccEarn, uint160 sqrtPrice_96, uint128 totalEarn, bool isEarnY ) internal returns(uint128 totalEarnRemain, uint128 claimSold, uint128 claimEarn) { // first, call `updateUnlegacyOrder` to update unlegacy order (totalEarnRemain, claimSold, claimEarn) = updateUnlegacyOrder(self, currAccEarn, sqrtPrice_96, totalEarn, isEarnY); // then, add self.sellingRemain = self.sellingRemain + delta; } /// @notice update UserEarn info for an unlegacy (uncleared during swap) limit order. /// and then decrease some amount of selling token (if remain) /// update strategy is 'first claim first earn', etc, earned token will be transformed for /// limit orders which is update first /// @param self UserEarn storage object of target limit order /// @param currAccEarn 'accEarn' value of corresponding point order on swap pool. /// accumulate amount of earned token /// @param sqrtPrice_96 describe price of limit order /// @param totalEarn remained(undistributed) amount of earned token of unlegacy limit order on corresponding point /// @param isEarnY direction of corresponding limit order. function decUnlegacyOrder( UserEarn.Data storage self, uint128 delta, uint256 currAccEarn, uint160 sqrtPrice_96, uint128 totalEarn, bool isEarnY ) internal returns(uint128 actualDelta, uint128 totalEarnRemain, uint128 claimSold, uint128 claimEarn) { // first, call `updateUnlegacyOrder` to update unlegacy order (totalEarnRemain, claimSold, claimEarn) = updateUnlegacyOrder(self, currAccEarn, sqrtPrice_96, totalEarn, isEarnY); // then decrease actualDelta = MaxMinMath.min(delta, self.sellingRemain); self.sellingRemain = self.sellingRemain - actualDelta; self.sellingDec = self.sellingDec + actualDelta; } /// @notice update UserEarn info for a legacy (cleared during swap) limit order. /// an limit order we call it 'legacy' if it together with other limit order of same /// direction and same point on the pool is cleared during one time of exchanging. /// if an limit order is convinced to be 'legacy', we should mark it as 'sold out', /// etc, transform all its remained selling token to earned token. /// @param self UserEarn storage object of target limit order /// @param addDelta addition of selling amount /// @param currAccEarn 'accEarn' value of corresponding point order on swap pool. /// accumulate amount of earned token /// @param sqrtPrice_96 describe price of limit order /// @param totalLegacyEarn remained(undistributed) amount of earned token of legacy limit order on corresponding point /// @param isEarnY direction of corresponding limit order. function updateLegacyOrder( UserEarn.Data storage self, uint128 addDelta, uint256 currAccEarn, uint160 sqrtPrice_96, uint128 totalLegacyEarn, bool isEarnY ) internal returns(uint128 totalLegacyEarnRemain, uint128 sold, uint128 claimedEarn) { sold = self.sellingRemain; uint256 earn = 0; if (sold > 0) { // transform all its remained selling token to earned token. if (isEarnY) { uint256 l = MulDivMath.mulDivFloor(sold, sqrtPrice_96, TwoPower.Pow96); // for earnY, earn = sold * price earn = MulDivMath.mulDivFloor(l, sqrtPrice_96, TwoPower.Pow96); } else { uint256 l = MulDivMath.mulDivFloor(sold, TwoPower.Pow96, sqrtPrice_96); // for earnX, earn = sold / price earn = MulDivMath.mulDivFloor(l, TwoPower.Pow96, sqrtPrice_96); } if (earn > totalLegacyEarn) { earn = totalLegacyEarn; } self.sellingRemain = 0; // count earned token into legacyEarn field, not earn field self.legacyEarn += uint128(earn); } claimedEarn = uint128(earn); self.lastAccEarn = currAccEarn; totalLegacyEarnRemain = totalLegacyEarn - claimedEarn; if (addDelta > 0) { // sellingRemain has been clear to 0 self.sellingRemain = addDelta; } } }
{ "optimizer": { "enabled": true } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint128","name":"addAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"acquireAmount","type":"uint128"},{"indexed":true,"internalType":"int24","name":"point","type":"int24"},{"indexed":false,"internalType":"uint128","name":"claimSold","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"claimEarn","type":"uint128"},{"indexed":false,"internalType":"bool","name":"sellXEarnY","type":"bool"}],"name":"AddLimitOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"int24","name":"leftPoint","type":"int24"},{"indexed":true,"internalType":"int24","name":"rightPoint","type":"int24"},{"indexed":false,"internalType":"uint128","name":"liquidity","type":"uint128"},{"indexed":false,"internalType":"uint256","name":"amountX","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountY","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":"point","type":"int24"},{"indexed":false,"internalType":"uint128","name":"collectDec","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"collectEarn","type":"uint128"},{"indexed":false,"internalType":"bool","name":"sellXEarnY","type":"bool"}],"name":"CollectLimitOrder","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":"leftPoint","type":"int24"},{"indexed":true,"internalType":"int24","name":"rightPoint","type":"int24"},{"indexed":false,"internalType":"uint256","name":"amountX","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountY","type":"uint256"}],"name":"CollectLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint128","name":"decreaseAmount","type":"uint128"},{"indexed":true,"internalType":"int24","name":"point","type":"int24"},{"indexed":false,"internalType":"uint128","name":"claimSold","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"claimEarn","type":"uint128"},{"indexed":false,"internalType":"bool","name":"sellXEarnY","type":"bool"}],"name":"DecLimitOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountX","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountY","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"paidX","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"paidY","type":"uint256"}],"name":"Flash","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":"leftPoint","type":"int24"},{"indexed":true,"internalType":"int24","name":"rightPoint","type":"int24"},{"indexed":false,"internalType":"uint128","name":"liquidity","type":"uint128"},{"indexed":false,"internalType":"uint256","name":"amountX","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountY","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenX","type":"address"},{"indexed":true,"internalType":"address","name":"tokenY","type":"address"},{"indexed":true,"internalType":"uint24","name":"fee","type":"uint24"},{"indexed":false,"internalType":"bool","name":"sellXEarnY","type":"bool"},{"indexed":false,"internalType":"uint256","name":"amountX","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountY","type":"uint256"}],"name":"Swap","type":"event"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"int24","name":"point","type":"int24"},{"internalType":"uint128","name":"amountX","type":"uint128"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"addLimOrderWithX","outputs":[{"internalType":"uint128","name":"orderX","type":"uint128"},{"internalType":"uint128","name":"acquireY","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"int24","name":"point","type":"int24"},{"internalType":"uint128","name":"amountY","type":"uint128"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"addLimOrderWithY","outputs":[{"internalType":"uint128","name":"orderY","type":"uint128"},{"internalType":"uint128","name":"acquireX","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int24","name":"point","type":"int24"},{"internalType":"uint128","name":"assignX","type":"uint128"},{"internalType":"bool","name":"fromLegacy","type":"bool"}],"name":"assignLimOrderEarnX","outputs":[{"internalType":"uint128","name":"actualAssignX","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int24","name":"point","type":"int24"},{"internalType":"uint128","name":"assignY","type":"uint128"},{"internalType":"bool","name":"fromLegacy","type":"bool"}],"name":"assignLimOrderEarnY","outputs":[{"internalType":"uint128","name":"actualAssignY","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int24","name":"leftPt","type":"int24"},{"internalType":"int24","name":"rightPt","type":"int24"},{"internalType":"uint128","name":"liquidDelta","type":"uint128"}],"name":"burn","outputs":[{"internalType":"uint256","name":"amountX","type":"uint256"},{"internalType":"uint256","name":"amountY","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"int24","name":"leftPt","type":"int24"},{"internalType":"int24","name":"rightPt","type":"int24"},{"internalType":"uint256","name":"amountXLim","type":"uint256"},{"internalType":"uint256","name":"amountYLim","type":"uint256"}],"name":"collect","outputs":[{"internalType":"uint256","name":"actualAmountX","type":"uint256"},{"internalType":"uint256","name":"actualAmountY","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collectFeeCharged","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"int24","name":"point","type":"int24"},{"internalType":"uint128","name":"collectDec","type":"uint128"},{"internalType":"uint128","name":"collectEarn","type":"uint128"},{"internalType":"bool","name":"isEarnY","type":"bool"}],"name":"collectLimOrder","outputs":[{"internalType":"uint128","name":"actualCollectDec","type":"uint128"},{"internalType":"uint128","name":"actualCollectEarn","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int24","name":"point","type":"int24"},{"internalType":"uint128","name":"deltaX","type":"uint128"}],"name":"decLimOrderWithX","outputs":[{"internalType":"uint128","name":"actualDeltaX","type":"uint128"},{"internalType":"uint256","name":"legacyAccEarn","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int24","name":"point","type":"int24"},{"internalType":"uint128","name":"deltaY","type":"uint128"}],"name":"decLimOrderWithY","outputs":[{"internalType":"uint128","name":"actualDeltaY","type":"uint128"},{"internalType":"uint256","name":"legacyAccEarn","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"newNextQueueLen","type":"uint16"}],"name":"expandObservationQueue","outputs":[],"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":"feeChargePercent","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeScaleX_128","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeScaleY_128","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountX","type":"uint256"},{"internalType":"uint256","name":"amountY","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"flash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"leftMostPt","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int24","name":"","type":"int24"}],"name":"limitOrderData","outputs":[{"internalType":"uint128","name":"sellingX","type":"uint128"},{"internalType":"uint128","name":"earnY","type":"uint128"},{"internalType":"uint256","name":"accEarnY","type":"uint256"},{"internalType":"uint256","name":"legacyAccEarnY","type":"uint256"},{"internalType":"uint128","name":"legacyEarnY","type":"uint128"},{"internalType":"uint128","name":"sellingY","type":"uint128"},{"internalType":"uint128","name":"earnX","type":"uint128"},{"internalType":"uint128","name":"legacyEarnX","type":"uint128"},{"internalType":"uint256","name":"accEarnX","type":"uint256"},{"internalType":"uint256","name":"legacyAccEarnX","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int24","name":"leftPoint","type":"int24"},{"internalType":"int24","name":"rightPoint","type":"int24"}],"name":"limitOrderSnapshot","outputs":[{"components":[{"internalType":"uint128","name":"sellingX","type":"uint128"},{"internalType":"uint128","name":"earnY","type":"uint128"},{"internalType":"uint256","name":"accEarnY","type":"uint256"},{"internalType":"uint128","name":"sellingY","type":"uint128"},{"internalType":"uint128","name":"earnX","type":"uint128"},{"internalType":"uint256","name":"accEarnX","type":"uint256"}],"internalType":"struct IiZiSwapPool.LimitOrderStruct[]","name":"limitOrders","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"liquidity","outputs":[{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint256","name":"lastFeeScaleX_128","type":"uint256"},{"internalType":"uint256","name":"lastFeeScaleY_128","type":"uint256"},{"internalType":"uint256","name":"tokenOwedX","type":"uint256"},{"internalType":"uint256","name":"tokenOwedY","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int24","name":"leftPoint","type":"int24"},{"internalType":"int24","name":"rightPoint","type":"int24"}],"name":"liquiditySnapshot","outputs":[{"internalType":"int128[]","name":"deltaLiquidities","type":"int128[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLiquidPt","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"int24","name":"leftPt","type":"int24"},{"internalType":"int24","name":"rightPt","type":"int24"},{"internalType":"uint128","name":"liquidDelta","type":"uint128"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"mint","outputs":[{"internalType":"uint256","name":"amountX","type":"uint256"},{"internalType":"uint256","name":"amountY","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint24","name":"newFeeChargePercent","type":"uint24"}],"name":"modifyFeeChargePercent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"observations","outputs":[{"internalType":"uint32","name":"timestamp","type":"uint32"},{"internalType":"int56","name":"accPoint","type":"int56"},{"internalType":"bool","name":"init","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32[]","name":"secondsAgos","type":"uint32[]"}],"name":"observe","outputs":[{"internalType":"int56[]","name":"accPoints","type":"int56[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int24","name":"","type":"int24"}],"name":"orderOrEndpoint","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int16","name":"","type":"int16"}],"name":"pointBitmap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pointDelta","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int24","name":"","type":"int24"}],"name":"points","outputs":[{"internalType":"uint128","name":"liquidSum","type":"uint128"},{"internalType":"int128","name":"liquidDelta","type":"int128"},{"internalType":"uint256","name":"accFeeXOut_128","type":"uint256"},{"internalType":"uint256","name":"accFeeYOut_128","type":"uint256"},{"internalType":"bool","name":"isEndpt","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rightMostPt","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sqrtRate_96","outputs":[{"internalType":"uint160","name":"","type":"uint160"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"state","outputs":[{"internalType":"uint160","name":"sqrtPrice_96","type":"uint160"},{"internalType":"int24","name":"currentPoint","type":"int24"},{"internalType":"uint16","name":"observationCurrentIndex","type":"uint16"},{"internalType":"uint16","name":"observationQueueLen","type":"uint16"},{"internalType":"uint16","name":"observationNextQueueLen","type":"uint16"},{"internalType":"bool","name":"locked","type":"bool"},{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint128","name":"liquidityX","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"int24","name":"lowPt","type":"int24"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"swapX2Y","outputs":[{"internalType":"uint256","name":"amountX","type":"uint256"},{"internalType":"uint256","name":"amountY","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"desireY","type":"uint128"},{"internalType":"int24","name":"lowPt","type":"int24"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"swapX2YDesireY","outputs":[{"internalType":"uint256","name":"amountX","type":"uint256"},{"internalType":"uint256","name":"amountY","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"int24","name":"highPt","type":"int24"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"swapY2X","outputs":[{"internalType":"uint256","name":"amountX","type":"uint256"},{"internalType":"uint256","name":"amountY","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"desireX","type":"uint128"},{"internalType":"int24","name":"highPt","type":"int24"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"swapY2XDesireX","outputs":[{"internalType":"uint256","name":"amountX","type":"uint256"},{"internalType":"uint256","name":"amountY","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tokenX","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalFeeXCharged","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalFeeYCharged","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"userEarnX","outputs":[{"internalType":"uint256","name":"lastAccEarn","type":"uint256"},{"internalType":"uint128","name":"sellingRemain","type":"uint128"},{"internalType":"uint128","name":"sellingDec","type":"uint128"},{"internalType":"uint128","name":"earn","type":"uint128"},{"internalType":"uint128","name":"legacyEarn","type":"uint128"},{"internalType":"uint128","name":"earnAssign","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"userEarnY","outputs":[{"internalType":"uint256","name":"lastAccEarn","type":"uint256"},{"internalType":"uint128","name":"sellingRemain","type":"uint128"},{"internalType":"uint128","name":"sellingDec","type":"uint128"},{"internalType":"uint128","name":"earn","type":"uint128"},{"internalType":"uint128","name":"legacyEarn","type":"uint128"},{"internalType":"uint128","name":"earnAssign","type":"uint128"}],"stateMutability":"view","type":"function"}]
Deployed Bytecode
0x0004000000000002000900000000000200000000030100190000006003300270000006a60430019700030000004103550002000000010355000006a60030019d000100000000001f00000001012001900000000c0000c13d1a9103d20000040f0000008001000039000000400010043f0000000001000416000000000110004c000000660000c13d000006a701000041000000800010043f0000000001000414000000000d0004110000000402d0008c000000400000613d0000008003000039000000c00500003900000000020d0019000000000403001900090000000d001d1a9103360000040f000000090d000029000000000110004c000000400000c13d0000000302000367000000400100043d00000001040000310000001f0340018f00000005044002720000002f0000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b000000270000413d000000000530004c0000003e0000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000311a9103c90000040f0000000103000031000000c00130008c000000c00100003900000000010340190000001f01100039000001e00210018f0000008001200039000000400010043f000000c00330008c000000660000413d000000800b00043d000006a803b0009c000000660000213d000000a00a00043d000006a803a0009c000000660000213d000000c00c00043d000006a903c0009c000000660000213d000000e00700043d000006aa03700198000006ab030000410000000003006019000006ac04700197000000000343019f000000000337004b000000660000c13d000001000900043d000006aa03900198000006ab030000410000000003006019000006ac04900197000000000343019f000000000339004b000000660000c13d000001200800043d000006a90380009c000000690000a13d000000000100001900000000020000191a9103c90000040f0000000003ab004b000001d90000813d000006af03000041000000000490004c00000000040000190000000004034019000006af05900197000000000650004c000000000300a019000006af0550009c000000000304c019000000000330004c000001e60000c13d000000000390004c000001e60000613d000006b001000041000000000201041a000006b1022001970000000003000410000000000232019f000000000021041b0000000102000039000000000102041a000006b1011001970000000001d1019f000100000002001d000000000012041b000006b201000041000000400300043d000000000013043500000000010004140000000402d0008c000000a10000613d0000000404000039000000200600003900000000020d0019000800000003001d0000000805000029000700000007001d000600000008001d000500000009001d00040000000a001d00030000000b001d00020000000c001d00090000000d001d1a9102ff0000040f0000000803000029000000090d000029000000020c000029000000030b000029000000040a000029000000050900002900000006080000290000000707000029000000000110004c000000200000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600420018f0000000002340019000000000442004b00000000050000190000000105004039000006b30420009c000002c90000213d0000000104500190000002c90000c13d000000400020043f000000200110008c000000660000413d0000000001030433000006a80210009c000000660000213d000006b402000041000000000302041a000006b103300197000000000113019f000000000012041b000006b501000041000000400200043d000800000002001d000000000012043500000000010004140000000402d0008c000000d70000613d0000000404000039000000200600003900000000020d001900000008030000290000000005030019000700000007001d000600000008001d000500000009001d00040000000a001d00030000000b001d00020000000c001d00090000000d001d1a9102ff0000040f000000090d000029000000020c000029000000030b000029000000040a000029000000050900002900000006080000290000000707000029000000000110004c000000200000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600320018f00000008020000290000000002230019000000000332004b00000000030000190000000103004039000006b30420009c000002c90000213d0000000103300190000002c90000c13d000000400020043f000000200110008c000000660000413d00000008010000290000000001010433000006a80210009c000000660000213d000006b602000041000000000302041a000006b103300197000000000113019f000000000012041b000006b701000041000000400200043d000800000002001d000000000012043500000000010004140000000402d0008c0000010f0000613d0000000404000039000000200600003900000000020d001900000008030000290000000005030019000700000007001d000600000008001d000500000009001d00040000000a001d00030000000b001d00020000000c001d00090000000d001d1a9102ff0000040f000000090d000029000000020c000029000000030b000029000000040a000029000000050900002900000006080000290000000707000029000000000110004c000000200000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600320018f00000008020000290000000002230019000000000332004b00000000030000190000000103004039000006b30420009c000002c90000213d0000000103300190000002c90000c13d000000400020043f000000200110008c000000660000413d00000008010000290000000001010433000006a80210009c000000660000213d000006b802000041000000000302041a000006b103300197000000000113019f000000000012041b000006b901000041000000400200043d000800000002001d000000000012043500000000010004140000000402d0008c000001470000613d0000000404000039000000200600003900000000020d001900000008030000290000000005030019000700000007001d000600000008001d000500000009001d00040000000a001d00030000000b001d00020000000c001d00090000000d001d1a9102ff0000040f000000090d000029000000020c000029000000030b000029000000040a000029000000050900002900000006080000290000000707000029000000000110004c000000200000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600320018f00000008020000290000000002230019000000000332004b00000000030000190000000103004039000006b30420009c000002c90000213d0000000103300190000002c90000c13d000000400020043f000000200110008c000000660000413d00000008010000290000000001010433000006a80210009c000000660000213d000006ba02000041000000000302041a000006b103300197000000000113019f000000000012041b000006bb01000041000000400200043d000900000002001d000000000012043500000000010004140000000402d0008c0000017d0000613d0000000404000039000000200600003900000000020d001900000009030000290000000005030019000700000007001d000600000008001d000500000009001d00040000000a001d00030000000b001d00020000000c001d1a9102ff0000040f000000020c000029000000030b000029000000040a000029000000050900002900000006080000290000000707000029000000000110004c000000200000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600320018f00000009020000290000000002230019000000000332004b00000000030000190000000103004039000006b30420009c000002c90000213d0000000103300190000002c90000c13d000000400020043f000000200110008c000000660000413d00000009010000290000000001010433000900000001001d000006a80110009c000000660000213d000600000008001d000700000007001d0000000202000039000000000102041a000006b1011001970000000001b1019f000006bc03000041000000000303041a000800000003001d000000000012041b000000a001c00210000006bd011001970000000001a1019f000000b803900210000006be03300197000000000131019f0000000303000039000000000403041a000006bf04400197000000000141019f000000000013041b000000000b090019000006c031900129000006c104300041000006aa01400198000006ab010000410000000001006019000006ac05400197000000000651019f000006c0010000410000000001310049000006a9034001970000001804100210000006c2044001970000000007610049000000000500041a000006ab08700041000006c30880009c000001d20000a13d000006aa08700198000006ab080000410000000008006019000006ac07700197000000000778019f000006af8770012c000006af09000041000000000a89004900000000080ac019000006afbab0012c0000000007a7013f0000000009b9004900000000090b601900000000989800d9000000ff077002120000000009870049000000000779019f0000000007086019000000000980004c0000000007086019000006a907700197000006a90870009c000001f30000c13d000006ec0100004100000000001004350000001101000039000000040010043f000000240200003900000000010000191a9103c90000040f000006ad030000410000000000310435000000c403200039000006ae040000410000000000430435000000a4032000390000000304000039000000000043043500000084022000390000002003000039000000000032043500000064020000391a9103c90000040f000006ad030000410000000000310435000000c403200039000006ed040000410000000000430435000000a4032000390000000304000039000000000043043500000084022000390000002003000039000000000032043500000064020000391a9103c90000040f000006af08000041000000070a00002900000000096a004b00000000090000190000000009088019000006af06600197000006af0aa00197000000000b6a004b000000000800801900000000066a013f000006af0660009c00000000060900190000000006086019000006c405500197000000000335019f000000000343019f0000000104700039000006c5544001290000003004400210000000000343019f000000000030041b000000000360004c000002170000c13d000000400100043d0000004403100039000006eb04000041000000000043043500000024031000390000000000230435000006ad02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391a9103c90000040f000006af030000410000000705000029000000000415004b0000000004000019000000000403a019000006af01100197000006af05500197000000000615004b000000000300a019000000000115013f000006af0110009c00000000010400190000000001036019000000000110004c000002330000c13d000000400100043d0000004403100039000006ea04000041000000000043043500000024031000390000000000230435000006ad02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391a9103c90000040f000006af010000410000000705000029000000000250004c00000000020000190000000002014019000006af03500197000000000430004c000000000100a019000006af0330009c000000000102c0190000000702000039000500000002001d000000000202041a000400000002001d000000000110004c0000000001050019000002490000613d0000000701000029000006af0110009c000001d20000613d00000007010000290000000001100049000006c60210009c000002590000a13d000000400100043d0000004402100039000006e9030000410000000000320435000000240210003900000001030000290000000000320435000006ad02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391a9103c90000040f0000000102100190000006c702000041000006c8030000410000000002036019000006c9432000d100000080033002700000000204100190000000000203c019000006ca432000d1000000800330027000000004041001900000000003026019000006af020000410000000705000029000000000450004c00000000040000190000000004022019000006af05500197000000000650004c0000000002008019000006af0550009c000000000204c019000006cb543000d100000080044002700000000805100190000000000304c019000006cc543000d100000080044002700000001005100190000000000304c019000006cd543000d100000080044002700000002005100190000000000304c019000006ce543000d100000080044002700000004005100190000000000304c019000006cf543000d100000080044002700000008005100190000000000304c019000006d0543000d100000080044002700000010005100190000000000304c019000006d1543000d100000080044002700000020005100190000000000304c019000006d2543000d100000080044002700000040005100190000000000304c019000006d3543000d100000080044002700000080005100190000000000304c019000006d4543000d100000080044002700000100005100190000000000304c019000006d5543000d100000080044002700000200005100190000000000304c019000006d6543000d100000080044002700000400005100190000000000304c019000006d7543000d100000080044002700000800005100190000000000304c019000006d8543000d10000008004400270000006d905100198000000000304c019000006da543000d10000008004400270000006db05100198000000000304c019000006dc543000d10000008004400270000006dd05100198000000000304c019000006de01100198000006df413000d100000080011002700000000001036019000300000001001d000000000120004c000002ba0000613d000000010100008a000000030200002900000000122100d9000300000002001d0000000801000039000000000001041b0000000601000039000000000201041a000006b102200197000006e0022001c7000000000021041b000006e10100004100000000001004391a9103b00000040f000000400200043d000006e20320009c00000007040000290000000605000029000002d00000a13d000006ec0100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191a9103c90000040f0000006003200039000000400030043f000000400320003900000001060000290000000000630435000006a6011001970000000000120435000000200220003900000000000204350000001002000039000000000302041a000006e303300197000000000131019f000006e4011001c7000000000012041b0000000401000029000006e501100197000000a002400210000006bd02200197000000000112019f00000003030000290000002002300270000006a6033001980000000003000019000000010300c0390000000002320019000006a802200197000000000121019f000006e6011001c70000000502000029000000000012041b000000a001500210000006bd011001970000000902000029000000000112019f0000000802000029000006e702200197000000000121019f000006bc02000041000000000012041b00000020010000390000010000100443000001200000044300000100010000390000004002000039000006e8030000411a9103bf0000040f0002000000000002000200000006001d000100000005001d000006a605000041000006a60630009c00000000030580190000004003300210000006a60640009c00000000040580190000006004400210000000000334019f000006a60410009c0000000001058019000000c001100210000000000113019f1a911a820000040f000000010900002900000000030100190000006003300270000006a6033001970000000205000029000000000453004b00000000050340190000001f0450018f0000000505500272000003220000613d000000000600001900000005076002100000000008790019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b0000031a0000413d000000010220018f000000000640004c000003320000613d0000000505500210000000000651034f00000000055900190000000304400210000000000705043300000000074701cf000000000747022f000000000606043b0000010004400089000000000646022f00000000044601cf000000000474019f0000000000450435000100000003001f00030000000103550000000001020019000000000001042d0002000000000002000200000005001d000100000004001d000006a604000041000006a60530009c0000000003048019000006a60510009c0000000001048019000000c0011002100000004003300210000000000113019f000006ee011001c71a911a870000040f000000010900002900000000030100190000006003300270000006a6033001970000000205000029000000000453004b00000000050340190000001f0450018f0000000505500272000003560000613d000000000600001900000005076002100000000008790019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b0000034e0000413d000000010220018f000000000640004c000003660000613d0000000505500210000000000651034f00000000055900190000000304400210000000000705043300000000074701cf000000000747022f000000000606043b0000010004400089000000000646022f00000000044601cf000000000474019f0000000000450435000100000003001f00030000000103550000000001020019000000000001042d0002000000000002000200000006001d000100000005001d000006a605000041000006a60630009c00000000030580190000004003300210000006a60640009c00000000040580190000006004400210000000000334019f000006a60410009c0000000001058019000000c001100210000000000113019f1a911a8c0000040f000000010900002900000000030100190000006003300270000006a6033001970000000205000029000000000453004b00000000050340190000001f0450018f00000005055002720000038d0000613d000000000600001900000005076002100000000008790019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000003850000413d000000010220018f000000000640004c0000039d0000613d0000000505500210000000000651034f00000000055900190000000304400210000000000705043300000000074701cf000000000747022f000000000606043b0000010004400089000000000646022f00000000044601cf000000000474019f0000000000450435000100000003001f00030000000103550000000001020019000000000001042d000006a6010000410000000002000414000006a60320009c0000000001024019000000c001100210000006ef011001c700008010020000391a911a870000040f0000000102200190000003ad0000613d000000000101043b000000000001042d000000000100001900000000020000191a9103c90000040f000006a6010000410000000002000414000006a60320009c0000000001024019000000c001100210000006f0011001c70000800b020000391a911a870000040f0000000102200190000003bc0000613d000000000101043b000000000001042d000000000100001900000000020000191a9103c90000040f000006a604000041000006a60510009c000000000104801900000040011002100000000001310019000006a60320009c00000000020480190000006002200210000000000121001900001a920001042e000006a603000041000006a60420009c0000000002038019000006a60410009c000000000103801900000040011002100000006002200210000000000112019f00001a9300010430000d0000000000020000008001000039000b00000001001d000000400010043f0000000001000031000000040110008c00000f7f0000413d0000000201000367000000000101043b000000e001100270000006f10210009c000004850000613d000006f20210009c0000049e0000613d000006f30210009c00000e4c0000613d000006f40210009c00000e690000613d000006f50210009c000004ef0000613d000006f60210009c00000e820000613d000006f70210009c00000e9a0000613d000006f80210009c000005330000613d000006f90210009c000005840000613d000006fa0210009c0000059c0000613d000006fb0210009c000006420000613d000006fc0210009c000006cf0000613d000006fd0210009c00000ec50000613d000006fe0210009c000007250000613d000006ff0210009c00000ee10000613d000007000210009c000007700000613d000007010210009c0000078e0000613d000007020210009c000007df0000613d000007030210009c000008350000613d000007040210009c00000ef90000613d000007050210009c00000f6e0000613d000007060210009c000008520000613d000007070210009c0000090d0000613d000007080210009c0000094f0000613d000007090210009c000009690000613d0000070a0210009c000009ba0000613d0000070b0210009c00000a240000613d0000070c0210009c00000a5a0000613d0000070d0210009c00000a930000613d0000070e0210009c00000ab80000613d0000070f0210009c00000b190000613d000007100210009c00000b390000613d000007110210009c00000c0a0000613d000007120210009c00000c740000613d000007130210009c00000c8d0000613d000007140210009c00000cc70000613d000007150210009c00000ce00000613d000007160210009c00000d3a0000613d000007170210009c00000d570000613d000007180210009c00000d710000613d000007190210009c00000d890000613d0000071a0210009c00000db00000613d0000071b0210009c00000dfb0000613d0000071c0110009c00000f7f0000c13d0000000001000416000000000110004c00000f7f0000c13d00000000010000311a9113d50000040f000d00000001001d000c00000002001d000b00000003001d000a00000004001d000900000005001d000006b001000041000000000101041a000006a8011001970000000002000410000000000112004b00000f7f0000c13d0000000701000039000800000001001d000000000101041a000700000001001d0000071d01100198000000000100001900000001010060391a9114f50000040f00000007010000290000071e011001970000071f011001c70000000802000029000000000012041b000006ba01000041000000000101041a000700000001001d0000072001000041000000400300043d000600000003001d0000002002300039000500000002001d000000000012043500000024013000390000000d020000290000000c030000290000000b040000290000000a0500002900000009060000291a9115f00000040f00000006050000290000000001510049000000200210008a00000000002504350000001f01100039000000200200008a000000000321016f0000000701000029000006a8021001970000000001530019000000000331004b00000000030000190000000103004039000006b30410009c000011d90000213d0000000103300190000011d90000c13d000000400010043f0000000001000414000000040320008c00000000030000190000047f0000613d00000000040504330000000503000029000000000500001900000000060000191a91036a0000040f000000000110004c00000000030000190000000103006039000b00000003001d1a9115060000040f0000000b02000029000000010220019000000f930000613d1a9115a10000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000000310004c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d0000000601000039000000000101041a000006a802100197000000400100043d0000000000210435000000200200003900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d00000000010000311a9113d50000040f000d00000001001d000c00000002001d000b00000003001d000a00000004001d000900000005001d000006b001000041000000000101041a000006a8011001970000000002000410000000000112004b00000f7f0000c13d0000000701000039000800000001001d000000000101041a000700000001001d0000071d01100198000000000100001900000001010060391a9114f50000040f00000007010000290000071e011001970000071f011001c70000000802000029000000000012041b000006ba01000041000000000101041a000700000001001d0000075001000041000000400300043d000600000003001d0000002002300039000500000002001d000000000012043500000024013000390000000d020000290000000c030000290000000b040000290000000a0500002900000009060000291a9115f00000040f00000006050000290000000001510049000000200210008a00000000002504350000001f01100039000000200200008a000000000321016f0000000701000029000006a8021001970000000001530019000000000331004b00000000030000190000000103004039000006b30410009c000011d90000213d0000000103300190000011d90000c13d000000400010043f0000000001000414000000040320008c0000000003000019000004e90000613d00000000040504330000000503000029000000000500001900000000060000191a91036a0000040f000000000110004c00000000030000190000000103006039000b00000003001d1a9115060000040f0000000b02000029000000010220019000000fce0000613d1a9115a10000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000200310008c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d00000004010000390000000201100367000000000101043b000d00000001001d0000ffff0110008c00000f7f0000213d000006b001000041000000000101041a000006a8011001970000000002000410000000000112004b00000f7f0000c13d0000000d010000290000ffff0110018f000c00000001001d0000000701000039000b00000001001d000000000101041a000a00000001001d0000071d01100198000000000100001900000001010060391a9114f50000040f0000000a030000290000071e013001970000071f011001c70000000b020000290000000004020019000000000012041b000000d8013002700000ffff0110018f0000000c020000290000000005020019000000000212004b000012ce0000a13d000000000210004c000011e70000c13d000000400100043d00000044021000390000074f030000410000000000320435000000240210003900000003030000390000000000320435000006ad02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391a9103c90000040f0000000001000416000000000110004c00000f7f0000c13d00000000010000311a91142e0000040f000d00000001001d000c00000002001d000b00000003001d000a00000004001d000900000005001d000006b001000041000000000101041a000006a8011001970000000002000410000000000112004b00000f7f0000c13d0000000701000039000800000001001d000000000101041a000700000001001d0000071d01100198000000000100001900000001010060391a9114f50000040f00000007010000290000071e011001970000071f011001c70000000802000029000000000012041b000006b601000041000000000101041a000700000001001d0000074701000041000000400300043d000600000003001d0000002002300039000500000002001d000000000012043500000024013000390000000d020000290000000c030000290000000b040000290000000a0500002900000009060000291a9116460000040f00000006050000290000000001510049000000200210008a00000000002504350000001f01100039000000200200008a000000000321016f0000000701000029000006a8021001970000000001530019000000000331004b00000000030000190000000103004039000006b30410009c000011d90000213d0000000103300190000011d90000c13d000000400010043f0000000001000414000000040320008c00000000030000190000057e0000613d00000000040504330000000503000029000000000500001900000000060000191a91036a0000040f000000000110004c00000000030000190000000103006039000d00000003001d1a9115060000040f0000000d020000290000000102200190000010080000613d1a9115a10000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000000310004c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d0000072e01000041000000000201041a000000400100043d0000000000210435000000200200003900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d0000000001000031000d00000001001d000000040110008a000006af02000041000000a00310008c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d0000000201000367000c0000000103530000000401100370000000000101043b000b00000001001d000006a80110009c00000f7f0000213d1a91138f0000040f000900000001001d1a91139d0000040f000800000001001d0000000c0100035f0000006401100370000000000101043b000a00000001001d000006c50110009c00000f7f0000213d0000000c0100035f0000008401100370000000000101043b000006b30210009c00000f7f0000213d00000004011000390000000d020000291a9113b90000040f000c00000001001d000d00000002001d000006b001000041000000000101041a000006a8011001970000000002000410000000000112004b00000f7f0000c13d0000000701000039000700000001001d000000000101041a000600000001001d0000071d01100198000000000100001900000001010060391a9114f50000040f00000006010000290000071e011001970000071f011001c70000000702000029000000000012041b000006b801000041000000000201041a000000a001000039000000400400043d000000a403400039000000000013043500000084014000390000000a03000029000000000031043500000745010000410000002003400039000000000013043500000024014000390000000b0500002900000000005104350000000808000029000006aa01800198000006ab01000041000000000501001900000000050060190000000907000029000006aa067001980000000001006019000006ac06700197000000000b61019f000006ac01800197000000000c15019f000000c4014000390000000d0d0000290000000000d1043500000064014000390000000000c1043500000044014000390000000000b104350000001f05d0018f000000e401400039000006a8022001970000000c0600002900000002066003670000000507d002720000060e0000613d00000000080000190000000509800210000000000a910019000000000996034f000000000909043b00000000009a04350000000108800039000000000978004b000006060000413d000000000850004c0000061d0000613d0000000507700210000000000676034f00000000077100190000000305500210000000000807043300000000085801cf000000000858022f000000000606043b0000010005500089000000000656022f00000000055601cf000000000585019f00000000005704350000000001d1001900000000000104350000001f01d00039000000200500008a000000000151016f000000c40610003900000000006404350000010301100039000000000151016f0000000001140019000000000541004b00000000050000190000000105004039000006b30610009c000011d90000213d0000000105500190000011d90000c13d00090000000c001d000c0000000b001d000000400010043f0000000001000414000000040520008c000d00000000001d0000063d0000613d0000000004040433000000000500001900000000060000191a91036a0000040f000000000110004c00000000010000190000000101006039000d00000001001d1a9115060000040f0000000d0200002900000001022001900000130f0000613d1a9115a10000040f0000000001000416000000000110004c00000f7f0000c13d0000000002000031000000040120008a000006af03000041000000800410008c00000000040000190000000004034019000006af01100197000000000510004c000000000300a019000006af0110009c00000000010400190000000001036019000000000110004c00000f7f0000c13d00000002010003670000000403100370000000000303043b000d00000003001d000006a80330009c00000f7f0000213d0000006401100370000000000101043b000006b30310009c00000f7f0000213d00000004011000391a9113b90000040f000a00000001001d000c00000002001d000006b001000041000000000101041a000006a8011001970000000002000410000000000112004b00000f7f0000c13d0000000701000039000900000001001d000000000101041a000800000001001d0000071d01100198000000000100001900000001010060391a9114f50000040f00000008010000290000071e011001970000071f011001c70000000902000029000000000012041b000006bc01000041000000000201041a0000074301000041000000400400043d0000002003400039000000000013043500000024014000390000000d05000029000000000051043500000024010000390000000201100367000000000101043b0000004405400039000000000015043500000044010000390000000201100367000000000101043b00000084054000390000000b06000029000000000065043500000064054000390000000000150435000000a4014000390000000c0b0000290000000000b104350000001f05b0018f000000c401400039000006a8022001970000000a0600002900000002066003670000000507b002720000069d0000613d00000000080000190000000509800210000000000a910019000000000996034f000000000909043b00000000009a04350000000108800039000000000978004b000006950000413d000000000850004c000006ac0000613d0000000507700210000000000676034f00000000077100190000000305500210000000000807043300000000085801cf000000000858022f000000000606043b0000010005500089000000000656022f00000000055601cf000000000585019f00000000005704350000000001b1001900000000000104350000001f01b00039000000200500008a000000000151016f000000a4061000390000000000640435000000e301100039000000000151016f0000000001140019000000000541004b00000000050000190000000105004039000006b30610009c000011d90000213d0000000105500190000011d90000c13d000000400010043f0000000001000414000000040520008c000c00000000001d000006ca0000613d0000000004040433000000000500001900000000060000191a91036a0000040f000000000110004c00000000010000190000000101006039000c00000001001d1a9115060000040f0000000c020000290000000102200190000012d60000613d1a9115a10000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000400310008c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d1a9113ab0000040f000d00000001001d00000024010000390000000201100367000000000101043b000c00000001001d000006c50110009c00000f7f0000213d000006b001000041000000000101041a000006a8011001970000000002000410000000000112004b00000f7f0000c13d0000000701000039000b00000001001d000000000101041a000a00000001001d0000071d01100198000000000100001900000001010060391a9114f50000040f0000000a010000290000071e011001970000071f011001c70000000b02000029000000000012041b000006ba01000041000000000101041a000000400400043d00000044024000390000000c0300002900000000003204350000074202000041000000200340003900000000002304350000000d06000029000006aa02600198000006ab02000041000000000200601900000044050000390000000000540435000006ac05600197000000000552019f00000024024000390000000000520435000006a8021001970000073e0140009c000011d90000213d000c00000005001d0000008001400039000000400010043f0000000001000414000000040520008c00000000050000190000071f0000613d0000000004040433000000000500001900000000060000191a91036a0000040f000000000110004c00000000050000190000000105006039000d00000005001d1a9115060000040f0000000d020000290000000102200190000011f00000613d1a9115a10000040f0000000001000416000000000110004c00000f7f0000c13d00000000010000311a9114610000040f000d00000001001d000c00000002001d000b00000003001d000006b001000041000000000101041a000006a8011001970000000002000410000000000112004b00000f7f0000c13d0000000701000039000a00000001001d000000000101041a000900000001001d0000071d01100198000000000100001900000001010060391a9114f50000040f00000009010000290000071e011001970000071f011001c70000000a02000029000000000012041b000006ba01000041000000000101041a0000000b02000029000000000220004c0000000002000019000000010200c039000000400400043d000000640340003900000000002304350000000c02000029000006c502200197000000440340003900000000002304350000074102000041000000200340003900000000002304350000000d05000029000006aa02500198000006ab020000410000000002006019000006ac05500197000000000252019f0000002405400039000000000025043500000064020000390000000000240435000006a802100197000007270140009c000011d90000213d000000a001400039000000400010043f0000000001000414000000040520008c00000000050000190000076a0000613d0000000004040433000000000500001900000000060000191a91036a0000040f000000000110004c00000000050000190000000105006039000d00000005001d1a9115060000040f0000000d020000290000000102200190000010460000613d1a9115a10000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000000310004c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d0000000301000039000000000101041a0000072f02100198000006ab020000410000000002006019000000b801100270000006ac01100197000000000212019f000000400100043d0000000000210435000000200200003900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d00000000010000311a91142e0000040f000d00000001001d000c00000002001d000b00000003001d000a00000004001d000900000005001d000006b001000041000000000101041a000006a8011001970000000002000410000000000112004b00000f7f0000c13d0000000701000039000800000001001d000000000101041a000700000001001d0000071d01100198000000000100001900000001010060391a9114f50000040f00000007010000290000071e011001970000071f011001c70000000802000029000000000012041b000006b401000041000000000101041a000700000001001d0000074001000041000000400300043d000600000003001d0000002002300039000500000002001d000000000012043500000024013000390000000d020000290000000c030000290000000b040000290000000a0500002900000009060000291a9116460000040f00000006050000290000000001510049000000200210008a00000000002504350000001f01100039000000200200008a000000000321016f0000000701000029000006a8021001970000000001530019000000000331004b00000000030000190000000103004039000006b30410009c000011d90000213d0000000103300190000011d90000c13d000000400010043f0000000001000414000000040320008c0000000003000019000007d90000613d00000000040504330000000503000029000000000500001900000000060000191a91036a0000040f000000000110004c00000000030000190000000103006039000d00000003001d1a9115060000040f0000000d020000290000000102200190000010600000613d1a9115a10000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000400310008c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d1a9113ab0000040f000d00000001001d00000024010000390000000201100367000000000101043b000c00000001001d000006c50110009c00000f7f0000213d000006b001000041000000000101041a000006a8011001970000000002000410000000000112004b00000f7f0000c13d0000000701000039000b00000001001d000000000101041a000a00000001001d0000071d01100198000000000100001900000001010060391a9114f50000040f0000000a010000290000071e011001970000071f011001c70000000b02000029000000000012041b000006ba01000041000000000101041a000000400400043d00000044024000390000000c0300002900000000003204350000073d02000041000000200340003900000000002304350000000d06000029000006aa02600198000006ab02000041000000000200601900000044050000390000000000540435000006ac05600197000000000552019f00000024024000390000000000520435000006a8021001970000073e0140009c000011d90000213d000c00000005001d0000008001400039000000400010043f0000000001000414000000040520008c00000000050000190000082f0000613d0000000004040433000000000500001900000000060000191a91036a0000040f000000000110004c00000000050000190000000105006039000d00000005001d1a9115060000040f0000000d020000290000000102200190000012220000613d1a9115a10000040f0000000001000416000000000110004c00000f7f0000c13d00000000010000311a9114080000040f00000000001004350000000e01000039000000200010043f1a9103a10000040f0000000302100039000000000702041a0000000202100039000000000602041a000000000201041a0000000101100039000000000401041a000000400100043d000d00000001001d000006c5034001970000008004400270000006c5056001970000008006600270000006c5077001971a91141c0000040f0000000d030000290000000002310049000000000103001900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000400310008c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d1a9113ab0000040f000a00000001001d000006aa02100198000006ab02000041000d00000002001d00000000030200190000000003006019000006ac02100197000000000123019f000b00000001001d1a91138f0000040f0000000002010019000c00000002001d000006aa012001980000000d010000290000000001006019000006ac02200197000000000221019f000300000002001d000006af05000041000900000005001d0000000b03000029000000000123004b00000000010000190000000001054019000006af04300197000700000004001d000006af03200197000800000003001d000000000234004b00000000020000190000000002052019000000000334013f000006af0330009c0000000001026019000000000110004c0000000001000019000000010100c0391a91184b0000040f000000000200041a000600000002001d000006aa012001980000000d010000290000000001006019000006ac02200197000000000121019f0000000b02000029000000000212004b000000090400002900000000020000190000000002048019000006af011001970000000705000029000000000315004b00000000030000190000000003044019000000000115013f000006af0110009c00000000010200190000000001036019000000000110004c0000000001000019000000010100c0391a91185c0000040f000000060200002900000729012001980000000d0100002900000000010060190000001802200270000006ac02200197000000000121019f0000000302000029000000000212004b00000009050000290000000002000019000000000205a019000006af011001970000000804000029000000000314004b00000000030000190000000003052019000000000114013f000006af0110009c00000000010200190000000001036019000000000110004c0000000001000019000000010100c0391a91186d0000040f0000000301000039000000000101041a0000072f021001980000000d020000290000000002006019000000b801100270000006ac01100197000000000212019f000400000002001d0000000a010000291a91187e0000040f000006aa021001980000000d020000290000000002006019000006ac0110019700000000011201a0000000000100001900000001010060391a91189e0000040f0000000c0100002900000004020000291a91187e0000040f000006aa021001980000000d020000290000000002006019000006ac0110019700000000011201a0000000000100001900000001010060391a9118af0000040f0000000c010000290000000a020000291a9118c00000040f00000004020000291a9118d60000040f000006aa021001980000000d020000290000000002006019000006ac01100197000000000212019f000006b30120009c000011d90000213d00000005012002100000003f03100039000000200400008a000000000343016f000000400600043d0000000003360019000000000463004b00000000040000190000000104004039000006b30530009c0000000005060019000011d90000213d0000000104400190000011d90000c13d000000400030043f000000000405001900000000030000190000000000240435000000000213004b000011640000813d000000400200043d000007390420009c000011d90000213d000000c004200039000000400040043f000000a004200039000000000004043500000080042000390000000000040435000000600420003900000000000404350000004004200039000000000004043500000020042000390000000000040435000000000002043500000020033000390000000004530019000008f70000013d0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000200310008c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d1a9113ab0000040f000006aa02100198000006ab020000410000000002006019000006ac01100197000000000112019f00000000001004350000000b01000039000000200010043f1a9103a10000040f0000000302100039000000000202041a0000000203100039000000000303041a000000000401041a0000000101100039000000000501041a000000400100043d0000004006100039000000000056043500000060051000390000000000350435000000ff022001900000000002000019000000010200c03900000080031000390000000000230435000000010200008a000006af03400197000006af0330009c000000000200c01900000080022002100000008003400270000000000223019f0000000b03000029000000000330004c00000000020460190000073003000041000007310520019800000000030060190000073202200197000000000223019f00000020031000390000000000230435000006c5024001970000000000210435000000a00200003900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000000310004c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d000006bc01000041000000000101041a000000a001100270000006a902100197000000400100043d0000000000210435000000200200003900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d00000000010000311a91142e0000040f000d00000001001d000c00000002001d000b00000003001d000a00000004001d000900000005001d000006b001000041000000000101041a000006a8011001970000000002000410000000000112004b00000f7f0000c13d0000000701000039000800000001001d000000000101041a000700000001001d0000071d01100198000000000100001900000001010060391a9114f50000040f00000007010000290000071e011001970000071f011001c70000000802000029000000000012041b000006b401000041000000000101041a000700000001001d0000073801000041000000400300043d000600000003001d0000002002300039000500000002001d000000000012043500000024013000390000000d020000290000000c030000290000000b040000290000000a0500002900000009060000291a9116460000040f00000006050000290000000001510049000000200210008a00000000002504350000001f01100039000000200200008a000000000321016f0000000701000029000006a8021001970000000001530019000000000331004b00000000030000190000000103004039000006b30410009c000011d90000213d0000000103300190000011d90000c13d000000400010043f0000000001000414000000040320008c0000000003000019000009b40000613d00000000040504330000000503000029000000000500001900000000060000191a91036a0000040f000000000110004c00000000030000190000000103006039000d00000003001d1a9115060000040f0000000d0200002900000001022001900000109f0000613d1a9115a10000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000a00310008c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d00000004010000390000000201100367000000000101043b000d00000001001d000006a80110009c00000f7f0000213d1a91138f0000040f000c00000001001d1a91139d0000040f000b00000001001d000006b001000041000000000101041a000006a8011001970000000002000410000000000112004b00000f7f0000c13d0000000701000039000a00000001001d000000000101041a000900000001001d0000071d01100198000000000100001900000001010060391a9114f50000040f00000009010000290000071e011001970000071f011001c70000000a02000029000000000012041b000006b801000041000000000101041a0000073502000041000000400400043d0000002003400039000000000023043500000002020003670000006405200370000000000505043b0000008402200370000000000202043b000000a40640003900000000002604350000008402400039000000000052043500000024024000390000000d0500002900000000005204350000000c06000029000006aa02600198000006ab0200004100000000050200190000000005006019000006ac06600197000000000665019f0000000b07000029000006aa057001980000000002006019000006ac05700197000000000552019f0000006402400039000000000052043500000044024000390000000000620435000000a4020000390000000000240435000006a802100197000007360140009c000011d90000213d000900000005001d000b00000006001d000000e001400039000000400010043f0000000001000414000000040520008c000000000500001900000a1e0000613d0000000004040433000000000500001900000000060000191a91036a0000040f000000000110004c00000000050000190000000105006039000c00000005001d1a9115060000040f0000000c020000290000000102200190000012530000613d1a9115a10000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000200310008c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d1a9113ab0000040f000006aa02100198000006ab020000410000000002006019000006ac01100197000000000112019f00000000001004350000000d01000039000000200010043f1a9103a10000040f0000000602100039000000000b02041a0000000502100039000000000a02041a0000000202100039000000000502041a0000000102100039000000000402041a0000000402100039000000000902041a0000000302100039000000000702041a000000000301041a000000400100043d000d00000001001d000006c5023001970000008003300270000006c5067001970000008007700270000006c50890019700000080099002701a9114b00000040f0000000d030000290000000002310049000000000103001900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d0000000003000031000000040130008a000006af02000041000000200410008c00000000040000190000000004024019000006af01100197000000000510004c000000000200a019000006af0110009c00000000010400190000000001026019000000000110004c00000f7f0000c13d00000002020003670000000401200370000000000101043b000006b30410009c00000f7f0000213d0000002304100039000006af05000041000000000634004b00000000060000190000000006058019000006af07300197000006af04400197000000000874004b0000000005008019000000000474013f000006af0440009c00000000040600190000000004056019000000000440004c00000f7f0000c13d0000000404100039000000000242034f000000000202043b000006b30420009c00000f7f0000213d000000240110003900000005042002100000000004140019000000000334004b00000f7f0000213d1a91167b0000040f0000000002010019000000400100043d000d00000001001d1a9114cb0000040f0000000d030000290000000002310049000000000103001900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000200310008c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d00000004010000390000000201100367000000000101043b0000800002100190000080000200008a000000000200601900007fff0310018f000000000232019f000000000221004b00000f7f0000c13d00000000001004350000000a01000039000000200010043f1a9103a10000040f000000000201041a000000400100043d0000000000210435000000200200003900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000600310008c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d1a9113ab0000040f000c00000001001d1a91138f0000040f000b00000001001d00000044010000390000000201100367000000000101043b000d00000001001d000006c50110009c00000f7f0000213d000006b001000041000000000101041a000006a8011001970000000002000410000000000112004b00000f7f0000c13d0000000701000039000a00000001001d000000000101041a000900000001001d0000071d01100198000000000100001900000001010060391a9114f50000040f00000009010000290000071e011001970000071f011001c70000000a02000029000000000012041b000006b801000041000000000101041a000000400400043d00000064024000390000000d0300002900000000003204350000073302000041000000200340003900000000002304350000000c06000029000006aa02600198000006ab0200004100000000050200190000000005006019000006ac06600197000000000665019f0000000b07000029000006aa057001980000000002006019000006ac05700197000000000552019f000000640200003900000000002404350000004402400039000000000052043500000024024000390000000000620435000006a802100197000007270140009c000011d90000213d000900000005001d000b00000006001d000000a001400039000000400010043f0000000001000414000000040520008c000000000500001900000b130000613d0000000004040433000000000500001900000000060000191a91036a0000040f000000000110004c00000000050000190000000105006039000c00000005001d1a9115060000040f0000000c0200002900000001022001900000128d0000613d1a9115a10000040f0000000001000416000000000110004c00000f7f0000c13d00000000010000311a9114080000040f00000000001004350000000901000039000000200010043f1a9103a10000040f0000000402100039000000000202041a0000000303100039000000000303041a0000000204100039000000000404041a000000000501041a0000000101100039000000000601041a000000400100043d00000020071000390000000000670435000000400610003900000000004604350000006004100039000000000034043500000080031000390000000000230435000006c5025001970000000000210435000000a00200003900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000400310008c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d1a9113ab0000040f000c00000001001d000006aa02100198000006ab02000041000d00000002001d00000000030200190000000003006019000006ac02100197000000000123019f000900000001001d1a91138f0000040f0000000002010019000800000002001d000006aa012001980000000d010000290000000001006019000006ac02200197000000000221019f000a00000002001d000006af05000041000700000005001d0000000903000029000000000123004b00000000010000190000000001054019000006af04300197000500000004001d000006af03200197000600000003001d000000000234004b00000000020000190000000002052019000000000334013f000006af0330009c0000000001026019000000000110004c0000000001000019000000010100c0391a91184b0000040f000000000200041a000400000002001d000006aa012001980000000d010000290000000001006019000006ac02200197000000000121019f0000000902000029000000000212004b000000070400002900000000020000190000000002048019000006af011001970000000505000029000000000315004b00000000030000190000000003044019000000000115013f000006af0110009c00000000010200190000000001036019000000000110004c0000000001000019000000010100c0391a91185c0000040f000000040200002900000729012001980000000d0100002900000000010060190000001802200270000006ac02200197000000000121019f0000000a02000029000000000212004b00000007050000290000000002000019000000000205a019000006af011001970000000604000029000000000314004b00000000030000190000000003052019000000000114013f000006af0110009c00000000010200190000000001036019000000000110004c0000000001000019000000010100c0391a91186d0000040f0000000301000039000000000101041a0000072f021001980000000d020000290000000002006019000000b801100270000006ac01100197000000000212019f000900000002001d0000000c010000291a91187e0000040f000006aa021001980000000d020000290000000002006019000006ac0110019700000000011201a0000000000100001900000001010060391a91189e0000040f000000080100002900000009020000291a91187e0000040f000006aa021001980000000d020000290000000002006019000006ac0110019700000000011201a0000000000100001900000001010060391a9118af0000040f00000008010000290000000c020000291a9118c00000040f00000009020000291a9118d60000040f000006aa021001980000000d020000290000000002006019000006ac01100197000000000112019f1a91190a0000040f0000000c07000029000800000001001d0000002001100039000700000001001d0000000008000019000006aa01700198000006ab010000410000000001006019000006ac02700197000000000121019f000006af020000410000000a04000029000000000341004b00000000030000190000000003024019000006af04400197000006af05100197000000000645004b000000000200a019000000000445013f000006af0440009c000000000203c019000000000220004c00000f8a0000613d00000008020000290000000002020433000000000282004b000011e00000a13d00000000001004350000000b01000039000000200010043f000c00000007001d000d00000008001d1a9103a10000040f000000000101041a000000010200008a000006af03100197000006af0330009c000000000200c01900000080022002100000008003100270000000000223019f0000000b03000029000000000330004c000000000102c0190000000d020000290000000502200210000000070300002900000000022300190000073003000041000007310410019800000000030060190000073201100197000000000113019f00000000001204350000000c0100002900000009020000291a9119420000040f0000000d080000290000000108800039000000000701001900000bd10000013d0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000000310004c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d000006b001000041000000000101041a000006a8011001970000000002000410000000000112004b00000f7f0000c13d0000000701000039000d00000001001d000000000101041a000c00000001001d0000071d01100198000000000100001900000001010060391a9114f50000040f0000000c010000290000071e011001970000071f011001c70000000d02000029000000000012041b0000000101000039000000000201041a000000400300043d0000072d0100004100000000001304350000000001000414000006a802200197000000040420008c00000c3e0000613d00000020050000390000000004030019000c00000003001d1a9103360000040f0000000c03000029000000000110004c00000d1a0000613d0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600420018f0000000002340019000000000442004b00000000050000190000000105004039000006b30420009c000011d90000213d0000000104500190000011d90000c13d000000400020043f000000200110008c00000f7f0000413d0000000001030433000006a80210009c00000f7f0000213d0000000002000411000c00000002001d000000000112004b000000000100001900000001010060391a9119580000040f0000000201000039000000000101041a0000072802000041000b00000002001d000000000302041a000006a8011001970000000c020000291a911a2f0000040f0000000301000039000000000101041a0000072e02000041000a00000002001d000000000302041a000006a8011001970000000c020000291a911a2f0000040f0000000b01000029000000000001041b0000000a01000029000000000001041b0000000d02000029000000000102041a0000071e01100197000000000012041b0000000001000019000000000200001900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000000310004c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d0000000301000039000000000101041a000006a802100197000000400100043d0000000000210435000000200200003900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000000310004c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d0000000701000039000000000201041a0000000801000039000000000301041a000000400100043d000000e00410003900000080053002700000000000540435000006c503300197000000c00410003900000000003404350000071d032001980000000003000019000000010300c039000000a0041000390000000000340435000000d8032002700000ffff0330018f00000080041000390000000000340435000000c8032002700000ffff0330018f00000060041000390000000000340435000000b8032002700000ffff0330018f000000400410003900000000003404350000072c03200198000006ab030000410000000003006019000000a004200270000006ac04400197000000000343019f00000020041000390000000000340435000006a8022001970000000000210435000001000200003900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000000310004c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d0000000101000039000000000101041a000006a802100197000000400100043d0000000000210435000000200200003900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000200310008c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d00000004010000390000000201100367000000000101043b000d00000001001d000006a90110009c00000f7f0000213d000006b001000041000000000101041a000006a8011001970000000002000410000000000112004b00000f7f0000c13d0000000701000039000c00000001001d000000000101041a000b00000001001d0000071d01100198000000000100001900000001010060391a9114f50000040f0000000b010000290000071e011001970000071f011001c70000000c02000029000000000012041b0000000101000039000000000201041a000000400300043d0000072a0100004100000000001304350000000001000414000006a802200197000000040420008c000011360000613d00000020050000390000000004030019000b00000003001d1a9103360000040f0000000b03000029000000000110004c000011360000c13d0000000302000367000000400100043d00000001040000310000001f0340018f000000050440027200000d290000613d000000000500001900000005065002100000000007610019000000000662034f000000000606043b00000000006704350000000105500039000000000645004b00000d210000413d000000000530004c00000d380000613d0000000504400210000000000242034f00000000044100190000000303300210000000000504043300000000053501cf000000000535022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000252019f000000000024043500000001020000311a9103c90000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000000310004c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d000000000100041a0000072902100198000006ab0200004100000000020060190000001801100270000006ac01100197000000000212019f000000400100043d0000000000210435000000200200003900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000000310004c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d0000000301000039000000000101041a000000a001100270000006a902100197000000400100043d0000000000210435000000200200003900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000000310004c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d0000072801000041000000000201041a000000400100043d0000000000210435000000200200003900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000200310008c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d1a9113ab0000040f000006aa02100198000006ab02000041000d00000002001d0000000002006019000006ac01100197000000000112019f00000000001004350000000c01000039000000200010043f1a9103a10000040f000000000101041a000006aa021001980000000d020000290000000002006019000006ac01100197000000000212019f000000400100043d0000000000210435000000200200003900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d00000000010000311a9114610000040f000d00000001001d000c00000002001d000b00000003001d000006b001000041000000000101041a000006a8011001970000000002000410000000000112004b00000f7f0000c13d0000000701000039000a00000001001d000000000101041a000900000001001d0000071d01100198000000000100001900000001010060391a9114f50000040f00000009010000290000071e011001970000071f011001c70000000a02000029000000000012041b000006ba01000041000000000101041a0000000b02000029000000000220004c0000000002000019000000010200c039000000400400043d000000640340003900000000002304350000000c02000029000006c502200197000000440340003900000000002304350000072602000041000000200340003900000000002304350000000d05000029000006aa02500198000006ab020000410000000002006019000006ac05500197000000000252019f0000002405400039000000000025043500000064020000390000000000240435000006a802100197000007270140009c000011d90000213d000000a001400039000000400010043f0000000001000414000000040520008c000000000500001900000df50000613d0000000004040433000000000500001900000000060000191a91036a0000040f000000000110004c00000000050000190000000105006039000d00000005001d1a9115060000040f0000000d020000290000000102200190000010de0000613d1a9115a10000040f0000000001000416000000000110004c00000f7f0000c13d00000000010000311a91142e0000040f000d00000001001d000c00000002001d000b00000003001d000a00000004001d000900000005001d000006b001000041000000000101041a000006a8011001970000000002000410000000000112004b00000f7f0000c13d0000000701000039000800000001001d000000000101041a000700000001001d0000071d01100198000000000100001900000001010060391a9114f50000040f00000007010000290000071e011001970000071f011001c70000000802000029000000000012041b000006b601000041000000000101041a000700000001001d0000072301000041000000400300043d000600000003001d0000002002300039000500000002001d000000000012043500000024013000390000000d020000290000000c030000290000000b040000290000000a0500002900000009060000291a9116460000040f00000006050000290000000001510049000000200210008a00000000002504350000001f01100039000000200200008a000000000321016f0000000701000029000006a8021001970000000001530019000000000331004b00000000030000190000000103004039000006b30410009c000011d90000213d0000000103300190000011d90000c13d000000400010043f0000000001000414000000040320008c000000000300001900000e460000613d00000000040504330000000503000029000000000500001900000000060000191a91036a0000040f000000000110004c00000000030000190000000103006039000d00000003001d1a9115060000040f0000000d020000290000000102200190000010f80000613d1a9115a10000040f0000000001000416000000000110004c00000f7f0000c13d00000000010000311a9114080000040f00000000001004350000000f01000039000000200010043f1a9103a10000040f0000000302100039000000000702041a0000000202100039000000000602041a000000000201041a0000000101100039000000000401041a000000400100043d000d00000001001d000006c5034001970000008004400270000006c5056001970000008006600270000006c5077001971a91141c0000040f0000000d030000290000000002310049000000000103001900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000000310004c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d0000000201000039000000000101041a000006a802100197000000400100043d0000000000210435000000200200003900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000000310004c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d0000000401000039000000000201041a000000400100043d0000000000210435000000200200003900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000200310008c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d00000004010000390000000201100367000000000101043b0000fffe0210008c00000f7f0000213d0000001001100039000000000201041a00000748012001980000000003000019000000010300c039000000400100043d0000004004100039000000000034043500000749032001980000074a03000041000000000300601900000020042002700000074b04400197000000000343019f00000020041000390000000000340435000006a6022001970000000000210435000000600200003900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000000310004c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d000000000100041a000006aa02100198000006ab020000410000000002006019000006ac01100197000000000212019f000000400100043d0000000000210435000000200200003900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000000310004c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d0000000501000039000000000201041a000000400100043d0000000000210435000000200200003900000000030000191a9103bf0000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000a00310008c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f7f0000c13d0000000201000367000d0000000103530000000401100370000000000101043b000c00000001001d000006a80110009c00000f7f0000213d1a91138f0000040f000b00000001001d0000000d0100035f0000004401100370000000000101043b000a00000001001d000006c50110009c00000f7f0000213d0000000d0100035f0000006401100370000000000101043b000900000001001d000006c50110009c00000f7f0000213d0000000d0100035f0000008401100370000000000201043b000000000120004c0000000001000019000000010100c039000d00000002001d000000000112004b00000f7f0000c13d000006b001000041000000000101041a000006a8011001970000000002000410000000000112004b00000f7f0000c13d0000000701000039000800000001001d000000000101041a000700000001001d0000071d01100198000000000100001900000001010060391a9114f50000040f00000007010000290000071e011001970000071f011001c70000000802000029000000000012041b000006ba01000041000000000101041a000000400400043d000000a4024000390000000d03000029000000000032043500000084024000390000000903000029000000000032043500000064024000390000000a0300002900000000003204350000073a020000410000002003400039000000000023043500000024024000390000000c0500002900000000005204350000000b06000029000006aa02600198000006ab020000410000000002006019000000a4050000390000000000540435000006ac05600197000000000552019f0000004402400039000a00000005001d0000000000520435000006a802100197000007360140009c000011d90000213d000000e001400039000000400010043f0000000001000414000000040520008c000b00000000001d00000f690000613d0000000004040433000000000500001900000000060000191a91036a0000040f000000000110004c00000000010000190000000101006039000b00000001001d1a9115060000040f0000000b0200002900000001022001900000134d0000613d1a9115a10000040f0000000001000416000000000110004c00000f7f0000c13d000000040100008a0000000001100031000006af02000041000000000310004c00000000030000190000000003024019000006af01100197000000000410004c000000000200a019000006af0110009c00000000010300190000000001026019000000000110004c00000f820000613d000000000100001900000000020000191a9103c90000040f000000000100041a0000003001100270000006c502100197000000400100043d0000000000210435000000200200003900000000030000191a9103bf0000040f000000400100043d000d00000001001d00000008020000291a9114e00000040f0000000d030000290000000002310049000000000103001900000000030000191a9103bf0000040f00000020031000390000000001010433000000000231001900000000010300191a9116250000040f000006c503300197000000400500043d00000040065000390000000000360435000006c50340019700000060045000390000000000340435000000800350003900000001040000390000000000430435000006c5032001970000002002500039000b00000003001d0000000000320435000006c501100197000a00000001001d0000000000150435000006a6010000410000000002000414000006a60320009c0000000002018019000006a60350009c00000000010540190000000c04000029000006aa03400198000006ab030000410000000003006019000006ac04400197000000000643019f0000004001100210000000c002200210000000000112019f0000000d02000029000006a80520019700000721011001c70000800d02000039000000030300003900000722040000411a911a820000040f000000010120019000000f7f0000613d0000000802000029000000000102041a0000071e01100197000000000012041b000000400100043d00000020021000390000000b0300002900000000003204350000000a020000290000000000210435000000400200003900000000030000191a9103bf0000040f00000020031000390000000001010433000000000231001900000000010300191a9116250000040f000006c503300197000000400500043d00000040065000390000000000360435000006c50340019700000060045000390000000000340435000006c5032001970000002002500039000b00000003001d000000000032043500000080025000390000000000020435000006c501100197000a00000001001d0000000000150435000006a6010000410000000002000414000006a60320009c0000000002018019000006a60350009c00000000010540190000000c04000029000006aa03400198000006ab030000410000000003006019000006ac04400197000000000643019f0000004001100210000000c002200210000000000112019f0000000d02000029000006a80520019700000721011001c70000800d02000039000000030300003900000722040000411a911a820000040f000000010120019000000f7f0000613d0000000802000029000000000102041a0000071e01100197000000000012041b000000400100043d00000020021000390000000b0300002900000000003204350000000a020000290000000000210435000000400200003900000000030000191a9103bf0000040f0000000002010433000006af03000041000000400420008c00000000040000190000000004034019000006af02200197000000000520004c000000000300a019000006af0220009c00000000020400190000000002036019000000000220004c00000f7f0000c13d0000000302000039000000000202041a0000000203000039000000000303041a0000002004100039000000000504043300000040011000390000000006010433000000400100043d0000004004100039000c00000006001d00000000006404350000002004100039000d00000005001d00000000005404350000000000010435000006a6040000410000000005000414000006a60650009c0000000005048019000006a60610009c00000000010480190000004001100210000000c004500210000000000114019f00000724011001c7000006a805300197000006a806200197000000a002200270000006a9072001970000800d02000039000000040300003900000725040000411a911a820000040f000000010120019000000f7f0000613d0000000802000029000000000102041a0000071e01100197000000000012041b000000400100043d00000020021000390000000c0300002900000000003204350000000d020000290000000000210435000000400200003900000000030000191a9103bf0000040f0000000002010433000006af03000041000000200420008c00000000040000190000000004034019000006af02200197000000000520004c000000000300a019000006af0220009c00000000020400190000000002036019000000000220004c00000f7f0000c13d00000020011000390000000002010433000006c50120009c00000f7f0000213d0000000a03000029000000000103041a0000071e01100197000000000013041b000000400100043d0000000000210435000000200200003900000000030000191a9103bf0000040f0000000002010433000006af03000041000000400420008c00000000040000190000000004034019000006af02200197000000000520004c000000000300a019000006af0220009c00000000020400190000000002036019000000000220004c00000f7f0000c13d0000000302000039000000000202041a0000000203000039000000000303041a0000002004100039000000000504043300000040011000390000000006010433000000400100043d0000004004100039000c00000006001d00000000006404350000002004100039000d00000005001d000000000054043500000001040000390000000000410435000006a6040000410000000005000414000006a60650009c0000000005048019000006a60610009c00000000010480190000004001100210000000c004500210000000000114019f00000724011001c7000006a805300197000006a806200197000000a002200270000006a9072001970000800d02000039000000040300003900000725040000411a911a820000040f000000010120019000000f7f0000613d0000000802000029000000000102041a0000071e01100197000000000012041b000000400100043d00000020021000390000000c0300002900000000003204350000000d020000290000000000210435000000400200003900000000030000191a9103bf0000040f0000000002010433000006af03000041000000400420008c00000000040000190000000004034019000006af02200197000000000520004c000000000300a019000006af0220009c00000000020400190000000002036019000000000220004c00000f7f0000c13d0000000302000039000000000202041a0000000203000039000000000303041a0000002004100039000000000504043300000040011000390000000006010433000000400100043d0000004004100039000c00000006001d00000000006404350000002004100039000d00000005001d000000000054043500000001040000390000000000410435000006a6040000410000000005000414000006a60650009c0000000005048019000006a60610009c00000000010480190000004001100210000000c004500210000000000114019f00000724011001c7000006a805300197000006a806200197000000a002200270000006a9072001970000800d02000039000000040300003900000725040000411a911a820000040f000000010120019000000f7f0000613d0000000802000029000000000102041a0000071e01100197000000000012041b000000400100043d00000020021000390000000c0300002900000000003204350000000d020000290000000000210435000000400200003900000000030000191a9103bf0000040f0000000002010433000006af03000041000000200420008c00000000040000190000000004034019000006af02200197000000000520004c000000000300a019000006af0220009c00000000020400190000000002036019000000000220004c00000f7f0000c13d00000020011000390000000002010433000006c50120009c00000f7f0000213d0000000a03000029000000000103041a0000071e01100197000000000013041b000000400100043d0000000000210435000000200200003900000000030000191a9103bf0000040f0000000002010433000006af03000041000000400420008c00000000040000190000000004034019000006af02200197000000000520004c000000000300a019000006af0220009c00000000020400190000000002036019000000000220004c00000f7f0000c13d0000000302000039000000000202041a0000000203000039000000000303041a0000002004100039000000000504043300000040011000390000000006010433000000400100043d0000004004100039000c00000006001d00000000006404350000002004100039000d00000005001d00000000005404350000000000010435000006a6040000410000000005000414000006a60650009c0000000005048019000006a60610009c00000000010480190000004001100210000000c004500210000000000114019f00000724011001c7000006a805300197000006a806200197000000a002200270000006a9072001970000800d02000039000000040300003900000725040000411a911a820000040f000000010120019000000f7f0000613d0000000802000029000000000102041a0000071e01100197000000000012041b000000400100043d00000020021000390000000c0300002900000000003204350000000d020000290000000000210435000000400200003900000000030000191a9103bf0000040f0000000101000031000000200210008c000000200200003900000000020140190000001f02200039000000600420018f0000000002340019000000000442004b00000000050000190000000105004039000006b30420009c000011d90000213d0000000104500190000011d90000c13d000000400020043f000000200110008c00000f7f0000413d0000000001030433000006a80210009c00000f7f0000213d0000000002000411000000000112004b000000000100001900000001010060391a9119690000040f0000000d01000029000000650110008c000000000100001900000001010040391a91197a0000040f0000000d01000029000000a001100210000006bd01100197000006bc02000041000000000302041a0000072b03300197000000000113019f000000000012041b0000000c02000029000000000102041a0000071e01100197000000000012041b0000000001000019000000000200001900000000030000191a9103bf0000040f000200000005001d0000002001500039000100000001001d000b00000000001d0000000a01000029000006aa02100198000006ab0200004100000000030200190000000003006019000a00000001001d000006ac02100197000000000623019f000006af010000410000000303000029000000000236004b00000000020000190000000002014019000006af03300197000006af04600197000000000534004b000000000100a019000000000334013f000006af0330009c000000000102c019000000000110004c000013060000613d00000000006004350000000d01000039000d00000001001d000000200010043f000c00000006001d1a9103a10000040f000000000101041a000900000001001d0000000c0100002900000000001004350000000d01000029000000200010043f1a9103a10000040f000000000101041a000800000001001d0000000c0100002900000000001004350000000d01000029000000200010043f1a9103a10000040f0000000101100039000000000101041a000700000001001d0000000c0100002900000000001004350000000d01000029000000200010043f1a9103a10000040f0000000301100039000000000101041a000600000001001d0000000c0100002900000000001004350000000d01000029000000200010043f1a9103a10000040f0000000401100039000000000101041a000500000001001d0000000c0100002900000000001004350000000d01000029000000200010043f1a9103a10000040f000000400200043d000007390320009c0000000204000029000011d90000213d0000000501100039000000000101041a000000c003200039000000400030043f000000a00320003900000000001304350000000501000029000006c50110019700000080032000390000000000130435000000060100002900000080011002700000006003200039000000000013043500000040012000390000000703000029000000000031043500000008010000290000008001100270000000200320003900000000001304350000000901000029000006c501100197000000000012043500000000010404330000000b05000029000000000151004b000011e00000a13d00000005015002100000000103000029000000000113001900000000002104350000000001040433000000000151004b000011e00000a13d0000000a010000290000000402000029000b00000005001d1a9119420000040f0000000b020000290000000102200039000b00000002001d000011690000013d000006ec0100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191a9103c90000040f000006ec0100004100000000001004350000003201000039000000040010043f000000240200003900000000010000191a9103c90000040f000000000251004b000012c70000813d0000001002100039000000000302041a0000074e0330019700000001033001bf000000000032041b0000000101100039000011e70000013d00000020031000390000000001010433000000000231001900000000010300191a9115d10000040f000d00000002001d000006c502300197000000400300043d00000020053000390000000000250435000006c50240019700000040043000390000000000240435000000600230003900000001040000390000000000420435000006c501100197000a00000001001d0000000000130435000006a6010000410000000002000414000006a60420009c0000000002018019000006a60430009c00000000010340190000004001100210000000c002200210000000000112019f0000073b011001c70000800d0200003900000003030000390000073f0400004100000000050004110000000c060000291a911a820000040f000000010120019000000f7f0000613d0000000b02000029000000000102041a0000071e01100197000000000012041b000000400100043d00000020021000390000000d0300002900000000003204350000000a020000290000000000210435000000400200003900000000030000191a9103bf0000040f00000020031000390000000001010433000000000231001900000000010300191a9115d10000040f000d00000002001d000006c502300197000000400300043d00000020053000390000000000250435000006c5024001970000004004300039000000000024043500000060023000390000000000020435000006c501100197000a00000001001d0000000000130435000006a6010000410000000002000414000006a60420009c0000000002018019000006a60430009c00000000010340190000004001100210000000c002200210000000000112019f0000073b011001c70000800d0200003900000003030000390000073f0400004100000000050004110000000c060000291a911a820000040f000000010120019000000f7f0000613d0000000b02000029000000000102041a0000071e01100197000000000012041b000000400100043d00000020021000390000000d0300002900000000003204350000000a020000290000000000210435000000400200003900000000030000191a9103bf0000040f0000000002010433000006af03000041000000400420008c00000000040000190000000004034019000006af02200197000000000520004c000000000300a019000006af0220009c00000000020400190000000002036019000000000220004c00000f7f0000c13d0000002002100039000000000302043300000040011000390000000004010433000000400100043d0000004002100039000800000004001d00000000004204350000002002100039000c00000003001d00000000003204350000000d020000290000000000210435000006a6020000410000000003000414000006a60430009c0000000003028019000006a60410009c00000000010280190000004001100210000000c002300210000000000112019f00000724011001c70000800d020000390000000403000039000007370400004100000000050004110000000b0600002900000009070000291a911a820000040f000000010120019000000f7f0000613d0000000a02000029000000000102041a0000071e01100197000000000012041b000000400100043d0000002002100039000000080300002900000000003204350000000c020000290000000000210435000000400200003900000000030000191a9103bf0000040f0000000002010433000006af03000041000000400420008c00000000040000190000000004034019000006af02200197000000000520004c000000000300a019000006af0220009c00000000020400190000000002036019000000000220004c00000f7f0000c13d0000002002100039000000000302043300000040011000390000000004010433000000400100043d0000004002100039000800000004001d00000000004204350000002002100039000c00000003001d00000000003204350000000d020000290000000000210435000006a6020000410000000003000414000006a60430009c0000000003028019000006a60410009c00000000010280190000004001100210000000c002300210000000000112019f00000724011001c70000800d020000390000000403000039000007340400004100000000050004110000000b0600002900000009070000291a911a820000040f000000010120019000000f7f0000613d0000000a02000029000000000102041a0000071e01100197000000000012041b000000400100043d0000002002100039000000080300002900000000003204350000000c020000290000000000210435000000400200003900000000030000191a9103bf0000040f0000000d01000029000000d8011002100000074c01100197000000000204041a0000074d02200197000000000112019f000000000014041b0000000701000039000000000201041a0000071e02200197000000000021041b0000000001000019000000000200001900000000030000191a9103bf0000040f0000000002010433000006af03000041000000800420008c00000000040000190000000004034019000006af02200197000000000520004c000000000300a019000006af0220009c00000000020400190000000002036019000000000220004c00000f7f0000c13d00000020021000390000000002020433000000400310003900000000030304330000006004100039000000000404043300000080011000390000000001010433000000400500043d0000006006500039000000000016043500000040015000390000000000410435000000200150003900000000003104350000000000250435000006a6010000410000000002000414000006a60320009c0000000002018019000006a60350009c00000000010540190000004001100210000000c002200210000000000112019f0000073b011001c70000800d020000390000000303000039000007440400004100000000050004110000000d060000291a911a820000040f0000000101200190000012ce0000c13d00000f7f0000013d000000400100043d000d00000001001d00000002020000291a9114870000040f0000000d030000290000000002310049000000000103001900000000030000191a9103bf0000040f0000000002010433000006af03000041000000400420008c00000000040000190000000004034019000006af02200197000000000520004c000000000300a019000006af0220009c00000000020400190000000002036019000000000220004c00000f7f0000c13d0000002002100039000000000402043300000040011000390000000005010433000000400100043d00000020021000390000000a0300002900000000003204350000006002100039000a00000005001d00000000005204350000004002100039000d00000004001d00000000004204350000000002000411000006a8022001970000000000210435000006a6020000410000000003000414000006a60430009c0000000003028019000006a60410009c00000000010280190000004001100210000000c002300210000000000112019f0000073b011001c70000800d02000039000000040300003900000746040000410000000b050000290000000c0600002900000009070000291a911a820000040f000000010120019000000f7f0000613d0000000702000029000000000102041a0000071e01100197000000000012041b000000400100043d00000020021000390000000a0300002900000000003204350000000d020000290000000000210435000000400200003900000000030000191a9103bf0000040f0000000002010433000006af03000041000000400420008c00000000040000190000000004034019000006af02200197000000000520004c000000000300a019000006af0220009c00000000020400190000000002036019000000000220004c00000f7f0000c13d00000020021000390000000002020433000b00000002001d000006c50220009c00000f7f0000213d00000040011000390000000001010433000900000001001d000006c50110009c00000f7f0000213d000000400100043d00000060021000390000000d03000029000000000032043500000040021000390000000903000029000000000032043500000020021000390000000b0300002900000000003204350000000c020000290000000000210435000006a6020000410000000003000414000006a60430009c0000000003028019000006a60410009c00000000010280190000004001100210000000c002300210000000000112019f0000073b011001c70000800d0200003900000003030000390000073c0400004100000000050004110000000a060000291a911a820000040f000000010120019000000f7f0000613d0000000802000029000000000102041a0000071e01100197000000000012041b000000400100043d0000002002100039000000090300002900000000003204350000000b020000290000000000210435000000400200003900000000030000191a9103bf0000040f00000024010000390000000201100367000000000101043b000006aa02100198000006ab020000410000000002006019000006ac03100197000000000232019f000000000221004b0000139a0000c13d000000000001042d000000000100001900000000020000191a9103c90000040f00000044010000390000000201100367000000000101043b000006aa02100198000006ab020000410000000002006019000006ac03100197000000000232019f000000000221004b000013a80000c13d000000000001042d000000000100001900000000020000191a9103c90000040f00000004010000390000000201100367000000000101043b000006aa02100198000006ab020000410000000002006019000006ac03100197000000000232019f000000000221004b000013b60000c13d000000000001042d000000000100001900000000020000191a9103c90000040f0000001f03100039000006af04000041000000000523004b00000000050000190000000005044019000006af06200197000006af03300197000000000763004b000000000400a019000000000363013f000006af0330009c00000000030500190000000003046019000000000330004c000013d20000613d0000000203100367000000000303043b000006b30430009c000013d20000213d00000020011000390000000004310019000000000224004b000013d20000213d0000000002030019000000000001042d000000000100001900000000020000191a9103c90000040f00030000000000020000000002010019000000040120008a000006af030000410000007f0410008c00000000040000190000000004032019000006af01100197000000000510004c0000000003008019000006af0110009c00000000010400190000000001036019000000000110004c000014050000613d00000002010003670000000403100370000000000303043b000300000003001d000006a80330009c000014050000213d0000002403100370000000000503043b000006aa03500198000006ab030000410000000003006019000006ac04500197000000000343019f000200000005001d000000000335004b000014050000c13d0000004403100370000000000303043b000100000003001d000006c50330009c000014050000213d0000006401100370000000000101043b000006b30310009c000014050000213d00000004011000391a9113b90000040f00000000040100190000000005020019000000030100002900000002020000290000000103000029000000000001042d000000000100001900000000020000191a9103c90000040f000000040110008a000006af020000410000001f0310008c00000000030000190000000003022019000006af01100197000000000410004c0000000002008019000006af0110009c00000000010300190000000001026019000000000110004c000014190000613d00000004010000390000000201100367000000000101043b000000000001042d000000000100001900000000020000191a9103c90000040f000006c507700197000000a0081000390000000000780435000006c50660019700000080071000390000000000670435000006c50550019700000060061000390000000000560435000006c50440019700000040051000390000000000450435000006c503300197000000200410003900000000003404350000000000210435000000c001100039000000000001042d00030000000000020000000002010019000000040120008a000006af030000410000007f0410008c00000000040000190000000004032019000006af01100197000000000510004c0000000003008019000006af0110009c00000000010400190000000001036019000000000110004c0000145e0000613d00000002010003670000000403100370000000000303043b000300000003001d000006a80330009c0000145e0000213d0000002403100370000000000303043b000200000003001d000006c50330009c0000145e0000213d0000004403100370000000000503043b000006aa03500198000006ab030000410000000003006019000006ac04500197000000000343019f000100000005001d000000000335004b0000145e0000c13d0000006401100370000000000101043b000006b30310009c0000145e0000213d00000004011000391a9113b90000040f00000000040100190000000005020019000000030100002900000002020000290000000103000029000000000001042d000000000100001900000000020000191a9103c90000040f000000040110008a000006af020000410000005f0310008c00000000030000190000000003022019000006af01100197000000000410004c0000000002008019000006af0110009c00000000010300190000000001026019000000000110004c000014840000613d00000002030003670000000401300370000000000101043b000006aa02100198000006ab020000410000000002006019000006ac04100197000000000242019f000000000221004b000014840000c13d0000002402300370000000000202043b000006c50420009c000014840000213d0000004403300370000000000303043b000000000430004c0000000004000019000000010400c039000000000443004b000014840000c13d000000000001042d000000000100001900000000020000191a9103c90000040f0000002003000039000000000031043500000000030204330000002004100039000000000034043500000040011000390000000004000019000000000534004b000014af0000813d000000200220003900000000050204330000000006050433000006c506600197000000000061043500000020065000390000000006060433000006c50660019700000020071000390000000000670435000000400650003900000000060604330000004007100039000000000067043500000060065000390000000006060433000006c5066001970000006007100039000000000067043500000080065000390000000006060433000006c50660019700000080071000390000000000670435000000a0055000390000000005050433000000a00610003900000000005604350000000104400039000000c0011000390000148e0000013d000000000001042d000001200c1000390000000000bc0435000001000b1000390000000000ab0435000006c509900197000000e00a10003900000000009a0435000006c508800197000000c0091000390000000000890435000006c507700197000000a0081000390000000000780435000006c506600197000000800710003900000000006704350000006006100039000000000056043500000040051000390000000000450435000006c50330019700000020041000390000000000340435000006c50220019700000000002104350000014001100039000000000001042d0000002003000039000000000031043500000000030204330000002004100039000000000034043500000040011000390000000004000019000000000534004b000014df0000813d0000002002200039000000000502043300000751065001980000074a0600004100000000060060190000074b05500197000000000556019f000000000051043500000001044000390000002001100039000014d20000013d000000000001042d0000002003000039000000000031043500000000030204330000002004100039000000000034043500000040011000390000000004000019000000000534004b000014f40000813d000000200220003900000000050204330000073106500198000007300600004100000000060060190000073205500197000000000556019f000000000051043500000001044000390000002001100039000014e70000013d000000000001042d000000000110004c000014f80000613d000000000001042d000000400100043d000000440210003900000752030000410000000000320435000000240210003900000003030000390000000000320435000006ad02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391a9103c90000040f00000060010000390000000102000032000015370000613d000007530120009c000015380000813d0000003f01200039000000200300008a000000000331016f000000400100043d0000000003310019000000000413004b00000000040000190000000104004039000006b30530009c000015380000213d0000000104400190000015380000c13d000000400030043f00000000002104350000002002100039000000030300036700000001050000310000001f0450018f0000000505500272000015280000613d000000000600001900000005076002100000000008720019000000000773034f000000000707043b00000000007804350000000106600039000000000756004b000015200000413d000000000640004c000015370000613d0000000505500210000000000353034f00000000025200190000000304400210000000000502043300000000054501cf000000000545022f000000000303043b0000010004400089000000000343022f00000000034301cf000000000353019f0000000000320435000000000001042d000006ec0100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191a9103c90000040f0000000003120049000006af040000410000001f0530008c00000000050000190000000005042019000006af03300197000000000630004c0000000004008019000006af0330009c00000000030500190000000003046019000000000330004c000015810000613d0000000003010433000006b30430009c000015810000213d00000000041300190000001f01400039000006af03000041000000000521004b00000000050000190000000005038019000006af01100197000006af06200197000000000761004b0000000003008019000000000161013f000006af0110009c00000000010500190000000001036019000000000110004c000015810000c13d0000000003040433000007530130009c000015840000813d0000003f01300039000000200500008a000000000551016f000000400100043d0000000005510019000000000615004b00000000060000190000000106004039000006b30750009c000015840000213d0000000106600190000015840000c13d000000400050043f000000000031043500000020044000390000000005340019000000000225004b000015810000213d00000020021000390000000005000019000000000635004b0000157e0000813d00000000062500190000000007540019000000000707043300000000007604350000002005500039000015760000013d00000000023200190000000000020435000000000001042d000000000100001900000000020000191a9103c90000040f000006ec0100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191a9103c90000040f0000002003000039000000000031043500000000030204330000002004100039000000000034043500000040011000390000000004000019000000000534004b0000159a0000813d00000000051400190000002004400039000000000624001900000000060604330000000000650435000015920000013d000000000213001900000000000204350000001f02300039000000200300008a000000000232016f0000000001210019000000000001042d00010000000000020000000002010433000000400320008c000015b00000c13d00000020021000390000000002020433000000400300043d00000000002304350000004001100039000000000101043300000020023000390000000000120435000000400200003900000000010300191a9103c90000040f000000440220008c000015c00000813d000000400100043d000000440210003900000754030000410000000000320435000000240210003900000002030000390000000000320435000006ad02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391a9103c90000040f000000240310003900000004011000390000000001010433000000000213001900000000010300191a91153f0000040f000006ad02000041000000400300043d000100000003001d0000000000230435000000000201001900000004013000391a91158b0000040f0000000103000029000000000231004900000000010300191a9103c90000040f0000000002120049000006af030000410000007f0420008c00000000040000190000000004032019000006af02200197000000000520004c0000000003008019000006af0220009c00000000020400190000000002036019000000000220004c000015ed0000613d0000000005010433000006c50250009c000015ed0000213d0000002002100039000000000202043300000040031000390000000003030433000006c50430009c000015ed0000213d00000060011000390000000004010433000006c50140009c000015ed0000213d0000000001050019000000000001042d000000000100001900000000020000191a9103c90000040f000000600710003900000080080000390000000000870435000006c50440019700000040071000390000000000470435000006aa04300198000006ab040000410000000004006019000006ac03300197000000000334019f0000002004100039000000000034043500000080031000390000000000630435000006a80220019700000000002104350000001f0260018f000000a001100039000000020350036700000005046002720000160f0000613d000000000500001900000005075002100000000008710019000000000773034f000000000707043b00000000007804350000000105500039000000000745004b000016070000413d000000000520004c0000161e0000613d0000000504400210000000000343034f00000000044100190000000302200210000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f0000000000240435000000000261001900000000000204350000001f02600039000000200300008a000000000232016f0000000001120019000000000001042d0000000002120049000006af030000410000007f0420008c00000000040000190000000004032019000006af02200197000000000520004c0000000003008019000006af0220009c00000000020400190000000002036019000000000220004c000016430000613d0000000005010433000006c50250009c000016430000213d00000020021000390000000002020433000006c50320009c000016430000213d00000040031000390000000003030433000006c50430009c000016430000213d00000060011000390000000004010433000006c50140009c000016430000213d0000000001050019000000000001042d000000000100001900000000020000191a9103c90000040f000000600710003900000080080000390000000000870435000006c50330019700000020071000390000000000370435000006aa03400198000006ab030000410000000003006019000006ac04400197000000000343019f0000004004100039000000000034043500000080031000390000000000630435000006a80220019700000000002104350000001f0260018f000000a00110003900000002035003670000000504600272000016650000613d000000000500001900000005075002100000000008710019000000000773034f000000000707043b00000000007804350000000105500039000000000745004b0000165d0000413d000000000520004c000016740000613d0000000504400210000000000343034f00000000044100190000000302200210000000000504043300000000052501cf000000000525022f000000000303043b0000010002200089000000000323022f00000000022301cf000000000252019f0000000000240435000000000261001900000000000204350000001f02600039000000200300008a000000000232016f0000000001120019000000000001042d0015000000000002000006b003000041000000000303041a000006a8033001970000000004000410000000000334004b0000181e0000c13d0000000703000039000000000703041a000007530320009c0000182f0000813d00000005032002100000003f04300039000000200500008a000000000454016f000000400500043d0000000004450019000700000005001d000000000554004b00000000050000190000000105004039000006b30640009c0000182f0000213d00000001055001900000182f0000c13d000000400040043f0000000704000029000000000024043500000000021300190000000003000031000000000332004b0000181e0000213d0000000703000029000000000421004b000016a60000813d0000000204100367000000000404043b000007550540009c0000181e0000813d0000002003300039000000000043043500000020011000390000169c0000013d000006e10100004100000000001004390000072c01700198000006ab010000410000000001006019001300000001001d000000a001700270000006ac01100197001200000001001d001500000007001d1a9103b00000040f000300000001001d000006a601100197000e00000001001d0000001501000029000000c8011002700000ffff01100190001400000001001d0000183d0000613d00000013010000290000001202000029000000000121019f000400000001001d000000070100002900000000010104331a91190a0000040f0000001405000029000000010250008a000100000002001d0000001502000029000000b80220027000000001032000390000ffff0220018f000600000002001d0000001002200039000500000002001d000a00000001001d0000ffff0130018f000200000001001d000000000400001900000007020000290000000001020433000000000114004b0000180e0000813d00000005014002100000002001100039000800000001001d00000000012100190000000001010433000006a601100198000900000004001d000017010000613d00000000020100190000000e01000029000d00000002001d0000000001210049000c00000001001d000007550110009c000018100000813d1a9119da0000040f1a9119da0000040f00000006010000290000ffff0110008c000018170000613d00000005010000291a91198b0000040f00000000070100190000000001070433000006a6031001970000000e05000029000000000253004b000017170000213d0000000d02000029000000000225004b000017170000413d0000000c06000029000000000263004b000017210000213d000000000161013f000006a6011001980000000001070019000017ad0000613d00000000010700190000000c020000290000000403000029001300000007001d1a9119ec0000040f00000013070000290000000002070433000006a603200197000017ad0000013d00000006010000290000ffff0110008c000018170000613d00000005010000291a91198b0000040f00000000020104330000000303000029000000000232013f000006a6022001980000170e0000613d0000000e0200002900000004030000291a9119ec0000040f0000002001100039000000000101043300000751021001980000074a0200004100000000020060190000074b01100197000000000112019f0000000904000029000017fe0000013d0000000c0600002900000755026001c70000000d04000029000000000445004b000000000206401900000755043001c7000000000553004b0000000004032019000000000224004b000016f40000a13d0000001401000029000000020200002900000000211200d9000f00000002001d00000010012000391a91198b0000040f00000040021000390000000002020433000000000220004c0000172e0000613d0000000e040000290000000c05000029000017460000013d000000400100043d000006e20210009c0000182f0000213d0000006002100039000000400020043f0000001002000039000000000202041a00000748032001980000000003000019000000010300c0390000004004100039000000000034043500000749032001980000074a03000041000000000300601900000020042002700000074b04400197000000000343019f00000020041000390000000000340435000006a60220019700000000002104350000000e040000290000000c050000290000000001010433000006a601100197000000000241004b000017520000213d0000000d02000029000000000224004b000017520000413d000000000151004b000018210000213d00000755015001c7000b00000001001d0000175c0000013d00000755025001c70000000d03000029000000000334004b000000000502801900000755021001c7000000000341004b000000000102a019000b00000005001d000000000151004b000018210000213d00000001010000290000000f020000290000000001210019001100000001001d1a9119da0000040f1a9119da0000040f0000000f02000029001000000002001d000000110200002900000010010000290000000003120019000000000123004b000000000100001900000001010040390000000101100190000018100000c13d001100000002001d001200000003001d0000000102300270001500000002001d000000140100002900000000211200d900000010012000391a91198b0000040f00000015020000290000000102200039000000000301001900000040013000390000000001010433000000000110004c000017630000613d000f00000002001d000000140100002900000000211200d90000001001200039001300000003001d1a91198b0000040f00000013070000290000000002070433000006a6032001970000000e05000029000000000253004b0000178e0000213d0000000d02000029000000000225004b0000178e0000413d0000000c02000029000000000223004b000017940000213d0000179a0000013d00000755023001c7000000000453004b00000000020320190000000b04000029000000000242004b0000179a0000a13d0000001201000029000000020110008c000018100000413d0000001501000029000000010210008a000017650000013d0000000002010433000006a6022001970000000d04000029000000000445004b000017a60000413d000000000452004b000017a60000213d0000000c04000029000000000224004b0000000f02000029000017630000213d000017ad0000013d00000755042001c7000000000552004b000000000204a0190000000b04000029000000000224004b0000000f02000029000017630000213d0000000c06000029000000000236004b0000002005700039000017b90000c13d000000000105043300000751021001980000074a0200004100000000020060190000074b01100197000000000112019f0000000904000029000017fe0000013d0000000002010433000006a604200197000000000246004b0000002006100039000017c60000c13d000000000106043300000751021001980000074a0200004100000000020060190000074b01100197000000000112019f0000000904000029000017fe0000013d0000000001340049000006a60210009c000018100000213d0000000c020000290000000002320049000006a60720009c000018100000213d000000000606043300000751076001980000074a07000041000000000807001900000000080060190000074b06600197000000000668019f00000000080504330000075105800198000000000507001900000000050060190000075109500198000000000907001900000000090060190000074b07800197000000000879019f00000000068600490000074a08600041000007560880009c000018100000413d000000000334004b000018360000613d000000000375019f001500000003001d00000751036001980000074a0300004100000000030060190000074b04600197000000000343019f000006af4330012c000006af050000410000000006450049000000000406c019000006af6110012c000000000113013f0000000003650049000000000306601900000000433400d9000000ff011002120000000004310049000000000114019f0000000001036019000000000430004c00000000010360191a9119a90000040f000000000201001900000015010000291a9119c40000040f00000009040000290000000a020000290000000002020433000000000242004b000018170000a13d0000000a020000290000000803000029000000000223001900000751031001980000074a0300004100000000030060190000074b01100197000000000113019f000000000012043500000001044000390000001403000029000016ce0000013d0000000a01000029000000000001042d000006ec0100004100000000001004350000001101000039000000040010043f000000240200003900000000010000191a9103c90000040f000006ec0100004100000000001004350000003201000039000000040010043f000000240200003900000000010000191a9103c90000040f000000000100001900000000020000191a9103c90000040f000000400100043d000000440210003900000757030000410000000000320435000000240210003900000003030000390000000000320435000006ad02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391a9103c90000040f000006ec0100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191a9103c90000040f000006ec0100004100000000001004350000001201000039000000040010043f000000240200003900000000010000191a9103c90000040f000000400100043d000000440210003900000758030000410000000000320435000000240210003900000001030000390000000000320435000006ad02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391a9103c90000040f000000000110004c0000184e0000613d000000000001042d000000400100043d000000440210003900000759030000410000000000320435000000240210003900000003030000390000000000320435000006ad02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391a9103c90000040f000000000110004c0000185f0000613d000000000001042d000000400100043d0000004402100039000006eb030000410000000000320435000000240210003900000002030000390000000000320435000006ad02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391a9103c90000040f000000000110004c000018700000613d000000000001042d000000400100043d00000044021000390000075a030000410000000000320435000000240210003900000002030000390000000000320435000006ad02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391a9103c90000040f000006aa03200198000006ab030000410000000003006019000006ac0220019700000000022301a0000018970000613d000006aa03100198000006ab030000410000000003006019000006ac01100197000000000113019f000006af03000041000006af5410012c00000000045300490000000004056019000006af5220012c0000000002530049000000000205601900000000322400d9000006af0110019800000000013000490000000001036019000000000230004c0000000001036019000000000001042d000006ec0100004100000000001004350000001201000039000000040010043f000000240200003900000000010000191a9103c90000040f000000000110004c000018a10000613d000000000001042d000000400100043d00000044021000390000075b030000410000000000320435000000240210003900000003030000390000000000320435000006ad02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391a9103c90000040f000000000110004c000018b20000613d000000000001042d000000400100043d00000044021000390000075c030000410000000000320435000000240210003900000003030000390000000000320435000006ad02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391a9103c90000040f000006aa03200198000006ab0300004100000000040300190000000004006019000006ac02200197000000000224019f000006aa041001980000000003006019000006ac01100197000000000113019f0000000001210049000006ab02100041000006c30220009c000018cf0000a13d000000000001042d000006ec0100004100000000001004350000001101000039000000040010043f000000240200003900000000010000191a9103c90000040f000006aa03100198000006ab0300004100000000040300190000000004006019000006ac01100197000006aa052001980000000003006019000006ac0220019700000000032301a0000018fc0000613d000000000214019f000006ab0120009c000018e60000c13d000000010100008a000000000113004b000019030000613d000006af01000041000006af0420009c000018ec0000c13d000000010400008a000000000443004b000018fb0000613d000006af3130012c000006af040000410000000005340049000000000305c019000006af5220012c000000000112013f0000000002540049000000000205601900000000323200d9000000ff011002120000000003210049000000000113019f0000000001026019000000000320004c0000000001026019000000000001042d000006ec0100004100000000001004350000001201000039000000040010043f000000240200003900000000010000191a9103c90000040f000006ec0100004100000000001004350000001101000039000000040010043f000000240200003900000000010000191a9103c90000040f0000000002010019000007530120009c0000193b0000813d00000005052002100000003f01500039000000200300008a000000000331016f000000400100043d0000000003310019000000000413004b00000000040000190000000104004039000006b30630009c0000193b0000213d00000001044001900000193b0000c13d000000400030043f00000000002104350000001f0250018f00000020031000390000000004000031000000020440036700000005055002720000192b0000613d000000000600001900000005076002100000000008730019000000000774034f000000000707043b00000000007804350000000106600039000000000756004b000019230000413d000000000620004c0000193a0000613d0000000505500210000000000454034f00000000035300190000000302200210000000000503043300000000052501cf000000000525022f000000000404043b0000010002200089000000000424022f00000000022401cf000000000252019f0000000000230435000000000001042d000006ec0100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191a9103c90000040f000006aa03100198000006ab0300004100000000040300190000000004006019000006ac01100197000000000114019f000006aa042001980000000003006019000006ac02200197000000000223019f0000000001120019000006ab02100041000006c30220009c000019510000a13d000000000001042d000006ec0100004100000000001004350000001101000039000000040010043f000000240200003900000000010000191a9103c90000040f000000000110004c0000195b0000613d000000000001042d000000400100043d00000044021000390000075d030000410000000000320435000000240210003900000002030000390000000000320435000006ad02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391a9103c90000040f000000000110004c0000196c0000613d000000000001042d000000400100043d00000044021000390000075e030000410000000000320435000000240210003900000003030000390000000000320435000006ad02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391a9103c90000040f000000000110004c0000197d0000613d000000000001042d000000400100043d00000044021000390000075f030000410000000000320435000000240210003900000003030000390000000000320435000006ad02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391a9103c90000040f0000000002010019000000400100043d000007600310009c000019a20000813d0000006003100039000000400030043f000000000202041a00000748032001980000000003000019000000010300c0390000004004100039000000000034043500000749032001980000074a03000041000000000300601900000020042002700000074b04400197000000000343019f00000020041000390000000000340435000006a6022001970000000000210435000000000001042d000006ec0100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191a9103c90000040f00000751031001980000074a03000041000000000403001900000000040060190000074b01100197000000000114019f0000075104200198000000000403001900000000040060190000074b02200197000000000224019f00000000211200a90000075102100198000000000203001900000000020060190000074b03100197000000000232019f000000000212004b000019bd0000c13d000000000001042d000006ec0100004100000000001004350000001101000039000000040010043f000000240200003900000000010000191a9103c90000040f00000751031001980000074a03000041000000000403001900000000040060190000074b01100197000000000114019f000007510420019800000000030060190000074b02200197000000000223019f00000000011200190000074a02100041000007610220009c000019d30000a13d000000000001042d000006ec0100004100000000001004350000001101000039000000040010043f000000240200003900000000010000191a9103c90000040f000000400100043d000007600210009c000019e50000813d0000006002100039000000400020043f00000040021000390000000000020435000000200210003900000000000204350000000000010435000000000001042d000006ec0100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191a9103c90000040f0003000000000002000100000003001d000300000002001d000200000001001d1a9119da0000040f00000002040000290000000301000029000006a6021001970000000001040433000006a601100197000300000002001d0000000002120049000007550120009c00001a210000813d0000000103000029000006aa01300198000006ab010000410000000001006019000006ac03300197000000000131019f00000020034000390000000003030433000200000003001d1a9119a90000040f000000020300002900000751023001980000074a0200004100000000020060190000074b03300197000000000232019f0000000003010019000000000102001900000000020300191a9119c40000040f0000000002010019000000400100043d000007600310009c00001a280000813d0000006003100039000000400030043f00000040031000390000000104000039000000000043043500000751032001980000074a0300004100000000030060190000074b02200197000000000223019f0000002003100039000000000023043500000003020000290000000000210435000000000001042d000006ec0100004100000000001004350000001101000039000000040010043f000000240200003900000000010000191a9103c90000040f000006ec0100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191a9103c90000040f00010000000000020000000005010019000000400400043d00000044014000390000000000310435000000200340003900000762010000410000000000130435000006a8012001970000002402400039000000000012043500000044010000390000000000140435000007630140009c00001a7b0000813d0000008001400039000000400010043f0000000001000414000000040250008c000000000200001900001a4c0000613d00000000040404330000000002050019000000000500001900000000060000191a9102ff0000040f000000000110004c00000000020000190000000102006039000100000002001d1a9115060000040f0000000102000029000000010220019000001a6a0000c13d0000000002010433000000000320004c00001a690000613d000006af030000410000001f0420008c00000000040000190000000004032019000006af02200197000000000520004c0000000003008019000006af0220009c00000000020400190000000002036019000000000220004c00001a780000613d00000020011000390000000001010433000000000210004c0000000002000019000000010200c039000000000221004b00001a780000c13d000000000110004c00001a6a0000613d000000000001042d000000400100043d000000440210003900000764030000410000000000320435000000240210003900000003030000390000000000320435000006ad02000041000000000021043500000004021000390000002003000039000000000032043500000064020000391a9103c90000040f000000000100001900000000020000191a9103c90000040f000006ec0100004100000000001004350000004101000039000000040010043f000000240200003900000000010000191a9103c90000040f00001a85002104210000000102000039000000000001042d000000000200001900001a840000013d00001a8a002104230000000102000039000000000001042d000000000200001900001a890000013d00001a8f002104250000000102000039000000000001042d000000000200001900001a8e0000013d00001a910000043200001a920001042e00001a9300010430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffcece24fe00000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000ffffff0000000000000000000000000000000000000000000000000000000000800000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000000000000000000000000000000000000000000000000000007fffff08c379a000000000000000000000000000000000000000000000000000000000783c79000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010011ffffffffffffffffffffffff0000000000000000000000000000000000000000254ace8f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff000000000000000000000000000000000000000000000000000000000001001286df77de000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010013400b6cdc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010014476476e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100155deef20a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010016000000000000000000ffffff0000000000000000000000000000000000000000000000000000ffffff0000000000000000000000000000000000000000000000ffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c3500fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3cb000000000000000000000000000000000000000000000000000000ffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000d89e800000000000000000000000000000000fffcb933bd6fad37aa2d162d1a594001000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000fff97272373d413259a46990580e213a00000000000000000000000000000000fff2e50f5f656932ef12357cf3c7fdcc00000000000000000000000000000000ffe5caca7e10e4e61c3624eaa0941cd000000000000000000000000000000000ffcb9843d60f6159c9db58835c92664400000000000000000000000000000000ff973b41fa98c081472e6896dfb254c000000000000000000000000000000000ff2ea16466c96a3843ec78b326b5286100000000000000000000000000000000fe5dee046a99a2a811c461f1969c305300000000000000000000000000000000fcbe86c7900a88aedcffc83b479aa3a400000000000000000000000000000000f987a7253ac413176f2b074cf7815e5400000000000000000000000000000000f3392b0822b70005940c7a398e4b70f300000000000000000000000000000000e7159475a2c29b7443b29c7fa6e889d900000000000000000000000000000000d097f3bdfd2022b8845ad8f792aa582500000000000000000000000000000000a9f746462d870fdf8a65dc1f90e061e50000000000000000000000000000000070d869a156d2a1b890bb3df62baf32f70000000000000000000000000000000031be135f97d08fd981231505542fcfa60000000000000000000000000000000009aa508b5b7a84e1c677de54f3e99bc9000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000005d6af8dedb81196699c329225ee60400000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000002216e584f5fa1ea926041bedfe98000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000048a170391f7dc42444e8fa20000000000000000000000000000000000000001000346d6ff11672ae55ad010796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d95539132000000000000000000000000000000000000000000000000ffffffffffffff9fffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000010000000000000000000000ffffff00000000000000000000000000000000000000000000000000000000000000000001000100000000000000000000000000000000000000000000000000ffffffffffffffffff000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000005400000000000000000000000000000000000000000000000000000000000000484f0000000000000000000000000000000000000000000000000000000000004c4f0000000000000000000000000000000000000000000000000000000000004e487b710000000000000000000000000000000000000000000000000000000070643000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000020000000000000000000000000000000000004000000000000000000000000002000002000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000009beabc1000000000000000000000000000000000000000000000000000000000e1552f0000000000000000000000000000000000000000000000000000000001621835f0000000000000000000000000000000000000000000000000000000016dc165b0000000000000000000000000000000000000000000000000000000017fdacb9000000000000000000000000000000000000000000000000000000001aae2e5500000000000000000000000000000000000000000000000000000000252c09d7000000000000000000000000000000000000000000000000000000002c4812520000000000000000000000000000000000000000000000000000000033005cd5000000000000000000000000000000000000000000000000000000003c8a7d8d00000000000000000000000000000000000000000000000000000000490e6cbc000000000000000000000000000000000000000000000000000000004cd70e9100000000000000000000000000000000000000000000000000000000537c2d8e00000000000000000000000000000000000000000000000000000000544e705700000000000000000000000000000000000000000000000000000000588e59ae0000000000000000000000000000000000000000000000000000000058c51ce60000000000000000000000000000000000000000000000000000000059dd14360000000000000000000000000000000000000000000000000000000062c944ca0000000000000000000000000000000000000000000000000000000062ccaafd000000000000000000000000000000000000000000000000000000006ad1718f000000000000000000000000000000000000000000000000000000006d01843b000000000000000000000000000000000000000000000000000000006f73f0060000000000000000000000000000000000000000000000000000000075c0e0d50000000000000000000000000000000000000000000000000000000081794fba00000000000000000000000000000000000000000000000000000000857f812f00000000000000000000000000000000000000000000000000000000872d1f15000000000000000000000000000000000000000000000000000000008790aca300000000000000000000000000000000000000000000000000000000883bdbfd0000000000000000000000000000000000000000000000000000000098a0f72e00000000000000000000000000000000000000000000000000000000a34123a700000000000000000000000000000000000000000000000000000000b0f5925700000000000000000000000000000000000000000000000000000000b14184e600000000000000000000000000000000000000000000000000000000b74d60a900000000000000000000000000000000000000000000000000000000b7d19fc400000000000000000000000000000000000000000000000000000000c19d93fb00000000000000000000000000000000000000000000000000000000c45a015500000000000000000000000000000000000000000000000000000000d38a85ad00000000000000000000000000000000000000000000000000000000d3b1686400000000000000000000000000000000000000000000000000000000ddca3f4300000000000000000000000000000000000000000000000000000000e556289f00000000000000000000000000000000000000000000000000000000edcba3b200000000000000000000000000000000000000000000000000000000f0163ef400000000000000000000000000000000000000000000000000000000f094685a00000000000000000000000000000000000000000000000000000000ff12504e0000ff0000000000000000000000000000000000000000000000000000000000ffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000010000000000000000000000000000000000000000000000000000000000ff12504e0000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000a00000000000000000000000004f4658280ee6d0e8f09b5e436dacaca69ec5dd7c2ba05fb010d5145a3567cdadf094685a000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000060000000000000000000000000e7779a36a28ae0e49bcbd9fcf57286fb607699c0c339c202e92495640505613ef0163ef400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff5f000000000000000000000000000000000000000000000000000000000001000f00000000000000000000000000000000000000000000000000008000000000008da5cb5b00000000000000000000000000000000000000000000000000000000ffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffff0000000000000000008000000000000000000000000000000000000000000000d8cd50e20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100100000000000008000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000007fffffffffffffffffffffffffffffffa34123a7000000000000000000000000000000000000000000000000000000000c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c872d1f1500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff1ff69135213cd78fa4cffb855edf80272133f69bd8a6fb3236340a69b4d6e248e3857f812f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff3f6ad1718f0000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000800000000000000000000000007d3d0e34c86e56b4dcd993c09bbbf1b04527ab27b4365dffca10e0ded914e07162c944ca00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff7f3736ba81d13006f6ea2012ba3e287f087169b55d90a9defb5966fe9eb830d7ea59dd143600000000000000000000000000000000000000000000000000000000544e7057000000000000000000000000000000000000000000000000000000004cd70e9100000000000000000000000000000000000000000000000000000000490e6cbc00000000000000000000000000000000000000000000000000000000bdbdb71d7860376ba52b25a5028beea23581364a40522f6bcfb86bb1f2dca6333c8a7d8d000000000000000000000000000000000000000000000000000000007a53080ba414158be7ec69b987b5fb7d07dee101fe85488f0853ae16239d0bde2c481252000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff00000000000000000000000000000000000000000000000000000000000000008000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000000000000000000000000000000000000000000000000000007fffffffffffff000000ffff000000000000000000000000000000000000000000000000000000ffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000004c454e00000000000000000000000000000000000000000000000000000000000e1552f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000004c4b440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000064630000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000ffffffffffffffffffffffffffffffffffffffffffffffffff000000000000004f4c44000000000000000000000000000000000000000000000000000000000049000000000000000000000000000000000000000000000000000000000000004c3c520000000000000000000000000000000000000000000000000000000000524f0000000000000000000000000000000000000000000000000000000000004c4430000000000000000000000000000000000000000000000000000000000052443000000000000000000000000000000000000000000000000000000000004e520000000000000000000000000000000000000000000000000000000000004e4f4e00000000000000000000000000000000000000000000000000000000004650300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffa0fffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffa9059cbb00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff80544e530000000000000000000000000000000000000000000000000000000000
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.