DegenHoodV4Factory

0x4999b79be94d1e9cadc7a50cbb4e75b81a0b3a00

Verification
Verified
v0.8.28+commit.7893614a
Type
Contract
21,300 bytes
ABI entries
57
24 read · 6 write
License
none

Contract information

Address
0x4999b79be94d1e9cadc7a50cbb4e75b81a0b3a00
Chain
Robinhood Chain (4663)
Compiler
v0.8.28+commit.7893614a
Optimization
Enabled
Creation tx
0x8fcdaddcf3…47174506f8

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (24)

FACTORY_VERSION()bytes32
INITIAL_TICK()int24
LAUNCH_FEE_DURATION()uint64
LP_FEE()uint24
MAXIMUM_TEMPORARY_HOOK_RATE()uint256
OPERATING_TREASURY()address
PERMANENT_HOOK_RATE()uint256
POOL_MANAGER()address
STANDARD_SUPPLY()uint256
TICK_SPACING()int24
TOKEN_RESERVE()address
UPPER_TICK()int24
VANITY_MASK()uint160
VANITY_SUFFIX()uint160
WETH()address
factoryDeprecated()bool
launchCommitment(tuple)bytes32
launchCount()uint256
launchRecord(address)tuple
owner()address
predictTokenAddress(tuple)address
template(uint256)tuple
tokenByLaunch(uint256)address
usedCommitments(bytes32)bool

Events (5)

FactoryPermanentlyDeprecatedOwnershipTransferredTemplateApprovedTemplateRetiredTokenLaunched

ABI

