AgentCoin

0xedfab19245990bc8cdb547668cfd0be3d06d3b11

Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
16,508 bytes
ABI entries
123
48 read · 20 write
License
none

Contract information

Address
0xedfab19245990bc8cdb547668cfd0be3d06d3b11
Chain
Robinhood Chain (4663)
Compiler
v0.8.26+commit.8a97fa7a
Optimization
Enabled
Creation tx
0xa9d1ecf9a2…904e60b8de

Token

Name
AgentCoin
Symbol
AGENT
Decimals
8
Holders
39

Read contract (48)

BPS_DENOMINATOR()uint256
DEFAULT_ADMIN_ROLE()bytes32
DEFAULT_MAX_MINTS()uint256
DEFAULT_PAYMENT_PER_MINT()uint256
DEFAULT_PAYMENT_SEED()uint256
DEFAULT_POOL_FEE()uint24
DEFAULT_POOL_TICK_SPACING()int24
DEFAULT_TOKENS_PER_MINT()uint256
HOOK_SETTER_ROLE()bytes32
LP_LOCK_DURATION()uint256
LP_MANAGER_ROLE()bytes32
MAX_MINTS()uint256
MAX_MINT_FACTOR_BPS()uint16
MINT_AUTHORIZATION_TYPEHASH()bytes32
MINT_SIGNER_ROLE()bytes32
MIN_MINT_FACTOR_BPS()uint16
PAYMENT_PER_MINT()uint256
SQRT_PRICE_AGENT_COIN_FIRST_DEFAULT()uint160
SQRT_PRICE_PAYMENT_TOKEN_FIRST_DEFAULT()uint160
TOKENS_PER_MINT()uint256
TRUMP_ACCOUNT_WITHDRAWER_ROLE()bytes32
allowance(address, address)uint256
balanceOf(address)uint256
decimals()uint8
eip712Domain()bytes1, string, string, uint256, address, bytes32, uint256[]
getRoleAdmin(bytes32)bytes32
hasRole(bytes32, address)bool
liquidityDeployed()bool
liquidityGuardHook()address
lpPositionClaimed()bool
lpTokenId()uint256
lpUnlockTime()uint256
mintAuthorizationDigest(uint256, uint16, uint256)bytes32
mintCount()uint256
mintDeposits(uint256)address, address, address, uint8
name()string
nextMintId()uint256
owner()address
paymentSeed()uint256
paymentToken()address
permit2()address
poolManager()address
poolSeedAmount()uint256
positionManager()address
supportsInterface(bytes4)bool
symbol()string
totalSupply()uint256
trumpAccountTokenReserve()uint256

Events (15)

ApprovalEIP712DomainChangedLiquidityDeployedLiquidityGuardHookSetLpFeesCollectedLpPositionClaimedMintCompletedMintFundedMintWithdrawnOwnershipTransferredRoleAdminChangedRoleGrantedRoleRevokedTransferTrumpAccountTokensWithdrawn

ABI

