More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 1,172,816 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Remove Liquidity | 54339752 | 28 hrs ago | IN | 0 AVAX | 0.02172537 | ||||
Remove Liquidity | 54328689 | 34 hrs ago | IN | 0 AVAX | 0.02028385 | ||||
Remove Liquidity | 54323861 | 37 hrs ago | IN | 0 AVAX | 0.02150088 | ||||
Remove Liquidity | 54304840 | 2 days ago | IN | 0 AVAX | 0.05142225 | ||||
Remove Liquidity | 54219633 | 4 days ago | IN | 0 AVAX | 0.02280036 | ||||
Remove Liquidity... | 54177838 | 5 days ago | IN | 0 AVAX | 0.02511553 | ||||
Remove Liquidity | 54164091 | 5 days ago | IN | 0 AVAX | 0.02319038 | ||||
Remove Liquidity | 54129247 | 6 days ago | IN | 0 AVAX | 0.05553203 | ||||
Remove Liquidity | 54125103 | 6 days ago | IN | 0 AVAX | 0.00423534 | ||||
Remove Liquidity | 54076270 | 7 days ago | IN | 0 AVAX | 0.02249592 | ||||
Remove Liquidity... | 54059814 | 7 days ago | IN | 0 AVAX | 0.1807314 | ||||
Remove Liquidity... | 54059750 | 7 days ago | IN | 0 AVAX | 0.3481686 | ||||
Remove Liquidity... | 54046143 | 8 days ago | IN | 0 AVAX | 0.02244992 | ||||
Remove Liquidity... | 54041100 | 8 days ago | IN | 0 AVAX | 0.02303663 | ||||
Remove Liquidity... | 54011951 | 8 days ago | IN | 0 AVAX | 0.02214271 | ||||
Remove Liquidity | 53997789 | 9 days ago | IN | 0 AVAX | 0.00422279 | ||||
Set Approval For... | 53967813 | 10 days ago | IN | 0 AVAX | 0.00054407 | ||||
Set Approval For... | 53967792 | 10 days ago | IN | 0 AVAX | 0.00054407 | ||||
Remove Liquidity | 53921547 | 11 days ago | IN | 0 AVAX | 0.02634964 | ||||
Remove Liquidity | 53908195 | 11 days ago | IN | 0 AVAX | 0.02235526 | ||||
Remove Liquidity | 53905355 | 11 days ago | IN | 0 AVAX | 0.05586427 | ||||
Remove Liquidity | 53902503 | 11 days ago | IN | 0 AVAX | 0.03747045 | ||||
Remove Liquidity... | 53902488 | 11 days ago | IN | 0 AVAX | 0.08654207 | ||||
Remove Liquidity | 53899445 | 11 days ago | IN | 0 AVAX | 0.05526877 | ||||
Add Liquidity | 53852518 | 12 days ago | IN | 0 AVAX | 0.01121552 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
54011951 | 8 days ago | 0.14116607 AVAX | ||||
54011951 | 8 days ago | 0.14116607 AVAX | ||||
52116852 | 53 days ago | 1.16910804 AVAX | ||||
52116852 | 53 days ago | 1.16910804 AVAX | ||||
51313743 | 73 days ago | 8.23723228 AVAX | ||||
51188044 | 76 days ago | 17.734 AVAX | ||||
50136303 | 101 days ago | 58.88289852 AVAX | ||||
50136303 | 101 days ago | 58.88289852 AVAX | ||||
50107738 | 102 days ago | 0.0001 AVAX | ||||
49592178 | 114 days ago | 0.38782202 AVAX | ||||
49592178 | 114 days ago | 0.38782202 AVAX | ||||
48829336 | 133 days ago | 3.50327614 AVAX | ||||
48829336 | 133 days ago | 3.50327614 AVAX | ||||
48333470 | 145 days ago | 0.17201413 AVAX | ||||
48333470 | 145 days ago | 0.17201413 AVAX | ||||
47927834 | 154 days ago | 4.49781789 AVAX | ||||
47927834 | 154 days ago | 4.49781789 AVAX | ||||
47927812 | 154 days ago | 0.55613686 AVAX | ||||
47927812 | 154 days ago | 0.55613686 AVAX | ||||
47522542 | 164 days ago | 10.00042585 AVAX | ||||
47522542 | 164 days ago | 10.00042585 AVAX | ||||
47296533 | 170 days ago | 80.65972032 AVAX | ||||
47296533 | 170 days ago | 80.65972032 AVAX | ||||
46865473 | 180 days ago | 0.12772522 AVAX | ||||
46865473 | 180 days ago | 0.12772522 AVAX |
Loading...
Loading
Contract Name:
LBRouter
Compiler Version
v0.8.10+commit.fc410830
Optimization Enabled:
Yes with 800 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "openzeppelin/token/ERC20/IERC20.sol"; import "./LBErrors.sol"; import "./libraries/BinHelper.sol"; import "./libraries/Constants.sol"; import "./libraries/FeeHelper.sol"; import "./libraries/JoeLibrary.sol"; import "./libraries/Math512Bits.sol"; import "./libraries/SwapHelper.sol"; import "./libraries/TokenHelper.sol"; import "./interfaces/IJoePair.sol"; import "./interfaces/ILBToken.sol"; import "./interfaces/ILBRouter.sol"; /// @title Liquidity Book Router /// @author Trader Joe /// @notice Main contract to interact with to swap and manage liquidity on Joe V2 exchange. contract LBRouter is ILBRouter { using TokenHelper for IERC20; using TokenHelper for IWAVAX; using FeeHelper for FeeHelper.FeeParameters; using Math512Bits for uint256; using SwapHelper for ILBPair.Bin; using JoeLibrary for uint256; ILBFactory public immutable override factory; IJoeFactory public immutable override oldFactory; IWAVAX public immutable override wavax; modifier onlyFactoryOwner() { if (msg.sender != factory.owner()) revert LBRouter__NotFactoryOwner(); _; } modifier ensure(uint256 _deadline) { if (block.timestamp > _deadline) revert LBRouter__DeadlineExceeded(_deadline, block.timestamp); _; } modifier verifyInputs(uint256[] memory _pairBinSteps, IERC20[] memory _tokenPath) { if (_pairBinSteps.length == 0 || _pairBinSteps.length + 1 != _tokenPath.length) revert LBRouter__LengthsMismatch(); _; } /// @notice Constructor /// @param _factory LBFactory address /// @param _oldFactory Address of old factory (Joe V1) /// @param _wavax Address of WAVAX constructor( ILBFactory _factory, IJoeFactory _oldFactory, IWAVAX _wavax ) { factory = _factory; oldFactory = _oldFactory; wavax = _wavax; } /// @dev Receive function that only accept AVAX from the WAVAX contract receive() external payable { if (msg.sender != address(wavax)) revert LBRouter__SenderIsNotWAVAX(); } /// @notice Returns the approximate id corresponding to the inputted price. /// Warning, the returned id may be inaccurate close to the start price of a bin /// @param _LBPair The address of the LBPair /// @param _price The price of y per x (multiplied by 1e36) /// @return The id corresponding to this price function getIdFromPrice(ILBPair _LBPair, uint256 _price) external view override returns (uint24) { return BinHelper.getIdFromPrice(_price, _LBPair.feeParameters().binStep); } /// @notice Returns the price corresponding to the inputted id /// @param _LBPair The address of the LBPair /// @param _id The id /// @return The price corresponding to this id function getPriceFromId(ILBPair _LBPair, uint24 _id) external view override returns (uint256) { return BinHelper.getPriceFromId(_id, _LBPair.feeParameters().binStep); } /// @notice Simulate a swap in /// @param _LBPair The address of the LBPair /// @param _amountOut The amount of token to receive /// @param _swapForY Whether you swap X for Y (true), or Y for X (false) /// @return amountIn The amount of token to send in order to receive _amountOut token /// @return feesIn The amount of fees paid in token sent function getSwapIn( ILBPair _LBPair, uint256 _amountOut, bool _swapForY ) public view override returns (uint256 amountIn, uint256 feesIn) { (uint256 _pairReserveX, uint256 _pairReserveY, uint256 _activeId) = _LBPair.getReservesAndId(); if (_amountOut == 0 || (_swapForY ? _amountOut > _pairReserveY : _amountOut > _pairReserveX)) revert LBRouter__WrongAmounts(_amountOut, _swapForY ? _pairReserveY : _pairReserveX); // If this is wrong, then we're sure the amounts sent are wrong FeeHelper.FeeParameters memory _fp = _LBPair.feeParameters(); _fp.updateVariableFeeParameters(_activeId); uint256 _amountOutOfBin; uint256 _amountInWithFees; uint256 _reserve; // Performs the actual swap, bin per bin // It uses the findFirstNonEmptyBinId function to make sure the bin we're currently looking at // has liquidity in it. while (true) { { (uint256 _reserveX, uint256 _reserveY) = _LBPair.getBin(uint24(_activeId)); _reserve = _swapForY ? _reserveY : _reserveX; } uint256 _price = BinHelper.getPriceFromId(_activeId, _fp.binStep); if (_reserve != 0) { _amountOutOfBin = _amountOut >= _reserve ? _reserve : _amountOut; uint256 _amountInToBin = _swapForY ? _amountOutOfBin.shiftDivRoundUp(Constants.SCALE_OFFSET, _price) : _price.mulShiftRoundUp(_amountOutOfBin, Constants.SCALE_OFFSET); // We update the fee, but we don't store the new volatility reference, volatility accumulated and indexRef to not penalize traders _fp.updateVolatilityAccumulated(_activeId); uint256 _fee = _fp.getFeeAmount(_amountInToBin); _amountInWithFees = _amountInToBin + _fee; if (_amountInWithFees + _reserve > type(uint112).max) revert LBRouter__SwapOverflows(_activeId); amountIn += _amountInWithFees; feesIn += _fee; _amountOut -= _amountOutOfBin; } if (_amountOut != 0) { _activeId = _LBPair.findFirstNonEmptyBinId(uint24(_activeId), _swapForY); } else { break; } } if (_amountOut != 0) revert LBRouter__BrokenSwapSafetyCheck(); // Safety check, but should never be false as it would have reverted on transfer } /// @notice Simulate a swap out /// @param _LBPair The address of the LBPair /// @param _amountIn The amount of token sent /// @param _swapForY Whether you swap X for Y (true), or Y for X (false) /// @return amountOut The amount of token received if _amountIn tokenX are sent /// @return feesIn The amount of fees paid in token sent function getSwapOut( ILBPair _LBPair, uint256 _amountIn, bool _swapForY ) external view override returns (uint256 amountOut, uint256 feesIn) { (, , uint256 _activeId) = _LBPair.getReservesAndId(); FeeHelper.FeeParameters memory _fp = _LBPair.feeParameters(); _fp.updateVariableFeeParameters(_activeId); ILBPair.Bin memory _bin; // Performs the actual swap, bin per bin // It uses the findFirstNonEmptyBinId function to make sure the bin we're currently looking at // has liquidity in it. while (true) { { (uint256 _reserveX, uint256 _reserveY) = _LBPair.getBin(uint24(_activeId)); _bin = ILBPair.Bin(uint112(_reserveX), uint112(_reserveY), 0, 0); } if (_bin.reserveX != 0 || _bin.reserveY != 0) { (uint256 _amountInToBin, uint256 _amountOutOfBin, FeeHelper.FeesDistribution memory _fees) = _bin .getAmounts(_fp, _activeId, _swapForY, _amountIn); if (_amountInToBin > type(uint112).max) revert LBRouter__BinReserveOverflows(_activeId); _amountIn -= _amountInToBin + _fees.total; feesIn += _fees.total; amountOut += _amountOutOfBin; } if (_amountIn != 0) { _activeId = _LBPair.findFirstNonEmptyBinId(uint24(_activeId), _swapForY); } else { break; } } if (_amountIn != 0) revert LBRouter__TooMuchTokensIn(_amountIn); } /// @notice Create a liquidity bin LBPair for _tokenX and _tokenY using the factory /// @param _tokenX The address of the first token /// @param _tokenY The address of the second token /// @param _activeId The active id of the pair /// @param _binStep The bin step in basis point, used to calculate log(1 + binStep) /// @return pair The address of the newly created LBPair function createLBPair( IERC20 _tokenX, IERC20 _tokenY, uint24 _activeId, uint16 _binStep ) external override returns (ILBPair pair) { pair = factory.createLBPair(_tokenX, _tokenY, _activeId, _binStep); } /// @notice Add liquidity while performing safety checks /// @dev This function is compliant with fee on transfer tokens /// @param _liquidityParameters The liquidity parameters /// @return depositIds Bin ids where the liquidity was actually deposited /// @return liquidityMinted Amounts of LBToken minted for each bin function addLiquidity(LiquidityParameters calldata _liquidityParameters) external override returns (uint256[] memory depositIds, uint256[] memory liquidityMinted) { ILBPair _LBPair = _getLBPairInformation( _liquidityParameters.tokenX, _liquidityParameters.tokenY, _liquidityParameters.binStep ); if (_liquidityParameters.tokenX != _LBPair.tokenX()) revert LBRouter__WrongTokenOrder(); _liquidityParameters.tokenX.safeTransferFrom(msg.sender, address(_LBPair), _liquidityParameters.amountX); _liquidityParameters.tokenY.safeTransferFrom(msg.sender, address(_LBPair), _liquidityParameters.amountY); (depositIds, liquidityMinted) = _addLiquidity(_liquidityParameters, _LBPair); } /// @notice Add liquidity with AVAX while performing safety checks /// @dev This function is compliant with fee on transfer tokens /// @param _liquidityParameters The liquidity parameters /// @return depositIds Bin ids where the liquidity was actually deposited /// @return liquidityMinted Amounts of LBToken minted for each bin function addLiquidityAVAX(LiquidityParameters calldata _liquidityParameters) external payable override returns (uint256[] memory depositIds, uint256[] memory liquidityMinted) { ILBPair _LBPair = _getLBPairInformation( _liquidityParameters.tokenX, _liquidityParameters.tokenY, _liquidityParameters.binStep ); if (_liquidityParameters.tokenX != _LBPair.tokenX()) revert LBRouter__WrongTokenOrder(); if (_liquidityParameters.tokenX == wavax && _liquidityParameters.amountX == msg.value) { _wavaxDepositAndTransfer(address(_LBPair), msg.value); _liquidityParameters.tokenY.safeTransferFrom(msg.sender, address(_LBPair), _liquidityParameters.amountY); } else if (_liquidityParameters.tokenY == wavax && _liquidityParameters.amountY == msg.value) { _liquidityParameters.tokenX.safeTransferFrom(msg.sender, address(_LBPair), _liquidityParameters.amountX); _wavaxDepositAndTransfer(address(_LBPair), msg.value); } else revert LBRouter__WrongAvaxLiquidityParameters( address(_liquidityParameters.tokenX), address(_liquidityParameters.tokenY), _liquidityParameters.amountX, _liquidityParameters.amountY, msg.value ); (depositIds, liquidityMinted) = _addLiquidity(_liquidityParameters, _LBPair); } /// @notice Remove liquidity while performing safety checks /// @dev This function is compliant with fee on transfer tokens /// @param _tokenX The address of token X /// @param _tokenY The address of token Y /// @param _binStep The bin step of the LBPair /// @param _amountXMin The min amount to receive of token X /// @param _amountYMin The min amount to receive of token Y /// @param _ids The list of ids to burn /// @param _amounts The list of amounts to burn of each id in `_ids` /// @param _to The address of the recipient /// @param _deadline The deadline of the tx /// @return amountX Amount of token X returned /// @return amountY Amount of token Y returned function removeLiquidity( IERC20 _tokenX, IERC20 _tokenY, uint16 _binStep, uint256 _amountXMin, uint256 _amountYMin, uint256[] memory _ids, uint256[] memory _amounts, address _to, uint256 _deadline ) external override ensure(_deadline) returns (uint256 amountX, uint256 amountY) { ILBPair _LBPair = _getLBPairInformation(_tokenX, _tokenY, _binStep); bool _isWrongOrder = _tokenX != _LBPair.tokenX(); if (_isWrongOrder) (_amountXMin, _amountYMin) = (_amountYMin, _amountXMin); (amountX, amountY) = _removeLiquidity(_LBPair, _amountXMin, _amountYMin, _ids, _amounts, _to); if (_isWrongOrder) (amountX, amountY) = (amountY, amountX); } /// @notice Remove AVAX liquidity while performing safety checks /// @dev This function is **NOT** compliant with fee on transfer tokens. /// This is wanted as it would make users pays the fee on transfer twice, /// use the `removeLiquidity` function to remove liquidity with fee on transfer tokens. /// @param _token The address of token /// @param _binStep The bin step of the LBPair /// @param _amountTokenMin The min amount to receive of token /// @param _amountAVAXMin The min amount to receive of AVAX /// @param _ids The list of ids to burn /// @param _amounts The list of amounts to burn of each id in `_ids` /// @param _to The address of the recipient /// @param _deadline The deadline of the tx /// @return amountToken Amount of token returned /// @return amountAVAX Amount of AVAX returned function removeLiquidityAVAX( IERC20 _token, uint16 _binStep, uint256 _amountTokenMin, uint256 _amountAVAXMin, uint256[] memory _ids, uint256[] memory _amounts, address payable _to, uint256 _deadline ) external override ensure(_deadline) returns (uint256 amountToken, uint256 amountAVAX) { ILBPair _LBPair = _getLBPairInformation(_token, IERC20(wavax), _binStep); bool _isAVAXTokenY = IERC20(wavax) == _LBPair.tokenY(); { if (!_isAVAXTokenY) { (_amountTokenMin, _amountAVAXMin) = (_amountAVAXMin, _amountTokenMin); } (uint256 _amountX, uint256 _amountY) = _removeLiquidity( _LBPair, _amountTokenMin, _amountAVAXMin, _ids, _amounts, address(this) ); (amountToken, amountAVAX) = _isAVAXTokenY ? (_amountX, _amountY) : (_amountY, _amountX); } _token.safeTransfer(_to, amountToken); wavax.withdraw(amountAVAX); _safeTransferAVAX(_to, amountAVAX); } /// @notice Swaps exact tokens for tokens while performing safety checks /// @param _amountIn The amount of token to send /// @param _amountOutMin The min amount of token to receive /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2) /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps` /// @param _to The address of the recipient /// @param _deadline The deadline of the tx /// @return amountOut Output amount of the swap function swapExactTokensForTokens( uint256 _amountIn, uint256 _amountOutMin, uint256[] memory _pairBinSteps, IERC20[] memory _tokenPath, address _to, uint256 _deadline ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) { address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath); _tokenPath[0].safeTransferFrom(msg.sender, _pairs[0], _amountIn); amountOut = _swapExactTokensForTokens(_amountIn, _pairs, _pairBinSteps, _tokenPath, _to); if (_amountOutMin > amountOut) revert LBRouter__InsufficientAmountOut(_amountOutMin, amountOut); } /// @notice Swaps exact tokens for AVAX while performing safety checks /// @param _amountIn The amount of token to send /// @param _amountOutMinAVAX The min amount of AVAX to receive /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2) /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps` /// @param _to The address of the recipient /// @param _deadline The deadline of the tx /// @return amountOut Output amount of the swap function swapExactTokensForAVAX( uint256 _amountIn, uint256 _amountOutMinAVAX, uint256[] memory _pairBinSteps, IERC20[] memory _tokenPath, address payable _to, uint256 _deadline ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) { if (_tokenPath[_pairBinSteps.length] != IERC20(wavax)) revert LBRouter__InvalidTokenPath(address(_tokenPath[_pairBinSteps.length])); address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath); _tokenPath[0].safeTransferFrom(msg.sender, _pairs[0], _amountIn); amountOut = _swapExactTokensForTokens(_amountIn, _pairs, _pairBinSteps, _tokenPath, address(this)); if (_amountOutMinAVAX > amountOut) revert LBRouter__InsufficientAmountOut(_amountOutMinAVAX, amountOut); wavax.withdraw(amountOut); _safeTransferAVAX(_to, amountOut); } /// @notice Swaps exact AVAX for tokens while performing safety checks /// @param _amountOutMin The min amount of token to receive /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2) /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps` /// @param _to The address of the recipient /// @param _deadline The deadline of the tx /// @return amountOut Output amount of the swap function swapExactAVAXForTokens( uint256 _amountOutMin, uint256[] memory _pairBinSteps, IERC20[] memory _tokenPath, address _to, uint256 _deadline ) external payable override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) { if (_tokenPath[0] != IERC20(wavax)) revert LBRouter__InvalidTokenPath(address(_tokenPath[0])); address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath); _wavaxDepositAndTransfer(_pairs[0], msg.value); amountOut = _swapExactTokensForTokens(msg.value, _pairs, _pairBinSteps, _tokenPath, _to); if (_amountOutMin > amountOut) revert LBRouter__InsufficientAmountOut(_amountOutMin, amountOut); } /// @notice Swaps tokens for exact tokens while performing safety checks /// @param _amountOut The amount of token to receive /// @param _amountInMax The max amount of token to send /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2) /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps` /// @param _to The address of the recipient /// @param _deadline The deadline of the tx /// @return amountsIn Input amounts for every step of the swap function swapTokensForExactTokens( uint256 _amountOut, uint256 _amountInMax, uint256[] memory _pairBinSteps, IERC20[] memory _tokenPath, address _to, uint256 _deadline ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256[] memory amountsIn) { address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath); amountsIn = _getAmountsIn(_pairBinSteps, _pairs, _tokenPath, _amountOut); if (amountsIn[0] > _amountInMax) revert LBRouter__MaxAmountInExceeded(_amountInMax, amountsIn[0]); _tokenPath[0].safeTransferFrom(msg.sender, _pairs[0], amountsIn[0]); uint256 _amountOutReal = _swapTokensForExactTokens(_pairs, _pairBinSteps, _tokenPath, amountsIn, _to); if (_amountOutReal < _amountOut) revert LBRouter__InsufficientAmountOut(_amountOut, _amountOutReal); } /// @notice Swaps tokens for exact AVAX while performing safety checks /// @param _amountAVAXOut The amount of AVAX to receive /// @param _amountInMax The max amount of token to send /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2) /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps` /// @param _to The address of the recipient /// @param _deadline The deadline of the tx /// @return amountsIn Input amounts for every step of the swap function swapTokensForExactAVAX( uint256 _amountAVAXOut, uint256 _amountInMax, uint256[] memory _pairBinSteps, IERC20[] memory _tokenPath, address payable _to, uint256 _deadline ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256[] memory amountsIn) { if (_tokenPath[_pairBinSteps.length] != IERC20(wavax)) revert LBRouter__InvalidTokenPath(address(_tokenPath[_pairBinSteps.length])); address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath); amountsIn = _getAmountsIn(_pairBinSteps, _pairs, _tokenPath, _amountAVAXOut); if (amountsIn[0] > _amountInMax) revert LBRouter__MaxAmountInExceeded(_amountInMax, amountsIn[0]); _tokenPath[0].safeTransferFrom(msg.sender, _pairs[0], amountsIn[0]); uint256 _amountOutReal = _swapTokensForExactTokens(_pairs, _pairBinSteps, _tokenPath, amountsIn, address(this)); if (_amountOutReal < _amountAVAXOut) revert LBRouter__InsufficientAmountOut(_amountAVAXOut, _amountOutReal); wavax.withdraw(_amountOutReal); _safeTransferAVAX(_to, _amountOutReal); } /// @notice Swaps AVAX for exact tokens while performing safety checks /// @dev Will refund any AVAX amount sent in excess to `msg.sender` /// @param _amountOut The amount of tokens to receive /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2) /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps` /// @param _to The address of the recipient /// @param _deadline The deadline of the tx /// @return amountsIn Input amounts for every step of the swap function swapAVAXForExactTokens( uint256 _amountOut, uint256[] memory _pairBinSteps, IERC20[] memory _tokenPath, address _to, uint256 _deadline ) external payable override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256[] memory amountsIn) { if (_tokenPath[0] != IERC20(wavax)) revert LBRouter__InvalidTokenPath(address(_tokenPath[0])); address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath); amountsIn = _getAmountsIn(_pairBinSteps, _pairs, _tokenPath, _amountOut); if (amountsIn[0] > msg.value) revert LBRouter__MaxAmountInExceeded(msg.value, amountsIn[0]); _wavaxDepositAndTransfer(_pairs[0], amountsIn[0]); uint256 _amountOutReal = _swapTokensForExactTokens(_pairs, _pairBinSteps, _tokenPath, amountsIn, _to); if (_amountOutReal < _amountOut) revert LBRouter__InsufficientAmountOut(_amountOut, _amountOutReal); if (msg.value > amountsIn[0]) _safeTransferAVAX(msg.sender, msg.value - amountsIn[0]); } /// @notice Swaps exact tokens for tokens while performing safety checks supporting for fee on transfer tokens /// @param _amountIn The amount of token to send /// @param _amountOutMin The min amount of token to receive /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2) /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps` /// @param _to The address of the recipient /// @param _deadline The deadline of the tx /// @return amountOut Output amount of the swap function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint256 _amountIn, uint256 _amountOutMin, uint256[] memory _pairBinSteps, IERC20[] memory _tokenPath, address _to, uint256 _deadline ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) { address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath); IERC20 _targetToken = _tokenPath[_pairs.length]; uint256 _balanceBefore = _targetToken.balanceOf(_to); _tokenPath[0].safeTransferFrom(msg.sender, _pairs[0], _amountIn); _swapSupportingFeeOnTransferTokens(_pairs, _pairBinSteps, _tokenPath, _to); amountOut = _targetToken.balanceOf(_to) - _balanceBefore; if (_amountOutMin > amountOut) revert LBRouter__InsufficientAmountOut(_amountOutMin, amountOut); } /// @notice Swaps exact tokens for AVAX while performing safety checks supporting for fee on transfer tokens /// @param _amountIn The amount of token to send /// @param _amountOutMinAVAX The min amount of AVAX to receive /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2) /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps` /// @param _to The address of the recipient /// @param _deadline The deadline of the tx /// @return amountOut Output amount of the swap function swapExactTokensForAVAXSupportingFeeOnTransferTokens( uint256 _amountIn, uint256 _amountOutMinAVAX, uint256[] memory _pairBinSteps, IERC20[] memory _tokenPath, address payable _to, uint256 _deadline ) external override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) { if (_tokenPath[_pairBinSteps.length] != IERC20(wavax)) revert LBRouter__InvalidTokenPath(address(_tokenPath[_pairBinSteps.length])); address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath); uint256 _balanceBefore = wavax.balanceOf(address(this)); _tokenPath[0].safeTransferFrom(msg.sender, _pairs[0], _amountIn); _swapSupportingFeeOnTransferTokens(_pairs, _pairBinSteps, _tokenPath, address(this)); amountOut = wavax.balanceOf(address(this)) - _balanceBefore; if (_amountOutMinAVAX > amountOut) revert LBRouter__InsufficientAmountOut(_amountOutMinAVAX, amountOut); wavax.withdraw(amountOut); _safeTransferAVAX(_to, amountOut); } /// @notice Swaps exact AVAX for tokens while performing safety checks supporting for fee on transfer tokens /// @param _amountOutMin The min amount of token to receive /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2) /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps` /// @param _to The address of the recipient /// @param _deadline The deadline of the tx /// @return amountOut Output amount of the swap function swapExactAVAXForTokensSupportingFeeOnTransferTokens( uint256 _amountOutMin, uint256[] memory _pairBinSteps, IERC20[] memory _tokenPath, address _to, uint256 _deadline ) external payable override ensure(_deadline) verifyInputs(_pairBinSteps, _tokenPath) returns (uint256 amountOut) { if (_tokenPath[0] != IERC20(wavax)) revert LBRouter__InvalidTokenPath(address(_tokenPath[0])); address[] memory _pairs = _getPairs(_pairBinSteps, _tokenPath); IERC20 _targetToken = _tokenPath[_pairs.length]; uint256 _balanceBefore = _targetToken.balanceOf(_to); _wavaxDepositAndTransfer(_pairs[0], msg.value); _swapSupportingFeeOnTransferTokens(_pairs, _pairBinSteps, _tokenPath, _to); amountOut = _targetToken.balanceOf(_to) - _balanceBefore; if (_amountOutMin > amountOut) revert LBRouter__InsufficientAmountOut(_amountOutMin, amountOut); } /// @notice Unstuck tokens that are sent to this contract by mistake /// @dev Only callable by the factory owner /// @param _token The address of the token /// @param _to The address of the user to send back the tokens /// @param _amount The amount to send function sweep( IERC20 _token, address _to, uint256 _amount ) external override onlyFactoryOwner { if (address(_token) == address(0)) { if (_amount == type(uint256).max) _amount = address(this).balance; _safeTransferAVAX(_to, _amount); } else { if (_amount == type(uint256).max) _amount = _token.balanceOf(address(this)); _token.safeTransfer(_to, _amount); } } /// @notice Unstuck LBTokens that are sent to this contract by mistake /// @dev Only callable by the factory owner /// @param _lbToken The address of the LBToken /// @param _to The address of the user to send back the tokens /// @param _ids The list of token ids /// @param _amounts The list of amounts to send function sweepLBToken( ILBToken _lbToken, address _to, uint256[] calldata _ids, uint256[] calldata _amounts ) external override onlyFactoryOwner { _lbToken.safeBatchTransferFrom(address(this), _to, _ids, _amounts); } /// @notice Helper function to add liquidity /// @param _liq The liquidity parameter /// @param _LBPair LBPair where liquidity is deposited /// @return depositIds Bin ids where the liquidity was actually deposited /// @return liquidityMinted Amounts of LBToken minted for each bin function _addLiquidity(LiquidityParameters calldata _liq, ILBPair _LBPair) private ensure(_liq.deadline) returns (uint256[] memory depositIds, uint256[] memory liquidityMinted) { unchecked { if (_liq.deltaIds.length != _liq.distributionX.length && _liq.deltaIds.length != _liq.distributionY.length) revert LBRouter__LengthsMismatch(); if (_liq.activeIdDesired > type(uint24).max || _liq.idSlippage > type(uint24).max) revert LBRouter__IdDesiredOverflows(_liq.activeIdDesired, _liq.idSlippage); (, , uint256 _activeId) = _LBPair.getReservesAndId(); if ( _liq.activeIdDesired + _liq.idSlippage < _activeId || _activeId + _liq.idSlippage < _liq.activeIdDesired ) revert LBRouter__IdSlippageCaught(_liq.activeIdDesired, _liq.idSlippage, _activeId); depositIds = new uint256[](_liq.deltaIds.length); for (uint256 i; i < depositIds.length; ++i) { int256 _id = int256(_activeId) + _liq.deltaIds[i]; if (_id < 0 || uint256(_id) > type(uint24).max) revert LBRouter__IdOverflows(_id); depositIds[i] = uint256(_id); } uint256 _amountXAdded; uint256 _amountYAdded; (_amountXAdded, _amountYAdded, liquidityMinted) = _LBPair.mint( depositIds, _liq.distributionX, _liq.distributionY, _liq.to ); if (_amountXAdded < _liq.amountXMin || _amountYAdded < _liq.amountYMin) revert LBRouter__AmountSlippageCaught(_liq.amountXMin, _amountXAdded, _liq.amountYMin, _amountYAdded); } } /// @notice Helper function to return the amounts in /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2) /// @param _pairs The list of pairs /// @param _tokenPath The swap path /// @param _amountOut The amount out /// @return amountsIn The list of amounts in function _getAmountsIn( uint256[] memory _pairBinSteps, address[] memory _pairs, IERC20[] memory _tokenPath, uint256 _amountOut ) private view returns (uint256[] memory amountsIn) { amountsIn = new uint256[](_tokenPath.length); // Avoid doing -1, as `_pairs.length == _pairBinSteps.length-1` amountsIn[_pairs.length] = _amountOut; for (uint256 i = _pairs.length; i != 0; i--) { IERC20 _token = _tokenPath[i - 1]; uint256 _binStep = _pairBinSteps[i - 1]; address _pair = _pairs[i - 1]; if (_binStep == 0) { (uint256 _reserveIn, uint256 _reserveOut, ) = IJoePair(_pair).getReserves(); if (_token > _tokenPath[i]) { (_reserveIn, _reserveOut) = (_reserveOut, _reserveIn); } uint256 amountOut_ = amountsIn[i]; amountsIn[i - 1] = amountOut_.getAmountIn(_reserveIn, _reserveOut); } else { (amountsIn[i - 1], ) = getSwapIn(ILBPair(_pair), amountsIn[i], ILBPair(_pair).tokenX() == _token); } } } /// @notice Helper function to remove liquidity /// @param _LBPair The address of the LBPair /// @param _amountXMin The min amount to receive of token X /// @param _amountYMin The min amount to receive of token Y /// @param _ids The list of ids to burn /// @param _amounts The list of amounts to burn of each id in `_ids` /// @param _to The address of the recipient /// @return amountX The amount of token X sent by the pair /// @return amountY The amount of token Y sent by the pair function _removeLiquidity( ILBPair _LBPair, uint256 _amountXMin, uint256 _amountYMin, uint256[] memory _ids, uint256[] memory _amounts, address _to ) private returns (uint256 amountX, uint256 amountY) { ILBToken(address(_LBPair)).safeBatchTransferFrom(msg.sender, address(_LBPair), _ids, _amounts); (amountX, amountY) = _LBPair.burn(_ids, _amounts, _to); if (amountX < _amountXMin || amountY < _amountYMin) revert LBRouter__AmountSlippageCaught(_amountXMin, amountX, _amountYMin, amountY); } /// @notice Helper function to swap exact tokens for tokens /// @param _amountIn The amount of token sent /// @param _pairs The list of pairs /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2) /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps` /// @param _to The address of the recipient /// @return amountOut The amount of token sent to `_to` function _swapExactTokensForTokens( uint256 _amountIn, address[] memory _pairs, uint256[] memory _pairBinSteps, IERC20[] memory _tokenPath, address _to ) private returns (uint256 amountOut) { IERC20 _token; uint256 _binStep; address _recipient; address _pair; IERC20 _tokenNext = _tokenPath[0]; amountOut = _amountIn; unchecked { for (uint256 i; i < _pairs.length; ++i) { _pair = _pairs[i]; _binStep = _pairBinSteps[i]; _token = _tokenNext; _tokenNext = _tokenPath[i + 1]; _recipient = i + 1 == _pairs.length ? _to : _pairs[i + 1]; if (_binStep == 0) { (uint256 _reserve0, uint256 _reserve1, ) = IJoePair(_pair).getReserves(); if (_token < _tokenNext) { amountOut = amountOut.getAmountOut(_reserve0, _reserve1); IJoePair(_pair).swap(0, amountOut, _recipient, ""); } else { amountOut = amountOut.getAmountOut(_reserve1, _reserve0); IJoePair(_pair).swap(amountOut, 0, _recipient, ""); } } else { bool _swapForY = _tokenNext == ILBPair(_pair).tokenY(); (uint256 _amountXOut, uint256 _amountYOut) = ILBPair(_pair).swap(_swapForY, _recipient); if (_swapForY) amountOut = _amountYOut; else amountOut = _amountXOut; } } } } /// @notice Helper function to swap tokens for exact tokens /// @param _pairs The array of pairs /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2) /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps` /// @param _amountsIn The list of amounts in /// @param _to The address of the recipient /// @return amountOut The amount of token sent to `_to` function _swapTokensForExactTokens( address[] memory _pairs, uint256[] memory _pairBinSteps, IERC20[] memory _tokenPath, uint256[] memory _amountsIn, address _to ) private returns (uint256 amountOut) { IERC20 _token; uint256 _binStep; address _recipient; address _pair; IERC20 _tokenNext = _tokenPath[0]; unchecked { for (uint256 i; i < _pairs.length; ++i) { _pair = _pairs[i]; _binStep = _pairBinSteps[i]; _token = _tokenNext; _tokenNext = _tokenPath[i + 1]; _recipient = i + 1 == _pairs.length ? _to : _pairs[i + 1]; if (_binStep == 0) { amountOut = _amountsIn[i + 1]; if (_token < _tokenNext) { IJoePair(_pair).swap(0, amountOut, _recipient, ""); } else { IJoePair(_pair).swap(amountOut, 0, _recipient, ""); } } else { bool _swapForY = _tokenNext == ILBPair(_pair).tokenY(); (uint256 _amountXOut, uint256 _amountYOut) = ILBPair(_pair).swap(_swapForY, _recipient); if (_swapForY) amountOut = _amountYOut; else amountOut = _amountXOut; } } } } /// @notice Helper function to swap exact tokens supporting for fee on transfer tokens /// @param _pairs The list of pairs /// @param _pairBinSteps The bin step of the pairs (0: V1, other values will use V2) /// @param _tokenPath The swap path using the binSteps following `_pairBinSteps` /// @param _to The address of the recipient function _swapSupportingFeeOnTransferTokens( address[] memory _pairs, uint256[] memory _pairBinSteps, IERC20[] memory _tokenPath, address _to ) private { IERC20 _token; uint256 _binStep; address _recipient; address _pair; IERC20 _tokenNext = _tokenPath[0]; unchecked { for (uint256 i; i < _pairs.length; ++i) { _pair = _pairs[i]; _binStep = _pairBinSteps[i]; _token = _tokenNext; _tokenNext = _tokenPath[i + 1]; _recipient = i + 1 == _pairs.length ? _to : _pairs[i + 1]; if (_binStep == 0) { (uint256 _reserve0, uint256 _reserve1, ) = IJoePair(_pair).getReserves(); if (_token < _tokenNext) { uint256 _amountIn = _token.balanceOf(_pair) - _reserve0; uint256 _amountOut = _amountIn.getAmountOut(_reserve0, _reserve1); IJoePair(_pair).swap(0, _amountOut, _recipient, ""); } else { uint256 _amountIn = _token.balanceOf(_pair) - _reserve1; uint256 _amountOut = _amountIn.getAmountOut(_reserve1, _reserve0); IJoePair(_pair).swap(_amountOut, 0, _recipient, ""); } } else { ILBPair(_pair).swap(_tokenNext == ILBPair(_pair).tokenY(), _recipient); } } } } /// @notice Helper function to return the address of the LBPair /// @dev Revert if the pair is not created yet /// @param _tokenX The address of the tokenX /// @param _tokenY The address of the tokenY /// @param _binStep The bin step of the LBPair /// @return The address of the LBPair function _getLBPairInformation( IERC20 _tokenX, IERC20 _tokenY, uint256 _binStep ) private view returns (ILBPair) { ILBPair _LBPair = factory.getLBPairInformation(_tokenX, _tokenY, _binStep).LBPair; if (address(_LBPair) == address(0)) revert LBRouter__PairNotCreated(address(_tokenX), address(_tokenY), _binStep); return _LBPair; } /// @notice Helper function to return the address of the pair (v1 or v2, according to `_binStep`) /// @dev Revert if the pair is not created yet /// @param _binStep The bin step of the LBPair, 0 means using V1 pair, any other value will use V2 /// @param _tokenX The address of the tokenX /// @param _tokenY The address of the tokenY /// @return _pair The address of the pair of binStep `_binStep` function _getPair( uint256 _binStep, IERC20 _tokenX, IERC20 _tokenY ) private view returns (address _pair) { if (_binStep == 0) { _pair = oldFactory.getPair(address(_tokenX), address(_tokenY)); if (_pair == address(0)) revert LBRouter__PairNotCreated(address(_tokenX), address(_tokenY), _binStep); } else _pair = address(_getLBPairInformation(_tokenX, _tokenY, _binStep)); } function _getPairs(uint256[] memory _pairBinSteps, IERC20[] memory _tokenPath) private view returns (address[] memory pairs) { pairs = new address[](_pairBinSteps.length); IERC20 _token; IERC20 _tokenNext = _tokenPath[0]; unchecked { for (uint256 i; i < pairs.length; ++i) { _token = _tokenNext; _tokenNext = _tokenPath[i + 1]; pairs[i] = _getPair(_pairBinSteps[i], _token, _tokenNext); } } } /// @notice Helper function to transfer AVAX /// @param _to The address of the recipient /// @param _amount The AVAX amount to send function _safeTransferAVAX(address _to, uint256 _amount) private { (bool success, ) = _to.call{value: _amount}(""); if (!success) revert LBRouter__FailedToSendAVAX(_to, _amount); } /// @notice Helper function to deposit and transfer wavax /// @param _to The address of the recipient /// @param _amount The AVAX amount to wrap function _wavaxDepositAndTransfer(address _to, uint256 _amount) private { wavax.deposit{value: _amount}(); wavax.safeTransfer(_to, _amount); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @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); /** * @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 `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "./interfaces/ILBPair.sol"; /** LBRouter errors */ error LBRouter__SenderIsNotWAVAX(); error LBRouter__PairNotCreated(address tokenX, address tokenY, uint256 binStep); error LBRouter__WrongAmounts(uint256 amount, uint256 reserve); error LBRouter__SwapOverflows(uint256 id); error LBRouter__BrokenSwapSafetyCheck(); error LBRouter__NotFactoryOwner(); error LBRouter__TooMuchTokensIn(uint256 excess); error LBRouter__BinReserveOverflows(uint256 id); error LBRouter__IdOverflows(int256 id); error LBRouter__LengthsMismatch(); error LBRouter__WrongTokenOrder(); error LBRouter__IdSlippageCaught(uint256 activeIdDesired, uint256 idSlippage, uint256 activeId); error LBRouter__AmountSlippageCaught(uint256 amountXMin, uint256 amountX, uint256 amountYMin, uint256 amountY); error LBRouter__IdDesiredOverflows(uint256 idDesired, uint256 idSlippage); error LBRouter__FailedToSendAVAX(address recipient, uint256 amount); error LBRouter__DeadlineExceeded(uint256 deadline, uint256 currentTimestamp); error LBRouter__AmountSlippageBPTooBig(uint256 amountSlippage); error LBRouter__InsufficientAmountOut(uint256 amountOutMin, uint256 amountOut); error LBRouter__MaxAmountInExceeded(uint256 amountInMax, uint256 amountIn); error LBRouter__InvalidTokenPath(address wrongToken); error LBRouter__InvalidVersion(uint256 version); error LBRouter__WrongAvaxLiquidityParameters( address tokenX, address tokenY, uint256 amountX, uint256 amountY, uint256 msgValue ); /** LBToken errors */ error LBToken__SpenderNotApproved(address owner, address spender); error LBToken__TransferFromOrToAddress0(); error LBToken__MintToAddress0(); error LBToken__BurnFromAddress0(); error LBToken__BurnExceedsBalance(address from, uint256 id, uint256 amount); error LBToken__LengthMismatch(uint256 accountsLength, uint256 idsLength); error LBToken__SelfApproval(address owner); error LBToken__TransferExceedsBalance(address from, uint256 id, uint256 amount); error LBToken__TransferToSelf(); /** LBFactory errors */ error LBFactory__IdenticalAddresses(IERC20 token); error LBFactory__QuoteAssetNotWhitelisted(IERC20 quoteAsset); error LBFactory__QuoteAssetAlreadyWhitelisted(IERC20 quoteAsset); error LBFactory__AddressZero(); error LBFactory__LBPairAlreadyExists(IERC20 tokenX, IERC20 tokenY, uint256 _binStep); error LBFactory__LBPairNotCreated(IERC20 tokenX, IERC20 tokenY, uint256 binStep); error LBFactory__DecreasingPeriods(uint16 filterPeriod, uint16 decayPeriod); error LBFactory__ReductionFactorOverflows(uint16 reductionFactor, uint256 max); error LBFactory__VariableFeeControlOverflows(uint16 variableFeeControl, uint256 max); error LBFactory__BaseFeesBelowMin(uint256 baseFees, uint256 minBaseFees); error LBFactory__FeesAboveMax(uint256 fees, uint256 maxFees); error LBFactory__FlashLoanFeeAboveMax(uint256 fees, uint256 maxFees); error LBFactory__BinStepRequirementsBreached(uint256 lowerBound, uint16 binStep, uint256 higherBound); error LBFactory__ProtocolShareOverflows(uint16 protocolShare, uint256 max); error LBFactory__FunctionIsLockedForUsers(address user); error LBFactory__FactoryLockIsAlreadyInTheSameState(); error LBFactory__LBPairIgnoredIsAlreadyInTheSameState(); error LBFactory__BinStepHasNoPreset(uint256 binStep); error LBFactory__SameFeeRecipient(address feeRecipient); error LBFactory__SameFlashLoanFee(uint256 flashLoanFee); error LBFactory__LBPairSafetyCheckFailed(address LBPairImplementation); error LBFactory__SameImplementation(address LBPairImplementation); error LBFactory__ImplementationNotSet(); /** LBPair errors */ error LBPair__InsufficientAmounts(); error LBPair__AddressZero(); error LBPair__AddressZeroOrThis(); error LBPair__CompositionFactorFlawed(uint256 id); error LBPair__InsufficientLiquidityMinted(uint256 id); error LBPair__InsufficientLiquidityBurned(uint256 id); error LBPair__WrongLengths(); error LBPair__OnlyStrictlyIncreasingId(); error LBPair__OnlyFactory(); error LBPair__DistributionsOverflow(); error LBPair__OnlyFeeRecipient(address feeRecipient, address sender); error LBPair__OracleNotEnoughSample(); error LBPair__AlreadyInitialized(); error LBPair__OracleNewSizeTooSmall(uint256 newSize, uint256 oracleSize); error LBPair__FlashLoanCallbackFailed(); error LBPair__FlashLoanInvalidBalance(); error LBPair__FlashLoanInvalidToken(); /** BinHelper errors */ error BinHelper__BinStepOverflows(uint256 bp); error BinHelper__IdOverflows(); /** Math128x128 errors */ error Math128x128__PowerUnderflow(uint256 x, int256 y); error Math128x128__LogUnderflow(); /** Math512Bits errors */ error Math512Bits__MulDivOverflow(uint256 prod1, uint256 denominator); error Math512Bits__ShiftDivOverflow(uint256 prod1, uint256 denominator); error Math512Bits__MulShiftOverflow(uint256 prod1, uint256 offset); error Math512Bits__OffsetOverflows(uint256 offset); /** Oracle errors */ error Oracle__AlreadyInitialized(uint256 _index); error Oracle__LookUpTimestampTooOld(uint256 _minTimestamp, uint256 _lookUpTimestamp); error Oracle__NotInitialized(); /** PendingOwnable errors */ error PendingOwnable__NotOwner(); error PendingOwnable__NotPendingOwner(); error PendingOwnable__PendingOwnerAlreadySet(); error PendingOwnable__NoPendingOwner(); error PendingOwnable__AddressZero(); /** ReentrancyGuardUpgradeable errors */ error ReentrancyGuardUpgradeable__ReentrantCall(); error ReentrancyGuardUpgradeable__AlreadyInitialized(); /** SafeCast errors */ error SafeCast__Exceeds256Bits(uint256 x); error SafeCast__Exceeds248Bits(uint256 x); error SafeCast__Exceeds240Bits(uint256 x); error SafeCast__Exceeds232Bits(uint256 x); error SafeCast__Exceeds224Bits(uint256 x); error SafeCast__Exceeds216Bits(uint256 x); error SafeCast__Exceeds208Bits(uint256 x); error SafeCast__Exceeds200Bits(uint256 x); error SafeCast__Exceeds192Bits(uint256 x); error SafeCast__Exceeds184Bits(uint256 x); error SafeCast__Exceeds176Bits(uint256 x); error SafeCast__Exceeds168Bits(uint256 x); error SafeCast__Exceeds160Bits(uint256 x); error SafeCast__Exceeds152Bits(uint256 x); error SafeCast__Exceeds144Bits(uint256 x); error SafeCast__Exceeds136Bits(uint256 x); error SafeCast__Exceeds128Bits(uint256 x); error SafeCast__Exceeds120Bits(uint256 x); error SafeCast__Exceeds112Bits(uint256 x); error SafeCast__Exceeds104Bits(uint256 x); error SafeCast__Exceeds96Bits(uint256 x); error SafeCast__Exceeds88Bits(uint256 x); error SafeCast__Exceeds80Bits(uint256 x); error SafeCast__Exceeds72Bits(uint256 x); error SafeCast__Exceeds64Bits(uint256 x); error SafeCast__Exceeds56Bits(uint256 x); error SafeCast__Exceeds48Bits(uint256 x); error SafeCast__Exceeds40Bits(uint256 x); error SafeCast__Exceeds32Bits(uint256 x); error SafeCast__Exceeds24Bits(uint256 x); error SafeCast__Exceeds16Bits(uint256 x); error SafeCast__Exceeds8Bits(uint256 x); /** TreeMath errors */ error TreeMath__ErrorDepthSearch(); /** JoeLibrary errors */ error JoeLibrary__IdenticalAddresses(); error JoeLibrary__AddressZero(); error JoeLibrary__InsufficientAmount(); error JoeLibrary__InsufficientLiquidity(); /** TokenHelper errors */ error TokenHelper__NonContract(); error TokenHelper__CallFailed(); error TokenHelper__TransferFailed(); /** LBQuoter errors */ error LBQuoter_InvalidLength();
// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.10; /// @title Joe V1 Factory Interface /// @notice Interface to interact with Joe V1 Factory interface IJoeFactory { event PairCreated(address indexed token0, address indexed token1, address pair, uint256); function feeTo() external view returns (address); function feeToSetter() external view returns (address); function migrator() external view returns (address); function getPair(address tokenA, address tokenB) external view returns (address pair); function allPairs(uint256) external view returns (address pair); function allPairsLength() external view returns (uint256); function createPair(address tokenA, address tokenB) external returns (address pair); function setFeeTo(address) external; function setFeeToSetter(address) external; function setMigrator(address) external; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.10; /// @title Joe V1 Pair Interface /// @notice Interface to interact with Joe V1 Pairs interface IJoePair { event Approval(address indexed owner, address indexed spender, uint256 value); event Transfer(address indexed from, address indexed to, uint256 value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint256); function balanceOf(address owner) external view returns (uint256); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 value) external returns (bool); function transfer(address to, uint256 value) external returns (bool); function transferFrom( address from, address to, uint256 value ) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint256); function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; event Mint(address indexed sender, uint256 amount0, uint256 amount1); event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to); event Swap( address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint256); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function getReserves() external view returns ( uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast ); function price0CumulativeLast() external view returns (uint256); function price1CumulativeLast() external view returns (uint256); function kLast() external view returns (uint256); function mint(address to) external returns (uint256 liquidity); function burn(address to) external returns (uint256 amount0, uint256 amount1); function swap( uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data ) external; function skim(address to) external; function sync() external; function initialize(address, address) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "openzeppelin/token/ERC20/IERC20.sol"; import "./ILBPair.sol"; import "./IPendingOwnable.sol"; /// @title Liquidity Book Factory Interface /// @author Trader Joe /// @notice Required interface of LBFactory contract interface ILBFactory is IPendingOwnable { /// @dev Structure to store the LBPair information, such as: /// - binStep: The bin step of the LBPair /// - LBPair: The address of the LBPair /// - createdByOwner: Whether the pair was created by the owner of the factory /// - ignoredForRouting: Whether the pair is ignored for routing or not. An ignored pair will not be explored during routes finding struct LBPairInformation { uint16 binStep; ILBPair LBPair; bool createdByOwner; bool ignoredForRouting; } event LBPairCreated( IERC20 indexed tokenX, IERC20 indexed tokenY, uint256 indexed binStep, ILBPair LBPair, uint256 pid ); event FeeRecipientSet(address oldRecipient, address newRecipient); event FlashLoanFeeSet(uint256 oldFlashLoanFee, uint256 newFlashLoanFee); event FeeParametersSet( address indexed sender, ILBPair indexed LBPair, uint256 binStep, uint256 baseFactor, uint256 filterPeriod, uint256 decayPeriod, uint256 reductionFactor, uint256 variableFeeControl, uint256 protocolShare, uint256 maxVolatilityAccumulated ); event FactoryLockedStatusUpdated(bool unlocked); event LBPairImplementationSet(address oldLBPairImplementation, address LBPairImplementation); event LBPairIgnoredStateChanged(ILBPair indexed LBPair, bool ignored); event PresetSet( uint256 indexed binStep, uint256 baseFactor, uint256 filterPeriod, uint256 decayPeriod, uint256 reductionFactor, uint256 variableFeeControl, uint256 protocolShare, uint256 maxVolatilityAccumulated, uint256 sampleLifetime ); event PresetRemoved(uint256 indexed binStep); event QuoteAssetAdded(IERC20 indexed quoteAsset); event QuoteAssetRemoved(IERC20 indexed quoteAsset); function MAX_FEE() external pure returns (uint256); function MIN_BIN_STEP() external pure returns (uint256); function MAX_BIN_STEP() external pure returns (uint256); function MAX_PROTOCOL_SHARE() external pure returns (uint256); function LBPairImplementation() external view returns (address); function getNumberOfQuoteAssets() external view returns (uint256); function getQuoteAsset(uint256 index) external view returns (IERC20); function isQuoteAsset(IERC20 token) external view returns (bool); function feeRecipient() external view returns (address); function flashLoanFee() external view returns (uint256); function creationUnlocked() external view returns (bool); function allLBPairs(uint256 id) external returns (ILBPair); function getNumberOfLBPairs() external view returns (uint256); function getLBPairInformation( IERC20 tokenX, IERC20 tokenY, uint256 binStep ) external view returns (LBPairInformation memory); function getPreset(uint16 binStep) external view returns ( uint256 baseFactor, uint256 filterPeriod, uint256 decayPeriod, uint256 reductionFactor, uint256 variableFeeControl, uint256 protocolShare, uint256 maxAccumulator, uint256 sampleLifetime ); function getAllBinSteps() external view returns (uint256[] memory presetsBinStep); function getAllLBPairs(IERC20 tokenX, IERC20 tokenY) external view returns (LBPairInformation[] memory LBPairsBinStep); function setLBPairImplementation(address LBPairImplementation) external; function createLBPair( IERC20 tokenX, IERC20 tokenY, uint24 activeId, uint16 binStep ) external returns (ILBPair pair); function setLBPairIgnored( IERC20 tokenX, IERC20 tokenY, uint256 binStep, bool ignored ) external; function setPreset( uint16 binStep, uint16 baseFactor, uint16 filterPeriod, uint16 decayPeriod, uint16 reductionFactor, uint24 variableFeeControl, uint16 protocolShare, uint24 maxVolatilityAccumulated, uint16 sampleLifetime ) external; function removePreset(uint16 binStep) external; function setFeesParametersOnPair( IERC20 tokenX, IERC20 tokenY, uint16 binStep, uint16 baseFactor, uint16 filterPeriod, uint16 decayPeriod, uint16 reductionFactor, uint24 variableFeeControl, uint16 protocolShare, uint24 maxVolatilityAccumulated ) external; function setFeeRecipient(address feeRecipient) external; function setFlashLoanFee(uint256 flashLoanFee) external; function setFactoryLockedState(bool locked) external; function addQuoteAsset(IERC20 quoteAsset) external; function removeQuoteAsset(IERC20 quoteAsset) external; function forceDecay(ILBPair LBPair) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "openzeppelin/token/ERC20/IERC20.sol"; /// @title Liquidity Book Flashloan Callback Interface /// @author Trader Joe /// @notice Required interface to interact with LB flash loans interface ILBFlashLoanCallback { function LBFlashLoanCallback( address sender, IERC20 token, uint256 amount, uint256 fee, bytes calldata data ) external returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "openzeppelin/token/ERC20/IERC20.sol"; import "../libraries/FeeHelper.sol"; import "./ILBFactory.sol"; import "./ILBFlashLoanCallback.sol"; /// @title Liquidity Book Pair Interface /// @author Trader Joe /// @notice Required interface of LBPair contract interface ILBPair { /// @dev Structure to store the reserves of bins: /// - reserveX: The current reserve of tokenX of the bin /// - reserveY: The current reserve of tokenY of the bin struct Bin { uint112 reserveX; uint112 reserveY; uint256 accTokenXPerShare; uint256 accTokenYPerShare; } /// @dev Structure to store the information of the pair such as: /// slot0: /// - activeId: The current id used for swaps, this is also linked with the price /// - reserveX: The sum of amounts of tokenX across all bins /// slot1: /// - reserveY: The sum of amounts of tokenY across all bins /// - oracleSampleLifetime: The lifetime of an oracle sample /// - oracleSize: The current size of the oracle, can be increase by users /// - oracleActiveSize: The current active size of the oracle, composed only from non empty data sample /// - oracleLastTimestamp: The current last timestamp at which a sample was added to the circular buffer /// - oracleId: The current id of the oracle /// slot2: /// - feesX: The current amount of fees to distribute in tokenX (total, protocol) /// slot3: /// - feesY: The current amount of fees to distribute in tokenY (total, protocol) struct PairInformation { uint24 activeId; uint136 reserveX; uint136 reserveY; uint16 oracleSampleLifetime; uint16 oracleSize; uint16 oracleActiveSize; uint40 oracleLastTimestamp; uint16 oracleId; FeeHelper.FeesDistribution feesX; FeeHelper.FeesDistribution feesY; } /// @dev Structure to store the debts of users /// - debtX: The tokenX's debt /// - debtY: The tokenY's debt struct Debts { uint256 debtX; uint256 debtY; } /// @dev Structure to store fees: /// - tokenX: The amount of fees of token X /// - tokenY: The amount of fees of token Y struct Fees { uint128 tokenX; uint128 tokenY; } /// @dev Structure to minting informations: /// - amountXIn: The amount of token X sent /// - amountYIn: The amount of token Y sent /// - amountXAddedToPair: The amount of token X that have been actually added to the pair /// - amountYAddedToPair: The amount of token Y that have been actually added to the pair /// - activeFeeX: Fees X currently generated /// - activeFeeY: Fees Y currently generated /// - totalDistributionX: Total distribution of token X. Should be 1e18 (100%) or 0 (0%) /// - totalDistributionY: Total distribution of token Y. Should be 1e18 (100%) or 0 (0%) /// - id: Id of the current working bin when looping on the distribution array /// - amountX: The amount of token X deposited in the current bin /// - amountY: The amount of token Y deposited in the current bin /// - distributionX: Distribution of token X for the current working bin /// - distributionY: Distribution of token Y for the current working bin struct MintInfo { uint256 amountXIn; uint256 amountYIn; uint256 amountXAddedToPair; uint256 amountYAddedToPair; uint256 activeFeeX; uint256 activeFeeY; uint256 totalDistributionX; uint256 totalDistributionY; uint256 id; uint256 amountX; uint256 amountY; uint256 distributionX; uint256 distributionY; } event Swap( address indexed sender, address indexed recipient, uint256 indexed id, bool swapForY, uint256 amountIn, uint256 amountOut, uint256 volatilityAccumulated, uint256 fees ); event FlashLoan( address indexed sender, ILBFlashLoanCallback indexed receiver, IERC20 token, uint256 amount, uint256 fee ); event CompositionFee( address indexed sender, address indexed recipient, uint256 indexed id, uint256 feesX, uint256 feesY ); event DepositedToBin( address indexed sender, address indexed recipient, uint256 indexed id, uint256 amountX, uint256 amountY ); event WithdrawnFromBin( address indexed sender, address indexed recipient, uint256 indexed id, uint256 amountX, uint256 amountY ); event FeesCollected(address indexed sender, address indexed recipient, uint256 amountX, uint256 amountY); event ProtocolFeesCollected(address indexed sender, address indexed recipient, uint256 amountX, uint256 amountY); event OracleSizeIncreased(uint256 previousSize, uint256 newSize); function tokenX() external view returns (IERC20); function tokenY() external view returns (IERC20); function factory() external view returns (ILBFactory); function getReservesAndId() external view returns ( uint256 reserveX, uint256 reserveY, uint256 activeId ); function getGlobalFees() external view returns ( uint128 feesXTotal, uint128 feesYTotal, uint128 feesXProtocol, uint128 feesYProtocol ); function getOracleParameters() external view returns ( uint256 oracleSampleLifetime, uint256 oracleSize, uint256 oracleActiveSize, uint256 oracleLastTimestamp, uint256 oracleId, uint256 min, uint256 max ); function getOracleSampleFrom(uint256 timeDelta) external view returns ( uint256 cumulativeId, uint256 cumulativeAccumulator, uint256 cumulativeBinCrossed ); function feeParameters() external view returns (FeeHelper.FeeParameters memory); function findFirstNonEmptyBinId(uint24 id_, bool sentTokenY) external view returns (uint24 id); function getBin(uint24 id) external view returns (uint256 reserveX, uint256 reserveY); function pendingFees(address account, uint256[] memory ids) external view returns (uint256 amountX, uint256 amountY); function swap(bool sentTokenY, address to) external returns (uint256 amountXOut, uint256 amountYOut); function flashLoan( ILBFlashLoanCallback receiver, IERC20 token, uint256 amount, bytes calldata data ) external; function mint( uint256[] calldata ids, uint256[] calldata distributionX, uint256[] calldata distributionY, address to ) external returns ( uint256 amountXAddedToPair, uint256 amountYAddedToPair, uint256[] memory liquidityMinted ); function burn( uint256[] calldata ids, uint256[] calldata amounts, address to ) external returns (uint256 amountX, uint256 amountY); function increaseOracleLength(uint16 newSize) external; function collectFees(address account, uint256[] calldata ids) external returns (uint256 amountX, uint256 amountY); function collectProtocolFees() external returns (uint128 amountX, uint128 amountY); function setFeesParameters(bytes32 packedFeeParameters) external; function forceDecay() external; function initialize( IERC20 tokenX, IERC20 tokenY, uint24 activeId, uint16 sampleLifetime, bytes32 packedFeeParameters ) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "./IJoeFactory.sol"; import "./ILBPair.sol"; import "./ILBToken.sol"; import "./IWAVAX.sol"; /// @title Liquidity Book Router Interface /// @author Trader Joe /// @notice Required interface of LBRouter contract interface ILBRouter { /// @dev The liquidity parameters, such as: /// - tokenX: The address of token X /// - tokenY: The address of token Y /// - binStep: The bin step of the pair /// - amountX: The amount to send of token X /// - amountY: The amount to send of token Y /// - amountXMin: The min amount of token X added to liquidity /// - amountYMin: The min amount of token Y added to liquidity /// - activeIdDesired: The active id that user wants to add liquidity from /// - idSlippage: The number of id that are allowed to slip /// - deltaIds: The list of delta ids to add liquidity (`deltaId = activeId - desiredId`) /// - distributionX: The distribution of tokenX with sum(distributionX) = 100e18 (100%) or 0 (0%) /// - distributionY: The distribution of tokenY with sum(distributionY) = 100e18 (100%) or 0 (0%) /// - to: The address of the recipient /// - deadline: The deadline of the tx struct LiquidityParameters { IERC20 tokenX; IERC20 tokenY; uint256 binStep; uint256 amountX; uint256 amountY; uint256 amountXMin; uint256 amountYMin; uint256 activeIdDesired; uint256 idSlippage; int256[] deltaIds; uint256[] distributionX; uint256[] distributionY; address to; uint256 deadline; } function factory() external view returns (ILBFactory); function oldFactory() external view returns (IJoeFactory); function wavax() external view returns (IWAVAX); function getIdFromPrice(ILBPair LBPair, uint256 price) external view returns (uint24); function getPriceFromId(ILBPair LBPair, uint24 id) external view returns (uint256); function getSwapIn( ILBPair LBPair, uint256 amountOut, bool swapForY ) external view returns (uint256 amountIn, uint256 feesIn); function getSwapOut( ILBPair LBPair, uint256 amountIn, bool swapForY ) external view returns (uint256 amountOut, uint256 feesIn); function createLBPair( IERC20 tokenX, IERC20 tokenY, uint24 activeId, uint16 binStep ) external returns (ILBPair pair); function addLiquidity(LiquidityParameters calldata liquidityParameters) external returns (uint256[] memory depositIds, uint256[] memory liquidityMinted); function addLiquidityAVAX(LiquidityParameters calldata liquidityParameters) external payable returns (uint256[] memory depositIds, uint256[] memory liquidityMinted); function removeLiquidity( IERC20 tokenX, IERC20 tokenY, uint16 binStep, uint256 amountXMin, uint256 amountYMin, uint256[] memory ids, uint256[] memory amounts, address to, uint256 deadline ) external returns (uint256 amountX, uint256 amountY); function removeLiquidityAVAX( IERC20 token, uint16 binStep, uint256 amountTokenMin, uint256 amountAVAXMin, uint256[] memory ids, uint256[] memory amounts, address payable to, uint256 deadline ) external returns (uint256 amountToken, uint256 amountAVAX); function swapExactTokensForTokens( uint256 amountIn, uint256 amountOutMin, uint256[] memory pairBinSteps, IERC20[] memory tokenPath, address to, uint256 deadline ) external returns (uint256 amountOut); function swapExactTokensForAVAX( uint256 amountIn, uint256 amountOutMinAVAX, uint256[] memory pairBinSteps, IERC20[] memory tokenPath, address payable to, uint256 deadline ) external returns (uint256 amountOut); function swapExactAVAXForTokens( uint256 amountOutMin, uint256[] memory pairBinSteps, IERC20[] memory tokenPath, address to, uint256 deadline ) external payable returns (uint256 amountOut); function swapTokensForExactTokens( uint256 amountOut, uint256 amountInMax, uint256[] memory pairBinSteps, IERC20[] memory tokenPath, address to, uint256 deadline ) external returns (uint256[] memory amountsIn); function swapTokensForExactAVAX( uint256 amountOut, uint256 amountInMax, uint256[] memory pairBinSteps, IERC20[] memory tokenPath, address payable to, uint256 deadline ) external returns (uint256[] memory amountsIn); function swapAVAXForExactTokens( uint256 amountOut, uint256[] memory pairBinSteps, IERC20[] memory tokenPath, address to, uint256 deadline ) external payable returns (uint256[] memory amountsIn); function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint256 amountIn, uint256 amountOutMin, uint256[] memory pairBinSteps, IERC20[] memory tokenPath, address to, uint256 deadline ) external returns (uint256 amountOut); function swapExactTokensForAVAXSupportingFeeOnTransferTokens( uint256 amountIn, uint256 amountOutMinAVAX, uint256[] memory pairBinSteps, IERC20[] memory tokenPath, address payable to, uint256 deadline ) external returns (uint256 amountOut); function swapExactAVAXForTokensSupportingFeeOnTransferTokens( uint256 amountOutMin, uint256[] memory pairBinSteps, IERC20[] memory tokenPath, address to, uint256 deadline ) external payable returns (uint256 amountOut); function sweep( IERC20 token, address to, uint256 amount ) external; function sweepLBToken( ILBToken _lbToken, address _to, uint256[] calldata _ids, uint256[] calldata _amounts ) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "openzeppelin/utils/introspection/IERC165.sol"; /// @title Liquidity Book Token Interface /// @author Trader Joe /// @notice Required interface of LBToken contract interface ILBToken is IERC165 { event TransferSingle(address indexed sender, address indexed from, address indexed to, uint256 id, uint256 amount); event TransferBatch( address indexed sender, address indexed from, address indexed to, uint256[] ids, uint256[] amounts ); event ApprovalForAll(address indexed account, address indexed sender, bool approved); function name() external view returns (string memory); function symbol() external view returns (string memory); function balanceOf(address account, uint256 id) external view returns (uint256); function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory batchBalances); function totalSupply(uint256 id) external view returns (uint256); function isApprovedForAll(address owner, address spender) external view returns (bool); function setApprovalForAll(address sender, bool approved) external; function safeTransferFrom( address from, address to, uint256 id, uint256 amount ) external; function safeBatchTransferFrom( address from, address to, uint256[] calldata id, uint256[] calldata amount ) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; /// @title Liquidity Book Pending Ownable Interface /// @author Trader Joe /// @notice Required interface of Pending Ownable contract used for LBFactory interface IPendingOwnable { event PendingOwnerSet(address indexed pendingOwner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); function owner() external view returns (address); function pendingOwner() external view returns (address); function setPendingOwner(address pendingOwner) external; function revokePendingOwner() external; function becomeOwner() external; function renounceOwnership() external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "openzeppelin/token/ERC20/IERC20.sol"; /// @title WAVAX Interface /// @notice Required interface of Wrapped AVAX contract interface IWAVAX is IERC20 { function deposit() external payable; function withdraw(uint256) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "../LBErrors.sol"; import "./Math128x128.sol"; /// @title Liquidity Book Bin Helper Library /// @author Trader Joe /// @notice Contract used to convert bin ID to price and back library BinHelper { using Math128x128 for uint256; int256 private constant REAL_ID_SHIFT = 1 << 23; /// @notice Returns the id corresponding to the given price /// @dev The id may be inaccurate due to rounding issues, always trust getPriceFromId rather than /// getIdFromPrice /// @param _price The price of y per x as a 128.128-binary fixed-point number /// @param _binStep The bin step /// @return The id corresponding to this price function getIdFromPrice(uint256 _price, uint256 _binStep) internal pure returns (uint24) { unchecked { uint256 _binStepValue = _getBPValue(_binStep); // can't overflow as `2**23 + log2(price) < 2**23 + 2**128 < max(uint256)` int256 _id = REAL_ID_SHIFT + _price.log2() / _binStepValue.log2(); if (_id < 0 || uint256(_id) > type(uint24).max) revert BinHelper__IdOverflows(); return uint24(uint256(_id)); } } /// @notice Returns the price corresponding to the given ID, as a 128.128-binary fixed-point number /// @dev This is the trusted function to link id to price, the other way may be inaccurate /// @param _id The id /// @param _binStep The bin step /// @return The price corresponding to this id, as a 128.128-binary fixed-point number function getPriceFromId(uint256 _id, uint256 _binStep) internal pure returns (uint256) { if (_id > uint256(type(uint24).max)) revert BinHelper__IdOverflows(); unchecked { int256 _realId = int256(_id) - REAL_ID_SHIFT; return _getBPValue(_binStep).power(_realId); } } /// @notice Returns the (1 + bp) value as a 128.128-decimal fixed-point number /// @param _binStep The bp value in [1; 100] (referring to 0.01% to 1%) /// @return The (1+bp) value as a 128.128-decimal fixed-point number function _getBPValue(uint256 _binStep) internal pure returns (uint256) { if (_binStep == 0 || _binStep > Constants.BASIS_POINT_MAX) revert BinHelper__BinStepOverflows(_binStep); unchecked { // can't overflow as `max(result) = 2**128 + 10_000 << 128 / 10_000 < max(uint256)` return Constants.SCALE + (_binStep << Constants.SCALE_OFFSET) / Constants.BASIS_POINT_MAX; } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; /// @title Liquidity Book Bit Math Library /// @author Trader Joe /// @notice Helper contract used for bit calculations library BitMath { /// @notice Returns the closest non-zero bit of `integer` to the right (of left) of the `bit` bits that is not `bit` /// @param _integer The integer as a uint256 /// @param _bit The bit index /// @param _rightSide Whether we're searching in the right side of the tree (true) or the left side (false) /// @return The index of the closest non-zero bit. If there is no closest bit, it returns max(uint256) function closestBit( uint256 _integer, uint8 _bit, bool _rightSide ) internal pure returns (uint256) { return _rightSide ? closestBitRight(_integer, _bit - 1) : closestBitLeft(_integer, _bit + 1); } /// @notice Returns the most (or least) significant bit of `_integer` /// @param _integer The integer /// @param _isMostSignificant Whether we want the most (true) or the least (false) significant bit /// @return The index of the most (or least) significant bit function significantBit(uint256 _integer, bool _isMostSignificant) internal pure returns (uint8) { return _isMostSignificant ? mostSignificantBit(_integer) : leastSignificantBit(_integer); } /// @notice Returns the index of the closest bit on the right of x that is non null /// @param x The value as a uint256 /// @param bit The index of the bit to start searching at /// @return id The index of the closest non null bit on the right of x. /// If there is no closest bit, it returns max(uint256) function closestBitRight(uint256 x, uint8 bit) internal pure returns (uint256 id) { unchecked { uint256 _shift = 255 - bit; x <<= _shift; // can't overflow as it's non-zero and we shifted it by `_shift` return (x == 0) ? type(uint256).max : mostSignificantBit(x) - _shift; } } /// @notice Returns the index of the closest bit on the left of x that is non null /// @param x The value as a uint256 /// @param bit The index of the bit to start searching at /// @return id The index of the closest non null bit on the left of x. /// If there is no closest bit, it returns max(uint256) function closestBitLeft(uint256 x, uint8 bit) internal pure returns (uint256 id) { unchecked { x >>= bit; return (x == 0) ? type(uint256).max : leastSignificantBit(x) + bit; } } /// @notice Returns the index of the most significant bit of x /// @param x The value as a uint256 /// @return msb The index of the most significant bit of x function mostSignificantBit(uint256 x) internal pure returns (uint8 msb) { unchecked { if (x >= 1 << 128) { x >>= 128; msb = 128; } if (x >= 1 << 64) { x >>= 64; msb += 64; } if (x >= 1 << 32) { x >>= 32; msb += 32; } if (x >= 1 << 16) { x >>= 16; msb += 16; } if (x >= 1 << 8) { x >>= 8; msb += 8; } if (x >= 1 << 4) { x >>= 4; msb += 4; } if (x >= 1 << 2) { x >>= 2; msb += 2; } if (x >= 1 << 1) { msb += 1; } } } /// @notice Returns the index of the least significant bit of x /// @param x The value as a uint256 /// @return lsb The index of the least significant bit of x function leastSignificantBit(uint256 x) internal pure returns (uint8 lsb) { unchecked { if (x << 128 != 0) { x <<= 128; lsb = 128; } if (x << 64 != 0) { x <<= 64; lsb += 64; } if (x << 32 != 0) { x <<= 32; lsb += 32; } if (x << 16 != 0) { x <<= 16; lsb += 16; } if (x << 8 != 0) { x <<= 8; lsb += 8; } if (x << 4 != 0) { x <<= 4; lsb += 4; } if (x << 2 != 0) { x <<= 2; lsb += 2; } if (x << 1 != 0) { lsb += 1; } return 255 - lsb; } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; /// @title Liquidity Book Constants Library /// @author Trader Joe /// @notice Set of constants for Liquidity Book contracts library Constants { uint256 internal constant SCALE_OFFSET = 128; uint256 internal constant SCALE = 1 << SCALE_OFFSET; uint256 internal constant PRECISION = 1e18; uint256 internal constant BASIS_POINT_MAX = 10_000; /// @dev The expected return after a successful flash loan bytes32 internal constant CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan"); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "../LBErrors.sol"; import "./Constants.sol"; import "./FeeHelper.sol"; /// @title Liquidity Book Fee Distribution Helper Library /// @author Trader Joe /// @notice Helper contract used for fees distribution calculations library FeeDistributionHelper { /// @notice Calculate the tokenPerShare when fees are added /// @param _fees The fees received by the pair /// @param _totalSupply the total supply of a specific bin function getTokenPerShare(FeeHelper.FeesDistribution memory _fees, uint256 _totalSupply) internal pure returns (uint256) { unchecked { // This can't overflow as `totalFees >= protocolFees`, // shift can't overflow as we shift fees that are a uint128, by 128 bits. // The result will always be smaller than max(uint256) return ((uint256(_fees.total) - _fees.protocol) << Constants.SCALE_OFFSET) / _totalSupply; } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "./Constants.sol"; import "./SafeCast.sol"; import "./SafeMath.sol"; /// @title Liquidity Book Fee Helper Library /// @author Trader Joe /// @notice Helper contract used for fees calculation library FeeHelper { using SafeCast for uint256; using SafeMath for uint256; /// @dev Structure to store the protocol fees: /// - binStep: The bin step /// - baseFactor: The base factor /// - filterPeriod: The filter period, where the fees stays constant /// - decayPeriod: The decay period, where the fees are halved /// - reductionFactor: The reduction factor, used to calculate the reduction of the accumulator /// - variableFeeControl: The variable fee control, used to control the variable fee, can be 0 to disable them /// - protocolShare: The share of fees sent to protocol /// - maxVolatilityAccumulated: The max value of volatility accumulated /// - volatilityAccumulated: The value of volatility accumulated /// - volatilityReference: The value of volatility reference /// - indexRef: The index reference /// - time: The last time the accumulator was called struct FeeParameters { // 144 lowest bits in slot uint16 binStep; uint16 baseFactor; uint16 filterPeriod; uint16 decayPeriod; uint16 reductionFactor; uint24 variableFeeControl; uint16 protocolShare; uint24 maxVolatilityAccumulated; // 112 highest bits in slot uint24 volatilityAccumulated; uint24 volatilityReference; uint24 indexRef; uint40 time; } /// @dev Structure used during swaps to distributes the fees: /// - total: The total amount of fees /// - protocol: The amount of fees reserved for protocol struct FeesDistribution { uint128 total; uint128 protocol; } /// @notice Update the value of the volatility accumulated /// @param _fp The current fee parameters /// @param _activeId The current active id function updateVariableFeeParameters(FeeParameters memory _fp, uint256 _activeId) internal view { uint256 _deltaT = block.timestamp - _fp.time; if (_deltaT >= _fp.filterPeriod || _fp.time == 0) { _fp.indexRef = uint24(_activeId); if (_deltaT < _fp.decayPeriod) { unchecked { // This can't overflow as `reductionFactor <= BASIS_POINT_MAX` _fp.volatilityReference = uint24( (uint256(_fp.reductionFactor) * _fp.volatilityAccumulated) / Constants.BASIS_POINT_MAX ); } } else { _fp.volatilityReference = 0; } } _fp.time = (block.timestamp).safe40(); updateVolatilityAccumulated(_fp, _activeId); } /// @notice Update the volatility accumulated /// @param _fp The fee parameter /// @param _activeId The current active id function updateVolatilityAccumulated(FeeParameters memory _fp, uint256 _activeId) internal pure { uint256 volatilityAccumulated = (_activeId.absSub(_fp.indexRef) * Constants.BASIS_POINT_MAX) + _fp.volatilityReference; _fp.volatilityAccumulated = volatilityAccumulated > _fp.maxVolatilityAccumulated ? _fp.maxVolatilityAccumulated : uint24(volatilityAccumulated); } /// @notice Returns the base fee added to a swap, with 18 decimals /// @param _fp The current fee parameters /// @return The fee with 18 decimals precision function getBaseFee(FeeParameters memory _fp) internal pure returns (uint256) { unchecked { return uint256(_fp.baseFactor) * _fp.binStep * 1e10; } } /// @notice Returns the variable fee added to a swap, with 18 decimals /// @param _fp The current fee parameters /// @return variableFee The variable fee with 18 decimals precision function getVariableFee(FeeParameters memory _fp) internal pure returns (uint256 variableFee) { if (_fp.variableFeeControl != 0) { // Can't overflow as the max value is `max(uint24) * (max(uint24) * max(uint16)) ** 2 < max(uint104)` // It returns 18 decimals as: // decimals(variableFeeControl * (volatilityAccumulated * binStep)**2 / 100) = 4 + (4 + 4) * 2 - 2 = 18 unchecked { uint256 _prod = uint256(_fp.volatilityAccumulated) * _fp.binStep; variableFee = (_prod * _prod * _fp.variableFeeControl + 99) / 100; } } } /// @notice Return the amount of fees from an amount /// @dev Rounds amount up, follows `amount = amountWithFees - getFeeAmountFrom(fp, amountWithFees)` /// @param _fp The current fee parameter /// @param _amountWithFees The amount of token sent /// @return The fee amount from the amount sent function getFeeAmountFrom(FeeParameters memory _fp, uint256 _amountWithFees) internal pure returns (uint256) { return (_amountWithFees * getTotalFee(_fp) + Constants.PRECISION - 1) / (Constants.PRECISION); } /// @notice Return the fees to add to an amount /// @dev Rounds amount up, follows `amountWithFees = amount + getFeeAmount(fp, amount)` /// @param _fp The current fee parameter /// @param _amount The amount of token sent /// @return The fee amount to add to the amount function getFeeAmount(FeeParameters memory _fp, uint256 _amount) internal pure returns (uint256) { uint256 _fee = getTotalFee(_fp); uint256 _denominator = Constants.PRECISION - _fee; return (_amount * _fee + _denominator - 1) / _denominator; } /// @notice Return the fees added when an user adds liquidity and change the ratio in the active bin /// @dev Rounds amount up /// @param _fp The current fee parameter /// @param _amountWithFees The amount of token sent /// @return The fee amount function getFeeAmountForC(FeeParameters memory _fp, uint256 _amountWithFees) internal pure returns (uint256) { uint256 _fee = getTotalFee(_fp); uint256 _denominator = Constants.PRECISION * Constants.PRECISION; return (_amountWithFees * _fee * (_fee + Constants.PRECISION) + _denominator - 1) / _denominator; } /// @notice Return the fees distribution added to an amount /// @param _fp The current fee parameter /// @param _fees The fee amount /// @return fees The fee distribution function getFeeAmountDistribution(FeeParameters memory _fp, uint256 _fees) internal pure returns (FeesDistribution memory fees) { fees.total = _fees.safe128(); // unsafe math is fine because total >= protocol unchecked { fees.protocol = uint128((_fees * _fp.protocolShare) / Constants.BASIS_POINT_MAX); } } /// @notice Return the total fee, i.e. baseFee + variableFee /// @param _fp The current fee parameter /// @return The total fee, with 18 decimals function getTotalFee(FeeParameters memory _fp) private pure returns (uint256) { unchecked { return getBaseFee(_fp) + getVariableFee(_fp); } } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.10; import "../LBErrors.sol"; /// @title Liquidity Book Joe Library Helper Library /// @author Trader Joe /// @notice Helper contract used for Joe V1 related calculations library JoeLibrary { // returns sorted token addresses, used to handle return values from pairs sorted in this order function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { if (tokenA == tokenB) revert JoeLibrary__IdenticalAddresses(); (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); if (token0 == address(0)) revert JoeLibrary__AddressZero(); } // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset function quote( uint256 amountA, uint256 reserveA, uint256 reserveB ) internal pure returns (uint256 amountB) { if (amountA == 0) revert JoeLibrary__InsufficientAmount(); if (reserveA == 0 || reserveB == 0) revert JoeLibrary__InsufficientLiquidity(); amountB = (amountA * reserveB) / reserveA; } // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset function getAmountOut( uint256 amountIn, uint256 reserveIn, uint256 reserveOut ) internal pure returns (uint256 amountOut) { if (amountIn == 0) revert JoeLibrary__InsufficientAmount(); if (reserveIn == 0 || reserveOut == 0) revert JoeLibrary__InsufficientLiquidity(); uint256 amountInWithFee = amountIn * 997; uint256 numerator = amountInWithFee * reserveOut; uint256 denominator = reserveIn * 1000 + amountInWithFee; amountOut = numerator / denominator; } // given an output amount of an asset and pair reserves, returns a required input amount of the other asset function getAmountIn( uint256 amountOut, uint256 reserveIn, uint256 reserveOut ) internal pure returns (uint256 amountIn) { if (amountOut == 0) revert JoeLibrary__InsufficientAmount(); if (reserveIn == 0 || reserveOut == 0) revert JoeLibrary__InsufficientLiquidity(); uint256 numerator = reserveIn * amountOut * 1000; uint256 denominator = (reserveOut - amountOut) * 997; amountIn = numerator / denominator + 1; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "../LBErrors.sol"; import "./BitMath.sol"; import "./Constants.sol"; import "./Math512Bits.sol"; /// @title Liquidity Book Math Helper Library /// @author Trader Joe /// @notice Helper contract used for power and log calculations library Math128x128 { using Math512Bits for uint256; using BitMath for uint256; uint256 constant LOG_SCALE_OFFSET = 127; uint256 constant LOG_SCALE = 1 << LOG_SCALE_OFFSET; uint256 constant LOG_SCALE_SQUARED = LOG_SCALE * LOG_SCALE; /// @notice Calculates the binary logarithm of x. /// /// @dev Based on the iterative approximation algorithm. /// https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation /// /// Requirements: /// - x must be greater than zero. /// /// Caveats: /// - The results are not perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation /// Also because x is converted to an unsigned 129.127-binary fixed-point number during the operation to optimize the multiplication /// /// @param x The unsigned 128.128-binary fixed-point number for which to calculate the binary logarithm. /// @return result The binary logarithm as a signed 128.128-binary fixed-point number. function log2(uint256 x) internal pure returns (int256 result) { // Convert x to a unsigned 129.127-binary fixed-point number to optimize the multiplication. // If we use an offset of 128 bits, y would need 129 bits and y**2 would would overflow and we would have to // use mulDiv, by reducing x to 129.127-binary fixed-point number we assert that y will use 128 bits, and we // can use the regular multiplication if (x == 1) return -128; if (x == 0) revert Math128x128__LogUnderflow(); x >>= 1; unchecked { // This works because log2(x) = -log2(1/x). int256 sign; if (x >= LOG_SCALE) { sign = 1; } else { sign = -1; // Do the fixed-point inversion inline to save gas x = LOG_SCALE_SQUARED / x; } // Calculate the integer part of the logarithm and add it to the result and finally calculate y = x * 2^(-n). uint256 n = (x >> LOG_SCALE_OFFSET).mostSignificantBit(); // The integer part of the logarithm as a signed 129.127-binary fixed-point number. The operation can't overflow // because n is maximum 255, LOG_SCALE_OFFSET is 127 bits and sign is either 1 or -1. result = int256(n) << LOG_SCALE_OFFSET; // This is y = x * 2^(-n). uint256 y = x >> n; // If y = 1, the fractional part is zero. if (y != LOG_SCALE) { // Calculate the fractional part via the iterative approximation. // The "delta >>= 1" part is equivalent to "delta /= 2", but shifting bits is faster. for (int256 delta = int256(1 << (LOG_SCALE_OFFSET - 1)); delta > 0; delta >>= 1) { y = (y * y) >> LOG_SCALE_OFFSET; // Is y^2 > 2 and so in the range [2,4)? if (y >= 1 << (LOG_SCALE_OFFSET + 1)) { // Add the 2^(-m) factor to the logarithm. result += delta; // Corresponds to z/2 on Wikipedia. y >>= 1; } } } // Convert x back to unsigned 128.128-binary fixed-point number result = (result * sign) << 1; } } /// @notice Returns the value of x^y. It calculates `1 / x^abs(y)` if x is bigger than 2^128. /// At the end of the operations, we invert the result if needed. /// @param x The unsigned 128.128-binary fixed-point number for which to calculate the power /// @param y A relative number without any decimals, needs to be between ]2^20; 2^20[ /// @return result The result of `x^y` function power(uint256 x, int256 y) internal pure returns (uint256 result) { bool invert; uint256 absY; if (y == 0) return Constants.SCALE; assembly { absY := y if slt(absY, 0) { absY := sub(0, absY) invert := iszero(invert) } } if (absY < 0x100000) { result = Constants.SCALE; assembly { let pow := x if gt(x, 0xffffffffffffffffffffffffffffffff) { pow := div(not(0), pow) invert := iszero(invert) } if and(absY, 0x1) { result := shr(128, mul(result, pow)) } pow := shr(128, mul(pow, pow)) if and(absY, 0x2) { result := shr(128, mul(result, pow)) } pow := shr(128, mul(pow, pow)) if and(absY, 0x4) { result := shr(128, mul(result, pow)) } pow := shr(128, mul(pow, pow)) if and(absY, 0x8) { result := shr(128, mul(result, pow)) } pow := shr(128, mul(pow, pow)) if and(absY, 0x10) { result := shr(128, mul(result, pow)) } pow := shr(128, mul(pow, pow)) if and(absY, 0x20) { result := shr(128, mul(result, pow)) } pow := shr(128, mul(pow, pow)) if and(absY, 0x40) { result := shr(128, mul(result, pow)) } pow := shr(128, mul(pow, pow)) if and(absY, 0x80) { result := shr(128, mul(result, pow)) } pow := shr(128, mul(pow, pow)) if and(absY, 0x100) { result := shr(128, mul(result, pow)) } pow := shr(128, mul(pow, pow)) if and(absY, 0x200) { result := shr(128, mul(result, pow)) } pow := shr(128, mul(pow, pow)) if and(absY, 0x400) { result := shr(128, mul(result, pow)) } pow := shr(128, mul(pow, pow)) if and(absY, 0x800) { result := shr(128, mul(result, pow)) } pow := shr(128, mul(pow, pow)) if and(absY, 0x1000) { result := shr(128, mul(result, pow)) } pow := shr(128, mul(pow, pow)) if and(absY, 0x2000) { result := shr(128, mul(result, pow)) } pow := shr(128, mul(pow, pow)) if and(absY, 0x4000) { result := shr(128, mul(result, pow)) } pow := shr(128, mul(pow, pow)) if and(absY, 0x8000) { result := shr(128, mul(result, pow)) } pow := shr(128, mul(pow, pow)) if and(absY, 0x10000) { result := shr(128, mul(result, pow)) } pow := shr(128, mul(pow, pow)) if and(absY, 0x20000) { result := shr(128, mul(result, pow)) } pow := shr(128, mul(pow, pow)) if and(absY, 0x40000) { result := shr(128, mul(result, pow)) } pow := shr(128, mul(pow, pow)) if and(absY, 0x80000) { result := shr(128, mul(result, pow)) } } } // revert if y is too big or if x^y underflowed if (result == 0) revert Math128x128__PowerUnderflow(x, y); return invert ? type(uint256).max / result : result; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "../LBErrors.sol"; import "./BitMath.sol"; /// @title Liquidity Book Math Helper Library /// @author Trader Joe /// @notice Helper contract used for full precision calculations library Math512Bits { using BitMath for uint256; /// @notice Calculates floor(x*y÷denominator) with full precision /// The result will be rounded down /// /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv /// /// Requirements: /// - The denominator cannot be zero /// - The result must fit within uint256 /// /// Caveats: /// - This function does not work with fixed-point numbers /// /// @param x The multiplicand as an uint256 /// @param y The multiplier as an uint256 /// @param denominator The divisor as an uint256 /// @return result The result as an uint256 function mulDivRoundDown( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { (uint256 prod0, uint256 prod1) = _getMulProds(x, y); return _getEndOfDivRoundDown(x, y, denominator, prod0, prod1); } /// @notice Calculates x * y >> offset with full precision /// The result will be rounded down /// /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv /// /// Requirements: /// - The offset needs to be strictly lower than 256 /// - The result must fit within uint256 /// /// Caveats: /// - This function does not work with fixed-point numbers /// /// @param x The multiplicand as an uint256 /// @param y The multiplier as an uint256 /// @param offset The offset as an uint256, can't be greater than 256 /// @return result The result as an uint256 function mulShiftRoundDown( uint256 x, uint256 y, uint256 offset ) internal pure returns (uint256 result) { if (offset > 255) revert Math512Bits__OffsetOverflows(offset); (uint256 prod0, uint256 prod1) = _getMulProds(x, y); if (prod0 != 0) result = prod0 >> offset; if (prod1 != 0) { // Make sure the result is less than 2^256. if (prod1 >= 1 << offset) revert Math512Bits__MulShiftOverflow(prod1, offset); unchecked { result += prod1 << (256 - offset); } } } /// @notice Calculates x * y >> offset with full precision /// The result will be rounded up /// /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv /// /// Requirements: /// - The offset needs to be strictly lower than 256 /// - The result must fit within uint256 /// /// Caveats: /// - This function does not work with fixed-point numbers /// /// @param x The multiplicand as an uint256 /// @param y The multiplier as an uint256 /// @param offset The offset as an uint256, can't be greater than 256 /// @return result The result as an uint256 function mulShiftRoundUp( uint256 x, uint256 y, uint256 offset ) internal pure returns (uint256 result) { unchecked { result = mulShiftRoundDown(x, y, offset); if (mulmod(x, y, 1 << offset) != 0) result += 1; } } /// @notice Calculates x << offset / y with full precision /// The result will be rounded down /// /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv /// /// Requirements: /// - The offset needs to be strictly lower than 256 /// - The result must fit within uint256 /// /// Caveats: /// - This function does not work with fixed-point numbers /// /// @param x The multiplicand as an uint256 /// @param offset The number of bit to shift x as an uint256 /// @param denominator The divisor as an uint256 /// @return result The result as an uint256 function shiftDivRoundDown( uint256 x, uint256 offset, uint256 denominator ) internal pure returns (uint256 result) { if (offset > 255) revert Math512Bits__OffsetOverflows(offset); uint256 prod0; uint256 prod1; prod0 = x << offset; // Least significant 256 bits of the product unchecked { prod1 = x >> (256 - offset); // Most significant 256 bits of the product } return _getEndOfDivRoundDown(x, 1 << offset, denominator, prod0, prod1); } /// @notice Calculates x << offset / y with full precision /// The result will be rounded up /// /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv /// /// Requirements: /// - The offset needs to be strictly lower than 256 /// - The result must fit within uint256 /// /// Caveats: /// - This function does not work with fixed-point numbers /// /// @param x The multiplicand as an uint256 /// @param offset The number of bit to shift x as an uint256 /// @param denominator The divisor as an uint256 /// @return result The result as an uint256 function shiftDivRoundUp( uint256 x, uint256 offset, uint256 denominator ) internal pure returns (uint256 result) { result = shiftDivRoundDown(x, offset, denominator); unchecked { if (mulmod(x, 1 << offset, denominator) != 0) result += 1; } } /// @notice Helper function to return the result of `x * y` as 2 uint256 /// @param x The multiplicand as an uint256 /// @param y The multiplier as an uint256 /// @return prod0 The least significant 256 bits of the product /// @return prod1 The most significant 256 bits of the product function _getMulProds(uint256 x, uint256 y) private pure returns (uint256 prod0, uint256 prod1) { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // 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. assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } } /// @notice Helper function to return the result of `x * y / denominator` with full precision /// @param x The multiplicand as an uint256 /// @param y The multiplier as an uint256 /// @param denominator The divisor as an uint256 /// @param prod0 The least significant 256 bits of the product /// @param prod1 The most significant 256 bits of the product /// @return result The result as an uint256 function _getEndOfDivRoundDown( uint256 x, uint256 y, uint256 denominator, uint256 prod0, uint256 prod1 ) private pure returns (uint256 result) { // Handle non-overflow cases, 256 by 256 division if (prod1 == 0) { unchecked { result = prod0 / denominator; } } else { // Make sure the result is less than 2^256. Also prevents denominator == 0 if (prod1 >= denominator) revert Math512Bits__MulDivOverflow(prod1, denominator); // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1 // See https://cs.stackexchange.com/q/138556/92363 unchecked { // Does not overflow because the denominator cannot be zero at this stage in the function uint256 lpotdod = denominator & (~denominator + 1); assembly { // Divide denominator by lpotdod. denominator := div(denominator, lpotdod) // Divide [prod1 prod0] by lpotdod. prod0 := div(prod0, lpotdod) // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one lpotdod := add(div(sub(0, lpotdod), lpotdod), 1) } // Shift in bits from prod1 into prod0 prod0 |= prod1 * lpotdod; // 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 for // four bits. That is, denominator * inv = 1 mod 2^4 uint256 inverse = (3 * denominator) ^ 2; // Use the 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 inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // 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 * inverse; } } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "../LBErrors.sol"; /// @title Liquidity Book Safe Cast Library /// @author Trader Joe /// @notice Helper contract used for converting uint values safely library SafeCast { /// @notice Returns x on uint248 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint248 function safe248(uint256 x) internal pure returns (uint248 y) { if ((y = uint248(x)) != x) revert SafeCast__Exceeds248Bits(x); } /// @notice Returns x on uint240 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint240 function safe240(uint256 x) internal pure returns (uint240 y) { if ((y = uint240(x)) != x) revert SafeCast__Exceeds240Bits(x); } /// @notice Returns x on uint232 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint232 function safe232(uint256 x) internal pure returns (uint232 y) { if ((y = uint232(x)) != x) revert SafeCast__Exceeds232Bits(x); } /// @notice Returns x on uint224 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint224 function safe224(uint256 x) internal pure returns (uint224 y) { if ((y = uint224(x)) != x) revert SafeCast__Exceeds224Bits(x); } /// @notice Returns x on uint216 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint216 function safe216(uint256 x) internal pure returns (uint216 y) { if ((y = uint216(x)) != x) revert SafeCast__Exceeds216Bits(x); } /// @notice Returns x on uint208 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint208 function safe208(uint256 x) internal pure returns (uint208 y) { if ((y = uint208(x)) != x) revert SafeCast__Exceeds208Bits(x); } /// @notice Returns x on uint200 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint200 function safe200(uint256 x) internal pure returns (uint200 y) { if ((y = uint200(x)) != x) revert SafeCast__Exceeds200Bits(x); } /// @notice Returns x on uint192 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint192 function safe192(uint256 x) internal pure returns (uint192 y) { if ((y = uint192(x)) != x) revert SafeCast__Exceeds192Bits(x); } /// @notice Returns x on uint184 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint184 function safe184(uint256 x) internal pure returns (uint184 y) { if ((y = uint184(x)) != x) revert SafeCast__Exceeds184Bits(x); } /// @notice Returns x on uint176 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint176 function safe176(uint256 x) internal pure returns (uint176 y) { if ((y = uint176(x)) != x) revert SafeCast__Exceeds176Bits(x); } /// @notice Returns x on uint168 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint168 function safe168(uint256 x) internal pure returns (uint168 y) { if ((y = uint168(x)) != x) revert SafeCast__Exceeds168Bits(x); } /// @notice Returns x on uint160 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint160 function safe160(uint256 x) internal pure returns (uint160 y) { if ((y = uint160(x)) != x) revert SafeCast__Exceeds160Bits(x); } /// @notice Returns x on uint152 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint152 function safe152(uint256 x) internal pure returns (uint152 y) { if ((y = uint152(x)) != x) revert SafeCast__Exceeds152Bits(x); } /// @notice Returns x on uint144 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint144 function safe144(uint256 x) internal pure returns (uint144 y) { if ((y = uint144(x)) != x) revert SafeCast__Exceeds144Bits(x); } /// @notice Returns x on uint136 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint136 function safe136(uint256 x) internal pure returns (uint136 y) { if ((y = uint136(x)) != x) revert SafeCast__Exceeds136Bits(x); } /// @notice Returns x on uint128 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint128 function safe128(uint256 x) internal pure returns (uint128 y) { if ((y = uint128(x)) != x) revert SafeCast__Exceeds128Bits(x); } /// @notice Returns x on uint120 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint120 function safe120(uint256 x) internal pure returns (uint120 y) { if ((y = uint120(x)) != x) revert SafeCast__Exceeds120Bits(x); } /// @notice Returns x on uint112 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint112 function safe112(uint256 x) internal pure returns (uint112 y) { if ((y = uint112(x)) != x) revert SafeCast__Exceeds112Bits(x); } /// @notice Returns x on uint104 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint104 function safe104(uint256 x) internal pure returns (uint104 y) { if ((y = uint104(x)) != x) revert SafeCast__Exceeds104Bits(x); } /// @notice Returns x on uint96 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint96 function safe96(uint256 x) internal pure returns (uint96 y) { if ((y = uint96(x)) != x) revert SafeCast__Exceeds96Bits(x); } /// @notice Returns x on uint88 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint88 function safe88(uint256 x) internal pure returns (uint88 y) { if ((y = uint88(x)) != x) revert SafeCast__Exceeds88Bits(x); } /// @notice Returns x on uint80 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint80 function safe80(uint256 x) internal pure returns (uint80 y) { if ((y = uint80(x)) != x) revert SafeCast__Exceeds80Bits(x); } /// @notice Returns x on uint72 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint72 function safe72(uint256 x) internal pure returns (uint72 y) { if ((y = uint72(x)) != x) revert SafeCast__Exceeds72Bits(x); } /// @notice Returns x on uint64 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint64 function safe64(uint256 x) internal pure returns (uint64 y) { if ((y = uint64(x)) != x) revert SafeCast__Exceeds64Bits(x); } /// @notice Returns x on uint56 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint56 function safe56(uint256 x) internal pure returns (uint56 y) { if ((y = uint56(x)) != x) revert SafeCast__Exceeds56Bits(x); } /// @notice Returns x on uint48 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint48 function safe48(uint256 x) internal pure returns (uint48 y) { if ((y = uint48(x)) != x) revert SafeCast__Exceeds48Bits(x); } /// @notice Returns x on uint40 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint40 function safe40(uint256 x) internal pure returns (uint40 y) { if ((y = uint40(x)) != x) revert SafeCast__Exceeds40Bits(x); } /// @notice Returns x on uint32 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint32 function safe32(uint256 x) internal pure returns (uint32 y) { if ((y = uint32(x)) != x) revert SafeCast__Exceeds32Bits(x); } /// @notice Returns x on uint24 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint24 function safe24(uint256 x) internal pure returns (uint24 y) { if ((y = uint24(x)) != x) revert SafeCast__Exceeds24Bits(x); } /// @notice Returns x on uint16 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint16 function safe16(uint256 x) internal pure returns (uint16 y) { if ((y = uint16(x)) != x) revert SafeCast__Exceeds16Bits(x); } /// @notice Returns x on uint8 and check that it does not overflow /// @param x The value as an uint256 /// @return y The value as an uint8 function safe8(uint256 x) internal pure returns (uint8 y) { if ((y = uint8(x)) != x) revert SafeCast__Exceeds8Bits(x); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; /// @title Liquidity Book Safe Math Helper Library /// @author Trader Joe /// @notice Helper contract used for calculating absolute value safely library SafeMath { /// @notice absSub, can't underflow or overflow /// @param x The first value /// @param y The second value /// @return The result of abs(x - y) function absSub(uint256 x, uint256 y) internal pure returns (uint256) { unchecked { return x > y ? x - y : y - x; } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "./BinHelper.sol"; import "./Constants.sol"; import "./FeeDistributionHelper.sol"; import "./FeeHelper.sol"; import "./Math512Bits.sol"; import "./SafeMath.sol"; import "../interfaces/ILBPair.sol"; /// @title Liquidity Book Swap Helper Library /// @author Trader Joe /// @notice Helper contract used for calculating swaps, fees and reserves changes library SwapHelper { using Math512Bits for uint256; using FeeHelper for FeeHelper.FeeParameters; using SafeMath for uint256; using FeeDistributionHelper for FeeHelper.FeesDistribution; /// @notice Returns the swap amounts in the current bin /// @param bin The bin information /// @param fp The fee parameters /// @param activeId The active id of the pair /// @param swapForY Whether you've swapping token X for token Y (true) or token Y for token X (false) /// @param amountIn The amount sent by the user /// @return amountInToBin The amount of token that is added to the bin without the fees /// @return amountOutOfBin The amount of token that is removed from the bin /// @return fees The swap fees function getAmounts( ILBPair.Bin memory bin, FeeHelper.FeeParameters memory fp, uint256 activeId, bool swapForY, uint256 amountIn ) internal pure returns ( uint256 amountInToBin, uint256 amountOutOfBin, FeeHelper.FeesDistribution memory fees ) { uint256 _price = BinHelper.getPriceFromId(activeId, fp.binStep); uint256 _reserve; uint256 _maxAmountInToBin; if (swapForY) { _reserve = bin.reserveY; _maxAmountInToBin = _reserve.shiftDivRoundUp(Constants.SCALE_OFFSET, _price); } else { _reserve = bin.reserveX; _maxAmountInToBin = _price.mulShiftRoundUp(_reserve, Constants.SCALE_OFFSET); } fp.updateVolatilityAccumulated(activeId); fees = fp.getFeeAmountDistribution(fp.getFeeAmount(_maxAmountInToBin)); if (_maxAmountInToBin + fees.total <= amountIn) { amountInToBin = _maxAmountInToBin; amountOutOfBin = _reserve; } else { fees = fp.getFeeAmountDistribution(fp.getFeeAmountFrom(amountIn)); amountInToBin = amountIn - fees.total; amountOutOfBin = swapForY ? _price.mulShiftRoundDown(amountInToBin, Constants.SCALE_OFFSET) : amountInToBin.shiftDivRoundDown(Constants.SCALE_OFFSET, _price); // Safety check in case rounding returns a higher value than expected if (amountOutOfBin > _reserve) amountOutOfBin = _reserve; } } /// @notice Update the fees of the pair and accumulated token per share of the bin /// @param bin The bin information /// @param pairFees The current fees of the pair information /// @param fees The fees amounts added to the pairFees /// @param swapForY whether the token sent was Y (true) or X (false) /// @param totalSupply The total supply of the token id function updateFees( ILBPair.Bin memory bin, FeeHelper.FeesDistribution memory pairFees, FeeHelper.FeesDistribution memory fees, bool swapForY, uint256 totalSupply ) internal pure { pairFees.total += fees.total; // unsafe math is fine because total >= protocol unchecked { pairFees.protocol += fees.protocol; } if (swapForY) { bin.accTokenXPerShare += fees.getTokenPerShare(totalSupply); } else { bin.accTokenYPerShare += fees.getTokenPerShare(totalSupply); } } /// @notice Update reserves /// @param bin The bin information /// @param pair The pair information /// @param swapForY whether the token sent was Y (true) or X (false) /// @param amountInToBin The amount of token that is added to the bin without fees /// @param amountOutOfBin The amount of token that is removed from the bin function updateReserves( ILBPair.Bin memory bin, ILBPair.PairInformation memory pair, bool swapForY, uint112 amountInToBin, uint112 amountOutOfBin ) internal pure { if (swapForY) { bin.reserveX += amountInToBin; unchecked { bin.reserveY -= amountOutOfBin; pair.reserveX += uint136(amountInToBin); pair.reserveY -= uint136(amountOutOfBin); } } else { bin.reserveY += amountInToBin; unchecked { bin.reserveX -= amountOutOfBin; pair.reserveX -= uint136(amountOutOfBin); pair.reserveY += uint136(amountInToBin); } } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "openzeppelin/token/ERC20/IERC20.sol"; import "../LBErrors.sol"; /// @title Safe Transfer /// @author Trader Joe /// @notice Wrappers around ERC20 operations that throw on failure (when the token /// contract returns false). Tokens that return no value (and instead revert or /// throw on failure) are also supported, non-reverting calls are assumed to be /// successful. /// To use this library you can add a `using TokenHelper for IERC20;` statement to your contract, /// which allows you to call the safe operation as `token.safeTransfer(...)` library TokenHelper { /// @notice Transfers token only if the amount is greater than zero /// @param token The address of the token /// @param owner The owner of the tokens /// @param recipient The address of the recipient /// @param amount The amount to send function safeTransferFrom( IERC20 token, address owner, address recipient, uint256 amount ) internal { if (amount != 0) { bytes memory data = abi.encodeWithSelector(token.transferFrom.selector, owner, recipient, amount); bytes memory returnData = _callAndCatchError(address(token), data); if (returnData.length > 0 && !abi.decode(returnData, (bool))) revert TokenHelper__TransferFailed(); } } /// @notice Transfers token only if the amount is greater than zero /// @param token The address of the token /// @param recipient The address of the recipient /// @param amount The amount to send function safeTransfer( IERC20 token, address recipient, uint256 amount ) internal { if (amount != 0) { bytes memory data = abi.encodeWithSelector(token.transfer.selector, recipient, amount); bytes memory returnData = _callAndCatchError(address(token), data); if (returnData.length > 0 && !abi.decode(returnData, (bool))) revert TokenHelper__TransferFailed(); } } /// @notice Returns the amount of token received by the pair /// @param token The address of the token /// @param reserve The total reserve of token /// @param fees The total fees of token /// @return The amount received by the pair function received( IERC20 token, uint256 reserve, uint256 fees ) internal view returns (uint256) { uint256 _internalBalance; unchecked { _internalBalance = reserve + fees; } return token.balanceOf(address(this)) - _internalBalance; } /// @notice Private view function to perform a low level call on `target` /// @dev Revert if the call doesn't succeed /// @param target The address of the account /// @param data The data to execute on `target` /// @return returnData The data returned by the call function _callAndCatchError(address target, bytes memory data) private returns (bytes memory) { (bool success, bytes memory returnData) = target.call(data); if (success) { if (returnData.length == 0 && !_isContract(target)) revert TokenHelper__NonContract(); } else { if (returnData.length == 0) revert TokenHelper__CallFailed(); else { // Look for revert reason and bubble it up if present assembly { revert(add(32, returnData), mload(returnData)) } } } return returnData; } /// @notice Private view function to return if an address is a contract /// @dev It is unsafe to assume that an address for which this function returns /// false is an externally-owned account (EOA) and not a contract. /// /// Among others, `isContract` will return false for the following /// types of addresses: /// - an externally-owned account /// - a contract in construction /// - an address where a contract will be created /// - an address where a contract lived, but was destroyed /// @param account The address of the account /// @return Whether the account is a contract (true) or not (false) function _isContract(address account) private view returns (bool) { return account.code.length > 0; } }
{ "remappings": [ "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "openzeppelin/=lib/openzeppelin-contracts/contracts/" ], "optimizer": { "enabled": true, "runs": 800 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract ILBFactory","name":"_factory","type":"address"},{"internalType":"contract IJoeFactory","name":"_oldFactory","type":"address"},{"internalType":"contract IWAVAX","name":"_wavax","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"bp","type":"uint256"}],"name":"BinHelper__BinStepOverflows","type":"error"},{"inputs":[],"name":"BinHelper__IdOverflows","type":"error"},{"inputs":[],"name":"JoeLibrary__InsufficientAmount","type":"error"},{"inputs":[],"name":"JoeLibrary__InsufficientLiquidity","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountXMin","type":"uint256"},{"internalType":"uint256","name":"amountX","type":"uint256"},{"internalType":"uint256","name":"amountYMin","type":"uint256"},{"internalType":"uint256","name":"amountY","type":"uint256"}],"name":"LBRouter__AmountSlippageCaught","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"LBRouter__BinReserveOverflows","type":"error"},{"inputs":[],"name":"LBRouter__BrokenSwapSafetyCheck","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"currentTimestamp","type":"uint256"}],"name":"LBRouter__DeadlineExceeded","type":"error"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LBRouter__FailedToSendAVAX","type":"error"},{"inputs":[{"internalType":"uint256","name":"idDesired","type":"uint256"},{"internalType":"uint256","name":"idSlippage","type":"uint256"}],"name":"LBRouter__IdDesiredOverflows","type":"error"},{"inputs":[{"internalType":"int256","name":"id","type":"int256"}],"name":"LBRouter__IdOverflows","type":"error"},{"inputs":[{"internalType":"uint256","name":"activeIdDesired","type":"uint256"},{"internalType":"uint256","name":"idSlippage","type":"uint256"},{"internalType":"uint256","name":"activeId","type":"uint256"}],"name":"LBRouter__IdSlippageCaught","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"LBRouter__InsufficientAmountOut","type":"error"},{"inputs":[{"internalType":"address","name":"wrongToken","type":"address"}],"name":"LBRouter__InvalidTokenPath","type":"error"},{"inputs":[],"name":"LBRouter__LengthsMismatch","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"LBRouter__MaxAmountInExceeded","type":"error"},{"inputs":[],"name":"LBRouter__NotFactoryOwner","type":"error"},{"inputs":[{"internalType":"address","name":"tokenX","type":"address"},{"internalType":"address","name":"tokenY","type":"address"},{"internalType":"uint256","name":"binStep","type":"uint256"}],"name":"LBRouter__PairNotCreated","type":"error"},{"inputs":[],"name":"LBRouter__SenderIsNotWAVAX","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"LBRouter__SwapOverflows","type":"error"},{"inputs":[{"internalType":"uint256","name":"excess","type":"uint256"}],"name":"LBRouter__TooMuchTokensIn","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"reserve","type":"uint256"}],"name":"LBRouter__WrongAmounts","type":"error"},{"inputs":[{"internalType":"address","name":"tokenX","type":"address"},{"internalType":"address","name":"tokenY","type":"address"},{"internalType":"uint256","name":"amountX","type":"uint256"},{"internalType":"uint256","name":"amountY","type":"uint256"},{"internalType":"uint256","name":"msgValue","type":"uint256"}],"name":"LBRouter__WrongAvaxLiquidityParameters","type":"error"},{"inputs":[],"name":"LBRouter__WrongTokenOrder","type":"error"},{"inputs":[],"name":"Math128x128__LogUnderflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"int256","name":"y","type":"int256"}],"name":"Math128x128__PowerUnderflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"prod1","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"Math512Bits__MulDivOverflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"prod1","type":"uint256"},{"internalType":"uint256","name":"offset","type":"uint256"}],"name":"Math512Bits__MulShiftOverflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"offset","type":"uint256"}],"name":"Math512Bits__OffsetOverflows","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"SafeCast__Exceeds128Bits","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"SafeCast__Exceeds40Bits","type":"error"},{"inputs":[],"name":"TokenHelper__CallFailed","type":"error"},{"inputs":[],"name":"TokenHelper__NonContract","type":"error"},{"inputs":[],"name":"TokenHelper__TransferFailed","type":"error"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"tokenX","type":"address"},{"internalType":"contract IERC20","name":"tokenY","type":"address"},{"internalType":"uint256","name":"binStep","type":"uint256"},{"internalType":"uint256","name":"amountX","type":"uint256"},{"internalType":"uint256","name":"amountY","type":"uint256"},{"internalType":"uint256","name":"amountXMin","type":"uint256"},{"internalType":"uint256","name":"amountYMin","type":"uint256"},{"internalType":"uint256","name":"activeIdDesired","type":"uint256"},{"internalType":"uint256","name":"idSlippage","type":"uint256"},{"internalType":"int256[]","name":"deltaIds","type":"int256[]"},{"internalType":"uint256[]","name":"distributionX","type":"uint256[]"},{"internalType":"uint256[]","name":"distributionY","type":"uint256[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct ILBRouter.LiquidityParameters","name":"_liquidityParameters","type":"tuple"}],"name":"addLiquidity","outputs":[{"internalType":"uint256[]","name":"depositIds","type":"uint256[]"},{"internalType":"uint256[]","name":"liquidityMinted","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"tokenX","type":"address"},{"internalType":"contract IERC20","name":"tokenY","type":"address"},{"internalType":"uint256","name":"binStep","type":"uint256"},{"internalType":"uint256","name":"amountX","type":"uint256"},{"internalType":"uint256","name":"amountY","type":"uint256"},{"internalType":"uint256","name":"amountXMin","type":"uint256"},{"internalType":"uint256","name":"amountYMin","type":"uint256"},{"internalType":"uint256","name":"activeIdDesired","type":"uint256"},{"internalType":"uint256","name":"idSlippage","type":"uint256"},{"internalType":"int256[]","name":"deltaIds","type":"int256[]"},{"internalType":"uint256[]","name":"distributionX","type":"uint256[]"},{"internalType":"uint256[]","name":"distributionY","type":"uint256[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct ILBRouter.LiquidityParameters","name":"_liquidityParameters","type":"tuple"}],"name":"addLiquidityAVAX","outputs":[{"internalType":"uint256[]","name":"depositIds","type":"uint256[]"},{"internalType":"uint256[]","name":"liquidityMinted","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_tokenX","type":"address"},{"internalType":"contract IERC20","name":"_tokenY","type":"address"},{"internalType":"uint24","name":"_activeId","type":"uint24"},{"internalType":"uint16","name":"_binStep","type":"uint16"}],"name":"createLBPair","outputs":[{"internalType":"contract ILBPair","name":"pair","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract ILBFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ILBPair","name":"_LBPair","type":"address"},{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"getIdFromPrice","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ILBPair","name":"_LBPair","type":"address"},{"internalType":"uint24","name":"_id","type":"uint24"}],"name":"getPriceFromId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ILBPair","name":"_LBPair","type":"address"},{"internalType":"uint256","name":"_amountOut","type":"uint256"},{"internalType":"bool","name":"_swapForY","type":"bool"}],"name":"getSwapIn","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"feesIn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ILBPair","name":"_LBPair","type":"address"},{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"bool","name":"_swapForY","type":"bool"}],"name":"getSwapOut","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"feesIn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oldFactory","outputs":[{"internalType":"contract IJoeFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_tokenX","type":"address"},{"internalType":"contract IERC20","name":"_tokenY","type":"address"},{"internalType":"uint16","name":"_binStep","type":"uint16"},{"internalType":"uint256","name":"_amountXMin","type":"uint256"},{"internalType":"uint256","name":"_amountYMin","type":"uint256"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountX","type":"uint256"},{"internalType":"uint256","name":"amountY","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"uint16","name":"_binStep","type":"uint16"},{"internalType":"uint256","name":"_amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"_amountAVAXMin","type":"uint256"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address payable","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"removeLiquidityAVAX","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountAVAX","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountOut","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapAVAXForExactTokens","outputs":[{"internalType":"uint256[]","name":"amountsIn","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountOutMin","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapExactAVAXForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountOutMin","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapExactAVAXForTokensSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"uint256","name":"_amountOutMinAVAX","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address payable","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapExactTokensForAVAX","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"uint256","name":"_amountOutMinAVAX","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address payable","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapExactTokensForAVAXSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"uint256","name":"_amountOutMin","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"uint256","name":"_amountOutMin","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapExactTokensForTokensSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountAVAXOut","type":"uint256"},{"internalType":"uint256","name":"_amountInMax","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address payable","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapTokensForExactAVAX","outputs":[{"internalType":"uint256[]","name":"amountsIn","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountOut","type":"uint256"},{"internalType":"uint256","name":"_amountInMax","type":"uint256"},{"internalType":"uint256[]","name":"_pairBinSteps","type":"uint256[]"},{"internalType":"contract IERC20[]","name":"_tokenPath","type":"address[]"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256[]","name":"amountsIn","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ILBToken","name":"_lbToken","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"sweepLBToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wavax","outputs":[{"internalType":"contract IWAVAX","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60e06040523480156200001157600080fd5b5060405162005ae038038062005ae083398101604081905262000034916200006b565b6001600160a01b0392831660805290821660a0521660c052620000bf565b6001600160a01b03811681146200006857600080fd5b50565b6000806000606084860312156200008157600080fd5b83516200008e8162000052565b6020850151909350620000a18162000052565b6040850151909250620000b48162000052565b809150509250925092565b60805160a05160c0516159496200019760003960008181610194015281816101eb01528181610ac301528181610c3d01528181610e640152818161170a0152818161185f01528181611948015281816119db01528181611a9e01528181611b5e01528181611d1101528181611dab01528181611e3501528181612332015281816123b0015281816125610152818161263a01528181612eac0152612f2a01526000818161023c01526143200152600081816104390152818161139001528181611533015281816121510152613b7301526159496000f3fe6080604052600436106101845760003560e01c80636d3420ed116100d6578063d0e380f21161007f578063ea8f43d811610059578063ea8f43d8146104c9578063f96fe925146104dc578063fb321c701461051057600080fd5b8063d0e380f21461045b578063e324a3e41461047b578063e9361c08146104a957600080fd5b8063bcb1c957116100b0578063bcb1c957146103e7578063c22159b614610407578063c45a01551461042757600080fd5b80636d3420ed146103875780639a17e820146103a7578063a7b856d3146103c757600080fd5b806342f564a01161013857806362c067671161011257806362c0676714610327578063659ac74b146103475780636d0ff4951461036757600080fd5b806342f564a0146102d4578063440830bd146102f45780635bdd4b7c1461030757600080fd5b80632004b724116101695780632004b7241461025e578063212a1d9414610293578063264bb94e146102c157600080fd5b8063117be4c2146101d95780631bd6dfe11461022a57600080fd5b366101d457336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101d2576040516310d0bef760e31b815260040160405180910390fd5b005b600080fd5b3480156101e557600080fd5b5061020d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561023657600080fd5b5061020d7f000000000000000000000000000000000000000000000000000000000000000081565b34801561026a57600080fd5b5061027e610279366004614bc9565b610530565b60408051928352602083019190915201610221565b34801561029f57600080fd5b506102b36102ae366004614d7a565b610839565b604051908152602001610221565b6102b36102cf366004614e0e565b610a57565b6102e76102e2366004614e0e565b610bd1565b6040516102219190614ed1565b6102b3610302366004614e0e565b610df8565b34801561031357600080fd5b5061027e610322366004614bc9565b61103d565b34801561033357600080fd5b506101d2610342366004614ee4565b61138e565b34801561035357600080fd5b5061020d610362366004614f51565b6114f4565b34801561037357600080fd5b506102b3610382366004614d7a565b6115ab565b34801561039357600080fd5b506102e76103a2366004614d7a565b61169e565b3480156103b357600080fd5b506102b36103c2366004614d7a565b6118dc565b3480156103d357600080fd5b506102e76103e2366004614d7a565b611bcc565b3480156103f357600080fd5b5061027e610402366004614fad565b611cdb565b34801561041357600080fd5b5061027e610422366004615068565b611eb3565b34801561043357600080fd5b5061020d7f000000000000000000000000000000000000000000000000000000000000000081565b34801561046757600080fd5b506102b3610476366004615130565b611fa7565b34801561048757600080fd5b5061049b610496366004615169565b612028565b6040516102219291906151a5565b3480156104b557600080fd5b506101d26104c4366004615216565b61214f565b61049b6104d7366004615169565b612272565b3480156104e857600080fd5b506104fc6104f73660046152ab565b612482565b60405162ffffff9091168152602001610221565b34801561051c57600080fd5b506102b361052b366004614d7a565b6124f5565b6000806000856001600160a01b0316631b05b83e6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610573573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061059791906152d7565b925050506000866001600160a01b03166398c7adf36040518163ffffffff1660e01b815260040161018060405180830381865afa1580156105dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106009190615330565b905061060c81836126a8565b6040805160808101825260008082526020820181905291810182905260608101919091525b604051630157d2d160e31b815262ffffff8416600482015260009081906001600160a01b038b1690630abe9688906024016040805180830381865afa15801561067e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a2919061541c565b604080516080810182526001600160701b03938416808252939092166020830152600090820181905260608201529350151591508190506106ef575060208101516001600160701b031615155b1561078557600080806107058486888c8e612765565b919450925090506001600160701b0383111561073c57604051633d9af4e160e11b8152600481018790526024015b60405180910390fd5b8051610751906001600160801b031684615456565b61075b908b61546e565b8151909a50610773906001600160801b031688615456565b965061077f8289615456565b97505050505b861561080c57604051638f919a8360e01b815262ffffff8416600482015286151560248201526001600160a01b03891690638f919a8390604401602060405180830381865afa1580156107dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108009190615485565b62ffffff169250610631565b861561082e576040516349cda5cd60e11b815260048101889052602401610733565b505050935093915050565b600081804211156108665760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480610885575080518251610882906001615456565b14155b156108a35760405163b91b4d4d60e01b815260040160405180910390fd5b60006108af8989612889565b90506000888251815181106108c6576108c66154a2565b60209081029190910101516040516370a0823160e01b81526001600160a01b038a811660048301529192506000918316906370a0823190602401602060405180830381865afa15801561091d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061094191906154b8565b9050610997338460008151811061095a5761095a6154a2565b60200260200101518f8d600081518110610976576109766154a2565b60200260200101516001600160a01b031661297e909392919063ffffffff16565b6109a3838c8c8c612a3f565b6040516370a0823160e01b81526001600160a01b038a811660048301528291908416906370a0823190602401602060405180830381865afa1580156109ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1091906154b8565b610a1a919061546e565b9650868c1115610a47576040516313fab00360e21b8152600481018d905260248101889052604401610733565b5050505050509695505050505050565b60008180421115610a845760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480610aa3575080518251610aa0906001615456565b14155b15610ac15760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031687600081518110610afe57610afe6154a2565b60200260200101516001600160a01b031614610b585786600081518110610b2757610b276154a2565b602002602001015160405163cfec0e0160e01b815260040161073391906001600160a01b0391909116815260200190565b6000610b648989612889565b9050610b8a81600081518110610b7c57610b7c6154a2565b602002602001015134612eaa565b610b9734828b8b8b612f59565b9450848a1115610bc4576040516313fab00360e21b8152600481018b905260248101869052604401610733565b5050505095945050505050565b60608180421115610bfe5760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480610c1d575080518251610c1a906001615456565b14155b15610c3b5760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031687600081518110610c7857610c786154a2565b60200260200101516001600160a01b031614610ca15786600081518110610b2757610b276154a2565b6000610cad8989612889565b9050610cbb89828a8d6132da565b94503485600081518110610cd157610cd16154a2565b60200260200101511115610d1f573485600081518110610cf357610cf36154a2565b602002602001015160405163194ee21960e31b8152600401610733929190918252602082015260400190565b610d5d81600081518110610d3557610d356154a2565b602002602001015186600081518110610d5057610d506154a2565b6020026020010151612eaa565b6000610d6c828b8b898c6135c5565b90508a811015610d99576040516313fab00360e21b8152600481018c905260248101829052604401610733565b85600081518110610dac57610dac6154a2565b6020026020010151341115610dea57610dea3387600081518110610dd257610dd26154a2565b602002602001015134610de5919061546e565b613894565b505050505095945050505050565b60008180421115610e255760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480610e44575080518251610e41906001615456565b14155b15610e625760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031687600081518110610e9f57610e9f6154a2565b60200260200101516001600160a01b031614610ec85786600081518110610b2757610b276154a2565b6000610ed48989612889565b9050600088825181518110610eeb57610eeb6154a2565b60209081029190910101516040516370a0823160e01b81526001600160a01b038a811660048301529192506000918316906370a0823190602401602060405180830381865afa158015610f42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6691906154b8565b9050610f7e83600081518110610b7c57610b7c6154a2565b610f8a838c8c8c612a3f565b6040516370a0823160e01b81526001600160a01b038a811660048301528291908416906370a0823190602401602060405180830381865afa158015610fd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff791906154b8565b611001919061546e565b9650868c111561102e576040516313fab00360e21b8152600481018d905260248101889052604401610733565b50505050505095945050505050565b6000806000806000876001600160a01b0316631b05b83e6040518163ffffffff1660e01b8152600401606060405180830381865afa158015611083573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a791906152d7565b92509250925086600014806110c85750856110c4578287116110c8565b8187115b156110fd5786866110d957836110db565b825b604051637c40a4df60e01b815260048101929092526024820152604401610733565b6000886001600160a01b03166398c7adf36040518163ffffffff1660e01b815260040161018060405180830381865afa15801561113e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111629190615330565b905061116e81836126a8565b60008060005b604051630157d2d160e31b815262ffffff8616600482015260009081906001600160a01b038f1690630abe9688906024016040805180830381865afa1580156111c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e5919061541c565b915091508b6111f457816111f6565b805b92505050600061120e86866000015161ffff1661391a565b905081156112cd57818c1015611224578b611226565b815b935060008b6112405761123b82866080613962565b61124c565b61124c85608084613995565b905061125886886139c7565b60006112648783613a39565b90506112708183615456565b94506001600160701b036112848587615456565b11156112a65760405163ec44eb8960e01b815260048101899052602401610733565b6112b0858d615456565b9b506112bc818c615456565b9a506112c8868f61546e565b9d5050505b8b1561135457604051638f919a8360e01b815262ffffff871660048201528b151560248201526001600160a01b038e1690638f919a8390604401602060405180830381865afa158015611324573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113489190615485565b62ffffff16955061135a565b50611360565b50611174565b8a1561137f576040516330b1335760e21b815260040160405180910390fd5b50505050505050935093915050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141091906154d1565b6001600160a01b0316336001600160a01b03161461144157604051635d9515b960e11b815260040160405180910390fd5b6001600160a01b03831661146b5760001981141561145c5750475b6114668282613894565b505050565b6000198114156114e0576040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156114b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114dd91906154b8565b90505b6114666001600160a01b0384168383613a89565b60405163659ac74b60e01b81526001600160a01b038581166004830152848116602483015262ffffff8416604483015261ffff831660648301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063659ac74b906084016020604051808303816000875af115801561157e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a291906154d1565b95945050505050565b600081804211156115d85760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b85858151600014806115f75750805182516115f4906001615456565b14155b156116155760405163b91b4d4d60e01b815260040160405180910390fd5b60006116218989612889565b9050611656338260008151811061163a5761163a6154a2565b60200260200101518d8b600081518110610976576109766154a2565b6116638b828b8b8b612f59565b9450848a1115611690576040516313fab00360e21b8152600481018b905260248101869052604401610733565b505050509695505050505050565b606081804211156116cb5760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b85858151600014806116ea5750805182516116e7906001615456565b14155b156117085760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031687895181518110611745576117456154a2565b60200260200101516001600160a01b03161461176e5786885181518110610b2757610b276154a2565b600061177a8989612889565b905061178889828a8e6132da565b9450898560008151811061179e5761179e6154a2565b602002602001015111156117c0578985600081518110610cf357610cf36154a2565b61180d33826000815181106117d7576117d76154a2565b6020026020010151876000815181106117f2576117f26154a2565b60200260200101518b600081518110610976576109766154a2565b600061181c828b8b89306135c5565b90508b811015611849576040516313fab00360e21b8152600481018d905260248101829052604401610733565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156118ab57600080fd5b505af11580156118bf573d6000803e3d6000fd5b505050506118cd8882613894565b50505050509695505050505050565b600081804211156119095760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480611928575080518251611925906001615456565b14155b156119465760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031687895181518110611983576119836154a2565b60200260200101516001600160a01b0316146119ac5786885181518110610b2757610b276154a2565b60006119b88989612889565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015611a22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4691906154b8565b9050611a7b3383600081518110611a5f57611a5f6154a2565b60200260200101518e8c600081518110610976576109766154a2565b611a87828b8b30612a3f565b6040516370a0823160e01b815230600482015281907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611aed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b1191906154b8565b611b1b919061546e565b9550858b1115611b48576040516313fab00360e21b8152600481018c905260248101879052604401610733565b604051632e1a7d4d60e01b8152600481018790527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015611baa57600080fd5b505af1158015611bbe573d6000803e3d6000fd5b505050506118cd8887613894565b60608180421115611bf95760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480611c18575080518251611c15906001615456565b14155b15611c365760405163b91b4d4d60e01b815260040160405180910390fd5b6000611c428989612889565b9050611c5089828a8e6132da565b94508985600081518110611c6657611c666154a2565b60200260200101511115611c88578985600081518110610cf357610cf36154a2565b611c9f33826000815181106117d7576117d76154a2565b6000611cae828b8b898c6135c5565b90508b8110156118cd576040516313fab00360e21b8152600481018d905260248101829052604401610733565b6000808280421115611d095760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b6000611d3a8c7f00000000000000000000000000000000000000000000000000000000000000008d61ffff16613b40565b90506000816001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da091906154d1565b6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614905080611ddf579899985b600080611df0848e8e8e8e30613c25565b9150915082611e00578082611e03565b81815b9097509550611e1f9150506001600160a01b038e168887613a89565b604051632e1a7d4d60e01b8152600481018590527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015611e8157600080fd5b505af1158015611e95573d6000803e3d6000fd5b50505050611ea38785613894565b5050509850989650505050505050565b6000808280421115611ee15760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b6000611ef28d8d8d61ffff16613b40565b90506000816001600160a01b03166316dc165b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5891906154d1565b6001600160a01b03168e6001600160a01b0316141590508015611f79579899985b611f87828c8c8c8c8c613c25565b90955093508015611f96579293925b505050995099975050505050505050565b600061201f8262ffffff16846001600160a01b03166398c7adf36040518163ffffffff1660e01b815260040161018060405180830381865afa158015611ff1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120159190615330565b5161ffff1661391a565b90505b92915050565b606080600061205761203d60208601866154ee565b61204d60408701602088016154ee565b8660400135613b40565b9050806001600160a01b03166316dc165b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120bb91906154d1565b6001600160a01b03166120d160208601866154ee565b6001600160a01b0316146120f85760405163b33f8ab960e01b815260040160405180910390fd5b6121203382606087013561210f60208901896154ee565b6001600160a01b031692919061297e565b61213a3382608087013561210f6040890160208a016154ee565b6121448482613d51565b909590945092505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d191906154d1565b6001600160a01b0316336001600160a01b03161461220257604051635d9515b960e11b815260040160405180910390fd5b604051633ee83b9960e21b81526001600160a01b0387169063fba0ee64906122389030908990899089908990899060040161555a565b600060405180830381600087803b15801561225257600080fd5b505af1158015612266573d6000803e3d6000fd5b50505050505050505050565b606080600061228761203d60208601866154ee565b9050806001600160a01b03166316dc165b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122eb91906154d1565b6001600160a01b031661230160208601866154ee565b6001600160a01b0316146123285760405163b33f8ab960e01b815260040160405180910390fd5b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001661235f60208601866154ee565b6001600160a01b03161480156123785750348460600135145b156123a6576123878134612eaa565b6123a13382608087013561210f6040890160208a016154ee565b61213a565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166123e060408601602087016154ee565b6001600160a01b03161480156123f95750348460800135145b1561241f576124153382606087013561210f60208901896154ee565b6123a18134612eaa565b61242c60208501856154ee565b61243c60408601602087016154ee565b60405163959ceb2b60e01b81526001600160a01b03928316600482015291166024820152606085013560448201526080850135606482015234608482015260a401610733565b600061201f82846001600160a01b03166398c7adf36040518163ffffffff1660e01b815260040161018060405180830381865afa1580156124c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124eb9190615330565b5161ffff166140ed565b600081804211156125225760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b858581516000148061254157508051825161253e906001615456565b14155b1561255f5760405163b91b4d4d60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168789518151811061259c5761259c6154a2565b60200260200101516001600160a01b0316146125c55786885181518110610b2757610b276154a2565b60006125d18989612889565b90506125ea338260008151811061163a5761163a6154a2565b6125f78b828b8b30612f59565b9450848a1115612624576040516313fab00360e21b8152600481018b905260248101869052604401610733565b604051632e1a7d4d60e01b8152600481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561268657600080fd5b505af115801561269a573d6000803e3d6000fd5b505050506116908786613894565b600082610160015164ffffffffff16426126c2919061546e565b9050826040015161ffff16811015806126e5575061016083015164ffffffffff16155b156127455762ffffff8216610140840152606083015161ffff1681101561273c5761271083610100015162ffffff16846080015161ffff16028161272b5761272b6155a7565b0462ffffff16610120840152612745565b60006101208401525b61274e42614153565b64ffffffffff1661016084015261146683836139c7565b60408051808201909152600080825260208201819052908190600061279287896000015161ffff1661391a565b905060008087156127c05760208b01516001600160701b031691506127b982608085613995565b90506127dc565b8a516001600160701b031691506127d983836080613962565b90505b6127e68a8a6139c7565b6127fa6127f38b83613a39565b8b90614183565b80519094508790612814906001600160801b031683615456565b116128245780955081945061287b565b6128316127f38b896141cf565b8051909450612849906001600160801b03168861546e565b9550876128615761285c86608085614216565b61286d565b61286d83876080614263565b94508185111561287b578194505b505050955095509592505050565b6060825167ffffffffffffffff8111156128a5576128a5614c0b565b6040519080825280602002602001820160405280156128ce578160200160208202803683370190505b509050600080836000815181106128e7576128e76154a2565b6020026020010151905060005b835181101561297557819250848160010181518110612915576129156154a2565b60200260200101519150612943868281518110612934576129346154a2565b602002602001015184846142f2565b848281518110612955576129556154a2565b6001600160a01b03909216602092830291909101909101526001016128f4565b50505092915050565b8015612a3957604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166323b872dd60e01b17905260006129f486836143de565b905060008151118015612a18575080806020019051810190612a1691906155bd565b155b15612a365760405163197138bd60e11b815260040160405180910390fd5b50505b50505050565b600080600080600086600081518110612a5a57612a5a6154a2565b6020026020010151905060005b895181101561226657898181518110612a8257612a826154a2565b60200260200101519250888181518110612a9e57612a9e6154a2565b60200260200101519450819550878160010181518110612ac057612ac06154a2565b6020026020010151915089518160010114612af757898160010181518110612aea57612aea6154a2565b6020026020010151612af9565b865b935084612da157600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015612b41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6591906155f1565b506001600160701b031691506001600160701b03169150836001600160a01b0316886001600160a01b03161015612c9a576040516370a0823160e01b81526001600160a01b03868116600483015260009184918b16906370a0823190602401602060405180830381865afa158015612be1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c0591906154b8565b0390506000612c158285856144a9565b60405163022c0d9f60e01b8152600060048201819052602482018390526001600160a01b038b811660448401526080606484015260848301919091529192509088169063022c0d9f9060a401600060405180830381600087803b158015612c7b57600080fd5b505af1158015612c8f573d6000803e3d6000fd5b505050505050612d9a565b6040516370a0823160e01b81526001600160a01b03868116600483015260009183918b16906370a0823190602401602060405180830381865afa158015612ce5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d0991906154b8565b0390506000612d198284866144a9565b60405163022c0d9f60e01b8152600481018290526000602482018190526001600160a01b038b811660448401526080606484015260848301919091529192509088169063022c0d9f9060a401600060405180830381600087803b158015612d7f57600080fd5b505af1158015612d93573d6000803e3d6000fd5b5050505050505b5050612ea2565b826001600160a01b03166353c059a0846001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015612dee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e1291906154d1565b60405160e083901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b03918216868316146004820152908716602482015260440160408051808303816000875af1158015612e7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e9f919061541c565b50505b600101612a67565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f0557600080fd5b505af1158015612f19573d6000803e3d6000fd5b50612f559350506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016915084905083613a89565b5050565b60008060008060008087600081518110612f7557612f756154a2565b602002602001015190508a955060005b8a5181101561102e578a8181518110612fa057612fa06154a2565b60200260200101519250898181518110612fbc57612fbc6154a2565b60200260200101519450819550888160010181518110612fde57612fde6154a2565b602002602001015191508a518160010114613015578a8160010181518110613008576130086154a2565b6020026020010151613017565b875b9350846131d357600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa15801561305f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061308391906155f1565b506001600160701b031691506001600160701b03169150836001600160a01b0316886001600160a01b03161015613142576130bf8983836144a9565b60405163022c0d9f60e01b8152600060048201819052602482018390526001600160a01b038981166044840152608060648401526084830191909152919a509086169063022c0d9f9060a401600060405180830381600087803b15801561312557600080fd5b505af1158015613139573d6000803e3d6000fd5b505050506131cc565b61314d8982846144a9565b60405163022c0d9f60e01b8152600481018290526000602482018190526001600160a01b038981166044840152608060648401526084830191909152919a509086169063022c0d9f9060a401600060405180830381600087803b1580156131b357600080fd5b505af11580156131c7573d6000803e3d6000fd5b505050505b50506132d2565b6000836001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015613213573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061323791906154d1565b60405163029e02cd60e51b81526001600160a01b039182168583161460048201819052878316602483015292506000918291908716906353c059a09060440160408051808303816000875af1158015613294573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132b8919061541c565b9150915082156132ca578099506132ce565b8199505b5050505b600101612f85565b6060825167ffffffffffffffff8111156132f6576132f6614c0b565b60405190808252806020026020018201604052801561331f578160200160208202803683370190505b5090508181855181518110613336576133366154a2565b602090810291909101015283515b80156135bc5760008461335860018461546e565b81518110613368576133686154a2565b60200260200101519050600087600184613382919061546e565b81518110613392576133926154a2565b602002602001015190506000876001856133ac919061546e565b815181106133bc576133bc6154a2565b6020026020010151905081600014156134e357600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015613410573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061343491906155f1565b506001600160701b031691506001600160701b0316915088868151811061345d5761345d6154a2565b60200260200101516001600160a01b0316856001600160a01b0316111561348057905b6000878781518110613494576134946154a2565b602002602001015190506134b38383836145409092919063ffffffff16565b886134bf60018a61546e565b815181106134cf576134cf6154a2565b6020026020010181815250505050506135a6565b61357c818686815181106134f9576134f96154a2565b6020026020010151856001600160a01b0316846001600160a01b03166316dc165b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613549573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061356d91906154d1565b6001600160a01b03161461103d565b508561358960018761546e565b81518110613599576135996154a2565b6020026020010181815250505b50505080806135b490615636565b915050613344565b50949350505050565b600080600080600080886000815181106135e1576135e16154a2565b6020026020010151905060005b8b5181101561102e578b8181518110613609576136096154a2565b602002602001015192508a8181518110613625576136256154a2565b60200260200101519450819550898160010181518110613647576136476154a2565b602002602001015191508b51816001011461367e578b8160010181518110613671576136716154a2565b6020026020010151613680565b875b93508461378d5788816001018151811061369c5761369c6154a2565b60200260200101519650816001600160a01b0316866001600160a01b031610156137405760405163022c0d9f60e01b8152600060048201819052602482018990526001600160a01b03868116604484015260806064840152608483019190915284169063022c0d9f9060a4015b600060405180830381600087803b15801561372357600080fd5b505af1158015613737573d6000803e3d6000fd5b5050505061388c565b60405163022c0d9f60e01b8152600481018890526000602482018190526001600160a01b03868116604484015260806064840152608483019190915284169063022c0d9f9060a401613709565b6000836001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156137cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137f191906154d1565b60405163029e02cd60e51b81526001600160a01b039182168583161460048201819052878316602483015292506000918291908716906353c059a09060440160408051808303816000875af115801561384e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613872919061541c565b91509150821561388457809950613888565b8199505b5050505b6001016135ee565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146138e1576040519150601f19603f3d011682016040523d82523d6000602084013e6138e6565b606091505b505090508061146657604051631722e2bb60e21b81526001600160a01b038416600482015260248101839052604401610733565b600062ffffff8311156139405760405163163d8bab60e21b815260040160405180910390fd5b627fffff19830161395a81613954856145d2565b90614618565b949350505050565b600061396f848484614263565b90506001821b80613982576139826155a7565b8385091561398e576001015b9392505050565b60006139a2848484614216565b905081806139b2576139b26155a7565b6001841b85091561398e576001019392505050565b600082610120015162ffffff166127106139f485610140015162ffffff168561487190919063ffffffff16565b6139fe919061564d565b613a089190615456565b90508260e0015162ffffff168111613a205780613a26565b8260e001515b62ffffff16610100909301929092525050565b600080613a4584614888565b90506000613a5b82670de0b6b3a764000061546e565b905080600181613a6b858861564d565b613a759190615456565b613a7f919061546e565b6115a2919061566c565b801561146657604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663a9059cbb60e01b1790526000613af785836143de565b905060008151118015613b1b575080806020019051810190613b1991906155bd565b155b15613b395760405163197138bd60e11b815260040160405180910390fd5b5050505050565b60405163704037bd60e01b81526001600160a01b03848116600483015283811660248301526044820183905260009182917f0000000000000000000000000000000000000000000000000000000000000000169063704037bd90606401608060405180830381865afa158015613bba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bde919061568e565b6020015190506001600160a01b03811661395a57604051636b2471d160e11b81526001600160a01b0380871660048301528516602482015260448101849052606401610733565b600080876001600160a01b031663fba0ee64338a88886040518563ffffffff1660e01b8152600401613c5a9493929190615713565b600060405180830381600087803b158015613c7457600080fd5b505af1158015613c88573d6000803e3d6000fd5b5050604051630acd451d60e01b81526001600160a01b038b169250630acd451d9150613cbc90889088908890600401615751565b60408051808303816000875af1158015613cda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cfe919061541c565b909250905086821080613d1057508581105b15613d46576040516318ccfb7760e11b815260048101889052602481018390526044810187905260648101829052608401610733565b965096945050505050565b606080836101a0013580421115613d845760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b613d92610140860186615790565b9050613da2610120870187615790565b905014158015613dd05750613dbb610160860186615790565b9050613dcb610120870187615790565b905014155b15613dee5760405163b91b4d4d60e01b815260040160405180910390fd5b62ffffff60e08601351180613e0a575062ffffff610100860135115b15613e395760405163197a55c760e11b815260e086013560048201526101008601356024820152604401610733565b6000846001600160a01b0316631b05b83e6040518163ffffffff1660e01b8152600401606060405180830381865afa158015613e79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e9d91906152d7565b92505050808661010001358760e00135011080613ec457508560e001358661010001358201105b15613efa57604051637d50edab60e11b815260e08701356004820152610100870135602482015260448101829052606401610733565b613f08610120870187615790565b905067ffffffffffffffff811115613f2257613f22614c0b565b604051908082528060200260200182016040528015613f4b578160200160208202803683370190505b50935060005b8451811015613fde576000613f6a610120890189615790565b83818110613f7a57613f7a6154a2565b90506020020135830190506000811280613f96575062ffffff81115b15613fb7576040516370a82e6160e11b815260048101829052602401610733565b80868381518110613fca57613fca6154a2565b602090810291909101015250600101613f51565b506000806001600160a01b03871663714c8592876140006101408c018c615790565b61400e6101608e018e615790565b8e61018001602081019061402291906154ee565b6040518763ffffffff1660e01b8152600401614043969594939291906157da565b6000604051808303816000875af1158015614062573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261408a9190810190615832565b9650909250905060a08801358210806140a657508760c0013581105b156140e2576040516318ccfb7760e11b815260a089013560048201526024810183905260c0890135604482015260648101829052608401610733565b505050509250929050565b6000806140f9836145d2565b90506000614106826148b1565b61410f866148b1565b8161411c5761411c6155a7565b05628000000190506000811280614135575062ffffff81115b1561395a5760405163163d8bab60e21b815260040160405180910390fd5b8064ffffffffff8116811461417e576040516302dfd99760e01b815260048101839052602401610733565b919050565b60408051808201909152600080825260208201526141a0826149bc565b6001600160801b0316815260c08301516127109061ffff168302046001600160801b0316602082015292915050565b6000670de0b6b3a76400006001670de0b6b3a76400006141ee86614888565b6141f8908661564d565b6142029190615456565b61420c919061546e565b61201f919061566c565b600060ff83111561423d57604051630b72ecf560e41b815260048101849052602401610733565b83831b61010084900385901c614259866001871b8685856149e9565b9695505050505050565b600060ff82111561428a57604051630b72ecf560e41b815260048101839052602401610733565b6000806142978686614a9c565b91509150816000146142a95781841c92505b80156142e9576001841b81106142dc57604051633d90990f60e01b81526004810182905260248101859052604401610733565b836101000381901b830192505b50509392505050565b6000836143d35760405163e6a4390560e01b81526001600160a01b03848116600483015283811660248301527f0000000000000000000000000000000000000000000000000000000000000000169063e6a4390590604401602060405180830381865afa158015614367573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061438b91906154d1565b90506001600160a01b0381166143ce57604051636b2471d160e11b81526001600160a01b0380851660048301528316602482015260448101859052606401610733565b61398e565b61395a838386613b40565b6060600080846001600160a01b0316846040516143fb91906158d8565b6000604051808303816000865af19150503d8060008114614438576040519150601f19603f3d011682016040523d82523d6000602084013e61443d565b606091505b5091509150811561448257805115801561445f57506001600160a01b0385163b155b1561447d57604051635d97df8960e01b815260040160405180910390fd5b61395a565b80516144a157604051632407429160e01b815260040160405180910390fd5b805181602001fd5b6000836144c95760405163b229ed3360e01b815260040160405180910390fd5b8215806144d4575081155b156144f2576040516398c59a2960e01b815260040160405180910390fd5b6000614500856103e561564d565b9050600061450e848361564d565b905060008261451f876103e861564d565b6145299190615456565b9050614535818361566c565b979650505050505050565b6000836145605760405163b229ed3360e01b815260040160405180910390fd5b82158061456b575081155b15614589576040516398c59a2960e01b815260040160405180910390fd5b6000614595858561564d565b6145a1906103e861564d565b905060006145af868561546e565b6145bb906103e561564d565b90506145c7818361566c565b614259906001615456565b60008115806145e2575061271082115b15614603576040516374da1e1160e11b815260048101839052602401610733565b612710608083901b04600160801b0192915050565b60008080836146305750600160801b91506120229050565b50826000811215614642579015906000035b6210000081101561483257600160801b9250846001600160801b0381111561466c57911591600019045b600182161561467d5792830260801c925b800260801c60028216156146935792830260801c925b800260801c60048216156146a95792830260801c925b800260801c60088216156146bf5792830260801c925b800260801c60108216156146d55792830260801c925b800260801c60208216156146eb5792830260801c925b800260801c60408216156147015792830260801c925b8002608090811c908216156147185792830260801c925b800260801c61010082161561472f5792830260801c925b800260801c6102008216156147465792830260801c925b800260801c61040082161561475d5792830260801c925b800260801c6108008216156147745792830260801c925b800260801c61100082161561478b5792830260801c925b800260801c6120008216156147a25792830260801c925b800260801c6140008216156147b95792830260801c925b800260801c6180008216156147d05792830260801c925b800260801c620100008216156147e85792830260801c925b800260801c620200008216156148005792830260801c925b800260801c620400008216156148185792830260801c925b800260801c620800008216156148305792830260801c925b505b8261485a57604051630e9c7d6160e31b81526004810186905260248101859052604401610733565b8161486557826115a2565b6115a28360001961566c565b60008183116148825782820361201f565b50900390565b600061489382614abb565b8251602084015161ffff9182169116026402540be400020192915050565b600081600114156148c55750607f19919050565b816148e3576040516304c9fcb960e01b815260040160405180910390fd5b60019190911c9060006f80000000000000000000000000000000831061490b57506001614926565b5060001982600160fe1b81614922576149226155a7565b0492505b6000614935607f85901c614b0f565b707f80000000000000000000000000000000607f82901b16935060ff16905083811c6f8000000000000000000000000000000081146149b1576f400000000000000000000000000000005b60008113156149af57908002607f1c90600160801b82106149a7579384019360019190911c905b60011d614980565b505b50500260011b919050565b806001600160801b038116811461417e5760405163089f6cfb60e21b815260048101839052602401610733565b600081614a07578383816149ff576149ff6155a7565b0490506115a2565b838210614a315760405163656b542b60e11b81526004810183905260248101859052604401610733565b600084868809600186198101871660008190038190049091018683119095039490940294038390049390931760029290940460038102831880820284030280820284030280820284030280820284030280820284030290810290920390910292909202949350505050565b6000806000198385098385029250828110838203039150509250929050565b60008160a0015162ffffff1660001461417e576000826000015161ffff1683610100015162ffffff1602905060648360a0015162ffffff168283020260630181614b0757614b076155a7565b049392505050565b6000600160801b8210614b245750608090811c905b680100000000000000008210614b3c57604091821c91015b6401000000008210614b5057602091821c91015b620100008210614b6257601091821c91015b6101008210614b7357600891821c91015b60108210614b8357600491821c91015b60048210614b9357600291821c91015b6002821061417e57600101919050565b6001600160a01b0381168114614bb857600080fd5b50565b8015158114614bb857600080fd5b600080600060608486031215614bde57600080fd5b8335614be981614ba3565b9250602084013591506040840135614c0081614bbb565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b604051610180810167ffffffffffffffff81118282101715614c4557614c45614c0b565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715614c7457614c74614c0b565b604052919050565b600067ffffffffffffffff821115614c9657614c96614c0b565b5060051b60200190565b600082601f830112614cb157600080fd5b81356020614cc6614cc183614c7c565b614c4b565b82815260059290921b84018101918181019086841115614ce557600080fd5b8286015b84811015614d005780358352918301918301614ce9565b509695505050505050565b803561417e81614ba3565b600082601f830112614d2757600080fd5b81356020614d37614cc183614c7c565b82815260059290921b84018101918181019086841115614d5657600080fd5b8286015b84811015614d00578035614d6d81614ba3565b8352918301918301614d5a565b60008060008060008060c08789031215614d9357600080fd5b8635955060208701359450604087013567ffffffffffffffff80821115614db957600080fd5b614dc58a838b01614ca0565b95506060890135915080821115614ddb57600080fd5b50614de889828a01614d16565b9350506080870135614df981614ba3565b8092505060a087013590509295509295509295565b600080600080600060a08688031215614e2657600080fd5b85359450602086013567ffffffffffffffff80821115614e4557600080fd5b614e5189838a01614ca0565b95506040880135915080821115614e6757600080fd5b50614e7488828901614d16565b9350506060860135614e8581614ba3565b949793965091946080013592915050565b600081518084526020808501945080840160005b83811015614ec657815187529582019590820190600101614eaa565b509495945050505050565b60208152600061201f6020830184614e96565b600080600060608486031215614ef957600080fd5b8335614f0481614ba3565b92506020840135614f1481614ba3565b929592945050506040919091013590565b62ffffff81168114614bb857600080fd5b61ffff81168114614bb857600080fd5b803561417e81614f36565b60008060008060808587031215614f6757600080fd5b8435614f7281614ba3565b93506020850135614f8281614ba3565b92506040850135614f9281614f25565b91506060850135614fa281614f36565b939692955090935050565b600080600080600080600080610100898b031215614fca57600080fd5b8835614fd581614ba3565b97506020890135614fe581614f36565b96506040890135955060608901359450608089013567ffffffffffffffff8082111561501057600080fd5b61501c8c838d01614ca0565b955060a08b013591508082111561503257600080fd5b5061503f8b828c01614ca0565b93505060c089013561505081614ba3565b8092505060e089013590509295985092959890939650565b60008060008060008060008060006101208a8c03121561508757600080fd5b893561509281614ba3565b985060208a01356150a281614ba3565b97506150b060408b01614f46565b965060608a0135955060808a0135945060a08a013567ffffffffffffffff808211156150db57600080fd5b6150e78d838e01614ca0565b955060c08c01359150808211156150fd57600080fd5b5061510a8c828d01614ca0565b93505061511960e08b01614d0b565b91506101008a013590509295985092959850929598565b6000806040838503121561514357600080fd5b823561514e81614ba3565b9150602083013561515e81614f25565b809150509250929050565b60006020828403121561517b57600080fd5b813567ffffffffffffffff81111561519257600080fd5b82016101c0818503121561398e57600080fd5b6040815260006151b86040830185614e96565b82810360208401526115a28185614e96565b60008083601f8401126151dc57600080fd5b50813567ffffffffffffffff8111156151f457600080fd5b6020830191508360208260051b850101111561520f57600080fd5b9250929050565b6000806000806000806080878903121561522f57600080fd5b863561523a81614ba3565b9550602087013561524a81614ba3565b9450604087013567ffffffffffffffff8082111561526757600080fd5b6152738a838b016151ca565b9096509450606089013591508082111561528c57600080fd5b5061529989828a016151ca565b979a9699509497509295939492505050565b600080604083850312156152be57600080fd5b82356152c981614ba3565b946020939093013593505050565b6000806000606084860312156152ec57600080fd5b8351925060208401519150604084015190509250925092565b805161417e81614f36565b805161417e81614f25565b805164ffffffffff8116811461417e57600080fd5b6000610180828403121561534357600080fd5b61534b614c21565b61535483615305565b815261536260208401615305565b602082015261537360408401615305565b604082015261538460608401615305565b606082015261539560808401615305565b60808201526153a660a08401615310565b60a08201526153b760c08401615305565b60c08201526153c860e08401615310565b60e08201526101006153db818501615310565b908201526101206153ed848201615310565b908201526101406153ff848201615310565b9082015261016061541184820161531b565b908201529392505050565b6000806040838503121561542f57600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b6000821982111561546957615469615440565b500190565b60008282101561548057615480615440565b500390565b60006020828403121561549757600080fd5b815161398e81614f25565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156154ca57600080fd5b5051919050565b6000602082840312156154e357600080fd5b815161398e81614ba3565b60006020828403121561550057600080fd5b813561398e81614ba3565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561553d57600080fd5b8260051b8083602087013760009401602001938452509192915050565b60006001600160a01b0380891683528088166020840152506080604083015261558760808301868861550b565b828103606084015261559a81858761550b565b9998505050505050505050565b634e487b7160e01b600052601260045260246000fd5b6000602082840312156155cf57600080fd5b815161398e81614bbb565b80516001600160701b038116811461417e57600080fd5b60008060006060848603121561560657600080fd5b61560f846155da565b925061561d602085016155da565b9150604084015163ffffffff81168114614c0057600080fd5b60008161564557615645615440565b506000190190565b600081600019048311821515161561566757615667615440565b500290565b60008261568957634e487b7160e01b600052601260045260246000fd5b500490565b6000608082840312156156a057600080fd5b6040516080810181811067ffffffffffffffff821117156156c3576156c3614c0b565b60405282516156d181614f36565b815260208301516156e181614ba3565b602082015260408301516156f481614bbb565b6040820152606083015161570781614bbb565b60608201529392505050565b60006001600160a01b0380871683528086166020840152506080604083015261573f6080830185614e96565b82810360608401526145358185614e96565b6060815260006157646060830186614e96565b82810360208401526157768186614e96565b9150506001600160a01b0383166040830152949350505050565b6000808335601e198436030181126157a757600080fd5b83018035915067ffffffffffffffff8211156157c257600080fd5b6020019150600581901b360382131561520f57600080fd5b6080815260006157ed6080830189614e96565b828103602084015261580081888a61550b565b9050828103604084015261581581868861550b565b9150506001600160a01b0383166060830152979650505050505050565b60008060006060848603121561584757600080fd5b835192506020808501519250604085015167ffffffffffffffff81111561586d57600080fd5b8501601f8101871361587e57600080fd5b805161588c614cc182614c7c565b81815260059190911b820183019083810190898311156158ab57600080fd5b928401925b828410156158c9578351825292840192908401906158b0565b80955050505050509250925092565b6000825160005b818110156158f957602081860181015185830152016158df565b81811115615908576000828501525b50919091019291505056fea26469706673582212206c05eee95a8862d596ac1d3ea3c231cfdc4a1453951fddb1394e8ead624c932964736f6c634300080a00330000000000000000000000006e77932a92582f504ff6c4bdbcef7da6c198aeef0000000000000000000000009ad6c38be94206ca50bb0d90783181662f0cfa10000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c7
Deployed Bytecode
0x6080604052600436106101845760003560e01c80636d3420ed116100d6578063d0e380f21161007f578063ea8f43d811610059578063ea8f43d8146104c9578063f96fe925146104dc578063fb321c701461051057600080fd5b8063d0e380f21461045b578063e324a3e41461047b578063e9361c08146104a957600080fd5b8063bcb1c957116100b0578063bcb1c957146103e7578063c22159b614610407578063c45a01551461042757600080fd5b80636d3420ed146103875780639a17e820146103a7578063a7b856d3146103c757600080fd5b806342f564a01161013857806362c067671161011257806362c0676714610327578063659ac74b146103475780636d0ff4951461036757600080fd5b806342f564a0146102d4578063440830bd146102f45780635bdd4b7c1461030757600080fd5b80632004b724116101695780632004b7241461025e578063212a1d9414610293578063264bb94e146102c157600080fd5b8063117be4c2146101d95780631bd6dfe11461022a57600080fd5b366101d457336001600160a01b037f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c716146101d2576040516310d0bef760e31b815260040160405180910390fd5b005b600080fd5b3480156101e557600080fd5b5061020d7f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c781565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561023657600080fd5b5061020d7f0000000000000000000000009ad6c38be94206ca50bb0d90783181662f0cfa1081565b34801561026a57600080fd5b5061027e610279366004614bc9565b610530565b60408051928352602083019190915201610221565b34801561029f57600080fd5b506102b36102ae366004614d7a565b610839565b604051908152602001610221565b6102b36102cf366004614e0e565b610a57565b6102e76102e2366004614e0e565b610bd1565b6040516102219190614ed1565b6102b3610302366004614e0e565b610df8565b34801561031357600080fd5b5061027e610322366004614bc9565b61103d565b34801561033357600080fd5b506101d2610342366004614ee4565b61138e565b34801561035357600080fd5b5061020d610362366004614f51565b6114f4565b34801561037357600080fd5b506102b3610382366004614d7a565b6115ab565b34801561039357600080fd5b506102e76103a2366004614d7a565b61169e565b3480156103b357600080fd5b506102b36103c2366004614d7a565b6118dc565b3480156103d357600080fd5b506102e76103e2366004614d7a565b611bcc565b3480156103f357600080fd5b5061027e610402366004614fad565b611cdb565b34801561041357600080fd5b5061027e610422366004615068565b611eb3565b34801561043357600080fd5b5061020d7f0000000000000000000000006e77932a92582f504ff6c4bdbcef7da6c198aeef81565b34801561046757600080fd5b506102b3610476366004615130565b611fa7565b34801561048757600080fd5b5061049b610496366004615169565b612028565b6040516102219291906151a5565b3480156104b557600080fd5b506101d26104c4366004615216565b61214f565b61049b6104d7366004615169565b612272565b3480156104e857600080fd5b506104fc6104f73660046152ab565b612482565b60405162ffffff9091168152602001610221565b34801561051c57600080fd5b506102b361052b366004614d7a565b6124f5565b6000806000856001600160a01b0316631b05b83e6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610573573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061059791906152d7565b925050506000866001600160a01b03166398c7adf36040518163ffffffff1660e01b815260040161018060405180830381865afa1580156105dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106009190615330565b905061060c81836126a8565b6040805160808101825260008082526020820181905291810182905260608101919091525b604051630157d2d160e31b815262ffffff8416600482015260009081906001600160a01b038b1690630abe9688906024016040805180830381865afa15801561067e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a2919061541c565b604080516080810182526001600160701b03938416808252939092166020830152600090820181905260608201529350151591508190506106ef575060208101516001600160701b031615155b1561078557600080806107058486888c8e612765565b919450925090506001600160701b0383111561073c57604051633d9af4e160e11b8152600481018790526024015b60405180910390fd5b8051610751906001600160801b031684615456565b61075b908b61546e565b8151909a50610773906001600160801b031688615456565b965061077f8289615456565b97505050505b861561080c57604051638f919a8360e01b815262ffffff8416600482015286151560248201526001600160a01b03891690638f919a8390604401602060405180830381865afa1580156107dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108009190615485565b62ffffff169250610631565b861561082e576040516349cda5cd60e11b815260048101889052602401610733565b505050935093915050565b600081804211156108665760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480610885575080518251610882906001615456565b14155b156108a35760405163b91b4d4d60e01b815260040160405180910390fd5b60006108af8989612889565b90506000888251815181106108c6576108c66154a2565b60209081029190910101516040516370a0823160e01b81526001600160a01b038a811660048301529192506000918316906370a0823190602401602060405180830381865afa15801561091d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061094191906154b8565b9050610997338460008151811061095a5761095a6154a2565b60200260200101518f8d600081518110610976576109766154a2565b60200260200101516001600160a01b031661297e909392919063ffffffff16565b6109a3838c8c8c612a3f565b6040516370a0823160e01b81526001600160a01b038a811660048301528291908416906370a0823190602401602060405180830381865afa1580156109ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1091906154b8565b610a1a919061546e565b9650868c1115610a47576040516313fab00360e21b8152600481018d905260248101889052604401610733565b5050505050509695505050505050565b60008180421115610a845760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480610aa3575080518251610aa0906001615456565b14155b15610ac15760405163b91b4d4d60e01b815260040160405180910390fd5b7f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031687600081518110610afe57610afe6154a2565b60200260200101516001600160a01b031614610b585786600081518110610b2757610b276154a2565b602002602001015160405163cfec0e0160e01b815260040161073391906001600160a01b0391909116815260200190565b6000610b648989612889565b9050610b8a81600081518110610b7c57610b7c6154a2565b602002602001015134612eaa565b610b9734828b8b8b612f59565b9450848a1115610bc4576040516313fab00360e21b8152600481018b905260248101869052604401610733565b5050505095945050505050565b60608180421115610bfe5760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480610c1d575080518251610c1a906001615456565b14155b15610c3b5760405163b91b4d4d60e01b815260040160405180910390fd5b7f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031687600081518110610c7857610c786154a2565b60200260200101516001600160a01b031614610ca15786600081518110610b2757610b276154a2565b6000610cad8989612889565b9050610cbb89828a8d6132da565b94503485600081518110610cd157610cd16154a2565b60200260200101511115610d1f573485600081518110610cf357610cf36154a2565b602002602001015160405163194ee21960e31b8152600401610733929190918252602082015260400190565b610d5d81600081518110610d3557610d356154a2565b602002602001015186600081518110610d5057610d506154a2565b6020026020010151612eaa565b6000610d6c828b8b898c6135c5565b90508a811015610d99576040516313fab00360e21b8152600481018c905260248101829052604401610733565b85600081518110610dac57610dac6154a2565b6020026020010151341115610dea57610dea3387600081518110610dd257610dd26154a2565b602002602001015134610de5919061546e565b613894565b505050505095945050505050565b60008180421115610e255760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480610e44575080518251610e41906001615456565b14155b15610e625760405163b91b4d4d60e01b815260040160405180910390fd5b7f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031687600081518110610e9f57610e9f6154a2565b60200260200101516001600160a01b031614610ec85786600081518110610b2757610b276154a2565b6000610ed48989612889565b9050600088825181518110610eeb57610eeb6154a2565b60209081029190910101516040516370a0823160e01b81526001600160a01b038a811660048301529192506000918316906370a0823190602401602060405180830381865afa158015610f42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6691906154b8565b9050610f7e83600081518110610b7c57610b7c6154a2565b610f8a838c8c8c612a3f565b6040516370a0823160e01b81526001600160a01b038a811660048301528291908416906370a0823190602401602060405180830381865afa158015610fd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff791906154b8565b611001919061546e565b9650868c111561102e576040516313fab00360e21b8152600481018d905260248101889052604401610733565b50505050505095945050505050565b6000806000806000876001600160a01b0316631b05b83e6040518163ffffffff1660e01b8152600401606060405180830381865afa158015611083573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110a791906152d7565b92509250925086600014806110c85750856110c4578287116110c8565b8187115b156110fd5786866110d957836110db565b825b604051637c40a4df60e01b815260048101929092526024820152604401610733565b6000886001600160a01b03166398c7adf36040518163ffffffff1660e01b815260040161018060405180830381865afa15801561113e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111629190615330565b905061116e81836126a8565b60008060005b604051630157d2d160e31b815262ffffff8616600482015260009081906001600160a01b038f1690630abe9688906024016040805180830381865afa1580156111c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e5919061541c565b915091508b6111f457816111f6565b805b92505050600061120e86866000015161ffff1661391a565b905081156112cd57818c1015611224578b611226565b815b935060008b6112405761123b82866080613962565b61124c565b61124c85608084613995565b905061125886886139c7565b60006112648783613a39565b90506112708183615456565b94506001600160701b036112848587615456565b11156112a65760405163ec44eb8960e01b815260048101899052602401610733565b6112b0858d615456565b9b506112bc818c615456565b9a506112c8868f61546e565b9d5050505b8b1561135457604051638f919a8360e01b815262ffffff871660048201528b151560248201526001600160a01b038e1690638f919a8390604401602060405180830381865afa158015611324573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113489190615485565b62ffffff16955061135a565b50611360565b50611174565b8a1561137f576040516330b1335760e21b815260040160405180910390fd5b50505050505050935093915050565b7f0000000000000000000000006e77932a92582f504ff6c4bdbcef7da6c198aeef6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141091906154d1565b6001600160a01b0316336001600160a01b03161461144157604051635d9515b960e11b815260040160405180910390fd5b6001600160a01b03831661146b5760001981141561145c5750475b6114668282613894565b505050565b6000198114156114e0576040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156114b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114dd91906154b8565b90505b6114666001600160a01b0384168383613a89565b60405163659ac74b60e01b81526001600160a01b038581166004830152848116602483015262ffffff8416604483015261ffff831660648301526000917f0000000000000000000000006e77932a92582f504ff6c4bdbcef7da6c198aeef9091169063659ac74b906084016020604051808303816000875af115801561157e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a291906154d1565b95945050505050565b600081804211156115d85760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b85858151600014806115f75750805182516115f4906001615456565b14155b156116155760405163b91b4d4d60e01b815260040160405180910390fd5b60006116218989612889565b9050611656338260008151811061163a5761163a6154a2565b60200260200101518d8b600081518110610976576109766154a2565b6116638b828b8b8b612f59565b9450848a1115611690576040516313fab00360e21b8152600481018b905260248101869052604401610733565b505050509695505050505050565b606081804211156116cb5760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b85858151600014806116ea5750805182516116e7906001615456565b14155b156117085760405163b91b4d4d60e01b815260040160405180910390fd5b7f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031687895181518110611745576117456154a2565b60200260200101516001600160a01b03161461176e5786885181518110610b2757610b276154a2565b600061177a8989612889565b905061178889828a8e6132da565b9450898560008151811061179e5761179e6154a2565b602002602001015111156117c0578985600081518110610cf357610cf36154a2565b61180d33826000815181106117d7576117d76154a2565b6020026020010151876000815181106117f2576117f26154a2565b60200260200101518b600081518110610976576109766154a2565b600061181c828b8b89306135c5565b90508b811015611849576040516313fab00360e21b8152600481018d905260248101829052604401610733565b604051632e1a7d4d60e01b8152600481018290527f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156118ab57600080fd5b505af11580156118bf573d6000803e3d6000fd5b505050506118cd8882613894565b50505050509695505050505050565b600081804211156119095760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480611928575080518251611925906001615456565b14155b156119465760405163b91b4d4d60e01b815260040160405180910390fd5b7f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031687895181518110611983576119836154a2565b60200260200101516001600160a01b0316146119ac5786885181518110610b2757610b276154a2565b60006119b88989612889565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c716906370a0823190602401602060405180830381865afa158015611a22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4691906154b8565b9050611a7b3383600081518110611a5f57611a5f6154a2565b60200260200101518e8c600081518110610976576109766154a2565b611a87828b8b30612a3f565b6040516370a0823160e01b815230600482015281907f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b0316906370a0823190602401602060405180830381865afa158015611aed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b1191906154b8565b611b1b919061546e565b9550858b1115611b48576040516313fab00360e21b8152600481018c905260248101879052604401610733565b604051632e1a7d4d60e01b8152600481018790527f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015611baa57600080fd5b505af1158015611bbe573d6000803e3d6000fd5b505050506118cd8887613894565b60608180421115611bf95760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b8585815160001480611c18575080518251611c15906001615456565b14155b15611c365760405163b91b4d4d60e01b815260040160405180910390fd5b6000611c428989612889565b9050611c5089828a8e6132da565b94508985600081518110611c6657611c666154a2565b60200260200101511115611c88578985600081518110610cf357610cf36154a2565b611c9f33826000815181106117d7576117d76154a2565b6000611cae828b8b898c6135c5565b90508b8110156118cd576040516313fab00360e21b8152600481018d905260248101829052604401610733565b6000808280421115611d095760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b6000611d3a8c7f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c78d61ffff16613b40565b90506000816001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da091906154d1565b6001600160a01b03167f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031614905080611ddf579899985b600080611df0848e8e8e8e30613c25565b9150915082611e00578082611e03565b81815b9097509550611e1f9150506001600160a01b038e168887613a89565b604051632e1a7d4d60e01b8152600481018590527f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015611e8157600080fd5b505af1158015611e95573d6000803e3d6000fd5b50505050611ea38785613894565b5050509850989650505050505050565b6000808280421115611ee15760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b6000611ef28d8d8d61ffff16613b40565b90506000816001600160a01b03166316dc165b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5891906154d1565b6001600160a01b03168e6001600160a01b0316141590508015611f79579899985b611f87828c8c8c8c8c613c25565b90955093508015611f96579293925b505050995099975050505050505050565b600061201f8262ffffff16846001600160a01b03166398c7adf36040518163ffffffff1660e01b815260040161018060405180830381865afa158015611ff1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120159190615330565b5161ffff1661391a565b90505b92915050565b606080600061205761203d60208601866154ee565b61204d60408701602088016154ee565b8660400135613b40565b9050806001600160a01b03166316dc165b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120bb91906154d1565b6001600160a01b03166120d160208601866154ee565b6001600160a01b0316146120f85760405163b33f8ab960e01b815260040160405180910390fd5b6121203382606087013561210f60208901896154ee565b6001600160a01b031692919061297e565b61213a3382608087013561210f6040890160208a016154ee565b6121448482613d51565b909590945092505050565b7f0000000000000000000000006e77932a92582f504ff6c4bdbcef7da6c198aeef6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d191906154d1565b6001600160a01b0316336001600160a01b03161461220257604051635d9515b960e11b815260040160405180910390fd5b604051633ee83b9960e21b81526001600160a01b0387169063fba0ee64906122389030908990899089908990899060040161555a565b600060405180830381600087803b15801561225257600080fd5b505af1158015612266573d6000803e3d6000fd5b50505050505050505050565b606080600061228761203d60208601866154ee565b9050806001600160a01b03166316dc165b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122eb91906154d1565b6001600160a01b031661230160208601866154ee565b6001600160a01b0316146123285760405163b33f8ab960e01b815260040160405180910390fd5b6001600160a01b037f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c71661235f60208601866154ee565b6001600160a01b03161480156123785750348460600135145b156123a6576123878134612eaa565b6123a13382608087013561210f6040890160208a016154ee565b61213a565b6001600160a01b037f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c7166123e060408601602087016154ee565b6001600160a01b03161480156123f95750348460800135145b1561241f576124153382606087013561210f60208901896154ee565b6123a18134612eaa565b61242c60208501856154ee565b61243c60408601602087016154ee565b60405163959ceb2b60e01b81526001600160a01b03928316600482015291166024820152606085013560448201526080850135606482015234608482015260a401610733565b600061201f82846001600160a01b03166398c7adf36040518163ffffffff1660e01b815260040161018060405180830381865afa1580156124c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124eb9190615330565b5161ffff166140ed565b600081804211156125225760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b858581516000148061254157508051825161253e906001615456565b14155b1561255f5760405163b91b4d4d60e01b815260040160405180910390fd5b7f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b03168789518151811061259c5761259c6154a2565b60200260200101516001600160a01b0316146125c55786885181518110610b2757610b276154a2565b60006125d18989612889565b90506125ea338260008151811061163a5761163a6154a2565b6125f78b828b8b30612f59565b9450848a1115612624576040516313fab00360e21b8152600481018b905260248101869052604401610733565b604051632e1a7d4d60e01b8152600481018690527f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561268657600080fd5b505af115801561269a573d6000803e3d6000fd5b505050506116908786613894565b600082610160015164ffffffffff16426126c2919061546e565b9050826040015161ffff16811015806126e5575061016083015164ffffffffff16155b156127455762ffffff8216610140840152606083015161ffff1681101561273c5761271083610100015162ffffff16846080015161ffff16028161272b5761272b6155a7565b0462ffffff16610120840152612745565b60006101208401525b61274e42614153565b64ffffffffff1661016084015261146683836139c7565b60408051808201909152600080825260208201819052908190600061279287896000015161ffff1661391a565b905060008087156127c05760208b01516001600160701b031691506127b982608085613995565b90506127dc565b8a516001600160701b031691506127d983836080613962565b90505b6127e68a8a6139c7565b6127fa6127f38b83613a39565b8b90614183565b80519094508790612814906001600160801b031683615456565b116128245780955081945061287b565b6128316127f38b896141cf565b8051909450612849906001600160801b03168861546e565b9550876128615761285c86608085614216565b61286d565b61286d83876080614263565b94508185111561287b578194505b505050955095509592505050565b6060825167ffffffffffffffff8111156128a5576128a5614c0b565b6040519080825280602002602001820160405280156128ce578160200160208202803683370190505b509050600080836000815181106128e7576128e76154a2565b6020026020010151905060005b835181101561297557819250848160010181518110612915576129156154a2565b60200260200101519150612943868281518110612934576129346154a2565b602002602001015184846142f2565b848281518110612955576129556154a2565b6001600160a01b03909216602092830291909101909101526001016128f4565b50505092915050565b8015612a3957604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166323b872dd60e01b17905260006129f486836143de565b905060008151118015612a18575080806020019051810190612a1691906155bd565b155b15612a365760405163197138bd60e11b815260040160405180910390fd5b50505b50505050565b600080600080600086600081518110612a5a57612a5a6154a2565b6020026020010151905060005b895181101561226657898181518110612a8257612a826154a2565b60200260200101519250888181518110612a9e57612a9e6154a2565b60200260200101519450819550878160010181518110612ac057612ac06154a2565b6020026020010151915089518160010114612af757898160010181518110612aea57612aea6154a2565b6020026020010151612af9565b865b935084612da157600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015612b41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6591906155f1565b506001600160701b031691506001600160701b03169150836001600160a01b0316886001600160a01b03161015612c9a576040516370a0823160e01b81526001600160a01b03868116600483015260009184918b16906370a0823190602401602060405180830381865afa158015612be1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c0591906154b8565b0390506000612c158285856144a9565b60405163022c0d9f60e01b8152600060048201819052602482018390526001600160a01b038b811660448401526080606484015260848301919091529192509088169063022c0d9f9060a401600060405180830381600087803b158015612c7b57600080fd5b505af1158015612c8f573d6000803e3d6000fd5b505050505050612d9a565b6040516370a0823160e01b81526001600160a01b03868116600483015260009183918b16906370a0823190602401602060405180830381865afa158015612ce5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d0991906154b8565b0390506000612d198284866144a9565b60405163022c0d9f60e01b8152600481018290526000602482018190526001600160a01b038b811660448401526080606484015260848301919091529192509088169063022c0d9f9060a401600060405180830381600087803b158015612d7f57600080fd5b505af1158015612d93573d6000803e3d6000fd5b5050505050505b5050612ea2565b826001600160a01b03166353c059a0846001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015612dee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e1291906154d1565b60405160e083901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b03918216868316146004820152908716602482015260440160408051808303816000875af1158015612e7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e9f919061541c565b50505b600101612a67565b7f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f0557600080fd5b505af1158015612f19573d6000803e3d6000fd5b50612f559350506001600160a01b037f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c716915084905083613a89565b5050565b60008060008060008087600081518110612f7557612f756154a2565b602002602001015190508a955060005b8a5181101561102e578a8181518110612fa057612fa06154a2565b60200260200101519250898181518110612fbc57612fbc6154a2565b60200260200101519450819550888160010181518110612fde57612fde6154a2565b602002602001015191508a518160010114613015578a8160010181518110613008576130086154a2565b6020026020010151613017565b875b9350846131d357600080846001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa15801561305f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061308391906155f1565b506001600160701b031691506001600160701b03169150836001600160a01b0316886001600160a01b03161015613142576130bf8983836144a9565b60405163022c0d9f60e01b8152600060048201819052602482018390526001600160a01b038981166044840152608060648401526084830191909152919a509086169063022c0d9f9060a401600060405180830381600087803b15801561312557600080fd5b505af1158015613139573d6000803e3d6000fd5b505050506131cc565b61314d8982846144a9565b60405163022c0d9f60e01b8152600481018290526000602482018190526001600160a01b038981166044840152608060648401526084830191909152919a509086169063022c0d9f9060a401600060405180830381600087803b1580156131b357600080fd5b505af11580156131c7573d6000803e3d6000fd5b505050505b50506132d2565b6000836001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa158015613213573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061323791906154d1565b60405163029e02cd60e51b81526001600160a01b039182168583161460048201819052878316602483015292506000918291908716906353c059a09060440160408051808303816000875af1158015613294573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132b8919061541c565b9150915082156132ca578099506132ce565b8199505b5050505b600101612f85565b6060825167ffffffffffffffff8111156132f6576132f6614c0b565b60405190808252806020026020018201604052801561331f578160200160208202803683370190505b5090508181855181518110613336576133366154a2565b602090810291909101015283515b80156135bc5760008461335860018461546e565b81518110613368576133686154a2565b60200260200101519050600087600184613382919061546e565b81518110613392576133926154a2565b602002602001015190506000876001856133ac919061546e565b815181106133bc576133bc6154a2565b6020026020010151905081600014156134e357600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015613410573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061343491906155f1565b506001600160701b031691506001600160701b0316915088868151811061345d5761345d6154a2565b60200260200101516001600160a01b0316856001600160a01b0316111561348057905b6000878781518110613494576134946154a2565b602002602001015190506134b38383836145409092919063ffffffff16565b886134bf60018a61546e565b815181106134cf576134cf6154a2565b6020026020010181815250505050506135a6565b61357c818686815181106134f9576134f96154a2565b6020026020010151856001600160a01b0316846001600160a01b03166316dc165b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613549573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061356d91906154d1565b6001600160a01b03161461103d565b508561358960018761546e565b81518110613599576135996154a2565b6020026020010181815250505b50505080806135b490615636565b915050613344565b50949350505050565b600080600080600080886000815181106135e1576135e16154a2565b6020026020010151905060005b8b5181101561102e578b8181518110613609576136096154a2565b602002602001015192508a8181518110613625576136256154a2565b60200260200101519450819550898160010181518110613647576136476154a2565b602002602001015191508b51816001011461367e578b8160010181518110613671576136716154a2565b6020026020010151613680565b875b93508461378d5788816001018151811061369c5761369c6154a2565b60200260200101519650816001600160a01b0316866001600160a01b031610156137405760405163022c0d9f60e01b8152600060048201819052602482018990526001600160a01b03868116604484015260806064840152608483019190915284169063022c0d9f9060a4015b600060405180830381600087803b15801561372357600080fd5b505af1158015613737573d6000803e3d6000fd5b5050505061388c565b60405163022c0d9f60e01b8152600481018890526000602482018190526001600160a01b03868116604484015260806064840152608483019190915284169063022c0d9f9060a401613709565b6000836001600160a01b031663b7d19fc46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156137cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137f191906154d1565b60405163029e02cd60e51b81526001600160a01b039182168583161460048201819052878316602483015292506000918291908716906353c059a09060440160408051808303816000875af115801561384e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613872919061541c565b91509150821561388457809950613888565b8199505b5050505b6001016135ee565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146138e1576040519150601f19603f3d011682016040523d82523d6000602084013e6138e6565b606091505b505090508061146657604051631722e2bb60e21b81526001600160a01b038416600482015260248101839052604401610733565b600062ffffff8311156139405760405163163d8bab60e21b815260040160405180910390fd5b627fffff19830161395a81613954856145d2565b90614618565b949350505050565b600061396f848484614263565b90506001821b80613982576139826155a7565b8385091561398e576001015b9392505050565b60006139a2848484614216565b905081806139b2576139b26155a7565b6001841b85091561398e576001019392505050565b600082610120015162ffffff166127106139f485610140015162ffffff168561487190919063ffffffff16565b6139fe919061564d565b613a089190615456565b90508260e0015162ffffff168111613a205780613a26565b8260e001515b62ffffff16610100909301929092525050565b600080613a4584614888565b90506000613a5b82670de0b6b3a764000061546e565b905080600181613a6b858861564d565b613a759190615456565b613a7f919061546e565b6115a2919061566c565b801561146657604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663a9059cbb60e01b1790526000613af785836143de565b905060008151118015613b1b575080806020019051810190613b1991906155bd565b155b15613b395760405163197138bd60e11b815260040160405180910390fd5b5050505050565b60405163704037bd60e01b81526001600160a01b03848116600483015283811660248301526044820183905260009182917f0000000000000000000000006e77932a92582f504ff6c4bdbcef7da6c198aeef169063704037bd90606401608060405180830381865afa158015613bba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bde919061568e565b6020015190506001600160a01b03811661395a57604051636b2471d160e11b81526001600160a01b0380871660048301528516602482015260448101849052606401610733565b600080876001600160a01b031663fba0ee64338a88886040518563ffffffff1660e01b8152600401613c5a9493929190615713565b600060405180830381600087803b158015613c7457600080fd5b505af1158015613c88573d6000803e3d6000fd5b5050604051630acd451d60e01b81526001600160a01b038b169250630acd451d9150613cbc90889088908890600401615751565b60408051808303816000875af1158015613cda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cfe919061541c565b909250905086821080613d1057508581105b15613d46576040516318ccfb7760e11b815260048101889052602481018390526044810187905260648101829052608401610733565b965096945050505050565b606080836101a0013580421115613d845760405163dae7ca7d60e01b815260048101829052426024820152604401610733565b613d92610140860186615790565b9050613da2610120870187615790565b905014158015613dd05750613dbb610160860186615790565b9050613dcb610120870187615790565b905014155b15613dee5760405163b91b4d4d60e01b815260040160405180910390fd5b62ffffff60e08601351180613e0a575062ffffff610100860135115b15613e395760405163197a55c760e11b815260e086013560048201526101008601356024820152604401610733565b6000846001600160a01b0316631b05b83e6040518163ffffffff1660e01b8152600401606060405180830381865afa158015613e79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e9d91906152d7565b92505050808661010001358760e00135011080613ec457508560e001358661010001358201105b15613efa57604051637d50edab60e11b815260e08701356004820152610100870135602482015260448101829052606401610733565b613f08610120870187615790565b905067ffffffffffffffff811115613f2257613f22614c0b565b604051908082528060200260200182016040528015613f4b578160200160208202803683370190505b50935060005b8451811015613fde576000613f6a610120890189615790565b83818110613f7a57613f7a6154a2565b90506020020135830190506000811280613f96575062ffffff81115b15613fb7576040516370a82e6160e11b815260048101829052602401610733565b80868381518110613fca57613fca6154a2565b602090810291909101015250600101613f51565b506000806001600160a01b03871663714c8592876140006101408c018c615790565b61400e6101608e018e615790565b8e61018001602081019061402291906154ee565b6040518763ffffffff1660e01b8152600401614043969594939291906157da565b6000604051808303816000875af1158015614062573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261408a9190810190615832565b9650909250905060a08801358210806140a657508760c0013581105b156140e2576040516318ccfb7760e11b815260a089013560048201526024810183905260c0890135604482015260648101829052608401610733565b505050509250929050565b6000806140f9836145d2565b90506000614106826148b1565b61410f866148b1565b8161411c5761411c6155a7565b05628000000190506000811280614135575062ffffff81115b1561395a5760405163163d8bab60e21b815260040160405180910390fd5b8064ffffffffff8116811461417e576040516302dfd99760e01b815260048101839052602401610733565b919050565b60408051808201909152600080825260208201526141a0826149bc565b6001600160801b0316815260c08301516127109061ffff168302046001600160801b0316602082015292915050565b6000670de0b6b3a76400006001670de0b6b3a76400006141ee86614888565b6141f8908661564d565b6142029190615456565b61420c919061546e565b61201f919061566c565b600060ff83111561423d57604051630b72ecf560e41b815260048101849052602401610733565b83831b61010084900385901c614259866001871b8685856149e9565b9695505050505050565b600060ff82111561428a57604051630b72ecf560e41b815260048101839052602401610733565b6000806142978686614a9c565b91509150816000146142a95781841c92505b80156142e9576001841b81106142dc57604051633d90990f60e01b81526004810182905260248101859052604401610733565b836101000381901b830192505b50509392505050565b6000836143d35760405163e6a4390560e01b81526001600160a01b03848116600483015283811660248301527f0000000000000000000000009ad6c38be94206ca50bb0d90783181662f0cfa10169063e6a4390590604401602060405180830381865afa158015614367573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061438b91906154d1565b90506001600160a01b0381166143ce57604051636b2471d160e11b81526001600160a01b0380851660048301528316602482015260448101859052606401610733565b61398e565b61395a838386613b40565b6060600080846001600160a01b0316846040516143fb91906158d8565b6000604051808303816000865af19150503d8060008114614438576040519150601f19603f3d011682016040523d82523d6000602084013e61443d565b606091505b5091509150811561448257805115801561445f57506001600160a01b0385163b155b1561447d57604051635d97df8960e01b815260040160405180910390fd5b61395a565b80516144a157604051632407429160e01b815260040160405180910390fd5b805181602001fd5b6000836144c95760405163b229ed3360e01b815260040160405180910390fd5b8215806144d4575081155b156144f2576040516398c59a2960e01b815260040160405180910390fd5b6000614500856103e561564d565b9050600061450e848361564d565b905060008261451f876103e861564d565b6145299190615456565b9050614535818361566c565b979650505050505050565b6000836145605760405163b229ed3360e01b815260040160405180910390fd5b82158061456b575081155b15614589576040516398c59a2960e01b815260040160405180910390fd5b6000614595858561564d565b6145a1906103e861564d565b905060006145af868561546e565b6145bb906103e561564d565b90506145c7818361566c565b614259906001615456565b60008115806145e2575061271082115b15614603576040516374da1e1160e11b815260048101839052602401610733565b612710608083901b04600160801b0192915050565b60008080836146305750600160801b91506120229050565b50826000811215614642579015906000035b6210000081101561483257600160801b9250846001600160801b0381111561466c57911591600019045b600182161561467d5792830260801c925b800260801c60028216156146935792830260801c925b800260801c60048216156146a95792830260801c925b800260801c60088216156146bf5792830260801c925b800260801c60108216156146d55792830260801c925b800260801c60208216156146eb5792830260801c925b800260801c60408216156147015792830260801c925b8002608090811c908216156147185792830260801c925b800260801c61010082161561472f5792830260801c925b800260801c6102008216156147465792830260801c925b800260801c61040082161561475d5792830260801c925b800260801c6108008216156147745792830260801c925b800260801c61100082161561478b5792830260801c925b800260801c6120008216156147a25792830260801c925b800260801c6140008216156147b95792830260801c925b800260801c6180008216156147d05792830260801c925b800260801c620100008216156147e85792830260801c925b800260801c620200008216156148005792830260801c925b800260801c620400008216156148185792830260801c925b800260801c620800008216156148305792830260801c925b505b8261485a57604051630e9c7d6160e31b81526004810186905260248101859052604401610733565b8161486557826115a2565b6115a28360001961566c565b60008183116148825782820361201f565b50900390565b600061489382614abb565b8251602084015161ffff9182169116026402540be400020192915050565b600081600114156148c55750607f19919050565b816148e3576040516304c9fcb960e01b815260040160405180910390fd5b60019190911c9060006f80000000000000000000000000000000831061490b57506001614926565b5060001982600160fe1b81614922576149226155a7565b0492505b6000614935607f85901c614b0f565b707f80000000000000000000000000000000607f82901b16935060ff16905083811c6f8000000000000000000000000000000081146149b1576f400000000000000000000000000000005b60008113156149af57908002607f1c90600160801b82106149a7579384019360019190911c905b60011d614980565b505b50500260011b919050565b806001600160801b038116811461417e5760405163089f6cfb60e21b815260048101839052602401610733565b600081614a07578383816149ff576149ff6155a7565b0490506115a2565b838210614a315760405163656b542b60e11b81526004810183905260248101859052604401610733565b600084868809600186198101871660008190038190049091018683119095039490940294038390049390931760029290940460038102831880820284030280820284030280820284030280820284030280820284030290810290920390910292909202949350505050565b6000806000198385098385029250828110838203039150509250929050565b60008160a0015162ffffff1660001461417e576000826000015161ffff1683610100015162ffffff1602905060648360a0015162ffffff168283020260630181614b0757614b076155a7565b049392505050565b6000600160801b8210614b245750608090811c905b680100000000000000008210614b3c57604091821c91015b6401000000008210614b5057602091821c91015b620100008210614b6257601091821c91015b6101008210614b7357600891821c91015b60108210614b8357600491821c91015b60048210614b9357600291821c91015b6002821061417e57600101919050565b6001600160a01b0381168114614bb857600080fd5b50565b8015158114614bb857600080fd5b600080600060608486031215614bde57600080fd5b8335614be981614ba3565b9250602084013591506040840135614c0081614bbb565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b604051610180810167ffffffffffffffff81118282101715614c4557614c45614c0b565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715614c7457614c74614c0b565b604052919050565b600067ffffffffffffffff821115614c9657614c96614c0b565b5060051b60200190565b600082601f830112614cb157600080fd5b81356020614cc6614cc183614c7c565b614c4b565b82815260059290921b84018101918181019086841115614ce557600080fd5b8286015b84811015614d005780358352918301918301614ce9565b509695505050505050565b803561417e81614ba3565b600082601f830112614d2757600080fd5b81356020614d37614cc183614c7c565b82815260059290921b84018101918181019086841115614d5657600080fd5b8286015b84811015614d00578035614d6d81614ba3565b8352918301918301614d5a565b60008060008060008060c08789031215614d9357600080fd5b8635955060208701359450604087013567ffffffffffffffff80821115614db957600080fd5b614dc58a838b01614ca0565b95506060890135915080821115614ddb57600080fd5b50614de889828a01614d16565b9350506080870135614df981614ba3565b8092505060a087013590509295509295509295565b600080600080600060a08688031215614e2657600080fd5b85359450602086013567ffffffffffffffff80821115614e4557600080fd5b614e5189838a01614ca0565b95506040880135915080821115614e6757600080fd5b50614e7488828901614d16565b9350506060860135614e8581614ba3565b949793965091946080013592915050565b600081518084526020808501945080840160005b83811015614ec657815187529582019590820190600101614eaa565b509495945050505050565b60208152600061201f6020830184614e96565b600080600060608486031215614ef957600080fd5b8335614f0481614ba3565b92506020840135614f1481614ba3565b929592945050506040919091013590565b62ffffff81168114614bb857600080fd5b61ffff81168114614bb857600080fd5b803561417e81614f36565b60008060008060808587031215614f6757600080fd5b8435614f7281614ba3565b93506020850135614f8281614ba3565b92506040850135614f9281614f25565b91506060850135614fa281614f36565b939692955090935050565b600080600080600080600080610100898b031215614fca57600080fd5b8835614fd581614ba3565b97506020890135614fe581614f36565b96506040890135955060608901359450608089013567ffffffffffffffff8082111561501057600080fd5b61501c8c838d01614ca0565b955060a08b013591508082111561503257600080fd5b5061503f8b828c01614ca0565b93505060c089013561505081614ba3565b8092505060e089013590509295985092959890939650565b60008060008060008060008060006101208a8c03121561508757600080fd5b893561509281614ba3565b985060208a01356150a281614ba3565b97506150b060408b01614f46565b965060608a0135955060808a0135945060a08a013567ffffffffffffffff808211156150db57600080fd5b6150e78d838e01614ca0565b955060c08c01359150808211156150fd57600080fd5b5061510a8c828d01614ca0565b93505061511960e08b01614d0b565b91506101008a013590509295985092959850929598565b6000806040838503121561514357600080fd5b823561514e81614ba3565b9150602083013561515e81614f25565b809150509250929050565b60006020828403121561517b57600080fd5b813567ffffffffffffffff81111561519257600080fd5b82016101c0818503121561398e57600080fd5b6040815260006151b86040830185614e96565b82810360208401526115a28185614e96565b60008083601f8401126151dc57600080fd5b50813567ffffffffffffffff8111156151f457600080fd5b6020830191508360208260051b850101111561520f57600080fd5b9250929050565b6000806000806000806080878903121561522f57600080fd5b863561523a81614ba3565b9550602087013561524a81614ba3565b9450604087013567ffffffffffffffff8082111561526757600080fd5b6152738a838b016151ca565b9096509450606089013591508082111561528c57600080fd5b5061529989828a016151ca565b979a9699509497509295939492505050565b600080604083850312156152be57600080fd5b82356152c981614ba3565b946020939093013593505050565b6000806000606084860312156152ec57600080fd5b8351925060208401519150604084015190509250925092565b805161417e81614f36565b805161417e81614f25565b805164ffffffffff8116811461417e57600080fd5b6000610180828403121561534357600080fd5b61534b614c21565b61535483615305565b815261536260208401615305565b602082015261537360408401615305565b604082015261538460608401615305565b606082015261539560808401615305565b60808201526153a660a08401615310565b60a08201526153b760c08401615305565b60c08201526153c860e08401615310565b60e08201526101006153db818501615310565b908201526101206153ed848201615310565b908201526101406153ff848201615310565b9082015261016061541184820161531b565b908201529392505050565b6000806040838503121561542f57600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b6000821982111561546957615469615440565b500190565b60008282101561548057615480615440565b500390565b60006020828403121561549757600080fd5b815161398e81614f25565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156154ca57600080fd5b5051919050565b6000602082840312156154e357600080fd5b815161398e81614ba3565b60006020828403121561550057600080fd5b813561398e81614ba3565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561553d57600080fd5b8260051b8083602087013760009401602001938452509192915050565b60006001600160a01b0380891683528088166020840152506080604083015261558760808301868861550b565b828103606084015261559a81858761550b565b9998505050505050505050565b634e487b7160e01b600052601260045260246000fd5b6000602082840312156155cf57600080fd5b815161398e81614bbb565b80516001600160701b038116811461417e57600080fd5b60008060006060848603121561560657600080fd5b61560f846155da565b925061561d602085016155da565b9150604084015163ffffffff81168114614c0057600080fd5b60008161564557615645615440565b506000190190565b600081600019048311821515161561566757615667615440565b500290565b60008261568957634e487b7160e01b600052601260045260246000fd5b500490565b6000608082840312156156a057600080fd5b6040516080810181811067ffffffffffffffff821117156156c3576156c3614c0b565b60405282516156d181614f36565b815260208301516156e181614ba3565b602082015260408301516156f481614bbb565b6040820152606083015161570781614bbb565b60608201529392505050565b60006001600160a01b0380871683528086166020840152506080604083015261573f6080830185614e96565b82810360608401526145358185614e96565b6060815260006157646060830186614e96565b82810360208401526157768186614e96565b9150506001600160a01b0383166040830152949350505050565b6000808335601e198436030181126157a757600080fd5b83018035915067ffffffffffffffff8211156157c257600080fd5b6020019150600581901b360382131561520f57600080fd5b6080815260006157ed6080830189614e96565b828103602084015261580081888a61550b565b9050828103604084015261581581868861550b565b9150506001600160a01b0383166060830152979650505050505050565b60008060006060848603121561584757600080fd5b835192506020808501519250604085015167ffffffffffffffff81111561586d57600080fd5b8501601f8101871361587e57600080fd5b805161588c614cc182614c7c565b81815260059190911b820183019083810190898311156158ab57600080fd5b928401925b828410156158c9578351825292840192908401906158b0565b80955050505050509250925092565b6000825160005b818110156158f957602081860181015185830152016158df565b81811115615908576000828501525b50919091019291505056fea26469706673582212206c05eee95a8862d596ac1d3ea3c231cfdc4a1453951fddb1394e8ead624c932964736f6c634300080a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000006e77932a92582f504ff6c4bdbcef7da6c198aeef0000000000000000000000009ad6c38be94206ca50bb0d90783181662f0cfa10000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c7
-----Decoded View---------------
Arg [0] : _factory (address): 0x6E77932A92582f504FF6c4BdbCef7Da6c198aEEf
Arg [1] : _oldFactory (address): 0x9Ad6C38BE94206cA50bb0d90783181662f0Cfa10
Arg [2] : _wavax (address): 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000006e77932a92582f504ff6c4bdbcef7da6c198aeef
Arg [1] : 0000000000000000000000009ad6c38be94206ca50bb0d90783181662f0cfa10
Arg [2] : 000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c7
Loading...
Loading
OVERVIEW
One-stop-shop decentralized trading on Avalanche.Loading...
Loading
Multichain Portfolio | 30 Chains
[ 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.