[
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "poolManager_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "weth_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "operatingTreasury_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "tokenReserve_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "initialOwner",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "EmptyNameOrSymbol",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "FactoryDeprecated",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidAddress",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidBeneficiary",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidFeeAdmin",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidLauncher",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidTemplate",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidTokenAdmin",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "LaunchAlreadyUsed",
    "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": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "name": "SafeERC20FailedOperation",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "TemplateAlreadyExists",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "TemplateCodeChanged",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "TemplateDeprecated",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "TemplateNotApproved",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "weth",
        "type": "address"
      }
    ],
    "name": "TokenMustSortBeforeWeth",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "UnauthorizedLauncher",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "UnexpectedPoolKey",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "UnexpectedPosition",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "name": "VanitySuffixMismatch",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [],
    "name": "FactoryPermanentlyDeprecated",
    "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": "templateId",
        "type": "uint256"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "hook",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "lpLocker",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "feeLocker",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "bytes32",
        "name": "hookCodeHash",
        "type": "bytes32"
      },
      {
        "indexed": false,
        "internalType": "bytes32",
        "name": "lockerCodeHash",
        "type": "bytes32"
      }
    ],
    "name": "TemplateApproved",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "templateId",
        "type": "uint256"
      }
    ],
    "name": "TemplateRetired",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "launchId",
        "type": "uint256"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "launcher",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "tokenAdmin",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "feeAdmin",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "beneficiary",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "operatingTreasury",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "tokenReserve",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "templateId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "hook",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "lpLocker",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "feeLocker",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "bytes32",
        "name": "poolId",
        "type": "bytes32"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "positionId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "supply",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint24",
        "name": "lpFee",
        "type": "uint24"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "permanentHookRate",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "maximumTemporaryHookRate",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint64",
        "name": "launchFeeDuration",
        "type": "uint64"
      },
      {
        "indexed": false,
        "internalType": "int24",
        "name": "initialTick",
        "type": "int24"
      },
      {
        "indexed": false,
        "internalType": "int24",
        "name": "upperTick",
        "type": "int24"
      },
      {
        "indexed": false,
        "internalType": "int24",
        "name": "tickSpacing",
        "type": "int24"
      },
      {
        "indexed": false,
        "internalType": "bytes32",
        "name": "metadataHash",
        "type": "bytes32"
      },
      {
        "indexed": false,
        "internalType": "bytes32",
        "name": "factoryVersion",
        "type": "bytes32"
      },
      {
        "indexed": false,
        "internalType": "bytes32",
        "name": "hookCodeHash",
        "type": "bytes32"
      },
      {
        "indexed": false,
        "internalType": "bytes32",
        "name": "lockerCodeHash",
        "type": "bytes32"
      }
    ],
    "name": "TokenLaunched",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "FACTORY_VERSION",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "INITIAL_TICK",
    "outputs": [
      {
        "internalType": "int24",
        "name": "",
        "type": "int24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "LAUNCH_FEE_DURATION",
    "outputs": [
      {
        "internalType": "uint64",
        "name": "",
        "type": "uint64"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "LP_FEE",
    "outputs": [
      {
        "internalType": "uint24",
        "name": "",
        "type": "uint24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAXIMUM_TEMPORARY_HOOK_RATE",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "OPERATING_TREASURY",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "PERMANENT_HOOK_RATE",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "POOL_MANAGER",
    "outputs": [
      {
        "internalType": "contract IPoolManager",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "STANDARD_SUPPLY",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "TICK_SPACING",
    "outputs": [
      {
        "internalType": "int24",
        "name": "",
        "type": "int24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "TOKEN_RESERVE",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "UPPER_TICK",
    "outputs": [
      {
        "internalType": "int24",
        "name": "",
        "type": "int24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "VANITY_MASK",
    "outputs": [
      {
        "internalType": "uint160",
        "name": "",
        "type": "uint160"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "VANITY_SUFFIX",
    "outputs": [
      {
        "internalType": "uint160",
        "name": "",
        "type": "uint160"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "WETH",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "templateId",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "hook",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "lpLocker",
        "type": "address"
      }
    ],
    "name": "approveTemplate",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "deprecateFactory",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "templateId",
        "type": "uint256"
      }
    ],
    "name": "deprecateTemplate",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "factoryDeprecated",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "string",
            "name": "name",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "symbol",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "contractURI",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "imageURI",
            "type": "string"
          },
          {
            "internalType": "address",
            "name": "launcher",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "tokenAdmin",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "feeAdmin",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "beneficiary",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "templateId",
            "type": "uint256"
          },
          {
            "internalType": "bytes32",
            "name": "userSalt",
            "type": "bytes32"
          }
        ],
        "internalType": "struct IDegenHoodV4Factory.LaunchRequest",
        "name": "request",
        "type": "tuple"
      }
    ],
    "name": "launch",
    "outputs": [
      {
        "components": [
          {
            "internalType": "uint256",
            "name": "launchId",
            "type": "uint256"
          },
          {
            "internalType": "address",
            "name": "token",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "launcher",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "tokenAdmin",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "feeAdmin",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "beneficiary",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "operatingTreasury",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "tokenReserve",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "templateId",
            "type": "uint256"
          },
          {
            "internalType": "address",
            "name": "hook",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "lpLocker",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "feeLocker",
            "type": "address"
          },
          {
            "components": [
              {
                "internalType": "Currency",
                "name": "currency0",
                "type": "address"
              },
              {
                "internalType": "Currency",
                "name": "currency1",
                "type": "address"
              },
              {
                "internalType": "uint24",
                "name": "fee",
                "type": "uint24"
              },
              {
                "internalType": "int24",
                "name": "tickSpacing",
                "type": "int24"
              },
              {
                "internalType": "contract IHooks",
                "name": "hooks",
                "type": "address"
              }
            ],
            "internalType": "struct PoolKey",
            "name": "poolKey",
            "type": "tuple"
          },
          {
            "internalType": "PoolId",
            "name": "poolId",
            "type": "bytes32"
          },
          {
            "internalType": "uint256",
            "name": "positionId",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "supply",
            "type": "uint256"
          },
          {
            "internalType": "uint24",
            "name": "lpFee",
            "type": "uint24"
          },
          {
            "internalType": "uint256",
            "name": "permanentHookRate",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "maximumTemporaryHookRate",
            "type": "uint256"
          },
          {
            "internalType": "uint64",
            "name": "launchFeeDuration",
            "type": "uint64"
          },
          {
            "internalType": "int24",
            "name": "initialTick",
            "type": "int24"
          },
          {
            "internalType": "int24",
            "name": "upperTick",
            "type": "int24"
          },
          {
            "internalType": "int24",
            "name": "tickSpacing",
            "type": "int24"
          },
          {
            "internalType": "bytes32",
            "name": "metadataHash",
            "type": "bytes32"
          },
          {
            "internalType": "bytes32",
            "name": "factoryVersion",
            "type": "bytes32"
          },
          {
            "internalType": "bytes32",
            "name": "hookCodeHash",
            "type": "bytes32"
          },
          {
            "internalType": "bytes32",
            "name": "lockerCodeHash",
            "type": "bytes32"
          }
        ],
        "internalType": "struct IDegenHoodV4Factory.LaunchRecord",
        "name": "record",
        "type": "tuple"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "string",
            "name": "name",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "symbol",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "contractURI",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "imageURI",
            "type": "string"
          },
          {
            "internalType": "address",
            "name": "launcher",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "tokenAdmin",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "feeAdmin",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "beneficiary",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "templateId",
            "type": "uint256"
          },
          {
            "internalType": "bytes32",
            "name": "userSalt",
            "type": "bytes32"
          }
        ],
        "internalType": "struct IDegenHoodV4Factory.LaunchRequest",
        "name": "request",
        "type": "tuple"
      }
    ],
    "name": "launchCommitment",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "pure",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "launchCount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "name": "launchRecord",
    "outputs": [
      {
        "components": [
          {
            "internalType": "uint256",
            "name": "launchId",
            "type": "uint256"
          },
          {
            "internalType": "address",
            "name": "token",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "launcher",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "tokenAdmin",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "feeAdmin",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "beneficiary",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "operatingTreasury",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "tokenReserve",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "templateId",
            "type": "uint256"
          },
          {
            "internalType": "address",
            "name": "hook",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "lpLocker",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "feeLocker",
            "type": "address"
          },
          {
            "components": [
              {
                "internalType": "Currency",
                "name": "currency0",
                "type": "address"
              },
              {
                "internalType": "Currency",
                "name": "currency1",
                "type": "address"
              },
              {
                "internalType": "uint24",
                "name": "fee",
                "type": "uint24"
              },
              {
                "internalType": "int24",
                "name": "tickSpacing",
                "type": "int24"
              },
              {
                "internalType": "contract IHooks",
                "name": "hooks",
                "type": "address"
              }
            ],
            "internalType": "struct PoolKey",
            "name": "poolKey",
            "type": "tuple"
          },
          {
            "internalType": "PoolId",
            "name": "poolId",
            "type": "bytes32"
          },
          {
            "internalType": "uint256",
            "name": "positionId",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "supply",
            "type": "uint256"
          },
          {
            "internalType": "uint24",
            "name": "lpFee",
            "type": "uint24"
          },
          {
            "internalType": "uint256",
            "name": "permanentHookRate",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "maximumTemporaryHookRate",
            "type": "uint256"
          },
          {
            "internalType": "uint64",
            "name": "launchFeeDuration",
            "type": "uint64"
          },
          {
            "internalType": "int24",
            "name": "initialTick",
            "type": "int24"
          },
          {
            "internalType": "int24",
            "name": "upperTick",
            "type": "int24"
          },
          {
            "internalType": "int24",
            "name": "tickSpacing",
            "type": "int24"
          },
          {
            "internalType": "bytes32",
            "name": "metadataHash",
            "type": "bytes32"
          },
          {
            "internalType": "bytes32",
            "name": "factoryVersion",
            "type": "bytes32"
          },
          {
            "internalType": "bytes32",
            "name": "hookCodeHash",
            "type": "bytes32"
          },
          {
            "internalType": "bytes32",
            "name": "lockerCodeHash",
            "type": "bytes32"
          }
        ],
        "internalType": "struct IDegenHoodV4Factory.LaunchRecord",
        "name": "",
        "type": "tuple"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "string",
            "name": "name",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "symbol",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "contractURI",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "imageURI",
            "type": "string"
          },
          {
            "internalType": "address",
            "name": "launcher",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "tokenAdmin",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "feeAdmin",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "beneficiary",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "templateId",
            "type": "uint256"
          },
          {
            "internalType": "bytes32",
            "name": "userSalt",
            "type": "bytes32"
          }
        ],
        "internalType": "struct IDegenHoodV4Factory.LaunchRequest",
        "name": "request",
        "type": "tuple"
      }
    ],
    "name": "predictTokenAddress",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "renounceOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "templateId",
        "type": "uint256"
      }
    ],
    "name": "template",
    "outputs": [
      {
        "components": [
          {
            "internalType": "address",
            "name": "hook",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "lpLocker",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "feeLocker",
            "type": "address"
          },
          {
            "internalType": "bytes32",
            "name": "hookCodeHash",
            "type": "bytes32"
          },
          {
            "internalType": "bytes32",
            "name": "lockerCodeHash",
            "type": "bytes32"
          },
          {
            "internalType": "bool",
            "name": "approved",
            "type": "bool"
          },
          {
            "internalType": "bool",
            "name": "deprecated",
            "type": "bool"
          }
        ],
        "internalType": "struct IDegenHoodV4Factory.Template",
        "name": "",
        "type": "tuple"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "launchId",
        "type": "uint256"
      }
    ],
    "name": "tokenByLaunch",
    "outputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "bytes32",
        "name": "commitment",
        "type": "bytes32"
      }
    ],
    "name": "usedCommitments",
    "outputs": [
      {
        "internalType": "bool",
        "name": "used",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  }
]

