{
  "tool_id": "art-708-v4-hook-permission-reconciler",
  "tool_version": "1.0.0",
  "display_name": "V4 Hook Permission Reconciler",
  "mcp_name": "reconcile_v4_hook_permissions",
  "mandate_type": "compliance_control",
  "wave": 127,
  "gpu": false,
  "url": "https://ainumbers.co/chaingraph/art-708-v4-hook-permission-reconciler.html",
  "description": "Decodes a Uniswap v4 hook address's 14 permission bits (the low 14 bits of the address, per v4-core at the pinned commit a7cf038cd568801a79a9b4cf92cd5b52c95c8585, src/libraries/Hooks.sol) against a caller-declared callback set, and reconciles the two: each of the 14 flags (beforeInitialize through afterRemoveLiquidityReturnDelta) is reported MATCH, DECLARED_NOT_SET (the callback will never fire) or SET_NOT_DECLARED (the PoolManager calls an undisclosed function), with the mismatch count equal to the popcount of declared XOR actual. The node also replicates v4-core's isValidHookAddress validity rule: each return-delta flag requires its base flag, the zero address must not carry a dynamic fee, and a non-zero hook must have at least one flag set or a dynamic pool fee (pool_fee 0x800000), reporting valid_hook_address plus the failing rule. declared_permissions is accepted flat (all 14 booleans required; a missing key is a refusal, never a default) or in the Uniswap hooklist entry shape { hook.address, flags, properties.dynamicFee }; when a registry dynamicFee declaration is supplied it is reconciled with the caller's pool_fee (dynamic iff pool_fee equals 0x800000 exactly, per LPFeeLibrary.sol isDynamicFee; any other value is a static fee) and the declaration_source is emitted. standards_basis names the pinned v4-core commit. Zero network: the node never reads a chain and decodes only what the caller supplies; it states no opinion on whether a hook is safe or compliant.",
  "input_schema_ref": "chaingraph/art-708-v4-hook-permission-reconciler.html#manifest",
  "consumes": [],
  "feeds": [],
  "status": "live",
  "conformance_fixtures": true,
  "compute_capability": "server",
  "compute_images": [{"system":"sha256-source","image_id":"sha256:e08cd99eaa433bc5d34fddce29b5bc96932043799b00ecc03f90b6e8670d25e9","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:22ef0ea3458a79deff62ad96a80e0cf324c59185658cb1b3d8bbbd98e2914641",
      "source_url": "https://raw.githubusercontent.com/Uniswap/v4-core/a7cf038cd568801a79a9b4cf92cd5b52c95c8585/src/libraries/Hooks.sol",
      "retrieved_at": "2026-10-12",
      "clause_path": "src/libraries/Hooks.sol L27-47 flag constants + L103-127 isValidHookAddress",
      "scheme": "solidity",
      "id": "v4-core a7cf038c Hooks.sol permission bits"
    },
    {
      "digest": "sha256:df3b010c74bca8274290e56fc7a876a205885243491f57748899e88b3b95aaaa",
      "source_url": "https://raw.githubusercontent.com/Uniswap/v4-core/a7cf038cd568801a79a9b4cf92cd5b52c95c8585/src/libraries/LPFeeLibrary.sol",
      "retrieved_at": "2026-10-17",
      "clause_path": "src/libraries/LPFeeLibrary.sol L30-32 isDynamicFee (true only when the fee equals DYNAMIC_FEE_FLAG 0x800000)",
      "scheme": "solidity",
      "id": "v4-core a7cf038c LPFeeLibrary isDynamicFee"
    }
  ],
  "compute_proof_ready": "ready",
  "cycle_preflight": "FAST - 6,301,757 user_cycles max across all 16 fixture vectors, measured exec-only 2026-10-22 (DEFERRED-EXEC-MEASURE-3); 0.21x the 30,000,000 line.",
  "compute_proof": {
    "type": "ZkVmReceipt",
    "system": "risc0",
    "receiptFormat": "groth16-bn254",
    "imageId": "sha256:a1a0bc89b5b1febaeda3519f6dbade0fa5ac16beeb143c4e1b01689573567bc6",
    "seal": "KY13dExTuf+VPhXiYmmGoLl5oH9sCZyTM/OaF9ero1kZlP7g1ZzLsucX4M/Hwt/oSu2Qo81MEZ7PxjBZwI0iPgJM3CE5mQzW/Jrmiqu8jojUkttLPwk9i1P8BdBve42yByR/3szdwRhpQ384M3SaHdxJmXyiH96bBPmKjoViehguXLeZ3fKSyIL9Nxsd3bDIspBR3qgzB92Ct3CStq0AGSwE5V4p4KFPBtgmKLPBfMsiu/AyfGcRXR+mKo1dsGWMA/vtkZrthebImFDfW1lhW0ihhJcwM8/+Ya3hy4QabwUD8bln144C4Kt1cuhSRwUFXcVkwxeHG4BDy58Izmp9Hw==",
    "journal": {
      "chaingraph_version": "0.4.0",
      "kernel_digest": "sha256:e08cd99eaa433bc5d34fddce29b5bc96932043799b00ecc03f90b6e8670d25e9",
      "output": {
        "assumptions": [
          "Flag table and validity rule pinned to Uniswap v4-core src/libraries/Hooks.sol at commit a7cf038cd568801a79a9b4cf92cd5b52c95c8585 (all 14 permission bits are the low 14 bits of the hook address).",
          "Zero network: the node never reads a chain and decodes only the caller-supplied address, declaration and fee.",
          "Checksummed addresses are accepted and normalised to lowercase; decoding uses BigInt arithmetic over the low 14 bits only.",
          "A missing declared boolean is a refusal, never a default: an undisclosed callback cannot be guessed."
        ],
        "declaration_source": null,
        "decoded_bits": "0x0",
        "dynamic_fee_declaration": null,
        "failing_rule": null,
        "flags": [
          {
            "actual": false,
            "bit": 13,
            "declared": false,
            "flag": "beforeInitialize",
            "status": "MATCH"
          },
          {
            "actual": false,
            "bit": 12,
            "declared": false,
            "flag": "afterInitialize",
            "status": "MATCH"
          },
          {
            "actual": false,
            "bit": 11,
            "declared": false,
            "flag": "beforeAddLiquidity",
            "status": "MATCH"
          },
          {
            "actual": false,
            "bit": 10,
            "declared": false,
            "flag": "afterAddLiquidity",
            "status": "MATCH"
          },
          {
            "actual": false,
            "bit": 9,
            "declared": false,
            "flag": "beforeRemoveLiquidity",
            "status": "MATCH"
          },
          {
            "actual": false,
            "bit": 8,
            "declared": false,
            "flag": "afterRemoveLiquidity",
            "status": "MATCH"
          },
          {
            "actual": false,
            "bit": 7,
            "declared": false,
            "flag": "beforeSwap",
            "status": "MATCH"
          },
          {
            "actual": false,
            "bit": 6,
            "declared": false,
            "flag": "afterSwap",
            "status": "MATCH"
          },
          {
            "actual": false,
            "bit": 5,
            "declared": false,
            "flag": "beforeDonate",
            "status": "MATCH"
          },
          {
            "actual": false,
            "bit": 4,
            "declared": false,
            "flag": "afterDonate",
            "status": "MATCH"
          },
          {
            "actual": false,
            "bit": 3,
            "declared": false,
            "flag": "beforeSwapReturnDelta",
            "status": "MATCH"
          },
          {
            "actual": false,
            "bit": 2,
            "declared": false,
            "flag": "afterSwapReturnDelta",
            "status": "MATCH"
          },
          {
            "actual": false,
            "bit": 1,
            "declared": false,
            "flag": "afterAddLiquidityReturnDelta",
            "status": "MATCH"
          },
          {
            "actual": false,
            "bit": 0,
            "declared": false,
            "flag": "afterRemoveLiquidityReturnDelta",
            "status": "MATCH"
          }
        ],
        "hook_address": "0x0000000000000000000000000000000000000000",
        "mismatch_count": 0,
        "mismatches": [],
        "pool_fee": 0,
        "v4_core_commit": "a7cf038cd568801a79a9b4cf92cd5b52c95c8585",
        "valid_hook_address": true
      }
    }
  }
}
