{
  "tool_id": "art-708-v4-hook-permission-reconciler",
  "kernel_id": "art-708-v4-hook-permission-reconciler",
  "display_name": "V4 Hook Permission Reconciler",
  "tool_version": "1.0.0",
  "mandate_type": "compliance_control",
  "purpose": "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.",
  "control_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.",
  "declared_inputs": [],
  "declared_outputs": [],
  "kernel_digest": "sha256:e08cd99eaa433bc5d34fddce29b5bc96932043799b00ecc03f90b6e8670d25e9",
  "trust_label": "independently verified: zkVM execution proof (risc0/groth16-bn254)",
  "data_vintage": "2026-10-17",
  "last_validated": "2026-10-17",
  "conformance_fixtures_vendored": true,
  "compute_proof_ready": "ready",
  "wave": 127,
  "source_url": "https://ainumbers.co/chaingraph/art-708-v4-hook-permission-reconciler.html",
  "generated_at": "2026-10-22T16:18:52.581Z"
}