Source code

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {DegenHoodFeeLocker} from "./DegenHoodFeeLocker.sol";
import {DegenHoodTokenV4} from "./DegenHoodTokenV4.sol";
import {DegenHoodV4Hook} from "./DegenHoodV4Hook.sol";
import {DegenHoodV4LpLocker} from "./DegenHoodV4LpLocker.sol";
import {IDegenHoodV4Factory} from "./interfaces/IDegenHoodV4Factory.sol";
import {DegenPoolKey} from "./libraries/DegenPoolKey.sol";

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol";
import {PoolId, PoolIdLibrary} from "@uniswap/v4-core/src/types/PoolId.sol";
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";

/*
HEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEENEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEOoooooOEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEOooooooooooNEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEOooooooooooooooHEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEEEEEEEEEEEEEEEOooooooooooooooooooNEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEEEEEEEEEEEEEhooooooooooooooooooooooEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEEEEEEEEEEEEoooooooooooooooooooooooooOEEEEEEEEEEEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEEEEEEEEEEOooooooooooooooooooooooooooooNEEEEEEEEEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEEEEEEEEEooooooooooooooeEnooooooooooooooOEEEEEEEEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEEEEEEEDoooooooooooeEEEEEEEEEEeoooooooooooEEEEEEEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEEEEEEoooooooogeEEEEEEEEEEEEEEEEEEeooooooooNEEEEEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEEEEEoooooogEEEEEEEEEEEEEEEEEEEEEEEEEEooooooOEEEEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEEEEooooooooooOOHEEEEEEEEEEEEEEEEhOOoooooooooOEEEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEEOooooooogEoooooooooooOOOooooooooooonEooooooooEEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEDooooooooEEEooooooooooooooooooooooodEEoooooooooEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEooooooooooOEEoooooooooeEEooooooooogEEoooooooooogEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEooooooooooooOEEEEEEnEEEEEEEenEEEEEEooooooooooogEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEEEooooooooooooNEEEEEEEEEEEEEEEEEEOoooooooooooeEEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEEEEEENooooooooooEEEEEEEEEEEEEEEEoooooooooeEEEEEEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEEEEEEEEEEhoooooooOEEEEEEEEEEEEoooooooeEEEEEEEEEEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEEEEEEEEEEEEEEEnooooNEEEEEEEEoooogEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEnoEEEEEOenEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
DEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
gEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
                                   DEGENHOOD
*/

