{
  "tool_id": "art-709-v4-hook-fee-conformance",
  "tool_version": "1.0.0",
  "display_name": "V4 Hook Fee Conformance",
  "mcp_name": "check_v4_hook_fee_conformance",
  "mandate_type": "compliance_control",
  "wave": 128,
  "gpu": false,
  "url": "https://ainumbers.co/chaingraph/art-709-v4-hook-fee-conformance.html",
  "description": "Recomputes a Uniswap v4 pool's per-swap fee from v4-core's own fee rules at the pinned commit a7cf038cd568801a79a9b4cf92cd5b52c95c8585 (ProtocolFeeLibrary.sol calculateSwapFee: swapFee = protocolFee + lpFee - protocolFee*lpFee/1e6; Pool.sol L307 the protocol-fee-zero pass-through and L310-316 the MAX_SWAP_FEE revert, which applies to exact-out swaps only; LPFeeLibrary.sol the 0x400000 override flag, the 0x800000 dynamic flag and MAX_LP_FEE 1,000,000) and checks each swap's emitted fee against that recomposition: per-swap CONFORMS, OUT_OF_BOUNDS (LP fee outside the declared bounds or over MAX_LP_FEE) or FEE_MISMATCH (the declared fee story does not explain what the pool charged). Validates the packed two-direction protocol fee with isValidProtocolFee (each direction <= 1000 pips), decodes a per-swap LP-fee override by stripping its flag per REMOVE_OVERRIDE_MASK (read only on a dynamic pool, per Hooks.sol beforeSwap; on a static pool it is ignored), enforces the declared total fee cap (swap fee + hook charge), accrues a separately declared hook charge per swap and per recipient in integer floor arithmetic with every remainder reported, and reports LP revenue (amount_in * lpFee / 1e6) side by side, never netted against the hook charge; LP revenue stays LP revenue. An exact-out swap whose composed fee is at or above MAX_SWAP_FEE (where v4 reverts) and a dynamic pool fee (0x800000) without a per-swap override are reported INDETERMINATE rather than guessed; an exact-in swap at that fee is checked like any other. Evidence artifact only: it states no opinion on whether a fee is lawful. Zero network: the node never reads a chain and recomputes only what the caller supplies.",
  "input_schema_ref": "chaingraph/art-709-v4-hook-fee-conformance.html#manifest",
  "consumes": [],
  "feeds": [],
  "status": "live",
  "conformance_fixtures": true,
  "compute_capability": "server",
  "compute_images": [{"system":"sha256-source","image_id":"sha256:68ca34965c2b4f1c5f10617b45c673cf3034c7fe65de08d9cf763d9e0bb04a27","valid_from":"2026-10-17"},{"system":"risc0","image_id":"sha256:a1a0bc89b5b1febaeda3519f6dbade0fa5ac16beeb143c4e1b01689573567bc6","valid_from":"2026-09-12"}],
  "export_capability": ["json"],
  "standards_basis": "implements_standard",
  "cited_clause_digest": [
    {
      "digest": "sha256:772863f912e017b60867f17f6c249bbef9acdf7459892c9865f71154cec9d383",
      "source_url": "https://raw.githubusercontent.com/Uniswap/v4-core/a7cf038cd568801a79a9b4cf92cd5b52c95c8585/src/libraries/ProtocolFeeLibrary.sol",
      "retrieved_at": "2026-10-12",
      "clause_path": "src/libraries/ProtocolFeeLibrary.sol L5-46 (MAX_PROTOCOL_FEE, isValidProtocolFee, calculateSwapFee)",
      "scheme": "solidity",
      "id": "v4-core a7cf038c ProtocolFeeLibrary calculateSwapFee"
    },
    {
      "digest": "sha256:e9a9c606ee72facf2999f4aed5b9e316e789a969e33921cfbfab32eb4634de15",
      "source_url": "https://raw.githubusercontent.com/Uniswap/v4-core/a7cf038cd568801a79a9b4cf92cd5b52c95c8585/src/libraries/Pool.sol",
      "retrieved_at": "2026-10-12",
      "clause_path": "src/libraries/Pool.sol L295-320 (swapFee = protocolFee == 0 ? lpFee : calculateSwapFee(lpFee); MAX_SWAP_FEE boundary; Swap emits the composed fee)",
      "scheme": "solidity",
      "id": "v4-core a7cf038c Pool.sol fee composition"
    },
    {
      "digest": "sha256:4cbcfb1c593d57a5d957b561785b134a244236d251d74884ac6e5619787e32e8",
      "source_url": "https://raw.githubusercontent.com/Uniswap/v4-core/a7cf038cd568801a79a9b4cf92cd5b52c95c8585/src/libraries/LPFeeLibrary.sol",
      "retrieved_at": "2026-10-12",
      "clause_path": "src/libraries/LPFeeLibrary.sol L12-70 (DYNAMIC_FEE_FLAG 0x800000, OVERRIDE_FEE_FLAG 0x400000, REMOVE_OVERRIDE_MASK 0xBFFFFF, MAX_LP_FEE, isDynamicFee, isValid, isOverride L61, removeOverrideFlag)",
      "scheme": "solidity",
      "id": "v4-core a7cf038c LPFeeLibrary fee constants and override helpers"
    },
    {
      "digest": "sha256:6438d6c7b59cbf623ef60d3f0b4c9e8798bf26b515795b0a1fd30158a92ec76c",
      "source_url": "https://raw.githubusercontent.com/Uniswap/v4-core/a7cf038cd568801a79a9b4cf92cd5b52c95c8585/src/libraries/SwapMath.sol",
      "retrieved_at": "2026-10-12",
      "clause_path": "src/libraries/SwapMath.sol L8-16 (MAX_SWAP_FEE = 1e6)",
      "scheme": "solidity",
      "id": "v4-core a7cf038c SwapMath MAX_SWAP_FEE"
    },
    {
      "digest": "sha256:deb04066ef8fe12173e874f7644d192cc5745dc14c4cf665bbeb979facb6ad1b",
      "source_url": "https://raw.githubusercontent.com/Uniswap/v4-core/a7cf038cd568801a79a9b4cf92cd5b52c95c8585/src/interfaces/IPoolManager.sol",
      "retrieved_at": "2026-10-12",
      "clause_path": "src/interfaces/IPoolManager.sol L82-91 (Swap event: fee = the swap fee in hundredths of a bip)",
      "scheme": "solidity",
      "id": "v4-core a7cf038c IPoolManager Swap event"
    },
    {
      "digest": "sha256:68d9070df74998f80b3a4190f1fd970dbe75911ce0ea53f0667ed4de18a0e0d4",
      "source_url": "https://raw.githubusercontent.com/Uniswap/v4-core/a7cf038cd568801a79a9b4cf92cd5b52c95c8585/src/libraries/Hooks.sol",
      "retrieved_at": "2026-10-17",
      "clause_path": "src/libraries/Hooks.sol L261-263 beforeSwap (lpFeeOverride read only when key.fee.isDynamicFee())",
      "scheme": "solidity",
      "id": "v4-core a7cf038c Hooks.sol beforeSwap override gate"
    }
  ],
  "compute_proof_ready": "ready",
  "cycle_preflight": "FAST - 7,734,936 user_cycles max across all 26 fixture vectors, measured exec-only 2026-10-22 (DEFERRED-EXEC-MEASURE-3).",
  "compute_proof": {
    "type": "ZkVmReceipt",
    "system": "risc0",
    "receiptFormat": "groth16-bn254",
    "imageId": "sha256:a1a0bc89b5b1febaeda3519f6dbade0fa5ac16beeb143c4e1b01689573567bc6",
    "seal": "KiUGw9RVxU7RMcuEYGdx1gD9QEv+r+W9Qfz9gxjobIoWoq7q4Rk+CPi9rCt3aDR2kcxwBnicIVIKR/yp82kROQpUAzbQgqZAvbJCx+HSIqQ4xi7LjZB/JBauDjyHw1hvARzOKARBc5P5tIhsLWkFYXHz4XrWg3xrgdXCacsaJy0Xj3Po4ZAaYmF47BAnVCEGAVV2iIr8s2s5e2FtSx1m5Bdy9btpqNGZQHCztHbEe8oj75SRfQP6G8zUJ1CzZyiyKLkIOcofiz3T4a2sBFUixCvrLJtt3X79H1g0/R+OrVsLPCTYKY67iRV4vrvLuNMViCvGwXdyN4ZUEPlS1xgilA==",
    "journal": {
      "chaingraph_version": "0.4.0",
      "kernel_digest": "sha256:68ca34965c2b4f1c5f10617b45c673cf3034c7fe65de08d9cf763d9e0bb04a27",
      "output": {
        "assumptions": [
          "Fee rules pinned to Uniswap v4-core at commit a7cf038cd568801a79a9b4cf92cd5b52c95c8585: LPFeeLibrary.sol (flags, MAX_LP_FEE), ProtocolFeeLibrary.sol (isValidProtocolFee, calculateSwapFee), Pool.sol L301-320 (fee composition and the emitted Swap fee), SwapMath.sol MAX_SWAP_FEE.",
          "calculateSwapFee replica: swapFee = protocolFee + lpFee - floor(protocolFee * lpFee / 1000000), in pips, per direction; a zero protocol fee means the whole fee is the LP fee.",
          "All monetary accruals are integer floor divisions in BigInt; every division remainder is reported and never silently dropped.",
          "LP revenue (amount_in * lpFee / 1e6) is reported separately and is never netted against the hook charge: LP revenue stays LP revenue.",
          "An exact-out swap whose composed fee is at or above MAX_SWAP_FEE is reported INDETERMINATE: v4 reverts that swap and this node does not model reverts. An exact-in swap at that fee is not reverted and is checked like any other swap.",
          "A per-swap LP-fee override is read only on a dynamic pool (pool_fee exactly 0x800000); on a static pool it is ignored and the pool fee applies. An LP fee above MAX_LP_FEE (1000000) is reported OUT_OF_BOUNDS.",
          "A dynamic pool fee (0x800000) without a per-swap override leaves the LP fee unknowable to an off-chain observer and is reported INDETERMINATE.",
          "Zero network: the node never reads a chain and recomputes only the caller-supplied declared values and emitted fees."
        ],
        "counts": {
          "conforms": 1,
          "fee_mismatch": 0,
          "indeterminate": 0,
          "out_of_bounds": 0,
          "swaps": 1
        },
        "declared_hook_charge": {
          "rate_pips": 500,
          "splits": [
            {
              "recipient_label": "treasury",
              "share_bps": 10000
            }
          ]
        },
        "declared_lp_fee_bounds": {
          "max_pips": 1000000,
          "min_pips": 0
        },
        "declared_total_fee_cap_pips": null,
        "fee_story_explained": true,
        "per_swap": [
          {
            "amount_in": 1000000,
            "cap_check": null,
            "emitted_fee_pips": 3000,
            "hook_charge_amount": 500,
            "hook_charge_per_recipient": {
              "treasury": {
                "amount": 500,
                "remainder": 0
              }
            },
            "hook_charge_remainder": 0,
            "indeterminate_reason": null,
            "index": 0,
            "lp_fee_pips": 3000,
            "lp_fee_source": "pool_static",
            "lp_fee_within_declared_bounds": true,
            "lp_revenue_amount": 3000,
            "protocol_fee_direction_pips": 0,
            "protocol_revenue_amount": 0,
            "status": "CONFORMS",
            "swap_fee_pips": 3000,
            "zero_for_one": true
          }
        ],
        "pool_fee": 3000,
        "pool_fee_is_dynamic": false,
        "protocol_fee": 0,
        "protocol_fee_one_for_zero_pips": 0,
        "protocol_fee_valid": true,
        "protocol_fee_zero_for_one_pips": 0,
        "splits_ok": true,
        "splits_sum_bps": 10000,
        "total_cap_ok": null,
        "totals": {
          "hook_charge": 500,
          "hook_charge_remainder": 0,
          "lp_revenue": 3000,
          "per_recipient": {
            "treasury": {
              "amount": 500,
              "remainder": 0
            }
          },
          "protocol_revenue": 0
        },
        "v4_core_commit": "a7cf038cd568801a79a9b4cf92cd5b52c95c8585"
      }
    }
  }
}
