编译器
0.8.10+commit.fc410830
文件 1 的 31:AddressHelper.sol
pragma solidity 0.8.10;
library AddressHelper {
error AddressHelper__NonContract();
error AddressHelper__CallFailed();
function callAndCatch(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returnData) = target.call(data);
if (success) {
if (returnData.length == 0 && !isContract(target)) revert AddressHelper__NonContract();
} else {
if (returnData.length == 0) {
revert AddressHelper__CallFailed();
} else {
assembly {
revert(add(32, returnData), mload(returnData))
}
}
}
return returnData;
}
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
}
文件 2 的 31:BinHelper.sol
pragma solidity 0.8.10;
import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";
import {PackedUint128Math} from "./math/PackedUint128Math.sol";
import {Uint256x256Math} from "./math/Uint256x256Math.sol";
import {SafeCast} from "./math/SafeCast.sol";
import {Constants} from "./Constants.sol";
import {PairParameterHelper} from "./PairParameterHelper.sol";
import {FeeHelper} from "./FeeHelper.sol";
import {PriceHelper} from "./PriceHelper.sol";
import {TokenHelper} from "./TokenHelper.sol";
library BinHelper {
using PackedUint128Math for bytes32;
using PackedUint128Math for uint128;
using Uint256x256Math for uint256;
using PriceHelper for uint24;
using SafeCast for uint256;
using PairParameterHelper for bytes32;
using FeeHelper for uint128;
using TokenHelper for IERC20;
error BinHelper__CompositionFactorFlawed(uint24 id);
error BinHelper__LiquidityOverflow();
function getAmountOutOfBin(bytes32 binReserves, uint256 amountToBurn, uint256 totalSupply)
internal
pure
returns (bytes32 amountsOut)
{
(uint128 binReserveX, uint128 binReserveY) = binReserves.decode();
uint128 amountXOutFromBin;
uint128 amountYOutFromBin;
if (binReserveX > 0) {
amountXOutFromBin = (amountToBurn.mulDivRoundDown(binReserveX, totalSupply)).safe128();
}
if (binReserveY > 0) {
amountYOutFromBin = (amountToBurn.mulDivRoundDown(binReserveY, totalSupply)).safe128();
}
amountsOut = amountXOutFromBin.encode(amountYOutFromBin);
}
function getSharesAndEffectiveAmountsIn(bytes32 binReserves, bytes32 amountsIn, uint256 price, uint256 totalSupply)
internal
pure
returns (uint256 shares, bytes32 effectiveAmountsIn)
{
(uint256 x, uint256 y) = amountsIn.decode();
uint256 userLiquidity = getLiquidity(x, y, price);
if (totalSupply == 0 || userLiquidity == 0) return (userLiquidity, amountsIn);
uint256 binLiquidity = getLiquidity(binReserves, price);
if (binLiquidity == 0) return (userLiquidity, amountsIn);
shares = userLiquidity.mulDivRoundDown(totalSupply, binLiquidity);
uint256 effectiveLiquidity = shares.mulDivRoundUp(binLiquidity, totalSupply);
if (userLiquidity > effectiveLiquidity) {
uint256 deltaLiquidity = userLiquidity - effectiveLiquidity;
if (deltaLiquidity >= Constants.SCALE) {
uint256 deltaY = deltaLiquidity >> Constants.SCALE_OFFSET;
deltaY = deltaY > y ? y : deltaY;
y -= deltaY;
deltaLiquidity -= deltaY << Constants.SCALE_OFFSET;
}
if (deltaLiquidity >= price) {
uint256 deltaX = deltaLiquidity / price;
deltaX = deltaX > x ? x : deltaX;
x -= deltaX;
}
amountsIn = uint128(x).encode(uint128(y));
}
return (shares, amountsIn);
}
function getLiquidity(bytes32 amounts, uint256 price) internal pure returns (uint256 liquidity) {
(uint256 x, uint256 y) = amounts.decode();
return getLiquidity(x, y, price);
}
function getLiquidity(uint256 x, uint256 y, uint256 price) internal pure returns (uint256 liquidity) {
if (x > 0) {
unchecked {
liquidity = price * x;
if (liquidity / x != price) revert BinHelper__LiquidityOverflow();
}
}
if (y > 0) {
unchecked {
y <<= Constants.SCALE_OFFSET;
liquidity += y;
if (liquidity < y) revert BinHelper__LiquidityOverflow();
}
}
return liquidity;
}
function verifyAmounts(bytes32 amounts, uint24 activeId, uint24 id) internal pure {
if (id < activeId && (amounts << 128) > 0 || id > activeId && uint256(amounts) > type(uint128).max) {
revert BinHelper__CompositionFactorFlawed(id);
}
}
function getCompositionFees(
bytes32 binReserves,
bytes32 parameters,
uint16 binStep,
bytes32 amountsIn,
uint256 totalSupply,
uint256 shares
) internal pure returns (bytes32 fees) {
if (shares == 0) return 0;
(uint128 amountX, uint128 amountY) = amountsIn.decode();
(uint128 receivedAmountX, uint128 receivedAmountY) =
getAmountOutOfBin(binReserves.add(amountsIn), shares, totalSupply + shares).decode();
if (receivedAmountX > amountX) {
uint128 feeY = (amountY - receivedAmountY).getCompositionFee(parameters.getTotalFee(binStep));
fees = feeY.encodeSecond();
} else if (receivedAmountY > amountY) {
uint128 feeX = (amountX - receivedAmountX).getCompositionFee(parameters.getTotalFee(binStep));
fees = feeX.encodeFirst();
}
}
function isEmpty(bytes32 binReserves, bool isX) internal pure returns (bool) {
return isX ? binReserves.decodeX() == 0 : binReserves.decodeY() == 0;
}
function getAmounts(
bytes32 binReserves,
bytes32 parameters,
uint16 binStep,
bool swapForY,
uint24 activeId,
bytes32 amountsInLeft
) internal pure returns (bytes32 amountsInWithFees, bytes32 amountsOutOfBin, bytes32 totalFees) {
uint256 price = activeId.getPriceFromId(binStep);
uint128 binReserveOut = binReserves.decode(!swapForY);
uint128 maxAmountIn = swapForY
? uint256(binReserveOut).shiftDivRoundUp(Constants.SCALE_OFFSET, price).safe128()
: uint256(binReserveOut).mulShiftRoundUp(price, Constants.SCALE_OFFSET).safe128();
uint128 totalFee = parameters.getTotalFee(binStep);
uint128 maxFee = maxAmountIn.getFeeAmount(totalFee);
maxAmountIn += maxFee;
uint128 amountIn128 = amountsInLeft.decode(swapForY);
uint128 fee128;
uint128 amountOut128;
if (amountIn128 >= maxAmountIn) {
fee128 = maxFee;
amountIn128 = maxAmountIn;
amountOut128 = binReserveOut;
} else {
fee128 = amountIn128.getFeeAmountFrom(totalFee);
uint256 amountIn = amountIn128 - fee128;
amountOut128 = swapForY
? uint256(amountIn).mulShiftRoundDown(price, Constants.SCALE_OFFSET).safe128()
: uint256(amountIn).shiftDivRoundDown(Constants.SCALE_OFFSET, price).safe128();
if (amountOut128 > binReserveOut) amountOut128 = binReserveOut;
}
(amountsInWithFees, amountsOutOfBin, totalFees) = swapForY
? (amountIn128.encodeFirst(), amountOut128.encodeSecond(), fee128.encodeFirst())
: (amountIn128.encodeSecond(), amountOut128.encodeFirst(), fee128.encodeSecond());
}
function received(bytes32 reserves, IERC20 tokenX, IERC20 tokenY) internal view returns (bytes32 amounts) {
amounts = _balanceOf(tokenX).encode(_balanceOf(tokenY)).sub(reserves);
}
function receivedX(bytes32 reserves, IERC20 tokenX) internal view returns (bytes32) {
uint128 reserveX = reserves.decodeX();
return (_balanceOf(tokenX) - reserveX).encodeFirst();
}
function receivedY(bytes32 reserves, IERC20 tokenY) internal view returns (bytes32) {
uint128 reserveY = reserves.decodeY();
return (_balanceOf(tokenY) - reserveY).encodeSecond();
}
function transfer(bytes32 amounts, IERC20 tokenX, IERC20 tokenY, address recipient) internal {
(uint128 amountX, uint128 amountY) = amounts.decode();
if (amountX > 0) tokenX.safeTransfer(recipient, amountX);
if (amountY > 0) tokenY.safeTransfer(recipient, amountY);
}
function transferX(bytes32 amounts, IERC20 tokenX, address recipient) internal {
uint128 amountX = amounts.decodeX();
if (amountX > 0) tokenX.safeTransfer(recipient, amountX);
}
function transferY(bytes32 amounts, IERC20 tokenY, address recipient) internal {
uint128 amountY = amounts.decodeY();
if (amountY > 0) tokenY.safeTransfer(recipient, amountY);
}
function _balanceOf(IERC20 token) private view returns (uint128) {
return token.balanceOf(address(this)).safe128();
}
}
文件 3 的 31:BitMath.sol
pragma solidity 0.8.10;
library BitMath {
function closestBitRight(uint256 x, uint8 bit) internal pure returns (uint256 id) {
unchecked {
uint256 shift = 255 - bit;
x <<= shift;
return (x == 0) ? type(uint256).max : mostSignificantBit(x) - shift;
}
}
function closestBitLeft(uint256 x, uint8 bit) internal pure returns (uint256 id) {
unchecked {
x >>= bit;
return (x == 0) ? type(uint256).max : leastSignificantBit(x) + bit;
}
}
function mostSignificantBit(uint256 x) internal pure returns (uint8 msb) {
assembly {
if gt(x, 0xffffffffffffffffffffffffffffffff) {
x := shr(128, x)
msb := 128
}
if gt(x, 0xffffffffffffffff) {
x := shr(64, x)
msb := add(msb, 64)
}
if gt(x, 0xffffffff) {
x := shr(32, x)
msb := add(msb, 32)
}
if gt(x, 0xffff) {
x := shr(16, x)
msb := add(msb, 16)
}
if gt(x, 0xff) {
x := shr(8, x)
msb := add(msb, 8)
}
if gt(x, 0xf) {
x := shr(4, x)
msb := add(msb, 4)
}
if gt(x, 0x3) {
x := shr(2, x)
msb := add(msb, 2)
}
if gt(x, 0x1) { msb := add(msb, 1) }
}
}
function leastSignificantBit(uint256 x) internal pure returns (uint8 lsb) {
assembly {
let sx := shl(128, x)
if iszero(iszero(sx)) {
lsb := 128
x := sx
}
sx := shl(64, x)
if iszero(iszero(sx)) {
x := sx
lsb := add(lsb, 64)
}
sx := shl(32, x)
if iszero(iszero(sx)) {
x := sx
lsb := add(lsb, 32)
}
sx := shl(16, x)
if iszero(iszero(sx)) {
x := sx
lsb := add(lsb, 16)
}
sx := shl(8, x)
if iszero(iszero(sx)) {
x := sx
lsb := add(lsb, 8)
}
sx := shl(4, x)
if iszero(iszero(sx)) {
x := sx
lsb := add(lsb, 4)
}
sx := shl(2, x)
if iszero(iszero(sx)) {
x := sx
lsb := add(lsb, 2)
}
if iszero(iszero(shl(1, x))) { lsb := add(lsb, 1) }
lsb := sub(255, lsb)
}
}
}
文件 4 的 31:Constants.sol
pragma solidity 0.8.10;
library Constants {
uint8 internal constant SCALE_OFFSET = 128;
uint256 internal constant SCALE = 1 << SCALE_OFFSET;
uint256 internal constant PRECISION = 1e18;
uint256 internal constant SQUARED_PRECISION = PRECISION * PRECISION;
uint256 internal constant MAX_FEE = 0.1e18;
uint256 internal constant MAX_PROTOCOL_SHARE = 2_500;
uint256 internal constant BASIS_POINT_MAX = 10_000;
bytes32 internal constant CALLBACK_SUCCESS = keccak256("LBPair.onFlashLoan");
}
文件 5 的 31:Encoded.sol
pragma solidity 0.8.10;
library Encoded {
uint256 internal constant MASK_UINT1 = 0x1;
uint256 internal constant MASK_UINT8 = 0xff;
uint256 internal constant MASK_UINT12 = 0xfff;
uint256 internal constant MASK_UINT14 = 0x3fff;
uint256 internal constant MASK_UINT16 = 0xffff;
uint256 internal constant MASK_UINT20 = 0xfffff;
uint256 internal constant MASK_UINT24 = 0xffffff;
uint256 internal constant MASK_UINT40 = 0xffffffffff;
uint256 internal constant MASK_UINT64 = 0xffffffffffffffff;
uint256 internal constant MASK_UINT128 = 0xffffffffffffffffffffffffffffffff;
function set(bytes32 encoded, uint256 value, uint256 mask, uint256 offset)
internal
pure
returns (bytes32 newEncoded)
{
assembly {
newEncoded := and(encoded, not(shl(offset, mask)))
newEncoded := or(newEncoded, shl(offset, and(value, mask)))
}
}
function setBool(bytes32 encoded, bool boolean, uint256 offset) internal pure returns (bytes32 newEncoded) {
return set(encoded, boolean ? 1 : 0, MASK_UINT1, offset);
}
function decode(bytes32 encoded, uint256 mask, uint256 offset) internal pure returns (uint256 value) {
assembly {
value := and(shr(offset, encoded), mask)
}
}
function decodeBool(bytes32 encoded, uint256 offset) internal pure returns (bool boolean) {
assembly {
boolean := and(shr(offset, encoded), MASK_UINT1)
}
}
function decodeUint8(bytes32 encoded, uint256 offset) internal pure returns (uint8 value) {
assembly {
value := and(shr(offset, encoded), MASK_UINT8)
}
}
function decodeUint12(bytes32 encoded, uint256 offset) internal pure returns (uint16 value) {
assembly {
value := and(shr(offset, encoded), MASK_UINT12)
}
}
function decodeUint14(bytes32 encoded, uint256 offset) internal pure returns (uint16 value) {
assembly {
value := and(shr(offset, encoded), MASK_UINT14)
}
}
function decodeUint16(bytes32 encoded, uint256 offset) internal pure returns (uint16 value) {
assembly {
value := and(shr(offset, encoded), MASK_UINT16)
}
}
function decodeUint20(bytes32 encoded, uint256 offset) internal pure returns (uint24 value) {
assembly {
value := and(shr(offset, encoded), MASK_UINT20)
}
}
function decodeUint24(bytes32 encoded, uint256 offset) internal pure returns (uint24 value) {
assembly {
value := and(shr(offset, encoded), MASK_UINT24)
}
}
function decodeUint40(bytes32 encoded, uint256 offset) internal pure returns (uint40 value) {
assembly {
value := and(shr(offset, encoded), MASK_UINT40)
}
}
function decodeUint64(bytes32 encoded, uint256 offset) internal pure returns (uint64 value) {
assembly {
value := and(shr(offset, encoded), MASK_UINT64)
}
}
function decodeUint128(bytes32 encoded, uint256 offset) internal pure returns (uint128 value) {
assembly {
value := and(shr(offset, encoded), MASK_UINT128)
}
}
}
文件 6 的 31:FeeHelper.sol
pragma solidity 0.8.10;
import {Constants} from "./Constants.sol";
library FeeHelper {
error FeeHelper__FeeTooLarge();
error FeeHelper__ProtocolShareTooLarge();
modifier verifyFee(uint128 fee) {
if (fee > Constants.MAX_FEE) revert FeeHelper__FeeTooLarge();
_;
}
modifier verifyProtocolShare(uint128 protocolShare) {
if (protocolShare > Constants.MAX_PROTOCOL_SHARE) revert FeeHelper__ProtocolShareTooLarge();
_;
}
function getFeeAmountFrom(uint128 amountWithFees, uint128 totalFee)
internal
pure
verifyFee(totalFee)
returns (uint128)
{
unchecked {
return uint128((uint256(amountWithFees) * totalFee + Constants.PRECISION - 1) / Constants.PRECISION);
}
}
function getFeeAmount(uint128 amount, uint128 totalFee) internal pure verifyFee(totalFee) returns (uint128) {
unchecked {
uint256 denominator = Constants.PRECISION - totalFee;
return uint128((uint256(amount) * totalFee + denominator - 1) / denominator);
}
}
function getCompositionFee(uint128 amountWithFees, uint128 totalFee)
internal
pure
verifyFee(totalFee)
returns (uint128)
{
unchecked {
uint256 denominator = Constants.SQUARED_PRECISION;
return uint128(uint256(amountWithFees) * totalFee * (uint256(totalFee) + Constants.PRECISION) / denominator);
}
}
function getProtocolFeeAmount(uint128 feeAmount, uint128 protocolShare)
internal
pure
verifyProtocolShare(protocolShare)
returns (uint128)
{
unchecked {
return uint128(uint256(feeAmount) * protocolShare / Constants.BASIS_POINT_MAX);
}
}
}
文件 7 的 31:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 8 的 31:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
文件 9 的 31:IJoeFactory.sol
pragma solidity 0.8.10;
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;
}
文件 10 的 31:IJoePair.sol
pragma solidity 0.8.10;
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;
}
文件 11 的 31:ILBFactory.sol
pragma solidity 0.8.10;
import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";
import {ILBPair} from "./ILBPair.sol";
import {IPendingOwnable} from "./IPendingOwnable.sol";
interface ILBFactory is IPendingOwnable {
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__LBPairDoesNotExist(IERC20 tokenX, IERC20 tokenY, uint256 binStep);
error LBFactory__LBPairNotCreated(IERC20 tokenX, IERC20 tokenY, uint256 binStep);
error LBFactory__FlashLoanFeeAboveMax(uint256 fees, uint256 maxFees);
error LBFactory__BinStepTooLow(uint256 binStep);
error LBFactory__PresetIsLockedForUsers(address user, uint256 binStep);
error LBFactory__LBPairIgnoredIsAlreadyInTheSameState();
error LBFactory__BinStepHasNoPreset(uint256 binStep);
error LBFactory__PresetOpenStateIsAlreadyInTheSameState();
error LBFactory__SameFeeRecipient(address feeRecipient);
error LBFactory__SameFlashLoanFee(uint256 flashLoanFee);
error LBFactory__LBPairSafetyCheckFailed(address LBPairImplementation);
error LBFactory__SameImplementation(address LBPairImplementation);
error LBFactory__ImplementationNotSet();
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 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 maxVolatilityAccumulator
);
event PresetOpenStateChanged(uint256 indexed binStep, bool indexed isOpen);
event PresetRemoved(uint256 indexed binStep);
event QuoteAssetAdded(IERC20 indexed quoteAsset);
event QuoteAssetRemoved(IERC20 indexed quoteAsset);
function getMinBinStep() external pure returns (uint256);
function getFeeRecipient() external view returns (address);
function getMaxFlashLoanFee() external pure returns (uint256);
function getFlashLoanFee() external view returns (uint256);
function getLBPairImplementation() external view returns (address);
function getNumberOfLBPairs() external view returns (uint256);
function getLBPairAtIndex(uint256 id) external returns (ILBPair);
function getNumberOfQuoteAssets() external view returns (uint256);
function getQuoteAssetAtIndex(uint256 index) external view returns (IERC20);
function isQuoteAsset(IERC20 token) external view returns (bool);
function getLBPairInformation(IERC20 tokenX, IERC20 tokenY, uint256 binStep)
external
view
returns (LBPairInformation memory);
function getPreset(uint256 binStep)
external
view
returns (
uint256 baseFactor,
uint256 filterPeriod,
uint256 decayPeriod,
uint256 reductionFactor,
uint256 variableFeeControl,
uint256 protocolShare,
uint256 maxAccumulator,
bool isOpen
);
function getAllBinSteps() external view returns (uint256[] memory presetsBinStep);
function getOpenBinSteps() external view returns (uint256[] memory openBinStep);
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, uint16 binStep, bool ignored) external;
function setPreset(
uint16 binStep,
uint16 baseFactor,
uint16 filterPeriod,
uint16 decayPeriod,
uint16 reductionFactor,
uint24 variableFeeControl,
uint16 protocolShare,
uint24 maxVolatilityAccumulator,
bool isOpen
) external;
function setPresetOpenState(uint16 binStep, bool isOpen) 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 maxVolatilityAccumulator
) external;
function setFeeRecipient(address feeRecipient) external;
function setFlashLoanFee(uint256 flashLoanFee) external;
function addQuoteAsset(IERC20 quoteAsset) external;
function removeQuoteAsset(IERC20 quoteAsset) external;
function forceDecay(ILBPair lbPair) external;
}
文件 12 的 31:ILBFlashLoanCallback.sol
pragma solidity 0.8.10;
import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";
interface ILBFlashLoanCallback {
function LBFlashLoanCallback(
address sender,
IERC20 tokenX,
IERC20 tokenY,
bytes32 amounts,
bytes32 totalFees,
bytes calldata data
) external returns (bytes32);
}
文件 13 的 31:ILBLegacyFactory.sol
pragma solidity 0.8.10;
import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";
import {ILBLegacyPair} from "./ILBLegacyPair.sol";
import {IPendingOwnable} from "./IPendingOwnable.sol";
interface ILBLegacyFactory is IPendingOwnable {
struct LBPairInformation {
uint16 binStep;
ILBLegacyPair LBPair;
bool createdByOwner;
bool ignoredForRouting;
}
event LBPairCreated(
IERC20 indexed tokenX, IERC20 indexed tokenY, uint256 indexed binStep, ILBLegacyPair LBPair, uint256 pid
);
event FeeRecipientSet(address oldRecipient, address newRecipient);
event FlashLoanFeeSet(uint256 oldFlashLoanFee, uint256 newFlashLoanFee);
event FeeParametersSet(
address indexed sender,
ILBLegacyPair indexed LBPair,
uint256 binStep,
uint256 baseFactor,
uint256 filterPeriod,
uint256 decayPeriod,
uint256 reductionFactor,
uint256 variableFeeControl,
uint256 protocolShare,
uint256 maxVolatilityAccumulator
);
event FactoryLockedStatusUpdated(bool unlocked);
event LBPairImplementationSet(address oldLBPairImplementation, address LBPairImplementation);
event LBPairIgnoredStateChanged(ILBLegacyPair indexed LBPair, bool ignored);
event PresetSet(
uint256 indexed binStep,
uint256 baseFactor,
uint256 filterPeriod,
uint256 decayPeriod,
uint256 reductionFactor,
uint256 variableFeeControl,
uint256 protocolShare,
uint256 maxVolatilityAccumulator,
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 (ILBLegacyPair);
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 (ILBLegacyPair 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 maxVolatilityAccumulator,
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 maxVolatilityAccumulator
) 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(ILBLegacyPair LBPair) external;
}
文件 14 的 31:ILBLegacyPair.sol
pragma solidity 0.8.10;
import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";
import {ILBLegacyToken} from "./ILBLegacyToken.sol";
interface ILBLegacyPair is ILBLegacyToken {
struct FeeParameters {
uint16 binStep;
uint16 baseFactor;
uint16 filterPeriod;
uint16 decayPeriod;
uint16 reductionFactor;
uint24 variableFeeControl;
uint16 protocolShare;
uint24 maxVolatilityAccumulated;
uint24 volatilityAccumulated;
uint24 volatilityReference;
uint24 indexRef;
uint40 time;
}
struct FeesDistribution {
uint128 total;
uint128 protocol;
}
struct Bin {
uint112 reserveX;
uint112 reserveY;
uint256 accTokenXPerShare;
uint256 accTokenYPerShare;
}
struct PairInformation {
uint24 activeId;
uint136 reserveX;
uint136 reserveY;
uint16 oracleSampleLifetime;
uint16 oracleSize;
uint16 oracleActiveSize;
uint40 oracleLastTimestamp;
uint16 oracleId;
FeesDistribution feesX;
FeesDistribution feesY;
}
struct Debts {
uint256 debtX;
uint256 debtY;
}
struct Fees {
uint128 tokenX;
uint128 tokenY;
}
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, address 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 (address);
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 (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(address 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;
}
文件 15 的 31:ILBLegacyRouter.sol
pragma solidity 0.8.10;
import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";
import {ILBFactory} from "./ILBFactory.sol";
import {IJoeFactory} from "./IJoeFactory.sol";
import {ILBLegacyPair} from "./ILBLegacyPair.sol";
import {ILBToken} from "./ILBToken.sol";
import {IWNATIVE} from "./IWNATIVE.sol";
interface ILBLegacyRouter {
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 (address);
function wavax() external view returns (address);
function oldFactory() external view returns (address);
function getIdFromPrice(ILBLegacyPair LBPair, uint256 price) external view returns (uint24);
function getPriceFromId(ILBLegacyPair LBPair, uint24 id) external view returns (uint256);
function getSwapIn(ILBLegacyPair lbPair, uint256 amountOut, bool swapForY)
external
view
returns (uint256 amountIn, uint256 feesIn);
function getSwapOut(ILBLegacyPair lbPair, uint256 amountIn, bool swapForY)
external
view
returns (uint256 amountOut, uint256 feesIn);
function createLBPair(IERC20 tokenX, IERC20 tokenY, uint24 activeId, uint16 binStep)
external
returns (ILBLegacyPair 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;
}
文件 16 的 31:ILBLegacyToken.sol
pragma solidity 0.8.10;
import "openzeppelin/utils/introspection/IERC165.sol";
interface ILBLegacyToken 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;
}
文件 17 的 31:ILBPair.sol
pragma solidity 0.8.10;
import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";
import {ILBFactory} from "./ILBFactory.sol";
import {ILBFlashLoanCallback} from "./ILBFlashLoanCallback.sol";
import {ILBToken} from "./ILBToken.sol";
interface ILBPair is ILBToken {
error LBPair__ZeroBorrowAmount();
error LBPair__AddressZero();
error LBPair__AlreadyInitialized();
error LBPair__EmptyMarketConfigs();
error LBPair__FlashLoanCallbackFailed();
error LBPair__FlashLoanInsufficientAmount();
error LBPair__InsufficientAmountIn();
error LBPair__InsufficientAmountOut();
error LBPair__InvalidInput();
error LBPair__InvalidStaticFeeParameters();
error LBPair__OnlyFactory();
error LBPair__OnlyProtocolFeeRecipient();
error LBPair__OutOfLiquidity();
error LBPair__TokenNotSupported();
error LBPair__ZeroAmount(uint24 id);
error LBPair__ZeroAmountsOut(uint24 id);
error LBPair__ZeroShares(uint24 id);
error LBPair__MaxTotalFeeExceeded();
struct MintArrays {
uint256[] ids;
bytes32[] amounts;
uint256[] liquidityMinted;
}
event DepositedToBins(address indexed sender, address indexed to, uint256[] ids, bytes32[] amounts);
event WithdrawnFromBins(address indexed sender, address indexed to, uint256[] ids, bytes32[] amounts);
event CompositionFees(address indexed sender, uint24 id, bytes32 totalFees, bytes32 protocolFees);
event CollectedProtocolFees(address indexed feeRecipient, bytes32 protocolFees);
event Swap(
address indexed sender,
address indexed to,
uint24 id,
bytes32 amountsIn,
bytes32 amountsOut,
uint24 volatilityAccumulator,
bytes32 totalFees,
bytes32 protocolFees
);
event StaticFeeParametersSet(
address indexed sender,
uint16 baseFactor,
uint16 filterPeriod,
uint16 decayPeriod,
uint16 reductionFactor,
uint24 variableFeeControl,
uint16 protocolShare,
uint24 maxVolatilityAccumulator
);
event FlashLoan(
address indexed sender,
ILBFlashLoanCallback indexed receiver,
uint24 activeId,
bytes32 amounts,
bytes32 totalFees,
bytes32 protocolFees
);
event OracleLengthIncreased(address indexed sender, uint16 oracleLength);
event ForcedDecay(address indexed sender, uint24 idReference, uint24 volatilityReference);
function initialize(
uint16 baseFactor,
uint16 filterPeriod,
uint16 decayPeriod,
uint16 reductionFactor,
uint24 variableFeeControl,
uint16 protocolShare,
uint24 maxVolatilityAccumulator,
uint24 activeId
) external;
function getFactory() external view returns (ILBFactory factory);
function getTokenX() external view returns (IERC20 tokenX);
function getTokenY() external view returns (IERC20 tokenY);
function getBinStep() external view returns (uint16 binStep);
function getReserves() external view returns (uint128 reserveX, uint128 reserveY);
function getActiveId() external view returns (uint24 activeId);
function getBin(uint24 id) external view returns (uint128 binReserveX, uint128 binReserveY);
function getNextNonEmptyBin(bool swapForY, uint24 id) external view returns (uint24 nextId);
function getProtocolFees() external view returns (uint128 protocolFeeX, uint128 protocolFeeY);
function getStaticFeeParameters()
external
view
returns (
uint16 baseFactor,
uint16 filterPeriod,
uint16 decayPeriod,
uint16 reductionFactor,
uint24 variableFeeControl,
uint16 protocolShare,
uint24 maxVolatilityAccumulator
);
function getVariableFeeParameters()
external
view
returns (uint24 volatilityAccumulator, uint24 volatilityReference, uint24 idReference, uint40 timeOfLastUpdate);
function getOracleParameters()
external
view
returns (uint8 sampleLifetime, uint16 size, uint16 activeSize, uint40 lastUpdated, uint40 firstTimestamp);
function getOracleSampleAt(uint40 lookupTimestamp)
external
view
returns (uint64 cumulativeId, uint64 cumulativeVolatility, uint64 cumulativeBinCrossed);
function getPriceFromId(uint24 id) external view returns (uint256 price);
function getIdFromPrice(uint256 price) external view returns (uint24 id);
function getSwapIn(uint128 amountOut, bool swapForY)
external
view
returns (uint128 amountIn, uint128 amountOutLeft, uint128 fee);
function getSwapOut(uint128 amountIn, bool swapForY)
external
view
returns (uint128 amountInLeft, uint128 amountOut, uint128 fee);
function swap(bool swapForY, address to) external returns (bytes32 amountsOut);
function flashLoan(ILBFlashLoanCallback receiver, bytes32 amounts, bytes calldata data) external;
function mint(address to, bytes32[] calldata liquidityConfigs, address refundTo)
external
returns (bytes32 amountsReceived, bytes32 amountsLeft, uint256[] memory liquidityMinted);
function burn(address from, address to, uint256[] calldata ids, uint256[] calldata amountsToBurn)
external
returns (bytes32[] memory amounts);
function collectProtocolFees() external returns (bytes32 collectedProtocolFees);
function increaseOracleLength(uint16 newLength) external;
function setStaticFeeParameters(
uint16 baseFactor,
uint16 filterPeriod,
uint16 decayPeriod,
uint16 reductionFactor,
uint24 variableFeeControl,
uint16 protocolShare,
uint24 maxVolatilityAccumulator
) external;
function forceDecay() external;
}
文件 18 的 31:ILBRouter.sol
pragma solidity 0.8.10;
import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";
import {IJoeFactory} from "./IJoeFactory.sol";
import {ILBFactory} from "./ILBFactory.sol";
import {ILBLegacyFactory} from "./ILBLegacyFactory.sol";
import {ILBLegacyRouter} from "./ILBLegacyRouter.sol";
import {ILBPair} from "./ILBPair.sol";
import {ILBToken} from "./ILBToken.sol";
import {IWNATIVE} from "./IWNATIVE.sol";
interface ILBRouter {
error LBRouter__SenderIsNotWNATIVE();
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__FailedToSendNATIVE(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__WrongNativeLiquidityParameters(
address tokenX, address tokenY, uint256 amountX, uint256 amountY, uint256 msgValue
);
enum Version {
V1,
V2,
V2_1
}
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;
address refundTo;
uint256 deadline;
}
struct Path {
uint256[] pairBinSteps;
Version[] versions;
IERC20[] tokenPath;
}
function getFactory() external view returns (ILBFactory);
function getLegacyFactory() external view returns (ILBLegacyFactory);
function getV1Factory() external view returns (IJoeFactory);
function getLegacyRouter() external view returns (ILBLegacyRouter);
function getWNATIVE() external view returns (IWNATIVE);
function getIdFromPrice(ILBPair LBPair, uint256 price) external view returns (uint24);
function getPriceFromId(ILBPair LBPair, uint24 id) external view returns (uint256);
function getSwapIn(ILBPair LBPair, uint128 amountOut, bool swapForY)
external
view
returns (uint128 amountIn, uint128 amountOutLeft, uint128 fee);
function getSwapOut(ILBPair LBPair, uint128 amountIn, bool swapForY)
external
view
returns (uint128 amountInLeft, uint128 amountOut, uint128 fee);
function createLBPair(IERC20 tokenX, IERC20 tokenY, uint24 activeId, uint16 binStep)
external
returns (ILBPair pair);
function addLiquidity(LiquidityParameters calldata liquidityParameters)
external
returns (
uint256 amountXAdded,
uint256 amountYAdded,
uint256 amountXLeft,
uint256 amountYLeft,
uint256[] memory depositIds,
uint256[] memory liquidityMinted
);
function addLiquidityNATIVE(LiquidityParameters calldata liquidityParameters)
external
payable
returns (
uint256 amountXAdded,
uint256 amountYAdded,
uint256 amountXLeft,
uint256 amountYLeft,
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 removeLiquidityNATIVE(
IERC20 token,
uint16 binStep,
uint256 amountTokenMin,
uint256 amountNATIVEMin,
uint256[] memory ids,
uint256[] memory amounts,
address payable to,
uint256 deadline
) external returns (uint256 amountToken, uint256 amountNATIVE);
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
Path memory path,
address to,
uint256 deadline
) external returns (uint256 amountOut);
function swapExactTokensForNATIVE(
uint256 amountIn,
uint256 amountOutMinNATIVE,
Path memory path,
address payable to,
uint256 deadline
) external returns (uint256 amountOut);
function swapExactNATIVEForTokens(uint256 amountOutMin, Path memory path, address to, uint256 deadline)
external
payable
returns (uint256 amountOut);
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
Path memory path,
address to,
uint256 deadline
) external returns (uint256[] memory amountsIn);
function swapTokensForExactNATIVE(
uint256 amountOut,
uint256 amountInMax,
Path memory path,
address payable to,
uint256 deadline
) external returns (uint256[] memory amountsIn);
function swapNATIVEForExactTokens(uint256 amountOut, Path memory path, address to, uint256 deadline)
external
payable
returns (uint256[] memory amountsIn);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
Path memory path,
address to,
uint256 deadline
) external returns (uint256 amountOut);
function swapExactTokensForNATIVESupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMinNATIVE,
Path memory path,
address payable to,
uint256 deadline
) external returns (uint256 amountOut);
function swapExactNATIVEForTokensSupportingFeeOnTransferTokens(
uint256 amountOutMin,
Path memory path,
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;
}
文件 19 的 31:ILBToken.sol
pragma solidity 0.8.10;
interface ILBToken {
error LBToken__AddressThisOrZero();
error LBToken__InvalidLength();
error LBToken__SelfApproval(address owner);
error LBToken__SpenderNotApproved(address from, address spender);
error LBToken__TransferExceedsBalance(address from, uint256 id, uint256 amount);
error LBToken__BurnExceedsBalance(address from, 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 totalSupply(uint256 id) external view returns (uint256);
function balanceOf(address account, uint256 id) external view returns (uint256);
function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
external
view
returns (uint256[] memory);
function isApprovedForAll(address owner, address spender) external view returns (bool);
function approveForAll(address spender, bool approved) external;
function batchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata amounts) external;
}
文件 20 的 31:IPendingOwnable.sol
pragma solidity 0.8.10;
interface IPendingOwnable {
error PendingOwnable__AddressZero();
error PendingOwnable__NoPendingOwner();
error PendingOwnable__NotOwner();
error PendingOwnable__NotPendingOwner();
error PendingOwnable__PendingOwnerAlreadySet();
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;
}
文件 21 的 31:IWNATIVE.sol
pragma solidity 0.8.10;
import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";
interface IWNATIVE is IERC20 {
function deposit() external payable;
function withdraw(uint256) external;
}
文件 22 的 31:JoeLibrary.sol
pragma solidity 0.8.10;
library JoeLibrary {
error JoeLibrary__AddressZero();
error JoeLibrary__IdenticalAddresses();
error JoeLibrary__InsufficientAmount();
error JoeLibrary__InsufficientLiquidity();
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();
}
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;
}
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;
}
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;
}
}
文件 23 的 31:LBRouter.sol
pragma solidity 0.8.10;
import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";
import {BinHelper} from "./libraries/BinHelper.sol";
import {Constants} from "./libraries/Constants.sol";
import {Encoded} from "./libraries/math/Encoded.sol";
import {FeeHelper} from "./libraries/FeeHelper.sol";
import {JoeLibrary} from "./libraries/JoeLibrary.sol";
import {LiquidityConfigurations} from "./libraries/math/LiquidityConfigurations.sol";
import {PackedUint128Math} from "./libraries/math/PackedUint128Math.sol";
import {TokenHelper} from "./libraries/TokenHelper.sol";
import {Uint256x256Math} from "./libraries/math/Uint256x256Math.sol";
import {IJoePair} from "./interfaces/IJoePair.sol";
import {ILBPair} from "./interfaces/ILBPair.sol";
import {ILBLegacyPair} from "./interfaces/ILBLegacyPair.sol";
import {ILBToken} from "./interfaces/ILBToken.sol";
import {ILBRouter} from "./interfaces/ILBRouter.sol";
import {ILBLegacyRouter} from "./interfaces/ILBLegacyRouter.sol";
import {IJoeFactory} from "./interfaces/IJoeFactory.sol";
import {ILBLegacyFactory} from "./interfaces/ILBLegacyFactory.sol";
import {ILBFactory} from "./interfaces/ILBFactory.sol";
import {IWNATIVE} from "./interfaces/IWNATIVE.sol";
contract LBRouter is ILBRouter {
using TokenHelper for IERC20;
using TokenHelper for IWNATIVE;
using JoeLibrary for uint256;
using PackedUint128Math for bytes32;
ILBFactory private immutable _factory;
IJoeFactory private immutable _factoryV1;
ILBLegacyFactory private immutable _legacyFactory;
ILBLegacyRouter private immutable _legacyRouter;
IWNATIVE private immutable _wnative;
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 verifyPathValidity(Path memory path) {
if (
path.pairBinSteps.length == 0 || path.versions.length != path.pairBinSteps.length
|| path.pairBinSteps.length + 1 != path.tokenPath.length
) revert LBRouter__LengthsMismatch();
_;
}
constructor(
ILBFactory factory,
IJoeFactory factoryV1,
ILBLegacyFactory legacyFactory,
ILBLegacyRouter legacyRouter,
IWNATIVE wnative
) {
_factory = factory;
_factoryV1 = factoryV1;
_legacyFactory = legacyFactory;
_legacyRouter = legacyRouter;
_wnative = wnative;
}
receive() external payable {
if (msg.sender != address(_wnative)) revert LBRouter__SenderIsNotWNATIVE();
}
function getFactory() external view override returns (ILBFactory lbFactory) {
return _factory;
}
function getLegacyFactory() external view override returns (ILBLegacyFactory legacyLBfactory) {
return _legacyFactory;
}
function getV1Factory() external view override returns (IJoeFactory factoryV1) {
return _factoryV1;
}
function getLegacyRouter() external view override returns (ILBLegacyRouter legacyRouter) {
return _legacyRouter;
}
function getWNATIVE() external view override returns (IWNATIVE wnative) {
return _wnative;
}
function getIdFromPrice(ILBPair pair, uint256 price) external view override returns (uint24) {
return pair.getIdFromPrice(price);
}
function getPriceFromId(ILBPair pair, uint24 id) external view override returns (uint256) {
return pair.getPriceFromId(id);
}
function getSwapIn(ILBPair pair, uint128 amountOut, bool swapForY)
public
view
override
returns (uint128 amountIn, uint128 amountOutLeft, uint128 fee)
{
(amountIn, amountOutLeft, fee) = pair.getSwapIn(amountOut, swapForY);
}
function getSwapOut(ILBPair pair, uint128 amountIn, bool swapForY)
external
view
override
returns (uint128 amountInLeft, uint128 amountOut, uint128 fee)
{
(amountInLeft, amountOut, fee) = pair.getSwapOut(amountIn, swapForY);
}
function createLBPair(IERC20 tokenX, IERC20 tokenY, uint24 activeId, uint16 binStep)
external
override
returns (ILBPair pair)
{
pair = _factory.createLBPair(tokenX, tokenY, activeId, binStep);
}
function addLiquidity(LiquidityParameters calldata liquidityParameters)
external
override
returns (
uint256 amountXAdded,
uint256 amountYAdded,
uint256 amountXLeft,
uint256 amountYLeft,
uint256[] memory depositIds,
uint256[] memory liquidityMinted
)
{
ILBPair lbPair = ILBPair(
_getLBPairInformation(
liquidityParameters.tokenX, liquidityParameters.tokenY, liquidityParameters.binStep, Version.V2_1
)
);
if (liquidityParameters.tokenX != lbPair.getTokenX()) revert LBRouter__WrongTokenOrder();
liquidityParameters.tokenX.safeTransferFrom(msg.sender, address(lbPair), liquidityParameters.amountX);
liquidityParameters.tokenY.safeTransferFrom(msg.sender, address(lbPair), liquidityParameters.amountY);
(amountXAdded, amountYAdded, amountXLeft, amountYLeft, depositIds, liquidityMinted) =
_addLiquidity(liquidityParameters, lbPair);
}
function addLiquidityNATIVE(LiquidityParameters calldata liquidityParameters)
external
payable
override
returns (
uint256 amountXAdded,
uint256 amountYAdded,
uint256 amountXLeft,
uint256 amountYLeft,
uint256[] memory depositIds,
uint256[] memory liquidityMinted
)
{
ILBPair _LBPair = ILBPair(
_getLBPairInformation(
liquidityParameters.tokenX, liquidityParameters.tokenY, liquidityParameters.binStep, Version.V2_1
)
);
if (liquidityParameters.tokenX != _LBPair.getTokenX()) revert LBRouter__WrongTokenOrder();
if (liquidityParameters.tokenX == _wnative && liquidityParameters.amountX == msg.value) {
_wnativeDepositAndTransfer(address(_LBPair), msg.value);
liquidityParameters.tokenY.safeTransferFrom(msg.sender, address(_LBPair), liquidityParameters.amountY);
} else if (liquidityParameters.tokenY == _wnative && liquidityParameters.amountY == msg.value) {
liquidityParameters.tokenX.safeTransferFrom(msg.sender, address(_LBPair), liquidityParameters.amountX);
_wnativeDepositAndTransfer(address(_LBPair), msg.value);
} else {
revert LBRouter__WrongNativeLiquidityParameters(
address(liquidityParameters.tokenX),
address(liquidityParameters.tokenY),
liquidityParameters.amountX,
liquidityParameters.amountY,
msg.value
);
}
(amountXAdded, amountYAdded, amountXLeft, amountYLeft, depositIds, liquidityMinted) =
_addLiquidity(liquidityParameters, _LBPair);
}
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 = ILBPair(_getLBPairInformation(tokenX, tokenY, binStep, Version.V2_1));
bool isWrongOrder = tokenX != _LBPair.getTokenX();
if (isWrongOrder) (amountXMin, amountYMin) = (amountYMin, amountXMin);
(amountX, amountY) = _removeLiquidity(_LBPair, amountXMin, amountYMin, ids, amounts, to);
if (isWrongOrder) (amountX, amountY) = (amountY, amountX);
}
function removeLiquidityNATIVE(
IERC20 token,
uint16 binStep,
uint256 amountTokenMin,
uint256 amountNATIVEMin,
uint256[] memory ids,
uint256[] memory amounts,
address payable to,
uint256 deadline
) external override ensure(deadline) returns (uint256 amountToken, uint256 amountNATIVE) {
IWNATIVE wnative = _wnative;
ILBPair lbPair = ILBPair(_getLBPairInformation(token, IERC20(wnative), binStep, Version.V2_1));
{
bool isNATIVETokenY = IERC20(wnative) == lbPair.getTokenY();
if (!isNATIVETokenY) {
(amountTokenMin, amountNATIVEMin) = (amountNATIVEMin, amountTokenMin);
}
(uint256 amountX, uint256 amountY) =
_removeLiquidity(lbPair, amountTokenMin, amountNATIVEMin, ids, amounts, address(this));
(amountToken, amountNATIVE) = isNATIVETokenY ? (amountX, amountY) : (amountY, amountX);
}
token.safeTransfer(to, amountToken);
wnative.withdraw(amountNATIVE);
_safeTransferNATIVE(to, amountNATIVE);
}
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
Path memory path,
address to,
uint256 deadline
) external override ensure(deadline) verifyPathValidity(path) returns (uint256 amountOut) {
address[] memory pairs = _getPairs(path.pairBinSteps, path.versions, path.tokenPath);
path.tokenPath[0].safeTransferFrom(msg.sender, pairs[0], amountIn);
amountOut = _swapExactTokensForTokens(amountIn, pairs, path.versions, path.tokenPath, to);
if (amountOutMin > amountOut) revert LBRouter__InsufficientAmountOut(amountOutMin, amountOut);
}
function swapExactTokensForNATIVE(
uint256 amountIn,
uint256 amountOutMinNATIVE,
Path memory path,
address payable to,
uint256 deadline
) external override ensure(deadline) verifyPathValidity(path) returns (uint256 amountOut) {
if (path.tokenPath[path.pairBinSteps.length] != IERC20(_wnative)) {
revert LBRouter__InvalidTokenPath(address(path.tokenPath[path.pairBinSteps.length]));
}
address[] memory pairs = _getPairs(path.pairBinSteps, path.versions, path.tokenPath);
path.tokenPath[0].safeTransferFrom(msg.sender, pairs[0], amountIn);
amountOut = _swapExactTokensForTokens(amountIn, pairs, path.versions, path.tokenPath, address(this));
if (amountOutMinNATIVE > amountOut) revert LBRouter__InsufficientAmountOut(amountOutMinNATIVE, amountOut);
_wnative.withdraw(amountOut);
_safeTransferNATIVE(to, amountOut);
}
function swapExactNATIVEForTokens(uint256 amountOutMin, Path memory path, address to, uint256 deadline)
external
payable
override
ensure(deadline)
verifyPathValidity(path)
returns (uint256 amountOut)
{
if (path.tokenPath[0] != IERC20(_wnative)) revert LBRouter__InvalidTokenPath(address(path.tokenPath[0]));
address[] memory pairs = _getPairs(path.pairBinSteps, path.versions, path.tokenPath);
_wnativeDepositAndTransfer(pairs[0], msg.value);
amountOut = _swapExactTokensForTokens(msg.value, pairs, path.versions, path.tokenPath, to);
if (amountOutMin > amountOut) revert LBRouter__InsufficientAmountOut(amountOutMin, amountOut);
}
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
Path memory path,
address to,
uint256 deadline
) external override ensure(deadline) verifyPathValidity(path) returns (uint256[] memory amountsIn) {
address[] memory pairs = _getPairs(path.pairBinSteps, path.versions, path.tokenPath);
{
amountsIn = _getAmountsIn(path.versions, pairs, path.tokenPath, amountOut);
if (amountsIn[0] > amountInMax) revert LBRouter__MaxAmountInExceeded(amountInMax, amountsIn[0]);
path.tokenPath[0].safeTransferFrom(msg.sender, pairs[0], amountsIn[0]);
uint256 _amountOutReal = _swapTokensForExactTokens(pairs, path.versions, path.tokenPath, amountsIn, to);
if (_amountOutReal < amountOut) revert LBRouter__InsufficientAmountOut(amountOut, _amountOutReal);
}
}
function swapTokensForExactNATIVE(
uint256 amountNATIVEOut,
uint256 amountInMax,
Path memory path,
address payable to,
uint256 deadline
) external override ensure(deadline) verifyPathValidity(path) returns (uint256[] memory amountsIn) {
if (path.tokenPath[path.pairBinSteps.length] != IERC20(_wnative)) {
revert LBRouter__InvalidTokenPath(address(path.tokenPath[path.pairBinSteps.length]));
}
address[] memory pairs = _getPairs(path.pairBinSteps, path.versions, path.tokenPath);
amountsIn = _getAmountsIn(path.versions, pairs, path.tokenPath, amountNATIVEOut);
if (amountsIn[0] > amountInMax) revert LBRouter__MaxAmountInExceeded(amountInMax, amountsIn[0]);
path.tokenPath[0].safeTransferFrom(msg.sender, pairs[0], amountsIn[0]);
uint256 _amountOutReal =
_swapTokensForExactTokens(pairs, path.versions, path.tokenPath, amountsIn, address(this));
if (_amountOutReal < amountNATIVEOut) revert LBRouter__InsufficientAmountOut(amountNATIVEOut, _amountOutReal);
_wnative.withdraw(_amountOutReal);
_safeTransferNATIVE(to, _amountOutReal);
}
function swapNATIVEForExactTokens(uint256 amountOut, Path memory path, address to, uint256 deadline)
external
payable
override
ensure(deadline)
verifyPathValidity(path)
returns (uint256[] memory amountsIn)
{
if (path.tokenPath[0] != IERC20(_wnative)) revert LBRouter__InvalidTokenPath(address(path.tokenPath[0]));
address[] memory pairs = _getPairs(path.pairBinSteps, path.versions, path.tokenPath);
amountsIn = _getAmountsIn(path.versions, pairs, path.tokenPath, amountOut);
if (amountsIn[0] > msg.value) revert LBRouter__MaxAmountInExceeded(msg.value, amountsIn[0]);
_wnativeDepositAndTransfer(pairs[0], amountsIn[0]);
uint256 amountOutReal = _swapTokensForExactTokens(pairs, path.versions, path.tokenPath, amountsIn, to);
if (amountOutReal < amountOut) revert LBRouter__InsufficientAmountOut(amountOut, amountOutReal);
if (msg.value > amountsIn[0]) _safeTransferNATIVE(msg.sender, msg.value - amountsIn[0]);
}
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
Path memory path,
address to,
uint256 deadline
) external override ensure(deadline) verifyPathValidity(path) returns (uint256 amountOut) {
address[] memory pairs = _getPairs(path.pairBinSteps, path.versions, path.tokenPath);
IERC20 targetToken = path.tokenPath[pairs.length];
uint256 balanceBefore = targetToken.balanceOf(to);
path.tokenPath[0].safeTransferFrom(msg.sender, pairs[0], amountIn);
_swapSupportingFeeOnTransferTokens(pairs, path.versions, path.tokenPath, to);
amountOut = targetToken.balanceOf(to) - balanceBefore;
if (amountOutMin > amountOut) revert LBRouter__InsufficientAmountOut(amountOutMin, amountOut);
}
function swapExactTokensForNATIVESupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMinNATIVE,
Path memory path,
address payable to,
uint256 deadline
) external override ensure(deadline) verifyPathValidity(path) returns (uint256 amountOut) {
if (path.tokenPath[path.pairBinSteps.length] != IERC20(_wnative)) {
revert LBRouter__InvalidTokenPath(address(path.tokenPath[path.pairBinSteps.length]));
}
address[] memory pairs = _getPairs(path.pairBinSteps, path.versions, path.tokenPath);
uint256 balanceBefore = _wnative.balanceOf(address(this));
path.tokenPath[0].safeTransferFrom(msg.sender, pairs[0], amountIn);
_swapSupportingFeeOnTransferTokens(pairs, path.versions, path.tokenPath, address(this));
amountOut = _wnative.balanceOf(address(this)) - balanceBefore;
if (amountOutMinNATIVE > amountOut) revert LBRouter__InsufficientAmountOut(amountOutMinNATIVE, amountOut);
_wnative.withdraw(amountOut);
_safeTransferNATIVE(to, amountOut);
}
function swapExactNATIVEForTokensSupportingFeeOnTransferTokens(
uint256 amountOutMin,
Path memory path,
address to,
uint256 deadline
) external payable override ensure(deadline) verifyPathValidity(path) returns (uint256 amountOut) {
if (path.tokenPath[0] != IERC20(_wnative)) revert LBRouter__InvalidTokenPath(address(path.tokenPath[0]));
address[] memory pairs = _getPairs(path.pairBinSteps, path.versions, path.tokenPath);
IERC20 targetToken = path.tokenPath[pairs.length];
uint256 balanceBefore = targetToken.balanceOf(to);
_wnativeDepositAndTransfer(pairs[0], msg.value);
_swapSupportingFeeOnTransferTokens(pairs, path.versions, path.tokenPath, to);
amountOut = targetToken.balanceOf(to) - balanceBefore;
if (amountOutMin > amountOut) revert LBRouter__InsufficientAmountOut(amountOutMin, amountOut);
}
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;
_safeTransferNATIVE(to, amount);
} else {
if (amount == type(uint256).max) amount = token.balanceOf(address(this));
token.safeTransfer(to, amount);
}
}
function sweepLBToken(ILBToken lbToken, address to, uint256[] calldata ids, uint256[] calldata amounts)
external
override
onlyFactoryOwner
{
lbToken.batchTransferFrom(address(this), to, ids, amounts);
}
function _addLiquidity(LiquidityParameters calldata liq, ILBPair pair)
private
ensure(liq.deadline)
returns (
uint256 amountXAdded,
uint256 amountYAdded,
uint256 amountXLeft,
uint256 amountYLeft,
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);
}
bytes32[] memory liquidityConfigs = new bytes32[](liq.deltaIds.length);
depositIds = new uint256[](liq.deltaIds.length);
{
uint256 _activeId = pair.getActiveId();
if (
liq.activeIdDesired + liq.idSlippage < _activeId || _activeId + liq.idSlippage < liq.activeIdDesired
) {
revert LBRouter__IdSlippageCaught(liq.activeIdDesired, liq.idSlippage, _activeId);
}
for (uint256 i; i < liquidityConfigs.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);
liquidityConfigs[i] = LiquidityConfigurations.encodeParams(
uint64(liq.distributionX[i]), uint64(liq.distributionY[i]), uint24(uint256(_id))
);
}
}
bytes32 amountsReceived;
bytes32 amountsLeft;
(amountsReceived, amountsLeft, liquidityMinted) = pair.mint(liq.to, liquidityConfigs, liq.refundTo);
amountXAdded = amountsReceived.decodeX();
amountYAdded = amountsReceived.decodeY();
if (amountXAdded < liq.amountXMin || amountYAdded < liq.amountYMin) {
revert LBRouter__AmountSlippageCaught(liq.amountXMin, amountXAdded, liq.amountYMin, amountYAdded);
}
amountXLeft = amountsLeft.decodeX();
amountYLeft = amountsLeft.decodeY();
}
}
function _getAmountsIn(
Version[] memory versions,
address[] memory pairs,
IERC20[] memory tokenPath,
uint256 amountOut
) private view returns (uint256[] memory amountsIn) {
amountsIn = new uint256[](tokenPath.length);
amountsIn[pairs.length] = amountOut;
for (uint256 i = pairs.length; i != 0; i--) {
IERC20 token = tokenPath[i - 1];
Version version = versions[i - 1];
address pair = pairs[i - 1];
if (version == Version.V1) {
(uint256 reserveIn, uint256 reserveOut,) = IJoePair(pair).getReserves();
if (token > tokenPath[i]) {
(reserveIn, reserveOut) = (reserveOut, reserveIn);
}
uint256 amountOut_ = amountsIn[i];
amountsIn[i - 1] = uint128(amountOut_.getAmountIn(reserveIn, reserveOut));
} else if (version == Version.V2) {
(amountsIn[i - 1],) = _legacyRouter.getSwapIn(
ILBLegacyPair(pair), uint128(amountsIn[i]), ILBLegacyPair(pair).tokenX() == token
);
} else {
(amountsIn[i - 1],,) =
getSwapIn(ILBPair(pair), uint128(amountsIn[i]), ILBPair(pair).getTokenX() == token);
}
}
}
function _removeLiquidity(
ILBPair pair,
uint256 amountXMin,
uint256 amountYMin,
uint256[] memory ids,
uint256[] memory amounts,
address to
) private returns (uint256 amountX, uint256 amountY) {
(bytes32[] memory amountsBurned) = pair.burn(msg.sender, to, ids, amounts);
for (uint256 i; i < amountsBurned.length; ++i) {
amountX += amountsBurned[i].decodeX();
amountY += amountsBurned[i].decodeY();
}
if (amountX < amountXMin || amountY < amountYMin) {
revert LBRouter__AmountSlippageCaught(amountXMin, amountX, amountYMin, amountY);
}
}
function _swapExactTokensForTokens(
uint256 amountIn,
address[] memory pairs,
Version[] memory versions,
IERC20[] memory tokenPath,
address to
) private returns (uint256 amountOut) {
IERC20 token;
Version version;
address recipient;
address pair;
IERC20 tokenNext = tokenPath[0];
amountOut = amountIn;
unchecked {
for (uint256 i; i < pairs.length; ++i) {
pair = pairs[i];
version = versions[i];
token = tokenNext;
tokenNext = tokenPath[i + 1];
recipient = i + 1 == pairs.length ? to : pairs[i + 1];
if (version == Version.V1) {
(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 if (version == Version.V2) {
bool swapForY = tokenNext == ILBLegacyPair(pair).tokenY();
(uint256 amountXOut, uint256 amountYOut) = ILBLegacyPair(pair).swap(swapForY, recipient);
if (swapForY) amountOut = amountYOut;
else amountOut = amountXOut;
} else {
bool swapForY = tokenNext == ILBPair(pair).getTokenY();
(uint256 amountXOut, uint256 amountYOut) = ILBPair(pair).swap(swapForY, recipient).decode();
if (swapForY) amountOut = amountYOut;
else amountOut = amountXOut;
}
}
}
}
function _swapTokensForExactTokens(
address[] memory pairs,
Version[] memory versions,
IERC20[] memory tokenPath,
uint256[] memory amountsIn,
address to
) private returns (uint256 amountOut) {
IERC20 token;
address recipient;
address pair;
Version version;
IERC20 tokenNext = tokenPath[0];
unchecked {
for (uint256 i; i < pairs.length; ++i) {
pair = pairs[i];
version = versions[i];
token = tokenNext;
tokenNext = tokenPath[i + 1];
recipient = i + 1 == pairs.length ? to : pairs[i + 1];
if (version == Version.V1) {
amountOut = amountsIn[i + 1];
if (token < tokenNext) {
IJoePair(pair).swap(0, amountOut, recipient, "");
} else {
IJoePair(pair).swap(amountOut, 0, recipient, "");
}
} else if (version == Version.V2) {
bool swapForY = tokenNext == ILBLegacyPair(pair).tokenY();
(uint256 amountXOut, uint256 amountYOut) = ILBLegacyPair(pair).swap(swapForY, recipient);
if (swapForY) amountOut = amountYOut;
else amountOut = amountXOut;
} else {
bool swapForY = tokenNext == ILBPair(pair).getTokenY();
(uint256 amountXOut, uint256 amountYOut) = ILBPair(pair).swap(swapForY, recipient).decode();
if (swapForY) amountOut = amountYOut;
else amountOut = amountXOut;
}
}
}
}
function _swapSupportingFeeOnTransferTokens(
address[] memory pairs,
Version[] memory versions,
IERC20[] memory tokenPath,
address to
) private {
IERC20 token;
Version version;
address recipient;
address pair;
IERC20 tokenNext = tokenPath[0];
unchecked {
for (uint256 i; i < pairs.length; ++i) {
pair = pairs[i];
version = versions[i];
token = tokenNext;
tokenNext = tokenPath[i + 1];
recipient = i + 1 == pairs.length ? to : pairs[i + 1];
if (version == Version.V1) {
(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 if (version == Version.V2) {
ILBLegacyPair(pair).swap(tokenNext == ILBLegacyPair(pair).tokenY(), recipient);
} else {
ILBPair(pair).swap(tokenNext == ILBPair(pair).getTokenY(), recipient);
}
}
}
}
function _getLBPairInformation(IERC20 tokenX, IERC20 tokenY, uint256 binStep, Version version)
private
view
returns (address lbPair)
{
if (version == Version.V2) {
lbPair = address(_legacyFactory.getLBPairInformation(tokenX, tokenY, binStep).LBPair);
} else {
lbPair = address(_factory.getLBPairInformation(tokenX, tokenY, binStep).LBPair);
}
if (lbPair == address(0)) {
revert LBRouter__PairNotCreated(address(tokenX), address(tokenY), binStep);
}
}
function _getPair(IERC20 tokenX, IERC20 tokenY, uint256 binStep, Version version)
private
view
returns (address pair)
{
if (version == Version.V1) {
pair = _factoryV1.getPair(address(tokenX), address(tokenY));
if (pair == address(0)) revert LBRouter__PairNotCreated(address(tokenX), address(tokenY), binStep);
} else {
pair = address(_getLBPairInformation(tokenX, tokenY, binStep, version));
}
}
function _getPairs(uint256[] memory pairBinSteps, Version[] memory versions, 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(token, tokenNext, pairBinSteps[i], versions[i]);
}
}
}
function _safeTransferNATIVE(address to, uint256 amount) private {
(bool success,) = to.call{value: amount}("");
if (!success) revert LBRouter__FailedToSendNATIVE(to, amount);
}
function _wnativeDepositAndTransfer(address to, uint256 amount) private {
_wnative.deposit{value: amount}();
_wnative.safeTransfer(to, amount);
}
}
文件 24 的 31:LiquidityConfigurations.sol
pragma solidity 0.8.10;
import {PackedUint128Math} from "./PackedUint128Math.sol";
import {Encoded} from "./Encoded.sol";
library LiquidityConfigurations {
using PackedUint128Math for bytes32;
using PackedUint128Math for uint128;
using Encoded for bytes32;
error LiquidityConfigurations__InvalidConfig();
uint256 private constant OFFSET_ID = 0;
uint256 private constant OFFSET_DISTRIBUTION_Y = 24;
uint256 private constant OFFSET_DISTRIBUTION_X = 88;
uint256 private constant PRECISION = 1e18;
function encodeParams(uint64 distributionX, uint64 distributionY, uint24 id)
internal
pure
returns (bytes32 config)
{
config = config.set(distributionX, Encoded.MASK_UINT64, OFFSET_DISTRIBUTION_X);
config = config.set(distributionY, Encoded.MASK_UINT64, OFFSET_DISTRIBUTION_Y);
config = config.set(id, Encoded.MASK_UINT24, OFFSET_ID);
}
function decodeParams(bytes32 config)
internal
pure
returns (uint64 distributionX, uint64 distributionY, uint24 id)
{
distributionX = config.decodeUint64(OFFSET_DISTRIBUTION_X);
distributionY = config.decodeUint64(OFFSET_DISTRIBUTION_Y);
id = config.decodeUint24(OFFSET_ID);
if (uint256(config) > type(uint152).max || distributionX > PRECISION || distributionY > PRECISION) {
revert LiquidityConfigurations__InvalidConfig();
}
}
function getAmountsAndId(bytes32 config, bytes32 amountsIn) internal pure returns (bytes32, uint24) {
(uint64 distributionX, uint64 distributionY, uint24 id) = decodeParams(config);
(uint128 x1, uint128 x2) = amountsIn.decode();
assembly {
x1 := div(mul(x1, distributionX), PRECISION)
x2 := div(mul(x2, distributionY), PRECISION)
}
return (x1.encode(x2), id);
}
}
文件 25 的 31:PackedUint128Math.sol
pragma solidity 0.8.10;
import {Constants} from "../Constants.sol";
library PackedUint128Math {
error PackedUint128Math__AddOverflow();
error PackedUint128Math__SubUnderflow();
error PackedUint128Math__MultiplierTooLarge();
uint256 private constant OFFSET = 128;
uint256 private constant MASK_128 = 0xffffffffffffffffffffffffffffffff;
uint256 private constant MASK_128_PLUS_ONE = MASK_128 + 1;
function encode(uint128 x1, uint128 x2) internal pure returns (bytes32 z) {
assembly {
z := or(and(x1, MASK_128), shl(OFFSET, x2))
}
}
function encodeFirst(uint128 x1) internal pure returns (bytes32 z) {
assembly {
z := and(x1, MASK_128)
}
}
function encodeSecond(uint128 x2) internal pure returns (bytes32 z) {
assembly {
z := shl(OFFSET, x2)
}
}
function encode(uint128 x, bool first) internal pure returns (bytes32 z) {
return first ? encodeFirst(x) : encodeSecond(x);
}
function decode(bytes32 z) internal pure returns (uint128 x1, uint128 x2) {
assembly {
x1 := and(z, MASK_128)
x2 := shr(OFFSET, z)
}
}
function decodeX(bytes32 z) internal pure returns (uint128 x) {
assembly {
x := and(z, MASK_128)
}
}
function decodeY(bytes32 z) internal pure returns (uint128 y) {
assembly {
y := shr(OFFSET, z)
}
}
function decode(bytes32 z, bool first) internal pure returns (uint128 x) {
return first ? decodeX(z) : decodeY(z);
}
function add(bytes32 x, bytes32 y) internal pure returns (bytes32 z) {
assembly {
z := add(x, y)
}
if (z < x || uint128(uint256(z)) < uint128(uint256(x))) {
revert PackedUint128Math__AddOverflow();
}
}
function add(bytes32 x, uint128 y1, uint128 y2) internal pure returns (bytes32) {
return add(x, encode(y1, y2));
}
function sub(bytes32 x, bytes32 y) internal pure returns (bytes32 z) {
assembly {
z := sub(x, y)
}
if (z > x || uint128(uint256(z)) > uint128(uint256(x))) {
revert PackedUint128Math__SubUnderflow();
}
}
function sub(bytes32 x, uint128 y1, uint128 y2) internal pure returns (bytes32) {
return sub(x, encode(y1, y2));
}
function lt(bytes32 x, bytes32 y) internal pure returns (bool) {
(uint128 x1, uint128 x2) = decode(x);
(uint128 y1, uint128 y2) = decode(y);
return x1 < y1 || x2 < y2;
}
function gt(bytes32 x, bytes32 y) internal pure returns (bool) {
(uint128 x1, uint128 x2) = decode(x);
(uint128 y1, uint128 y2) = decode(y);
return x1 > y1 || x2 > y2;
}
function scalarMulDivBasisPointRoundDown(bytes32 x, uint128 multiplier) internal pure returns (bytes32 z) {
if (multiplier == 0) return 0;
uint256 BASIS_POINT_MAX = Constants.BASIS_POINT_MAX;
if (multiplier > BASIS_POINT_MAX) revert PackedUint128Math__MultiplierTooLarge();
(uint128 x1, uint128 x2) = decode(x);
assembly {
x1 := div(mul(x1, multiplier), BASIS_POINT_MAX)
x2 := div(mul(x2, multiplier), BASIS_POINT_MAX)
}
return encode(x1, x2);
}
}
文件 26 的 31:PairParameterHelper.sol
pragma solidity 0.8.10;
import {Constants} from "./Constants.sol";
import {SafeCast} from "./math/SafeCast.sol";
import {Encoded} from "./math/Encoded.sol";
library PairParameterHelper {
using SafeCast for uint256;
using Encoded for bytes32;
error PairParametersHelper__InvalidParameter();
uint256 internal constant OFFSET_BASE_FACTOR = 0;
uint256 internal constant OFFSET_FILTER_PERIOD = 16;
uint256 internal constant OFFSET_DECAY_PERIOD = 28;
uint256 internal constant OFFSET_REDUCTION_FACTOR = 40;
uint256 internal constant OFFSET_VAR_FEE_CONTROL = 54;
uint256 internal constant OFFSET_PROTOCOL_SHARE = 78;
uint256 internal constant OFFSET_MAX_VOL_ACC = 92;
uint256 internal constant OFFSET_VOL_ACC = 112;
uint256 internal constant OFFSET_VOL_REF = 132;
uint256 internal constant OFFSET_ID_REF = 152;
uint256 internal constant OFFSET_TIME_LAST_UPDATE = 176;
uint256 internal constant OFFSET_ORACLE_ID = 216;
uint256 internal constant OFFSET_ACTIVE_ID = 232;
uint256 internal constant MASK_STATIC_PARAMETER = 0xffffffffffffffffffffffffffff;
function getBaseFactor(bytes32 params) internal pure returns (uint16 baseFactor) {
baseFactor = params.decodeUint16(OFFSET_BASE_FACTOR);
}
function getFilterPeriod(bytes32 params) internal pure returns (uint16 filterPeriod) {
filterPeriod = params.decodeUint12(OFFSET_FILTER_PERIOD);
}
function getDecayPeriod(bytes32 params) internal pure returns (uint16 decayPeriod) {
decayPeriod = params.decodeUint12(OFFSET_DECAY_PERIOD);
}
function getReductionFactor(bytes32 params) internal pure returns (uint16 reductionFactor) {
reductionFactor = params.decodeUint14(OFFSET_REDUCTION_FACTOR);
}
function getVariableFeeControl(bytes32 params) internal pure returns (uint24 variableFeeControl) {
variableFeeControl = params.decodeUint24(OFFSET_VAR_FEE_CONTROL);
}
function getProtocolShare(bytes32 params) internal pure returns (uint16 protocolShare) {
protocolShare = params.decodeUint14(OFFSET_PROTOCOL_SHARE);
}
function getMaxVolatilityAccumulator(bytes32 params) internal pure returns (uint24 maxVolatilityAccumulator) {
maxVolatilityAccumulator = params.decodeUint20(OFFSET_MAX_VOL_ACC);
}
function getVolatilityAccumulator(bytes32 params) internal pure returns (uint24 volatilityAccumulator) {
volatilityAccumulator = params.decodeUint20(OFFSET_VOL_ACC);
}
function getVolatilityReference(bytes32 params) internal pure returns (uint24 volatilityReference) {
volatilityReference = params.decodeUint20(OFFSET_VOL_REF);
}
function getIdReference(bytes32 params) internal pure returns (uint24 idReference) {
idReference = params.decodeUint24(OFFSET_ID_REF);
}
function getTimeOfLastUpdate(bytes32 params) internal pure returns (uint40 timeOflastUpdate) {
timeOflastUpdate = params.decodeUint40(OFFSET_TIME_LAST_UPDATE);
}
function getOracleId(bytes32 params) internal pure returns (uint16 oracleId) {
oracleId = params.decodeUint16(OFFSET_ORACLE_ID);
}
function getActiveId(bytes32 params) internal pure returns (uint24 activeId) {
activeId = params.decodeUint24(OFFSET_ACTIVE_ID);
}
function getDeltaId(bytes32 params, uint24 activeId) internal pure returns (uint24) {
uint24 id = getActiveId(params);
unchecked {
return activeId > id ? activeId - id : id - activeId;
}
}
function getBaseFee(bytes32 params, uint16 binStep) internal pure returns (uint256) {
unchecked {
return uint256(getBaseFactor(params)) * binStep * 1e10;
}
}
function getVariableFee(bytes32 params, uint16 binStep) internal pure returns (uint256 variableFee) {
uint256 variableFeeControl = getVariableFeeControl(params);
if (variableFeeControl != 0) {
unchecked {
uint256 prod = uint256(getVolatilityAccumulator(params)) * binStep;
variableFee = (prod * prod * variableFeeControl + 99) / 100;
}
}
}
function getTotalFee(bytes32 params, uint16 binStep) internal pure returns (uint128) {
unchecked {
return (getBaseFee(params, binStep) + getVariableFee(params, binStep)).safe128();
}
}
function setOracleId(bytes32 params, uint16 oracleId) internal pure returns (bytes32) {
return params.set(oracleId, Encoded.MASK_UINT16, OFFSET_ORACLE_ID);
}
function setVolatilityReference(bytes32 params, uint24 volRef) internal pure returns (bytes32) {
if (volRef > Encoded.MASK_UINT20) revert PairParametersHelper__InvalidParameter();
return params.set(volRef, Encoded.MASK_UINT20, OFFSET_VOL_REF);
}
function setVolatilityAccumulator(bytes32 params, uint24 volAcc) internal pure returns (bytes32) {
if (volAcc > Encoded.MASK_UINT20) revert PairParametersHelper__InvalidParameter();
return params.set(volAcc, Encoded.MASK_UINT20, OFFSET_VOL_ACC);
}
function setActiveId(bytes32 params, uint24 activeId) internal pure returns (bytes32 newParams) {
return params.set(activeId, Encoded.MASK_UINT24, OFFSET_ACTIVE_ID);
}
function setStaticFeeParameters(
bytes32 params,
uint16 baseFactor,
uint16 filterPeriod,
uint16 decayPeriod,
uint16 reductionFactor,
uint24 variableFeeControl,
uint16 protocolShare,
uint24 maxVolatilityAccumulator
) internal pure returns (bytes32 newParams) {
if (
filterPeriod > decayPeriod || decayPeriod > Encoded.MASK_UINT12
|| reductionFactor > Constants.BASIS_POINT_MAX || protocolShare > Constants.MAX_PROTOCOL_SHARE
|| maxVolatilityAccumulator > Encoded.MASK_UINT20
) revert PairParametersHelper__InvalidParameter();
newParams = newParams.set(baseFactor, Encoded.MASK_UINT16, OFFSET_BASE_FACTOR);
newParams = newParams.set(filterPeriod, Encoded.MASK_UINT12, OFFSET_FILTER_PERIOD);
newParams = newParams.set(decayPeriod, Encoded.MASK_UINT12, OFFSET_DECAY_PERIOD);
newParams = newParams.set(reductionFactor, Encoded.MASK_UINT14, OFFSET_REDUCTION_FACTOR);
newParams = newParams.set(variableFeeControl, Encoded.MASK_UINT24, OFFSET_VAR_FEE_CONTROL);
newParams = newParams.set(protocolShare, Encoded.MASK_UINT14, OFFSET_PROTOCOL_SHARE);
newParams = newParams.set(maxVolatilityAccumulator, Encoded.MASK_UINT20, OFFSET_MAX_VOL_ACC);
return params.set(uint256(newParams), MASK_STATIC_PARAMETER, 0);
}
function updateIdReference(bytes32 params) internal pure returns (bytes32 newParams) {
uint24 activeId = getActiveId(params);
return params.set(activeId, Encoded.MASK_UINT24, OFFSET_ID_REF);
}
function updateTimeOfLastUpdate(bytes32 params) internal view returns (bytes32 newParams) {
uint40 currentTime = block.timestamp.safe40();
return params.set(currentTime, Encoded.MASK_UINT40, OFFSET_TIME_LAST_UPDATE);
}
function updateVolatilityReference(bytes32 params) internal pure returns (bytes32) {
uint256 volAcc = getVolatilityAccumulator(params);
uint256 reductionFactor = getReductionFactor(params);
uint24 volRef;
unchecked {
volRef = uint24(volAcc * reductionFactor / Constants.BASIS_POINT_MAX);
}
return setVolatilityReference(params, volRef);
}
function updateVolatilityAccumulator(bytes32 params, uint24 activeId) internal pure returns (bytes32) {
uint256 idReference = getIdReference(params);
uint256 deltaId;
uint256 volAcc;
unchecked {
deltaId = activeId > idReference ? activeId - idReference : idReference - activeId;
volAcc = (uint256(getVolatilityReference(params)) + deltaId * Constants.BASIS_POINT_MAX);
}
uint256 maxVolAcc = getMaxVolatilityAccumulator(params);
volAcc = volAcc > maxVolAcc ? maxVolAcc : volAcc;
return setVolatilityAccumulator(params, uint24(volAcc));
}
function updateReferences(bytes32 params) internal view returns (bytes32) {
uint256 dt = block.timestamp - getTimeOfLastUpdate(params);
if (dt >= getFilterPeriod(params)) {
params = updateIdReference(params);
params = dt < getDecayPeriod(params) ? updateVolatilityReference(params) : setVolatilityReference(params, 0);
}
return updateTimeOfLastUpdate(params);
}
function updateVolatilityParameters(bytes32 params, uint24 activeId) internal view returns (bytes32) {
params = updateReferences(params);
return updateVolatilityAccumulator(params, activeId);
}
}
文件 27 的 31:PriceHelper.sol
pragma solidity 0.8.10;
import {Uint128x128Math} from "./math/Uint128x128Math.sol";
import {Uint256x256Math} from "./math/Uint256x256Math.sol";
import {SafeCast} from "./math/SafeCast.sol";
import {Constants} from "./Constants.sol";
library PriceHelper {
using Uint128x128Math for uint256;
using Uint256x256Math for uint256;
using SafeCast for uint256;
int256 private constant REAL_ID_SHIFT = 1 << 23;
function getPriceFromId(uint24 id, uint16 binStep) internal pure returns (uint256 price) {
uint256 base = getBase(binStep);
int256 exponent = getExponent(id);
price = base.pow(exponent);
}
function getIdFromPrice(uint256 price, uint16 binStep) internal pure returns (uint24 id) {
uint256 base = getBase(binStep);
int256 realId = price.log2() / base.log2();
unchecked {
id = uint256(REAL_ID_SHIFT + realId).safe24();
}
}
function getBase(uint16 binStep) internal pure returns (uint256) {
unchecked {
return Constants.SCALE + (uint256(binStep) << Constants.SCALE_OFFSET) / Constants.BASIS_POINT_MAX;
}
}
function getExponent(uint24 id) internal pure returns (int256) {
unchecked {
return int256(uint256(id)) - REAL_ID_SHIFT;
}
}
function convertDecimalPriceTo128x128(uint256 price) internal pure returns (uint256) {
return price.shiftDivRoundDown(Constants.SCALE_OFFSET, Constants.PRECISION);
}
function convert128x128PriceToDecimal(uint256 price128x128) internal pure returns (uint256) {
return price128x128.mulShiftRoundDown(Constants.PRECISION, Constants.SCALE_OFFSET);
}
}
文件 28 的 31:SafeCast.sol
pragma solidity 0.8.10;
library SafeCast {
error SafeCast__Exceeds248Bits();
error SafeCast__Exceeds240Bits();
error SafeCast__Exceeds232Bits();
error SafeCast__Exceeds224Bits();
error SafeCast__Exceeds216Bits();
error SafeCast__Exceeds208Bits();
error SafeCast__Exceeds200Bits();
error SafeCast__Exceeds192Bits();
error SafeCast__Exceeds184Bits();
error SafeCast__Exceeds176Bits();
error SafeCast__Exceeds168Bits();
error SafeCast__Exceeds160Bits();
error SafeCast__Exceeds152Bits();
error SafeCast__Exceeds144Bits();
error SafeCast__Exceeds136Bits();
error SafeCast__Exceeds128Bits();
error SafeCast__Exceeds120Bits();
error SafeCast__Exceeds112Bits();
error SafeCast__Exceeds104Bits();
error SafeCast__Exceeds96Bits();
error SafeCast__Exceeds88Bits();
error SafeCast__Exceeds80Bits();
error SafeCast__Exceeds72Bits();
error SafeCast__Exceeds64Bits();
error SafeCast__Exceeds56Bits();
error SafeCast__Exceeds48Bits();
error SafeCast__Exceeds40Bits();
error SafeCast__Exceeds32Bits();
error SafeCast__Exceeds24Bits();
error SafeCast__Exceeds16Bits();
error SafeCast__Exceeds8Bits();
function safe248(uint256 x) internal pure returns (uint248 y) {
if ((y = uint248(x)) != x) revert SafeCast__Exceeds248Bits();
}
function safe240(uint256 x) internal pure returns (uint240 y) {
if ((y = uint240(x)) != x) revert SafeCast__Exceeds240Bits();
}
function safe232(uint256 x) internal pure returns (uint232 y) {
if ((y = uint232(x)) != x) revert SafeCast__Exceeds232Bits();
}
function safe224(uint256 x) internal pure returns (uint224 y) {
if ((y = uint224(x)) != x) revert SafeCast__Exceeds224Bits();
}
function safe216(uint256 x) internal pure returns (uint216 y) {
if ((y = uint216(x)) != x) revert SafeCast__Exceeds216Bits();
}
function safe208(uint256 x) internal pure returns (uint208 y) {
if ((y = uint208(x)) != x) revert SafeCast__Exceeds208Bits();
}
function safe200(uint256 x) internal pure returns (uint200 y) {
if ((y = uint200(x)) != x) revert SafeCast__Exceeds200Bits();
}
function safe192(uint256 x) internal pure returns (uint192 y) {
if ((y = uint192(x)) != x) revert SafeCast__Exceeds192Bits();
}
function safe184(uint256 x) internal pure returns (uint184 y) {
if ((y = uint184(x)) != x) revert SafeCast__Exceeds184Bits();
}
function safe176(uint256 x) internal pure returns (uint176 y) {
if ((y = uint176(x)) != x) revert SafeCast__Exceeds176Bits();
}
function safe168(uint256 x) internal pure returns (uint168 y) {
if ((y = uint168(x)) != x) revert SafeCast__Exceeds168Bits();
}
function safe160(uint256 x) internal pure returns (uint160 y) {
if ((y = uint160(x)) != x) revert SafeCast__Exceeds160Bits();
}
function safe152(uint256 x) internal pure returns (uint152 y) {
if ((y = uint152(x)) != x) revert SafeCast__Exceeds152Bits();
}
function safe144(uint256 x) internal pure returns (uint144 y) {
if ((y = uint144(x)) != x) revert SafeCast__Exceeds144Bits();
}
function safe136(uint256 x) internal pure returns (uint136 y) {
if ((y = uint136(x)) != x) revert SafeCast__Exceeds136Bits();
}
function safe128(uint256 x) internal pure returns (uint128 y) {
if ((y = uint128(x)) != x) revert SafeCast__Exceeds128Bits();
}
function safe120(uint256 x) internal pure returns (uint120 y) {
if ((y = uint120(x)) != x) revert SafeCast__Exceeds120Bits();
}
function safe112(uint256 x) internal pure returns (uint112 y) {
if ((y = uint112(x)) != x) revert SafeCast__Exceeds112Bits();
}
function safe104(uint256 x) internal pure returns (uint104 y) {
if ((y = uint104(x)) != x) revert SafeCast__Exceeds104Bits();
}
function safe96(uint256 x) internal pure returns (uint96 y) {
if ((y = uint96(x)) != x) revert SafeCast__Exceeds96Bits();
}
function safe88(uint256 x) internal pure returns (uint88 y) {
if ((y = uint88(x)) != x) revert SafeCast__Exceeds88Bits();
}
function safe80(uint256 x) internal pure returns (uint80 y) {
if ((y = uint80(x)) != x) revert SafeCast__Exceeds80Bits();
}
function safe72(uint256 x) internal pure returns (uint72 y) {
if ((y = uint72(x)) != x) revert SafeCast__Exceeds72Bits();
}
function safe64(uint256 x) internal pure returns (uint64 y) {
if ((y = uint64(x)) != x) revert SafeCast__Exceeds64Bits();
}
function safe56(uint256 x) internal pure returns (uint56 y) {
if ((y = uint56(x)) != x) revert SafeCast__Exceeds56Bits();
}
function safe48(uint256 x) internal pure returns (uint48 y) {
if ((y = uint48(x)) != x) revert SafeCast__Exceeds48Bits();
}
function safe40(uint256 x) internal pure returns (uint40 y) {
if ((y = uint40(x)) != x) revert SafeCast__Exceeds40Bits();
}
function safe32(uint256 x) internal pure returns (uint32 y) {
if ((y = uint32(x)) != x) revert SafeCast__Exceeds32Bits();
}
function safe24(uint256 x) internal pure returns (uint24 y) {
if ((y = uint24(x)) != x) revert SafeCast__Exceeds24Bits();
}
function safe16(uint256 x) internal pure returns (uint16 y) {
if ((y = uint16(x)) != x) revert SafeCast__Exceeds16Bits();
}
function safe8(uint256 x) internal pure returns (uint8 y) {
if ((y = uint8(x)) != x) revert SafeCast__Exceeds8Bits();
}
}
文件 29 的 31:TokenHelper.sol
pragma solidity 0.8.10;
import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";
import {AddressHelper} from "./AddressHelper.sol";
library TokenHelper {
using AddressHelper for address;
error TokenHelper__TransferFailed();
function safeTransferFrom(IERC20 token, address owner, address recipient, uint256 amount) internal {
bytes memory data = abi.encodeWithSelector(token.transferFrom.selector, owner, recipient, amount);
bytes memory returnData = address(token).callAndCatch(data);
if (returnData.length > 0 && !abi.decode(returnData, (bool))) revert TokenHelper__TransferFailed();
}
function safeTransfer(IERC20 token, address recipient, uint256 amount) internal {
bytes memory data = abi.encodeWithSelector(token.transfer.selector, recipient, amount);
bytes memory returnData = address(token).callAndCatch(data);
if (returnData.length > 0 && !abi.decode(returnData, (bool))) revert TokenHelper__TransferFailed();
}
}
文件 30 的 31:Uint128x128Math.sol
pragma solidity 0.8.10;
import {Constants} from "../Constants.sol";
import {BitMath} from "./BitMath.sol";
library Uint128x128Math {
using BitMath for uint256;
error Uint128x128Math__LogUnderflow();
error Uint128x128Math__PowUnderflow(uint256 x, int256 y);
uint256 constant LOG_SCALE_OFFSET = 127;
uint256 constant LOG_SCALE = 1 << LOG_SCALE_OFFSET;
uint256 constant LOG_SCALE_SQUARED = LOG_SCALE * LOG_SCALE;
function log2(uint256 x) internal pure returns (int256 result) {
if (x == 1) return -128;
if (x == 0) revert Uint128x128Math__LogUnderflow();
x >>= 1;
unchecked {
int256 sign;
if (x >= LOG_SCALE) {
sign = 1;
} else {
sign = -1;
x = LOG_SCALE_SQUARED / x;
}
uint256 n = (x >> LOG_SCALE_OFFSET).mostSignificantBit();
result = int256(n) << LOG_SCALE_OFFSET;
uint256 y = x >> n;
if (y != LOG_SCALE) {
for (int256 delta = int256(1 << (LOG_SCALE_OFFSET - 1)); delta > 0; delta >>= 1) {
y = (y * y) >> LOG_SCALE_OFFSET;
if (y >= 1 << (LOG_SCALE_OFFSET + 1)) {
result += delta;
y >>= 1;
}
}
}
result = (result * sign) << 1;
}
}
function pow(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 squared := x
if gt(x, 0xffffffffffffffffffffffffffffffff) {
squared := div(not(0), squared)
invert := iszero(invert)
}
if and(absY, 0x1) { result := shr(128, mul(result, squared)) }
squared := shr(128, mul(squared, squared))
if and(absY, 0x2) { result := shr(128, mul(result, squared)) }
squared := shr(128, mul(squared, squared))
if and(absY, 0x4) { result := shr(128, mul(result, squared)) }
squared := shr(128, mul(squared, squared))
if and(absY, 0x8) { result := shr(128, mul(result, squared)) }
squared := shr(128, mul(squared, squared))
if and(absY, 0x10) { result := shr(128, mul(result, squared)) }
squared := shr(128, mul(squared, squared))
if and(absY, 0x20) { result := shr(128, mul(result, squared)) }
squared := shr(128, mul(squared, squared))
if and(absY, 0x40) { result := shr(128, mul(result, squared)) }
squared := shr(128, mul(squared, squared))
if and(absY, 0x80) { result := shr(128, mul(result, squared)) }
squared := shr(128, mul(squared, squared))
if and(absY, 0x100) { result := shr(128, mul(result, squared)) }
squared := shr(128, mul(squared, squared))
if and(absY, 0x200) { result := shr(128, mul(result, squared)) }
squared := shr(128, mul(squared, squared))
if and(absY, 0x400) { result := shr(128, mul(result, squared)) }
squared := shr(128, mul(squared, squared))
if and(absY, 0x800) { result := shr(128, mul(result, squared)) }
squared := shr(128, mul(squared, squared))
if and(absY, 0x1000) { result := shr(128, mul(result, squared)) }
squared := shr(128, mul(squared, squared))
if and(absY, 0x2000) { result := shr(128, mul(result, squared)) }
squared := shr(128, mul(squared, squared))
if and(absY, 0x4000) { result := shr(128, mul(result, squared)) }
squared := shr(128, mul(squared, squared))
if and(absY, 0x8000) { result := shr(128, mul(result, squared)) }
squared := shr(128, mul(squared, squared))
if and(absY, 0x10000) { result := shr(128, mul(result, squared)) }
squared := shr(128, mul(squared, squared))
if and(absY, 0x20000) { result := shr(128, mul(result, squared)) }
squared := shr(128, mul(squared, squared))
if and(absY, 0x40000) { result := shr(128, mul(result, squared)) }
squared := shr(128, mul(squared, squared))
if and(absY, 0x80000) { result := shr(128, mul(result, squared)) }
}
}
if (result == 0) revert Uint128x128Math__PowUnderflow(x, y);
return invert ? type(uint256).max / result : result;
}
}
文件 31 的 31:Uint256x256Math.sol
pragma solidity 0.8.10;
library Uint256x256Math {
error Uint256x256Math__MulShiftOverflow();
error Uint256x256Math__MulDivOverflow();
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);
}
function mulDivRoundUp(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
result = mulDivRoundDown(x, y, denominator);
if (mulmod(x, y, denominator) != 0) result += 1;
}
function mulShiftRoundDown(uint256 x, uint256 y, uint8 offset) internal pure returns (uint256 result) {
(uint256 prod0, uint256 prod1) = _getMulProds(x, y);
if (prod0 != 0) result = prod0 >> offset;
if (prod1 != 0) {
if (prod1 >= 1 << offset) revert Uint256x256Math__MulShiftOverflow();
unchecked {
result += prod1 << (256 - offset);
}
}
}
function mulShiftRoundUp(uint256 x, uint256 y, uint8 offset) internal pure returns (uint256 result) {
result = mulShiftRoundDown(x, y, offset);
if (mulmod(x, y, 1 << offset) != 0) result += 1;
}
function shiftDivRoundDown(uint256 x, uint8 offset, uint256 denominator) internal pure returns (uint256 result) {
uint256 prod0;
uint256 prod1;
prod0 = x << offset;
unchecked {
prod1 = x >> (256 - offset);
}
return _getEndOfDivRoundDown(x, 1 << offset, denominator, prod0, prod1);
}
function shiftDivRoundUp(uint256 x, uint8 offset, uint256 denominator) internal pure returns (uint256 result) {
result = shiftDivRoundDown(x, offset, denominator);
if (mulmod(x, 1 << offset, denominator) != 0) result += 1;
}
function _getMulProds(uint256 x, uint256 y) private pure returns (uint256 prod0, uint256 prod1) {
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
}
function _getEndOfDivRoundDown(uint256 x, uint256 y, uint256 denominator, uint256 prod0, uint256 prod1)
private
pure
returns (uint256 result)
{
if (prod1 == 0) {
unchecked {
result = prod0 / denominator;
}
} else {
if (prod1 >= denominator) revert Uint256x256Math__MulDivOverflow();
uint256 remainder;
assembly {
remainder := mulmod(x, y, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
unchecked {
uint256 lpotdod = denominator & (~denominator + 1);
assembly {
denominator := div(denominator, lpotdod)
prod0 := div(prod0, lpotdod)
lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)
}
prod0 |= prod1 * lpotdod;
uint256 inverse = (3 * denominator) ^ 2;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
result = prod0 * inverse;
}
}
}
}
{
"compilationTarget": {
"src/LBRouter.sol": "LBRouter"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 800
},
"remappings": [
":ds-test/=lib/forge-std/lib/ds-test/src/",
":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
":forge-std/=lib/forge-std/src/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/",
":openzeppelin/=lib/openzeppelin-contracts/contracts/"
]
}
[{"inputs":[{"internalType":"contract ILBFactory","name":"factory","type":"address"},{"internalType":"contract IJoeFactory","name":"factoryV1","type":"address"},{"internalType":"contract ILBLegacyFactory","name":"legacyFactory","type":"address"},{"internalType":"contract ILBLegacyRouter","name":"legacyRouter","type":"address"},{"internalType":"contract IWNATIVE","name":"wnative","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressHelper__CallFailed","type":"error"},{"inputs":[],"name":"AddressHelper__NonContract","type":"error"},{"inputs":[],"name":"JoeLibrary__InsufficientAmount","type":"error"},{"inputs":[],"name":"JoeLibrary__InsufficientLiquidity","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountSlippage","type":"uint256"}],"name":"LBRouter__AmountSlippageBPTooBig","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__FailedToSendNATIVE","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":[{"internalType":"uint256","name":"version","type":"uint256"}],"name":"LBRouter__InvalidVersion","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__SenderIsNotWNATIVE","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__WrongNativeLiquidityParameters","type":"error"},{"inputs":[],"name":"LBRouter__WrongTokenOrder","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":"address","name":"refundTo","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct ILBRouter.LiquidityParameters","name":"liquidityParameters","type":"tuple"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amountXAdded","type":"uint256"},{"internalType":"uint256","name":"amountYAdded","type":"uint256"},{"internalType":"uint256","name":"amountXLeft","type":"uint256"},{"internalType":"uint256","name":"amountYLeft","type":"uint256"},{"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":"address","name":"refundTo","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct ILBRouter.LiquidityParameters","name":"liquidityParameters","type":"tuple"}],"name":"addLiquidityNATIVE","outputs":[{"internalType":"uint256","name":"amountXAdded","type":"uint256"},{"internalType":"uint256","name":"amountYAdded","type":"uint256"},{"internalType":"uint256","name":"amountXLeft","type":"uint256"},{"internalType":"uint256","name":"amountYLeft","type":"uint256"},{"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":"getFactory","outputs":[{"internalType":"contract ILBFactory","name":"lbFactory","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ILBPair","name":"pair","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"}],"name":"getIdFromPrice","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLegacyFactory","outputs":[{"internalType":"contract ILBLegacyFactory","name":"legacyLBfactory","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLegacyRouter","outputs":[{"internalType":"contract ILBLegacyRouter","name":"legacyRouter","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ILBPair","name":"pair","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":"pair","type":"address"},{"internalType":"uint128","name":"amountOut","type":"uint128"},{"internalType":"bool","name":"swapForY","type":"bool"}],"name":"getSwapIn","outputs":[{"internalType":"uint128","name":"amountIn","type":"uint128"},{"internalType":"uint128","name":"amountOutLeft","type":"uint128"},{"internalType":"uint128","name":"fee","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ILBPair","name":"pair","type":"address"},{"internalType":"uint128","name":"amountIn","type":"uint128"},{"internalType":"bool","name":"swapForY","type":"bool"}],"name":"getSwapOut","outputs":[{"internalType":"uint128","name":"amountInLeft","type":"uint128"},{"internalType":"uint128","name":"amountOut","type":"uint128"},{"internalType":"uint128","name":"fee","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getV1Factory","outputs":[{"internalType":"contract IJoeFactory","name":"factoryV1","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWNATIVE","outputs":[{"internalType":"contract IWNATIVE","name":"wnative","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":"amountNATIVEMin","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":"removeLiquidityNATIVE","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountNATIVE","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"components":[{"internalType":"uint256[]","name":"pairBinSteps","type":"uint256[]"},{"internalType":"enum ILBRouter.Version[]","name":"versions","type":"uint8[]"},{"internalType":"contract IERC20[]","name":"tokenPath","type":"address[]"}],"internalType":"struct ILBRouter.Path","name":"path","type":"tuple"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactNATIVEForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"components":[{"internalType":"uint256[]","name":"pairBinSteps","type":"uint256[]"},{"internalType":"enum ILBRouter.Version[]","name":"versions","type":"uint8[]"},{"internalType":"contract IERC20[]","name":"tokenPath","type":"address[]"}],"internalType":"struct ILBRouter.Path","name":"path","type":"tuple"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactNATIVEForTokensSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinNATIVE","type":"uint256"},{"components":[{"internalType":"uint256[]","name":"pairBinSteps","type":"uint256[]"},{"internalType":"enum ILBRouter.Version[]","name":"versions","type":"uint8[]"},{"internalType":"contract IERC20[]","name":"tokenPath","type":"address[]"}],"internalType":"struct ILBRouter.Path","name":"path","type":"tuple"},{"internalType":"address payable","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForNATIVE","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinNATIVE","type":"uint256"},{"components":[{"internalType":"uint256[]","name":"pairBinSteps","type":"uint256[]"},{"internalType":"enum ILBRouter.Version[]","name":"versions","type":"uint8[]"},{"internalType":"contract IERC20[]","name":"tokenPath","type":"address[]"}],"internalType":"struct ILBRouter.Path","name":"path","type":"tuple"},{"internalType":"address payable","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForNATIVESupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"components":[{"internalType":"uint256[]","name":"pairBinSteps","type":"uint256[]"},{"internalType":"enum ILBRouter.Version[]","name":"versions","type":"uint8[]"},{"internalType":"contract IERC20[]","name":"tokenPath","type":"address[]"}],"internalType":"struct ILBRouter.Path","name":"path","type":"tuple"},{"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"},{"components":[{"internalType":"uint256[]","name":"pairBinSteps","type":"uint256[]"},{"internalType":"enum ILBRouter.Version[]","name":"versions","type":"uint8[]"},{"internalType":"contract IERC20[]","name":"tokenPath","type":"address[]"}],"internalType":"struct ILBRouter.Path","name":"path","type":"tuple"},{"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":"amountOut","type":"uint256"},{"components":[{"internalType":"uint256[]","name":"pairBinSteps","type":"uint256[]"},{"internalType":"enum ILBRouter.Version[]","name":"versions","type":"uint8[]"},{"internalType":"contract IERC20[]","name":"tokenPath","type":"address[]"}],"internalType":"struct ILBRouter.Path","name":"path","type":"tuple"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapNATIVEForExactTokens","outputs":[{"internalType":"uint256[]","name":"amountsIn","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountNATIVEOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"components":[{"internalType":"uint256[]","name":"pairBinSteps","type":"uint256[]"},{"internalType":"enum ILBRouter.Version[]","name":"versions","type":"uint8[]"},{"internalType":"contract IERC20[]","name":"tokenPath","type":"address[]"}],"internalType":"struct ILBRouter.Path","name":"path","type":"tuple"},{"internalType":"address payable","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactNATIVE","outputs":[{"internalType":"uint256[]","name":"amountsIn","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"components":[{"internalType":"uint256[]","name":"pairBinSteps","type":"uint256[]"},{"internalType":"enum ILBRouter.Version[]","name":"versions","type":"uint8[]"},{"internalType":"contract IERC20[]","name":"tokenPath","type":"address[]"}],"internalType":"struct ILBRouter.Path","name":"path","type":"tuple"},{"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"},{"stateMutability":"payable","type":"receive"}]