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
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