LBFactory
0xf8e7505380c3c9c949b071e374fe9b3ae5ff752e
Verification
Verified
0.8.20+commit.a1b79de6
Type
Contract
12,021 bytes
ABI entries
88
22 read · 20 write
License
none
Contract information
- Address
- 0xf8e7505380c3c9c949b071e374fe9b3ae5ff752e
- Chain
- Robinhood Chain (4663)
- Compiler
- 0.8.20+commit.a1b79de6
- Optimization
- Enabled
- Creator
- 0xD07B1A5110…e07F1C9025
- Creation tx
- 0x939df77adc…54c6c5a14c
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (22)
DEFAULT_ADMIN_ROLE() → bytes32
LB_HOOKS_MANAGER_ROLE() → bytes32
getAllBinSteps() → uint256[]
getAllLBPairs(address, address) → tuple[]
getFeeRecipient() → address
getFlashLoanFee() → uint256
getLBPairAtIndex(uint256) → address
getLBPairImplementation() → address
getLBPairInformation(address, address, uint256) → tuple
getMaxFlashLoanFee() → uint256
getMinBinStep() → uint256
getNumberOfLBPairs() → uint256
getNumberOfQuoteAssets() → uint256
getOpenBinSteps() → uint256[]
getPreset(uint256) → uint256, uint256, uint256, uint256, uint256, uint256, uint256, bool
getQuoteAssetAtIndex(uint256) → address
getRoleAdmin(bytes32) → bytes32
hasRole(bytes32, address) → bool
isQuoteAsset(address) → bool
owner() → address
pendingOwner() → address
supportsInterface(bytes4) → bool
Events (15)
FeeRecipientSetFlashLoanFeeSetLBPairCreatedLBPairIgnoredStateChangedLBPairImplementationSetOwnershipTransferStartedOwnershipTransferredPresetOpenStateChangedPresetRemovedPresetSetQuoteAssetAddedQuoteAssetRemovedRoleAdminChangedRoleGrantedRoleRevoked
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "feeRecipient",
"type": "address"
},
{
"internalType": "address",
"name": "initialOwner",
"type": "address"
},
{
"internalType": "uint256",
"name": "flashLoanFee",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "AccessControlBadConfirmation",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "bytes32",
"name": "neededRole",
"type": "bytes32"
}
],
"name": "AccessControlUnauthorizedAccount",
"type": "error"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "key",
"type": "bytes32"
}
],
"name": "EnumerableMapNonexistentKey",
"type": "error"
},
{
"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": [],
"name": "LBFactory__CannotGrantDefaultAdminRole",
"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": [],
"name": "LBFactory__InvalidHooksParameters",
"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": "hooksImplementation",
"type": "address"
}
],
"name": "LBFactory__SameHooksImplementation",
"type": "error"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "hooksParameters",
"type": "bytes32"
}
],
"name": "LBFactory__SameHooksParameters",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "LBPairImplementation",
"type": "address"
}
],
"name": "LBFactory__SameImplementation",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "OwnableInvalidOwner",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "OwnableUnauthorizedAccount",
"type": "error"
},
{
"inputs": [],
"name": "PairParametersHelper__InvalidParameter",
"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": "OwnershipTransferStarted",
"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": "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"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "previousAdminRole",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "newAdminRole",
"type": "bytes32"
}
],
"name": "RoleAdminChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "RoleGranted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "RoleRevoked",
"type": "event"
},
{
"inputs": [],
"name": "DEFAULT_ADMIN_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "LB_HOOKS_MANAGER_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "acceptOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract IERC20",
"name": "quoteAsset",
"type": "address"
}
],
"name": "addQuoteAsset",
"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": "bytes32",
"name": "role",
"type": "bytes32"
}
],
"name": "getRoleAdmin",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "grantRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "hasRole",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"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": "contract IERC20",
"name": "tokenX",
"type": "address"
},
{
"internalType": "contract IERC20",
"name": "tokenY",
"type": "address"
},
{
"internalType": "uint16",
"name": "binStep",
"type": "uint16"
}
],
"name": "removeLBHooksOnPair",
"outputs": [],
"stateMutability": "nonpayable",
"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": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "callerConfirmation",
"type": "address"
}
],
"name": "renounceRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "revokeRole",
"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": "bytes32",
"name": "hooksParameters",
"type": "bytes32"
},
{
"internalType": "bytes",
"name": "onHooksSetData",
"type": "bytes"
}
],
"name": "setLBHooksParametersOnPair",
"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": "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"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "interfaceId",
"type": "bytes4"
}
],
"name": "supportsInterface",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {EnumerableMap} from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol";
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {PairParameterHelper} from "./libraries/PairParameterHelper.sol";
import {Encoded} from "./libraries/math/Encoded.sol";
import {ImmutableClone} from "./libraries/ImmutableClone.sol";
import {PriceHelper} from "./libraries/PriceHelper.sol";
import {SafeCast} from "./libraries/math/SafeCast.sol";
import {Hooks} from "./libraries/Hooks.sol";
import {ILBFactory} from "./interfaces/ILBFactory.sol";
import {ILBPair} from "./interfaces/ILBPair.sol";
import {ILBHooks} from "./interfaces/ILBHooks.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 Ownable2Step, AccessControl, 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;
bytes32 public constant LB_HOOKS_MANAGER_ROLE = keccak256("LB_HOOKS_MANAGER_ROLE");
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, address initialOwner, uint256 flashLoanFee) Ownable(initialOwner) {
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 The address of the LBPair implementation
*/
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))
)
);
}
_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);
pair.initialize(
preset.getBaseFactor(),
preset.getFilterPeriod(),
preset.getDecayPeriod(),
preset.getReductionFactor(),
preset.getVariableFeeControl(),
preset.getProtocolShare(),
preset.getMaxVolatilityAccumulator(),
activeId
);
}
/**
* @notice Function to set whether the pair is ignored or not for routing, it will make the pair unusable by the router
* @dev Needs to be called by the owner
* Reverts if:
* - The pair doesn't exist
* - The ignored state is already in the same state
* @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
* @dev Needs to be called by the owner
* Reverts if:
* - The binStep is lower than the minimum 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
* @dev Needs to be called by the owner
* Reverts if:
* - The binStep doesn't have a preset
* - The preset is already in the same state
* @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
* @dev Needs to be called by the owner
* Reverts if:
* - The binStep doesn't have a preset
* @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
* @dev Needs to be called by the owner
* Reverts if:
* - The pair doesn't exist
* @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 hooks parameters of a pair
* @dev Needs to be called by an address with the LB_HOOKS_MANAGER_ROLE
* Reverts if:
* - The pair doesn't exist
* - The hooks is `address(0)` or the hooks flags are all false
* @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 hooksParameters The hooks parameters
* @param onHooksSetData The data to pass to the onHooksSet function
*/
function setLBHooksParametersOnPair(
IERC20 tokenX,
IERC20 tokenY,
uint16 binStep,
bytes32 hooksParameters,
bytes calldata onHooksSetData
) external override onlyRole(LB_HOOKS_MANAGER_ROLE) {
if (Hooks.getHooks(hooksParameters) == address(0) || Hooks.getFlags(hooksParameters) == 0) {
revert LBFactory__InvalidHooksParameters();
}
_setLBHooksParametersOnPair(tokenX, tokenY, binStep, hooksParameters, onHooksSetData);
}
/**
* @notice Function to remove the hooks contract from the pair
* @dev Needs to be called by an address with the LB_HOOKS_MANAGER_ROLE
* Reverts if:
* - The pair doesn't exist
* @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
*/
function removeLBHooksOnPair(IERC20 tokenX, IERC20 tokenY, uint16 binStep)
external
override
onlyRole(LB_HOOKS_MANAGER_ROLE)
{
_setLBHooksParametersOnPair(tokenX, tokenY, binStep, 0, new bytes(0));
}
/**
* @notice Function to set the recipient of the fees. This address needs to be able to receive ERC20s
* @dev Needs to be called by the owner
* Reverts if:
* - The feeRecipient is `address(0)`
* - The feeRecipient is the same as the current one
* @param feeRecipient The address of the recipient
*/
function setFeeRecipient(address feeRecipient) external override onlyOwner {
_setFeeRecipient(feeRecipient);
}
/**
* @notice Function to set the flash loan fee
* @dev Needs to be called by the owner
* Reverts if:
* - The flashLoanFee is the same as the current one
* - The flashLoanFee is above the maximum 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
* @dev Needs to be called by the owner
* Reverts if:
* - The quoteAsset is already whitelisted
* @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
* @dev Needs to be called by the owner
* Reverts if:
* - The quoteAsset was not whitelisted
* @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);
}
/**
* @notice Function to force the decay of the volatility accumulator of a pair
* @dev Needs to be called by the owner
* @param pair The pair to force the decay
*/
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);
}
/**
* @notice Internal function to set a hooks contract to the pair
* @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 hooksParameters The hooks parameters
* @param onHooksSetData The data to pass to the onHooksSet function
*/
function _setLBHooksParametersOnPair(
IERC20 tokenX,
IERC20 tokenY,
uint16 binStep,
bytes32 hooksParameters,
bytes memory onHooksSetData
) internal {
ILBPair lbPair = _getLBPairInformation(tokenX, tokenY, binStep).LBPair;
if (address(lbPair) == address(0)) revert LBFactory__LBPairNotCreated(tokenX, tokenY, binStep);
if (lbPair.getLBHooksParameters() == hooksParameters) revert LBFactory__SameHooksParameters(hooksParameters);
lbPair.setHooksParameters(hooksParameters, onHooksSetData);
}
/**
* @notice Returns whether the caller has the role or not, only the owner has the DEFAULT_ADMIN_ROLE
* @param role The role to check
* @param account The address to check
* @return Whether the account has the role or not
*/
function hasRole(bytes32 role, address account) public view override returns (bool) {
if (role == DEFAULT_ADMIN_ROLE) return account == owner();
return super.hasRole(role, account);
}
/**
* @notice Grants a role to an address, the DEFAULT_ADMIN_ROLE can not be granted
* @param role The role to grant
* @param account The address to grant the role to
* @return Whether the role has been granted or not
*/
function _grantRole(bytes32 role, address account) internal override returns (bool) {
if (role == DEFAULT_ADMIN_ROLE) revert LBFactory__CannotGrantDefaultAdminRole();
return super._grantRole(role, account);
}
}
Chain explorer1551msChain node76ms