/// @title DegenHood v4 atomic factory
/// @notice Deploys role-bound tokens into approved immutable hook/locker templates.
/// @dev Non-proxy template registry. Each launch pins immutable implementation addresses and role
///      bindings; future launch versions require separately approved templates.
contract DegenHoodV4Factory is IDegenHoodV4Factory, Ownable {
    using PoolIdLibrary for PoolKey;
    using SafeERC20 for IERC20;

    bytes32 public constant FACTORY_VERSION = keccak256("DegenHoodV4Factory/1.0.0");
    uint256 public constant STANDARD_SUPPLY = 100_000_000_000 ether;
    uint24 public constant LP_FEE = 7000;
    uint256 public constant PERMANENT_HOOK_RATE = 5000;
    uint256 public constant MAXIMUM_TEMPORARY_HOOK_RATE = 795_000;
    uint64 public constant LAUNCH_FEE_DURATION = 30 seconds;
    int24 public constant INITIAL_TICK = -230_400;
    int24 public constant UPPER_TICK = -120_000;
    int24 public constant TICK_SPACING = 200;
    uint160 public constant VANITY_MASK = 0xFFF;
    uint160 public constant VANITY_SUFFIX = 0xDE6;

    IPoolManager public immutable POOL_MANAGER;
    address public immutable WETH;
    address public immutable OPERATING_TREASURY;
    address public immutable TOKEN_RESERVE;

    bool public factoryDeprecated;
    uint256 public launchCount;
    mapping(uint256 templateId => Template config) private _templates;
    mapping(bytes32 pairHash => bool approved) private _approvedPairs;
    mapping(address token => LaunchRecord record) private _launchRecords;
    mapping(uint256 launchId => address token) public tokenByLaunch;
    mapping(bytes32 commitment => bool used) public usedCommitments;

    constructor(
        address poolManager_,
        address weth_,
        address operatingTreasury_,
        address tokenReserve_,
        address initialOwner
    ) Ownable(initialOwner) {
        if (
            poolManager_ == address(0) || weth_ == address(0) || operatingTreasury_ == address(0)
                || tokenReserve_ == address(0) || poolManager_.code.length == 0
                || weth_.code.length == 0 || operatingTreasury_ == tokenReserve_
                || initialOwner == operatingTreasury_ || initialOwner == tokenReserve_
        ) {
            revert InvalidAddress();
        }
        POOL_MANAGER = IPoolManager(poolManager_);
        WETH = weth_;
        OPERATING_TREASURY = operatingTreasury_;
        TOKEN_RESERVE = tokenReserve_;
    }

    function template(uint256 templateId) external view returns (Template memory) {
        return _templates[templateId];
    }

    function launchRecord(address token) external view returns (LaunchRecord memory) {
        return _launchRecords[token];
    }

    function transferOwnership(address newOwner) public override onlyOwner {
        if (newOwner == OPERATING_TREASURY || newOwner == TOKEN_RESERVE) {
            revert InvalidAddress();
        }
        super.transferOwnership(newOwner);
    }

    function approveTemplate(uint256 templateId, address hook, address lpLocker)
        external
        onlyOwner
    {
        if (templateId == 0 || hook.code.length == 0 || lpLocker.code.length == 0) {
            revert InvalidTemplate();
        }
        if (_templates[templateId].approved) revert TemplateAlreadyExists();
        bytes32 pairHash = keccak256(abi.encode(hook, lpLocker));
        if (_approvedPairs[pairHash]) revert InvalidTemplate();

        DegenHoodV4Hook degenHook = DegenHoodV4Hook(hook);
        DegenHoodV4LpLocker locker = DegenHoodV4LpLocker(lpLocker);
        address hookFeeLocker = address(degenHook.feeLocker());
        DegenHoodFeeLocker ledger = DegenHoodFeeLocker(hookFeeLocker);
        if (
            degenHook.factory() != address(this)
                || address(degenHook.poolManager()) != address(POOL_MANAGER)
                || degenHook.weth() != WETH || degenHook.operatingTreasury() != OPERATING_TREASURY
                || locker.factory() != address(this) || locker.hook() != hook
                || locker.weth() != WETH || locker.tokenReserve() != TOKEN_RESERVE
                || address(locker.positionManager().poolManager()) != address(POOL_MANAGER)
                || address(locker.feeLocker()) != hookFeeLocker || !ledger.allowedDepositors(hook)
                || !ledger.allowedDepositors(lpLocker)
        ) {
            revert InvalidTemplate();
        }

        bytes32 hookCodeHash = hook.codehash;
        bytes32 lockerCodeHash = lpLocker.codehash;
        _templates[templateId] = Template({
            hook: hook,
            lpLocker: lpLocker,
            feeLocker: hookFeeLocker,
            hookCodeHash: hookCodeHash,
            lockerCodeHash: lockerCodeHash,
            approved: true,
            deprecated: false
        });
        _approvedPairs[pairHash] = true;
        emit TemplateApproved(
            templateId, hook, lpLocker, hookFeeLocker, hookCodeHash, lockerCodeHash
        );
    }

    function deprecateTemplate(uint256 templateId) external onlyOwner {
        Template storage config = _templates[templateId];
        if (!config.approved) revert TemplateNotApproved();
        config.deprecated = true;
        emit TemplateRetired(templateId);
    }

    function deprecateFactory() external onlyOwner {
        factoryDeprecated = true;
        emit FactoryPermanentlyDeprecated();
    }

    function launch(LaunchRequest calldata request) external returns (LaunchRecord memory record) {
        if (factoryDeprecated) revert FactoryDeprecated();
        _validateRoles(request);
        Template memory config = _activeTemplate(request.templateId);

        bytes32 commitment = launchCommitment(request);
        if (usedCommitments[commitment]) revert LaunchAlreadyUsed();
        address predicted = _predictTokenAddress(request, commitment);
        _validateTokenAddress(predicted);
        usedCommitments[commitment] = true;

        address token = address(
            new DegenHoodTokenV4{salt: commitment}(
                request.name,
                request.symbol,
                address(this),
                request.tokenAdmin,
                request.contractURI,
                request.imageURI
            )
        );
        if (token != predicted) revert UnexpectedPosition();

        DegenHoodV4Hook degenHook = DegenHoodV4Hook(config.hook);
        PoolKey memory poolKey = degenHook.registerPool(token, request.beneficiary, config.lpLocker);
        if (!DegenPoolKey.matches(poolKey, token, WETH, config.hook)) revert UnexpectedPoolKey();
        PoolId poolId = poolKey.toId();
        POOL_MANAGER.initialize(poolKey, TickMath.getSqrtPriceAtTick(INITIAL_TICK));

        IERC20(token).forceApprove(config.lpLocker, STANDARD_SUPPLY);
        uint256 positionId = DegenHoodV4LpLocker(config.lpLocker)
            .placeLiquidity(poolKey, token, STANDARD_SUPPLY, request.beneficiary, request.feeAdmin);
        IERC20(token).forceApprove(config.lpLocker, 0);
        if (IERC20(token).balanceOf(address(this)) != 0) revert UnexpectedPosition();

        uint256 launchId = ++launchCount;
        bytes32 metadataHash = _metadataHash(request);
        record = LaunchRecord({
            launchId: launchId,
            token: token,
            launcher: request.launcher,
            tokenAdmin: request.tokenAdmin,
            feeAdmin: request.feeAdmin,
            beneficiary: request.beneficiary,
            operatingTreasury: OPERATING_TREASURY,
            tokenReserve: TOKEN_RESERVE,
            templateId: request.templateId,
            hook: config.hook,
            lpLocker: config.lpLocker,
            feeLocker: config.feeLocker,
            poolKey: poolKey,
            poolId: poolId,
            positionId: positionId,
            supply: STANDARD_SUPPLY,
            lpFee: LP_FEE,
            permanentHookRate: PERMANENT_HOOK_RATE,
            maximumTemporaryHookRate: MAXIMUM_TEMPORARY_HOOK_RATE,
            launchFeeDuration: LAUNCH_FEE_DURATION,
            initialTick: INITIAL_TICK,
            upperTick: UPPER_TICK,
            tickSpacing: TICK_SPACING,
            metadataHash: metadataHash,
            factoryVersion: FACTORY_VERSION,
            hookCodeHash: config.hookCodeHash,
            lockerCodeHash: config.lockerCodeHash
        });
        _launchRecords[token] = record;
        tokenByLaunch[launchId] = token;
        _emitLaunch(record);
    }

    function predictTokenAddress(LaunchRequest calldata request) external view returns (address) {
        return _predictTokenAddress(request, launchCommitment(request));
    }

    function launchCommitment(LaunchRequest calldata request) public pure returns (bytes32) {
        return keccak256(
            abi.encode(
                request.userSalt,
                request.launcher,
                request.tokenAdmin,
                request.feeAdmin,
                request.beneficiary,
                request.templateId,
                _metadataHash(request)
            )
        );
    }

    function _predictTokenAddress(LaunchRequest calldata request, bytes32 commitment)
        private
        view
        returns (address)
    {
        bytes32 initCodeHash = keccak256(
            abi.encodePacked(
                type(DegenHoodTokenV4).creationCode,
                abi.encode(
                    request.name,
                    request.symbol,
                    address(this),
                    request.tokenAdmin,
                    request.contractURI,
                    request.imageURI
                )
            )
        );
        return address(
            uint160(
                uint256(
                    keccak256(
                        abi.encodePacked(bytes1(0xff), address(this), commitment, initCodeHash)
                    )
                )
            )
        );
    }

    function _metadataHash(LaunchRequest calldata request) private pure returns (bytes32) {
        return
            keccak256(
                abi.encode(request.name, request.symbol, request.contractURI, request.imageURI)
            );
    }

    function _validateRoles(LaunchRequest calldata request) private view {
        if (request.launcher == address(0)) revert InvalidLauncher();
        if (msg.sender != request.launcher) revert UnauthorizedLauncher();
        if (request.tokenAdmin == address(0)) revert InvalidTokenAdmin();
        if (request.feeAdmin == address(0)) revert InvalidFeeAdmin();
        if (request.beneficiary == address(0)) revert InvalidBeneficiary();
        if (bytes(request.name).length == 0 || bytes(request.symbol).length == 0) {
            revert EmptyNameOrSymbol();
        }
    }

    function _activeTemplate(uint256 templateId) private view returns (Template memory config) {
        config = _templates[templateId];
        if (!config.approved) revert TemplateNotApproved();
        if (config.deprecated) revert TemplateDeprecated();
        if (
            config.hook.codehash != config.hookCodeHash
                || config.lpLocker.codehash != config.lockerCodeHash
        ) {
            revert TemplateCodeChanged();
        }
        DegenHoodFeeLocker ledger = DegenHoodFeeLocker(config.feeLocker);
        if (!ledger.allowedDepositors(config.hook) || !ledger.allowedDepositors(config.lpLocker)) {
            revert InvalidTemplate();
        }
    }

    function _validateTokenAddress(address token) private view {
        if (token >= WETH) revert TokenMustSortBeforeWeth(token, WETH);
        if (uint160(token) & VANITY_MASK != VANITY_SUFFIX) {
            revert VanitySuffixMismatch(token);
        }
    }

    function _emitLaunch(LaunchRecord memory record) private {
        emit TokenLaunched(
            record.launchId,
            record.token,
            record.launcher,
            record.tokenAdmin,
            record.feeAdmin,
            record.beneficiary,
            record.operatingTreasury,
            record.tokenReserve,
            record.templateId,
            record.hook,
            record.lpLocker,
            record.feeLocker,
            PoolId.unwrap(record.poolId),
            record.positionId,
            record.supply,
            record.lpFee,
            record.permanentHookRate,
            record.maximumTemporaryHookRate,
            record.launchFeeDuration,
            record.initialTick,
            record.upperTick,
            record.tickSpacing,
            record.metadataHash,
            record.factoryVersion,
            record.hookCodeHash,
            record.lockerCodeHash
        );
    }
}
Chain explorer4600msChain node75ms