More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 281 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Readjust Liquidi... | 8397717 | 285 days ago | IN | 0 ETH | 0.0017159 | ||||
Readjust Liquidi... | 7888849 | 296 days ago | IN | 0 ETH | 0.00249748 | ||||
Withdraw | 6882615 | 316 days ago | IN | 0 ETH | 0.00034881 | ||||
Withdraw | 6770999 | 319 days ago | IN | 0 ETH | 0.00025647 | ||||
Withdraw | 6770818 | 319 days ago | IN | 0 ETH | 0.00023712 | ||||
Withdraw | 6770777 | 319 days ago | IN | 0 ETH | 0.00029206 | ||||
Withdraw | 6770760 | 319 days ago | IN | 0 ETH | 0.00030302 | ||||
Withdraw | 6770746 | 319 days ago | IN | 0 ETH | 0.00029855 | ||||
Withdraw | 6770607 | 319 days ago | IN | 0 ETH | 0.00024891 | ||||
Withdraw | 6770571 | 319 days ago | IN | 0 ETH | 0.00029534 | ||||
Withdraw | 6770171 | 319 days ago | IN | 0 ETH | 0.00027304 | ||||
Withdraw | 6770036 | 319 days ago | IN | 0 ETH | 0.00027976 | ||||
Withdraw | 6696836 | 321 days ago | IN | 0 ETH | 0.00024534 | ||||
Withdraw | 6686903 | 322 days ago | IN | 0 ETH | 0.00019316 | ||||
Withdraw | 6686792 | 322 days ago | IN | 0 ETH | 0.00018852 | ||||
Withdraw | 6686206 | 322 days ago | IN | 0 ETH | 0.00015843 | ||||
Withdraw | 6590602 | 325 days ago | IN | 0 ETH | 0.00027541 | ||||
Withdraw | 6590601 | 325 days ago | IN | 0 ETH | 0.00027541 | ||||
Withdraw | 6590598 | 325 days ago | IN | 0 ETH | 0.00027975 | ||||
Withdraw | 6589218 | 325 days ago | IN | 0 ETH | 0.00029597 | ||||
Deposit | 6434560 | 329 days ago | IN | 0.00335442 ETH | 0.00031987 | ||||
Deposit | 6434532 | 329 days ago | IN | 0.00435299 ETH | 0.00031905 | ||||
Deposit | 6434500 | 329 days ago | IN | 0.00386736 ETH | 0.00036206 | ||||
Deposit | 6432742 | 329 days ago | IN | 0.00469467 ETH | 0.00033245 | ||||
Deposit | 6432647 | 329 days ago | IN | 0.0048779 ETH | 0.00036951 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
6882615 | 316 days ago | 0.0003619 ETH | ||||
6882615 | 316 days ago | 0.0003619 ETH | ||||
6770999 | 319 days ago | 0.00008554 ETH | ||||
6770999 | 319 days ago | 0.00008554 ETH | ||||
6770818 | 319 days ago | 0.00008715 ETH | ||||
6770818 | 319 days ago | 0.00008715 ETH | ||||
6770777 | 319 days ago | 0.00008756 ETH | ||||
6770777 | 319 days ago | 0.00008756 ETH | ||||
6770760 | 319 days ago | 0.00009261 ETH | ||||
6770760 | 319 days ago | 0.00009261 ETH | ||||
6770746 | 319 days ago | 0.00009441 ETH | ||||
6770746 | 319 days ago | 0.00009441 ETH | ||||
6770607 | 319 days ago | 0.00006201 ETH | ||||
6770607 | 319 days ago | 0.00006201 ETH | ||||
6770571 | 319 days ago | 0.0000698 ETH | ||||
6770571 | 319 days ago | 0.0000698 ETH | ||||
6770171 | 319 days ago | 0.00007176 ETH | ||||
6770171 | 319 days ago | 0.00007176 ETH | ||||
6770036 | 319 days ago | 0.00007126 ETH | ||||
6770036 | 319 days ago | 0.00007126 ETH | ||||
6696836 | 321 days ago | 0.00071458 ETH | ||||
6696836 | 321 days ago | 0.00071458 ETH | ||||
6686903 | 322 days ago | 0.00002912 ETH | ||||
6686903 | 322 days ago | 0.00002912 ETH | ||||
6686792 | 322 days ago | 0.00002912 ETH |
Loading...
Loading
Contract Name:
UnipilotActiveVault
Compiler Version
v0.7.6+commit.7338295f
Optimization Enabled:
Yes with 10 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
//SPDX-License-Identifier: MIT pragma solidity 0.7.6; pragma abicoder v2; import "./libraries/TransferHelper.sol"; import "./interfaces/external/IWETH9.sol"; import "./interfaces/IUnipilotVault.sol"; import "./interfaces/IUnipilotStrategy.sol"; import "./interfaces/IUnipilotFactory.sol"; import "./libraries/UniswapLiquidityManagement.sol"; import "./libraries/SafeCastExtended.sol"; import "./libraries/UniswapPoolActions.sol"; import "@openzeppelin/contracts/drafts/ERC20Permit.sol"; /// @title Unipilot Active Vault /// @author 0xMudassir & 721Orbit /// @dev Active liquidity managment contract that handles user liquidity of any Uniswap V3 pool & earn fees for them /// @dev minimalist, and gas-optimized contract that ensures user liquidity is always /// in range and earns maximum amount of fees available at current liquidity utilization /// rate. /// @dev In order to minimize IL for users contract pulls liquidity to the vault (HODL) when necessary contract UnipilotActiveVault is ERC20Permit, IUnipilotVault { using SafeCastExtended for uint256; using LowGasSafeMath for uint256; using UniswapPoolActions for IAlgebraPool; using UniswapLiquidityManagement for IAlgebraPool; IERC20 private token0; IERC20 private token1; int24 private tickSpacing; TicksData public ticksData; IAlgebraPool private pool; IUnipilotFactory private unipilotFactory; uint256 internal constant MIN_INITIAL_SHARES = 1e3; address private WETH; uint16 private _strategyType; uint32 private _pulled = 1; uint32 private _unlocked = 1; mapping(address => bool) private _operatorApproved; modifier onlyGovernance() { (address governance, , , , ) = getProtocolDetails(); require(msg.sender == governance); _; } modifier onlyOperator() { require(_operatorApproved[msg.sender]); _; } modifier nonReentrant() { require(_unlocked == 1); _unlocked = 2; _; _unlocked = 1; } modifier checkDeviation() { (, address strategy, , , ) = getProtocolDetails(); IUnipilotStrategy(strategy).checkDeviation(address(pool)); _; } constructor( address _pool, address _unipilotFactory, address _WETH, uint16 _strategytype, string memory _name, string memory _symbol ) ERC20Permit(_name) ERC20(_name, _symbol) { require(_pool != address(0)); require(_WETH != address(0)); require(_unipilotFactory != address(0)); pool = IAlgebraPool(_pool); unipilotFactory = IUnipilotFactory(_unipilotFactory); WETH = _WETH; token0 = IERC20(pool.token0()); token1 = IERC20(pool.token1()); tickSpacing = pool.tickSpacing(); _strategyType = _strategytype; } receive() external payable {} fallback() external payable {} /// @inheritdoc IUnipilotVault function deposit( uint256 amount0Desired, uint256 amount1Desired, address recipient ) external payable override nonReentrant checkDeviation returns ( uint256 lpShares, uint256 amount0, uint256 amount1 ) { require(recipient != address(0)); require(amount0Desired > 0 && amount1Desired > 0); address sender = _msgSender(); uint256 totalSupply = totalSupply(); (lpShares, amount0, amount1) = pool.computeLpShares( true, amount0Desired, amount1Desired, _balance0(), _balance1(), totalSupply, ticksData ); if (totalSupply == 0) { // prevent first LP from stealing funds of subsequent LPs // see https://code4rena.com/reports/2022-01-sherlock/#h-01-first-user-can-steal-everyone-elses-tokens require(lpShares > MIN_INITIAL_SHARES, "ML"); } require(lpShares != 0, "IS"); pay(address(token0), sender, address(this), amount0); pay(address(token1), sender, address(this), amount1); if (_pulled == 1) { pool.mintLiquidity( ticksData.baseTickLower, ticksData.baseTickUpper, amount0, amount1 ); } if (address(this).balance > 0) TransferHelper.safeTransferETH(sender, address(this).balance); _mint(recipient, lpShares); emit Deposit(sender, recipient, amount0, amount1, lpShares); } /// @inheritdoc IUnipilotVault function withdraw( uint256 liquidity, address recipient, bool refundAsETH ) external override nonReentrant checkDeviation returns (uint256 amount0, uint256 amount1) { require(liquidity > 0); uint256 totalSupply = totalSupply(); /// @dev if liquidity has pulled in contract then calculate share accordingly if (_pulled == 1) { uint256 liquidityShare = FullMath.mulDiv( liquidity, 1e18, totalSupply ); (amount0, amount1) = pool.burnUserLiquidity( ticksData.baseTickLower, ticksData.baseTickUpper, liquidityShare, address(this) ); (uint256 fees0, uint256 fees1) = pool.collectPendingFees( address(this), ticksData.baseTickLower, ticksData.baseTickUpper ); transferFeesToIF(false, fees0, fees1); } uint256 unusedAmount0 = FullMath.mulDiv( _balance0().sub(amount0), liquidity, totalSupply ); uint256 unusedAmount1 = FullMath.mulDiv( _balance1().sub(amount1), liquidity, totalSupply ); amount0 = amount0.add(unusedAmount0); amount1 = amount1.add(unusedAmount1); if (amount0 > 0) { transferFunds(refundAsETH, recipient, address(token0), amount0); } if (amount1 > 0) { transferFunds(refundAsETH, recipient, address(token1), amount1); } _burn(msg.sender, liquidity); emit Withdraw(recipient, liquidity, amount0, amount1); if (_pulled == 1) { (uint256 c0, uint256 c1) = pool.mintLiquidity( ticksData.baseTickLower, ticksData.baseTickUpper, _balance0(), _balance1() ); emit CompoundFees(c0, c1); } } /// @inheritdoc IUnipilotVault function readjustLiquidity(uint8 swapBP) external override onlyOperator checkDeviation { _pulled = 1; ReadjustVars memory a; (uint128 totalLiquidity, , ) = pool.getPositionLiquidity( ticksData.baseTickLower, ticksData.baseTickUpper ); (a.amount0Desired, a.amount1Desired, a.fees0, a.fees1) = pool .burnLiquidity( ticksData.baseTickLower, ticksData.baseTickUpper, address(this) ); transferFeesToIF(true, a.fees0, a.fees1); int24 baseThreshold = tickSpacing * getBaseThreshold(); (, a.currentTick, ) = pool.getSqrtRatioX96AndTick(); (a.tickLower, a.tickUpper) = UniswapLiquidityManagement.getBaseTicks( a.currentTick, baseThreshold, tickSpacing ); if ( (totalLiquidity > 0) && (a.amount0Desired == 0 || a.amount1Desired == 0) ) { bool zeroForOne = a.amount0Desired > 0 ? true : false; int256 amountSpecified = zeroForOne ? FullMath.mulDiv(a.amount0Desired, swapBP, 100).toInt256() : FullMath.mulDiv(a.amount1Desired, swapBP, 100).toInt256(); pool.swapToken(address(this), zeroForOne, amountSpecified); } else { a.amount0Desired = _balance0(); a.amount1Desired = _balance1(); a.liquidity = pool.getLiquidityForAmounts( a.amount0Desired, a.amount1Desired, a.tickLower, a.tickUpper ); (a.amount0, a.amount1) = pool.getAmountsForLiquidity( a.liquidity, a.tickLower, a.tickUpper ); a.zeroForOne = UniswapLiquidityManagement.amountsDirection( a.amount0Desired, a.amount1Desired, a.amount0, a.amount1 ); a.amountSpecified = a.zeroForOne ? int256( FullMath.mulDiv( a.amount0Desired.sub(a.amount0), swapBP, 100 ) ) : int256( FullMath.mulDiv( a.amount1Desired.sub(a.amount1), swapBP, 100 ) ); pool.swapToken(address(this), a.zeroForOne, a.amountSpecified); } a.amount0Desired = _balance0(); a.amount1Desired = _balance1(); (ticksData.baseTickLower, ticksData.baseTickUpper) = pool .getPositionTicks( a.amount0Desired, a.amount1Desired, baseThreshold, tickSpacing ); pool.mintLiquidity( ticksData.baseTickLower, ticksData.baseTickUpper, a.amount0Desired, a.amount1Desired ); } function rebalance( int256 swapAmount, bool zeroForOne, int24 tickLower, int24 tickUpper ) external onlyOperator checkDeviation { _pulled = 1; UniswapLiquidityManagement.checkRange( tickLower, tickUpper, tickSpacing ); // Withdraw all current liquidity from Uniswap pool & transfer fees (, , uint256 fees0, uint256 fees1) = pool.burnLiquidity( ticksData.baseTickLower, ticksData.baseTickUpper, address(this) ); transferFeesToIF(true, fees0, fees1); if (swapAmount != 0) pool.swapToken(address(this), zeroForOne, swapAmount); pool.mintLiquidity(tickLower, tickUpper, _balance0(), _balance1()); (ticksData.baseTickLower, ticksData.baseTickUpper) = ( tickLower, tickUpper ); } /// @inheritdoc IUnipilotVault function algebraMintCallback( uint256 amount0Owed, uint256 amount1Owed, bytes calldata data ) external override { _verifyCallback(); address recipient = _msgSender(); address payer = abi.decode(data, (address)); if (amount0Owed > 0) TransferHelper.safeTransfer( address(token0), recipient, amount0Owed ); if (amount1Owed > 0) TransferHelper.safeTransfer( address(token1), recipient, amount1Owed ); } /// @inheritdoc IUnipilotVault function algebraSwapCallback( int256 amount0, int256 amount1, bytes calldata data ) external override { _verifyCallback(); require(amount0 > 0 || amount1 > 0); bool zeroForOne = abi.decode(data, (bool)); if (zeroForOne) TransferHelper.safeTransfer( address(token0), _msgSender(), uint256(amount0) ); else TransferHelper.safeTransfer( address(token1), _msgSender(), uint256(amount1) ); } /// @dev Burns all the Unipilot position and HODL in the vault to prevent users from huge IL /// Only called by the selected operators /// @dev Users can also deposit/withdraw during HODL period. function pullLiquidity() external onlyOperator { ( uint256 reserves0, uint256 reserves1, uint256 fees0, uint256 fees1 ) = pool.burnLiquidity( ticksData.baseTickLower, ticksData.baseTickUpper, address(this) ); _pulled = 2; emit PullLiquidity(reserves0, reserves1, fees0, fees1); } /// @notice Calculates the vault's total holdings of TOKEN0 and TOKEN1 - in /// other words, how much of each token the vault would hold if it withdrew /// all its liquidity from Uniswap. /// @dev Updates the position and return the updated reserves, fees & liquidity. /// @return amount0 Amount of token0 in the unipilot vault /// @return amount1 Amount of token1 in the unipilot vault /// @return fees0 Total amount of fees collected by unipilot position in terms of token0 /// @return fees1 Total amount of fees collected by unipilot position in terms of token1 /// @return baseLiquidity The total liquidity of the base position /// @return rangeLiquidity The total liquidity of the range position - N/A for active vault function getPositionDetails() external returns ( uint256 amount0, uint256 amount1, uint256 fees0, uint256 fees1, uint128 baseLiquidity, uint128 rangeLiquidity ) { return pool.getTotalAmounts(true, ticksData); } /// @notice Updates the status of given account as operator /// @dev Must be called by the current governance /// @param _operator Account to update status function toggleOperator(address _operator) external onlyGovernance { _operatorApproved[_operator] = !_operatorApproved[_operator]; } /// @notice Returns the status for a given operator that can operate readjust & pull liquidity function isOperator(address _operator) external view returns (bool) { return _operatorApproved[_operator]; } /// @notice Returns unipilot vault details /// @return The first of the two tokens of the pool, sorted by address /// @return The second of the two tokens of the pool, sorted by address /// @return The pool's fee in hundredths of a bip, i.e. 1e-6 /// @return The address of the Uniswap V3 Pool function getVaultInfo() external view returns ( address, address, uint16, address ) { (, , uint16 fee, , , , ) = pool.globalState(); return (address(token0), address(token1), fee, address(pool)); } /// @dev Amount of token0 held as unused balance. function _balance0() internal view returns (uint256) { return token0.balanceOf(address(this)); } /// @dev Amount of token1 held as unused balance. function _balance1() internal view returns (uint256) { return token1.balanceOf(address(this)); } /// @notice Verify that caller should be the address of a valid Uniswap V3 Pool function _verifyCallback() internal view { require(msg.sender == address(pool)); } function getBaseThreshold() internal view returns (int24 baseThreshold) { (, address strategy, , , ) = getProtocolDetails(); return IUnipilotStrategy(strategy).getBaseThreshold( address(pool), _strategyType ); } function getProtocolDetails() internal view returns ( address governance, address strategy, address indexFund, uint8 indexFundPercentage, uint8 swapPercentage ) { return unipilotFactory.getUnipilotDetails(); } /// @dev method to transfer unipilot earned fees to Index Fund function transferFeesToIF( bool isReadjustLiquidity, uint256 fees0, uint256 fees1 ) internal { (, , address indexFund, uint8 percentage, ) = getProtocolDetails(); if (percentage > 0) { if (fees0 > 0) TransferHelper.safeTransfer( address(token0), indexFund, FullMath.mulDiv(fees0, percentage, 100) ); if (fees1 > 0) TransferHelper.safeTransfer( address(token1), indexFund, FullMath.mulDiv(fees1, percentage, 100) ); emit FeesSnapshot(isReadjustLiquidity, fees0, fees1); } } function transferFunds( bool refundAsETH, address recipient, address token, uint256 amount ) internal { if (refundAsETH && token == WETH) { IWETH9(WETH).withdraw(amount); TransferHelper.safeTransferETH(recipient, amount); } else { TransferHelper.safeTransfer(token, recipient, amount); } } /// @param token The token to pay /// @param payer The entity that must pay /// @param recipient The entity that will receive payment /// @param value The amount to pay function pay( address token, address payer, address recipient, uint256 value ) internal { if (token == WETH && address(this).balance >= value) { // pay with WETH9 IWETH9(WETH).deposit{ value: value }(); // wrap only what is needed to pay IWETH9(WETH).transfer(recipient, value); } else if (payer == address(this)) { // pay with tokens already in the contract (for the exact input multihop case) TransferHelper.safeTransfer(token, recipient, value); } else { // pull payment TransferHelper.safeTransferFrom(token, payer, recipient, value); } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.6.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; //import "../interfaces/external/IERC20.sol"; library TransferHelper { /// @notice Transfers tokens from the targeted address to the given destination /// @notice Errors with 'STF' if transfer fails /// @param token The contract address of the token to be transferred /// @param from The originating address from which the tokens will be transferred /// @param to The destination address of the transfer /// @param value The amount to be transferred function safeTransferFrom( address token, address from, address to, uint256 value ) internal { (bool success, bytes memory data) = token.call( abi.encodeWithSelector( IERC20.transferFrom.selector, from, to, value ) ); require( success && (data.length == 0 || abi.decode(data, (bool))), "STF" ); } /// @notice Transfers tokens from msg.sender to a recipient /// @dev Errors with ST if transfer fails /// @param token The contract address of the token which will be transferred /// @param to The recipient of the transfer /// @param value The value of the transfer function safeTransfer( address token, address to, uint256 value ) internal { (bool success, bytes memory data) = token.call( abi.encodeWithSelector(IERC20.transfer.selector, to, value) ); require( success && (data.length == 0 || abi.decode(data, (bool))), "ST" ); } /// @notice Approves the stipulated contract to spend the given allowance in the given token /// @dev Errors with 'SA' if transfer fails /// @param token The contract address of the token to be approved /// @param to The target of the approval /// @param value The amount of the given token the target will be allowed to spend function safeApprove( address token, address to, uint256 value ) internal { (bool success, bytes memory data) = token.call( abi.encodeWithSelector(IERC20.approve.selector, to, value) ); require( success && (data.length == 0 || abi.decode(data, (bool))), "SA" ); } /// @notice Transfers ETH to the recipient address /// @dev Fails with `STE` /// @param to The destination of the transfer /// @param value The value to be transferred function safeTransferETH(address to, uint256 value) internal { (bool success, ) = to.call{ value: value }(new bytes(0)); require(success, "STE"); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity =0.7.6; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /// @title Interface for WETH9 interface IWETH9 is IERC20 { /// @notice Deposit ether to get wrapped ether function deposit() external payable; /// @notice Withdraw wrapped ether to get ether function withdraw(uint256) external; }
//SPDX-License-Identifier: MIT pragma solidity ^0.7.6; interface IUnipilotVault { struct ReadjustVars { uint256 fees0; uint256 fees1; int24 currentTick; int24 tickLower; int24 tickUpper; uint256 amount0Desired; uint256 amount1Desired; uint128 liquidity; uint256 amount0; uint256 amount1; bool zeroForOne; int256 amountSpecified; uint160 exactSqrtPriceImpact; uint160 sqrtPriceLimitX96; } struct TicksData { int24 baseTickLower; int24 baseTickUpper; int24 rangeTickLower; int24 rangeTickUpper; } struct Tick { int24 baseTickLower; int24 baseTickUpper; int24 bidTickLower; int24 bidTickUpper; int24 rangeTickLower; int24 rangeTickUpper; } struct Cache { uint256 totalSupply; uint256 liquidityShare; } event Deposit( address indexed depositor, address indexed recipient, uint256 amount0, uint256 amount1, uint256 lpShares ); event FeesSnapshot(bool isReadjustLiquidity, uint256 fees0, uint256 fees1); event Withdraw( address indexed recipient, uint256 shares, uint256 amount0, uint256 amount1 ); event PullLiquidity( uint256 reserves0, uint256 reserves1, uint256 fees0, uint256 fees1 ); event CompoundFees(uint256 amount0, uint256 amount1); /// @notice Deposits tokens in proportion to the Unipilot's current holdings & mints them /// `Unipilot`s LP token. /// @param amount0Desired Max amount of token0 to deposit /// @param amount1Desired Max amount of token1 to deposit /// @param recipient Recipient of shares /// @return lpShares Number of shares minted /// @return amount0 Amount of token0 deposited in vault /// @return amount1 Amount of token1 deposited in vault function deposit( uint256 amount0Desired, uint256 amount1Desired, address recipient ) external payable returns ( uint256 lpShares, uint256 amount0, uint256 amount1 ); /// @notice Withdraws the desired shares from the vault with accumulated user fees and transfers to recipient. /// @param recipient Recipient of tokens /// @param refundAsETH whether to recieve in WETH or ETH (only valid for WETH/ALT pairs) /// @return amount0 Amount of token0 sent to recipient /// @return amount1 Amount of token1 sent to recipient function withdraw( uint256 liquidity, address recipient, bool refundAsETH ) external returns (uint256 amount0, uint256 amount1); /// @notice Pull in tokens from sender. Called to `msg.sender` after minting liquidity to a position from IUniswapV3Pool#mint. /// @dev In the implementation you must pay to the pool for the minted liquidity. /// @param amount0Owed The amount of token0 due to the pool for the minted liquidity /// @param amount1Owed The amount of token1 due to the pool for the minted liquidity /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#mint call function algebraMintCallback( uint256 amount0Owed, uint256 amount1Owed, bytes calldata data ) external; /// @notice Called to `msg.sender` after minting swaping from IUniswapV3Pool#swap. /// @dev In the implementation you must pay to the pool for swap. /// @param amount0Delta The amount of token0 due to the pool for the swap /// @param amount1Delta The amount of token1 due to the pool for the swap /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call function algebraSwapCallback( int256 amount0Delta, int256 amount1Delta, bytes calldata data ) external; /// @notice Burns all position(s), collects any fees accrued and updates Unipilot's position(s) /// @dev mints all amounts to this position(s) (including earned fees) /// @dev For active vaults it can be called by the governance or operator, /// swaps imbalanced token and add all liquidity in base position. /// @dev For passive vaults it can be called by any user. /// Two positions are placed - a base position and a limit position. The base /// position is placed first with as much liquidity as possible. This position /// should use up all of one token, leaving only the other one. This excess /// amount is then placed as a single-sided bid or ask position. function readjustLiquidity(uint8 swapBP) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.7.6; pragma abicoder v2; interface IUnipilotStrategy { struct PoolStrategy { int24 baseThreshold; int24 rangeThreshold; int24 maxTwapDeviation; int24 readjustThreshold; uint32 twapDuration; int24 baseMultiplier; } event GovernanceUpdated(address oldGovernance, address newGovernance); event StrategyUpdated(PoolStrategy oldStrategy, PoolStrategy newStrategy); event MaxTwapDeviationUpdated(int24 oldDeviation, int24 newDeviation); event BaseTicksUpdated(int24 oldBaseTicks, int24 newBaseTicks); event RangeTicksUpdated(int24 oldRangeTicks, int24 newRangeTicks); event TwapDurationUpdated(uint32 oldDuration, uint32 newDuration); event ReadjustMultiplierUpdated(int24 oldMultiplier, int24 newMultiplier); function getTicks(address _pool) external returns ( int24 baseLower, int24 baseUpper, int24 bidLower, int24 bidUpper, int24 askLower, int24 askUpper ); function getTwap(address _pool) external view returns (int24); function getStrategy(address _pool) external view returns (PoolStrategy memory strategy); function getBaseThreshold(address _pool, uint16 _strategyType) external view returns (int24 baseThreshold); function twapDuration() external view returns (uint32); function maxTwapDeviation() external view returns (int24); function checkDeviation(address pool) external view; }
//SPDX-License-Identifier: MIT pragma solidity ^0.7.6; /// @title The interface for the Unipilot Factory interface IUnipilotFactory { /// @notice Emitted when a vault is created /// @param _tokenA The first token of the pool by address sort order /// @param _tokenB The second token of the pool by address sort order /// @param _vault The address of the vault that is created event VaultCreated( address indexed _tokenA, address indexed _tokenB, uint16 _strategyType, address indexed _vault ); /// @notice Emitted when the governance of the factory is changed /// @param _oldGovernance The governance before the governance was changed /// @param _newGovernance The governance after the governance was changed event GovernanceChanged( address indexed _oldGovernance, address indexed _newGovernance ); /// @notice Creates a vault for the given two tokens and fee /// @param _tokenA The first token of the pool by address sort order /// @param _tokenB The second token of the pool by address sort order /// @dev tokenA and tokenB may be passed in either order: token0/token1 or token1/token0. /// The call will revert if the vault already exists, the fee is invalid, or the token arguments /// are invalid. /// @return _vault The address of the newly created pool function createVault( address _tokenA, address _tokenB, uint16 _vaultStrategy, uint160 _sqrtPriceX96, string memory _name, string memory _symbol ) external returns (address _vault); /// @notice Used to give addresses of governance, strategy, indexFund /// @return governance address, strategy address, indexFund address function getUnipilotDetails() external view returns ( address, address, address, uint8, uint8 ); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; import "./UniswapPoolActions.sol"; import "../interfaces/IUnipilotVault.sol"; import "@uniswap/v3-core/contracts/libraries/TickMath.sol"; import "@uniswap/v3-periphery/contracts/libraries/PositionKey.sol"; import "@cryptoalgebra/periphery/contracts/libraries/LiquidityAmounts.sol"; import "@cryptoalgebra/core/contracts/libraries/PriceMovementMath.sol"; /// @title Liquidity and ticks functions /// @notice Provides functions for computing liquidity and ticks for token amounts and prices library UniswapLiquidityManagement { using LowGasSafeMath for uint256; struct Info { uint256 amount0Desired; uint256 amount1Desired; uint256 amount0; uint256 amount1; uint128 liquidity; int24 tickLower; int24 tickUpper; } /// @dev Wrapper around `LiquidityAmounts.getAmountsForLiquidity()`. /// @param pool Uniswap V3 pool /// @param liquidity The liquidity being valued /// @param _tickLower The lower tick of the range /// @param _tickUpper The upper tick of the range /// @return amounts of token0 and token1 that corresponds to liquidity function getAmountsForLiquidity( IAlgebraPool pool, uint128 liquidity, int24 _tickLower, int24 _tickUpper ) internal view returns (uint256, uint256) { (uint160 sqrtRatioX96, , , , , , ) = pool.globalState(); return LiquidityAmounts.getAmountsForLiquidity( sqrtRatioX96, TickMath.getSqrtRatioAtTick(_tickLower), TickMath.getSqrtRatioAtTick(_tickUpper), liquidity ); } /// @dev Wrapper around `LiquidityAmounts.getLiquidityForAmounts()`. /// @param pool Uniswap V3 pool /// @param amount0 The amount of token0 /// @param amount1 The amount of token1 /// @param _tickLower The lower tick of the range /// @param _tickUpper The upper tick of the range /// @return The maximum amount of liquidity that can be held amount0 and amount1 function getLiquidityForAmounts( IAlgebraPool pool, uint256 amount0, uint256 amount1, int24 _tickLower, int24 _tickUpper ) internal view returns (uint128) { (uint160 sqrtRatioX96, , , , , , ) = pool.globalState(); return LiquidityAmounts.getLiquidityForAmounts( sqrtRatioX96, TickMath.getSqrtRatioAtTick(_tickLower), TickMath.getSqrtRatioAtTick(_tickUpper), amount0, amount1 ); } /// @dev Amount of liquidity in contract position. /// @param pool Uniswap V3 pool /// @param _tickLower The lower tick of the range /// @param _tickUpper The upper tick of the range /// @return liquidity stored in position function getPositionLiquidity( IAlgebraPool pool, int24 _tickLower, int24 _tickUpper ) internal view returns ( uint128 liquidity, uint128 tokensOwed0, uint128 tokensOwed1 ) { bytes32 positionKey; address vault = address(this); assembly { positionKey := or( shl(24, or(shl(24, vault), and(_tickLower, 0xFFFFFF))), and(_tickUpper, 0xFFFFFF) ) } (liquidity, , , , tokensOwed0, tokensOwed1) = pool.positions( positionKey ); } /// @dev Rounds tick down towards negative infinity so that it's a multiple /// of `tickSpacing`. function floor(int24 tick, int24 tickSpacing) internal pure returns (int24) { int24 compressed = tick / tickSpacing; if (tick < 0 && tick % tickSpacing != 0) compressed--; return compressed * tickSpacing; } function getSqrtRatioX96AndTick(IAlgebraPool pool) internal view returns ( uint160 _sqrtRatioX96, int24 _tick, uint16 observationCardinality ) { (_sqrtRatioX96, _tick, , observationCardinality, , , ) = pool .globalState(); } /// @dev Calc base ticks depending on base threshold and tickspacing function getBaseTicks( int24 currentTick, int24 baseThreshold, int24 tickSpacing ) internal pure returns (int24 tickLower, int24 tickUpper) { int24 tickFloor = floor(currentTick, tickSpacing); tickLower = tickFloor - baseThreshold; tickUpper = tickFloor + baseThreshold; } function collectableAmountsInPosition( IAlgebraPool pool, int24 _lowerTick, int24 _upperTick ) internal view returns ( uint256, uint256, uint256, uint256 ) { ( uint128 liquidity, uint128 earnable0, uint128 earnable1 ) = getPositionLiquidity(pool, _lowerTick, _upperTick); (uint256 burnable0, uint256 burnable1) = UniswapLiquidityManagement .getAmountsForLiquidity(pool, liquidity, _lowerTick, _upperTick); return (burnable0, burnable1, earnable0, earnable1); } function computeLpShares( IAlgebraPool pool, bool isWhitelisted, uint256 amount0Max, uint256 amount1Max, uint256 balance0, uint256 balance1, uint256 totalSupply, IUnipilotVault.TicksData memory ticks ) internal returns ( uint256 shares, uint256 amount0, uint256 amount1 ) { ( uint256 res0, uint256 res1, uint256 fees0, uint256 fees1, , ) = getTotalAmounts(pool, isWhitelisted, ticks); uint256 reserve0 = res0.add(fees0).add(balance0); uint256 reserve1 = res1.add(fees1).add(balance1); // If total supply > 0, pool can't be empty assert(totalSupply == 0 || reserve0 != 0 || reserve1 != 0); (shares, amount0, amount1) = calculateShare( amount0Max, amount1Max, reserve0, reserve1, totalSupply ); } function getTotalAmounts( IAlgebraPool pool, bool isWhitelisted, IUnipilotVault.TicksData memory ticks ) internal returns ( uint256 amount0, uint256 amount1, uint256 fees0, uint256 fees1, uint128 baseLiquidity, uint128 rangeLiquidity ) { (amount0, amount1, fees0, fees1, baseLiquidity) = getReserves( pool, ticks.baseTickLower, ticks.baseTickUpper ); if (!isWhitelisted) { ( uint256 range0, uint256 range1, uint256 rangeFees0, uint256 rangeFees1, uint128 rangeliquidity ) = getReserves(pool, ticks.rangeTickLower, ticks.rangeTickUpper); amount0 = amount0.add(range0); amount1 = amount1.add(range1); fees0 = fees0.add(rangeFees0); fees1 = fees1.add(rangeFees1); rangeLiquidity = rangeliquidity; } } function getReserves( IAlgebraPool pool, int24 tickLower, int24 tickUpper ) internal returns ( uint256 amount0, uint256 amount1, uint256 fees0, uint256 fees1, uint128 liquidity ) { liquidity = UniswapPoolActions.updatePosition( pool, tickLower, tickUpper ); if (liquidity > 0) { (amount0, amount1, fees0, fees1) = collectableAmountsInPosition( pool, tickLower, tickUpper ); } } function calculateShare( uint256 amount0Max, uint256 amount1Max, uint256 reserve0, uint256 reserve1, uint256 totalSupply ) internal pure returns ( uint256 shares, uint256 amount0, uint256 amount1 ) { if (totalSupply == 0) { // For first deposit, just use the amounts desired amount0 = amount0Max; amount1 = amount1Max; shares = amount0 > amount1 ? amount0 : amount1; // max } else if (reserve0 == 0) { amount1 = amount1Max; shares = FullMath.mulDiv(amount1, totalSupply, reserve1); } else if (reserve1 == 0) { amount0 = amount0Max; shares = FullMath.mulDiv(amount0, totalSupply, reserve0); } else { amount0 = FullMath.mulDiv(amount1Max, reserve0, reserve1); if (amount0 < amount0Max) { amount1 = amount1Max; shares = FullMath.mulDiv(amount1, totalSupply, reserve1); } else { amount0 = amount0Max; amount1 = FullMath.mulDiv(amount0, reserve1, reserve0); shares = FullMath.mulDiv(amount0, totalSupply, reserve0); } } } /// @dev Gets ticks with proportion equivalent to desired amount /// @param pool Uniswap V3 pool /// @param amount0Desired The desired amount of token0 /// @param amount1Desired The desired amount of token1 /// @param baseThreshold The range for upper and lower ticks /// @param tickSpacing The pool tick spacing /// @return tickLower The lower tick of the range /// @return tickUpper The upper tick of the range function getPositionTicks( IAlgebraPool pool, uint256 amount0Desired, uint256 amount1Desired, int24 baseThreshold, int24 tickSpacing ) internal view returns (int24 tickLower, int24 tickUpper) { Info memory cache = Info(amount0Desired, amount1Desired, 0, 0, 0, 0, 0); // Get current price and tick from the pool (uint160 sqrtPriceX96, int24 currentTick, , , , , ) = pool .globalState(); //Calc base ticks (cache.tickLower, cache.tickUpper) = getBaseTicks( currentTick, baseThreshold, tickSpacing ); //Calc amounts of token0 and token1 that can be stored in base range (cache.amount0, cache.amount1) = getAmountsForTicks( pool, cache.amount0Desired, cache.amount1Desired, cache.tickLower, cache.tickUpper ); // //Liquidity that can be stored in base range cache.liquidity = getLiquidityForAmounts( pool, cache.amount0, cache.amount1, cache.tickLower, cache.tickUpper ); // //Get imbalanced token bool zeroGreaterOne = amountsDirection( cache.amount0Desired, cache.amount1Desired, cache.amount0, cache.amount1 ); //Calc new tick(upper or lower) for imbalanced token if (zeroGreaterOne) { uint160 nextSqrtPrice0 = PriceMovementMath.getNewPrice( sqrtPriceX96, cache.liquidity, cache.amount0Desired, false, false ); cache.tickUpper = floor( TickMath.getTickAtSqrtRatio(nextSqrtPrice0), tickSpacing ); } else { uint160 nextSqrtPrice1 = PriceMovementMath.getNewPrice( sqrtPriceX96, cache.liquidity, cache.amount1Desired, true, false ); cache.tickLower = floor( TickMath.getTickAtSqrtRatio(nextSqrtPrice1), tickSpacing ); } checkRange(cache.tickLower, cache.tickUpper, tickSpacing); /// floor the tick again because one tick is still not valid tick due to + - baseThreshold tickLower = floor(cache.tickLower, tickSpacing); tickUpper = floor(cache.tickUpper, tickSpacing); } /// @dev Gets amounts of token0 and token1 that can be stored in range of upper and lower ticks /// @param pool Uniswap V3 pool /// @param amount0Desired The desired amount of token0 /// @param amount1Desired The desired amount of token1 /// @param _tickLower The lower tick of the range /// @param _tickUpper The upper tick of the range /// @return amount0 amounts of token0 that can be stored in range /// @return amount1 amounts of token1 that can be stored in range function getAmountsForTicks( IAlgebraPool pool, uint256 amount0Desired, uint256 amount1Desired, int24 _tickLower, int24 _tickUpper ) internal view returns (uint256 amount0, uint256 amount1) { uint128 liquidity = getLiquidityForAmounts( pool, amount0Desired, amount1Desired, _tickLower, _tickUpper ); (amount0, amount1) = getAmountsForLiquidity( pool, liquidity, _tickLower, _tickUpper ); } /// @dev Common checks for valid tick inputs. /// @param tickLower The lower tick of the range /// @param tickUpper The upper tick of the range /// @param tickSpacing The pool tick spacing function checkRange( int24 tickLower, int24 tickUpper, int24 tickSpacing ) internal pure { require(tickLower < tickUpper, "TLU"); require(tickLower >= TickMath.MIN_TICK, "TLM"); require(tickUpper <= TickMath.MAX_TICK, "TUM"); require(tickLower % tickSpacing == 0, "TLI"); require(tickUpper % tickSpacing == 0, "TUI"); } /// @dev Get imbalanced token /// @param amount0Desired The desired amount of token0 /// @param amount1Desired The desired amount of token1 /// @param amount0 Amounts of token0 that can be stored in base range /// @param amount1 Amounts of token1 that can be stored in base range /// @return zeroGreaterOne true if token0 is imbalanced. False if token1 is imbalanced function amountsDirection( uint256 amount0Desired, uint256 amount1Desired, uint256 amount0, uint256 amount1 ) internal pure returns (bool zeroGreaterOne) { zeroGreaterOne = amount0Desired.sub(amount0).mul(amount1Desired) > amount1Desired.sub(amount1).mul(amount0Desired) ? true : false; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing * all math on `uint256` and `int256` and then downcasting. */ library SafeCastExtended { /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128) { require(value < 2**128, "SafeCast: value doesn't fit in 128 bits"); return uint128(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits */ function toUint64(uint256 value) internal pure returns (uint64) { require(value < 2**64, "SafeCast: value doesn't fit in 64 bits"); return uint64(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits */ function toUint32(uint256 value) internal pure returns (uint32) { require(value < 2**32, "SafeCast: value doesn't fit in 32 bits"); return uint32(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits */ function toUint16(uint256 value) internal pure returns (uint16) { require(value < 2**16, "SafeCast: value doesn't fit in 16 bits"); return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits. */ function toUint8(uint256 value) internal pure returns (uint8) { require(value < 2**8, "SafeCast: value doesn't fit in 8 bits"); return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v3.1._ */ function toInt128(int256 value) internal pure returns (int128) { require( value >= -2**127 && value < 2**127, "SafeCast: value doesn't fit in 128 bits" ); return int128(value); } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v3.1._ */ function toInt64(int256 value) internal pure returns (int64) { require( value >= -2**63 && value < 2**63, "SafeCast: value doesn't fit in 64 bits" ); return int64(value); } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v3.1._ */ function toInt32(int256 value) internal pure returns (int32) { require( value >= -2**31 && value < 2**31, "SafeCast: value doesn't fit in 32 bits" ); return int32(value); } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v3.1._ */ function toInt16(int256 value) internal pure returns (int16) { require( value >= -2**15 && value < 2**15, "SafeCast: value doesn't fit in 16 bits" ); return int16(value); } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits. * * _Available since v3.1._ */ function toInt8(int256 value) internal pure returns (int8) { require( value >= -2**7 && value < 2**7, "SafeCast: value doesn't fit in 8 bits" ); return int8(value); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { require(value < 2**255, "SafeCast: value doesn't fit in an int256"); return int256(value); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; import "./SafeCastExtended.sol"; import "./UniswapLiquidityManagement.sol"; import "@cryptoalgebra/core/contracts/libraries/FullMath.sol"; import "@cryptoalgebra/core/contracts/interfaces/IAlgebraPool.sol"; import "@cryptoalgebra/core/contracts/libraries/LowGasSafeMath.sol"; /// @title Liquidity and ticks functions /// @notice Provides functions for computing liquidity and ticks for token amounts and prices library UniswapPoolActions { using LowGasSafeMath for uint256; using SafeCastExtended for uint256; using UniswapLiquidityManagement for IAlgebraPool; function updatePosition( IAlgebraPool pool, int24 tickLower, int24 tickUpper ) internal returns (uint128 liquidity) { (liquidity, , ) = pool.getPositionLiquidity(tickLower, tickUpper); if (liquidity > 0) { pool.burn(tickLower, tickUpper, 0); } } function burnLiquidity( IAlgebraPool pool, int24 tickLower, int24 tickUpper, address recipient ) internal returns ( uint256 amount0, uint256 amount1, uint256 fees0, uint256 fees1 ) { (uint128 liquidity, , ) = pool.getPositionLiquidity( tickLower, tickUpper ); if (liquidity > 0) { (amount0, amount1) = pool.burn(tickLower, tickUpper, liquidity); if (amount0 > 0 || amount1 > 0) { (uint256 collect0, uint256 collect1) = pool.collect( recipient, tickLower, tickUpper, type(uint128).max, type(uint128).max ); (fees0, fees1) = (collect0.sub(amount0), collect1.sub(amount1)); } } } function burnUserLiquidity( IAlgebraPool pool, int24 tickLower, int24 tickUpper, uint256 userSharePercentage, address recipient ) internal returns (uint256 amount0, uint256 amount1) { (uint128 liquidity, , ) = pool.getPositionLiquidity( tickLower, tickUpper ); uint256 liquidityRemoved = FullMath.mulDiv( uint256(liquidity), userSharePercentage, 1e18 ); (amount0, amount1) = pool.burn( tickLower, tickUpper, liquidityRemoved.toUint128() ); if (amount0 > 0 || amount1 > 0) { (amount0, amount0) = pool.collect( recipient, tickLower, tickUpper, amount0.toUint128(), amount1.toUint128() ); } } function mintLiquidity( IAlgebraPool pool, int24 tickLower, int24 tickUpper, uint256 amount0Desired, uint256 amount1Desired ) internal returns (uint256 amount0, uint256 amount1) { uint128 liquidity = pool.getLiquidityForAmounts( amount0Desired, amount1Desired, tickLower, tickUpper ); if (liquidity > 0) { (amount0, amount1, ) = pool.mint( address(this), address(this), tickLower, tickUpper, liquidity, abi.encode(address(this)) ); } } function swapToken( IAlgebraPool pool, address recipient, bool zeroForOne, int256 amountSpecified ) internal { (uint160 sqrtPriceX96, , ) = pool.getSqrtRatioX96AndTick(); uint160 exactSqrtPriceImpact = (sqrtPriceX96 * (1e5 / 2)) / 1e6; uint160 sqrtPriceLimitX96 = zeroForOne ? sqrtPriceX96 - exactSqrtPriceImpact : sqrtPriceX96 + exactSqrtPriceImpact; pool.swap( recipient, zeroForOne, amountSpecified, sqrtPriceLimitX96, abi.encode(zeroForOne) ); } function collectPendingFees( IAlgebraPool pool, address recipient, int24 tickLower, int24 tickUpper ) internal returns (uint256 collect0, uint256 collect1) { updatePosition(pool, tickLower, tickUpper); (collect0, collect1) = pool.collect( recipient, tickLower, tickUpper, type(uint128).max, type(uint128).max ); } function rerangeLiquidity( IAlgebraPool pool, int24 baseThreshold, int24 tickSpacing, uint256 balance0, uint256 balance1 ) internal returns (int24 tickLower, int24 tickUpper) { (tickLower, tickUpper) = pool.getPositionTicks( balance0, balance1, baseThreshold, tickSpacing ); mintLiquidity(pool, tickLower, tickUpper, balance0, balance1); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.5 <0.8.0; import "../token/ERC20/ERC20.sol"; import "./IERC20Permit.sol"; import "../cryptography/ECDSA.sol"; import "../utils/Counters.sol"; import "./EIP712.sol"; /** * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * _Available since v3.4._ */ abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 { using Counters for Counters.Counter; mapping (address => Counters.Counter) private _nonces; // solhint-disable-next-line var-name-mixedcase bytes32 private immutable _PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); /** * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. * * It's a good idea to use the same `name` that is defined as the ERC20 token name. */ constructor(string memory name) EIP712(name, "1") { } /** * @dev See {IERC20Permit-permit}. */ function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public virtual override { // solhint-disable-next-line not-rely-on-time require(block.timestamp <= deadline, "ERC20Permit: expired deadline"); bytes32 structHash = keccak256( abi.encode( _PERMIT_TYPEHASH, owner, spender, value, _nonces[owner].current(), deadline ) ); bytes32 hash = _hashTypedDataV4(structHash); address signer = ECDSA.recover(hash, v, r, s); require(signer == owner, "ERC20Permit: invalid signature"); _nonces[owner].increment(); _approve(owner, spender, value); } /** * @dev See {IERC20Permit-nonces}. */ function nonces(address owner) public view override returns (uint256) { return _nonces[owner].current(); } /** * @dev See {IERC20Permit-DOMAIN_SEPARATOR}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view override returns (bytes32) { return _domainSeparatorV4(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title Math library for computing sqrt prices from ticks and vice versa /// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports /// prices between 2**-128 and 2**128 library TickMath { /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128 int24 internal constant MIN_TICK = -887272; /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128 int24 internal constant MAX_TICK = -MIN_TICK; /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK) uint160 internal constant MIN_SQRT_RATIO = 4295128739; /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK) uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342; /// @notice Calculates sqrt(1.0001^tick) * 2^96 /// @dev Throws if |tick| > max tick /// @param tick The input tick for the above formula /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0) /// at the given tick function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) { uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick)); require(absTick <= uint256(MAX_TICK), 'T'); uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000; if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128; if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128; if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128; if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128; if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128; if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128; if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128; if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128; if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128; if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128; if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128; if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128; if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128; if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128; if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128; if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128; if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128; if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128; if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128; if (tick > 0) ratio = type(uint256).max / ratio; // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96. // we then downcast because we know the result always fits within 160 bits due to our tick input constraint // we round up in the division so getTickAtSqrtRatio of the output price is always consistent sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1)); } /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may /// ever return. /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96 /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio function getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) { // second inequality must be < because the price can never reach the price at the max tick require(sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, 'R'); uint256 ratio = uint256(sqrtPriceX96) << 32; uint256 r = ratio; uint256 msb = 0; assembly { let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(5, gt(r, 0xFFFFFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(4, gt(r, 0xFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(3, gt(r, 0xFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(2, gt(r, 0xF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(1, gt(r, 0x3)) msb := or(msb, f) r := shr(f, r) } assembly { let f := gt(r, 0x1) msb := or(msb, f) } if (msb >= 128) r = ratio >> (msb - 127); else r = ratio << (127 - msb); int256 log_2 = (int256(msb) - 128) << 64; assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(63, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(62, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(61, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(60, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(59, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(58, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(57, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(56, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(55, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(54, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(53, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(52, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(51, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(50, f)) } int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128); int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128); tick = tickLow == tickHi ? tickLow : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow; } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; library PositionKey { /// @dev Returns the key of the position in the core library function compute( address owner, int24 tickLower, int24 tickUpper ) internal pure returns (bytes32) { return keccak256(abi.encodePacked(owner, tickLower, tickUpper)); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; import '@cryptoalgebra/core/contracts/libraries/FullMath.sol'; import '@cryptoalgebra/core/contracts/libraries/Constants.sol'; /// @title Liquidity amount functions /// @notice Provides functions for computing liquidity amounts from token amounts and prices /// @dev Credit to Uniswap Labs under GPL-2.0-or-later license: /// https://github.com/Uniswap/v3-periphery library LiquidityAmounts { /// @notice Downcasts uint256 to uint128 /// @param x The uint258 to be downcasted /// @return y The passed value, downcasted to uint128 function toUint128(uint256 x) private pure returns (uint128 y) { require((y = uint128(x)) == x); } /// @notice Computes the amount of liquidity received for a given amount of token0 and price range /// @dev Calculates amount0 * (sqrt(upper) * sqrt(lower)) / (sqrt(upper) - sqrt(lower)) /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary /// @param amount0 The amount0 being sent in /// @return liquidity The amount of returned liquidity function getLiquidityForAmount0( uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint256 amount0 ) internal pure returns (uint128 liquidity) { if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); uint256 intermediate = FullMath.mulDiv(sqrtRatioAX96, sqrtRatioBX96, Constants.Q96); return toUint128(FullMath.mulDiv(amount0, intermediate, sqrtRatioBX96 - sqrtRatioAX96)); } /// @notice Computes the amount of liquidity received for a given amount of token1 and price range /// @dev Calculates amount1 / (sqrt(upper) - sqrt(lower)). /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary /// @param amount1 The amount1 being sent in /// @return liquidity The amount of returned liquidity function getLiquidityForAmount1( uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint256 amount1 ) internal pure returns (uint128 liquidity) { if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); return toUint128(FullMath.mulDiv(amount1, Constants.Q96, sqrtRatioBX96 - sqrtRatioAX96)); } /// @notice Computes the maximum amount of liquidity received for a given amount of token0, token1, the current /// pool prices and the prices at the tick boundaries /// @param sqrtRatioX96 A sqrt price representing the current pool prices /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary /// @param amount0 The amount of token0 being sent in /// @param amount1 The amount of token1 being sent in /// @return liquidity The maximum amount of liquidity received function getLiquidityForAmounts( uint160 sqrtRatioX96, uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint256 amount0, uint256 amount1 ) internal pure returns (uint128 liquidity) { if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); if (sqrtRatioX96 <= sqrtRatioAX96) { liquidity = getLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, amount0); } else if (sqrtRatioX96 < sqrtRatioBX96) { uint128 liquidity0 = getLiquidityForAmount0(sqrtRatioX96, sqrtRatioBX96, amount0); uint128 liquidity1 = getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioX96, amount1); liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1; } else { liquidity = getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1); } } /// @notice Computes the amount of token0 for a given amount of liquidity and a price range /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary /// @param liquidity The liquidity being valued /// @return amount0 The amount of token0 function getAmount0ForLiquidity( uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity ) internal pure returns (uint256 amount0) { if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); return FullMath.mulDiv(uint256(liquidity) << Constants.RESOLUTION, sqrtRatioBX96 - sqrtRatioAX96, sqrtRatioBX96) / sqrtRatioAX96; } /// @notice Computes the amount of token1 for a given amount of liquidity and a price range /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary /// @param liquidity The liquidity being valued /// @return amount1 The amount of token1 function getAmount1ForLiquidity( uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity ) internal pure returns (uint256 amount1) { if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); return FullMath.mulDiv(liquidity, sqrtRatioBX96 - sqrtRatioAX96, Constants.Q96); } /// @notice Computes the token0 and token1 value for a given amount of liquidity, the current /// pool prices and the prices at the tick boundaries /// @param sqrtRatioX96 A sqrt price representing the current pool prices /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary /// @param liquidity The liquidity being valued /// @return amount0 The amount of token0 /// @return amount1 The amount of token1 function getAmountsForLiquidity( uint160 sqrtRatioX96, uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity ) internal pure returns (uint256 amount0, uint256 amount1) { if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); if (sqrtRatioX96 <= sqrtRatioAX96) { amount0 = getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity); } else if (sqrtRatioX96 < sqrtRatioBX96) { amount0 = getAmount0ForLiquidity(sqrtRatioX96, sqrtRatioBX96, liquidity); amount1 = getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioX96, liquidity); } else { amount1 = getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity); } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.7.6; import './FullMath.sol'; import './TokenDeltaMath.sol'; /// @title Computes the result of price movement /// @notice Contains methods for computing the result of price movement within a single tick price range. library PriceMovementMath { using LowGasSafeMath for uint256; using SafeCast for uint256; /// @notice Gets the next sqrt price given an input amount of token0 or token1 /// @dev Throws if price or liquidity are 0, or if the next price is out of bounds /// @param price The starting Q64.96 sqrt price, i.e., before accounting for the input amount /// @param liquidity The amount of usable liquidity /// @param input How much of token0, or token1, is being swapped in /// @param zeroToOne Whether the amount in is token0 or token1 /// @return resultPrice The Q64.96 sqrt price after adding the input amount to token0 or token1 function getNewPriceAfterInput( uint160 price, uint128 liquidity, uint256 input, bool zeroToOne ) internal pure returns (uint160 resultPrice) { return getNewPrice(price, liquidity, input, zeroToOne, true); } /// @notice Gets the next sqrt price given an output amount of token0 or token1 /// @dev Throws if price or liquidity are 0 or the next price is out of bounds /// @param price The starting Q64.96 sqrt price before accounting for the output amount /// @param liquidity The amount of usable liquidity /// @param output How much of token0, or token1, is being swapped out /// @param zeroToOne Whether the amount out is token0 or token1 /// @return resultPrice The Q64.96 sqrt price after removing the output amount of token0 or token1 function getNewPriceAfterOutput( uint160 price, uint128 liquidity, uint256 output, bool zeroToOne ) internal pure returns (uint160 resultPrice) { return getNewPrice(price, liquidity, output, zeroToOne, false); } function getNewPrice( uint160 price, uint128 liquidity, uint256 amount, bool zeroToOne, bool fromInput ) internal pure returns (uint160 resultPrice) { require(price > 0); require(liquidity > 0); if (zeroToOne == fromInput) { // rounding up or down if (amount == 0) return price; uint256 liquidityShifted = uint256(liquidity) << Constants.RESOLUTION; if (fromInput) { uint256 product; if ((product = amount * price) / amount == price) { uint256 denominator = liquidityShifted + product; if (denominator >= liquidityShifted) return uint160(FullMath.mulDivRoundingUp(liquidityShifted, price, denominator)); // always fits in 160 bits } return uint160(FullMath.divRoundingUp(liquidityShifted, (liquidityShifted / price).add(amount))); } else { uint256 product; require((product = amount * price) / amount == price); // if the product overflows, we know the denominator underflows require(liquidityShifted > product); // in addition, we must check that the denominator does not underflow return FullMath.mulDivRoundingUp(liquidityShifted, price, liquidityShifted - product).toUint160(); } } else { // if we're adding (subtracting), rounding down requires rounding the quotient down (up) // in both cases, avoid a mulDiv for most inputs if (fromInput) { return uint256(price) .add(amount <= type(uint160).max ? (amount << Constants.RESOLUTION) / liquidity : FullMath.mulDiv(amount, Constants.Q96, liquidity)) .toUint160(); } else { uint256 quotient = amount <= type(uint160).max ? FullMath.divRoundingUp(amount << Constants.RESOLUTION, liquidity) : FullMath.mulDivRoundingUp(amount, Constants.Q96, liquidity); require(price > quotient); return uint160(price - quotient); // always fits 160 bits } } } function getTokenADelta01( uint160 to, uint160 from, uint128 liquidity ) internal pure returns (uint256) { return TokenDeltaMath.getToken0Delta(to, from, liquidity, true); } function getTokenADelta10( uint160 to, uint160 from, uint128 liquidity ) internal pure returns (uint256) { return TokenDeltaMath.getToken1Delta(from, to, liquidity, true); } function getTokenBDelta01( uint160 to, uint160 from, uint128 liquidity ) internal pure returns (uint256) { return TokenDeltaMath.getToken1Delta(to, from, liquidity, false); } function getTokenBDelta10( uint160 to, uint160 from, uint128 liquidity ) internal pure returns (uint256) { return TokenDeltaMath.getToken0Delta(from, to, liquidity, false); } /// @notice Computes the result of swapping some amount in, or amount out, given the parameters of the swap /// @dev The fee, plus the amount in, will never exceed the amount remaining if the swap's `amountSpecified` is positive /// @param currentPrice The current Q64.96 sqrt price of the pool /// @param targetPrice The Q64.96 sqrt price that cannot be exceeded, from which the direction of the swap is inferred /// @param liquidity The usable liquidity /// @param amountAvailable How much input or output amount is remaining to be swapped in/out /// @param fee The fee taken from the input amount, expressed in hundredths of a bip /// @return resultPrice The Q64.96 sqrt price after swapping the amount in/out, not to exceed the price target /// @return input The amount to be swapped in, of either token0 or token1, based on the direction of the swap /// @return output The amount to be received, of either token0 or token1, based on the direction of the swap /// @return feeAmount The amount of input that will be taken as a fee function movePriceTowardsTarget( bool zeroToOne, uint160 currentPrice, uint160 targetPrice, uint128 liquidity, int256 amountAvailable, uint16 fee ) internal pure returns ( uint160 resultPrice, uint256 input, uint256 output, uint256 feeAmount ) { function(uint160, uint160, uint128) pure returns (uint256) getAmountA = zeroToOne ? getTokenADelta01 : getTokenADelta10; if (amountAvailable >= 0) { // exactIn or not uint256 amountAvailableAfterFee = FullMath.mulDiv(uint256(amountAvailable), 1e6 - fee, 1e6); input = getAmountA(targetPrice, currentPrice, liquidity); if (amountAvailableAfterFee >= input) { resultPrice = targetPrice; feeAmount = FullMath.mulDivRoundingUp(input, fee, 1e6 - fee); } else { resultPrice = getNewPriceAfterInput(currentPrice, liquidity, amountAvailableAfterFee, zeroToOne); if (targetPrice != resultPrice) { input = getAmountA(resultPrice, currentPrice, liquidity); // we didn't reach the target, so take the remainder of the maximum input as fee feeAmount = uint256(amountAvailable) - input; } else { feeAmount = FullMath.mulDivRoundingUp(input, fee, 1e6 - fee); } } output = (zeroToOne ? getTokenBDelta01 : getTokenBDelta10)(resultPrice, currentPrice, liquidity); } else { function(uint160, uint160, uint128) pure returns (uint256) getAmountB = zeroToOne ? getTokenBDelta01 : getTokenBDelta10; output = getAmountB(targetPrice, currentPrice, liquidity); amountAvailable = -amountAvailable; if (uint256(amountAvailable) >= output) resultPrice = targetPrice; else { resultPrice = getNewPriceAfterOutput(currentPrice, liquidity, uint256(amountAvailable), zeroToOne); if (targetPrice != resultPrice) { output = getAmountB(resultPrice, currentPrice, liquidity); } // cap the output amount to not exceed the remaining output amount if (output > uint256(amountAvailable)) { output = uint256(amountAvailable); } } input = getAmountA(resultPrice, currentPrice, liquidity); feeAmount = FullMath.mulDivRoundingUp(input, fee, 1e6 - fee); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.0; /// @title Contains 512-bit math functions /// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision /// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits library FullMath { /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return result The 256-bit result /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv function mulDiv( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256 result) { // 512-bit multiply [prod1 prod0] = a * b // Compute the product mod 2**256 and mod 2**256 - 1 // then use the Chinese Remainder Theorem to reconstruct // the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2**256 + prod0 uint256 prod0 = a * b; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(a, b, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Make sure the result is less than 2**256. // Also prevents denominator == 0 require(denominator > prod1); // Handle non-overflow cases, 256 by 256 division if (prod1 == 0) { assembly { result := div(prod0, denominator) } return result; } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0] // Compute remainder using mulmod // Subtract 256 bit remainder from 512 bit number assembly { let remainder := mulmod(a, b, denominator) prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator // Compute largest power of two divisor of denominator. // Always >= 1. uint256 twos = -denominator & denominator; // Divide denominator by power of two assembly { denominator := div(denominator, twos) } // Divide [prod1 prod0] by the factors of two assembly { prod0 := div(prod0, twos) } // Shift in bits from prod1 into prod0. For this we need // to flip `twos` such that it is 2**256 / twos. // If twos is zero, then it becomes one assembly { twos := add(div(sub(0, twos), twos), 1) } prod0 |= prod1 * twos; // Invert denominator mod 2**256 // Now that denominator is an odd number, it has an inverse // modulo 2**256 such that denominator * inv = 1 mod 2**256. // Compute the inverse by starting with a seed that is correct // correct for four bits. That is, denominator * inv = 1 mod 2**4 uint256 inv = (3 * denominator) ^ 2; // Now use Newton-Raphson iteration to improve the precision. // Thanks to Hensel's lifting lemma, this also works in modular // arithmetic, doubling the correct bits in each step. inv *= 2 - denominator * inv; // inverse mod 2**8 inv *= 2 - denominator * inv; // inverse mod 2**16 inv *= 2 - denominator * inv; // inverse mod 2**32 inv *= 2 - denominator * inv; // inverse mod 2**64 inv *= 2 - denominator * inv; // inverse mod 2**128 inv *= 2 - denominator * inv; // inverse mod 2**256 // Because the division is now exact we can divide by multiplying // with the modular inverse of denominator. This will give us the // correct result modulo 2**256. Since the preconditions guarantee // that the outcome is less than 2**256, this is the final result. // We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inv; return result; } /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return result The 256-bit result function mulDivRoundingUp( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256 result) { if (a == 0 || ((result = a * b) / a == b)) { require(denominator > 0); assembly { result := add(div(result, denominator), gt(mod(result, denominator), 0)) } } else { result = mulDiv(a, b, denominator); if (mulmod(a, b, denominator) > 0) { require(result < type(uint256).max); result++; } } } /// @notice Returns ceil(x / y) /// @dev division by 0 has unspecified behavior, and must be checked externally /// @param x The dividend /// @param y The divisor /// @return z The quotient, ceil(x / y) function divRoundingUp(uint256 x, uint256 y) internal pure returns (uint256 z) { assembly { z := add(div(x, y), gt(mod(x, y), 0)) } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; import './pool/IAlgebraPoolImmutables.sol'; import './pool/IAlgebraPoolState.sol'; import './pool/IAlgebraPoolDerivedState.sol'; import './pool/IAlgebraPoolActions.sol'; import './pool/IAlgebraPoolPermissionedActions.sol'; import './pool/IAlgebraPoolEvents.sol'; /** * @title The interface for a Algebra Pool * @dev The pool interface is broken up into many smaller pieces. * Credit to Uniswap Labs under GPL-2.0-or-later license: * https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces */ interface IAlgebraPool is IAlgebraPoolImmutables, IAlgebraPoolState, IAlgebraPoolDerivedState, IAlgebraPoolActions, IAlgebraPoolPermissionedActions, IAlgebraPoolEvents { // used only for combining interfaces }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.7.0; /// @title Optimized overflow and underflow safe math operations /// @notice Contains methods for doing math operations that revert on overflow or underflow for minimal gas cost /// @dev Credit to Uniswap Labs under GPL-2.0-or-later license: /// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries library LowGasSafeMath { /// @notice Returns x + y, reverts if sum overflows uint256 /// @param x The augend /// @param y The addend /// @return z The sum of x and y function add(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x); } /// @notice Returns x - y, reverts if underflows /// @param x The minuend /// @param y The subtrahend /// @return z The difference of x and y function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x - y) <= x); } /// @notice Returns x * y, reverts if overflows /// @param x The multiplicand /// @param y The multiplier /// @return z The product of x and y function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(x == 0 || (z = x * y) / x == y); } /// @notice Returns x + y, reverts if overflows or underflows /// @param x The augend /// @param y The addend /// @return z The sum of x and y function add(int256 x, int256 y) internal pure returns (int256 z) { require((z = x + y) >= x == (y >= 0)); } /// @notice Returns x - y, reverts if overflows or underflows /// @param x The minuend /// @param y The subtrahend /// @return z The difference of x and y function sub(int256 x, int256 y) internal pure returns (int256 z) { require((z = x - y) <= x == (y >= 0)); } /// @notice Returns x + y, reverts if overflows or underflows /// @param x The augend /// @param y The addend /// @return z The sum of x and y function add128(uint128 x, uint128 y) internal pure returns (uint128 z) { require((z = x + y) >= x); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity =0.7.6; library Constants { uint8 internal constant RESOLUTION = 96; uint256 internal constant Q96 = 0x1000000000000000000000000; uint256 internal constant Q128 = 0x100000000000000000000000000000000; // fee value in hundredths of a bip, i.e. 1e-6 uint16 internal constant BASE_FEE = 100; int24 internal constant TICK_SPACING = 60; // max(uint128) / ( (MAX_TICK - MIN_TICK) / TICK_SPACING ) uint128 internal constant MAX_LIQUIDITY_PER_TICK = 11505743598341114571880798222544994; uint32 internal constant MAX_LIQUIDITY_COOLDOWN = 1 days; uint8 internal constant MAX_COMMUNITY_FEE = 250; uint256 internal constant COMMUNITY_FEE_DENOMINATOR = 1000; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.7.6; import './LowGasSafeMath.sol'; import './SafeCast.sol'; import './FullMath.sol'; import './Constants.sol'; /// @title Functions based on Q64.96 sqrt price and liquidity /// @notice Contains the math that uses square root of price as a Q64.96 and liquidity to compute deltas library TokenDeltaMath { using LowGasSafeMath for uint256; using SafeCast for uint256; /// @notice Gets the token0 delta between two prices /// @dev Calculates liquidity / sqrt(lower) - liquidity / sqrt(upper) /// @param priceLower A Q64.96 sqrt price /// @param priceUpper Another Q64.96 sqrt price /// @param liquidity The amount of usable liquidity /// @param roundUp Whether to round the amount up or down /// @return token0Delta Amount of token0 required to cover a position of size liquidity between the two passed prices function getToken0Delta( uint160 priceLower, uint160 priceUpper, uint128 liquidity, bool roundUp ) internal pure returns (uint256 token0Delta) { uint256 priceDelta = priceUpper - priceLower; require(priceDelta < priceUpper); // forbids underflow and 0 priceLower uint256 liquidityShifted = uint256(liquidity) << Constants.RESOLUTION; token0Delta = roundUp ? FullMath.divRoundingUp(FullMath.mulDivRoundingUp(priceDelta, liquidityShifted, priceUpper), priceLower) : FullMath.mulDiv(priceDelta, liquidityShifted, priceUpper) / priceLower; } /// @notice Gets the token1 delta between two prices /// @dev Calculates liquidity * (sqrt(upper) - sqrt(lower)) /// @param priceLower A Q64.96 sqrt price /// @param priceUpper Another Q64.96 sqrt price /// @param liquidity The amount of usable liquidity /// @param roundUp Whether to round the amount up, or down /// @return token1Delta Amount of token1 required to cover a position of size liquidity between the two passed prices function getToken1Delta( uint160 priceLower, uint160 priceUpper, uint128 liquidity, bool roundUp ) internal pure returns (uint256 token1Delta) { require(priceUpper >= priceLower); uint256 priceDelta = priceUpper - priceLower; token1Delta = roundUp ? FullMath.mulDivRoundingUp(priceDelta, liquidity, Constants.Q96) : FullMath.mulDiv(priceDelta, liquidity, Constants.Q96); } /// @notice Helper that gets signed token0 delta /// @param priceLower A Q64.96 sqrt price /// @param priceUpper Another Q64.96 sqrt price /// @param liquidity The change in liquidity for which to compute the token0 delta /// @return token0Delta Amount of token0 corresponding to the passed liquidityDelta between the two prices function getToken0Delta( uint160 priceLower, uint160 priceUpper, int128 liquidity ) internal pure returns (int256 token0Delta) { token0Delta = liquidity >= 0 ? getToken0Delta(priceLower, priceUpper, uint128(liquidity), true).toInt256() : -getToken0Delta(priceLower, priceUpper, uint128(-liquidity), false).toInt256(); } /// @notice Helper that gets signed token1 delta /// @param priceLower A Q64.96 sqrt price /// @param priceUpper Another Q64.96 sqrt price /// @param liquidity The change in liquidity for which to compute the token1 delta /// @return token1Delta Amount of token1 corresponding to the passed liquidityDelta between the two prices function getToken1Delta( uint160 priceLower, uint160 priceUpper, int128 liquidity ) internal pure returns (int256 token1Delta) { token1Delta = liquidity >= 0 ? getToken1Delta(priceLower, priceUpper, uint128(liquidity), true).toInt256() : -getToken1Delta(priceLower, priceUpper, uint128(-liquidity), false).toInt256(); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title Safe casting methods /// @notice Contains methods for safely casting between types /// @dev Credit to Uniswap Labs under GPL-2.0-or-later license: /// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries library SafeCast { /// @notice Cast a uint256 to a uint160, revert on overflow /// @param y The uint256 to be downcasted /// @return z The downcasted integer, now type uint160 function toUint160(uint256 y) internal pure returns (uint160 z) { require((z = uint160(y)) == y); } /// @notice Cast a int256 to a int128, revert on overflow or underflow /// @param y The int256 to be downcasted /// @return z The downcasted integer, now type int128 function toInt128(int256 y) internal pure returns (int128 z) { require((z = int128(y)) == y); } /// @notice Cast a uint256 to a int256, revert on overflow /// @param y The uint256 to be casted /// @return z The casted integer, now type int256 function toInt256(uint256 y) internal pure returns (int256 z) { require(y < 2**255); z = int256(y); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; import '../IDataStorageOperator.sol'; /// @title Pool state that never changes /// @dev Credit to Uniswap Labs under GPL-2.0-or-later license: /// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces interface IAlgebraPoolImmutables { /** * @notice The contract that stores all the timepoints and can perform actions with them * @return The operator address */ function dataStorageOperator() external view returns (address); /** * @notice The contract that deployed the pool, which must adhere to the IAlgebraFactory interface * @return The contract address */ function factory() external view returns (address); /** * @notice The first of the two tokens of the pool, sorted by address * @return The token contract address */ function token0() external view returns (address); /** * @notice The second of the two tokens of the pool, sorted by address * @return The token contract address */ function token1() external view returns (address); /** * @notice The pool tick spacing * @dev Ticks can only be used at multiples of this value * e.g.: a tickSpacing of 60 means ticks can be initialized every 60th tick, i.e., ..., -120, -60, 0, 60, 120, ... * This value is an int24 to avoid casting even though it is always positive. * @return The tick spacing */ function tickSpacing() external view returns (int24); /** * @notice The maximum amount of position liquidity that can use any tick in the range * @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and * also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool * @return The max amount of liquidity per tick */ function maxLiquidityPerTick() external view returns (uint128); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title Pool state that can change /// @dev Credit to Uniswap Labs under GPL-2.0-or-later license: /// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces interface IAlgebraPoolState { /** * @notice The globalState structure in the pool stores many values but requires only one slot * and is exposed as a single method to save gas when accessed externally. * @return price The current price of the pool as a sqrt(token1/token0) Q64.96 value; * Returns tick The current tick of the pool, i.e. according to the last tick transition that was run; * Returns This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(price) if the price is on a tick * boundary; * Returns fee The last pool fee value in hundredths of a bip, i.e. 1e-6; * Returns timepointIndex The index of the last written timepoint; * Returns communityFeeToken0 The community fee percentage of the swap fee in thousandths (1e-3) for token0; * Returns communityFeeToken1 The community fee percentage of the swap fee in thousandths (1e-3) for token1; * Returns unlocked Whether the pool is currently locked to reentrancy; */ function globalState() external view returns ( uint160 price, int24 tick, uint16 fee, uint16 timepointIndex, uint8 communityFeeToken0, uint8 communityFeeToken1, bool unlocked ); /** * @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool * @dev This value can overflow the uint256 */ function totalFeeGrowth0Token() external view returns (uint256); /** * @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool * @dev This value can overflow the uint256 */ function totalFeeGrowth1Token() external view returns (uint256); /** * @notice The currently in range liquidity available to the pool * @dev This value has no relationship to the total liquidity across all ticks. * Returned value cannot exceed type(uint128).max */ function liquidity() external view returns (uint128); /** * @notice Look up information about a specific tick in the pool * @dev This is a public structure, so the `return` natspec tags are omitted. * @param tick The tick to look up * @return liquidityTotal the total amount of position liquidity that uses the pool either as tick lower or * tick upper; * Returns liquidityDelta how much liquidity changes when the pool price crosses the tick; * Returns outerFeeGrowth0Token the fee growth on the other side of the tick from the current tick in token0; * Returns outerFeeGrowth1Token the fee growth on the other side of the tick from the current tick in token1; * Returns outerTickCumulative the cumulative tick value on the other side of the tick from the current tick; * Returns outerSecondsPerLiquidity the seconds spent per liquidity on the other side of the tick from the current tick; * Returns outerSecondsSpent the seconds spent on the other side of the tick from the current tick; * Returns initialized Set to true if the tick is initialized, i.e. liquidityTotal is greater than 0 * otherwise equal to false. Outside values can only be used if the tick is initialized. * In addition, these values are only relative and must be used only in comparison to previous snapshots for * a specific position. */ function ticks(int24 tick) external view returns ( uint128 liquidityTotal, int128 liquidityDelta, uint256 outerFeeGrowth0Token, uint256 outerFeeGrowth1Token, int56 outerTickCumulative, uint160 outerSecondsPerLiquidity, uint32 outerSecondsSpent, bool initialized ); /** @notice Returns 256 packed tick initialized boolean values. See TickTable for more information */ function tickTable(int16 wordPosition) external view returns (uint256); /** * @notice Returns the information about a position by the position's key * @dev This is a public mapping of structures, so the `return` natspec tags are omitted. * @param key The position's key is a hash of a preimage composed by the owner, bottomTick and topTick * @return liquidityAmount The amount of liquidity in the position; * Returns lastLiquidityAddTimestamp Timestamp of last adding of liquidity; * Returns innerFeeGrowth0Token Fee growth of token0 inside the tick range as of the last mint/burn/poke; * Returns innerFeeGrowth1Token Fee growth of token1 inside the tick range as of the last mint/burn/poke; * Returns fees0 The computed amount of token0 owed to the position as of the last mint/burn/poke; * Returns fees1 The computed amount of token1 owed to the position as of the last mint/burn/poke */ function positions(bytes32 key) external view returns ( uint128 liquidityAmount, uint32 lastLiquidityAddTimestamp, uint256 innerFeeGrowth0Token, uint256 innerFeeGrowth1Token, uint128 fees0, uint128 fees1 ); /** * @notice Returns data about a specific timepoint index * @param index The element of the timepoints array to fetch * @dev You most likely want to use #getTimepoints() instead of this method to get an timepoint as of some amount of time * ago, rather than at a specific index in the array. * This is a public mapping of structures, so the `return` natspec tags are omitted. * @return initialized whether the timepoint has been initialized and the values are safe to use; * Returns blockTimestamp The timestamp of the timepoint; * Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the timepoint timestamp; * Returns secondsPerLiquidityCumulative the seconds per in range liquidity for the life of the pool as of the timepoint timestamp; * Returns volatilityCumulative Cumulative standard deviation for the life of the pool as of the timepoint timestamp; * Returns averageTick Time-weighted average tick; * Returns volumePerLiquidityCumulative Cumulative swap volume per liquidity for the life of the pool as of the timepoint timestamp; */ function timepoints(uint256 index) external view returns ( bool initialized, uint32 blockTimestamp, int56 tickCumulative, uint160 secondsPerLiquidityCumulative, uint88 volatilityCumulative, int24 averageTick, uint144 volumePerLiquidityCumulative ); /** * @notice Returns the information about active incentive * @dev if there is no active incentive at the moment, virtualPool,endTimestamp,startTimestamp would be equal to 0 * @return virtualPool The address of a virtual pool associated with the current active incentive */ function activeIncentive() external view returns (address virtualPool); /** * @notice Returns the lock time for added liquidity */ function liquidityCooldown() external view returns (uint32 cooldownInSeconds); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /** * @title Pool state that is not stored * @notice Contains view functions to provide information about the pool that is computed rather than stored on the * blockchain. The functions here may have variable gas costs. * @dev Credit to Uniswap Labs under GPL-2.0-or-later license: * https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces */ interface IAlgebraPoolDerivedState { /** * @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp * @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing * the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick, * you must call it with secondsAgos = [3600, 0]. * @dev The time weighted average tick represents the geometric time weighted average price of the pool, in * log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio. * @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned * @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp * @return secondsPerLiquidityCumulatives Cumulative seconds per liquidity-in-range value as of each `secondsAgos` * from the current block timestamp * @return volatilityCumulatives Cumulative standard deviation as of each `secondsAgos` * @return volumePerAvgLiquiditys Cumulative swap volume per liquidity as of each `secondsAgos` */ function getTimepoints(uint32[] calldata secondsAgos) external view returns ( int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulatives, uint112[] memory volatilityCumulatives, uint256[] memory volumePerAvgLiquiditys ); /** * @notice Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range * @dev Snapshots must only be compared to other snapshots, taken over a period for which a position existed. * I.e., snapshots cannot be compared if a position is not held for the entire period between when the first * snapshot is taken and the second snapshot is taken. * @param bottomTick The lower tick of the range * @param topTick The upper tick of the range * @return innerTickCumulative The snapshot of the tick accumulator for the range * @return innerSecondsSpentPerLiquidity The snapshot of seconds per liquidity for the range * @return innerSecondsSpent The snapshot of the number of seconds during which the price was in this range */ function getInnerCumulatives(int24 bottomTick, int24 topTick) external view returns ( int56 innerTickCumulative, uint160 innerSecondsSpentPerLiquidity, uint32 innerSecondsSpent ); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title Permissionless pool actions /// @dev Credit to Uniswap Labs under GPL-2.0-or-later license: /// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces interface IAlgebraPoolActions { /** * @notice Sets the initial price for the pool * @dev Price is represented as a sqrt(amountToken1/amountToken0) Q64.96 value * @param price the initial sqrt price of the pool as a Q64.96 */ function initialize(uint160 price) external; /** * @notice Adds liquidity for the given recipient/bottomTick/topTick position * @dev The caller of this method receives a callback in the form of IAlgebraMintCallback# AlgebraMintCallback * in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends * on bottomTick, topTick, the amount of liquidity, and the current price. * @param sender The address which will receive potential surplus of paid tokens * @param recipient The address for which the liquidity will be created * @param bottomTick The lower tick of the position in which to add liquidity * @param topTick The upper tick of the position in which to add liquidity * @param amount The desired amount of liquidity to mint * @param data Any data that should be passed through to the callback * @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback * @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback * @return liquidityActual The actual minted amount of liquidity */ function mint( address sender, address recipient, int24 bottomTick, int24 topTick, uint128 amount, bytes calldata data ) external returns ( uint256 amount0, uint256 amount1, uint128 liquidityActual ); /** * @notice Collects tokens owed to a position * @dev Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity. * Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or * amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the * actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity. * @param recipient The address which should receive the fees collected * @param bottomTick The lower tick of the position for which to collect fees * @param topTick The upper tick of the position for which to collect fees * @param amount0Requested How much token0 should be withdrawn from the fees owed * @param amount1Requested How much token1 should be withdrawn from the fees owed * @return amount0 The amount of fees collected in token0 * @return amount1 The amount of fees collected in token1 */ function collect( address recipient, int24 bottomTick, int24 topTick, uint128 amount0Requested, uint128 amount1Requested ) external returns (uint128 amount0, uint128 amount1); /** * @notice Burn liquidity from the sender and account tokens owed for the liquidity to the position * @dev Can be used to trigger a recalculation of fees owed to a position by calling with an amount of 0 * @dev Fees must be collected separately via a call to #collect * @param bottomTick The lower tick of the position for which to burn liquidity * @param topTick The upper tick of the position for which to burn liquidity * @param amount How much liquidity to burn * @return amount0 The amount of token0 sent to the recipient * @return amount1 The amount of token1 sent to the recipient */ function burn( int24 bottomTick, int24 topTick, uint128 amount ) external returns (uint256 amount0, uint256 amount1); /** * @notice Swap token0 for token1, or token1 for token0 * @dev The caller of this method receives a callback in the form of IAlgebraSwapCallback# AlgebraSwapCallback * @param recipient The address to receive the output of the swap * @param zeroToOne The direction of the swap, true for token0 to token1, false for token1 to token0 * @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative) * @param limitSqrtPrice The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this * value after the swap. If one for zero, the price cannot be greater than this value after the swap * @param data Any data to be passed through to the callback. If using the Router it should contain * SwapRouter#SwapCallbackData * @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive * @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive */ function swap( address recipient, bool zeroToOne, int256 amountSpecified, uint160 limitSqrtPrice, bytes calldata data ) external returns (int256 amount0, int256 amount1); /** * @notice Swap token0 for token1, or token1 for token0 (tokens that have fee on transfer) * @dev The caller of this method receives a callback in the form of I AlgebraSwapCallback# AlgebraSwapCallback * @param sender The address called this function (Comes from the Router) * @param recipient The address to receive the output of the swap * @param zeroToOne The direction of the swap, true for token0 to token1, false for token1 to token0 * @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative) * @param limitSqrtPrice The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this * value after the swap. If one for zero, the price cannot be greater than this value after the swap * @param data Any data to be passed through to the callback. If using the Router it should contain * SwapRouter#SwapCallbackData * @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive * @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive */ function swapSupportingFeeOnInputTokens( address sender, address recipient, bool zeroToOne, int256 amountSpecified, uint160 limitSqrtPrice, bytes calldata data ) external returns (int256 amount0, int256 amount1); /** * @notice Receive token0 and/or token1 and pay it back, plus a fee, in the callback * @dev The caller of this method receives a callback in the form of IAlgebraFlashCallback# AlgebraFlashCallback * @dev All excess tokens paid in the callback are distributed to liquidity providers as an additional fee. So this method can be used * to donate underlying tokens to currently in-range liquidity providers by calling with 0 amount{0,1} and sending * the donation amount(s) from the callback * @param recipient The address which will receive the token0 and token1 amounts * @param amount0 The amount of token0 to send * @param amount1 The amount of token1 to send * @param data Any data to be passed through to the callback */ function flash( address recipient, uint256 amount0, uint256 amount1, bytes calldata data ) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /** * @title Permissioned pool actions * @notice Contains pool methods that may only be called by the factory owner or tokenomics * @dev Credit to Uniswap Labs under GPL-2.0-or-later license: * https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces */ interface IAlgebraPoolPermissionedActions { /** * @notice Set the community's % share of the fees. Cannot exceed 25% (250) * @param communityFee0 new community fee percent for token0 of the pool in thousandths (1e-3) * @param communityFee1 new community fee percent for token1 of the pool in thousandths (1e-3) */ function setCommunityFee(uint8 communityFee0, uint8 communityFee1) external; /** * @notice Sets an active incentive * @param virtualPoolAddress The address of a virtual pool associated with the incentive */ function setIncentive(address virtualPoolAddress) external; /** * @notice Sets new lock time for added liquidity * @param newLiquidityCooldown The time in seconds */ function setLiquidityCooldown(uint32 newLiquidityCooldown) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title Events emitted by a pool /// @dev Credit to Uniswap Labs under GPL-2.0-or-later license: /// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces interface IAlgebraPoolEvents { /** * @notice Emitted exactly once by a pool when #initialize is first called on the pool * @dev Mint/Burn/Swap cannot be emitted by the pool before Initialize * @param price The initial sqrt price of the pool, as a Q64.96 * @param tick The initial tick of the pool, i.e. log base 1.0001 of the starting price of the pool */ event Initialize(uint160 price, int24 tick); /** * @notice Emitted when liquidity is minted for a given position * @param sender The address that minted the liquidity * @param owner The owner of the position and recipient of any minted liquidity * @param bottomTick The lower tick of the position * @param topTick The upper tick of the position * @param liquidityAmount The amount of liquidity minted to the position range * @param amount0 How much token0 was required for the minted liquidity * @param amount1 How much token1 was required for the minted liquidity */ event Mint( address sender, address indexed owner, int24 indexed bottomTick, int24 indexed topTick, uint128 liquidityAmount, uint256 amount0, uint256 amount1 ); /** * @notice Emitted when fees are collected by the owner of a position * @dev Collect events may be emitted with zero amount0 and amount1 when the caller chooses not to collect fees * @param owner The owner of the position for which fees are collected * @param recipient The address that received fees * @param bottomTick The lower tick of the position * @param topTick The upper tick of the position * @param amount0 The amount of token0 fees collected * @param amount1 The amount of token1 fees collected */ event Collect(address indexed owner, address recipient, int24 indexed bottomTick, int24 indexed topTick, uint128 amount0, uint128 amount1); /** * @notice Emitted when a position's liquidity is removed * @dev Does not withdraw any fees earned by the liquidity position, which must be withdrawn via #collect * @param owner The owner of the position for which liquidity is removed * @param bottomTick The lower tick of the position * @param topTick The upper tick of the position * @param liquidityAmount The amount of liquidity to remove * @param amount0 The amount of token0 withdrawn * @param amount1 The amount of token1 withdrawn */ event Burn(address indexed owner, int24 indexed bottomTick, int24 indexed topTick, uint128 liquidityAmount, uint256 amount0, uint256 amount1); /** * @notice Emitted by the pool for any swaps between token0 and token1 * @param sender The address that initiated the swap call, and that received the callback * @param recipient The address that received the output of the swap * @param amount0 The delta of the token0 balance of the pool * @param amount1 The delta of the token1 balance of the pool * @param price The sqrt(price) of the pool after the swap, as a Q64.96 * @param liquidity The liquidity of the pool after the swap * @param tick The log base 1.0001 of price of the pool after the swap */ event Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 price, uint128 liquidity, int24 tick); /** * @notice Emitted by the pool for any flashes of token0/token1 * @param sender The address that initiated the swap call, and that received the callback * @param recipient The address that received the tokens from flash * @param amount0 The amount of token0 that was flashed * @param amount1 The amount of token1 that was flashed * @param paid0 The amount of token0 paid for the flash, which can exceed the amount0 plus the fee * @param paid1 The amount of token1 paid for the flash, which can exceed the amount1 plus the fee */ event Flash(address indexed sender, address indexed recipient, uint256 amount0, uint256 amount1, uint256 paid0, uint256 paid1); /** * @notice Emitted when the community fee is changed by the pool * @param communityFee0New The updated value of the token0 community fee percent * @param communityFee1New The updated value of the token1 community fee percent */ event CommunityFee(uint8 communityFee0New, uint8 communityFee1New); /** * @notice Emitted when new activeIncentive is set * @param virtualPoolAddress The address of a virtual pool associated with the current active incentive */ event Incentive(address indexed virtualPoolAddress); /** * @notice Emitted when the fee changes * @param fee The value of the token fee */ event Fee(uint16 fee); /** * @notice Emitted when the LiquidityCooldown changes * @param liquidityCooldown The value of locktime for added liquidity */ event LiquidityCooldown(uint32 liquidityCooldown); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; pragma abicoder v2; import '../libraries/AdaptiveFee.sol'; interface IDataStorageOperator { event FeeConfiguration(AdaptiveFee.Configuration feeConfig); /** * @notice Returns data belonging to a certain timepoint * @param index The index of timepoint in the array * @dev There is more convenient function to fetch a timepoint: observe(). Which requires not an index but seconds * @return initialized Whether the timepoint has been initialized and the values are safe to use, * blockTimestamp The timestamp of the observation, * tickCumulative The tick multiplied by seconds elapsed for the life of the pool as of the timepoint timestamp, * secondsPerLiquidityCumulative The seconds per in range liquidity for the life of the pool as of the timepoint timestamp, * volatilityCumulative Cumulative standard deviation for the life of the pool as of the timepoint timestamp, * averageTick Time-weighted average tick, * volumePerLiquidityCumulative Cumulative swap volume per liquidity for the life of the pool as of the timepoint timestamp */ function timepoints(uint256 index) external view returns ( bool initialized, uint32 blockTimestamp, int56 tickCumulative, uint160 secondsPerLiquidityCumulative, uint88 volatilityCumulative, int24 averageTick, uint144 volumePerLiquidityCumulative ); /// @notice Initialize the dataStorage array by writing the first slot. Called once for the lifecycle of the timepoints array /// @param time The time of the dataStorage initialization, via block.timestamp truncated to uint32 /// @param tick Initial tick function initialize(uint32 time, int24 tick) external; /// @dev Reverts if an timepoint at or before the desired timepoint timestamp does not exist. /// 0 may be passed as `secondsAgo' to return the current cumulative values. /// If called with a timestamp falling between two timepoints, returns the counterfactual accumulator values /// at exactly the timestamp between the two timepoints. /// @param time The current block timestamp /// @param secondsAgo The amount of time to look back, in seconds, at which point to return an timepoint /// @param tick The current tick /// @param index The index of the timepoint that was most recently written to the timepoints array /// @param liquidity The current in-range pool liquidity /// @return tickCumulative The cumulative tick since the pool was first initialized, as of `secondsAgo` /// @return secondsPerLiquidityCumulative The cumulative seconds / max(1, liquidity) since the pool was first initialized, as of `secondsAgo` /// @return volatilityCumulative The cumulative volatility value since the pool was first initialized, as of `secondsAgo` /// @return volumePerAvgLiquidity The cumulative volume per liquidity value since the pool was first initialized, as of `secondsAgo` function getSingleTimepoint( uint32 time, uint32 secondsAgo, int24 tick, uint16 index, uint128 liquidity ) external view returns ( int56 tickCumulative, uint160 secondsPerLiquidityCumulative, uint112 volatilityCumulative, uint256 volumePerAvgLiquidity ); /// @notice Returns the accumulator values as of each time seconds ago from the given time in the array of `secondsAgos` /// @dev Reverts if `secondsAgos` > oldest timepoint /// @param time The current block.timestamp /// @param secondsAgos Each amount of time to look back, in seconds, at which point to return an timepoint /// @param tick The current tick /// @param index The index of the timepoint that was most recently written to the timepoints array /// @param liquidity The current in-range pool liquidity /// @return tickCumulatives The cumulative tick since the pool was first initialized, as of each `secondsAgo` /// @return secondsPerLiquidityCumulatives The cumulative seconds / max(1, liquidity) since the pool was first initialized, as of each `secondsAgo` /// @return volatilityCumulatives The cumulative volatility values since the pool was first initialized, as of each `secondsAgo` /// @return volumePerAvgLiquiditys The cumulative volume per liquidity values since the pool was first initialized, as of each `secondsAgo` function getTimepoints( uint32 time, uint32[] memory secondsAgos, int24 tick, uint16 index, uint128 liquidity ) external view returns ( int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulatives, uint112[] memory volatilityCumulatives, uint256[] memory volumePerAvgLiquiditys ); /// @notice Returns average volatility in the range from time-WINDOW to time /// @param time The current block.timestamp /// @param tick The current tick /// @param index The index of the timepoint that was most recently written to the timepoints array /// @param liquidity The current in-range pool liquidity /// @return TWVolatilityAverage The average volatility in the recent range /// @return TWVolumePerLiqAverage The average volume per liquidity in the recent range function getAverages( uint32 time, int24 tick, uint16 index, uint128 liquidity ) external view returns (uint112 TWVolatilityAverage, uint256 TWVolumePerLiqAverage); /// @notice Writes an dataStorage timepoint to the array /// @dev Writable at most once per block. Index represents the most recently written element. index must be tracked externally. /// @param index The index of the timepoint that was most recently written to the timepoints array /// @param blockTimestamp The timestamp of the new timepoint /// @param tick The active tick at the time of the new timepoint /// @param liquidity The total in-range liquidity at the time of the new timepoint /// @param volumePerLiquidity The gmean(volumes)/liquidity at the time of the new timepoint /// @return indexUpdated The new index of the most recently written element in the dataStorage array function write( uint16 index, uint32 blockTimestamp, int24 tick, uint128 liquidity, uint128 volumePerLiquidity ) external returns (uint16 indexUpdated); /// @notice Changes fee configuration for the pool function changeFeeConfiguration(AdaptiveFee.Configuration calldata feeConfig) external; /// @notice Calculates gmean(volume/liquidity) for block /// @param liquidity The current in-range pool liquidity /// @param amount0 Total amount of swapped token0 /// @param amount1 Total amount of swapped token1 /// @return volumePerLiquidity gmean(volume/liquidity) capped by 100000 << 64 function calculateVolumePerLiquidity( uint128 liquidity, int256 amount0, int256 amount1 ) external pure returns (uint128 volumePerLiquidity); /// @return windowLength Length of window used to calculate averages function window() external view returns (uint32 windowLength); /// @notice Calculates fee based on combination of sigmoids /// @param time The current block.timestamp /// @param tick The current tick /// @param index The index of the timepoint that was most recently written to the timepoints array /// @param liquidity The current in-range pool liquidity /// @return fee The fee in hundredths of a bip, i.e. 1e-6 function getFee( uint32 time, int24 tick, uint16 index, uint128 liquidity ) external view returns (uint16 fee); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.7.6; import './Constants.sol'; /// @title AdaptiveFee /// @notice Calculates fee based on combination of sigmoids library AdaptiveFee { // alpha1 + alpha2 + baseFee must be <= type(uint16).max struct Configuration { uint16 alpha1; // max value of the first sigmoid uint16 alpha2; // max value of the second sigmoid uint32 beta1; // shift along the x-axis for the first sigmoid uint32 beta2; // shift along the x-axis for the second sigmoid uint16 gamma1; // horizontal stretch factor for the first sigmoid uint16 gamma2; // horizontal stretch factor for the second sigmoid uint32 volumeBeta; // shift along the x-axis for the outer volume-sigmoid uint16 volumeGamma; // horizontal stretch factor the outer volume-sigmoid uint16 baseFee; // minimum possible fee } /// @notice Calculates fee based on formula: /// baseFee + sigmoidVolume(sigmoid1(volatility, volumePerLiquidity) + sigmoid2(volatility, volumePerLiquidity)) /// maximum value capped by baseFee + alpha1 + alpha2 function getFee( uint88 volatility, uint256 volumePerLiquidity, Configuration memory config ) internal pure returns (uint16 fee) { uint256 sumOfSigmoids = sigmoid(volatility, config.gamma1, config.alpha1, config.beta1) + sigmoid(volatility, config.gamma2, config.alpha2, config.beta2); if (sumOfSigmoids > type(uint16).max) { // should be impossible, just in case sumOfSigmoids = type(uint16).max; } return uint16(config.baseFee + sigmoid(volumePerLiquidity, config.volumeGamma, uint16(sumOfSigmoids), config.volumeBeta)); // safe since alpha1 + alpha2 + baseFee _must_ be <= type(uint16).max } /// @notice calculates α / (1 + e^( (β-x) / γ)) /// that is a sigmoid with a maximum value of α, x-shifted by β, and stretched by γ /// @dev returns uint256 for fuzzy testing. Guaranteed that the result is not greater than alpha function sigmoid( uint256 x, uint16 g, uint16 alpha, uint256 beta ) internal pure returns (uint256 res) { if (x > beta) { x = x - beta; if (x >= 6 * uint256(g)) return alpha; // so x < 19 bits uint256 g8 = uint256(g)**8; // < 128 bits (8*16) uint256 ex = exp(x, g, g8); // < 155 bits res = (alpha * ex) / (g8 + ex); // in worst case: (16 + 155 bits) / 155 bits // so res <= alpha } else { x = beta - x; if (x >= 6 * uint256(g)) return 0; // so x < 19 bits uint256 g8 = uint256(g)**8; // < 128 bits (8*16) uint256 ex = g8 + exp(x, g, g8); // < 156 bits res = (alpha * g8) / ex; // in worst case: (16 + 128 bits) / 156 bits // g8 <= ex, so res <= alpha } } /// @notice calculates e^(x/g) * g^8 in a series, since (around zero): /// e^x = 1 + x + x^2/2 + ... + x^n/n! + ... /// e^(x/g) = 1 + x/g + x^2/(2*g^2) + ... + x^(n)/(g^n * n!) + ... function exp( uint256 x, uint16 g, uint256 gHighestDegree ) internal pure returns (uint256 res) { // calculating: // g**8 + x * g**7 + (x**2 * g**6) / 2 + (x**3 * g**5) / 6 + (x**4 * g**4) / 24 + (x**5 * g**3) / 120 + (x**6 * g^2) / 720 + x**7 * g / 5040 + x**8 / 40320 // x**8 < 152 bits (19*8) and g**8 < 128 bits (8*16) // so each summand < 152 bits and res < 155 bits uint256 xLowestDegree = x; res = gHighestDegree; // g**8 gHighestDegree /= g; // g**7 res += xLowestDegree * gHighestDegree; gHighestDegree /= g; // g**6 xLowestDegree *= x; // x**2 res += (xLowestDegree * gHighestDegree) / 2; gHighestDegree /= g; // g**5 xLowestDegree *= x; // x**3 res += (xLowestDegree * gHighestDegree) / 6; gHighestDegree /= g; // g**4 xLowestDegree *= x; // x**4 res += (xLowestDegree * gHighestDegree) / 24; gHighestDegree /= g; // g**3 xLowestDegree *= x; // x**5 res += (xLowestDegree * gHighestDegree) / 120; gHighestDegree /= g; // g**2 xLowestDegree *= x; // x**6 res += (xLowestDegree * gHighestDegree) / 720; xLowestDegree *= x; // x**7 res += (xLowestDegree * g) / 5040 + (xLowestDegree * x) / (40320); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; import "../../utils/Context.sol"; import "./IERC20.sol"; import "../../math/SafeMath.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ constructor (string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; _decimals = 18; } /** * @dev Returns the name of the token. */ function name() public view virtual returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual returns (uint8) { return _decimals; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Sets {decimals} to a value other than the default one of 18. * * WARNING: This function should only be called from the constructor. Most * applications that interact with token contracts will not expect * {decimals} to ever change, and may work incorrectly if it does. */ function _setupDecimals(uint8 decimals_) internal virtual { _decimals = decimals_; } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over `owner`'s tokens, * given `owner`'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for `permit`, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { // Check the signature length if (signature.length != 65) { revert("ECDSA: invalid signature length"); } // Divide the signature in r, s and v variables bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. // solhint-disable-next-line no-inline-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return recover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover-bytes32-bytes-} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "ECDSA: invalid signature 's' value"); require(v == 27 || v == 28, "ECDSA: invalid signature 'v' value"); // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); require(signer != address(0), "ECDSA: invalid signature"); return signer; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * replicates the behavior of the * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`] * JSON-RPC method. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; import "../math/SafeMath.sol"; /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {SafeMath} * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never * directly accessed. */ library Counters { using SafeMath for uint256; struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { // The {SafeMath} overflow check can be skipped here, see the comment at the top counter._value += 1; } function decrement(Counter storage counter) internal { counter._value = counter._value.sub(1); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding * they need in their contracts using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * _Available since v3.4._ */ abstract contract EIP712 { /* solhint-disable var-name-mixedcase */ // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. bytes32 private immutable _CACHED_DOMAIN_SEPARATOR; uint256 private immutable _CACHED_CHAIN_ID; bytes32 private immutable _HASHED_NAME; bytes32 private immutable _HASHED_VERSION; bytes32 private immutable _TYPE_HASH; /* solhint-enable var-name-mixedcase */ /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ constructor(string memory name, string memory version) { bytes32 hashedName = keccak256(bytes(name)); bytes32 hashedVersion = keccak256(bytes(version)); bytes32 typeHash = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); _HASHED_NAME = hashedName; _HASHED_VERSION = hashedVersion; _CACHED_CHAIN_ID = _getChainId(); _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion); _TYPE_HASH = typeHash; } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view virtual returns (bytes32) { if (_getChainId() == _CACHED_CHAIN_ID) { return _CACHED_DOMAIN_SEPARATOR; } else { return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION); } } function _buildDomainSeparator(bytes32 typeHash, bytes32 name, bytes32 version) private view returns (bytes32) { return keccak256( abi.encode( typeHash, name, version, _getChainId(), address(this) ) ); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), structHash)); } function _getChainId() private view returns (uint256 chainId) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 // solhint-disable-next-line no-inline-assembly assembly { chainId := chainid() } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } }
{ "metadata": { "bytecodeHash": "none" }, "optimizer": { "enabled": true, "runs": 10 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_pool","type":"address"},{"internalType":"address","name":"_unipilotFactory","type":"address"},{"internalType":"address","name":"_WETH","type":"address"},{"internalType":"uint16","name":"_strategytype","type":"uint16"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"CompoundFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lpShares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isReadjustLiquidity","type":"bool"},{"indexed":false,"internalType":"uint256","name":"fees0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fees1","type":"uint256"}],"name":"FeesSnapshot","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"reserves0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reserves1","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fees0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fees1","type":"uint256"}],"name":"PullLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"Withdraw","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount0Owed","type":"uint256"},{"internalType":"uint256","name":"amount1Owed","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"algebraMintCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int256","name":"amount0","type":"int256"},{"internalType":"int256","name":"amount1","type":"int256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"algebraSwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount0Desired","type":"uint256"},{"internalType":"uint256","name":"amount1Desired","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"lpShares","type":"uint256"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getPositionDetails","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"},{"internalType":"uint256","name":"fees0","type":"uint256"},{"internalType":"uint256","name":"fees1","type":"uint256"},{"internalType":"uint128","name":"baseLiquidity","type":"uint128"},{"internalType":"uint128","name":"rangeLiquidity","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getVaultInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"}],"name":"isOperator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pullLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"swapBP","type":"uint8"}],"name":"readjustLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int256","name":"swapAmount","type":"int256"},{"internalType":"bool","name":"zeroForOne","type":"bool"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"}],"name":"rebalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ticksData","outputs":[{"internalType":"int24","name":"baseTickLower","type":"int24"},{"internalType":"int24","name":"baseTickUpper","type":"int24"},{"internalType":"int24","name":"rangeTickLower","type":"int24"},{"internalType":"int24","name":"rangeTickUpper","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"}],"name":"toggleOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bool","name":"refundAsETH","type":"bool"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
6101406040527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c961012052600c805463ffffffff60d01b1963ffffffff60b01b19909116600160b01b1716600160d01b1790553480156200005f57600080fd5b50604051620055ca380380620055ca833981016040819052620000829162000597565b8180604051806040016040528060018152602001603160f81b81525084848160039080519060200190620000b89291906200040f565b508051620000ce9060049060208401906200040f565b50506005805460ff1916601217905550815160208084019190912082519183019190912060c082905260e08190527f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f62000127620003a7565b60a05262000137818484620003ab565b6080526101005250505050506001600160a01b0386166200015757600080fd5b6001600160a01b0384166200016b57600080fd5b6001600160a01b0385166200017f57600080fd5b600a80546001600160a01b038089166001600160a01b03199283161792839055600b8054898316908416179055600c805488831693169290921790915560408051630dfe168160e01b815290519290911691630dfe168191600480820192602092909190829003018186803b158015620001f857600080fd5b505afa1580156200020d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000233919062000573565b600780546001600160a01b0319166001600160a01b03928316179055600a546040805163d21220a760e01b81529051919092169163d21220a7916004808301926020929190829003018186803b1580156200028d57600080fd5b505afa158015620002a2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002c8919062000573565b600880546001600160a01b0319166001600160a01b03928316179055600a54604080516334324e9f60e21b81529051919092169163d0c93a7c916004808301926020929190829003018186803b1580156200032257600080fd5b505afa15801562000337573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200035d91906200064f565b600860146101000a81548162ffffff021916908360020b62ffffff16021790555082600c60146101000a81548161ffff021916908361ffff16021790555050505050505062000672565b4690565b6000838383620003ba620003a7565b3060405160200180868152602001858152602001848152602001838152602001826001600160a01b03168152602001955050505050506040516020818303038152906040528051906020012090509392505050565b828054600181600116156101000203166002900490600052602060002090601f01602090048101928262000447576000855562000492565b82601f106200046257805160ff191683800117855562000492565b8280016001018555821562000492579182015b828111156200049257825182559160200191906001019062000475565b50620004a0929150620004a4565b5090565b5b80821115620004a05760008155600101620004a5565b80516001600160a01b0381168114620004d357600080fd5b919050565b600082601f830112620004e9578081fd5b81516001600160401b0380821115620004fe57fe5b6040516020601f8401601f19168201810183811183821017156200051e57fe5b604052838252858401810187101562000535578485fd5b8492505b8383101562000558578583018101518284018201529182019162000539565b838311156200056957848185840101525b5095945050505050565b60006020828403121562000585578081fd5b6200059082620004bb565b9392505050565b60008060008060008060c08789031215620005b0578182fd5b620005bb87620004bb565b9550620005cb60208801620004bb565b9450620005db60408801620004bb565b9350606087015161ffff81168114620005f2578283fd5b60808801519093506001600160401b03808211156200060f578384fd5b6200061d8a838b01620004d8565b935060a089015191508082111562000633578283fd5b506200064289828a01620004d8565b9150509295509295509295565b60006020828403121562000661578081fd5b81518060020b811462000590578182fd5b60805160a05160c05160e0516101005161012051614f0e620006bc600039806115fc525080612ded525080612e2f525080612e0e525080612d94525080612dc45250614f0e6000f3fe6080604052600436106101345760003560e01c8062ebf5dd1461013d57806306fdde0314610174578063095ea7b31461019657806318160ddd146101c35780631a87e87d146101e557806323b872dd146102055780632c8958f614610225578063313ce567146102455780633644e51514610267578063395093511461027c5780633dd657c51461029c5780633fe529f0146102bc5780636d70f7ae146102dc57806370a08231146102fc5780637ecebe001461031c5780637f98aa711461033c5780638dbdbe6d1461036157806395d89b4114610383578063a457c2d714610398578063a9059cbb146103b8578063ac2dc562146103d8578063c8696232146103fd578063cb81da2e14610424578063d505accf14610444578063dd62ed3e14610464578063f8e35be7146104845761013b565b3661013b57005b005b34801561014957600080fd5b5061015d610158366004614a66565b610499565b60405161016b929190614c45565b60405180910390f35b34801561018057600080fd5b506101896107a3565b60405161016b9190614bba565b3480156101a257600080fd5b506101b66101b1366004614899565b61083a565b60405161016b9190614b69565b3480156101cf57600080fd5b506101d8610858565b60405161016b9190614b8c565b3480156101f157600080fd5b5061013b610200366004614ad4565b61085e565b34801561021157600080fd5b506101b66102203660046147e9565b610c7e565b34801561023157600080fd5b5061013b61024036600461496a565b610d06565b34801561025157600080fd5b5061025a610d84565b60405161016b9190614cb8565b34801561027357600080fd5b506101d8610d8d565b34801561028857600080fd5b506101b6610297366004614899565b610d9c565b3480156102a857600080fd5b5061013b6102b736600461496a565b610dea565b3480156102c857600080fd5b5061013b6102d7366004614721565b610e50565b3480156102e857600080fd5b506101b66102f7366004614721565b610ea8565b34801561030857600080fd5b506101d8610317366004614721565b610eca565b34801561032857600080fd5b506101d8610337366004614721565b610ee5565b34801561034857600080fd5b50610351610f06565b60405161016b9493929190614b04565b61037461036f366004614aa7565b610fc1565b60405161016b93929190614c53565b34801561038f57600080fd5b50610189611290565b3480156103a457600080fd5b506101b66103b3366004614899565b6112f1565b3480156103c457600080fd5b506101b66103d3366004614899565b611359565b3480156103e457600080fd5b506103ed61136d565b60405161016b9493929190614b95565b34801561040957600080fd5b50610412611396565b60405161016b96959493929190614c84565b34801561043057600080fd5b5061013b61043f366004614918565b611422565b34801561045057600080fd5b5061013b61045f366004614829565b61158d565b34801561047057600080fd5b506101d861047f36600461473d565b611744565b34801561049057600080fd5b5061013b61176f565b600080600c601a9054906101000a900463ffffffff1663ffffffff166001146104c157600080fd5b600c805463ffffffff60d01b1916600160d11b17905560006104e1611823565b5050600a5460405163051bb83360e01b81529294506001600160a01b03808616945063051bb833936105199350911690600401614af0565b60006040518083038186803b15801561053157600080fd5b505afa158015610545573d6000803e3d6000fd5b505050506000861161055657600080fd5b6000610560610858565b600c54909150600160b01b900463ffffffff166001141561060657600061059088670de0b6b3a7640000846118c2565b600954600a549192506105bd916001600160a01b031690600281810b9163010000009004900b8430611958565b600954600a5492975090955060009182916105f2916001600160a01b0316903090600281810b9163010000009004900b611b25565b9150915061060260008383611bec565b5050505b600061062461061d86610617611c9b565b90611d1c565b89846118c2565b9050600061063e61063786610617611d2c565b8a856118c2565b905061064a8683611d5d565b95506106568582611d5d565b94508515610678576007546106789088908a906001600160a01b031689611d6d565b8415610698576008546106989088908a906001600160a01b031688611d6d565b6106a2338a611e0e565b876001600160a01b03167f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca948a88886040516106df93929190614c53565b60405180910390a2600c54600160b01b900463ffffffff166001141561077f57600954600090819061073f90600281810b9163010000009004900b610722611c9b565b61072a611d2c565b600a546001600160a01b031693929190611ef8565b915091507f2fb985eb745b9e89bb1ab82e0f8ceb6bf94d4d60aed7e8196540c50161a5fe918282604051610774929190614c45565b60405180910390a150505b5050600c805463ffffffff60d01b1916600160d01b17905550919590945092505050565b60038054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561082f5780601f106108045761010080835404028352916020019161082f565b820191906000526020600020905b81548152906001019060200180831161081257829003601f168201915b505050505090505b90565b600061084e610847612080565b8484612084565b5060015b92915050565b60025490565b336000908152600d602052604090205460ff1661087a57600080fd5b6000610884611823565b5050600a5460405163051bb83360e01b81529294506001600160a01b03808616945063051bb833936108bc9350911690600401614af0565b60006040518083038186803b1580156108d457600080fd5b505afa1580156108e8573d6000803e3d6000fd5b5050600c805463ffffffff60b01b1916600160b01b1790555061090b9050614634565b600954600a54600091610936916001600160a01b031690600281810b9163010000009004900b612170565b5050600954600a54919250610964916001600160a01b031690600281810b9163010000009004900b3061221e565b6020860181905281865260c086019290925260a085019290925261098a91600191611bec565b60006109946123d2565b600854600a54600160a01b90910460020b9190910291506109bd906001600160a01b031661247b565b50600290810b810b604086018190526008546109e6935090918491600160a01b9004900b6124fd565b600290810b810b608086015290810b900b60608401526001600160801b03821615801590610a22575060a08301511580610a22575060c0830151155b15610a9f576000808460a0015111610a3b576000610a3e565b60015b9050600081610a6757610a62610a5d8660c001518960ff1660646118c2565b61251a565b610a7d565b610a7d610a5d8660a001518960ff1660646118c2565b600a54909150610a98906001600160a01b0316308484612562565b5050610bc5565b610aa7611c9b565b60a0840152610ab4611d2c565b60c0840181905260a084015160608501516080860151600a54610ae5946001600160a01b03909116939290916126de565b6001600160801b031660e0840181905260608401516080850151600a54610b19936001600160a01b03909116929091612772565b6101208501819052610100850182905260a085015160c0860151610b41939192909190612809565b15156101408401819052610b7e57610b79610b6e8461012001518560c00151611d1c90919063ffffffff16565b8660ff1660646118c2565b610b9d565b610b9d610b6e8461010001518560a00151611d1c90919063ffffffff16565b6101608401819052610140840151600a54610bc5926001600160a01b03909116913091612562565b610bcd611c9b565b60a0840152610bda611d2c565b60c0840181905260a0840151600854600a54610c0e936001600160a01b0390911692918590600160a01b900460020b612844565b6009805465ffffff00000019166301000000600293840b62ffffff90811682029290921762ffffff191694840b91909116939093179081905560a086015160c0870151600a54610c75956001600160a01b039091169484810b9491909104900b9190611ef8565b50505050505050565b6000610c8b848484612a50565b610cfb84610c97612080565b610cf685604051806060016040528060288152602001614e03602891396001600160a01b038a16600090815260016020526040812090610cd5612080565b6001600160a01b031681526020810191909152604001600020549190612b99565b612084565b5060015b9392505050565b610d0e612c30565b6000841380610d1d5750600083135b610d2657600080fd5b6000610d34828401846148c4565b90508015610d5f57600754610d5a906001600160a01b0316610d54612080565b87612c49565b610d7d565b600854610d7d906001600160a01b0316610d77612080565b86612c49565b5050505050565b60055460ff1690565b6000610d97612d90565b905090565b600061084e610da9612080565b84610cf68560016000610dba612080565b6001600160a01b03908116825260208083019390935260409182016000908120918c168152925290205490612e5a565b610df2612c30565b6000610dfc612080565b90506000610e0c83850185614721565b90508515610e2b57600754610e2b906001600160a01b03168388612c49565b8415610e4857600854610e48906001600160a01b03168387612c49565b505050505050565b6000610e5a611823565b505050509050806001600160a01b0316336001600160a01b031614610e7e57600080fd5b506001600160a01b03166000908152600d60205260409020805460ff19811660ff90911615179055565b6001600160a01b0381166000908152600d602052604090205460ff165b919050565b6001600160a01b031660009081526020819052604090205490565b6001600160a01b038116600090815260066020526040812061085290612eb2565b6000806000806000600a60009054906101000a90046001600160a01b03166001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b158015610f5c57600080fd5b505afa158015610f70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f9491906149ba565b5050600754600854600a546001600160a01b039283169d9183169c50949a50931697509195505050505050565b6000806000600c601a9054906101000a900463ffffffff1663ffffffff16600114610feb57600080fd5b600c805463ffffffff60d01b1916600160d11b179055600061100b611823565b5050600a5460405163051bb83360e01b81529294506001600160a01b03808616945063051bb833936110439350911690600401614af0565b60006040518083038186803b15801561105b57600080fd5b505afa15801561106f573d6000803e3d6000fd5b505050506001600160a01b03851661108657600080fd5b6000871180156110965750600086115b61109f57600080fd5b60006110a9612080565b905060006110b5610858565b905061113860018a8a6110c6611c9b565b6110ce611d2c565b60408051608081018252600954600281810b810b810b835263010000008204810b810b810b6020840152600160301b8204810b810b810b93830193909352600160481b9004820b820b90910b6060820152600a546001600160a01b03169594939291908890612eb6565b919750955093508061116e576103e8861161116e5760405162461bcd60e51b815260040161116590614c0d565b60405180910390fd5b8561118b5760405162461bcd60e51b815260040161116590614c29565b6007546111a3906001600160a01b0316833088612f52565b6008546111bb906001600160a01b0316833087612f52565b600c54600160b01b900463ffffffff166001141561120257600954600a546111ff916001600160a01b0390911690600281810b9163010000009004900b8888611ef8565b50505b471561121257611212824761308f565b61121c8787613183565b866001600160a01b0316826001600160a01b03167f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f687878a60405161126393929190614c53565b60405180910390a35050600c805463ffffffff60d01b1916600160d01b1790555091959094509092509050565b60048054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561082f5780601f106108045761010080835404028352916020019161082f565b600061084e6112fe612080565b84610cf685604051806060016040528060258152602001614edd6025913960016000611328612080565b6001600160a01b03908116825260208083019390935260409182016000908120918d16815292529020549190612b99565b600061084e611366612080565b8484612a50565b600954600281810b9163010000008104820b91600160301b8204810b91600160481b9004900b84565b60408051608081018252600954600281810b810b810b835263010000008204810b810b810b6020840152600160301b8204810b810b810b93830193909352600160481b9004820b820b90910b6060820152600a546000918291829182918291829161140f916001600160a01b0390911690600190613261565b949b939a50919850965094509092509050565b336000908152600d602052604090205460ff1661143e57600080fd5b6000611448611823565b5050600a5460405163051bb83360e01b81529294506001600160a01b03808616945063051bb833936114809350911690600401614af0565b60006040518083038186803b15801561149857600080fd5b505afa1580156114ac573d6000803e3d6000fd5b5050600c805463ffffffff60b01b1916600160b01b17905550506008546114e09084908490600160a01b900460020b6132f8565b600954600a546000918291611510916001600160a01b0390911690600281810b9163010000009004900b3061221e565b93509350505061152260018383611bec565b861561154057600a54611540906001600160a01b031630888a612562565b61154d8585610722611c9b565b505060098054600296870b62ffffff90811662ffffff199790980b1663010000000265ffffff000000199091161794909416949094179092555050505050565b834211156115e2576040805162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e65000000604482015290519081900360640190fd5b6001600160a01b03871660009081526006602052604081207f00000000000000000000000000000000000000000000000000000000000000009089908990899061162b90612eb2565b8960405160200180878152602001866001600160a01b03168152602001856001600160a01b031681526020018481526020018381526020018281526020019650505050505050604051602081830303815290604052805190602001209050600061169482613453565b905060006116a48287878761349f565b9050896001600160a01b0316816001600160a01b03161461170c576040805162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e61747572650000604482015290519081900360640190fd5b6001600160a01b038a16600090815260066020526040902061172d90613605565b6117388a8a8a612084565b50505050505050505050565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b336000908152600d602052604090205460ff1661178b57600080fd5b600954600a546000918291829182916117bf916001600160a01b0390911690600281810b9163010000009004900b3061221e565b600c805463ffffffff60b01b1916600160b11b179055604051939750919550935091507f0b807fda608508350274d5da730325b52bb86f7ba43085d327059ed4b2fc840490611815908690869086908690614c69565b60405180910390a150505050565b6000806000806000600b60009054906101000a90046001600160a01b03166001600160a01b03166338d772806040518163ffffffff1660e01b815260040160a06040518083038186803b15801561187957600080fd5b505afa15801561188d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b19190614775565b945094509450945094509091929394565b600083830281600019858709828110838203039150508084116118e457600080fd5b806118f457508290049050610cff565b8385870960008581038616958690049560026003880281188089028203028089028203028089028203028089028203028089028203028089029091030291819003819004600101858411909403939093029190930391909104170290509392505050565b600080806119706001600160a01b0389168888612170565b505090506000611992826001600160801b031687670de0b6b3a76400006118c2565b9050886001600160a01b031663a34123a789896119ae8561360e565b6040518463ffffffff1660e01b8152600401808460020b81526020018360020b8152602001826001600160801b0316815260200193505050506040805180830381600087803b158015611a0057600080fd5b505af1158015611a14573d6000803e3d6000fd5b505050506040513d6040811015611a2a57600080fd5b508051602090910151909450925083151580611a465750600083115b15611b1957886001600160a01b0316634f1eb3d8868a8a611a668961360e565b611a6f8961360e565b6040518663ffffffff1660e01b815260040180866001600160a01b031681526020018560020b81526020018460020b8152602001836001600160801b03168152602001826001600160801b03168152602001955050505050506040805180830381600087803b158015611ae157600080fd5b505af1158015611af5573d6000803e3d6000fd5b505050506040513d6040811015611b0b57600080fd5b50516001600160801b031693505b50509550959350505050565b600080611b33868585613652565b50604080516309e3d67b60e31b81526001600160a01b038781166004830152600287810b602484015286900b60448301526001600160801b03606483018190526084830152825190891692634f1eb3d89260a480820193918290030181600087803b158015611ba157600080fd5b505af1158015611bb5573d6000803e3d6000fd5b505050506040513d6040811015611bcb57600080fd5b5080516020909101516001600160801b039182169891169650945050505050565b600080611bf7611823565b509094509250505060ff811615610d7d578315611c3357600754611c33906001600160a01b031683611c2e8760ff861660646118c2565b612c49565b8215611c5957600854611c59906001600160a01b031683611c2e8660ff861660646118c2565b7ff8994d9c768d599c5c6e92d52cd9cc24762cd773384c7a4612796773c56a86a6858585604051611c8c93929190614b74565b60405180910390a15050505050565b6007546040516370a0823160e01b81526000916001600160a01b0316906370a0823190611ccc903090600401614af0565b60206040518083038186803b158015611ce457600080fd5b505afa158015611cf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d979190614a4e565b8082038281111561085257600080fd5b6008546040516370a0823160e01b81526000916001600160a01b0316906370a0823190611ccc903090600401614af0565b8082018281101561085257600080fd5b838015611d875750600c546001600160a01b038381169116145b15611dfd57600c54604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d90611dbc908490600401614b8c565b600060405180830381600087803b158015611dd657600080fd5b505af1158015611dea573d6000803e3d6000fd5b50505050611df8838261308f565b611e08565b611e08828483612c49565b50505050565b6001600160a01b038216611e535760405162461bcd60e51b8152600401808060200182810382526021815260200180614e4b6021913960400191505060405180910390fd5b611e5f8260008361317e565b611e9c81604051806060016040528060228152602001614d2e602291396001600160a01b0385166000908152602081905260409020549190612b99565b6001600160a01b038316600090815260208190526040902055600254611ec2908261370b565b6002556040805182815290516000916001600160a01b03851691600080516020614e2b8339815191529181900360200190a35050565b60008080611f126001600160a01b03891686868a8a6126de565b90506001600160801b0381161561207557876001600160a01b031663aafe29c030308a8a863060405160200180826001600160a01b031681526020019150506040516020818303038152906040526040518763ffffffff1660e01b815260040180876001600160a01b03168152602001866001600160a01b031681526020018560020b81526020018460020b8152602001836001600160801b0316815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611feb578181015183820152602001611fd3565b50505050905090810190601f1680156120185780820380516001836020036101000a031916815260200191505b50975050505050505050606060405180830381600087803b15801561203c57600080fd5b505af1158015612050573d6000803e3d6000fd5b505050506040513d606081101561206657600080fd5b50805160209091015190935091505b509550959350505050565b3390565b6001600160a01b0383166120c95760405162461bcd60e51b8152600401808060200182810382526024815260200180614e916024913960400191505060405180910390fd5b6001600160a01b03821661210e5760405162461bcd60e51b8152600401808060200182810382526022815260200180614d506022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b600080600080600030905062ffffff861662ffffff88168260181b1760181b179150876001600160a01b031663514ea4bf836040518263ffffffff1660e01b81526004018082815260200191505060c06040518083038186803b1580156121d657600080fd5b505afa1580156121ea573d6000803e3d6000fd5b505050506040513d60c081101561220057600080fd5b508051608082015160a090920151909a919950975095505050505050565b6000808080806122386001600160a01b038a168989612170565b50909150506001600160801b038116156123c6576040805163a34123a760e01b815260028a810b600483015289900b60248201526001600160801b038316604482015281516001600160a01b038c169263a34123a792606480820193918290030181600087803b1580156122ab57600080fd5b505af11580156122bf573d6000803e3d6000fd5b505050506040513d60408110156122d557600080fd5b5080516020909101519095509350841515806122f15750600084115b156123c657604080516309e3d67b60e31b81526001600160a01b03888116600483015260028b810b60248401528a900b60448301526001600160801b0360648301819052608483015282516000938493928e1692634f1eb3d89260a4808301939282900301818787803b15801561236757600080fd5b505af115801561237b573d6000803e3d6000fd5b505050506040513d604081101561239157600080fd5b5080516020909101516001600160801b0391821693501690506123b48288611d1c565b6123be8288611d1c565b909550935050505b50945094509450949050565b6000806123dd611823565b5050600a54600c5460405163b0a42a5160e01b81529395506001600160a01b03808716955063b0a42a51946124259450921691600160a01b90910461ffff1690600401614b33565b60206040518083038186803b15801561243d57600080fd5b505afa158015612451573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061247591906148fc565b91505090565b6000806000836001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b1580156124b957600080fd5b505afa1580156124cd573d6000803e3d6000fd5b505050506040513d60e08110156124e357600080fd5b508051602082015160609092015190969195509350915050565b600080600061250c8685613768565b858103979501955050505050565b6000600160ff1b821061255e5760405162461bcd60e51b8152600401808060200182810382526028815260200180614eb56028913960400191505060405180910390fd5b5090565b6000612576856001600160a01b031661247b565b505090506000620f42408261c350026001600160a01b03168161259557fe5b0490506000846125a7578183016125ab565b8183035b9050866001600160a01b031663128acb08878787858a6040516020018082151581526020019150506040516020818303038152906040526040518663ffffffff1660e01b815260040180866001600160a01b031681526020018515158152602001848152602001836001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561265a578181015183820152602001612642565b50505050905090810190601f1680156126875780820380516001836020036101000a031916815260200191505b5096505050505050506040805180830381600087803b1580156126a957600080fd5b505af11580156126bd573d6000803e3d6000fd5b505050506040513d60408110156126d357600080fd5b505050505050505050565b600080866001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b15801561271a57600080fd5b505afa15801561272e573d6000803e3d6000fd5b505050506040513d60e081101561274457600080fd5b5051905061276581612755866137b4565b61275e866137b4565b8989613adb565b9150505b95945050505050565b6000806000866001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b1580156127b057600080fd5b505afa1580156127c4573d6000803e3d6000fd5b505050506040513d60e08110156127da57600080fd5b505190506127fa816127eb876137b4565b6127f4876137b4565b89613b9d565b92509250505b94509492505050565b600061281f856128198685611d1c565b90613c38565b61282d856128198887611d1c565b11612839576000612769565b600195945050505050565b60008060006040518060e00160405280888152602001878152602001600081526020016000815260200160006001600160801b03168152602001600060020b8152602001600060020b8152509050600080896001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b1580156128ce57600080fd5b505afa1580156128e2573d6000803e3d6000fd5b505050506040513d60e08110156128f857600080fd5b50805160209091015190925090506129118188886124fd565b600290810b810b60c0860181905291810b900b60a085018190528451602086015161293e938e9390613c5c565b606085018190526040850182905260a085015160c0860151612965938e93909290916126de565b6001600160801b0316608084015282516020840151604085015160608601516000936129949390929091612809565b905080156129da5760006129b48486608001518760000151600080613c8b565b90506129c86129c282613e6f565b89613768565b600290810b900b60c086015250612a0f565b60006129f3848660800151876020015160016000613c8b565b9050612a016129c282613e6f565b600290810b900b60a0860152505b612a228460a001518560c00151896132f8565b612a308460a0015188613768565b9550612a408460c0015188613768565b9450505050509550959350505050565b6001600160a01b038316612a955760405162461bcd60e51b8152600401808060200182810382526025815260200180614e6c6025913960400191505060405180910390fd5b6001600160a01b038216612ada5760405162461bcd60e51b8152600401808060200182810382526023815260200180614d0b6023913960400191505060405180910390fd5b612ae583838361317e565b612b2281604051806060016040528060268152602001614d72602691396001600160a01b0386166000908152602081905260409020549190612b99565b6001600160a01b038085166000908152602081905260408082209390935590841681522054612b519082612e5a565b6001600160a01b03808416600081815260208181526040918290209490945580518581529051919392871692600080516020614e2b83398151915292918290030190a3505050565b60008184841115612c285760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612bed578181015183820152602001612bd5565b50505050905090810190601f168015612c1a5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600a546001600160a01b03163314612c4757600080fd5b565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b60208310612cc55780518252601f199092019160209182019101612ca6565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612d27576040519150601f19603f3d011682016040523d82523d6000602084013e612d2c565b606091505b5091509150818015612d5a575080511580612d5a5750808060200190516020811015612d5757600080fd5b50515b610d7d576040805162461bcd60e51b815260206004820152600260248201526114d560f21b604482015290519081900360640190fd5b60007f0000000000000000000000000000000000000000000000000000000000000000612dbb61415a565b1415612de857507f0000000000000000000000000000000000000000000000000000000000000000610837565b612e537f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000061415e565b9050610837565b600082820183811015610cff576040805162461bcd60e51b815260206004820152601b60248201527a536166654d6174683a206164646974696f6e206f766572666c6f7760281b604482015290519081900360640190fd5b5490565b6000806000806000806000612ecc8f8f8a613261565b505093509350935093506000612ef58c612eef8588611d5d90919063ffffffff16565b90611d5d565b90506000612f078c612eef8786611d5d565b90508a1580612f1557508115155b80612f1f57508015155b612f2557fe5b612f328f8f84848f6141c0565b809950819a50829b50505050505050505050985098509895505050505050565b600c546001600160a01b038581169116148015612f6f5750804710155b1561306757600c60009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612fc457600080fd5b505af1158015612fd8573d6000803e3d6000fd5b5050600c5460405163a9059cbb60e01b81526001600160a01b03909116935063a9059cbb925061300f915085908590600401614b50565b602060405180830381600087803b15801561302957600080fd5b505af115801561303d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061306191906148e0565b50611e08565b6001600160a01b03831630141561308357611df8848383612c49565b611e0884848484614254565b604080516000808252602082019092526001600160a01b0384169083906040518082805190602001908083835b602083106130db5780518252601f1990920191602091820191016130bc565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d806000811461313d576040519150601f19603f3d011682016040523d82523d6000602084013e613142565b606091505b505090508061317e576040805162461bcd60e51b815260206004820152600360248201526253544560e81b604482015290519081900360640190fd5b505050565b6001600160a01b0382166131de576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b6131ea6000838361317e565b6002546131f79082612e5a565b6002556001600160a01b03821660009081526020819052604090205461321d9082612e5a565b6001600160a01b038316600081815260208181526040808320949094558351858152935192939192600080516020614e2b8339815191529281900390910190a35050565b60008060008060008061327d89886000015189602001516143a4565b939950919750955093509150876132ec5760008060008060006132a98e8d604001518e606001516143a4565b9398509196509450925090506132bf8b86611d5d565b9a506132cb8a85611d5d565b99506132d78984611d5d565b98506132e38883611d5d565b97509450505050505b93975093979195509350565b8160020b8360020b12613338576040805162461bcd60e51b8152602060048201526003602482015262544c5560e81b604482015290519081900360640190fd5b620d89e719600284900b121561337b576040805162461bcd60e51b8152602060048201526003602482015262544c4d60e81b604482015290519081900360640190fd5b620d89e8600283900b13156133bd576040805162461bcd60e51b815260206004820152600360248201526254554d60e81b604482015290519081900360640190fd5b8060020b8360020b816133cc57fe5b0760020b15613408576040805162461bcd60e51b8152602060048201526003602482015262544c4960e81b604482015290519081900360640190fd5b8060020b8260020b8161341757fe5b0760020b1561317e576040805162461bcd60e51b815260206004820152600360248201526254554960e81b604482015290519081900360640190fd5b600061345d612d90565b82604051602001808061190160f01b81525060020183815260200182815260200192505050604051602081830303815290604052805190602001209050919050565b60006fa2a8918ca85bafe22016d0b997e4df60600160ff1b038211156134f65760405162461bcd60e51b8152600401808060200182810382526022815260200180614dbf6022913960400191505060405180910390fd5b8360ff16601b148061350b57508360ff16601c145b6135465760405162461bcd60e51b8152600401808060200182810382526022815260200180614de16022913960400191505060405180910390fd5b600060018686868660405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156135a2573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116612769576040805162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b604482015290519081900360640190fd5b80546001019055565b6000600160801b821061255e5760405162461bcd60e51b8152600401808060200182810382526027815260200180614d986027913960400191505060405180910390fd5b60006136686001600160a01b0385168484612170565b50909150506001600160801b03811615610cff57836001600160a01b031663a34123a7848460006040518463ffffffff1660e01b8152600401808460020b81526020018360020b815260200182815260200193505050506040805180830381600087803b1580156136d857600080fd5b505af11580156136ec573d6000803e3d6000fd5b505050506040513d604081101561370257600080fd5b50509392505050565b600082821115613762576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000808260020b8460020b8161377a57fe5b05905060008460020b1280156137a157508260020b8460020b8161379a57fe5b0760020b15155b156137ab57600019015b90910292915050565b60008060008360020b126137cb578260020b6137d3565b8260020b6000035b9050620d89e8811115613811576040805162461bcd60e51b81526020600482015260016024820152601560fa1b604482015290519081900360640190fd5b60006001821661382557600160801b613837565b6ffffcb933bd6fad37aa2d162d1a5940015b6001600160881b031690506002821615613861576ffff97272373d413259a46990580e213a0260801c5b6004821615613880576ffff2e50f5f656932ef12357cf3c7fdcc0260801c5b600882161561389f576fffe5caca7e10e4e61c3624eaa0941cd00260801c5b60108216156138be576fffcb9843d60f6159c9db58835c9266440260801c5b60208216156138dd576fff973b41fa98c081472e6896dfb254c00260801c5b60408216156138fc576fff2ea16466c96a3843ec78b326b528610260801c5b608082161561391b576ffe5dee046a99a2a811c461f1969c30530260801c5b61010082161561393b576ffcbe86c7900a88aedcffc83b479aa3a40260801c5b61020082161561395b576ff987a7253ac413176f2b074cf7815e540260801c5b61040082161561397b576ff3392b0822b70005940c7a398e4b70f30260801c5b61080082161561399b576fe7159475a2c29b7443b29c7fa6e889d90260801c5b6110008216156139bb576fd097f3bdfd2022b8845ad8f792aa58250260801c5b6120008216156139db576fa9f746462d870fdf8a65dc1f90e061e50260801c5b6140008216156139fb576f70d869a156d2a1b890bb3df62baf32f70260801c5b618000821615613a1b576f31be135f97d08fd981231505542fcfa60260801c5b62010000821615613a3c576f09aa508b5b7a84e1c677de54f3e99bc90260801c5b62020000821615613a5c576e5d6af8dedb81196699c329225ee6040260801c5b62040000821615613a7b576d2216e584f5fa1ea926041bedfe980260801c5b62080000821615613a98576b048a170391f7dc42444e8fa20260801c5b60008460020b1315613ab3578060001981613aaf57fe5b0490505b600160201b810615613ac6576001613ac9565b60005b60ff16602082901c0192505050919050565b6000836001600160a01b0316856001600160a01b03161115613afb579293925b846001600160a01b0316866001600160a01b031611613b2657613b1f8585856143e9565b9050612769565b836001600160a01b0316866001600160a01b03161015613b88576000613b4d8786866143e9565b90506000613b5c87898661444c565b9050806001600160801b0316826001600160801b031610613b7d5780613b7f565b815b92505050612769565b613b9385858461444c565b9695505050505050565b600080836001600160a01b0316856001600160a01b03161115613bbe579293925b846001600160a01b0316866001600160a01b031611613be957613be2858585614491565b9150612800565b836001600160a01b0316866001600160a01b03161015613c2257613c0e868585614491565b9150613c1b8587856144fa565b9050612800565b613c2d8585856144fa565b905094509492505050565b6000821580613c5357505081810281838281613c5057fe5b04145b61085257600080fd5b6000806000613c6e88888888886126de565b9050613c7c88828787612772565b90999098509650505050505050565b600080866001600160a01b031611613ca257600080fd5b6000856001600160801b031611613cb857600080fd5b8115158315151415613da15783613cd0575084612769565b600160601b600160e01b03606086901b168215613d55576001600160a01b03871685810290868281613cfe57fe5b041415613d2f57818101828110613d2d57613d23838a6001600160a01b03168361453d565b9350505050612769565b505b613b7f82613d50888b6001600160a01b03168681613d4957fe5b0490611d5d565b6145b1565b6001600160a01b03871685810290868281613d6c57fe5b0414613d7757600080fd5b808211613d8357600080fd5b613b7f613d9c838a6001600160a01b031684860361453d565b6145bc565b8115613e0157613b1f613d9c6001600160a01b03861115613dd957613dd486600160601b896001600160801b03166118c2565b613df1565b6001600160801b038716606087901b81613def57fe5b045b6001600160a01b03891690611d5d565b60006001600160a01b03851115613e2f57613e2a85600160601b886001600160801b031661453d565b613e46565b613e46606086901b6001600160801b0388166145b1565b905080876001600160a01b031611613e5d57600080fd5b6001600160a01b038716039050612769565b60006401000276a36001600160a01b03831610801590613eab575073fffd8963efd1fc6a506488495d951d5263988d266001600160a01b038316105b613ee0576040805162461bcd60e51b81526020600482015260016024820152602960f91b604482015290519081900360640190fd5b600160201b600160c01b03602083901b166001600160801b03811160071b81811c6001600160401b03811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c60ff8111600390811b91821c600f811160021b90811c918211600190811b92831c97908811961790941790921717909117171760808110613f7257607f810383901c9150613f7c565b80607f0383901b91505b908002607f81811c60ff83811c9190911c800280831c81831c1c800280841c81841c1c800280851c81851c1c800280861c81861c1c800280871c81871c1c800280881c81881c1c800280891c81891c1c8002808a1c818a1c1c8002808b1c818b1c1c8002808c1c818c1c1c8002808d1c818d1c1c8002808e1c9c81901c9c909c1c80029c8d901c9e9d607f198f0160401b60c09190911c6001603f1b161760c19b909b1c6001603e1b169a909a1760c29990991c6001603d1b169890981760c39790971c6001603c1b169690961760c49590951c6001603b1b169490941760c59390931c6001603a1b169290921760c69190911c600160391b161760c79190911c600160381b161760c89190911c600160371b161760c99190911c600160361b161760ca9190911c600160351b161760cb9190911c600160341b161760cc9190911c600160331b161760cd9190911c600160321b1617693627a301d71055774c8581026f028f6481ab7f045a5af012a19d003aa9198101608090811d906fdb2df09e81959a81455e260799a0632f8301901d600281810b9083900b1461414b57886001600160a01b031661412f826137b4565b6001600160a01b031611156141445781614146565b805b61414d565b815b9998505050505050505050565b4690565b600083838361416b61415a565b3060405160200180868152602001858152602001848152602001838152602001826001600160a01b03168152602001955050505050506040516020818303038152906040528051906020012090509392505050565b60008080836141e45750869050858082116141db57806141dd565b815b9250614249565b856141f65750856141dd8185876118c2565b84614209578791506141dd8285886118c2565b6142148787876118c2565b91508782101561422b5750856141dd8185876118c2565b8791506142398286886118c2565b90506142468285886118c2565b92505b955095509592505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b178152925182516000948594938a169392918291908083835b602083106142d85780518252601f1990920191602091820191016142b9565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811461433a576040519150601f19603f3d011682016040523d82523d6000602084013e61433f565b606091505b509150915081801561436d57508051158061436d575080806020019051602081101561436a57600080fd5b50515b610e48576040805162461bcd60e51b815260206004820152600360248201526229aa2360e91b604482015290519081900360640190fd5b60008060008060006143b7888888613652565b90506001600160801b038116156143de576143d38888886145d2565b929750909550935091505b939792965093509350565b6000826001600160a01b0316846001600160a01b03161115614409579192915b600061442c856001600160a01b0316856001600160a01b0316600160601b6118c2565b905061276961444784838888036001600160a01b03166118c2565b61461e565b6000826001600160a01b0316846001600160a01b0316111561446c579192915b61448961444783600160601b8787036001600160a01b03166118c2565b949350505050565b6000826001600160a01b0316846001600160a01b031611156144b1579192915b836001600160a01b03166144ea606060ff16846001600160801b0316901b8686036001600160a01b0316866001600160a01b03166118c2565b816144f157fe5b04949350505050565b6000826001600160a01b0316846001600160a01b0316111561451a579192915b614489826001600160801b03168585036001600160a01b0316600160601b6118c2565b60008315806145585750508282028284828161455557fe5b04145b15614579576000821161456a57600080fd5b81810490829006151501610cff565b6145848484846118c2565b90506000828061459057fe5b8486091115610cff5760001981106145a757600080fd5b6001019392505050565b808204910615150190565b806001600160a01b0381168114610ec557600080fd5b60008060008060008060006145e88a8a8a612170565b9250925092506000806145fd8c868d8d612772565b9099509750506001600160801b039283169550501691505093509350935093565b806001600160801b0381168114610ec557600080fd5b604051806101c001604052806000815260200160008152602001600060020b8152602001600060020b8152602001600060020b8152602001600081526020016000815260200160006001600160801b0316815260200160008152602001600081526020016000151581526020016000815260200160006001600160a01b0316815260200160006001600160a01b031681525090565b60008083601f8401126146da578182fd5b5081356001600160401b038111156146f0578182fd5b60208301915083602082850101111561470857600080fd5b9250929050565b805161ffff81168114610ec557600080fd5b600060208284031215614732578081fd5b8135610cff81614cc6565b6000806040838503121561474f578081fd5b823561475a81614cc6565b9150602083013561476a81614cc6565b809150509250929050565b600080600080600060a0868803121561478c578081fd5b855161479781614cc6565b60208701519095506147a881614cc6565b60408701519094506147b981614cc6565b60608701519093506147ca81614cfb565b60808701519092506147db81614cfb565b809150509295509295909350565b6000806000606084860312156147fd578283fd5b833561480881614cc6565b9250602084013561481881614cc6565b929592945050506040919091013590565b600080600080600080600060e0888a031215614843578182fd5b873561484e81614cc6565b9650602088013561485e81614cc6565b95506040880135945060608801359350608088013561487c81614cfb565b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156148ab578182fd5b82356148b681614cc6565b946020939093013593505050565b6000602082840312156148d5578081fd5b8135610cff81614cde565b6000602082840312156148f1578081fd5b8151610cff81614cde565b60006020828403121561490d578081fd5b8151610cff81614cec565b6000806000806080858703121561492d578182fd5b84359350602085013561493f81614cde565b9250604085013561494f81614cec565b9150606085013561495f81614cec565b939692955090935050565b6000806000806060858703121561497f578182fd5b843593506020850135925060408501356001600160401b038111156149a2578283fd5b6149ae878288016146c9565b95989497509550505050565b600080600080600080600060e0888a0312156149d4578081fd5b87516149df81614cc6565b60208901519097506149f081614cec565b95506149fe6040890161470f565b9450614a0c6060890161470f565b93506080880151614a1c81614cfb565b60a0890151909350614a2d81614cfb565b60c0890151909250614a3e81614cde565b8091505092959891949750929550565b600060208284031215614a5f578081fd5b5051919050565b600080600060608486031215614a7a578081fd5b833592506020840135614a8c81614cc6565b91506040840135614a9c81614cde565b809150509250925092565b600080600060608486031215614abb578081fd5b83359250602084013591506040840135614a9c81614cc6565b600060208284031215614ae5578081fd5b8135610cff81614cfb565b6001600160a01b0391909116815260200190565b6001600160a01b039485168152928416602084015261ffff919091166040830152909116606082015260800190565b6001600160a01b0392909216825261ffff16602082015260400190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b92151583526020830191909152604082015260600190565b90815260200190565b600294850b815292840b602084015290830b604083015290910b606082015260800190565b6000602080835283518082850152825b81811015614be657858101830151858201604001528201614bca565b81811115614bf75783604083870101525b50601f01601f1916929092016040019392505050565b602080825260029082015261135360f21b604082015260600190565b602080825260029082015261495360f01b604082015260600190565b918252602082015260400190565b9283526020830191909152604082015260600190565b93845260208401929092526040830152606082015260800190565b9586526020860194909452604085019290925260608401526001600160801b0390811660808401521660a082015260c00190565b60ff91909116815260200190565b6001600160a01b0381168114614cdb57600080fd5b50565b8015158114614cdb57600080fd5b8060020b8114614cdb57600080fd5b60ff81168114614cdb57600080fdfe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636553616665436173743a2076616c756520646f65736e27742066697420696e20313238206269747345434453413a20696e76616c6964207369676e6174757265202773272076616c756545434453413a20696e76616c6964207369676e6174757265202776272076616c756545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e6365ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef45524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737353616665436173743a2076616c756520646f65736e27742066697420696e20616e20696e7432353645524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa164736f6c6343000706000a000000000000000000000000c44ad482f24fd750caeba387d2726d8653f8c4bb000000000000000000000000c99fa77ab721817da9dd3c3b4f8ecb13772fcece0000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e9000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000028556e6970696c6f7420574554482f555344432042414c414e43454420416374697665205661756c740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012554c502d574554482f555344432d41562d320000000000000000000000000000
Deployed Bytecode
0x6080604052600436106101345760003560e01c8062ebf5dd1461013d57806306fdde0314610174578063095ea7b31461019657806318160ddd146101c35780631a87e87d146101e557806323b872dd146102055780632c8958f614610225578063313ce567146102455780633644e51514610267578063395093511461027c5780633dd657c51461029c5780633fe529f0146102bc5780636d70f7ae146102dc57806370a08231146102fc5780637ecebe001461031c5780637f98aa711461033c5780638dbdbe6d1461036157806395d89b4114610383578063a457c2d714610398578063a9059cbb146103b8578063ac2dc562146103d8578063c8696232146103fd578063cb81da2e14610424578063d505accf14610444578063dd62ed3e14610464578063f8e35be7146104845761013b565b3661013b57005b005b34801561014957600080fd5b5061015d610158366004614a66565b610499565b60405161016b929190614c45565b60405180910390f35b34801561018057600080fd5b506101896107a3565b60405161016b9190614bba565b3480156101a257600080fd5b506101b66101b1366004614899565b61083a565b60405161016b9190614b69565b3480156101cf57600080fd5b506101d8610858565b60405161016b9190614b8c565b3480156101f157600080fd5b5061013b610200366004614ad4565b61085e565b34801561021157600080fd5b506101b66102203660046147e9565b610c7e565b34801561023157600080fd5b5061013b61024036600461496a565b610d06565b34801561025157600080fd5b5061025a610d84565b60405161016b9190614cb8565b34801561027357600080fd5b506101d8610d8d565b34801561028857600080fd5b506101b6610297366004614899565b610d9c565b3480156102a857600080fd5b5061013b6102b736600461496a565b610dea565b3480156102c857600080fd5b5061013b6102d7366004614721565b610e50565b3480156102e857600080fd5b506101b66102f7366004614721565b610ea8565b34801561030857600080fd5b506101d8610317366004614721565b610eca565b34801561032857600080fd5b506101d8610337366004614721565b610ee5565b34801561034857600080fd5b50610351610f06565b60405161016b9493929190614b04565b61037461036f366004614aa7565b610fc1565b60405161016b93929190614c53565b34801561038f57600080fd5b50610189611290565b3480156103a457600080fd5b506101b66103b3366004614899565b6112f1565b3480156103c457600080fd5b506101b66103d3366004614899565b611359565b3480156103e457600080fd5b506103ed61136d565b60405161016b9493929190614b95565b34801561040957600080fd5b50610412611396565b60405161016b96959493929190614c84565b34801561043057600080fd5b5061013b61043f366004614918565b611422565b34801561045057600080fd5b5061013b61045f366004614829565b61158d565b34801561047057600080fd5b506101d861047f36600461473d565b611744565b34801561049057600080fd5b5061013b61176f565b600080600c601a9054906101000a900463ffffffff1663ffffffff166001146104c157600080fd5b600c805463ffffffff60d01b1916600160d11b17905560006104e1611823565b5050600a5460405163051bb83360e01b81529294506001600160a01b03808616945063051bb833936105199350911690600401614af0565b60006040518083038186803b15801561053157600080fd5b505afa158015610545573d6000803e3d6000fd5b505050506000861161055657600080fd5b6000610560610858565b600c54909150600160b01b900463ffffffff166001141561060657600061059088670de0b6b3a7640000846118c2565b600954600a549192506105bd916001600160a01b031690600281810b9163010000009004900b8430611958565b600954600a5492975090955060009182916105f2916001600160a01b0316903090600281810b9163010000009004900b611b25565b9150915061060260008383611bec565b5050505b600061062461061d86610617611c9b565b90611d1c565b89846118c2565b9050600061063e61063786610617611d2c565b8a856118c2565b905061064a8683611d5d565b95506106568582611d5d565b94508515610678576007546106789088908a906001600160a01b031689611d6d565b8415610698576008546106989088908a906001600160a01b031688611d6d565b6106a2338a611e0e565b876001600160a01b03167f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca948a88886040516106df93929190614c53565b60405180910390a2600c54600160b01b900463ffffffff166001141561077f57600954600090819061073f90600281810b9163010000009004900b610722611c9b565b61072a611d2c565b600a546001600160a01b031693929190611ef8565b915091507f2fb985eb745b9e89bb1ab82e0f8ceb6bf94d4d60aed7e8196540c50161a5fe918282604051610774929190614c45565b60405180910390a150505b5050600c805463ffffffff60d01b1916600160d01b17905550919590945092505050565b60038054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561082f5780601f106108045761010080835404028352916020019161082f565b820191906000526020600020905b81548152906001019060200180831161081257829003601f168201915b505050505090505b90565b600061084e610847612080565b8484612084565b5060015b92915050565b60025490565b336000908152600d602052604090205460ff1661087a57600080fd5b6000610884611823565b5050600a5460405163051bb83360e01b81529294506001600160a01b03808616945063051bb833936108bc9350911690600401614af0565b60006040518083038186803b1580156108d457600080fd5b505afa1580156108e8573d6000803e3d6000fd5b5050600c805463ffffffff60b01b1916600160b01b1790555061090b9050614634565b600954600a54600091610936916001600160a01b031690600281810b9163010000009004900b612170565b5050600954600a54919250610964916001600160a01b031690600281810b9163010000009004900b3061221e565b6020860181905281865260c086019290925260a085019290925261098a91600191611bec565b60006109946123d2565b600854600a54600160a01b90910460020b9190910291506109bd906001600160a01b031661247b565b50600290810b810b604086018190526008546109e6935090918491600160a01b9004900b6124fd565b600290810b810b608086015290810b900b60608401526001600160801b03821615801590610a22575060a08301511580610a22575060c0830151155b15610a9f576000808460a0015111610a3b576000610a3e565b60015b9050600081610a6757610a62610a5d8660c001518960ff1660646118c2565b61251a565b610a7d565b610a7d610a5d8660a001518960ff1660646118c2565b600a54909150610a98906001600160a01b0316308484612562565b5050610bc5565b610aa7611c9b565b60a0840152610ab4611d2c565b60c0840181905260a084015160608501516080860151600a54610ae5946001600160a01b03909116939290916126de565b6001600160801b031660e0840181905260608401516080850151600a54610b19936001600160a01b03909116929091612772565b6101208501819052610100850182905260a085015160c0860151610b41939192909190612809565b15156101408401819052610b7e57610b79610b6e8461012001518560c00151611d1c90919063ffffffff16565b8660ff1660646118c2565b610b9d565b610b9d610b6e8461010001518560a00151611d1c90919063ffffffff16565b6101608401819052610140840151600a54610bc5926001600160a01b03909116913091612562565b610bcd611c9b565b60a0840152610bda611d2c565b60c0840181905260a0840151600854600a54610c0e936001600160a01b0390911692918590600160a01b900460020b612844565b6009805465ffffff00000019166301000000600293840b62ffffff90811682029290921762ffffff191694840b91909116939093179081905560a086015160c0870151600a54610c75956001600160a01b039091169484810b9491909104900b9190611ef8565b50505050505050565b6000610c8b848484612a50565b610cfb84610c97612080565b610cf685604051806060016040528060288152602001614e03602891396001600160a01b038a16600090815260016020526040812090610cd5612080565b6001600160a01b031681526020810191909152604001600020549190612b99565b612084565b5060015b9392505050565b610d0e612c30565b6000841380610d1d5750600083135b610d2657600080fd5b6000610d34828401846148c4565b90508015610d5f57600754610d5a906001600160a01b0316610d54612080565b87612c49565b610d7d565b600854610d7d906001600160a01b0316610d77612080565b86612c49565b5050505050565b60055460ff1690565b6000610d97612d90565b905090565b600061084e610da9612080565b84610cf68560016000610dba612080565b6001600160a01b03908116825260208083019390935260409182016000908120918c168152925290205490612e5a565b610df2612c30565b6000610dfc612080565b90506000610e0c83850185614721565b90508515610e2b57600754610e2b906001600160a01b03168388612c49565b8415610e4857600854610e48906001600160a01b03168387612c49565b505050505050565b6000610e5a611823565b505050509050806001600160a01b0316336001600160a01b031614610e7e57600080fd5b506001600160a01b03166000908152600d60205260409020805460ff19811660ff90911615179055565b6001600160a01b0381166000908152600d602052604090205460ff165b919050565b6001600160a01b031660009081526020819052604090205490565b6001600160a01b038116600090815260066020526040812061085290612eb2565b6000806000806000600a60009054906101000a90046001600160a01b03166001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b158015610f5c57600080fd5b505afa158015610f70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f9491906149ba565b5050600754600854600a546001600160a01b039283169d9183169c50949a50931697509195505050505050565b6000806000600c601a9054906101000a900463ffffffff1663ffffffff16600114610feb57600080fd5b600c805463ffffffff60d01b1916600160d11b179055600061100b611823565b5050600a5460405163051bb83360e01b81529294506001600160a01b03808616945063051bb833936110439350911690600401614af0565b60006040518083038186803b15801561105b57600080fd5b505afa15801561106f573d6000803e3d6000fd5b505050506001600160a01b03851661108657600080fd5b6000871180156110965750600086115b61109f57600080fd5b60006110a9612080565b905060006110b5610858565b905061113860018a8a6110c6611c9b565b6110ce611d2c565b60408051608081018252600954600281810b810b810b835263010000008204810b810b810b6020840152600160301b8204810b810b810b93830193909352600160481b9004820b820b90910b6060820152600a546001600160a01b03169594939291908890612eb6565b919750955093508061116e576103e8861161116e5760405162461bcd60e51b815260040161116590614c0d565b60405180910390fd5b8561118b5760405162461bcd60e51b815260040161116590614c29565b6007546111a3906001600160a01b0316833088612f52565b6008546111bb906001600160a01b0316833087612f52565b600c54600160b01b900463ffffffff166001141561120257600954600a546111ff916001600160a01b0390911690600281810b9163010000009004900b8888611ef8565b50505b471561121257611212824761308f565b61121c8787613183565b866001600160a01b0316826001600160a01b03167f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f687878a60405161126393929190614c53565b60405180910390a35050600c805463ffffffff60d01b1916600160d01b1790555091959094509092509050565b60048054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561082f5780601f106108045761010080835404028352916020019161082f565b600061084e6112fe612080565b84610cf685604051806060016040528060258152602001614edd6025913960016000611328612080565b6001600160a01b03908116825260208083019390935260409182016000908120918d16815292529020549190612b99565b600061084e611366612080565b8484612a50565b600954600281810b9163010000008104820b91600160301b8204810b91600160481b9004900b84565b60408051608081018252600954600281810b810b810b835263010000008204810b810b810b6020840152600160301b8204810b810b810b93830193909352600160481b9004820b820b90910b6060820152600a546000918291829182918291829161140f916001600160a01b0390911690600190613261565b949b939a50919850965094509092509050565b336000908152600d602052604090205460ff1661143e57600080fd5b6000611448611823565b5050600a5460405163051bb83360e01b81529294506001600160a01b03808616945063051bb833936114809350911690600401614af0565b60006040518083038186803b15801561149857600080fd5b505afa1580156114ac573d6000803e3d6000fd5b5050600c805463ffffffff60b01b1916600160b01b17905550506008546114e09084908490600160a01b900460020b6132f8565b600954600a546000918291611510916001600160a01b0390911690600281810b9163010000009004900b3061221e565b93509350505061152260018383611bec565b861561154057600a54611540906001600160a01b031630888a612562565b61154d8585610722611c9b565b505060098054600296870b62ffffff90811662ffffff199790980b1663010000000265ffffff000000199091161794909416949094179092555050505050565b834211156115e2576040805162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e65000000604482015290519081900360640190fd5b6001600160a01b03871660009081526006602052604081207f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c99089908990899061162b90612eb2565b8960405160200180878152602001866001600160a01b03168152602001856001600160a01b031681526020018481526020018381526020018281526020019650505050505050604051602081830303815290604052805190602001209050600061169482613453565b905060006116a48287878761349f565b9050896001600160a01b0316816001600160a01b03161461170c576040805162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e61747572650000604482015290519081900360640190fd5b6001600160a01b038a16600090815260066020526040902061172d90613605565b6117388a8a8a612084565b50505050505050505050565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b336000908152600d602052604090205460ff1661178b57600080fd5b600954600a546000918291829182916117bf916001600160a01b0390911690600281810b9163010000009004900b3061221e565b600c805463ffffffff60b01b1916600160b11b179055604051939750919550935091507f0b807fda608508350274d5da730325b52bb86f7ba43085d327059ed4b2fc840490611815908690869086908690614c69565b60405180910390a150505050565b6000806000806000600b60009054906101000a90046001600160a01b03166001600160a01b03166338d772806040518163ffffffff1660e01b815260040160a06040518083038186803b15801561187957600080fd5b505afa15801561188d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b19190614775565b945094509450945094509091929394565b600083830281600019858709828110838203039150508084116118e457600080fd5b806118f457508290049050610cff565b8385870960008581038616958690049560026003880281188089028203028089028203028089028203028089028203028089028203028089029091030291819003819004600101858411909403939093029190930391909104170290509392505050565b600080806119706001600160a01b0389168888612170565b505090506000611992826001600160801b031687670de0b6b3a76400006118c2565b9050886001600160a01b031663a34123a789896119ae8561360e565b6040518463ffffffff1660e01b8152600401808460020b81526020018360020b8152602001826001600160801b0316815260200193505050506040805180830381600087803b158015611a0057600080fd5b505af1158015611a14573d6000803e3d6000fd5b505050506040513d6040811015611a2a57600080fd5b508051602090910151909450925083151580611a465750600083115b15611b1957886001600160a01b0316634f1eb3d8868a8a611a668961360e565b611a6f8961360e565b6040518663ffffffff1660e01b815260040180866001600160a01b031681526020018560020b81526020018460020b8152602001836001600160801b03168152602001826001600160801b03168152602001955050505050506040805180830381600087803b158015611ae157600080fd5b505af1158015611af5573d6000803e3d6000fd5b505050506040513d6040811015611b0b57600080fd5b50516001600160801b031693505b50509550959350505050565b600080611b33868585613652565b50604080516309e3d67b60e31b81526001600160a01b038781166004830152600287810b602484015286900b60448301526001600160801b03606483018190526084830152825190891692634f1eb3d89260a480820193918290030181600087803b158015611ba157600080fd5b505af1158015611bb5573d6000803e3d6000fd5b505050506040513d6040811015611bcb57600080fd5b5080516020909101516001600160801b039182169891169650945050505050565b600080611bf7611823565b509094509250505060ff811615610d7d578315611c3357600754611c33906001600160a01b031683611c2e8760ff861660646118c2565b612c49565b8215611c5957600854611c59906001600160a01b031683611c2e8660ff861660646118c2565b7ff8994d9c768d599c5c6e92d52cd9cc24762cd773384c7a4612796773c56a86a6858585604051611c8c93929190614b74565b60405180910390a15050505050565b6007546040516370a0823160e01b81526000916001600160a01b0316906370a0823190611ccc903090600401614af0565b60206040518083038186803b158015611ce457600080fd5b505afa158015611cf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d979190614a4e565b8082038281111561085257600080fd5b6008546040516370a0823160e01b81526000916001600160a01b0316906370a0823190611ccc903090600401614af0565b8082018281101561085257600080fd5b838015611d875750600c546001600160a01b038381169116145b15611dfd57600c54604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d90611dbc908490600401614b8c565b600060405180830381600087803b158015611dd657600080fd5b505af1158015611dea573d6000803e3d6000fd5b50505050611df8838261308f565b611e08565b611e08828483612c49565b50505050565b6001600160a01b038216611e535760405162461bcd60e51b8152600401808060200182810382526021815260200180614e4b6021913960400191505060405180910390fd5b611e5f8260008361317e565b611e9c81604051806060016040528060228152602001614d2e602291396001600160a01b0385166000908152602081905260409020549190612b99565b6001600160a01b038316600090815260208190526040902055600254611ec2908261370b565b6002556040805182815290516000916001600160a01b03851691600080516020614e2b8339815191529181900360200190a35050565b60008080611f126001600160a01b03891686868a8a6126de565b90506001600160801b0381161561207557876001600160a01b031663aafe29c030308a8a863060405160200180826001600160a01b031681526020019150506040516020818303038152906040526040518763ffffffff1660e01b815260040180876001600160a01b03168152602001866001600160a01b031681526020018560020b81526020018460020b8152602001836001600160801b0316815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611feb578181015183820152602001611fd3565b50505050905090810190601f1680156120185780820380516001836020036101000a031916815260200191505b50975050505050505050606060405180830381600087803b15801561203c57600080fd5b505af1158015612050573d6000803e3d6000fd5b505050506040513d606081101561206657600080fd5b50805160209091015190935091505b509550959350505050565b3390565b6001600160a01b0383166120c95760405162461bcd60e51b8152600401808060200182810382526024815260200180614e916024913960400191505060405180910390fd5b6001600160a01b03821661210e5760405162461bcd60e51b8152600401808060200182810382526022815260200180614d506022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b600080600080600030905062ffffff861662ffffff88168260181b1760181b179150876001600160a01b031663514ea4bf836040518263ffffffff1660e01b81526004018082815260200191505060c06040518083038186803b1580156121d657600080fd5b505afa1580156121ea573d6000803e3d6000fd5b505050506040513d60c081101561220057600080fd5b508051608082015160a090920151909a919950975095505050505050565b6000808080806122386001600160a01b038a168989612170565b50909150506001600160801b038116156123c6576040805163a34123a760e01b815260028a810b600483015289900b60248201526001600160801b038316604482015281516001600160a01b038c169263a34123a792606480820193918290030181600087803b1580156122ab57600080fd5b505af11580156122bf573d6000803e3d6000fd5b505050506040513d60408110156122d557600080fd5b5080516020909101519095509350841515806122f15750600084115b156123c657604080516309e3d67b60e31b81526001600160a01b03888116600483015260028b810b60248401528a900b60448301526001600160801b0360648301819052608483015282516000938493928e1692634f1eb3d89260a4808301939282900301818787803b15801561236757600080fd5b505af115801561237b573d6000803e3d6000fd5b505050506040513d604081101561239157600080fd5b5080516020909101516001600160801b0391821693501690506123b48288611d1c565b6123be8288611d1c565b909550935050505b50945094509450949050565b6000806123dd611823565b5050600a54600c5460405163b0a42a5160e01b81529395506001600160a01b03808716955063b0a42a51946124259450921691600160a01b90910461ffff1690600401614b33565b60206040518083038186803b15801561243d57600080fd5b505afa158015612451573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061247591906148fc565b91505090565b6000806000836001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b1580156124b957600080fd5b505afa1580156124cd573d6000803e3d6000fd5b505050506040513d60e08110156124e357600080fd5b508051602082015160609092015190969195509350915050565b600080600061250c8685613768565b858103979501955050505050565b6000600160ff1b821061255e5760405162461bcd60e51b8152600401808060200182810382526028815260200180614eb56028913960400191505060405180910390fd5b5090565b6000612576856001600160a01b031661247b565b505090506000620f42408261c350026001600160a01b03168161259557fe5b0490506000846125a7578183016125ab565b8183035b9050866001600160a01b031663128acb08878787858a6040516020018082151581526020019150506040516020818303038152906040526040518663ffffffff1660e01b815260040180866001600160a01b031681526020018515158152602001848152602001836001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561265a578181015183820152602001612642565b50505050905090810190601f1680156126875780820380516001836020036101000a031916815260200191505b5096505050505050506040805180830381600087803b1580156126a957600080fd5b505af11580156126bd573d6000803e3d6000fd5b505050506040513d60408110156126d357600080fd5b505050505050505050565b600080866001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b15801561271a57600080fd5b505afa15801561272e573d6000803e3d6000fd5b505050506040513d60e081101561274457600080fd5b5051905061276581612755866137b4565b61275e866137b4565b8989613adb565b9150505b95945050505050565b6000806000866001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b1580156127b057600080fd5b505afa1580156127c4573d6000803e3d6000fd5b505050506040513d60e08110156127da57600080fd5b505190506127fa816127eb876137b4565b6127f4876137b4565b89613b9d565b92509250505b94509492505050565b600061281f856128198685611d1c565b90613c38565b61282d856128198887611d1c565b11612839576000612769565b600195945050505050565b60008060006040518060e00160405280888152602001878152602001600081526020016000815260200160006001600160801b03168152602001600060020b8152602001600060020b8152509050600080896001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b1580156128ce57600080fd5b505afa1580156128e2573d6000803e3d6000fd5b505050506040513d60e08110156128f857600080fd5b50805160209091015190925090506129118188886124fd565b600290810b810b60c0860181905291810b900b60a085018190528451602086015161293e938e9390613c5c565b606085018190526040850182905260a085015160c0860151612965938e93909290916126de565b6001600160801b0316608084015282516020840151604085015160608601516000936129949390929091612809565b905080156129da5760006129b48486608001518760000151600080613c8b565b90506129c86129c282613e6f565b89613768565b600290810b900b60c086015250612a0f565b60006129f3848660800151876020015160016000613c8b565b9050612a016129c282613e6f565b600290810b900b60a0860152505b612a228460a001518560c00151896132f8565b612a308460a0015188613768565b9550612a408460c0015188613768565b9450505050509550959350505050565b6001600160a01b038316612a955760405162461bcd60e51b8152600401808060200182810382526025815260200180614e6c6025913960400191505060405180910390fd5b6001600160a01b038216612ada5760405162461bcd60e51b8152600401808060200182810382526023815260200180614d0b6023913960400191505060405180910390fd5b612ae583838361317e565b612b2281604051806060016040528060268152602001614d72602691396001600160a01b0386166000908152602081905260409020549190612b99565b6001600160a01b038085166000908152602081905260408082209390935590841681522054612b519082612e5a565b6001600160a01b03808416600081815260208181526040918290209490945580518581529051919392871692600080516020614e2b83398151915292918290030190a3505050565b60008184841115612c285760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612bed578181015183820152602001612bd5565b50505050905090810190601f168015612c1a5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600a546001600160a01b03163314612c4757600080fd5b565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b60208310612cc55780518252601f199092019160209182019101612ca6565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612d27576040519150601f19603f3d011682016040523d82523d6000602084013e612d2c565b606091505b5091509150818015612d5a575080511580612d5a5750808060200190516020811015612d5757600080fd5b50515b610d7d576040805162461bcd60e51b815260206004820152600260248201526114d560f21b604482015290519081900360640190fd5b60007f000000000000000000000000000000000000000000000000000000000000044d612dbb61415a565b1415612de857507f76d9c86506021fb1e24425d4a37aed47447b2d6fc3eb06191b32de199850f272610837565b612e537f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7fcac9caa3e7fd118df8e0f7e886ac0ebcc5d62dd582affb51fe90cb7bb541c6787fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc661415e565b9050610837565b600082820183811015610cff576040805162461bcd60e51b815260206004820152601b60248201527a536166654d6174683a206164646974696f6e206f766572666c6f7760281b604482015290519081900360640190fd5b5490565b6000806000806000806000612ecc8f8f8a613261565b505093509350935093506000612ef58c612eef8588611d5d90919063ffffffff16565b90611d5d565b90506000612f078c612eef8786611d5d565b90508a1580612f1557508115155b80612f1f57508015155b612f2557fe5b612f328f8f84848f6141c0565b809950819a50829b50505050505050505050985098509895505050505050565b600c546001600160a01b038581169116148015612f6f5750804710155b1561306757600c60009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612fc457600080fd5b505af1158015612fd8573d6000803e3d6000fd5b5050600c5460405163a9059cbb60e01b81526001600160a01b03909116935063a9059cbb925061300f915085908590600401614b50565b602060405180830381600087803b15801561302957600080fd5b505af115801561303d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061306191906148e0565b50611e08565b6001600160a01b03831630141561308357611df8848383612c49565b611e0884848484614254565b604080516000808252602082019092526001600160a01b0384169083906040518082805190602001908083835b602083106130db5780518252601f1990920191602091820191016130bc565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d806000811461313d576040519150601f19603f3d011682016040523d82523d6000602084013e613142565b606091505b505090508061317e576040805162461bcd60e51b815260206004820152600360248201526253544560e81b604482015290519081900360640190fd5b505050565b6001600160a01b0382166131de576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b6131ea6000838361317e565b6002546131f79082612e5a565b6002556001600160a01b03821660009081526020819052604090205461321d9082612e5a565b6001600160a01b038316600081815260208181526040808320949094558351858152935192939192600080516020614e2b8339815191529281900390910190a35050565b60008060008060008061327d89886000015189602001516143a4565b939950919750955093509150876132ec5760008060008060006132a98e8d604001518e606001516143a4565b9398509196509450925090506132bf8b86611d5d565b9a506132cb8a85611d5d565b99506132d78984611d5d565b98506132e38883611d5d565b97509450505050505b93975093979195509350565b8160020b8360020b12613338576040805162461bcd60e51b8152602060048201526003602482015262544c5560e81b604482015290519081900360640190fd5b620d89e719600284900b121561337b576040805162461bcd60e51b8152602060048201526003602482015262544c4d60e81b604482015290519081900360640190fd5b620d89e8600283900b13156133bd576040805162461bcd60e51b815260206004820152600360248201526254554d60e81b604482015290519081900360640190fd5b8060020b8360020b816133cc57fe5b0760020b15613408576040805162461bcd60e51b8152602060048201526003602482015262544c4960e81b604482015290519081900360640190fd5b8060020b8260020b8161341757fe5b0760020b1561317e576040805162461bcd60e51b815260206004820152600360248201526254554960e81b604482015290519081900360640190fd5b600061345d612d90565b82604051602001808061190160f01b81525060020183815260200182815260200192505050604051602081830303815290604052805190602001209050919050565b60006fa2a8918ca85bafe22016d0b997e4df60600160ff1b038211156134f65760405162461bcd60e51b8152600401808060200182810382526022815260200180614dbf6022913960400191505060405180910390fd5b8360ff16601b148061350b57508360ff16601c145b6135465760405162461bcd60e51b8152600401808060200182810382526022815260200180614de16022913960400191505060405180910390fd5b600060018686868660405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156135a2573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116612769576040805162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b604482015290519081900360640190fd5b80546001019055565b6000600160801b821061255e5760405162461bcd60e51b8152600401808060200182810382526027815260200180614d986027913960400191505060405180910390fd5b60006136686001600160a01b0385168484612170565b50909150506001600160801b03811615610cff57836001600160a01b031663a34123a7848460006040518463ffffffff1660e01b8152600401808460020b81526020018360020b815260200182815260200193505050506040805180830381600087803b1580156136d857600080fd5b505af11580156136ec573d6000803e3d6000fd5b505050506040513d604081101561370257600080fd5b50509392505050565b600082821115613762576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000808260020b8460020b8161377a57fe5b05905060008460020b1280156137a157508260020b8460020b8161379a57fe5b0760020b15155b156137ab57600019015b90910292915050565b60008060008360020b126137cb578260020b6137d3565b8260020b6000035b9050620d89e8811115613811576040805162461bcd60e51b81526020600482015260016024820152601560fa1b604482015290519081900360640190fd5b60006001821661382557600160801b613837565b6ffffcb933bd6fad37aa2d162d1a5940015b6001600160881b031690506002821615613861576ffff97272373d413259a46990580e213a0260801c5b6004821615613880576ffff2e50f5f656932ef12357cf3c7fdcc0260801c5b600882161561389f576fffe5caca7e10e4e61c3624eaa0941cd00260801c5b60108216156138be576fffcb9843d60f6159c9db58835c9266440260801c5b60208216156138dd576fff973b41fa98c081472e6896dfb254c00260801c5b60408216156138fc576fff2ea16466c96a3843ec78b326b528610260801c5b608082161561391b576ffe5dee046a99a2a811c461f1969c30530260801c5b61010082161561393b576ffcbe86c7900a88aedcffc83b479aa3a40260801c5b61020082161561395b576ff987a7253ac413176f2b074cf7815e540260801c5b61040082161561397b576ff3392b0822b70005940c7a398e4b70f30260801c5b61080082161561399b576fe7159475a2c29b7443b29c7fa6e889d90260801c5b6110008216156139bb576fd097f3bdfd2022b8845ad8f792aa58250260801c5b6120008216156139db576fa9f746462d870fdf8a65dc1f90e061e50260801c5b6140008216156139fb576f70d869a156d2a1b890bb3df62baf32f70260801c5b618000821615613a1b576f31be135f97d08fd981231505542fcfa60260801c5b62010000821615613a3c576f09aa508b5b7a84e1c677de54f3e99bc90260801c5b62020000821615613a5c576e5d6af8dedb81196699c329225ee6040260801c5b62040000821615613a7b576d2216e584f5fa1ea926041bedfe980260801c5b62080000821615613a98576b048a170391f7dc42444e8fa20260801c5b60008460020b1315613ab3578060001981613aaf57fe5b0490505b600160201b810615613ac6576001613ac9565b60005b60ff16602082901c0192505050919050565b6000836001600160a01b0316856001600160a01b03161115613afb579293925b846001600160a01b0316866001600160a01b031611613b2657613b1f8585856143e9565b9050612769565b836001600160a01b0316866001600160a01b03161015613b88576000613b4d8786866143e9565b90506000613b5c87898661444c565b9050806001600160801b0316826001600160801b031610613b7d5780613b7f565b815b92505050612769565b613b9385858461444c565b9695505050505050565b600080836001600160a01b0316856001600160a01b03161115613bbe579293925b846001600160a01b0316866001600160a01b031611613be957613be2858585614491565b9150612800565b836001600160a01b0316866001600160a01b03161015613c2257613c0e868585614491565b9150613c1b8587856144fa565b9050612800565b613c2d8585856144fa565b905094509492505050565b6000821580613c5357505081810281838281613c5057fe5b04145b61085257600080fd5b6000806000613c6e88888888886126de565b9050613c7c88828787612772565b90999098509650505050505050565b600080866001600160a01b031611613ca257600080fd5b6000856001600160801b031611613cb857600080fd5b8115158315151415613da15783613cd0575084612769565b600160601b600160e01b03606086901b168215613d55576001600160a01b03871685810290868281613cfe57fe5b041415613d2f57818101828110613d2d57613d23838a6001600160a01b03168361453d565b9350505050612769565b505b613b7f82613d50888b6001600160a01b03168681613d4957fe5b0490611d5d565b6145b1565b6001600160a01b03871685810290868281613d6c57fe5b0414613d7757600080fd5b808211613d8357600080fd5b613b7f613d9c838a6001600160a01b031684860361453d565b6145bc565b8115613e0157613b1f613d9c6001600160a01b03861115613dd957613dd486600160601b896001600160801b03166118c2565b613df1565b6001600160801b038716606087901b81613def57fe5b045b6001600160a01b03891690611d5d565b60006001600160a01b03851115613e2f57613e2a85600160601b886001600160801b031661453d565b613e46565b613e46606086901b6001600160801b0388166145b1565b905080876001600160a01b031611613e5d57600080fd5b6001600160a01b038716039050612769565b60006401000276a36001600160a01b03831610801590613eab575073fffd8963efd1fc6a506488495d951d5263988d266001600160a01b038316105b613ee0576040805162461bcd60e51b81526020600482015260016024820152602960f91b604482015290519081900360640190fd5b600160201b600160c01b03602083901b166001600160801b03811160071b81811c6001600160401b03811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c60ff8111600390811b91821c600f811160021b90811c918211600190811b92831c97908811961790941790921717909117171760808110613f7257607f810383901c9150613f7c565b80607f0383901b91505b908002607f81811c60ff83811c9190911c800280831c81831c1c800280841c81841c1c800280851c81851c1c800280861c81861c1c800280871c81871c1c800280881c81881c1c800280891c81891c1c8002808a1c818a1c1c8002808b1c818b1c1c8002808c1c818c1c1c8002808d1c818d1c1c8002808e1c9c81901c9c909c1c80029c8d901c9e9d607f198f0160401b60c09190911c6001603f1b161760c19b909b1c6001603e1b169a909a1760c29990991c6001603d1b169890981760c39790971c6001603c1b169690961760c49590951c6001603b1b169490941760c59390931c6001603a1b169290921760c69190911c600160391b161760c79190911c600160381b161760c89190911c600160371b161760c99190911c600160361b161760ca9190911c600160351b161760cb9190911c600160341b161760cc9190911c600160331b161760cd9190911c600160321b1617693627a301d71055774c8581026f028f6481ab7f045a5af012a19d003aa9198101608090811d906fdb2df09e81959a81455e260799a0632f8301901d600281810b9083900b1461414b57886001600160a01b031661412f826137b4565b6001600160a01b031611156141445781614146565b805b61414d565b815b9998505050505050505050565b4690565b600083838361416b61415a565b3060405160200180868152602001858152602001848152602001838152602001826001600160a01b03168152602001955050505050506040516020818303038152906040528051906020012090509392505050565b60008080836141e45750869050858082116141db57806141dd565b815b9250614249565b856141f65750856141dd8185876118c2565b84614209578791506141dd8285886118c2565b6142148787876118c2565b91508782101561422b5750856141dd8185876118c2565b8791506142398286886118c2565b90506142468285886118c2565b92505b955095509592505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b178152925182516000948594938a169392918291908083835b602083106142d85780518252601f1990920191602091820191016142b9565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811461433a576040519150601f19603f3d011682016040523d82523d6000602084013e61433f565b606091505b509150915081801561436d57508051158061436d575080806020019051602081101561436a57600080fd5b50515b610e48576040805162461bcd60e51b815260206004820152600360248201526229aa2360e91b604482015290519081900360640190fd5b60008060008060006143b7888888613652565b90506001600160801b038116156143de576143d38888886145d2565b929750909550935091505b939792965093509350565b6000826001600160a01b0316846001600160a01b03161115614409579192915b600061442c856001600160a01b0316856001600160a01b0316600160601b6118c2565b905061276961444784838888036001600160a01b03166118c2565b61461e565b6000826001600160a01b0316846001600160a01b0316111561446c579192915b61448961444783600160601b8787036001600160a01b03166118c2565b949350505050565b6000826001600160a01b0316846001600160a01b031611156144b1579192915b836001600160a01b03166144ea606060ff16846001600160801b0316901b8686036001600160a01b0316866001600160a01b03166118c2565b816144f157fe5b04949350505050565b6000826001600160a01b0316846001600160a01b0316111561451a579192915b614489826001600160801b03168585036001600160a01b0316600160601b6118c2565b60008315806145585750508282028284828161455557fe5b04145b15614579576000821161456a57600080fd5b81810490829006151501610cff565b6145848484846118c2565b90506000828061459057fe5b8486091115610cff5760001981106145a757600080fd5b6001019392505050565b808204910615150190565b806001600160a01b0381168114610ec557600080fd5b60008060008060008060006145e88a8a8a612170565b9250925092506000806145fd8c868d8d612772565b9099509750506001600160801b039283169550501691505093509350935093565b806001600160801b0381168114610ec557600080fd5b604051806101c001604052806000815260200160008152602001600060020b8152602001600060020b8152602001600060020b8152602001600081526020016000815260200160006001600160801b0316815260200160008152602001600081526020016000151581526020016000815260200160006001600160a01b0316815260200160006001600160a01b031681525090565b60008083601f8401126146da578182fd5b5081356001600160401b038111156146f0578182fd5b60208301915083602082850101111561470857600080fd5b9250929050565b805161ffff81168114610ec557600080fd5b600060208284031215614732578081fd5b8135610cff81614cc6565b6000806040838503121561474f578081fd5b823561475a81614cc6565b9150602083013561476a81614cc6565b809150509250929050565b600080600080600060a0868803121561478c578081fd5b855161479781614cc6565b60208701519095506147a881614cc6565b60408701519094506147b981614cc6565b60608701519093506147ca81614cfb565b60808701519092506147db81614cfb565b809150509295509295909350565b6000806000606084860312156147fd578283fd5b833561480881614cc6565b9250602084013561481881614cc6565b929592945050506040919091013590565b600080600080600080600060e0888a031215614843578182fd5b873561484e81614cc6565b9650602088013561485e81614cc6565b95506040880135945060608801359350608088013561487c81614cfb565b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156148ab578182fd5b82356148b681614cc6565b946020939093013593505050565b6000602082840312156148d5578081fd5b8135610cff81614cde565b6000602082840312156148f1578081fd5b8151610cff81614cde565b60006020828403121561490d578081fd5b8151610cff81614cec565b6000806000806080858703121561492d578182fd5b84359350602085013561493f81614cde565b9250604085013561494f81614cec565b9150606085013561495f81614cec565b939692955090935050565b6000806000806060858703121561497f578182fd5b843593506020850135925060408501356001600160401b038111156149a2578283fd5b6149ae878288016146c9565b95989497509550505050565b600080600080600080600060e0888a0312156149d4578081fd5b87516149df81614cc6565b60208901519097506149f081614cec565b95506149fe6040890161470f565b9450614a0c6060890161470f565b93506080880151614a1c81614cfb565b60a0890151909350614a2d81614cfb565b60c0890151909250614a3e81614cde565b8091505092959891949750929550565b600060208284031215614a5f578081fd5b5051919050565b600080600060608486031215614a7a578081fd5b833592506020840135614a8c81614cc6565b91506040840135614a9c81614cde565b809150509250925092565b600080600060608486031215614abb578081fd5b83359250602084013591506040840135614a9c81614cc6565b600060208284031215614ae5578081fd5b8135610cff81614cfb565b6001600160a01b0391909116815260200190565b6001600160a01b039485168152928416602084015261ffff919091166040830152909116606082015260800190565b6001600160a01b0392909216825261ffff16602082015260400190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b92151583526020830191909152604082015260600190565b90815260200190565b600294850b815292840b602084015290830b604083015290910b606082015260800190565b6000602080835283518082850152825b81811015614be657858101830151858201604001528201614bca565b81811115614bf75783604083870101525b50601f01601f1916929092016040019392505050565b602080825260029082015261135360f21b604082015260600190565b602080825260029082015261495360f01b604082015260600190565b918252602082015260400190565b9283526020830191909152604082015260600190565b93845260208401929092526040830152606082015260800190565b9586526020860194909452604085019290925260608401526001600160801b0390811660808401521660a082015260c00190565b60ff91909116815260200190565b6001600160a01b0381168114614cdb57600080fd5b50565b8015158114614cdb57600080fd5b8060020b8114614cdb57600080fd5b60ff81168114614cdb57600080fdfe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636553616665436173743a2076616c756520646f65736e27742066697420696e20313238206269747345434453413a20696e76616c6964207369676e6174757265202773272076616c756545434453413a20696e76616c6964207369676e6174757265202776272076616c756545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e6365ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef45524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737353616665436173743a2076616c756520646f65736e27742066697420696e20616e20696e7432353645524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa164736f6c6343000706000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c44ad482f24fd750caeba387d2726d8653f8c4bb000000000000000000000000c99fa77ab721817da9dd3c3b4f8ecb13772fcece0000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e9000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000028556e6970696c6f7420574554482f555344432042414c414e43454420416374697665205661756c740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012554c502d574554482f555344432d41562d320000000000000000000000000000
-----Decoded View---------------
Arg [0] : _pool (address): 0xc44AD482f24fd750cAeBa387d2726d8653F8c4bB
Arg [1] : _unipilotFactory (address): 0xC99fA77AB721817Da9dD3C3b4F8ecB13772FCECE
Arg [2] : _WETH (address): 0x4F9A0e7FD2Bf6067db6994CF12E4495Df938E6e9
Arg [3] : _strategytype (uint16): 2
Arg [4] : _name (string): Unipilot WETH/USDC BALANCED Active Vault
Arg [5] : _symbol (string): ULP-WETH/USDC-AV-2
-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 000000000000000000000000c44ad482f24fd750caeba387d2726d8653f8c4bb
Arg [1] : 000000000000000000000000c99fa77ab721817da9dd3c3b4f8ecb13772fcece
Arg [2] : 0000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e9
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [4] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000028
Arg [7] : 556e6970696c6f7420574554482f555344432042414c414e4345442041637469
Arg [8] : 7665205661756c74000000000000000000000000000000000000000000000000
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000012
Arg [10] : 554c502d574554482f555344432d41562d320000000000000000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ZKEVM | 100.00% | $2,421.74 | 0.00067073 | $1.62 |
[ 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.