[
  {
    "inputs": [
      {
        "internalType": "contract IPoolManager",
        "name": "poolManager_",
        "type": "address"
      },
      {
        "internalType": "contract IPositionManager",
        "name": "positionManager_",
        "type": "address"
      },
      {
        "internalType": "contract IAllowanceTransfer",
        "name": "permit2_",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "paymentSeed_",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "poolSeedAmount_",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "tokensPerMint_",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "maxMints_",
        "type": "uint256"
      },
      {
        "components": [
          {
            "internalType": "address",
            "name": "owner",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "defaultAdmin",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "mintSigner",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "lpManager",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "trumpAccountWithdrawer",
            "type": "address"
          }
        ],
        "internalType": "struct AgentCoin.InitialRoles",
        "name": "initialRoles_",
        "type": "tuple"
      }
    ],
    "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": "target",
        "type": "address"
      }
    ],
    "name": "AddressEmptyCode",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "AddressInsufficientBalance",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ContractFeeClaimWindowClosed",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "allowance",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "needed",
        "type": "uint256"
      }
    ],
    "name": "ERC20InsufficientAllowance",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "balance",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "needed",
        "type": "uint256"
      }
    ],
    "name": "ERC20InsufficientBalance",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "approver",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidApprover",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "receiver",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidReceiver",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidSender",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidSpender",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "FailedInnerCall",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "available",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "requested",
        "type": "uint256"
      }
    ],
    "name": "InsufficientTrumpAccountReserve",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidAddress",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "signer",
        "type": "address"
      }
    ],
    "name": "InvalidMintAuthorization",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidMintConfig",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "uint16",
        "name": "factorBps",
        "type": "uint16"
      }
    ],
    "name": "InvalidMintFactor",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "expected",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "received",
        "type": "uint256"
      }
    ],
    "name": "InvalidPaymentAmount",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidPaymentTokenDecimals",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidRobinhoodProtocolAddresses",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidShortString",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "LiquidityAlreadyDeployed",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "LiquidityGuardHookAlreadySet",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "LpNotInitialized",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "LpPositionAlreadyClaimed",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "unlockTime",
        "type": "uint256"
      }
    ],
    "name": "LpPositionLocked",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "MaxMintsReached",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "deadline",
        "type": "uint256"
      }
    ],
    "name": "MintAuthorizationExpired",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "mintId",
        "type": "uint256"
      }
    ],
    "name": "MintDepositNotFunded",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NativeTransferFailed",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "caller",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "funder",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "negotiator",
        "type": "address"
      }
    ],
    "name": "NotMintDepositWithdrawer",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "caller",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "negotiator",
        "type": "address"
      }
    ],
    "name": "NotMintNegotiator",
    "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": "PoolInitializationFailed",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ReentrancyGuardReentrantCall",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "uint8",
        "name": "bits",
        "type": "uint8"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "SafeCastOverflowedUintDowncast",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "name": "SafeERC20FailedOperation",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "string",
        "name": "str",
        "type": "string"
      }
    ],
    "name": "StringTooLong",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "owner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "Approval",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [],
    "name": "EIP712DomainChanged",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint128",
        "name": "liquidity",
        "type": "uint128"
      }
    ],
    "name": "LiquidityDeployed",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "hook",
        "type": "address"
      }
    ],
    "name": "LiquidityGuardHookSet",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "LpFeesCollected",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "LpPositionClaimed",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "mintId",
        "type": "uint256"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "funder",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "negotiator",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "tokenAmount",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "trumpAccountAmount",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint16",
        "name": "factorBps",
        "type": "uint16"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "signer",
        "type": "address"
      }
    ],
    "name": "MintCompleted",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "mintId",
        "type": "uint256"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "funder",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "negotiator",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "paymentAmount",
        "type": "uint256"
      }
    ],
    "name": "MintFunded",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "mintId",
        "type": "uint256"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "funder",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "initiator",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "paymentAmount",
        "type": "uint256"
      }
    ],
    "name": "MintWithdrawn",
    "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": "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"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "Transfer",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "TrumpAccountTokensWithdrawn",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "BPS_DENOMINATOR",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "DEFAULT_ADMIN_ROLE",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "DEFAULT_MAX_MINTS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "DEFAULT_PAYMENT_PER_MINT",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "DEFAULT_PAYMENT_SEED",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "DEFAULT_POOL_FEE",
    "outputs": [
      {
        "internalType": "uint24",
        "name": "",
        "type": "uint24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "DEFAULT_POOL_TICK_SPACING",
    "outputs": [
      {
        "internalType": "int24",
        "name": "",
        "type": "int24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "DEFAULT_TOKENS_PER_MINT",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "HOOK_SETTER_ROLE",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "LP_LOCK_DURATION",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "LP_MANAGER_ROLE",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAX_MINTS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAX_MINT_FACTOR_BPS",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MINT_AUTHORIZATION_TYPEHASH",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MINT_SIGNER_ROLE",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MIN_MINT_FACTOR_BPS",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "PAYMENT_PER_MINT",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "SQRT_PRICE_AGENT_COIN_FIRST_DEFAULT",
    "outputs": [
      {
        "internalType": "uint160",
        "name": "",
        "type": "uint160"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "SQRT_PRICE_PAYMENT_TOKEN_FIRST_DEFAULT",
    "outputs": [
      {
        "internalType": "uint160",
        "name": "",
        "type": "uint160"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "TOKENS_PER_MINT",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "TRUMP_ACCOUNT_WITHDRAWER_ROLE",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      }
    ],
    "name": "allowance",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "approve",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "balanceOf",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "burn",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "burnFrom",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "claimLpPosition",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "collectLpFees",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "mintId",
        "type": "uint256"
      },
      {
        "internalType": "uint16",
        "name": "factorBps",
        "type": "uint16"
      },
      {
        "internalType": "uint256",
        "name": "deadline",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "signer",
        "type": "address"
      },
      {
        "internalType": "bytes",
        "name": "signature",
        "type": "bytes"
      }
    ],
    "name": "completeMint",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "tokenAmount",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "decimals",
    "outputs": [
      {
        "internalType": "uint8",
        "name": "",
        "type": "uint8"
      }
    ],
    "stateMutability": "pure",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "eip712Domain",
    "outputs": [
      {
        "internalType": "bytes1",
        "name": "fields",
        "type": "bytes1"
      },
      {
        "internalType": "string",
        "name": "name",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "version",
        "type": "string"
      },
      {
        "internalType": "uint256",
        "name": "chainId",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "verifyingContract",
        "type": "address"
      },
      {
        "internalType": "bytes32",
        "name": "salt",
        "type": "bytes32"
      },
      {
        "internalType": "uint256[]",
        "name": "extensions",
        "type": "uint256[]"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "emergencyWithdrawNative",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "emergencyWithdrawToken",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "negotiator",
        "type": "address"
      }
    ],
    "name": "fundMint",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "mintId",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "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": [],
    "name": "liquidityDeployed",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "liquidityGuardHook",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "lpPositionClaimed",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "lpTokenId",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "lpUnlockTime",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "mintId",
        "type": "uint256"
      },
      {
        "internalType": "uint16",
        "name": "factorBps",
        "type": "uint16"
      },
      {
        "internalType": "uint256",
        "name": "deadline",
        "type": "uint256"
      }
    ],
    "name": "mintAuthorizationDigest",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "mintCount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "mintId",
        "type": "uint256"
      }
    ],
    "name": "mintDeposits",
    "outputs": [
      {
        "internalType": "address",
        "name": "funder",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "negotiator",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      },
      {
        "internalType": "enum AgentCoin.MintDepositStatus",
        "name": "status",
        "type": "uint8"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "name",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "nextMintId",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "paymentSeed",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "paymentToken",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "permit2",
    "outputs": [
      {
        "internalType": "contract IAllowanceTransfer",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "poolManager",
    "outputs": [
      {
        "internalType": "contract IPoolManager",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "poolSeedAmount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "positionManager",
    "outputs": [
      {
        "internalType": "contract IPositionManager",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "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": "liquidityGuardHook_",
        "type": "address"
      }
    ],
    "name": "setInitialLiquidityGuardHook",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "liquidityGuardHook_",
        "type": "address"
      }
    ],
    "name": "setLiquidityGuardHook",
    "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": [],
    "name": "symbol",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalSupply",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "transfer",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "transferFrom",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "trumpAccountTokenReserve",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "mintId",
        "type": "uint256"
      }
    ],
    "name": "withdrawMintDeposit",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "withdrawTrumpAccountTokens",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  }
]

