Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 24 from a total of 24 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Create LB Pair | 20937129 | 429 days ago | IN | 0 ETH | 0.00247086 | ||||
| Create LB Pair | 20930926 | 430 days ago | IN | 0 ETH | 0.00320149 | ||||
| Create LB Pair | 19747661 | 595 days ago | IN | 0 ETH | 0.00235773 | ||||
| Create LB Pair | 19454557 | 636 days ago | IN | 0 ETH | 0.00697967 | ||||
| Create LB Pair | 19263674 | 663 days ago | IN | 0 ETH | 0.00882698 | ||||
| Create LB Pair | 19241423 | 666 days ago | IN | 0 ETH | 0.00956852 | ||||
| Create LB Pair | 19224607 | 669 days ago | IN | 0 ETH | 0.0052047 | ||||
| Create LB Pair | 18635040 | 751 days ago | IN | 0 ETH | 0.01064246 | ||||
| Create LB Pair | 18607685 | 755 days ago | IN | 0 ETH | 0.00604495 | ||||
| Create LB Pair | 18580292 | 759 days ago | IN | 0 ETH | 0.00958718 | ||||
| Create LB Pair | 18552649 | 763 days ago | IN | 0 ETH | 0.0055713 | ||||
| Create LB Pair | 18522555 | 767 days ago | IN | 0 ETH | 0.00735596 | ||||
| Create LB Pair | 18493587 | 771 days ago | IN | 0 ETH | 0.00632355 | ||||
| Set Pending Owne... | 17821282 | 865 days ago | IN | 0 ETH | 0.00163959 | ||||
| Set Preset | 17821282 | 865 days ago | IN | 0 ETH | 0.00354994 | ||||
| Set Preset | 17821282 | 865 days ago | IN | 0 ETH | 0.00354952 | ||||
| Set Preset | 17821282 | 865 days ago | IN | 0 ETH | 0.00354952 | ||||
| Set Preset | 17821282 | 865 days ago | IN | 0 ETH | 0.00354952 | ||||
| Set Preset | 17821282 | 865 days ago | IN | 0 ETH | 0.00354952 | ||||
| Set Preset | 17821282 | 865 days ago | IN | 0 ETH | 0.00354952 | ||||
| Set Preset | 17821282 | 865 days ago | IN | 0 ETH | 0.00354994 | ||||
| Set Preset | 17821282 | 865 days ago | IN | 0 ETH | 0.00354952 | ||||
| Set Preset | 17821282 | 865 days ago | IN | 0 ETH | 0.00414046 | ||||
| Set LB Pair Impl... | 17821282 | 865 days ago | IN | 0 ETH | 0.00175777 |
Latest 15 internal transactions
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x6100613d | 20937129 | 429 days ago | Contract Creation | 0 ETH | |||
| 0x6100613d | 20930926 | 430 days ago | Contract Creation | 0 ETH | |||
| 0x6100613d | 19747661 | 595 days ago | Contract Creation | 0 ETH | |||
| 0x6100613d | 19454557 | 636 days ago | Contract Creation | 0 ETH | |||
| 0x6100613d | 19263674 | 663 days ago | Contract Creation | 0 ETH | |||
| 0x6100613d | 19241423 | 666 days ago | Contract Creation | 0 ETH | |||
| 0x6100613d | 19224607 | 669 days ago | Contract Creation | 0 ETH | |||
| 0x6100613d | 18635040 | 751 days ago | Contract Creation | 0 ETH | |||
| 0x6100613d | 18607685 | 755 days ago | Contract Creation | 0 ETH | |||
| 0x6100613d | 18580292 | 759 days ago | Contract Creation | 0 ETH | |||
| 0x6100613d | 18552649 | 763 days ago | Contract Creation | 0 ETH | |||
| 0x6100613d | 18522555 | 767 days ago | Contract Creation | 0 ETH | |||
| 0x6100613d | 18493587 | 771 days ago | Contract Creation | 0 ETH | |||
| 0x6100613d | 17822480 | 865 days ago | Contract Creation | 0 ETH | |||
| 0x6100613d | 17822480 | 865 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
LBFactory
Compiler Version
v0.8.10+commit.fc410830
Optimization Enabled:
Yes with 800 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import {EnumerableSet} from "openzeppelin/utils/structs/EnumerableSet.sol";
import {EnumerableMap} from "openzeppelin/utils/structs/EnumerableMap.sol";
import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";
import {PairParameterHelper} from "./libraries/PairParameterHelper.sol";
import {Encoded} from "./libraries/math/Encoded.sol";
import {ImmutableClone} from "./libraries/ImmutableClone.sol";
import {PendingOwnable} from "./libraries/PendingOwnable.sol";
import {PriceHelper} from "./libraries/PriceHelper.sol";
import {SafeCast} from "./libraries/math/SafeCast.sol";
import {ILBFactory} from "./interfaces/ILBFactory.sol";
import {ILBPair} from "./interfaces/ILBPair.sol";
/**
* @title Liquidity Book Factory
* @author Trader Joe
* @notice Contract used to deploy and register new LBPairs.
* Enables setting fee parameters, flashloan fees and LBPair implementation.
* Unless the `isOpen` is `true`, only the owner of the factory can create pairs.
*/
contract LBFactory is PendingOwnable, ILBFactory {
using SafeCast for uint256;
using Encoded for bytes32;
using PairParameterHelper for bytes32;
using EnumerableSet for EnumerableSet.AddressSet;
using EnumerableSet for EnumerableSet.UintSet;
using EnumerableMap for EnumerableMap.UintToUintMap;
uint256 private constant _OFFSET_IS_PRESET_OPEN = 255;
uint256 private constant _MIN_BIN_STEP = 1; // 0.001%
uint256 private constant _MAX_FLASHLOAN_FEE = 0.1e18; // 10%
address private _feeRecipient;
uint256 private _flashLoanFee;
address private _lbPairImplementation;
ILBPair[] private _allLBPairs;
/**
* @dev Mapping from a (tokenA, tokenB, binStep) to a LBPair. The tokens are ordered to save gas, but they can be
* in the reverse order in the actual pair.
* Always query one of the 2 tokens of the pair to assert the order of the 2 tokens
*/
mapping(IERC20 => mapping(IERC20 => mapping(uint256 => LBPairInformation))) private _lbPairsInfo;
EnumerableMap.UintToUintMap private _presets;
EnumerableSet.AddressSet private _quoteAssetWhitelist;
/**
* @dev Mapping from a (tokenA, tokenB) to a set of available bin steps, this is used to keep track of the
* bin steps that are already used for a pair.
* The tokens are ordered to save gas, but they can be in the reverse order in the actual pair.
* Always query one of the 2 tokens of the pair to assert the order of the 2 tokens
*/
mapping(IERC20 => mapping(IERC20 => EnumerableSet.UintSet)) private _availableLBPairBinSteps;
/**
* @notice Constructor
* @param feeRecipient The address of the fee recipient
* @param flashLoanFee The value of the fee for flash loan
*/
constructor(address feeRecipient, uint256 flashLoanFee) {
if (flashLoanFee > _MAX_FLASHLOAN_FEE) revert LBFactory__FlashLoanFeeAboveMax(flashLoanFee, _MAX_FLASHLOAN_FEE);
_setFeeRecipient(feeRecipient);
_flashLoanFee = flashLoanFee;
emit FlashLoanFeeSet(0, flashLoanFee);
}
/**
* @notice Get the minimum bin step a pair can have
* @return minBinStep
*/
function getMinBinStep() external pure override returns (uint256 minBinStep) {
return _MIN_BIN_STEP;
}
/**
* @notice Get the protocol fee recipient
* @return feeRecipient
*/
function getFeeRecipient() external view override returns (address feeRecipient) {
return _feeRecipient;
}
/**
* @notice Get the maximum fee percentage for flashLoans
* @return maxFee
*/
function getMaxFlashLoanFee() external pure override returns (uint256 maxFee) {
return _MAX_FLASHLOAN_FEE;
}
/**
* @notice Get the fee for flash loans, in 1e18
* @return flashLoanFee The fee for flash loans, in 1e18
*/
function getFlashLoanFee() external view override returns (uint256 flashLoanFee) {
return _flashLoanFee;
}
/**
* @notice Get the address of the LBPair implementation
* @return lbPairImplementation
*/
function getLBPairImplementation() external view override returns (address lbPairImplementation) {
return _lbPairImplementation;
}
/**
* @notice View function to return the number of LBPairs created
* @return lbPairNumber
*/
function getNumberOfLBPairs() external view override returns (uint256 lbPairNumber) {
return _allLBPairs.length;
}
/**
* @notice View function to return the LBPair created at index `index`
* @param index The index
* @return lbPair The address of the LBPair at index `index`
*/
function getLBPairAtIndex(uint256 index) external view override returns (ILBPair lbPair) {
return _allLBPairs[index];
}
/**
* @notice View function to return the number of quote assets whitelisted
* @return numberOfQuoteAssets The number of quote assets
*/
function getNumberOfQuoteAssets() external view override returns (uint256 numberOfQuoteAssets) {
return _quoteAssetWhitelist.length();
}
/**
* @notice View function to return the quote asset whitelisted at index `index`
* @param index The index
* @return asset The address of the quoteAsset at index `index`
*/
function getQuoteAssetAtIndex(uint256 index) external view override returns (IERC20 asset) {
return IERC20(_quoteAssetWhitelist.at(index));
}
/**
* @notice View function to return whether a token is a quotedAsset (true) or not (false)
* @param token The address of the asset
* @return isQuote Whether the token is a quote asset or not
*/
function isQuoteAsset(IERC20 token) external view override returns (bool isQuote) {
return _quoteAssetWhitelist.contains(address(token));
}
/**
* @notice Returns the LBPairInformation if it exists,
* if not, then the address 0 is returned. The order doesn't matter
* @param tokenA The address of the first token of the pair
* @param tokenB The address of the second token of the pair
* @param binStep The bin step of the LBPair
* @return lbPairInformation The LBPairInformation
*/
function getLBPairInformation(IERC20 tokenA, IERC20 tokenB, uint256 binStep)
external
view
override
returns (LBPairInformation memory lbPairInformation)
{
return _getLBPairInformation(tokenA, tokenB, binStep);
}
/**
* @notice View function to return the different parameters of the preset
* Will revert if the preset doesn't exist
* @param binStep The bin step of the preset
* @return baseFactor The base factor
* @return filterPeriod The filter period of the preset
* @return decayPeriod The decay period of the preset
* @return reductionFactor The reduction factor of the preset
* @return variableFeeControl The variable fee control of the preset
* @return protocolShare The protocol share of the preset
* @return maxVolatilityAccumulator The max volatility accumulator of the preset
* @return isOpen Whether the preset is open or not
*/
function getPreset(uint256 binStep)
external
view
override
returns (
uint256 baseFactor,
uint256 filterPeriod,
uint256 decayPeriod,
uint256 reductionFactor,
uint256 variableFeeControl,
uint256 protocolShare,
uint256 maxVolatilityAccumulator,
bool isOpen
)
{
if (!_presets.contains(binStep)) revert LBFactory__BinStepHasNoPreset(binStep);
bytes32 preset = bytes32(_presets.get(binStep));
baseFactor = preset.getBaseFactor();
filterPeriod = preset.getFilterPeriod();
decayPeriod = preset.getDecayPeriod();
reductionFactor = preset.getReductionFactor();
variableFeeControl = preset.getVariableFeeControl();
protocolShare = preset.getProtocolShare();
maxVolatilityAccumulator = preset.getMaxVolatilityAccumulator();
isOpen = preset.decodeBool(_OFFSET_IS_PRESET_OPEN);
}
/**
* @notice View function to return the list of available binStep with a preset
* @return binStepWithPreset The list of binStep
*/
function getAllBinSteps() external view override returns (uint256[] memory binStepWithPreset) {
return _presets.keys();
}
/**
* @notice View function to return the list of open binSteps
* @return openBinStep The list of open binSteps
*/
function getOpenBinSteps() external view override returns (uint256[] memory openBinStep) {
uint256 length = _presets.length();
if (length > 0) {
openBinStep = new uint256[](length);
uint256 index;
for (uint256 i; i < length; ++i) {
(uint256 binStep, uint256 preset) = _presets.at(i);
if (_isPresetOpen(bytes32(preset))) {
openBinStep[index] = binStep;
index++;
}
}
if (index < length) {
assembly {
mstore(openBinStep, index)
}
}
}
}
/**
* @notice View function to return all the LBPair of a pair of tokens
* @param tokenX The first token of the pair
* @param tokenY The second token of the pair
* @return lbPairsAvailable The list of available LBPairs
*/
function getAllLBPairs(IERC20 tokenX, IERC20 tokenY)
external
view
override
returns (LBPairInformation[] memory lbPairsAvailable)
{
unchecked {
(IERC20 tokenA, IERC20 tokenB) = _sortTokens(tokenX, tokenY);
EnumerableSet.UintSet storage addressSet = _availableLBPairBinSteps[tokenA][tokenB];
uint256 length = addressSet.length();
if (length > 0) {
lbPairsAvailable = new LBPairInformation[](length);
mapping(uint256 => LBPairInformation) storage lbPairsInfo = _lbPairsInfo[tokenA][tokenB];
for (uint256 i = 0; i < length; ++i) {
uint16 binStep = addressSet.at(i).safe16();
lbPairsAvailable[i] = LBPairInformation({
binStep: binStep,
LBPair: lbPairsInfo[binStep].LBPair,
createdByOwner: lbPairsInfo[binStep].createdByOwner,
ignoredForRouting: lbPairsInfo[binStep].ignoredForRouting
});
}
}
}
}
/**
* @notice Set the LBPair implementation address
* @dev Needs to be called by the owner
* @param newLBPairImplementation The address of the implementation
*/
function setLBPairImplementation(address newLBPairImplementation) external override onlyOwner {
if (ILBPair(newLBPairImplementation).getFactory() != this) {
revert LBFactory__LBPairSafetyCheckFailed(newLBPairImplementation);
}
address oldLBPairImplementation = _lbPairImplementation;
if (oldLBPairImplementation == newLBPairImplementation) {
revert LBFactory__SameImplementation(newLBPairImplementation);
}
_lbPairImplementation = newLBPairImplementation;
emit LBPairImplementationSet(oldLBPairImplementation, newLBPairImplementation);
}
/**
* @notice Create a liquidity bin LBPair for tokenX and tokenY
* @param tokenX The address of the first token
* @param tokenY The address of the second token
* @param activeId The active id of the pair
* @param binStep The bin step in basis point, used to calculate log(1 + binStep / 10_000)
* @return pair The address of the newly created LBPair
*/
function createLBPair(IERC20 tokenX, IERC20 tokenY, uint24 activeId, uint16 binStep)
external
override
returns (ILBPair pair)
{
if (!_presets.contains(binStep)) revert LBFactory__BinStepHasNoPreset(binStep);
bytes32 preset = bytes32(_presets.get(binStep));
bool isOwner = msg.sender == owner();
if (!_isPresetOpen(preset) && !isOwner) {
revert LBFactory__PresetIsLockedForUsers(msg.sender, binStep);
}
if (!_quoteAssetWhitelist.contains(address(tokenY))) revert LBFactory__QuoteAssetNotWhitelisted(tokenY);
if (tokenX == tokenY) revert LBFactory__IdenticalAddresses(tokenX);
// safety check, making sure that the price can be calculated
PriceHelper.getPriceFromId(activeId, binStep);
// We sort token for storage efficiency, only one input needs to be stored because they are sorted
(IERC20 tokenA, IERC20 tokenB) = _sortTokens(tokenX, tokenY);
// single check is sufficient
if (address(tokenA) == address(0)) revert LBFactory__AddressZero();
if (address(_lbPairsInfo[tokenA][tokenB][binStep].LBPair) != address(0)) {
revert LBFactory__LBPairAlreadyExists(tokenX, tokenY, binStep);
}
{
address implementation = _lbPairImplementation;
if (implementation == address(0)) revert LBFactory__ImplementationNotSet();
pair = ILBPair(
ImmutableClone.cloneDeterministic(
implementation,
abi.encodePacked(tokenX, tokenY, binStep),
keccak256(abi.encode(tokenA, tokenB, binStep))
)
);
}
pair.initialize(
preset.getBaseFactor(),
preset.getFilterPeriod(),
preset.getDecayPeriod(),
preset.getReductionFactor(),
preset.getVariableFeeControl(),
preset.getProtocolShare(),
preset.getMaxVolatilityAccumulator(),
activeId
);
_lbPairsInfo[tokenA][tokenB][binStep] =
LBPairInformation({binStep: binStep, LBPair: pair, createdByOwner: isOwner, ignoredForRouting: false});
_allLBPairs.push(pair);
_availableLBPairBinSteps[tokenA][tokenB].add(binStep);
emit LBPairCreated(tokenX, tokenY, binStep, pair, _allLBPairs.length - 1);
}
/**
* @notice Function to set whether the pair is ignored or not for routing, it will make the pair unusable by the router
* @param tokenX The address of the first token of the pair
* @param tokenY The address of the second token of the pair
* @param binStep The bin step in basis point of the pair
* @param ignored Whether to ignore (true) or not (false) the pair for routing
*/
function setLBPairIgnored(IERC20 tokenX, IERC20 tokenY, uint16 binStep, bool ignored) external override onlyOwner {
(IERC20 tokenA, IERC20 tokenB) = _sortTokens(tokenX, tokenY);
LBPairInformation memory pairInformation = _lbPairsInfo[tokenA][tokenB][binStep];
if (address(pairInformation.LBPair) == address(0)) {
revert LBFactory__LBPairDoesNotExist(tokenX, tokenY, binStep);
}
if (pairInformation.ignoredForRouting == ignored) revert LBFactory__LBPairIgnoredIsAlreadyInTheSameState();
_lbPairsInfo[tokenA][tokenB][binStep].ignoredForRouting = ignored;
emit LBPairIgnoredStateChanged(pairInformation.LBPair, ignored);
}
/**
* @notice Sets the preset parameters of a bin step
* @param binStep The bin step in basis point, used to calculate the price
* @param baseFactor The base factor, used to calculate the base fee, baseFee = baseFactor * binStep
* @param filterPeriod The period where the accumulator value is untouched, prevent spam
* @param decayPeriod The period where the accumulator value is decayed, by the reduction factor
* @param reductionFactor The reduction factor, used to calculate the reduction of the accumulator
* @param variableFeeControl The variable fee control, used to control the variable fee, can be 0 to disable it
* @param protocolShare The share of the fees received by the protocol
* @param maxVolatilityAccumulator The max value of the volatility accumulator
*/
function setPreset(
uint16 binStep,
uint16 baseFactor,
uint16 filterPeriod,
uint16 decayPeriod,
uint16 reductionFactor,
uint24 variableFeeControl,
uint16 protocolShare,
uint24 maxVolatilityAccumulator,
bool isOpen
) external override onlyOwner {
if (binStep < _MIN_BIN_STEP) revert LBFactory__BinStepTooLow(binStep);
bytes32 preset = bytes32(0).setStaticFeeParameters(
baseFactor,
filterPeriod,
decayPeriod,
reductionFactor,
variableFeeControl,
protocolShare,
maxVolatilityAccumulator
);
if (isOpen) {
preset = preset.setBool(true, _OFFSET_IS_PRESET_OPEN);
}
_presets.set(binStep, uint256(preset));
emit PresetSet(
binStep,
baseFactor,
filterPeriod,
decayPeriod,
reductionFactor,
variableFeeControl,
protocolShare,
maxVolatilityAccumulator
);
emit PresetOpenStateChanged(binStep, isOpen);
}
/**
* @notice Sets if the preset is open or not to be used by users
* @param binStep The bin step in basis point, used to calculate the price
* @param isOpen Whether the preset is open or not
*/
function setPresetOpenState(uint16 binStep, bool isOpen) external override onlyOwner {
if (!_presets.contains(binStep)) revert LBFactory__BinStepHasNoPreset(binStep);
bytes32 preset = bytes32(_presets.get(binStep));
if (preset.decodeBool(_OFFSET_IS_PRESET_OPEN) == isOpen) {
revert LBFactory__PresetOpenStateIsAlreadyInTheSameState();
}
_presets.set(binStep, uint256(preset.setBool(isOpen, _OFFSET_IS_PRESET_OPEN)));
emit PresetOpenStateChanged(binStep, isOpen);
}
/**
* @notice Remove the preset linked to a binStep
* @param binStep The bin step to remove
*/
function removePreset(uint16 binStep) external override onlyOwner {
if (!_presets.remove(binStep)) revert LBFactory__BinStepHasNoPreset(binStep);
emit PresetRemoved(binStep);
}
/**
* @notice Function to set the fee parameter of a LBPair
* @param tokenX The address of the first token
* @param tokenY The address of the second token
* @param binStep The bin step in basis point, used to calculate the price
* @param baseFactor The base factor, used to calculate the base fee, baseFee = baseFactor * binStep
* @param filterPeriod The period where the accumulator value is untouched, prevent spam
* @param decayPeriod The period where the accumulator value is decayed, by the reduction factor
* @param reductionFactor The reduction factor, used to calculate the reduction of the accumulator
* @param variableFeeControl The variable fee control, used to control the variable fee, can be 0 to disable it
* @param protocolShare The share of the fees received by the protocol
* @param maxVolatilityAccumulator The max value of volatility accumulator
*/
function setFeesParametersOnPair(
IERC20 tokenX,
IERC20 tokenY,
uint16 binStep,
uint16 baseFactor,
uint16 filterPeriod,
uint16 decayPeriod,
uint16 reductionFactor,
uint24 variableFeeControl,
uint16 protocolShare,
uint24 maxVolatilityAccumulator
) external override onlyOwner {
ILBPair lbPair = _getLBPairInformation(tokenX, tokenY, binStep).LBPair;
if (address(lbPair) == address(0)) revert LBFactory__LBPairNotCreated(tokenX, tokenY, binStep);
lbPair.setStaticFeeParameters(
baseFactor,
filterPeriod,
decayPeriod,
reductionFactor,
variableFeeControl,
protocolShare,
maxVolatilityAccumulator
);
}
/**
* @notice Function to set the recipient of the fees. This address needs to be able to receive ERC20s
* @param feeRecipient The address of the recipient
*/
function setFeeRecipient(address feeRecipient) external override onlyOwner {
_setFeeRecipient(feeRecipient);
}
/**
* @notice Function to set the flash loan fee
* @param flashLoanFee The value of the fee for flash loan
*/
function setFlashLoanFee(uint256 flashLoanFee) external override onlyOwner {
uint256 oldFlashLoanFee = _flashLoanFee;
if (oldFlashLoanFee == flashLoanFee) revert LBFactory__SameFlashLoanFee(flashLoanFee);
if (flashLoanFee > _MAX_FLASHLOAN_FEE) revert LBFactory__FlashLoanFeeAboveMax(flashLoanFee, _MAX_FLASHLOAN_FEE);
_flashLoanFee = flashLoanFee;
emit FlashLoanFeeSet(oldFlashLoanFee, flashLoanFee);
}
/**
* @notice Function to add an asset to the whitelist of quote assets
* @param quoteAsset The quote asset (e.g: NATIVE, USDC...)
*/
function addQuoteAsset(IERC20 quoteAsset) external override onlyOwner {
if (!_quoteAssetWhitelist.add(address(quoteAsset))) {
revert LBFactory__QuoteAssetAlreadyWhitelisted(quoteAsset);
}
emit QuoteAssetAdded(quoteAsset);
}
/**
* @notice Function to remove an asset from the whitelist of quote assets
* @param quoteAsset The quote asset (e.g: NATIVE, USDC...)
*/
function removeQuoteAsset(IERC20 quoteAsset) external override onlyOwner {
if (!_quoteAssetWhitelist.remove(address(quoteAsset))) revert LBFactory__QuoteAssetNotWhitelisted(quoteAsset);
emit QuoteAssetRemoved(quoteAsset);
}
function _isPresetOpen(bytes32 preset) internal pure returns (bool) {
return preset.decodeBool(_OFFSET_IS_PRESET_OPEN);
}
/**
* @notice Internal function to set the recipient of the fee
* @param feeRecipient The address of the recipient
*/
function _setFeeRecipient(address feeRecipient) internal {
if (feeRecipient == address(0)) revert LBFactory__AddressZero();
address oldFeeRecipient = _feeRecipient;
if (oldFeeRecipient == feeRecipient) revert LBFactory__SameFeeRecipient(_feeRecipient);
_feeRecipient = feeRecipient;
emit FeeRecipientSet(oldFeeRecipient, feeRecipient);
}
function forceDecay(ILBPair pair) external override onlyOwner {
pair.forceDecay();
}
/**
* @notice Returns the LBPairInformation if it exists,
* if not, then the address 0 is returned. The order doesn't matter
* @param tokenA The address of the first token of the pair
* @param tokenB The address of the second token of the pair
* @param binStep The bin step of the LBPair
* @return The LBPairInformation
*/
function _getLBPairInformation(IERC20 tokenA, IERC20 tokenB, uint256 binStep)
private
view
returns (LBPairInformation memory)
{
(tokenA, tokenB) = _sortTokens(tokenA, tokenB);
return _lbPairsInfo[tokenA][tokenB][binStep];
}
/**
* @notice Private view function to sort 2 tokens in ascending order
* @param tokenA The first token
* @param tokenB The second token
* @return The sorted first token
* @return The sorted second token
*/
function _sortTokens(IERC20 tokenA, IERC20 tokenB) private pure returns (IERC20, IERC20) {
if (tokenA > tokenB) (tokenA, tokenB) = (tokenB, tokenA);
return (tokenA, tokenB);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableMap.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js.
pragma solidity ^0.8.0;
import "./EnumerableSet.sol";
/**
* @dev Library for managing an enumerable variant of Solidity's
* https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
* type.
*
* Maps have the following properties:
*
* - Entries are added, removed, and checked for existence in constant time
* (O(1)).
* - Entries are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableMap for EnumerableMap.UintToAddressMap;
*
* // Declare a set state variable
* EnumerableMap.UintToAddressMap private myMap;
* }
* ```
*
* The following map types are supported:
*
* - `uint256 -> address` (`UintToAddressMap`) since v3.0.0
* - `address -> uint256` (`AddressToUintMap`) since v4.6.0
* - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0
* - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0
* - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableMap.
* ====
*/
library EnumerableMap {
using EnumerableSet for EnumerableSet.Bytes32Set;
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Map type with
// bytes32 keys and values.
// The Map implementation uses private functions, and user-facing
// implementations (such as Uint256ToAddressMap) are just wrappers around
// the underlying Map.
// This means that we can only create new EnumerableMaps for types that fit
// in bytes32.
struct Bytes32ToBytes32Map {
// Storage of keys
EnumerableSet.Bytes32Set _keys;
mapping(bytes32 => bytes32) _values;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) {
map._values[key] = value;
return map._keys.add(key);
}
/**
* @dev Removes a key-value pair from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) {
delete map._values[key];
return map._keys.remove(key);
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) {
return map._keys.contains(key);
}
/**
* @dev Returns the number of key-value pairs in the map. O(1).
*/
function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) {
return map._keys.length();
}
/**
* @dev Returns the key-value pair stored at position `index` in the map. O(1).
*
* Note that there are no guarantees on the ordering of entries inside the
* array, and it may change when more entries are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) {
bytes32 key = map._keys.at(index);
return (key, map._values[key]);
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) {
bytes32 value = map._values[key];
if (value == bytes32(0)) {
return (contains(map, key), bytes32(0));
} else {
return (true, value);
}
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) {
bytes32 value = map._values[key];
require(value != 0 || contains(map, key), "EnumerableMap: nonexistent key");
return value;
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
Bytes32ToBytes32Map storage map,
bytes32 key,
string memory errorMessage
) internal view returns (bytes32) {
bytes32 value = map._values[key];
require(value != 0 || contains(map, key), errorMessage);
return value;
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) {
return map._keys.values();
}
// UintToUintMap
struct UintToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) {
return set(map._inner, bytes32(key), bytes32(value));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(UintToUintMap storage map, uint256 key) internal returns (bool) {
return remove(map._inner, bytes32(key));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) {
return contains(map._inner, bytes32(key));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(UintToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (uint256(key), uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(key)));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(UintToUintMap storage map, uint256 key, string memory errorMessage) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(key), errorMessage));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(UintToUintMap storage map) internal view returns (uint256[] memory) {
bytes32[] memory store = keys(map._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintToAddressMap
struct UintToAddressMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {
return set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
return remove(map._inner, bytes32(key));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
return contains(map._inner, bytes32(key));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(UintToAddressMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (uint256(key), address(uint160(uint256(value))));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
return (success, address(uint160(uint256(value))));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
return address(uint160(uint256(get(map._inner, bytes32(key)))));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
UintToAddressMap storage map,
uint256 key,
string memory errorMessage
) internal view returns (address) {
return address(uint160(uint256(get(map._inner, bytes32(key), errorMessage))));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) {
bytes32[] memory store = keys(map._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressToUintMap
struct AddressToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) {
return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(AddressToUintMap storage map, address key) internal returns (bool) {
return remove(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(AddressToUintMap storage map, address key) internal view returns (bool) {
return contains(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(AddressToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (address(uint160(uint256(key))), uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key))));
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(AddressToUintMap storage map, address key) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(uint256(uint160(key)))));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
AddressToUintMap storage map,
address key,
string memory errorMessage
) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(uint256(uint160(key))), errorMessage));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(AddressToUintMap storage map) internal view returns (address[] memory) {
bytes32[] memory store = keys(map._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// Bytes32ToUintMap
struct Bytes32ToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) {
return set(map._inner, key, bytes32(value));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) {
return remove(map._inner, key);
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) {
return contains(map._inner, key);
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(Bytes32ToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (key, uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, key);
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) {
return uint256(get(map._inner, key));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
Bytes32ToUintMap storage map,
bytes32 key,
string memory errorMessage
) internal view returns (uint256) {
return uint256(get(map._inner, key, errorMessage));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) {
bytes32[] memory store = keys(map._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import {Constants} from "./Constants.sol";
import {SafeCast} from "./math/SafeCast.sol";
import {Encoded} from "./math/Encoded.sol";
/**
* @title Liquidity Book Pair Parameter Helper Library
* @author Trader Joe
* @dev This library contains functions to get and set parameters of a pair
* The parameters are stored in a single bytes32 variable in the following format:
* [0 - 16[: base factor (16 bits)
* [16 - 28[: filter period (12 bits)
* [28 - 40[: decay period (12 bits)
* [40 - 54[: reduction factor (14 bits)
* [54 - 78[: variable fee control (24 bits)
* [78 - 92[: protocol share (14 bits)
* [92 - 112[: max volatility accumulator (20 bits)
* [112 - 132[: volatility accumulator (20 bits)
* [132 - 152[: volatility reference (20 bits)
* [152 - 176[: index reference (24 bits)
* [176 - 216[: time of last update (40 bits)
* [216 - 232[: oracle index (16 bits)
* [232 - 256[: active index (24 bits)
*/
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;
/**
* @dev Get the base factor from the encoded pair parameters
* @param params The encoded pair parameters, as follows:
* [0 - 16[: base factor (16 bits)
* [16 - 256[: other parameters
* @return baseFactor The base factor
*/
function getBaseFactor(bytes32 params) internal pure returns (uint16 baseFactor) {
baseFactor = params.decodeUint16(OFFSET_BASE_FACTOR);
}
/**
* @dev Get the filter period from the encoded pair parameters
* @param params The encoded pair parameters, as follows:
* [0 - 16[: other parameters
* [16 - 28[: filter period (12 bits)
* [28 - 256[: other parameters
* @return filterPeriod The filter period
*/
function getFilterPeriod(bytes32 params) internal pure returns (uint16 filterPeriod) {
filterPeriod = params.decodeUint12(OFFSET_FILTER_PERIOD);
}
/**
* @dev Get the decay period from the encoded pair parameters
* @param params The encoded pair parameters, as follows:
* [0 - 28[: other parameters
* [28 - 40[: decay period (12 bits)
* [40 - 256[: other parameters
* @return decayPeriod The decay period
*/
function getDecayPeriod(bytes32 params) internal pure returns (uint16 decayPeriod) {
decayPeriod = params.decodeUint12(OFFSET_DECAY_PERIOD);
}
/**
* @dev Get the reduction factor from the encoded pair parameters
* @param params The encoded pair parameters, as follows:
* [0 - 40[: other parameters
* [40 - 54[: reduction factor (14 bits)
* [54 - 256[: other parameters
* @return reductionFactor The reduction factor
*/
function getReductionFactor(bytes32 params) internal pure returns (uint16 reductionFactor) {
reductionFactor = params.decodeUint14(OFFSET_REDUCTION_FACTOR);
}
/**
* @dev Get the variable fee control from the encoded pair parameters
* @param params The encoded pair parameters, as follows:
* [0 - 54[: other parameters
* [54 - 78[: variable fee control (24 bits)
* [78 - 256[: other parameters
* @return variableFeeControl The variable fee control
*/
function getVariableFeeControl(bytes32 params) internal pure returns (uint24 variableFeeControl) {
variableFeeControl = params.decodeUint24(OFFSET_VAR_FEE_CONTROL);
}
/**
* @dev Get the protocol share from the encoded pair parameters
* @param params The encoded pair parameters, as follows:
* [0 - 78[: other parameters
* [78 - 92[: protocol share (14 bits)
* [92 - 256[: other parameters
* @return protocolShare The protocol share
*/
function getProtocolShare(bytes32 params) internal pure returns (uint16 protocolShare) {
protocolShare = params.decodeUint14(OFFSET_PROTOCOL_SHARE);
}
/**
* @dev Get the max volatility accumulator from the encoded pair parameters
* @param params The encoded pair parameters, as follows:
* [0 - 92[: other parameters
* [92 - 112[: max volatility accumulator (20 bits)
* [112 - 256[: other parameters
* @return maxVolatilityAccumulator The max volatility accumulator
*/
function getMaxVolatilityAccumulator(bytes32 params) internal pure returns (uint24 maxVolatilityAccumulator) {
maxVolatilityAccumulator = params.decodeUint20(OFFSET_MAX_VOL_ACC);
}
/**
* @dev Get the volatility accumulator from the encoded pair parameters
* @param params The encoded pair parameters, as follows:
* [0 - 112[: other parameters
* [112 - 132[: volatility accumulator (20 bits)
* [132 - 256[: other parameters
* @return volatilityAccumulator The volatility accumulator
*/
function getVolatilityAccumulator(bytes32 params) internal pure returns (uint24 volatilityAccumulator) {
volatilityAccumulator = params.decodeUint20(OFFSET_VOL_ACC);
}
/**
* @dev Get the volatility reference from the encoded pair parameters
* @param params The encoded pair parameters, as follows:
* [0 - 132[: other parameters
* [132 - 152[: volatility reference (20 bits)
* [152 - 256[: other parameters
* @return volatilityReference The volatility reference
*/
function getVolatilityReference(bytes32 params) internal pure returns (uint24 volatilityReference) {
volatilityReference = params.decodeUint20(OFFSET_VOL_REF);
}
/**
* @dev Get the index reference from the encoded pair parameters
* @param params The encoded pair parameters, as follows:
* [0 - 152[: other parameters
* [152 - 176[: index reference (24 bits)
* [176 - 256[: other parameters
* @return idReference The index reference
*/
function getIdReference(bytes32 params) internal pure returns (uint24 idReference) {
idReference = params.decodeUint24(OFFSET_ID_REF);
}
/**
* @dev Get the time of last update from the encoded pair parameters
* @param params The encoded pair parameters, as follows:
* [0 - 176[: other parameters
* [176 - 216[: time of last update (40 bits)
* [216 - 256[: other parameters
* @return timeOflastUpdate The time of last update
*/
function getTimeOfLastUpdate(bytes32 params) internal pure returns (uint40 timeOflastUpdate) {
timeOflastUpdate = params.decodeUint40(OFFSET_TIME_LAST_UPDATE);
}
/**
* @dev Get the oracle id from the encoded pair parameters
* @param params The encoded pair parameters, as follows:
* [0 - 216[: other parameters
* [216 - 232[: oracle id (16 bits)
* [232 - 256[: other parameters
* @return oracleId The oracle id
*/
function getOracleId(bytes32 params) internal pure returns (uint16 oracleId) {
oracleId = params.decodeUint16(OFFSET_ORACLE_ID);
}
/**
* @dev Get the active index from the encoded pair parameters
* @param params The encoded pair parameters, as follows:
* [0 - 232[: other parameters
* [232 - 256[: active index (24 bits)
* @return activeId The active index
*/
function getActiveId(bytes32 params) internal pure returns (uint24 activeId) {
activeId = params.decodeUint24(OFFSET_ACTIVE_ID);
}
/**
* @dev Get the delta between the current active index and the cached active index
* @param params The encoded pair parameters, as follows:
* [0 - 232[: other parameters
* [232 - 256[: active index (24 bits)
* @param activeId The current active index
* @return The delta
*/
function getDeltaId(bytes32 params, uint24 activeId) internal pure returns (uint24) {
uint24 id = getActiveId(params);
unchecked {
return activeId > id ? activeId - id : id - activeId;
}
}
/**
* @dev Calculates the base fee, with 18 decimals
* @param params The encoded pair parameters
* @param binStep The bin step (in basis points)
* @return baseFee The base fee
*/
function getBaseFee(bytes32 params, uint16 binStep) internal pure returns (uint256) {
unchecked {
// Base factor is in basis points, binStep is in basis points, so we multiply by 1e10
return uint256(getBaseFactor(params)) * binStep * 1e10;
}
}
/**
* @dev Calculates the variable fee
* @param params The encoded pair parameters
* @param binStep The bin step (in basis points)
* @return variableFee The variable fee
*/
function getVariableFee(bytes32 params, uint16 binStep) internal pure returns (uint256 variableFee) {
uint256 variableFeeControl = getVariableFeeControl(params);
if (variableFeeControl != 0) {
unchecked {
// The volatility accumulator is in basis points, binStep is in basis points,
// and the variable fee control is in basis points, so the result is in 100e18th
uint256 prod = uint256(getVolatilityAccumulator(params)) * binStep;
variableFee = (prod * prod * variableFeeControl + 99) / 100;
}
}
}
/**
* @dev Calculates the total fee, which is the sum of the base fee and the variable fee
* @param params The encoded pair parameters
* @param binStep The bin step (in basis points)
* @return totalFee The total fee
*/
function getTotalFee(bytes32 params, uint16 binStep) internal pure returns (uint128) {
unchecked {
return (getBaseFee(params, binStep) + getVariableFee(params, binStep)).safe128();
}
}
/**
* @dev Set the oracle id in the encoded pair parameters
* @param params The encoded pair parameters
* @param oracleId The oracle id
* @return The updated encoded pair parameters
*/
function setOracleId(bytes32 params, uint16 oracleId) internal pure returns (bytes32) {
return params.set(oracleId, Encoded.MASK_UINT16, OFFSET_ORACLE_ID);
}
/**
* @dev Set the volatility reference in the encoded pair parameters
* @param params The encoded pair parameters
* @param volRef The volatility reference
* @return The updated encoded pair parameters
*/
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);
}
/**
* @dev Set the volatility accumulator in the encoded pair parameters
* @param params The encoded pair parameters
* @param volAcc The volatility accumulator
* @return The updated encoded pair parameters
*/
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);
}
/**
* @dev Set the active id in the encoded pair parameters
* @param params The encoded pair parameters
* @param activeId The active id
* @return newParams The updated encoded pair parameters
*/
function setActiveId(bytes32 params, uint24 activeId) internal pure returns (bytes32 newParams) {
return params.set(activeId, Encoded.MASK_UINT24, OFFSET_ACTIVE_ID);
}
/**
* @dev Sets the static fee parameters in the encoded pair parameters
* @param params The encoded pair parameters
* @param baseFactor The base factor
* @param filterPeriod The filter period
* @param decayPeriod The decay period
* @param reductionFactor The reduction factor
* @param variableFeeControl The variable fee control
* @param protocolShare The protocol share
* @param maxVolatilityAccumulator The max volatility accumulator
* @return newParams The updated encoded pair parameters
*/
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);
}
/**
* @dev Updates the index reference in the encoded pair parameters
* @param params The encoded pair parameters
* @return newParams The updated encoded pair parameters
*/
function updateIdReference(bytes32 params) internal pure returns (bytes32 newParams) {
uint24 activeId = getActiveId(params);
return params.set(activeId, Encoded.MASK_UINT24, OFFSET_ID_REF);
}
/**
* @dev Updates the time of last update in the encoded pair parameters
* @param params The encoded pair parameters
* @return newParams The updated encoded pair parameters
*/
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);
}
/**
* @dev Updates the volatility reference in the encoded pair parameters
* @param params The encoded pair parameters
* @return The updated encoded pair parameters
*/
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);
}
/**
* @dev Updates the volatility accumulator in the encoded pair parameters
* @param params The encoded pair parameters
* @param activeId The active id
* @return The updated encoded pair parameters
*/
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));
}
/**
* @dev Updates the volatility reference and the volatility accumulator in the encoded pair parameters
* @param params The encoded pair parameters
* @return The updated encoded pair parameters
*/
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);
}
/**
* @dev Updates the volatility reference and the volatility accumulator in the encoded pair parameters
* @param params The encoded pair parameters
* @param activeId The active id
* @return The updated encoded pair parameters
*/
function updateVolatilityParameters(bytes32 params, uint24 activeId) internal view returns (bytes32) {
params = updateReferences(params);
return updateVolatilityAccumulator(params, activeId);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
/**
* @title Liquidity Book Encoded Library
* @author Trader Joe
* @notice Helper contract used for decoding bytes32 sample
*/
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;
/**
* @notice Internal function to set a value in an encoded bytes32 using a mask and offset
* @dev This function can overflow
* @param encoded The previous encoded value
* @param value The value to encode
* @param mask The mask
* @param offset The offset
* @return newEncoded The new encoded value
*/
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)))
}
}
/**
* @notice Internal function to set a bool in an encoded bytes32 using an offset
* @dev This function can overflow
* @param encoded The previous encoded value
* @param boolean The bool to encode
* @param offset The offset
* @return newEncoded The new encoded value
*/
function setBool(bytes32 encoded, bool boolean, uint256 offset) internal pure returns (bytes32 newEncoded) {
return set(encoded, boolean ? 1 : 0, MASK_UINT1, offset);
}
/**
* @notice Internal function to decode a bytes32 sample using a mask and offset
* @dev This function can overflow
* @param encoded The encoded value
* @param mask The mask
* @param offset The offset
* @return value The decoded value
*/
function decode(bytes32 encoded, uint256 mask, uint256 offset) internal pure returns (uint256 value) {
assembly {
value := and(shr(offset, encoded), mask)
}
}
/**
* @notice Internal function to decode a bytes32 sample into a bool using an offset
* @dev This function can overflow
* @param encoded The encoded value
* @param offset The offset
* @return boolean The decoded value as a bool
*/
function decodeBool(bytes32 encoded, uint256 offset) internal pure returns (bool boolean) {
assembly {
boolean := and(shr(offset, encoded), MASK_UINT1)
}
}
/**
* @notice Internal function to decode a bytes32 sample into a uint8 using an offset
* @dev This function can overflow
* @param encoded The encoded value
* @param offset The offset
* @return value The decoded value
*/
function decodeUint8(bytes32 encoded, uint256 offset) internal pure returns (uint8 value) {
assembly {
value := and(shr(offset, encoded), MASK_UINT8)
}
}
/**
* @notice Internal function to decode a bytes32 sample into a uint12 using an offset
* @dev This function can overflow
* @param encoded The encoded value
* @param offset The offset
* @return value The decoded value as a uint16, since uint12 is not supported
*/
function decodeUint12(bytes32 encoded, uint256 offset) internal pure returns (uint16 value) {
assembly {
value := and(shr(offset, encoded), MASK_UINT12)
}
}
/**
* @notice Internal function to decode a bytes32 sample into a uint14 using an offset
* @dev This function can overflow
* @param encoded The encoded value
* @param offset The offset
* @return value The decoded value as a uint16, since uint14 is not supported
*/
function decodeUint14(bytes32 encoded, uint256 offset) internal pure returns (uint16 value) {
assembly {
value := and(shr(offset, encoded), MASK_UINT14)
}
}
/**
* @notice Internal function to decode a bytes32 sample into a uint16 using an offset
* @dev This function can overflow
* @param encoded The encoded value
* @param offset The offset
* @return value The decoded value
*/
function decodeUint16(bytes32 encoded, uint256 offset) internal pure returns (uint16 value) {
assembly {
value := and(shr(offset, encoded), MASK_UINT16)
}
}
/**
* @notice Internal function to decode a bytes32 sample into a uint20 using an offset
* @dev This function can overflow
* @param encoded The encoded value
* @param offset The offset
* @return value The decoded value as a uint24, since uint20 is not supported
*/
function decodeUint20(bytes32 encoded, uint256 offset) internal pure returns (uint24 value) {
assembly {
value := and(shr(offset, encoded), MASK_UINT20)
}
}
/**
* @notice Internal function to decode a bytes32 sample into a uint24 using an offset
* @dev This function can overflow
* @param encoded The encoded value
* @param offset The offset
* @return value The decoded value
*/
function decodeUint24(bytes32 encoded, uint256 offset) internal pure returns (uint24 value) {
assembly {
value := and(shr(offset, encoded), MASK_UINT24)
}
}
/**
* @notice Internal function to decode a bytes32 sample into a uint40 using an offset
* @dev This function can overflow
* @param encoded The encoded value
* @param offset The offset
* @return value The decoded value
*/
function decodeUint40(bytes32 encoded, uint256 offset) internal pure returns (uint40 value) {
assembly {
value := and(shr(offset, encoded), MASK_UINT40)
}
}
/**
* @notice Internal function to decode a bytes32 sample into a uint64 using an offset
* @dev This function can overflow
* @param encoded The encoded value
* @param offset The offset
* @return value The decoded value
*/
function decodeUint64(bytes32 encoded, uint256 offset) internal pure returns (uint64 value) {
assembly {
value := and(shr(offset, encoded), MASK_UINT64)
}
}
/**
* @notice Internal function to decode a bytes32 sample into a uint128 using an offset
* @dev This function can overflow
* @param encoded The encoded value
* @param offset The offset
* @return value The decoded value
*/
function decodeUint128(bytes32 encoded, uint256 offset) internal pure returns (uint128 value) {
assembly {
value := and(shr(offset, encoded), MASK_UINT128)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
/**
* @title Liquidity Book Immutable Clone Library
* @notice Minimal immutable proxy library.
* @author Trader Joe
* @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibClone.sol)
* @author Minimal proxy by 0age (https://github.com/0age)
* @author Clones with immutable args by wighawag, zefram.eth, Saw-mon & Natalie
* (https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args)
* @dev Minimal proxy:
* Although the sw0nt pattern saves 5 gas over the erc-1167 pattern during runtime,
* it is not supported out-of-the-box on Etherscan. Hence, we choose to use the 0age pattern,
* which saves 4 gas over the erc-1167 pattern during runtime, and has the smallest bytecode.
* @dev Clones with immutable args (CWIA):
* The implementation of CWIA here doesn't implements a `receive()` as it is not needed for LB.
*/
library ImmutableClone {
error DeploymentFailed();
error PackedDataTooBig();
/**
* @dev Deploys a deterministic clone of `implementation` using immutable arguments encoded in `data`, with `salt`
* @param implementation The address of the implementation
* @param data The encoded immutable arguments
* @param salt The salt
*/
function cloneDeterministic(address implementation, bytes memory data, bytes32 salt)
internal
returns (address instance)
{
assembly {
// Compute the boundaries of the data and cache the memory slots around it.
let mBefore2 := mload(sub(data, 0x40))
let mBefore1 := mload(sub(data, 0x20))
let dataLength := mload(data)
let dataEnd := add(add(data, 0x20), dataLength)
let mAfter1 := mload(dataEnd)
// +2 bytes for telling how much data there is appended to the call.
let extraLength := add(dataLength, 2)
// The `creationSize` is `extraLength + 63`
// The `runSize` is `creationSize - 10`.
// if `extraLength` is greater than `0xffca` revert as the `creationSize` would be greater than `0xffff`.
if gt(extraLength, 0xffca) {
// Store the function selector of `PackedDataTooBig()`.
mstore(0x00, 0xc8c78139)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
/**
* ---------------------------------------------------------------------------------------------------+
* CREATION (10 bytes) |
* ---------------------------------------------------------------------------------------------------|
* Opcode | Mnemonic | Stack | Memory |
* ---------------------------------------------------------------------------------------------------|
* 61 runSize | PUSH2 runSize | r | |
* 3d | RETURNDATASIZE | 0 r | |
* 81 | DUP2 | r 0 r | |
* 60 offset | PUSH1 offset | o r 0 r | |
* 3d | RETURNDATASIZE | 0 o r 0 r | |
* 39 | CODECOPY | 0 r | [0..runSize): runtime code |
* f3 | RETURN | | [0..runSize): runtime code |
* ---------------------------------------------------------------------------------------------------|
* RUNTIME (98 bytes + extraLength) |
* ---------------------------------------------------------------------------------------------------|
* Opcode | Mnemonic | Stack | Memory |
* ---------------------------------------------------------------------------------------------------|
* |
* ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 36 | CALLDATASIZE | cds | |
* 3d | RETURNDATASIZE | 0 cds | |
* 3d | RETURNDATASIZE | 0 0 cds | |
* 37 | CALLDATACOPY | | [0..cds): calldata |
* |
* ::: keep some values in stack :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | 0 | [0..cds): calldata |
* 3d | RETURNDATASIZE | 0 0 | [0..cds): calldata |
* 3d | RETURNDATASIZE | 0 0 0 | [0..cds): calldata |
* 3d | RETURNDATASIZE | 0 0 0 0 | [0..cds): calldata |
* 61 extra | PUSH2 extra | e 0 0 0 0 | [0..cds): calldata |
* |
* ::: copy extra data to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 80 | DUP1 | e e 0 0 0 0 | [0..cds): calldata |
* 60 0x35 | PUSH1 0x35 | 0x35 e e 0 0 0 0 | [0..cds): calldata |
* 36 | CALLDATASIZE | cds 0x35 e e 0 0 0 0 | [0..cds): calldata |
* 39 | CODECOPY | e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* |
* ::: delegate call to the implementation contract ::::::::::::::::::::::::::::::::::::::::::::::::: |
* 36 | CALLDATASIZE | cds e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* 01 | ADD | cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* 3d | RETURNDATASIZE | 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* 73 addr | PUSH20 addr | addr 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* 5a | GAS | gas addr 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* f4 | DELEGATECALL | success 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* |
* ::: copy return data to memory ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 3d | RETURNDATASIZE | rds success 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* 3d | RETURNDATASIZE | rds rds success 0 0 | [0..cds): calldata, [cds..cds+e): extraData |
* 93 | SWAP4 | 0 rds success 0 rds | [0..cds): calldata, [cds..cds+e): extraData |
* 80 | DUP1 | 0 0 rds success 0 rds | [0..cds): calldata, [cds..cds+e): extraData |
* 3e | RETURNDATACOPY | success 0 rds | [0..rds): returndata |
* |
* 60 0x33 | PUSH1 0x33 | 0x33 success 0 rds | [0..rds): returndata |
* 57 | JUMPI | 0 rds | [0..rds): returndata |
* |
* ::: revert ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* fd | REVERT | | [0..rds): returndata |
* |
* ::: return ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
* 5b | JUMPDEST | 0 rds | [0..rds): returndata |
* f3 | RETURN | | [0..rds): returndata |
* ---------------------------------------------------------------------------------------------------+
*/
// Write the bytecode before the data.
mstore(data, 0x5af43d3d93803e603357fd5bf3)
// Write the address of the implementation.
mstore(sub(data, 0x0d), implementation)
mstore(
sub(data, 0x21),
or(
shl(0xd8, add(extraLength, 0x35)),
or(shl(0x48, extraLength), 0x6100003d81600a3d39f3363d3d373d3d3d3d610000806035363936013d73)
)
)
mstore(dataEnd, shl(0xf0, extraLength))
// Create the instance.
instance := create2(0, sub(data, 0x1f), add(extraLength, 0x3f), salt)
// If `instance` is zero, revert.
if iszero(instance) {
// Store the function selector of `DeploymentFailed()`.
mstore(0x00, 0x30116425)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
// Restore the overwritten memory surrounding `data`.
mstore(dataEnd, mAfter1)
mstore(data, dataLength)
mstore(sub(data, 0x20), mBefore1)
mstore(sub(data, 0x40), mBefore2)
}
}
/**
* @dev Returns the initialization code hash of the clone of `implementation`
* using immutable arguments encoded in `data`.
* Used for mining vanity addresses with create2crunch.
* @param implementation The address of the implementation contract.
* @param data The encoded immutable arguments.
* @return hash The initialization code hash.
*/
function initCodeHash(address implementation, bytes memory data) internal pure returns (bytes32 hash) {
assembly {
// Compute the boundaries of the data and cache the memory slots around it.
let mBefore2 := mload(sub(data, 0x40))
let mBefore1 := mload(sub(data, 0x20))
let dataLength := mload(data)
let dataEnd := add(add(data, 0x20), dataLength)
let mAfter1 := mload(dataEnd)
// +2 bytes for telling how much data there is appended to the call.
let extraLength := add(dataLength, 2)
// The `creationSize` is `extraLength + 63`
// The `runSize` is `creationSize - 10`.
// if `extraLength` is greater than `0xffca` revert as the `creationSize` would be greater than `0xffff`.
if gt(extraLength, 0xffca) {
// Store the function selector of `PackedDataTooBig()`.
mstore(0x00, 0xc8c78139)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
// Write the bytecode before the data.
mstore(data, 0x5af43d3d93803e603357fd5bf3)
// Write the address of the implementation.
mstore(sub(data, 0x0d), implementation)
mstore(
sub(data, 0x21),
or(
shl(0xd8, add(extraLength, 0x35)),
or(shl(0x48, extraLength), 0x6100003d81600a3d39f3363d3d373d3d3d3d610000806035363936013d73)
)
)
mstore(dataEnd, shl(0xf0, extraLength))
// Create the instance.
hash := keccak256(sub(data, 0x1f), add(extraLength, 0x3f))
// Restore the overwritten memory surrounding `data`.
mstore(dataEnd, mAfter1)
mstore(data, dataLength)
mstore(sub(data, 0x20), mBefore1)
mstore(sub(data, 0x40), mBefore2)
}
}
/**
* @dev Returns the address of the deterministic clone of
* `implementation` using immutable arguments encoded in `data`, with `salt`, by `deployer`.
* @param implementation The address of the implementation.
* @param data The immutable arguments of the implementation.
* @param salt The salt used to compute the address.
* @param deployer The address of the deployer.
* @return predicted The predicted address.
*/
function predictDeterministicAddress(address implementation, bytes memory data, bytes32 salt, address deployer)
internal
pure
returns (address predicted)
{
bytes32 hash = initCodeHash(implementation, data);
predicted = predictDeterministicAddress(hash, salt, deployer);
}
/**
* @dev Returns the address when a contract with initialization code hash,
* `hash`, is deployed with `salt`, by `deployer`.
* @param hash The initialization code hash.
* @param salt The salt used to compute the address.
* @param deployer The address of the deployer.
* @return predicted The predicted address.
*/
function predictDeterministicAddress(bytes32 hash, bytes32 salt, address deployer)
internal
pure
returns (address predicted)
{
/// @solidity memory-safe-assembly
assembly {
// Compute the boundaries of the data and cache the memory slots around it.
let mBefore := mload(0x35)
// Compute and store the bytecode hash.
mstore8(0x00, 0xff) // Write the prefix.
mstore(0x35, hash)
mstore(0x01, shl(96, deployer))
mstore(0x15, salt)
predicted := keccak256(0x00, 0x55)
// Restore the part of the free memory pointer that has been overwritten.
mstore(0x35, mBefore)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import {IPendingOwnable} from "../interfaces/IPendingOwnable.sol";
/**
* @title Pending Ownable
* @author Trader Joe
* @notice Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions. The ownership of this contract is transferred using the
* push and pull pattern, the current owner sets a `pendingOwner` using
* {setPendingOwner} and that address can then call {becomeOwner} to become the
* owner of that contract. The main logic and comments comes from OpenZeppelin's
* Ownable contract.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {setPendingOwner} and {becomeOwner}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner
*/
contract PendingOwnable is IPendingOwnable {
address private _owner;
address private _pendingOwner;
/**
* @notice Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
if (msg.sender != _owner) revert PendingOwnable__NotOwner();
_;
}
/**
* /**
* @notice Throws if called by any account other than the pending owner.
*/
modifier onlyPendingOwner() {
if (msg.sender != _pendingOwner || msg.sender == address(0)) revert PendingOwnable__NotPendingOwner();
_;
}
/**
* /**
* @notice Initializes the contract setting the deployer as the initial owner
*/
constructor() {
_transferOwnership(msg.sender);
}
/**
* @notice Returns the address of the current owner
* @return The address of the current owner
*/
function owner() public view override returns (address) {
return _owner;
}
/**
* @notice Returns the address of the current pending owner
* @return The address of the current pending owner
*/
function pendingOwner() public view override returns (address) {
return _pendingOwner;
}
/**
* @notice Sets the pending owner address. This address will be able to become
* the owner of this contract by calling {becomeOwner}
*/
function setPendingOwner(address pendingOwner_) public override onlyOwner {
if (pendingOwner_ == address(0)) revert PendingOwnable__AddressZero();
if (_pendingOwner != address(0)) revert PendingOwnable__PendingOwnerAlreadySet();
_setPendingOwner(pendingOwner_);
}
/**
* @notice Revoke the pending owner address. This address will not be able to
* call {becomeOwner} to become the owner anymore.
* Can only be called by the owner
*/
function revokePendingOwner() public override onlyOwner {
if (_pendingOwner == address(0)) revert PendingOwnable__NoPendingOwner();
_setPendingOwner(address(0));
}
/**
* @notice Transfers the ownership to the new owner (`pendingOwner).
* Can only be called by the pending owner
*/
function becomeOwner() public override onlyPendingOwner {
_transferOwnership(msg.sender);
}
/**
* @notice Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public override onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
* @param _newOwner The address of the new owner
*/
function _transferOwnership(address _newOwner) internal virtual {
address _oldOwner = _owner;
_owner = _newOwner;
_pendingOwner = address(0);
emit OwnershipTransferred(_oldOwner, _newOwner);
}
/**
* @dev Push the new owner, it needs to be pulled to be effective.
* Internal function without access restriction.
* @param pendingOwner_ The address of the new pending owner
*/
function _setPendingOwner(address pendingOwner_) internal virtual {
_pendingOwner = pendingOwner_;
emit PendingOwnerSet(pendingOwner_);
}
}// SPDX-License-Identifier: MIT
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";
/**
* @title Liquidity Book Price Helper Library
* @author Trader Joe
* @notice This library contains functions to calculate prices
*/
library PriceHelper {
using Uint128x128Math for uint256;
using Uint256x256Math for uint256;
using SafeCast for uint256;
int256 private constant REAL_ID_SHIFT = 1 << 23;
/**
* @dev Calculates the price from the id and the bin step
* @param id The id
* @param binStep The bin step
* @return price The price as a 128.128-binary fixed-point number
*/
function getPriceFromId(uint24 id, uint16 binStep) internal pure returns (uint256 price) {
uint256 base = getBase(binStep);
int256 exponent = getExponent(id);
price = base.pow(exponent);
}
/**
* @dev Calculates the id from the price and the bin step
* @param price The price as a 128.128-binary fixed-point number
* @param binStep The bin step
* @return id The id
*/
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();
}
}
/**
* @dev Calculates the base from the bin step, which is `1 + binStep / BASIS_POINT_MAX`
* @param binStep The bin step
* @return base The base
*/
function getBase(uint16 binStep) internal pure returns (uint256) {
unchecked {
return Constants.SCALE + (uint256(binStep) << Constants.SCALE_OFFSET) / Constants.BASIS_POINT_MAX;
}
}
/**
* @dev Calculates the exponent from the id, which is `id - REAL_ID_SHIFT`
* @param id The id
* @return exponent The exponent
*/
function getExponent(uint24 id) internal pure returns (int256) {
unchecked {
return int256(uint256(id)) - REAL_ID_SHIFT;
}
}
/**
* @dev Converts a price with 18 decimals to a 128.128-binary fixed-point number
* @param price The price with 18 decimals
* @return price128x128 The 128.128-binary fixed-point number
*/
function convertDecimalPriceTo128x128(uint256 price) internal pure returns (uint256) {
return price.shiftDivRoundDown(Constants.SCALE_OFFSET, Constants.PRECISION);
}
/**
* @dev Converts a 128.128-binary fixed-point number to a price with 18 decimals
* @param price128x128 The 128.128-binary fixed-point number
* @return price The price with 18 decimals
*/
function convert128x128PriceToDecimal(uint256 price128x128) internal pure returns (uint256) {
return price128x128.mulShiftRoundDown(Constants.PRECISION, Constants.SCALE_OFFSET);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
/**
* @title Liquidity Book Safe Cast Library
* @author Trader Joe
* @notice This library contains functions to safely cast uint256 to different uint types.
*/
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();
/**
* @dev Returns x on uint248 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint248
*/
function safe248(uint256 x) internal pure returns (uint248 y) {
if ((y = uint248(x)) != x) revert SafeCast__Exceeds248Bits();
}
/**
* @dev Returns x on uint240 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint240
*/
function safe240(uint256 x) internal pure returns (uint240 y) {
if ((y = uint240(x)) != x) revert SafeCast__Exceeds240Bits();
}
/**
* @dev Returns x on uint232 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint232
*/
function safe232(uint256 x) internal pure returns (uint232 y) {
if ((y = uint232(x)) != x) revert SafeCast__Exceeds232Bits();
}
/**
* @dev Returns x on uint224 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint224
*/
function safe224(uint256 x) internal pure returns (uint224 y) {
if ((y = uint224(x)) != x) revert SafeCast__Exceeds224Bits();
}
/**
* @dev Returns x on uint216 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint216
*/
function safe216(uint256 x) internal pure returns (uint216 y) {
if ((y = uint216(x)) != x) revert SafeCast__Exceeds216Bits();
}
/**
* @dev Returns x on uint208 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint208
*/
function safe208(uint256 x) internal pure returns (uint208 y) {
if ((y = uint208(x)) != x) revert SafeCast__Exceeds208Bits();
}
/**
* @dev Returns x on uint200 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint200
*/
function safe200(uint256 x) internal pure returns (uint200 y) {
if ((y = uint200(x)) != x) revert SafeCast__Exceeds200Bits();
}
/**
* @dev Returns x on uint192 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint192
*/
function safe192(uint256 x) internal pure returns (uint192 y) {
if ((y = uint192(x)) != x) revert SafeCast__Exceeds192Bits();
}
/**
* @dev Returns x on uint184 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint184
*/
function safe184(uint256 x) internal pure returns (uint184 y) {
if ((y = uint184(x)) != x) revert SafeCast__Exceeds184Bits();
}
/**
* @dev Returns x on uint176 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint176
*/
function safe176(uint256 x) internal pure returns (uint176 y) {
if ((y = uint176(x)) != x) revert SafeCast__Exceeds176Bits();
}
/**
* @dev Returns x on uint168 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint168
*/
function safe168(uint256 x) internal pure returns (uint168 y) {
if ((y = uint168(x)) != x) revert SafeCast__Exceeds168Bits();
}
/**
* @dev Returns x on uint160 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint160
*/
function safe160(uint256 x) internal pure returns (uint160 y) {
if ((y = uint160(x)) != x) revert SafeCast__Exceeds160Bits();
}
/**
* @dev Returns x on uint152 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint152
*/
function safe152(uint256 x) internal pure returns (uint152 y) {
if ((y = uint152(x)) != x) revert SafeCast__Exceeds152Bits();
}
/**
* @dev Returns x on uint144 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint144
*/
function safe144(uint256 x) internal pure returns (uint144 y) {
if ((y = uint144(x)) != x) revert SafeCast__Exceeds144Bits();
}
/**
* @dev Returns x on uint136 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint136
*/
function safe136(uint256 x) internal pure returns (uint136 y) {
if ((y = uint136(x)) != x) revert SafeCast__Exceeds136Bits();
}
/**
* @dev Returns x on uint128 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint128
*/
function safe128(uint256 x) internal pure returns (uint128 y) {
if ((y = uint128(x)) != x) revert SafeCast__Exceeds128Bits();
}
/**
* @dev Returns x on uint120 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint120
*/
function safe120(uint256 x) internal pure returns (uint120 y) {
if ((y = uint120(x)) != x) revert SafeCast__Exceeds120Bits();
}
/**
* @dev Returns x on uint112 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint112
*/
function safe112(uint256 x) internal pure returns (uint112 y) {
if ((y = uint112(x)) != x) revert SafeCast__Exceeds112Bits();
}
/**
* @dev Returns x on uint104 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint104
*/
function safe104(uint256 x) internal pure returns (uint104 y) {
if ((y = uint104(x)) != x) revert SafeCast__Exceeds104Bits();
}
/**
* @dev Returns x on uint96 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint96
*/
function safe96(uint256 x) internal pure returns (uint96 y) {
if ((y = uint96(x)) != x) revert SafeCast__Exceeds96Bits();
}
/**
* @dev Returns x on uint88 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint88
*/
function safe88(uint256 x) internal pure returns (uint88 y) {
if ((y = uint88(x)) != x) revert SafeCast__Exceeds88Bits();
}
/**
* @dev Returns x on uint80 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint80
*/
function safe80(uint256 x) internal pure returns (uint80 y) {
if ((y = uint80(x)) != x) revert SafeCast__Exceeds80Bits();
}
/**
* @dev Returns x on uint72 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint72
*/
function safe72(uint256 x) internal pure returns (uint72 y) {
if ((y = uint72(x)) != x) revert SafeCast__Exceeds72Bits();
}
/**
* @dev Returns x on uint64 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint64
*/
function safe64(uint256 x) internal pure returns (uint64 y) {
if ((y = uint64(x)) != x) revert SafeCast__Exceeds64Bits();
}
/**
* @dev Returns x on uint56 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint56
*/
function safe56(uint256 x) internal pure returns (uint56 y) {
if ((y = uint56(x)) != x) revert SafeCast__Exceeds56Bits();
}
/**
* @dev Returns x on uint48 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint48
*/
function safe48(uint256 x) internal pure returns (uint48 y) {
if ((y = uint48(x)) != x) revert SafeCast__Exceeds48Bits();
}
/**
* @dev Returns x on uint40 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint40
*/
function safe40(uint256 x) internal pure returns (uint40 y) {
if ((y = uint40(x)) != x) revert SafeCast__Exceeds40Bits();
}
/**
* @dev Returns x on uint32 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint32
*/
function safe32(uint256 x) internal pure returns (uint32 y) {
if ((y = uint32(x)) != x) revert SafeCast__Exceeds32Bits();
}
/**
* @dev Returns x on uint24 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint24
*/
function safe24(uint256 x) internal pure returns (uint24 y) {
if ((y = uint24(x)) != x) revert SafeCast__Exceeds24Bits();
}
/**
* @dev Returns x on uint16 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint16
*/
function safe16(uint256 x) internal pure returns (uint16 y) {
if ((y = uint16(x)) != x) revert SafeCast__Exceeds16Bits();
}
/**
* @dev Returns x on uint8 and check that it does not overflow
* @param x The value as an uint256
* @return y The value as an uint8
*/
function safe8(uint256 x) internal pure returns (uint8 y) {
if ((y = uint8(x)) != x) revert SafeCast__Exceeds8Bits();
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";
import {ILBPair} from "./ILBPair.sol";
import {IPendingOwnable} from "./IPendingOwnable.sol";
/**
* @title Liquidity Book Factory Interface
* @author Trader Joe
* @notice Required interface of LBFactory contract
*/
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();
/**
* @dev Structure to store the LBPair information, such as:
* binStep: The bin step of the LBPair
* LBPair: The address of the LBPair
* createdByOwner: Whether the pair was created by the owner of the factory
* ignoredForRouting: Whether the pair is ignored for routing or not. An ignored pair will not be explored during routes finding
*/
struct LBPairInformation {
uint16 binStep;
ILBPair LBPair;
bool createdByOwner;
bool ignoredForRouting;
}
event LBPairCreated(
IERC20 indexed tokenX, IERC20 indexed tokenY, uint256 indexed binStep, ILBPair LBPair, uint256 pid
);
event FeeRecipientSet(address oldRecipient, address newRecipient);
event FlashLoanFeeSet(uint256 oldFlashLoanFee, uint256 newFlashLoanFee);
event 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;
}// SPDX-License-Identifier: MIT
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;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
/**
* @title Liquidity Book Constants Library
* @author Trader Joe
* @notice Set of constants for Liquidity Book contracts
*/
library Constants {
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; // 10%
uint256 internal constant MAX_PROTOCOL_SHARE = 2_500; // 25% of the fee
uint256 internal constant BASIS_POINT_MAX = 10_000;
/// @dev The expected return after a successful flash loan
bytes32 internal constant CALLBACK_SUCCESS = keccak256("LBPair.onFlashLoan");
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
/**
* @title Liquidity Book Pending Ownable Interface
* @author Trader Joe
* @notice Required interface of Pending Ownable contract used for LBFactory
*/
interface IPendingOwnable {
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;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import {Constants} from "../Constants.sol";
import {BitMath} from "./BitMath.sol";
/**
* @title Liquidity Book Uint128x128 Math Library
* @author Trader Joe
* @notice Helper contract used for power and log calculations
*/
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;
/**
* @notice Calculates the binary logarithm of x.
* @dev Based on the iterative approximation algorithm.
* https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation
* Requirements:
* - x must be greater than zero.
* Caveats:
* - The results are not perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation
* Also because x is converted to an unsigned 129.127-binary fixed-point number during the operation to optimize the multiplication
* @param x The unsigned 128.128-binary fixed-point number for which to calculate the binary logarithm.
* @return result The binary logarithm as a signed 128.128-binary fixed-point number.
*/
function log2(uint256 x) internal pure returns (int256 result) {
// Convert x to a unsigned 129.127-binary fixed-point number to optimize the multiplication.
// If we use an offset of 128 bits, y would need 129 bits and y**2 would would overflow and we would have to
// use mulDiv, by reducing x to 129.127-binary fixed-point number we assert that y will use 128 bits, and we
// can use the regular multiplication
if (x == 1) return -128;
if (x == 0) revert Uint128x128Math__LogUnderflow();
x >>= 1;
unchecked {
// This works because log2(x) = -log2(1/x).
int256 sign;
if (x >= LOG_SCALE) {
sign = 1;
} else {
sign = -1;
// Do the fixed-point inversion inline to save gas
x = LOG_SCALE_SQUARED / x;
}
// Calculate the integer part of the logarithm and add it to the result and finally calculate y = x * 2^(-n).
uint256 n = (x >> LOG_SCALE_OFFSET).mostSignificantBit();
// The integer part of the logarithm as a signed 129.127-binary fixed-point number. The operation can't overflow
// because n is maximum 255, LOG_SCALE_OFFSET is 127 bits and sign is either 1 or -1.
result = int256(n) << LOG_SCALE_OFFSET;
// This is y = x * 2^(-n).
uint256 y = x >> n;
// If y = 1, the fractional part is zero.
if (y != LOG_SCALE) {
// Calculate the fractional part via the iterative approximation.
// The "delta >>= 1" part is equivalent to "delta /= 2", but shifting bits is faster.
for (int256 delta = int256(1 << (LOG_SCALE_OFFSET - 1)); delta > 0; delta >>= 1) {
y = (y * y) >> LOG_SCALE_OFFSET;
// Is y^2 > 2 and so in the range [2,4)?
if (y >= 1 << (LOG_SCALE_OFFSET + 1)) {
// Add the 2^(-m) factor to the logarithm.
result += delta;
// Corresponds to z/2 on Wikipedia.
y >>= 1;
}
}
}
// Convert x back to unsigned 128.128-binary fixed-point number
result = (result * sign) << 1;
}
}
/**
* @notice Returns the value of x^y. It calculates `1 / x^abs(y)` if x is bigger than 2^128.
* At the end of the operations, we invert the result if needed.
* @param x The unsigned 128.128-binary fixed-point number for which to calculate the power
* @param y A relative number without any decimals, needs to be between ]2^21; 2^21[
*/
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)) }
}
}
// revert if y is too big or if x^y underflowed
if (result == 0) revert Uint128x128Math__PowUnderflow(x, y);
return invert ? type(uint256).max / result : result;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
/**
* @title Liquidity Book Uint256x256 Math Library
* @author Trader Joe
* @notice Helper contract used for full precision calculations
*/
library Uint256x256Math {
error Uint256x256Math__MulShiftOverflow();
error Uint256x256Math__MulDivOverflow();
/**
* @notice Calculates floor(x*y/denominator) with full precision
* The result will be rounded down
* @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
* Requirements:
* - The denominator cannot be zero
* - The result must fit within uint256
* Caveats:
* - This function does not work with fixed-point numbers
* @param x The multiplicand as an uint256
* @param y The multiplier as an uint256
* @param denominator The divisor as an uint256
* @return result The result as an uint256
*/
function mulDivRoundDown(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
(uint256 prod0, uint256 prod1) = _getMulProds(x, y);
return _getEndOfDivRoundDown(x, y, denominator, prod0, prod1);
}
/**
* @notice Calculates ceil(x*y/denominator) with full precision
* The result will be rounded up
* @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
* Requirements:
* - The denominator cannot be zero
* - The result must fit within uint256
* Caveats:
* - This function does not work with fixed-point numbers
* @param x The multiplicand as an uint256
* @param y The multiplier as an uint256
* @param denominator The divisor as an uint256
* @return result The result as an uint256
*/
function 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;
}
/**
* @notice Calculates floor(x * y / 2**offset) with full precision
* The result will be rounded down
* @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
* Requirements:
* - The offset needs to be strictly lower than 256
* - The result must fit within uint256
* Caveats:
* - This function does not work with fixed-point numbers
* @param x The multiplicand as an uint256
* @param y The multiplier as an uint256
* @param offset The offset as an uint256, can't be greater than 256
* @return result The result as an uint256
*/
function mulShiftRoundDown(uint256 x, uint256 y, uint8 offset) internal pure returns (uint256 result) {
(uint256 prod0, uint256 prod1) = _getMulProds(x, y);
if (prod0 != 0) result = prod0 >> offset;
if (prod1 != 0) {
// Make sure the result is less than 2^256.
if (prod1 >= 1 << offset) revert Uint256x256Math__MulShiftOverflow();
unchecked {
result += prod1 << (256 - offset);
}
}
}
/**
* @notice Calculates floor(x * y / 2**offset) with full precision
* The result will be rounded down
* @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
* Requirements:
* - The offset needs to be strictly lower than 256
* - The result must fit within uint256
* Caveats:
* - This function does not work with fixed-point numbers
* @param x The multiplicand as an uint256
* @param y The multiplier as an uint256
* @param offset The offset as an uint256, can't be greater than 256
* @return result The result as an uint256
*/
function 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;
}
/**
* @notice Calculates floor(x << offset / y) with full precision
* The result will be rounded down
* @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
* Requirements:
* - The offset needs to be strictly lower than 256
* - The result must fit within uint256
* Caveats:
* - This function does not work with fixed-point numbers
* @param x The multiplicand as an uint256
* @param offset The number of bit to shift x as an uint256
* @param denominator The divisor as an uint256
* @return result The result as an uint256
*/
function shiftDivRoundDown(uint256 x, uint8 offset, uint256 denominator) internal pure returns (uint256 result) {
uint256 prod0;
uint256 prod1;
prod0 = x << offset; // Least significant 256 bits of the product
unchecked {
prod1 = x >> (256 - offset); // Most significant 256 bits of the product
}
return _getEndOfDivRoundDown(x, 1 << offset, denominator, prod0, prod1);
}
/**
* @notice Calculates ceil(x << offset / y) with full precision
* The result will be rounded up
* @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
* Requirements:
* - The offset needs to be strictly lower than 256
* - The result must fit within uint256
* Caveats:
* - This function does not work with fixed-point numbers
* @param x The multiplicand as an uint256
* @param offset The number of bit to shift x as an uint256
* @param denominator The divisor as an uint256
* @return result The result as an uint256
*/
function shiftDivRoundUp(uint256 x, uint8 offset, uint256 denominator) internal pure returns (uint256 result) {
result = shiftDivRoundDown(x, offset, denominator);
if (mulmod(x, 1 << offset, denominator) != 0) result += 1;
}
/**
* @notice Helper function to return the result of `x * y` as 2 uint256
* @param x The multiplicand as an uint256
* @param y The multiplier as an uint256
* @return prod0 The least significant 256 bits of the product
* @return prod1 The most significant 256 bits of the product
*/
function _getMulProds(uint256 x, uint256 y) private pure returns (uint256 prod0, uint256 prod1) {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
}
/**
* @notice Helper function to return the result of `x * y / denominator` with full precision
* @param x The multiplicand as an uint256
* @param y The multiplier as an uint256
* @param denominator The divisor as an uint256
* @param prod0 The least significant 256 bits of the product
* @param prod1 The most significant 256 bits of the product
* @return result The result as an uint256
*/
function _getEndOfDivRoundDown(uint256 x, uint256 y, uint256 denominator, uint256 prod0, uint256 prod1)
private
pure
returns (uint256 result)
{
// Handle non-overflow cases, 256 by 256 division
if (prod1 == 0) {
unchecked {
result = prod0 / denominator;
}
} else {
// Make sure the result is less than 2^256. Also prevents denominator == 0
if (prod1 >= denominator) revert Uint256x256Math__MulDivOverflow();
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1
// See https://cs.stackexchange.com/q/138556/92363
unchecked {
// Does not overflow because the denominator cannot be zero at this stage in the function
uint256 lpotdod = denominator & (~denominator + 1);
assembly {
// Divide denominator by lpotdod.
denominator := div(denominator, lpotdod)
// Divide [prod1 prod0] by lpotdod.
prod0 := div(prod0, lpotdod)
// Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one
lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)
}
// Shift in bits from prod1 into prod0
prod0 |= prod1 * lpotdod;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";
/// @title Liquidity Book Flashloan Callback Interface
/// @author Trader Joe
/// @notice Required interface to interact with LB flash loans
interface ILBFlashLoanCallback {
function LBFlashLoanCallback(
address sender,
IERC20 tokenX,
IERC20 tokenY,
bytes32 amounts,
bytes32 totalFees,
bytes calldata data
) external returns (bytes32);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
/**
* @title Liquidity Book Token Interface
* @author Trader Joe
* @notice Interface to interact with the LBToken.
*/
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;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
/**
* @title Liquidity Book Bit Math Library
* @author Trader Joe
* @notice Helper contract used for bit calculations
*/
library BitMath {
/**
* @dev Returns the index of the closest bit on the right of x that is non null
* @param x The value as a uint256
* @param bit The index of the bit to start searching at
* @return id The index of the closest non null bit on the right of x.
* If there is no closest bit, it returns max(uint256)
*/
function closestBitRight(uint256 x, uint8 bit) internal pure returns (uint256 id) {
unchecked {
uint256 shift = 255 - bit;
x <<= shift;
// can't overflow as it's non-zero and we shifted it by `_shift`
return (x == 0) ? type(uint256).max : mostSignificantBit(x) - shift;
}
}
/**
* @dev Returns the index of the closest bit on the left of x that is non null
* @param x The value as a uint256
* @param bit The index of the bit to start searching at
* @return id The index of the closest non null bit on the left of x.
* If there is no closest bit, it returns max(uint256)
*/
function closestBitLeft(uint256 x, uint8 bit) internal pure returns (uint256 id) {
unchecked {
x >>= bit;
return (x == 0) ? type(uint256).max : leastSignificantBit(x) + bit;
}
}
/**
* @dev Returns the index of the most significant bit of x
* This function returns 0 if x is 0
* @param x The value as a uint256
* @return msb The index of the most significant bit of x
*/
function mostSignificantBit(uint256 x) internal pure returns (uint8 msb) {
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) }
}
}
/**
* @dev Returns the index of the least significant bit of x
* This function returns 255 if x is 0
* @param x The value as a uint256
* @return lsb The index of the least significant bit of x
*/
function leastSignificantBit(uint256 x) internal pure returns (uint8 lsb) {
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)
}
}
}{
"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/",
"lib/forge-std:ds-test/=lib/forge-std/lib/ds-test/src/",
"lib/openzeppelin-contracts:ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
"lib/openzeppelin-contracts:erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"lib/openzeppelin-contracts:forge-std/=lib/openzeppelin-contracts/lib/forge-std/src/"
],
"optimizer": {
"enabled": true,
"runs": 800
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"feeRecipient","type":"address"},{"internalType":"uint256","name":"flashLoanFee","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"LBFactory__AddressZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"binStep","type":"uint256"}],"name":"LBFactory__BinStepHasNoPreset","type":"error"},{"inputs":[{"internalType":"uint256","name":"binStep","type":"uint256"}],"name":"LBFactory__BinStepTooLow","type":"error"},{"inputs":[{"internalType":"uint256","name":"fees","type":"uint256"},{"internalType":"uint256","name":"maxFees","type":"uint256"}],"name":"LBFactory__FlashLoanFeeAboveMax","type":"error"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"LBFactory__IdenticalAddresses","type":"error"},{"inputs":[],"name":"LBFactory__ImplementationNotSet","type":"error"},{"inputs":[{"internalType":"contract IERC20","name":"tokenX","type":"address"},{"internalType":"contract IERC20","name":"tokenY","type":"address"},{"internalType":"uint256","name":"_binStep","type":"uint256"}],"name":"LBFactory__LBPairAlreadyExists","type":"error"},{"inputs":[{"internalType":"contract IERC20","name":"tokenX","type":"address"},{"internalType":"contract IERC20","name":"tokenY","type":"address"},{"internalType":"uint256","name":"binStep","type":"uint256"}],"name":"LBFactory__LBPairDoesNotExist","type":"error"},{"inputs":[],"name":"LBFactory__LBPairIgnoredIsAlreadyInTheSameState","type":"error"},{"inputs":[{"internalType":"contract IERC20","name":"tokenX","type":"address"},{"internalType":"contract IERC20","name":"tokenY","type":"address"},{"internalType":"uint256","name":"binStep","type":"uint256"}],"name":"LBFactory__LBPairNotCreated","type":"error"},{"inputs":[{"internalType":"address","name":"LBPairImplementation","type":"address"}],"name":"LBFactory__LBPairSafetyCheckFailed","type":"error"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"binStep","type":"uint256"}],"name":"LBFactory__PresetIsLockedForUsers","type":"error"},{"inputs":[],"name":"LBFactory__PresetOpenStateIsAlreadyInTheSameState","type":"error"},{"inputs":[{"internalType":"contract IERC20","name":"quoteAsset","type":"address"}],"name":"LBFactory__QuoteAssetAlreadyWhitelisted","type":"error"},{"inputs":[{"internalType":"contract IERC20","name":"quoteAsset","type":"address"}],"name":"LBFactory__QuoteAssetNotWhitelisted","type":"error"},{"inputs":[{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"LBFactory__SameFeeRecipient","type":"error"},{"inputs":[{"internalType":"uint256","name":"flashLoanFee","type":"uint256"}],"name":"LBFactory__SameFlashLoanFee","type":"error"},{"inputs":[{"internalType":"address","name":"LBPairImplementation","type":"address"}],"name":"LBFactory__SameImplementation","type":"error"},{"inputs":[],"name":"PairParametersHelper__InvalidParameter","type":"error"},{"inputs":[],"name":"PendingOwnable__AddressZero","type":"error"},{"inputs":[],"name":"PendingOwnable__NoPendingOwner","type":"error"},{"inputs":[],"name":"PendingOwnable__NotOwner","type":"error"},{"inputs":[],"name":"PendingOwnable__NotPendingOwner","type":"error"},{"inputs":[],"name":"PendingOwnable__PendingOwnerAlreadySet","type":"error"},{"inputs":[],"name":"SafeCast__Exceeds16Bits","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"int256","name":"y","type":"int256"}],"name":"Uint128x128Math__PowUnderflow","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldRecipient","type":"address"},{"indexed":false,"internalType":"address","name":"newRecipient","type":"address"}],"name":"FeeRecipientSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFlashLoanFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFlashLoanFee","type":"uint256"}],"name":"FlashLoanFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC20","name":"tokenX","type":"address"},{"indexed":true,"internalType":"contract IERC20","name":"tokenY","type":"address"},{"indexed":true,"internalType":"uint256","name":"binStep","type":"uint256"},{"indexed":false,"internalType":"contract ILBPair","name":"LBPair","type":"address"},{"indexed":false,"internalType":"uint256","name":"pid","type":"uint256"}],"name":"LBPairCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ILBPair","name":"LBPair","type":"address"},{"indexed":false,"internalType":"bool","name":"ignored","type":"bool"}],"name":"LBPairIgnoredStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldLBPairImplementation","type":"address"},{"indexed":false,"internalType":"address","name":"LBPairImplementation","type":"address"}],"name":"LBPairImplementationSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"PendingOwnerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"binStep","type":"uint256"},{"indexed":true,"internalType":"bool","name":"isOpen","type":"bool"}],"name":"PresetOpenStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"binStep","type":"uint256"}],"name":"PresetRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"binStep","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"baseFactor","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"filterPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"decayPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reductionFactor","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"variableFeeControl","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"protocolShare","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxVolatilityAccumulator","type":"uint256"}],"name":"PresetSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC20","name":"quoteAsset","type":"address"}],"name":"QuoteAssetAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC20","name":"quoteAsset","type":"address"}],"name":"QuoteAssetRemoved","type":"event"},{"inputs":[{"internalType":"contract IERC20","name":"quoteAsset","type":"address"}],"name":"addQuoteAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"becomeOwner","outputs":[],"stateMutability":"nonpayable","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":[{"internalType":"contract ILBPair","name":"pair","type":"address"}],"name":"forceDecay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllBinSteps","outputs":[{"internalType":"uint256[]","name":"binStepWithPreset","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"tokenX","type":"address"},{"internalType":"contract IERC20","name":"tokenY","type":"address"}],"name":"getAllLBPairs","outputs":[{"components":[{"internalType":"uint16","name":"binStep","type":"uint16"},{"internalType":"contract ILBPair","name":"LBPair","type":"address"},{"internalType":"bool","name":"createdByOwner","type":"bool"},{"internalType":"bool","name":"ignoredForRouting","type":"bool"}],"internalType":"struct ILBFactory.LBPairInformation[]","name":"lbPairsAvailable","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFeeRecipient","outputs":[{"internalType":"address","name":"feeRecipient","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFlashLoanFee","outputs":[{"internalType":"uint256","name":"flashLoanFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getLBPairAtIndex","outputs":[{"internalType":"contract ILBPair","name":"lbPair","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLBPairImplementation","outputs":[{"internalType":"address","name":"lbPairImplementation","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"tokenA","type":"address"},{"internalType":"contract IERC20","name":"tokenB","type":"address"},{"internalType":"uint256","name":"binStep","type":"uint256"}],"name":"getLBPairInformation","outputs":[{"components":[{"internalType":"uint16","name":"binStep","type":"uint16"},{"internalType":"contract ILBPair","name":"LBPair","type":"address"},{"internalType":"bool","name":"createdByOwner","type":"bool"},{"internalType":"bool","name":"ignoredForRouting","type":"bool"}],"internalType":"struct ILBFactory.LBPairInformation","name":"lbPairInformation","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxFlashLoanFee","outputs":[{"internalType":"uint256","name":"maxFee","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getMinBinStep","outputs":[{"internalType":"uint256","name":"minBinStep","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getNumberOfLBPairs","outputs":[{"internalType":"uint256","name":"lbPairNumber","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNumberOfQuoteAssets","outputs":[{"internalType":"uint256","name":"numberOfQuoteAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOpenBinSteps","outputs":[{"internalType":"uint256[]","name":"openBinStep","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"binStep","type":"uint256"}],"name":"getPreset","outputs":[{"internalType":"uint256","name":"baseFactor","type":"uint256"},{"internalType":"uint256","name":"filterPeriod","type":"uint256"},{"internalType":"uint256","name":"decayPeriod","type":"uint256"},{"internalType":"uint256","name":"reductionFactor","type":"uint256"},{"internalType":"uint256","name":"variableFeeControl","type":"uint256"},{"internalType":"uint256","name":"protocolShare","type":"uint256"},{"internalType":"uint256","name":"maxVolatilityAccumulator","type":"uint256"},{"internalType":"bool","name":"isOpen","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getQuoteAssetAtIndex","outputs":[{"internalType":"contract IERC20","name":"asset","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"isQuoteAsset","outputs":[{"internalType":"bool","name":"isQuote","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"binStep","type":"uint16"}],"name":"removePreset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"quoteAsset","type":"address"}],"name":"removeQuoteAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"revokePendingOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"setFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"tokenX","type":"address"},{"internalType":"contract IERC20","name":"tokenY","type":"address"},{"internalType":"uint16","name":"binStep","type":"uint16"},{"internalType":"uint16","name":"baseFactor","type":"uint16"},{"internalType":"uint16","name":"filterPeriod","type":"uint16"},{"internalType":"uint16","name":"decayPeriod","type":"uint16"},{"internalType":"uint16","name":"reductionFactor","type":"uint16"},{"internalType":"uint24","name":"variableFeeControl","type":"uint24"},{"internalType":"uint16","name":"protocolShare","type":"uint16"},{"internalType":"uint24","name":"maxVolatilityAccumulator","type":"uint24"}],"name":"setFeesParametersOnPair","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"flashLoanFee","type":"uint256"}],"name":"setFlashLoanFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"tokenX","type":"address"},{"internalType":"contract IERC20","name":"tokenY","type":"address"},{"internalType":"uint16","name":"binStep","type":"uint16"},{"internalType":"bool","name":"ignored","type":"bool"}],"name":"setLBPairIgnored","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newLBPairImplementation","type":"address"}],"name":"setLBPairImplementation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner_","type":"address"}],"name":"setPendingOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"binStep","type":"uint16"},{"internalType":"uint16","name":"baseFactor","type":"uint16"},{"internalType":"uint16","name":"filterPeriod","type":"uint16"},{"internalType":"uint16","name":"decayPeriod","type":"uint16"},{"internalType":"uint16","name":"reductionFactor","type":"uint16"},{"internalType":"uint24","name":"variableFeeControl","type":"uint24"},{"internalType":"uint16","name":"protocolShare","type":"uint16"},{"internalType":"uint24","name":"maxVolatilityAccumulator","type":"uint24"},{"internalType":"bool","name":"isOpen","type":"bool"}],"name":"setPreset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"binStep","type":"uint16"},{"internalType":"bool","name":"isOpen","type":"bool"}],"name":"setPresetOpenState","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60806040523480156200001157600080fd5b5060405162002b9b38038062002b9b8339810160408190526200003491620001f4565b6200003f33620000d1565b67016345785d8a00008111156200007f57604051635e8988c160e01b81526004810182905267016345785d8a000060248201526044015b60405180910390fd5b6200008a826200012b565b60038190556040805160008152602081018390527f5c34e91c94c78b662a45d0bd4a25a4e32c584c54a45a76e4a4d43be27ba40e50910160405180910390a1505062000230565b600080546001600160a01b038381166001600160a01b031980841682178555600180549091169055604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b0381166200015357604051632573cfb960e21b815260040160405180910390fd5b6002546001600160a01b039081169082168114156200019557600254604051634fcea97160e01b81526001600160a01b03909116600482015260240162000076565b600280546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f15d80a013f22151bc7246e3bc132e12828cde19de98870475e3fa70840152721910160405180910390a15050565b600080604083850312156200020857600080fd5b82516001600160a01b03811681146200022057600080fd5b6020939093015192949293505050565b61295b80620002406000396000f3fe608060405234801561001057600080fd5b506004361061020b5760003560e01c8063704037bd1161012a578063b0384781116100bd578063e30c39781161008c578063e92d0d5d11610071578063e92d0d5d14610490578063f9dca989146104a3578063fd90c2be146104ab57600080fd5b8063e30c39781461046c578063e74b981b1461047d57600080fd5b8063b038478114610420578063c42069ec14610433578063ddbfd94114610446578063e203a31f1461045957600080fd5b80638ce9aa1c116100f95780638ce9aa1c146103a05780638da5cb5b146103ae578063aabc4b3c146103bf578063af3710651461040f57600080fd5b8063704037bd1461035d578063715018a61461037d5780637daf5d661461038557806380c5061e1461039857600080fd5b80634e937c3a116101a25780636622e0d7116101715780636622e0d71461031b57806367ab8a4e1461033b57806369d56ea314610343578063701ab8c11461035657600080fd5b80634e937c3a146102db5780635a440923146102ed5780635b35875c14610300578063659ac74b1461030857600080fd5b8063379ee803116101de578063379ee803146102915780633c78a941146102a45780634ccb20c0146102b75780634cd161d3146102c857600080fd5b80630282c9c1146102105780630752092b1461022e578063093ff76914610259578063277218421461026e575b600080fd5b6102186104b3565b6040516102259190612415565b60405180910390f35b61024161023c366004612459565b61058d565b6040516001600160a01b039091168152602001610225565b61026c6102673660046124ac565b6105a0565b005b61028161027c36600461256a565b6106c9565b6040519015158152602001610225565b61026c61029f366004612597565b6106d6565b61026c6102b236600461256a565b610815565b6002546001600160a01b0316610241565b61026c6102d636600461263f565b610896565b6005545b604051908152602001610225565b61026c6102fb36600461256a565b610985565b610218610a1a565b610241610316366004612672565b610a2b565b61032e6103293660046126ca565b610f8f565b6040516102259190612703565b61026c611127565b61026c610351366004612777565b611187565b60016102df565b61037061036b3660046127c4565b611335565b6040516102259190612805565b61026c61136c565b610241610393366004612459565b6113a1565b6102df6113d1565b67016345785d8a00006102df565b6000546001600160a01b0316610241565b6103d26103cd366004612459565b6113dd565b604080519889526020890197909752958701949094526060860192909252608085015260a084015260c0830152151560e082015261010001610225565b6004546001600160a01b0316610241565b61026c61042e36600461256a565b61149e565b61026c61044136600461256a565b611603565b61026c61045436600461256a565b61168b565b61026c610467366004612841565b611720565b6001546001600160a01b0316610241565b61026c61048b36600461256a565b6117af565b61026c61049e366004612459565b6117e3565b61026c6118aa565b6003546102df565b606060006104c160076118e9565b90508015610589578067ffffffffffffffff8111156104e2576104e261285c565b60405190808252806020026020018201604052801561050b578160200160208202803683370190505b5091506000805b8281101561057a576000806105286007846118f4565b909250905061053681611910565b15610567578186858151811061054e5761054e612872565b6020908102919091010152836105638161289e565b9450505b5050806105739061289e565b9050610512565b5081811015610587578083525b505b5090565b600061059a600a8361191c565b92915050565b6000546001600160a01b031633146105cb57604051639f216c1360e01b815260040160405180910390fd5b60006105dc8b8b8b61ffff1661192f565b6020015190506001600160a01b03811661062b5760405163b65ee95360e01b81526001600160a01b03808d1660048301528b16602482015261ffff8a1660448201526064015b60405180910390fd5b604051633329c28d60e11b815261ffff808a16600483015280891660248301528088166044830152808716606483015262ffffff808716608484015290851660a4830152831660c48201526001600160a01b03821690636653851a9060e401600060405180830381600087803b1580156106a457600080fd5b505af11580156106b8573d6000803e3d6000fd5b505050505050505050505050505050565b600061059a600a836119d9565b6000546001600160a01b0316331461070157604051639f216c1360e01b815260040160405180910390fd5b60018961ffff16101561072d57604051634f958e7160e01b815261ffff8a166004820152602401610622565b600061073f818a8a8a8a8a8a8a6119fb565b905081156107575761075481600160ff611afb565b90505b610767600761ffff8c1683611b22565b506040805161ffff8b811682528a8116602083015289811682840152888116606083015262ffffff888116608084015287821660a0840152861660c08301529151918c16917f839844a256a87f87c9c835117d9a1c40be013954064c937072acb32d36db6a289181900360e00190a26040518215159061ffff8c16907f58a8b6a02b964cca2712e5a71d7b0d564a56b4a0f573b4c47f389341ade14cfd90600090a350505050505050505050565b6000546001600160a01b0316331461084057604051639f216c1360e01b815260040160405180910390fd5b806001600160a01b031663d3b9fbe46040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561087b57600080fd5b505af115801561088f573d6000803e3d6000fd5b5050505050565b6000546001600160a01b031633146108c157604051639f216c1360e01b815260040160405180910390fd5b6108d0600761ffff8416611b2f565b6108f357604051637d9160bf60e11b815261ffff83166004820152602401610622565b6000610904600761ffff8516611b3b565b905081151560ff82901c1515141561092f576040516311be38db60e11b815260040160405180910390fd5b61094c61ffff8416610943838560ff611afb565b60079190611b22565b506040518215159061ffff8516907f58a8b6a02b964cca2712e5a71d7b0d564a56b4a0f573b4c47f389341ade14cfd90600090a3505050565b6000546001600160a01b031633146109b057604051639f216c1360e01b815260040160405180910390fd5b6109bb600a82611b47565b6109e3576040516303ce0ad960e01b81526001600160a01b0382166004820152602401610622565b6040516001600160a01b038216907f84cc2115995684dcb0cd3d3a9565e3d32f075de81db70c8dc3a719b2a47af67e90600090a250565b6060610a266007611b5c565b905090565b6000610a3c600761ffff8416611b2f565b610a5f57604051637d9160bf60e11b815261ffff83166004820152602401610622565b6000610a70600761ffff8516611b3b565b90506000610a866000546001600160a01b031690565b6001600160a01b0316336001600160a01b0316149050610aa582611910565b158015610ab0575080155b15610ada576040516304fc2fe760e11b815233600482015261ffff85166024820152604401610622565b610ae5600a876119d9565b610b0d57604051638e888ef360e01b81526001600160a01b0387166004820152602401610622565b856001600160a01b0316876001600160a01b03161415610b4b57604051632f9b185360e01b81526001600160a01b0388166004820152602401610622565b610b558585611b69565b50600080610b638989611bad565b90925090506001600160a01b038216610b8f57604051632573cfb960e21b815260040160405180910390fd5b6001600160a01b0382811660009081526006602090815260408083208585168452825280832061ffff8b1684529091529020546201000090041615610c045760405163cb27a43560e01b81526001600160a01b03808b1660048301528916602482015261ffff87166044820152606401610622565b6004546001600160a01b031680610c2e576040516328b4fcf960e21b815260040160405180910390fd5b6040516bffffffffffffffffffffffff1960608c811b821660208401528b901b1660348201527fffff00000000000000000000000000000000000000000000000000000000000060f089901b166048820152610cdb908290604a0160408051601f198184030181528282526001600160a01b03808916602085015287169183019190915261ffff8b1660608301529060800160405160208183030381529060405280519060200120611bd6565b955050846001600160a01b03166347973bff610cf686611c91565b610cff87611c9d565b610d0888611cad565b610d1189611cbd565b610d1a8a611ccd565b610d238b611cde565b610d2c8c611cee565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e08a901b16815261ffff978816600482015295871660248701529386166044860152918516606485015262ffffff9081166084850152931660a4830152821660c4820152908a1660e482015261010401600060405180830381600087803b158015610dbb57600080fd5b505af1158015610dcf573d6000803e3d6000fd5b50506040805160808101825261ffff808b168083526001600160a01b03808c1660208086018281528c15158789019081526000606089018181528e8716808352600686528b83208f89168085529087528c84208a855287528c84209b518c549651955193511515600160b81b0260ff60b81b19941515600160b01b02949094167fffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffff96909a1662010000027fffffffffffffffffffff000000000000000000000000000000000000000000009097169b169a909a179490941792909216959095171790965560058054600181019091557f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00180546001600160a01b031916909217909155938152600c84528481209281529190925291909120610f1393509150611cff565b508561ffff16886001600160a01b03168a6001600160a01b03167f2c8d104b27c6b7f4492017a6f5cf3803043688934ebcaa6a03540beeaf976aff886001600580549050610f6191906128b9565b604080516001600160a01b03909316835260208301919091520160405180910390a450505050949350505050565b6060600080610f9e8585611bad565b6001600160a01b038083166000908152600c602090815260408083209385168352929052908120929450909250610fd482611d0b565b9050801561111d578067ffffffffffffffff811115610ff557610ff561285c565b60405190808252806020026020018201604052801561104757816020015b6040805160808101825260008082526020808301829052928201819052606082015282526000199092019101816110135790505b506001600160a01b03808616600090815260066020908152604080832093881683529290529081209196505b8281101561111a57600061108f61108a868461191c565b611d15565b6040805160808101825261ffff831680825260008181526020888152848220546001600160a01b03620100008204168286015260ff600160b01b8204811615159686019690965292909152879052600160b81b90049091161515606082015289519192509089908490811061110657611106612872565b602090810291909101015250600101611073565b50505b5050505092915050565b6000546001600160a01b0316331461115257604051639f216c1360e01b815260040160405180910390fd5b6001546001600160a01b031661117b5760405163ecfad6bf60e01b815260040160405180910390fd5b6111856000611d3f565b565b6000546001600160a01b031633146111b257604051639f216c1360e01b815260040160405180910390fd5b6000806111bf8686611bad565b6001600160a01b0380831660009081526006602090815260408083208486168452825280832061ffff808c1685529083529281902081516080810183529054938416815262010000840490941691840182905260ff600160b01b84048116151591850191909152600160b81b90920490911615156060830152929450909250906112795760405163102a919160e21b81526001600160a01b0380891660048301528716602482015261ffff86166044820152606401610622565b8315158160600151151514156112a157604051626ee66560e11b815260040160405180910390fd5b6001600160a01b0380841660009081526006602090815260408083208685168452825280832061ffff8a1684528252918290208054881515600160b81b0260ff60b81b1990911617905583015190519116907f44cf35361c9ff3c8c1397ec6410d5495cc481feaef35c9af11da1a637107de4f9061132490871515815260200190565b60405180910390a250505050505050565b60408051608081018252600080825260208201819052918101829052606081019190915261136484848461192f565b949350505050565b6000546001600160a01b0316331461139757604051639f216c1360e01b815260040160405180910390fd5b6111856000611d89565b6000600582815481106113b6576113b6612872565b6000918252602090912001546001600160a01b031692915050565b6000610a26600a611d0b565b6000808080808080806113f160078a611b2f565b61141157604051637d9160bf60e11b8152600481018a9052602401610622565b600061141e60078b611b3b565b905061142981611c91565b61ffff16985061143881611c9d565b61ffff16975061144781611cad565b61ffff16965061145681611cbd565b61ffff16955061146581611ccd565b62ffffff16945061147581611cde565b61ffff16935061148481611cee565b62ffffff16925060ff81901c915050919395975091939597565b6000546001600160a01b031633146114c957604051639f216c1360e01b815260040160405180910390fd5b306001600160a01b0316816001600160a01b03166388cc58e46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611511573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153591906128d0565b6001600160a01b03161461156757604051630a3e70af60e11b81526001600160a01b0382166004820152602401610622565b6004546001600160a01b039081169082168114156115a357604051630ded3b9560e31b81526001600160a01b0383166004820152602401610622565b600480546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f900d0e3d359f50e4f923ecdc06b401e07dbb9f485e17b07bcfc91a13000b277e91015b60405180910390a15050565b6000546001600160a01b0316331461162e57604051639f216c1360e01b815260040160405180910390fd5b6001600160a01b038116611655576040516391f3851560e01b815260040160405180910390fd5b6001546001600160a01b03161561167f5760405163716b1fbf60e01b815260040160405180910390fd5b61168881611d3f565b50565b6000546001600160a01b031633146116b657604051639f216c1360e01b815260040160405180910390fd5b6116c1600a82611de3565b6116e957604051638e888ef360e01b81526001600160a01b0382166004820152602401610622565b6040516001600160a01b038216907f0b767739217755d8af5a2ba75b181a19fa1750f8bb701f09311cb19a90140cb390600090a250565b6000546001600160a01b0316331461174b57604051639f216c1360e01b815260040160405180910390fd5b61175a600761ffff8316611df8565b61177d57604051637d9160bf60e11b815261ffff82166004820152602401610622565b60405161ffff8216907fdd86b848bb56ff540caa68683fa467d0e7eb5f8b2d44e4ee435742eeeae9be1390600090a250565b6000546001600160a01b031633146117da57604051639f216c1360e01b815260040160405180910390fd5b61168881611e04565b6000546001600160a01b0316331461180e57604051639f216c1360e01b815260040160405180910390fd5b6003548181141561183557604051631baa31e960e21b815260048101839052602401610622565b67016345785d8a000082111561186f57604051635e8988c160e01b81526004810183905267016345785d8a00006024820152604401610622565b600382905560408051828152602081018490527f5c34e91c94c78b662a45d0bd4a25a4e32c584c54a45a76e4a4d43be27ba40e5091016115f7565b6001546001600160a01b0316331415806118c2575033155b156118e057604051633982680960e11b815260040160405180910390fd5b61118533611d89565b600061059a82611ec3565b60008080806119038686611ece565b9097909650945050505050565b600060ff82901c61059a565b60006119288383611ef9565b9392505050565b60408051608081018252600080825260208201819052918101829052606081019190915261195d8484611bad565b6001600160a01b03918216600090815260066020908152604080832093851683529281528282209582529485528190208151608081018352905461ffff811682526201000081049093169481019490945260ff600160b01b83048116151591850191909152600160b81b90910416151560608301525092915050565b6001600160a01b03811660009081526001830160205260408120541515611928565b60008561ffff168761ffff161180611a185750610fff8661ffff16115b80611a2857506127108561ffff16115b80611a3857506109c48361ffff16115b80611a4a5750620fffff8262ffffff16115b15611a6857604051631c07203f60e01b815260040160405180910390fd5b5060109590951b630fff00001661ffff9690961695909517601c9390931b64fff0000000169290921760289190911b663fff0000000000161760369190911b693fffffc00000000000001617604e9290921b6b0fffc00000000000000000001691909117605c9190911b6dfffff0000000000000000000000016176dffffffffffffffffffffffffffff19919091161790565b60006113648484611b0d576000611b10565b60015b600180861b19929092169116841b1790565b6000611364848484611f23565b60006119288383611f40565b60006119288383611f4c565b6000611928836001600160a01b038416611fbc565b606060006119288361200b565b600061271071ffff00000000000000000000000000000000608084901b1604600160801b0162ffffff8416627fffff1901611ba48282612016565b95945050505050565b600080826001600160a01b0316846001600160a01b03161115611bce579192915b509192909150565b600060408303516020840351845180602087010180516002830161ffca811115611c085763c8c781396000526004601cfd5b6c5af43d3d93803e603357fd5bf3895289600d8a03527d6100003d81600a3d39f3363d3d373d3d3d3d610000806035363936013d738160481b176035820160d81b1760218a03528060f01b835287603f8201601f8b036000f596505085611c775763301164256000526004601cfd5b90528552601f19850152603f199093019290925250919050565b600061ffff821661059a565b600061059a8260101c610fff1690565b600061059a82601c1c610fff1690565b600061059a8260281c613fff1690565b600061059a8260361c62ffffff1690565b600061059a82604e1c613fff1690565b600061059a82605c1c620fffff1690565b60006119288383611fbc565b600061059a825490565b8061ffff81168114611d3a576040516364ae406d60e01b815260040160405180910390fd5b919050565b600180546001600160a01b0319166001600160a01b0383169081179091556040517f68f49b346b94582a8b5f9d10e3fe3365318fe8f191ff8dce7c59c6cad06b02f590600090a250565b600080546001600160a01b038381166001600160a01b031980841682178555600180549091169055604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000611928836001600160a01b038416612278565b6000611928838361236b565b6001600160a01b038116611e2b57604051632573cfb960e21b815260040160405180910390fd5b6002546001600160a01b03908116908216811415611e6b57600254604051634fcea97160e01b81526001600160a01b039091166004820152602401610622565b600280546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f15d80a013f22151bc7246e3bc132e12828cde19de98870475e3fa7084015272191016115f7565b600061059a82611d0b565b60008080611edc858561191c565b600081815260029690960160205260409095205494959350505050565b6000826000018281548110611f1057611f10612872565b9060005260206000200154905092915050565b600082815260028401602052604081208290556113648484611cff565b60006119288383612388565b600081815260028301602052604081205480151580611f705750611f708484611f40565b6119285760405162461bcd60e51b815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b657900006044820152606401610622565b60008181526001830160205260408120546120035750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561059a565b50600061059a565b606061059a826123a0565b600080808361202e5750600160801b915061059a9050565b50826000811215612040579015906000035b6210000081101561223957600160801b9250846fffffffffffffffffffffffffffffffff81111561207357911591600019045b60018216156120845792830260801c925b800260801c600282161561209a5792830260801c925b800260801c60048216156120b05792830260801c925b800260801c60088216156120c65792830260801c925b800260801c60108216156120dc5792830260801c925b800260801c60208216156120f25792830260801c925b800260801c60408216156121085792830260801c925b8002608090811c9082161561211f5792830260801c925b800260801c6101008216156121365792830260801c925b800260801c61020082161561214d5792830260801c925b800260801c6104008216156121645792830260801c925b800260801c61080082161561217b5792830260801c925b800260801c6110008216156121925792830260801c925b800260801c6120008216156121a95792830260801c925b800260801c6140008216156121c05792830260801c925b800260801c6180008216156121d75792830260801c925b800260801c620100008216156121ef5792830260801c925b800260801c620200008216156122075792830260801c925b800260801c6204000082161561221f5792830260801c925b800260801c620800008216156122375792830260801c925b505b8261226157604051631dba598d60e11b81526004810186905260248101859052604401610622565b8161226c5782611ba4565b611ba4836000196128ed565b6000818152600183016020526040812054801561236157600061229c6001836128b9565b85549091506000906122b0906001906128b9565b90508181146123155760008660000182815481106122d0576122d0612872565b90600052602060002001549050808760000184815481106122f3576122f3612872565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806123265761232661290f565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061059a565b600091505061059a565b6000818152600283016020526040812081905561192883836123ad565b60008181526001830160205260408120541515611928565b60606000611928836123b9565b60006119288383612278565b60608160000180548060200260200160405190810160405280929190818152602001828054801561240957602002820191906000526020600020905b8154815260200190600101908083116123f5575b50505050509050919050565b6020808252825182820181905260009190848201906040850190845b8181101561244d57835183529284019291840191600101612431565b50909695505050505050565b60006020828403121561246b57600080fd5b5035919050565b6001600160a01b038116811461168857600080fd5b803561ffff81168114611d3a57600080fd5b803562ffffff81168114611d3a57600080fd5b6000806000806000806000806000806101408b8d0312156124cc57600080fd5b8a356124d781612472565b995060208b01356124e781612472565b98506124f560408c01612487565b975061250360608c01612487565b965061251160808c01612487565b955061251f60a08c01612487565b945061252d60c08c01612487565b935061253b60e08c01612499565b925061254a6101008c01612487565b91506125596101208c01612499565b90509295989b9194979a5092959850565b60006020828403121561257c57600080fd5b813561192881612472565b80358015158114611d3a57600080fd5b60008060008060008060008060006101208a8c0312156125b657600080fd5b6125bf8a612487565b98506125cd60208b01612487565b97506125db60408b01612487565b96506125e960608b01612487565b95506125f760808b01612487565b945061260560a08b01612499565b935061261360c08b01612487565b925061262160e08b01612499565b91506126306101008b01612587565b90509295985092959850929598565b6000806040838503121561265257600080fd5b61265b83612487565b915061266960208401612587565b90509250929050565b6000806000806080858703121561268857600080fd5b843561269381612472565b935060208501356126a381612472565b92506126b160408601612499565b91506126bf60608601612487565b905092959194509250565b600080604083850312156126dd57600080fd5b82356126e881612472565b915060208301356126f881612472565b809150509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561244d5761276483855161ffff81511682526001600160a01b0360208201511660208301526040810151151560408301526060810151151560608301525050565b928401926080929092019160010161271f565b6000806000806080858703121561278d57600080fd5b843561279881612472565b935060208501356127a881612472565b92506127b660408601612487565b91506126bf60608601612587565b6000806000606084860312156127d957600080fd5b83356127e481612472565b925060208401356127f481612472565b929592945050506040919091013590565b815161ffff1681526020808301516001600160a01b0316908201526040808301511515908201526060808301511515908201526080810161059a565b60006020828403121561285357600080fd5b61192882612487565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006000198214156128b2576128b2612888565b5060010190565b6000828210156128cb576128cb612888565b500390565b6000602082840312156128e257600080fd5b815161192881612472565b60008261290a57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603160045260246000fdfea2646970667358221220079cb1c62be258c69df2ae0da85aaf7db5b67bbc079c22b17ba701294c1fce6f64736f6c634300080a00330000000000000000000000001f36930a75c44f323d4d66aee449af0c72d19f2e0000000000000000000000000000000000000000000000000000048c27395000
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061020b5760003560e01c8063704037bd1161012a578063b0384781116100bd578063e30c39781161008c578063e92d0d5d11610071578063e92d0d5d14610490578063f9dca989146104a3578063fd90c2be146104ab57600080fd5b8063e30c39781461046c578063e74b981b1461047d57600080fd5b8063b038478114610420578063c42069ec14610433578063ddbfd94114610446578063e203a31f1461045957600080fd5b80638ce9aa1c116100f95780638ce9aa1c146103a05780638da5cb5b146103ae578063aabc4b3c146103bf578063af3710651461040f57600080fd5b8063704037bd1461035d578063715018a61461037d5780637daf5d661461038557806380c5061e1461039857600080fd5b80634e937c3a116101a25780636622e0d7116101715780636622e0d71461031b57806367ab8a4e1461033b57806369d56ea314610343578063701ab8c11461035657600080fd5b80634e937c3a146102db5780635a440923146102ed5780635b35875c14610300578063659ac74b1461030857600080fd5b8063379ee803116101de578063379ee803146102915780633c78a941146102a45780634ccb20c0146102b75780634cd161d3146102c857600080fd5b80630282c9c1146102105780630752092b1461022e578063093ff76914610259578063277218421461026e575b600080fd5b6102186104b3565b6040516102259190612415565b60405180910390f35b61024161023c366004612459565b61058d565b6040516001600160a01b039091168152602001610225565b61026c6102673660046124ac565b6105a0565b005b61028161027c36600461256a565b6106c9565b6040519015158152602001610225565b61026c61029f366004612597565b6106d6565b61026c6102b236600461256a565b610815565b6002546001600160a01b0316610241565b61026c6102d636600461263f565b610896565b6005545b604051908152602001610225565b61026c6102fb36600461256a565b610985565b610218610a1a565b610241610316366004612672565b610a2b565b61032e6103293660046126ca565b610f8f565b6040516102259190612703565b61026c611127565b61026c610351366004612777565b611187565b60016102df565b61037061036b3660046127c4565b611335565b6040516102259190612805565b61026c61136c565b610241610393366004612459565b6113a1565b6102df6113d1565b67016345785d8a00006102df565b6000546001600160a01b0316610241565b6103d26103cd366004612459565b6113dd565b604080519889526020890197909752958701949094526060860192909252608085015260a084015260c0830152151560e082015261010001610225565b6004546001600160a01b0316610241565b61026c61042e36600461256a565b61149e565b61026c61044136600461256a565b611603565b61026c61045436600461256a565b61168b565b61026c610467366004612841565b611720565b6001546001600160a01b0316610241565b61026c61048b36600461256a565b6117af565b61026c61049e366004612459565b6117e3565b61026c6118aa565b6003546102df565b606060006104c160076118e9565b90508015610589578067ffffffffffffffff8111156104e2576104e261285c565b60405190808252806020026020018201604052801561050b578160200160208202803683370190505b5091506000805b8281101561057a576000806105286007846118f4565b909250905061053681611910565b15610567578186858151811061054e5761054e612872565b6020908102919091010152836105638161289e565b9450505b5050806105739061289e565b9050610512565b5081811015610587578083525b505b5090565b600061059a600a8361191c565b92915050565b6000546001600160a01b031633146105cb57604051639f216c1360e01b815260040160405180910390fd5b60006105dc8b8b8b61ffff1661192f565b6020015190506001600160a01b03811661062b5760405163b65ee95360e01b81526001600160a01b03808d1660048301528b16602482015261ffff8a1660448201526064015b60405180910390fd5b604051633329c28d60e11b815261ffff808a16600483015280891660248301528088166044830152808716606483015262ffffff808716608484015290851660a4830152831660c48201526001600160a01b03821690636653851a9060e401600060405180830381600087803b1580156106a457600080fd5b505af11580156106b8573d6000803e3d6000fd5b505050505050505050505050505050565b600061059a600a836119d9565b6000546001600160a01b0316331461070157604051639f216c1360e01b815260040160405180910390fd5b60018961ffff16101561072d57604051634f958e7160e01b815261ffff8a166004820152602401610622565b600061073f818a8a8a8a8a8a8a6119fb565b905081156107575761075481600160ff611afb565b90505b610767600761ffff8c1683611b22565b506040805161ffff8b811682528a8116602083015289811682840152888116606083015262ffffff888116608084015287821660a0840152861660c08301529151918c16917f839844a256a87f87c9c835117d9a1c40be013954064c937072acb32d36db6a289181900360e00190a26040518215159061ffff8c16907f58a8b6a02b964cca2712e5a71d7b0d564a56b4a0f573b4c47f389341ade14cfd90600090a350505050505050505050565b6000546001600160a01b0316331461084057604051639f216c1360e01b815260040160405180910390fd5b806001600160a01b031663d3b9fbe46040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561087b57600080fd5b505af115801561088f573d6000803e3d6000fd5b5050505050565b6000546001600160a01b031633146108c157604051639f216c1360e01b815260040160405180910390fd5b6108d0600761ffff8416611b2f565b6108f357604051637d9160bf60e11b815261ffff83166004820152602401610622565b6000610904600761ffff8516611b3b565b905081151560ff82901c1515141561092f576040516311be38db60e11b815260040160405180910390fd5b61094c61ffff8416610943838560ff611afb565b60079190611b22565b506040518215159061ffff8516907f58a8b6a02b964cca2712e5a71d7b0d564a56b4a0f573b4c47f389341ade14cfd90600090a3505050565b6000546001600160a01b031633146109b057604051639f216c1360e01b815260040160405180910390fd5b6109bb600a82611b47565b6109e3576040516303ce0ad960e01b81526001600160a01b0382166004820152602401610622565b6040516001600160a01b038216907f84cc2115995684dcb0cd3d3a9565e3d32f075de81db70c8dc3a719b2a47af67e90600090a250565b6060610a266007611b5c565b905090565b6000610a3c600761ffff8416611b2f565b610a5f57604051637d9160bf60e11b815261ffff83166004820152602401610622565b6000610a70600761ffff8516611b3b565b90506000610a866000546001600160a01b031690565b6001600160a01b0316336001600160a01b0316149050610aa582611910565b158015610ab0575080155b15610ada576040516304fc2fe760e11b815233600482015261ffff85166024820152604401610622565b610ae5600a876119d9565b610b0d57604051638e888ef360e01b81526001600160a01b0387166004820152602401610622565b856001600160a01b0316876001600160a01b03161415610b4b57604051632f9b185360e01b81526001600160a01b0388166004820152602401610622565b610b558585611b69565b50600080610b638989611bad565b90925090506001600160a01b038216610b8f57604051632573cfb960e21b815260040160405180910390fd5b6001600160a01b0382811660009081526006602090815260408083208585168452825280832061ffff8b1684529091529020546201000090041615610c045760405163cb27a43560e01b81526001600160a01b03808b1660048301528916602482015261ffff87166044820152606401610622565b6004546001600160a01b031680610c2e576040516328b4fcf960e21b815260040160405180910390fd5b6040516bffffffffffffffffffffffff1960608c811b821660208401528b901b1660348201527fffff00000000000000000000000000000000000000000000000000000000000060f089901b166048820152610cdb908290604a0160408051601f198184030181528282526001600160a01b03808916602085015287169183019190915261ffff8b1660608301529060800160405160208183030381529060405280519060200120611bd6565b955050846001600160a01b03166347973bff610cf686611c91565b610cff87611c9d565b610d0888611cad565b610d1189611cbd565b610d1a8a611ccd565b610d238b611cde565b610d2c8c611cee565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e08a901b16815261ffff978816600482015295871660248701529386166044860152918516606485015262ffffff9081166084850152931660a4830152821660c4820152908a1660e482015261010401600060405180830381600087803b158015610dbb57600080fd5b505af1158015610dcf573d6000803e3d6000fd5b50506040805160808101825261ffff808b168083526001600160a01b03808c1660208086018281528c15158789019081526000606089018181528e8716808352600686528b83208f89168085529087528c84208a855287528c84209b518c549651955193511515600160b81b0260ff60b81b19941515600160b01b02949094167fffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffff96909a1662010000027fffffffffffffffffffff000000000000000000000000000000000000000000009097169b169a909a179490941792909216959095171790965560058054600181019091557f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00180546001600160a01b031916909217909155938152600c84528481209281529190925291909120610f1393509150611cff565b508561ffff16886001600160a01b03168a6001600160a01b03167f2c8d104b27c6b7f4492017a6f5cf3803043688934ebcaa6a03540beeaf976aff886001600580549050610f6191906128b9565b604080516001600160a01b03909316835260208301919091520160405180910390a450505050949350505050565b6060600080610f9e8585611bad565b6001600160a01b038083166000908152600c602090815260408083209385168352929052908120929450909250610fd482611d0b565b9050801561111d578067ffffffffffffffff811115610ff557610ff561285c565b60405190808252806020026020018201604052801561104757816020015b6040805160808101825260008082526020808301829052928201819052606082015282526000199092019101816110135790505b506001600160a01b03808616600090815260066020908152604080832093881683529290529081209196505b8281101561111a57600061108f61108a868461191c565b611d15565b6040805160808101825261ffff831680825260008181526020888152848220546001600160a01b03620100008204168286015260ff600160b01b8204811615159686019690965292909152879052600160b81b90049091161515606082015289519192509089908490811061110657611106612872565b602090810291909101015250600101611073565b50505b5050505092915050565b6000546001600160a01b0316331461115257604051639f216c1360e01b815260040160405180910390fd5b6001546001600160a01b031661117b5760405163ecfad6bf60e01b815260040160405180910390fd5b6111856000611d3f565b565b6000546001600160a01b031633146111b257604051639f216c1360e01b815260040160405180910390fd5b6000806111bf8686611bad565b6001600160a01b0380831660009081526006602090815260408083208486168452825280832061ffff808c1685529083529281902081516080810183529054938416815262010000840490941691840182905260ff600160b01b84048116151591850191909152600160b81b90920490911615156060830152929450909250906112795760405163102a919160e21b81526001600160a01b0380891660048301528716602482015261ffff86166044820152606401610622565b8315158160600151151514156112a157604051626ee66560e11b815260040160405180910390fd5b6001600160a01b0380841660009081526006602090815260408083208685168452825280832061ffff8a1684528252918290208054881515600160b81b0260ff60b81b1990911617905583015190519116907f44cf35361c9ff3c8c1397ec6410d5495cc481feaef35c9af11da1a637107de4f9061132490871515815260200190565b60405180910390a250505050505050565b60408051608081018252600080825260208201819052918101829052606081019190915261136484848461192f565b949350505050565b6000546001600160a01b0316331461139757604051639f216c1360e01b815260040160405180910390fd5b6111856000611d89565b6000600582815481106113b6576113b6612872565b6000918252602090912001546001600160a01b031692915050565b6000610a26600a611d0b565b6000808080808080806113f160078a611b2f565b61141157604051637d9160bf60e11b8152600481018a9052602401610622565b600061141e60078b611b3b565b905061142981611c91565b61ffff16985061143881611c9d565b61ffff16975061144781611cad565b61ffff16965061145681611cbd565b61ffff16955061146581611ccd565b62ffffff16945061147581611cde565b61ffff16935061148481611cee565b62ffffff16925060ff81901c915050919395975091939597565b6000546001600160a01b031633146114c957604051639f216c1360e01b815260040160405180910390fd5b306001600160a01b0316816001600160a01b03166388cc58e46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611511573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153591906128d0565b6001600160a01b03161461156757604051630a3e70af60e11b81526001600160a01b0382166004820152602401610622565b6004546001600160a01b039081169082168114156115a357604051630ded3b9560e31b81526001600160a01b0383166004820152602401610622565b600480546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f900d0e3d359f50e4f923ecdc06b401e07dbb9f485e17b07bcfc91a13000b277e91015b60405180910390a15050565b6000546001600160a01b0316331461162e57604051639f216c1360e01b815260040160405180910390fd5b6001600160a01b038116611655576040516391f3851560e01b815260040160405180910390fd5b6001546001600160a01b03161561167f5760405163716b1fbf60e01b815260040160405180910390fd5b61168881611d3f565b50565b6000546001600160a01b031633146116b657604051639f216c1360e01b815260040160405180910390fd5b6116c1600a82611de3565b6116e957604051638e888ef360e01b81526001600160a01b0382166004820152602401610622565b6040516001600160a01b038216907f0b767739217755d8af5a2ba75b181a19fa1750f8bb701f09311cb19a90140cb390600090a250565b6000546001600160a01b0316331461174b57604051639f216c1360e01b815260040160405180910390fd5b61175a600761ffff8316611df8565b61177d57604051637d9160bf60e11b815261ffff82166004820152602401610622565b60405161ffff8216907fdd86b848bb56ff540caa68683fa467d0e7eb5f8b2d44e4ee435742eeeae9be1390600090a250565b6000546001600160a01b031633146117da57604051639f216c1360e01b815260040160405180910390fd5b61168881611e04565b6000546001600160a01b0316331461180e57604051639f216c1360e01b815260040160405180910390fd5b6003548181141561183557604051631baa31e960e21b815260048101839052602401610622565b67016345785d8a000082111561186f57604051635e8988c160e01b81526004810183905267016345785d8a00006024820152604401610622565b600382905560408051828152602081018490527f5c34e91c94c78b662a45d0bd4a25a4e32c584c54a45a76e4a4d43be27ba40e5091016115f7565b6001546001600160a01b0316331415806118c2575033155b156118e057604051633982680960e11b815260040160405180910390fd5b61118533611d89565b600061059a82611ec3565b60008080806119038686611ece565b9097909650945050505050565b600060ff82901c61059a565b60006119288383611ef9565b9392505050565b60408051608081018252600080825260208201819052918101829052606081019190915261195d8484611bad565b6001600160a01b03918216600090815260066020908152604080832093851683529281528282209582529485528190208151608081018352905461ffff811682526201000081049093169481019490945260ff600160b01b83048116151591850191909152600160b81b90910416151560608301525092915050565b6001600160a01b03811660009081526001830160205260408120541515611928565b60008561ffff168761ffff161180611a185750610fff8661ffff16115b80611a2857506127108561ffff16115b80611a3857506109c48361ffff16115b80611a4a5750620fffff8262ffffff16115b15611a6857604051631c07203f60e01b815260040160405180910390fd5b5060109590951b630fff00001661ffff9690961695909517601c9390931b64fff0000000169290921760289190911b663fff0000000000161760369190911b693fffffc00000000000001617604e9290921b6b0fffc00000000000000000001691909117605c9190911b6dfffff0000000000000000000000016176dffffffffffffffffffffffffffff19919091161790565b60006113648484611b0d576000611b10565b60015b600180861b19929092169116841b1790565b6000611364848484611f23565b60006119288383611f40565b60006119288383611f4c565b6000611928836001600160a01b038416611fbc565b606060006119288361200b565b600061271071ffff00000000000000000000000000000000608084901b1604600160801b0162ffffff8416627fffff1901611ba48282612016565b95945050505050565b600080826001600160a01b0316846001600160a01b03161115611bce579192915b509192909150565b600060408303516020840351845180602087010180516002830161ffca811115611c085763c8c781396000526004601cfd5b6c5af43d3d93803e603357fd5bf3895289600d8a03527d6100003d81600a3d39f3363d3d373d3d3d3d610000806035363936013d738160481b176035820160d81b1760218a03528060f01b835287603f8201601f8b036000f596505085611c775763301164256000526004601cfd5b90528552601f19850152603f199093019290925250919050565b600061ffff821661059a565b600061059a8260101c610fff1690565b600061059a82601c1c610fff1690565b600061059a8260281c613fff1690565b600061059a8260361c62ffffff1690565b600061059a82604e1c613fff1690565b600061059a82605c1c620fffff1690565b60006119288383611fbc565b600061059a825490565b8061ffff81168114611d3a576040516364ae406d60e01b815260040160405180910390fd5b919050565b600180546001600160a01b0319166001600160a01b0383169081179091556040517f68f49b346b94582a8b5f9d10e3fe3365318fe8f191ff8dce7c59c6cad06b02f590600090a250565b600080546001600160a01b038381166001600160a01b031980841682178555600180549091169055604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000611928836001600160a01b038416612278565b6000611928838361236b565b6001600160a01b038116611e2b57604051632573cfb960e21b815260040160405180910390fd5b6002546001600160a01b03908116908216811415611e6b57600254604051634fcea97160e01b81526001600160a01b039091166004820152602401610622565b600280546001600160a01b0319166001600160a01b0384811691821790925560408051928416835260208301919091527f15d80a013f22151bc7246e3bc132e12828cde19de98870475e3fa7084015272191016115f7565b600061059a82611d0b565b60008080611edc858561191c565b600081815260029690960160205260409095205494959350505050565b6000826000018281548110611f1057611f10612872565b9060005260206000200154905092915050565b600082815260028401602052604081208290556113648484611cff565b60006119288383612388565b600081815260028301602052604081205480151580611f705750611f708484611f40565b6119285760405162461bcd60e51b815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b657900006044820152606401610622565b60008181526001830160205260408120546120035750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561059a565b50600061059a565b606061059a826123a0565b600080808361202e5750600160801b915061059a9050565b50826000811215612040579015906000035b6210000081101561223957600160801b9250846fffffffffffffffffffffffffffffffff81111561207357911591600019045b60018216156120845792830260801c925b800260801c600282161561209a5792830260801c925b800260801c60048216156120b05792830260801c925b800260801c60088216156120c65792830260801c925b800260801c60108216156120dc5792830260801c925b800260801c60208216156120f25792830260801c925b800260801c60408216156121085792830260801c925b8002608090811c9082161561211f5792830260801c925b800260801c6101008216156121365792830260801c925b800260801c61020082161561214d5792830260801c925b800260801c6104008216156121645792830260801c925b800260801c61080082161561217b5792830260801c925b800260801c6110008216156121925792830260801c925b800260801c6120008216156121a95792830260801c925b800260801c6140008216156121c05792830260801c925b800260801c6180008216156121d75792830260801c925b800260801c620100008216156121ef5792830260801c925b800260801c620200008216156122075792830260801c925b800260801c6204000082161561221f5792830260801c925b800260801c620800008216156122375792830260801c925b505b8261226157604051631dba598d60e11b81526004810186905260248101859052604401610622565b8161226c5782611ba4565b611ba4836000196128ed565b6000818152600183016020526040812054801561236157600061229c6001836128b9565b85549091506000906122b0906001906128b9565b90508181146123155760008660000182815481106122d0576122d0612872565b90600052602060002001549050808760000184815481106122f3576122f3612872565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806123265761232661290f565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061059a565b600091505061059a565b6000818152600283016020526040812081905561192883836123ad565b60008181526001830160205260408120541515611928565b60606000611928836123b9565b60006119288383612278565b60608160000180548060200260200160405190810160405280929190818152602001828054801561240957602002820191906000526020600020905b8154815260200190600101908083116123f5575b50505050509050919050565b6020808252825182820181905260009190848201906040850190845b8181101561244d57835183529284019291840191600101612431565b50909695505050505050565b60006020828403121561246b57600080fd5b5035919050565b6001600160a01b038116811461168857600080fd5b803561ffff81168114611d3a57600080fd5b803562ffffff81168114611d3a57600080fd5b6000806000806000806000806000806101408b8d0312156124cc57600080fd5b8a356124d781612472565b995060208b01356124e781612472565b98506124f560408c01612487565b975061250360608c01612487565b965061251160808c01612487565b955061251f60a08c01612487565b945061252d60c08c01612487565b935061253b60e08c01612499565b925061254a6101008c01612487565b91506125596101208c01612499565b90509295989b9194979a5092959850565b60006020828403121561257c57600080fd5b813561192881612472565b80358015158114611d3a57600080fd5b60008060008060008060008060006101208a8c0312156125b657600080fd5b6125bf8a612487565b98506125cd60208b01612487565b97506125db60408b01612487565b96506125e960608b01612487565b95506125f760808b01612487565b945061260560a08b01612499565b935061261360c08b01612487565b925061262160e08b01612499565b91506126306101008b01612587565b90509295985092959850929598565b6000806040838503121561265257600080fd5b61265b83612487565b915061266960208401612587565b90509250929050565b6000806000806080858703121561268857600080fd5b843561269381612472565b935060208501356126a381612472565b92506126b160408601612499565b91506126bf60608601612487565b905092959194509250565b600080604083850312156126dd57600080fd5b82356126e881612472565b915060208301356126f881612472565b809150509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561244d5761276483855161ffff81511682526001600160a01b0360208201511660208301526040810151151560408301526060810151151560608301525050565b928401926080929092019160010161271f565b6000806000806080858703121561278d57600080fd5b843561279881612472565b935060208501356127a881612472565b92506127b660408601612487565b91506126bf60608601612587565b6000806000606084860312156127d957600080fd5b83356127e481612472565b925060208401356127f481612472565b929592945050506040919091013590565b815161ffff1681526020808301516001600160a01b0316908201526040808301511515908201526060808301511515908201526080810161059a565b60006020828403121561285357600080fd5b61192882612487565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006000198214156128b2576128b2612888565b5060010190565b6000828210156128cb576128cb612888565b500390565b6000602082840312156128e257600080fd5b815161192881612472565b60008261290a57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603160045260246000fdfea2646970667358221220079cb1c62be258c69df2ae0da85aaf7db5b67bbc079c22b17ba701294c1fce6f64736f6c634300080a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000001f36930a75c44f323d4d66aee449af0c72d19f2e0000000000000000000000000000000000000000000000000000048c27395000
-----Decoded View---------------
Arg [0] : feeRecipient (address): 0x1f36930A75C44F323d4D66AEE449AF0c72D19f2E
Arg [1] : flashLoanFee (uint256): 5000000000000
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000001f36930a75c44f323d4d66aee449af0c72d19f2e
Arg [1] : 0000000000000000000000000000000000000000000000000000048c27395000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.