DLMMFactory
0xdcd5f77697914e27f56fd263ef82923c8524abac
Verification
Verified
v0.8.30+commit.73712a01
Type
Contract
13,908 bytes
ABI entries
104
29 read · 25 write
License
none
Contract information
- Address
- 0xdcd5f77697914e27f56fd263ef82923c8524abac
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.30+commit.73712a01
- Optimization
- Enabled
- Creator
- 0xAAA5D87392…68f000b9De
- Creation tx
- 0xef64e3d85e…fcc67a627c
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (29)
DEFAULT_ADMIN_ROLE() → bytes32
DEFAULT_PROTOCOL_SHARE() → uint16
GAUGED_PROTOCOL_SHARE() → uint16
LB_HOOKS_MANAGER_ROLE() → bytes32
defaultProtocolShare() → uint16
feeCollector() → address
gaugedProtocolShare() → uint16
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
isPool(address) → bool
isQuoteAsset(address) → bool
owner() → address
pendingOwner() → address
supportsInterface(bytes4) → bool
voter() → address
Events (16)
DLMMVoterSetFeeRecipientSetFlashLoanFeeSetLBPairCreatedLBPairIgnoredStateChangedLBPairImplementationSetOwnershipTransferStartedOwnershipTransferredPresetOpenStateChangedPresetRemovedPresetSetQuoteAssetAddedQuoteAssetRemovedRoleAdminChangedRoleGrantedRoleRevoked
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": "address",
"name": "pool",
"type": "address"
}
],
"name": "DLMMFactory__InvalidPool",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "caller",
"type": "address"
}
],
"name": "DLMMFactory__NotOwnerOrVoter",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "voter",
"type": "address"
}
],
"name": "DLMMFactory__SameVoter",
"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": true,
"internalType": "address",
"name": "oldVoter",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newVoter",
"type": "address"
}
],
"name": "DLMMVoterSet",
"type": "event"
},
{
"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 IDLMMPool",
"name": "LBPair",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "pid",
"type": "uint256"
}
],
"name": "LBPairCreated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "contract IDLMMPool",
"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": "DEFAULT_PROTOCOL_SHARE",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "GAUGED_PROTOCOL_SHARE",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"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 IDLMMPool",
"name": "pair",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "defaultProtocolShare",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [],
"name": "feeCollector",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract IDLMMPool",
"name": "pair",
"type": "address"
}
],
"name": "forceDecay",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "gaugedProtocolShare",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "pure",
"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 IDLMMPool",
"name": "LBPair",
"type": "address"
},
{
"internalType": "bool",
"name": "createdByOwner",
"type": "bool"
},
{
"internalType": "bool",
"name": "ignoredForRouting",
"type": "bool"
}
],
"internalType": "struct IDLMMFactory.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 IDLMMPool",
"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 IDLMMPool",
"name": "LBPair",
"type": "address"
},
{
"internalType": "bool",
"name": "createdByOwner",
"type": "bool"
},
{
"internalType": "bool",
"name": "ignoredForRouting",
"type": "bool"
}
],
"internalType": "struct IDLMMFactory.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": "address",
"name": "pool",
"type": "address"
}
],
"name": "isPool",
"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": "address",
"name": "pool",
"type": "address"
}
],
"name": "setPoolDefaultProtocolShare",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "pool",
"type": "address"
}
],
"name": "setPoolGaugedProtocolShare",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "pool",
"type": "address"
},
{
"internalType": "uint16",
"name": "protocolShare",
"type": "uint16"
}
],
"name": "setPoolProtocolShare",
"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": "uint16",
"name": "binStep",
"type": "uint16"
},
{
"internalType": "uint16",
"name": "protocolShare",
"type": "uint16"
}
],
"name": "setPresetProtocolShare",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newVoter",
"type": "address"
}
],
"name": "setVoter",
"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"
},
{
"inputs": [],
"name": "voter",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"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 {IDLMMFactory} from "./interfaces/IDLMMFactory.sol";
import {IDLMMPool} from "./interfaces/IDLMMPool.sol";
import {IDLMMHooks} from "./interfaces/IDLMMHooks.sol";
/// @title DLMM Factory
/// @notice Contract used to deploy and register new DLMM pools
contract DLMMFactory is Ownable2Step, AccessControl, IDLMMFactory {
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");
uint16 public constant DEFAULT_PROTOCOL_SHARE = 2_500;
uint16 public constant GAUGED_PROTOCOL_SHARE = 10_000;
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 _voter;
address private _lbPairImplementation;
IDLMMPool[] private _allLBPairs;
/// @dev Mapping from a (tokenA, tokenB, binStep) to a DLMM pool. 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;
}
function feeCollector() external view override returns (address) {
return _feeRecipient;
}
function voter() external view override returns (address) {
return _voter;
}
function defaultProtocolShare() external pure override returns (uint16) {
return DEFAULT_PROTOCOL_SHARE;
}
function gaugedProtocolShare() external pure override returns (uint16) {
return GAUGED_PROTOCOL_SHARE;
}
function setVoter(address newVoter) external override onlyOwner {
if (newVoter == _voter) revert DLMMFactory__SameVoter(newVoter);
emit DLMMVoterSet(_voter, newVoter);
_voter = newVoter;
}
function setPoolProtocolShare(address pool, uint16 protocolShare) external override {
_checkOwnerOrVoter();
_setPoolProtocolShare(pool, protocolShare);
}
function setPoolDefaultProtocolShare(address pool) external override {
_checkOwnerOrVoter();
_setPoolProtocolShare(pool, DEFAULT_PROTOCOL_SHARE);
}
function setPoolGaugedProtocolShare(address pool) external override {
_checkOwnerOrVoter();
_setPoolProtocolShare(pool, GAUGED_PROTOCOL_SHARE);
}
/// @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 DLMM pool implementation
/// @return lbPairImplementation The address of the DLMM pool implementation
function getLBPairImplementation() external view override returns (address lbPairImplementation) {
return _lbPairImplementation;
}
/// @notice View function to return the number of DLMM pools created
/// @return lbPairNumber
function getNumberOfLBPairs() external view override returns (uint256 lbPairNumber) {
return _allLBPairs.length;
}
/// @notice View function to return the DLMM pool created at index `index`
/// @param index The index
/// @return lbPair The address of the DLMM pool at index `index`
function getLBPairAtIndex(uint256 index) external view override returns (IDLMMPool 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));
}
function isPool(address pool) external view override returns (bool) {
if (pool.code.length == 0) return false;
IDLMMPool dlmmPool = IDLMMPool(pool);
try dlmmPool.getFactory() returns (IDLMMFactory factory) {
if (address(factory) != address(this)) return false;
return address(
_getLBPairInformation(dlmmPool.getTokenX(), dlmmPool.getTokenY(), dlmmPool.getBinStep()).LBPair
) == pool;
} catch {
return false;
}
}
/// @notice Returns the pool information 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 DLMM pool
/// @return lbPairInformation The pool information
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 DLMM pools 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 DLMM pools
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 DLMM pool 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 (IDLMMPool(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 DLMM pool 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 DLMM pool
function createLBPair(IERC20 tokenX, IERC20 tokenY, uint24 activeId, uint16 binStep)
external
override
returns (IDLMMPool 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 = IDLMMPool(
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 only the protocol share for an existing preset.
/// @dev Needs to be called by the owner.
/// @param binStep The bin step of the preset
/// @param protocolShare The share of the fees received by the protocol
function setPresetProtocolShare(uint16 binStep, uint16 protocolShare) external override onlyOwner {
if (!_presets.contains(binStep)) revert LBFactory__BinStepHasNoPreset(binStep);
bytes32 preset = bytes32(_presets.get(binStep));
uint16 baseFactor = preset.getBaseFactor();
uint16 filterPeriod = preset.getFilterPeriod();
uint16 decayPeriod = preset.getDecayPeriod();
uint16 reductionFactor = preset.getReductionFactor();
uint24 variableFeeControl = preset.getVariableFeeControl();
uint24 maxVolatilityAccumulator = preset.getMaxVolatilityAccumulator();
preset = preset.setStaticFeeParameters(
baseFactor,
filterPeriod,
decayPeriod,
reductionFactor,
variableFeeControl,
protocolShare,
maxVolatilityAccumulator
);
_presets.set(binStep, uint256(preset));
emit PresetSet(
binStep,
baseFactor,
filterPeriod,
decayPeriod,
reductionFactor,
variableFeeControl,
protocolShare,
maxVolatilityAccumulator
);
}
/// @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 DLMM pool
/// @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 {
IDLMMPool 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(IDLMMPool pair) external override onlyOwner {
pair.forceDecay();
}
function _checkOwnerOrVoter() internal view {
if (msg.sender != owner() && msg.sender != _voter) revert DLMMFactory__NotOwnerOrVoter(msg.sender);
}
function _setPoolProtocolShare(address pool, uint16 protocolShare) internal {
if (pool.code.length == 0) revert DLMMFactory__InvalidPool(pool);
IDLMMPool dlmmPool = IDLMMPool(pool);
if (address(dlmmPool.getFactory()) != address(this)) revert DLMMFactory__InvalidPool(pool);
(
uint16 baseFactor,
uint16 filterPeriod,
uint16 decayPeriod,
uint16 reductionFactor,
uint24 variableFeeControl,,
uint24 maxVolatilityAccumulator
) = dlmmPool.getStaticFeeParameters();
dlmmPool.setStaticFeeParameters(
baseFactor,
filterPeriod,
decayPeriod,
reductionFactor,
variableFeeControl,
protocolShare,
maxVolatilityAccumulator
);
}
/// @notice Returns the pool information 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 DLMM pool
/// @return The pool information
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 {
IDLMMPool 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 explorer1953msChain node73ms