Source code

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {ERC20Burnable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {IPositionManager, PoolKey as PositionPoolKey} from "v4-periphery/src/interfaces/IPositionManager.sol";
import {Actions} from "v4-periphery/src/libraries/Actions.sol";
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
import {IAllowanceTransfer} from "permit2/src/interfaces/IAllowanceTransfer.sol";
import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol";
import {LiquidityAmounts} from "v4-periphery/src/libraries/LiquidityAmounts.sol";
import {RobinhoodAddresses} from "src/RobinhoodAddresses.sol";

contract AgentCoin is ERC20, ERC20Burnable, AccessControl, Ownable, EIP712, ReentrancyGuard {
    using SafeERC20 for IERC20;

    bytes32 public constant MINT_SIGNER_ROLE = keccak256("MINT_SIGNER_ROLE");
    bytes32 public constant LP_MANAGER_ROLE = keccak256("LP_MANAGER_ROLE");
    bytes32 public constant TRUMP_ACCOUNT_WITHDRAWER_ROLE = keccak256("TRUMP_ACCOUNT_WITHDRAWER_ROLE");
    bytes32 public constant HOOK_SETTER_ROLE = keccak256("HOOK_SETTER_ROLE");

    bytes32 public constant MINT_AUTHORIZATION_TYPEHASH = keccak256(
        "MintAuthorization(uint256 mintId,address funder,address negotiator,address recipient,uint16 factorBps,uint256 deadline)"
    );

    // User mint side is 50% of total supply:
    // 2,100 AgentCoin/mint * 5,000 mints = 10,500,000 AgentCoin.
    uint256 public constant DEFAULT_TOKENS_PER_MINT = 2_100 * 10 ** 8;
    uint256 public constant DEFAULT_MAX_MINTS = 5_000;
    uint256 public constant DEFAULT_PAYMENT_SEED = 50_000 * 10 ** 6;
    uint256 public constant DEFAULT_PAYMENT_PER_MINT = 10 * 10 ** 6;
    uint16 public constant MIN_MINT_FACTOR_BPS = 2_000; // 20%
    uint16 public constant MAX_MINT_FACTOR_BPS = 10_000; // 100%
    uint256 public constant BPS_DENOMINATOR = 10_000;
    uint24 public constant DEFAULT_POOL_FEE = 10_000; // 1%
    int24 public constant DEFAULT_POOL_TICK_SPACING = 200;
    uint256 public constant LP_LOCK_DURATION = 365 days;

    // Derived from LP seed ratio 50,000 USDG (6d) : 10,500,000 AgentCoin (8d),
    // using sqrtPriceX96 = floor(sqrt((amountToken1Raw << 192) / amountToken0Raw)).
    uint160 public constant SQRT_PRICE_PAYMENT_TOKEN_FIRST_DEFAULT = 11481251519025279852052291705240;
    uint160 public constant SQRT_PRICE_AGENT_COIN_FIRST_DEFAULT = 546726262810727612002490081;

    error NativeTransferFailed();
    error InvalidPaymentTokenDecimals();
    error InvalidRobinhoodProtocolAddresses();
    error LpNotInitialized();
    error LpPositionAlreadyClaimed();
    error LpPositionLocked(uint256 unlockTime);
    error ContractFeeClaimWindowClosed();
    error MaxMintsReached();
    error InvalidMintConfig();
    error InvalidAddress();
    error LiquidityAlreadyDeployed();
    error LiquidityGuardHookAlreadySet();
    error PoolInitializationFailed();
    error MintDepositNotFunded(uint256 mintId);
    error NotMintDepositWithdrawer(address caller, address funder, address negotiator);
    error NotMintNegotiator(address caller, address negotiator);
    error InvalidMintFactor(uint16 factorBps);
    error MintAuthorizationExpired(uint256 deadline);
    error InvalidMintAuthorization(address signer);
    error InvalidPaymentAmount(uint256 expected, uint256 received);
    error InsufficientTrumpAccountReserve(uint256 available, uint256 requested);

    enum MintDepositStatus {
        None,
        Funded,
        Withdrawn,
        Completed
    }

    struct MintDeposit {
        address funder;
        address negotiator;
        address recipient;
        MintDepositStatus status;
    }

    struct InitialRoles {
        address owner;
        address defaultAdmin;
        address mintSigner;
        address lpManager;
        address trumpAccountWithdrawer;
    }

    IPoolManager public immutable poolManager;
    IPositionManager public immutable positionManager;
    IAllowanceTransfer public immutable permit2;
    address public constant paymentToken = RobinhoodAddresses.USDG;
    uint256 public immutable paymentSeed;
    uint256 public immutable poolSeedAmount;
    uint256 internal immutable _tokensPerMint;
    uint256 internal immutable _maxMints;
    uint256 internal immutable _paymentPerMint;
    address public liquidityGuardHook;
    uint256 public lpTokenId;
    uint256 public lpUnlockTime;
    bool public liquidityDeployed;
    bool public lpPositionClaimed;
    uint256 public nextMintId = 1;
    uint256 public trumpAccountTokenReserve;

    mapping(uint256 mintId => MintDeposit deposit) public mintDeposits;

    uint160 internal _sqrtPricePaymentTokenFirst;
    uint160 internal _sqrtPriceAgentCoinFirst;

    uint256 public mintCount;

    event MintFunded(
        uint256 indexed mintId,
        address indexed funder,
        address indexed negotiator,
        address recipient,
        uint256 paymentAmount
    );
    event MintWithdrawn(
        uint256 indexed mintId, address indexed funder, address indexed initiator, uint256 paymentAmount
    );
    event MintCompleted(
        uint256 indexed mintId,
        address indexed funder,
        address indexed negotiator,
        address recipient,
        uint256 tokenAmount,
        uint256 trumpAccountAmount,
        uint16 factorBps,
        address signer
    );
    event TrumpAccountTokensWithdrawn(address indexed recipient, uint256 amount);
    event LiquidityGuardHookSet(address indexed hook);
    event LiquidityDeployed(uint256 tokenId, uint128 liquidity);
    event LpFeesCollected(address indexed recipient, uint256 indexed tokenId);
    event LpPositionClaimed(address indexed recipient, uint256 indexed tokenId);

    constructor(
        IPoolManager poolManager_,
        IPositionManager positionManager_,
        IAllowanceTransfer permit2_,
        uint256 paymentSeed_,
        uint256 poolSeedAmount_,
        uint256 tokensPerMint_,
        uint256 maxMints_,
        InitialRoles memory initialRoles_
    ) ERC20("AgentCoin", "AGENT") Ownable(initialRoles_.owner) EIP712("AgentCoin", "1") {
        if (
            address(poolManager_) == address(0) || address(positionManager_) == address(0)
                || address(permit2_) == address(0) || initialRoles_.owner == address(0)
                || initialRoles_.defaultAdmin == address(0) || initialRoles_.mintSigner == address(0)
                || initialRoles_.lpManager == address(0) || initialRoles_.trumpAccountWithdrawer == address(0)
        ) {
            revert InvalidAddress();
        }
        if (
            block.chainid == RobinhoodAddresses.CHAIN_ID
                && (address(poolManager_) != RobinhoodAddresses.UNISWAP_V4_POOL_MANAGER
                    || address(positionManager_) != RobinhoodAddresses.UNISWAP_V4_POSITION_MANAGER
                    || address(permit2_) != RobinhoodAddresses.PERMIT2)
        ) {
            revert InvalidRobinhoodProtocolAddresses();
        }
        if (
            paymentSeed_ != DEFAULT_PAYMENT_SEED || poolSeedAmount_ != DEFAULT_TOKENS_PER_MINT * DEFAULT_MAX_MINTS
                || tokensPerMint_ != DEFAULT_TOKENS_PER_MINT || maxMints_ != DEFAULT_MAX_MINTS
                || paymentSeed_ / maxMints_ != DEFAULT_PAYMENT_PER_MINT
        ) {
            revert InvalidMintConfig();
        }
        if (IERC20Metadata(paymentToken).decimals() != 6) revert InvalidPaymentTokenDecimals();

        poolManager = poolManager_;
        positionManager = positionManager_;
        permit2 = permit2_;
        paymentSeed = paymentSeed_;
        poolSeedAmount = poolSeedAmount_;
        _tokensPerMint = tokensPerMint_;
        _maxMints = maxMints_;
        _paymentPerMint = paymentSeed_ / maxMints_;

        _grantRole(DEFAULT_ADMIN_ROLE, initialRoles_.defaultAdmin);
        _grantRole(MINT_SIGNER_ROLE, initialRoles_.mintSigner);
        _grantRole(LP_MANAGER_ROLE, initialRoles_.lpManager);
        _grantRole(TRUMP_ACCOUNT_WITHDRAWER_ROLE, initialRoles_.trumpAccountWithdrawer);
        _grantRole(HOOK_SETTER_ROLE, msg.sender);
        _sqrtPricePaymentTokenFirst = SQRT_PRICE_PAYMENT_TOKEN_FIRST_DEFAULT;
        _sqrtPriceAgentCoinFirst = SQRT_PRICE_AGENT_COIN_FIRST_DEFAULT;

        // Pre-mint LP seed allocation (50% of total supply) to this contract.
        if (poolSeedAmount_ > 0) {
            _mint(address(this), poolSeedAmount_);
        }
    }

    // ===== Metadata =====
    function decimals() public pure override returns (uint8) {
        return 8;
    }

    function TOKENS_PER_MINT() public view returns (uint256) {
        return _tokensPerMint;
    }

    function MAX_MINTS() public view returns (uint256) {
        return _maxMints;
    }

    function PAYMENT_PER_MINT() public view returns (uint256) {
        return _paymentPerMint;
    }

    // ===== Mint Escrow =====
    function fundMint(address recipient, address negotiator) external nonReentrant returns (uint256 mintId) {
        if (mintCount >= _maxMints) revert MaxMintsReached();

        address resolvedRecipient = recipient == address(0) ? msg.sender : recipient;
        address resolvedNegotiator = negotiator == address(0) ? msg.sender : negotiator;
        mintId = nextMintId++;
        mintDeposits[mintId] = MintDeposit({
            funder: msg.sender,
            negotiator: resolvedNegotiator,
            recipient: resolvedRecipient,
            status: MintDepositStatus.Funded
        });

        uint256 balanceBefore = IERC20(paymentToken).balanceOf(address(this));
        IERC20(paymentToken).safeTransferFrom(msg.sender, address(this), _paymentPerMint);
        uint256 received = IERC20(paymentToken).balanceOf(address(this)) - balanceBefore;
        if (received != _paymentPerMint) revert InvalidPaymentAmount(_paymentPerMint, received);
        emit MintFunded(mintId, msg.sender, resolvedNegotiator, resolvedRecipient, _paymentPerMint);
    }

    function withdrawMintDeposit(uint256 mintId) external nonReentrant {
        MintDeposit storage deposit = mintDeposits[mintId];
        if (deposit.status != MintDepositStatus.Funded) revert MintDepositNotFunded(mintId);
        if (msg.sender != deposit.funder && msg.sender != deposit.negotiator) {
            revert NotMintDepositWithdrawer(msg.sender, deposit.funder, deposit.negotiator);
        }

        deposit.status = MintDepositStatus.Withdrawn;
        IERC20(paymentToken).safeTransfer(deposit.funder, _paymentPerMint);
        emit MintWithdrawn(mintId, deposit.funder, msg.sender, _paymentPerMint);
    }

    function completeMint(uint256 mintId, uint16 factorBps, uint256 deadline, address signer, bytes calldata signature)
        external
        nonReentrant
        returns (uint256 tokenAmount)
    {
        if (mintCount >= _maxMints) revert MaxMintsReached();

        MintDeposit storage deposit = mintDeposits[mintId];
        if (deposit.status != MintDepositStatus.Funded) revert MintDepositNotFunded(mintId);
        if (msg.sender != deposit.negotiator) revert NotMintNegotiator(msg.sender, deposit.negotiator);
        if (factorBps < MIN_MINT_FACTOR_BPS || factorBps > MAX_MINT_FACTOR_BPS) {
            revert InvalidMintFactor(factorBps);
        }
        if (block.timestamp > deadline) revert MintAuthorizationExpired(deadline);

        bytes32 digest = _mintAuthorizationDigest(mintId, deposit, factorBps, deadline);
        if (!hasRole(MINT_SIGNER_ROLE, signer) || !SignatureChecker.isValidSignatureNow(signer, digest, signature)) {
            revert InvalidMintAuthorization(signer);
        }

        deposit.status = MintDepositStatus.Completed;
        mintCount += 1;

        tokenAmount = _tokensPerMint * factorBps / BPS_DENOMINATOR;
        uint256 trumpAccountAmount = _tokensPerMint - tokenAmount;

        _mint(address(this), _tokensPerMint);
        _transfer(address(this), deposit.recipient, tokenAmount);
        trumpAccountTokenReserve += trumpAccountAmount;

        emit MintCompleted(
            mintId,
            deposit.funder,
            deposit.negotiator,
            deposit.recipient,
            tokenAmount,
            trumpAccountAmount,
            factorBps,
            signer
        );

        if (mintCount == _maxMints) _initializePoolAndDeployLiquidity(DEFAULT_POOL_FEE, DEFAULT_POOL_TICK_SPACING);
    }

    function mintAuthorizationDigest(uint256 mintId, uint16 factorBps, uint256 deadline)
        external
        view
        returns (bytes32)
    {
        MintDeposit storage deposit = mintDeposits[mintId];
        if (deposit.status == MintDepositStatus.None) revert MintDepositNotFunded(mintId);
        return _mintAuthorizationDigest(mintId, deposit, factorBps, deadline);
    }

    // ===== AccessControl-Gated Actions =====
    function setInitialLiquidityGuardHook(address liquidityGuardHook_) external onlyRole(HOOK_SETTER_ROLE) {
        if (liquidityGuardHook != address(0)) revert LiquidityGuardHookAlreadySet();
        _setLiquidityGuardHook(liquidityGuardHook_);
        _revokeRole(HOOK_SETTER_ROLE, msg.sender);
    }

    function setLiquidityGuardHook(address liquidityGuardHook_) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (liquidityDeployed) revert LiquidityAlreadyDeployed();
        _setLiquidityGuardHook(liquidityGuardHook_);
    }

    function _setLiquidityGuardHook(address liquidityGuardHook_) internal {
        if (liquidityGuardHook_ == address(0)) revert InvalidAddress();
        liquidityGuardHook = liquidityGuardHook_;
        emit LiquidityGuardHookSet(liquidityGuardHook_);
    }

    function collectLpFees() external onlyRole(LP_MANAGER_ROLE) nonReentrant {
        if (!liquidityDeployed) revert LpNotInitialized();
        if (lpPositionClaimed) revert LpPositionAlreadyClaimed();
        if (block.timestamp >= lpUnlockTime) revert ContractFeeClaimWindowClosed();

        uint256 tokenId = lpTokenId;
        (PositionPoolKey memory poolKey,) = positionManager.getPoolAndPositionInfo(tokenId);

        bytes[] memory params = new bytes[](2);
        params[0] = abi.encode(tokenId, uint256(0), uint128(0), uint128(0), bytes(""));
        params[1] = abi.encode(poolKey.currency0, poolKey.currency1, msg.sender);

        positionManager.modifyLiquidities(
            abi.encode(abi.encodePacked(uint8(Actions.DECREASE_LIQUIDITY), uint8(Actions.TAKE_PAIR)), params),
            block.timestamp + 1 hours
        );
        emit LpFeesCollected(msg.sender, tokenId);
    }

    function claimLpPosition() external onlyRole(LP_MANAGER_ROLE) nonReentrant {
        if (!liquidityDeployed) revert LpNotInitialized();
        if (lpPositionClaimed) revert LpPositionAlreadyClaimed();
        if (block.timestamp < lpUnlockTime) revert LpPositionLocked(lpUnlockTime);

        uint256 tokenId = lpTokenId;
        lpPositionClaimed = true;
        IERC721(address(positionManager)).safeTransferFrom(address(this), msg.sender, tokenId);
        emit LpPositionClaimed(msg.sender, tokenId);
    }

    function withdrawTrumpAccountTokens(address recipient, uint256 amount)
        external
        onlyRole(TRUMP_ACCOUNT_WITHDRAWER_ROLE)
        nonReentrant
    {
        if (recipient == address(0)) revert InvalidAddress();
        uint256 reserve = trumpAccountTokenReserve;
        if (amount > reserve) revert InsufficientTrumpAccountReserve(reserve, amount);

        trumpAccountTokenReserve = reserve - amount;
        _transfer(address(this), recipient, amount);
        emit TrumpAccountTokensWithdrawn(recipient, amount);
    }

    function emergencyWithdrawToken(address token, uint256 amount) external onlyRole(DEFAULT_ADMIN_ROLE) nonReentrant {
        IERC20(token).safeTransfer(msg.sender, amount);
    }

    function emergencyWithdrawNative(uint256 amount) external onlyRole(DEFAULT_ADMIN_ROLE) nonReentrant {
        (bool ok,) = payable(msg.sender).call{value: amount}("");
        if (!ok) revert NativeTransferFailed();
    }

    // ===== Internal Logic =====
    function _mintAuthorizationDigest(uint256 mintId, MintDeposit storage deposit, uint16 factorBps, uint256 deadline)
        internal
        view
        returns (bytes32)
    {
        return _hashTypedDataV4(
            keccak256(
                abi.encode(
                    MINT_AUTHORIZATION_TYPEHASH,
                    mintId,
                    deposit.funder,
                    deposit.negotiator,
                    deposit.recipient,
                    factorBps,
                    deadline
                )
            )
        );
    }

    function _initializePoolAndDeployLiquidity(uint24 fee, int24 tickSpacing) internal {
        if (liquidityDeployed) revert LiquidityAlreadyDeployed();
        if (liquidityGuardHook == address(0)) revert InvalidAddress();

        (address token0, address token1, uint160 sqrtPriceX96) = _sortedTokenData();

        PoolKey memory poolKey = PoolKey({
            currency0: Currency.wrap(token0),
            currency1: Currency.wrap(token1),
            fee: fee,
            tickSpacing: tickSpacing,
            hooks: IHooks(liquidityGuardHook)
        });

        try poolManager.initialize(poolKey, sqrtPriceX96) returns (int24) {}
        catch {
            revert PoolInitializationFailed();
        }

        uint256 amountPayment = paymentSeed;
        uint256 seedAmount = poolSeedAmount;

        (uint128 amount0Max, uint128 amount1Max, uint128 liquidity) =
            _calculateMintParams(poolKey, amountPayment, seedAmount);
        (int24 tickLower, int24 tickUpper) = _fullRangeTicks(tickSpacing);

        IERC20(paymentToken).forceApprove(address(permit2), amountPayment);
        IERC20(address(this)).forceApprove(address(permit2), seedAmount);
        permit2.approve(paymentToken, address(positionManager), SafeCast.toUint160(amountPayment), type(uint48).max);
        permit2.approve(address(this), address(positionManager), SafeCast.toUint160(seedAmount), type(uint48).max);

        bytes[] memory params = new bytes[](2);
        params[0] =
            abi.encode(poolKey, tickLower, tickUpper, liquidity, amount0Max, amount1Max, address(this), bytes(""));
        params[1] = abi.encode(poolKey.currency0, poolKey.currency1);

        lpTokenId = positionManager.nextTokenId();
        positionManager.modifyLiquidities(
            abi.encode(abi.encodePacked(uint8(Actions.MINT_POSITION), uint8(Actions.SETTLE_PAIR)), params),
            block.timestamp
        );

        liquidityDeployed = true;
        lpUnlockTime = block.timestamp + LP_LOCK_DURATION;
        emit LiquidityDeployed(lpTokenId, liquidity);
    }

    function _calculateMintParams(PoolKey memory poolKey, uint256 amountPaymentToken, uint256 amountAgentCoin)
        internal
        view
        returns (uint128 amount0Max, uint128 amount1Max, uint128 liquidity)
    {
        uint256 amount0;
        uint256 amount1;

        if (paymentToken < address(this)) {
            amount0 = amountPaymentToken;
            amount1 = amountAgentCoin;
        } else {
            amount0 = amountAgentCoin;
            amount1 = amountPaymentToken;
        }

        amount0Max = SafeCast.toUint128(amount0);
        amount1Max = SafeCast.toUint128(amount1);

        (int24 tickLower, int24 tickUpper) = _fullRangeTicks(poolKey.tickSpacing);

        liquidity = LiquidityAmounts.getLiquidityForAmounts(
            SafeCast.toUint160(paymentToken < address(this) ? _sqrtPricePaymentTokenFirst : _sqrtPriceAgentCoinFirst),
            TickMath.getSqrtPriceAtTick(tickLower),
            TickMath.getSqrtPriceAtTick(tickUpper),
            amount0,
            amount1
        );
    }

    function _fullRangeTicks(int24 tickSpacing) internal pure returns (int24 tickLower, int24 tickUpper) {
        tickLower = (TickMath.MIN_TICK / tickSpacing) * tickSpacing;
        if (tickLower < TickMath.MIN_TICK) {
            tickLower += tickSpacing;
        }

        tickUpper = (TickMath.MAX_TICK / tickSpacing) * tickSpacing;
        if (tickUpper > TickMath.MAX_TICK) {
            tickUpper -= tickSpacing;
        }
    }

    function _sortedTokenData() internal view returns (address token0, address token1, uint160 sqrtPriceX96) {
        if (paymentToken < address(this)) {
            token0 = paymentToken;
            token1 = address(this);
            sqrtPriceX96 = _sqrtPricePaymentTokenFirst;
        } else {
            token0 = address(this);
            token1 = paymentToken;
            sqrtPriceX96 = _sqrtPriceAgentCoinFirst;
        }
    }
}
Chain explorer1522msChain node102ms