{"version":3,"file":"delegation-service.mjs","names":[],"sources":["../../../src/services/delegation-service.ts"],"sourcesContent":["/**\n * Delegation Service — On-chain delegation lifecycle management.\n *\n * Handles creating, signing, revoking, and checking delegations via the\n * MetaMask DelegationManager contract. Uses viem for all chain interaction.\n *\n * Delegation flow:\n *   1. Policy is compiled to caveats (delegation-compiler.ts)\n *   2. User signs the delegation (EIP-712 via wallet client)\n *   3. Signed delegation is stored in the policy metadata\n *   4. Agent can redeem the delegation to execute actions on-chain\n *   5. User or agent can revoke via disableDelegation()\n *\n * Signing paths:\n *   - Private key mode: walletClient.signTypedData() (auto-sign)\n *   - WalletConnect: walletClient.signTypedData() (prompts user's wallet)\n *   - Bankr: bankrSign({ signatureType: 'eth_signTypedData_v4', ... })\n */\n\nimport {\n  createPublicClient,\n  createWalletClient,\n  http,\n  encodeAbiParameters,\n  decodeAbiParameters,\n  encodePacked,\n  keccak256,\n  type Address,\n  type Hex,\n} from 'viem';\nimport { mainnet, base, arbitrum, optimism, polygon, sepolia, linea, baseSepolia } from 'viem/chains';\n\nimport {\n  DELEGATION_CONTRACTS,\n  DELEGATION_MANAGER_ABI,\n  DELEGATION_EIP712_TYPES,\n  CHAIN_NAMES,\n  SUPPORTED_CHAIN_IDS,\n  EXECUTE_MODE_DEFAULT,\n  getDelegationDomain,\n  type Caveat,\n  type SignedDelegation,\n  type UnsignedDelegation,\n  type DelegationStatus,\n  type ExecutionAction,\n} from './delegation-types.js';\nimport {\n  compilePolicyToDelegation,\n  formatCompilationSummary,\n  setCompilationContext,\n  type CompilationResult,\n} from './delegation-compiler.js';\nimport { getPolicyStore } from './policy-store.js';\nimport { getDelegationStore } from './delegation-store.js';\nimport type { Policy, DelegationInfo } from './policy-types.js';\n\n// ─── Chain Configuration ────────────────────────────────────────────────\n\nconst CHAIN_CONFIGS: Record<number, any> = {\n  1:        mainnet,\n  8453:     base,\n  42161:    arbitrum,\n  10:       optimism,\n  137:      polygon,\n  59144:    linea,\n  11155111: sepolia,\n  84532:    baseSepolia,\n};\n\n/** Default chain for delegation operations. */\nconst DEFAULT_CHAIN_ID = 8453; // Base\n\n// ─── Public Client Cache ────────────────────────────────────────────────\n\nconst clientCache = new Map<number, any>();\n\nfunction getDelegationPublicClient(chainId: number): any {\n  let client = clientCache.get(chainId);\n  if (client) return client;\n\n  const chain = CHAIN_CONFIGS[chainId];\n  if (!chain) throw new Error(`No chain config for chainId ${chainId}`);\n\n  client = createPublicClient({ chain, transport: http() });\n  clientCache.set(chainId, client);\n  return client;\n}\n\n// ─── Wallet Access Helpers ──────────────────────────────────────────────\n\n/**\n * Get the wallet state from the wallet service.\n * Uses dynamic import to avoid circular dependency.\n */\nasync function getWallet(): Promise<{\n  mode: 'private_key' | 'walletconnect' | 'bankr' | 'none';\n  address: Address | null;\n  walletClient: any | null;\n}> {\n  try {\n    const { getWalletState, getWalletClient } = await import('./walletconnect-service.js');\n    const state = getWalletState();\n    if (!state.connected || !state.address) {\n      return { mode: 'none', address: null, walletClient: null };\n    }\n    let wc: any = null;\n    try { wc = getWalletClient(); } catch { /* not available */ }\n    return {\n      mode: state.mode as any,\n      address: state.address as Address,\n      walletClient: wc,\n    };\n  } catch {\n    return { mode: 'none', address: null, walletClient: null };\n  }\n}\n\n// ─── Delegation Lifecycle ───────────────────────────────────────────────\n\nexport interface CreateDelegationInput {\n  /** The policy to create a delegation for. */\n  policy: Policy;\n  /** The user's wallet address (delegator). Override auto-detected. */\n  delegator?: Address;\n  /** The agent's wallet address (delegate). Override auto-detected. */\n  delegate?: Address;\n  /** Target chain ID. Defaults to Base (8453). */\n  chainId?: number;\n}\n\nexport interface CreateDelegationResult {\n  /** The compilation result with delegation and caveat details. */\n  compilation: CompilationResult;\n  /** Human-readable summary for user review before signing. */\n  summary: string;\n  /** The chain ID for this delegation. */\n  chainId: number;\n}\n\n/**\n * Step 1: Compile a policy into a delegation and return it for user review.\n * Fetches live ETH price for USD→wei conversion when possible.\n * Does NOT sign or store — the user must review and approve first.\n */\nexport async function prepareDelegation(input: CreateDelegationInput): Promise<CreateDelegationResult | { error: string }> {\n  const chainId = input.chainId ?? DEFAULT_CHAIN_ID;\n\n  // Resolve addresses:\n  // Delegator = the smart account (HybridDeleGator) that holds funds\n  // Delegate = the agent's EOA that calls redeemDelegations\n  // Try agent keystore first (has both), fall back to wallet + env var\n  const wallet = await getWallet();\n  const zeroAddr = ('0x' + '0'.repeat(40)) as Address;\n\n  let delegator = input.delegator ?? zeroAddr;\n  let delegate = input.delegate ?? (process.env.CLAWNCHER_ADDRESS as Address | undefined) ?? zeroAddr;\n\n  try {\n    const { loadMeta } = await import('./agent-keystore.js');\n    const meta = loadMeta();\n    if (meta) {\n      if (delegator === zeroAddr) delegator = meta.smartAccountAddress as Address;\n      if (delegate === zeroAddr) delegate = meta.agentAddress as Address;\n    }\n  } catch { /* keystore not available */ }\n\n  // Final fallback: use connected wallet as delegator\n  if (delegator === zeroAddr && wallet.address) {\n    delegator = wallet.address as Address;\n  }\n\n  // Fetch live ETH price for accurate USD → wei conversion\n  let ethPriceUsd = 0;\n  try {\n    const { getEthPrice } = await import('./price-service.js');\n    ethPriceUsd = await getEthPrice();\n  } catch { /* primary source failed */ }\n\n  // Fallback: fetch directly from DexScreener if primary failed\n  if (ethPriceUsd <= 0) {\n    try {\n      const resp = await fetch('https://api.dexscreener.com/latest/dex/pairs/base/0xd0b53D9277642d899DF5C87A3966A349A798F224');\n      const data = await resp.json() as any;\n      const price = parseFloat(data?.pair?.priceUsd ?? data?.pairs?.[0]?.priceUsd ?? '0');\n      if (price > 0) ethPriceUsd = price;\n    } catch { /* fallback also failed */ }\n  }\n\n  if (ethPriceUsd > 0) {\n    setCompilationContext({ ethPriceUsd });\n  } else {\n    setCompilationContext({});\n  }\n\n  const result = compilePolicyToDelegation(input.policy, delegator, delegate, chainId);\n\n  if ('type' in result && result.type === 'error') {\n    return { error: result.message };\n  }\n\n  const compilation = result as CompilationResult;\n  const summary = formatCompilationSummary(compilation, chainId);\n\n  return { compilation, summary, chainId };\n}\n\n/**\n * Step 2: Sign a delegation using the connected wallet.\n *\n * Supports three modes:\n *   - private_key: auto-sign via viem WalletClient.signTypedData()\n *   - walletconnect: prompts user's external wallet for EIP-712 signature\n *   - bankr: signs via Bankr Agent API (eth_signTypedData_v4)\n *\n * Returns the signed delegation or an error string.\n */\nexport async function signDelegation(\n  unsigned: UnsignedDelegation,\n  chainId: number,\n): Promise<{ signed: SignedDelegation } | { error: string }> {\n  const wallet = await getWallet();\n\n  // Try agent keystore first — the agent key signs delegations\n  // (the connected wallet is the owner, not the signer for delegations)\n  try {\n    const { loadAgentKey } = await import('./agent-keystore.js');\n    const agentKey = loadAgentKey();\n    if (agentKey) {\n      const { privateKeyToAccount } = await import('viem/accounts');\n      const { createWalletClient, http } = await import('viem');\n      const { base, baseSepolia } = await import('viem/chains');\n\n      const account = privateKeyToAccount(agentKey as `0x${string}`);\n      const chain = chainId === 84532 ? baseSepolia : base;\n      const agentWallet = createWalletClient({ account, chain, transport: http() });\n\n      const domain = getDelegationDomain(chainId);\n      const sig = await agentWallet.signTypedData({\n        domain,\n        types: DELEGATION_EIP712_TYPES,\n        primaryType: 'Delegation',\n        message: {\n          delegate: unsigned.delegate,\n          delegator: unsigned.delegator,\n          authority: unsigned.authority,\n          caveats: unsigned.caveats.map(c => ({ enforcer: c.enforcer, terms: c.terms })),\n          salt: unsigned.salt,\n        },\n      });\n\n      return {\n        signed: { ...unsigned, signature: sig } as SignedDelegation,\n      };\n    }\n  } catch { /* agent key not available — fall through to wallet signing */ }\n\n  if (wallet.mode === 'none' || !wallet.address) {\n    return { error: 'No wallet connected and no agent key available. Use /connect, set CLAWNCHER_PRIVATE_KEY, or run /delegator create.' };\n  }\n\n  const domain = getDelegationDomain(chainId);\n  const message = {\n    delegate: unsigned.delegate,\n    delegator: unsigned.delegator,\n    authority: unsigned.authority,\n    caveats: unsigned.caveats.map(c => ({\n      enforcer: c.enforcer,\n      terms: c.terms,\n    })),\n    salt: unsigned.salt,\n  };\n\n  try {\n    let signature: Hex;\n\n    if (wallet.mode === 'bankr') {\n      // Bankr: use bankrSign API\n      const { bankrSign } = await import('./bankr-api.js');\n      const result = await bankrSign({\n        signatureType: 'eth_signTypedData_v4',\n        typedData: {\n          domain,\n          types: DELEGATION_EIP712_TYPES,\n          primaryType: 'Delegation',\n          message,\n        },\n        chainId,\n      });\n      signature = result.signature as Hex;\n    } else if (wallet.walletClient) {\n      // Private key or WalletConnect: use viem walletClient.signTypedData\n      signature = await wallet.walletClient.signTypedData({\n        domain,\n        types: DELEGATION_EIP712_TYPES,\n        primaryType: 'Delegation',\n        message,\n      });\n    } else {\n      return { error: `Wallet mode \"${wallet.mode}\" connected but no wallet client available for signing.` };\n    }\n\n    const signed: SignedDelegation = { ...unsigned, signature };\n    return { signed };\n  } catch (err) {\n    const msg = err instanceof Error ? err.message : String(err);\n    return { error: `Signing failed: ${msg}` };\n  }\n}\n\n/**\n * Extract the earliest expiry timestamp from TimestampEnforcer caveats.\n * TimestampEnforcer terms are: (uint128 executeAfter, uint128 executeBefore).\n * Returns ISO string for the earliest executeBefore, or undefined if none.\n */\nfunction extractExpiryFromCaveats(caveats: Caveat[]): string | undefined {\n  const timestampEnforcerAddr = DELEGATION_CONTRACTS.TimestampEnforcer.toLowerCase();\n  let earliestExpiry: bigint | undefined;\n\n  for (const caveat of caveats) {\n    if (caveat.enforcer.toLowerCase() !== timestampEnforcerAddr) continue;\n\n    try {\n      const decoded = decodeAbiParameters(\n        [\n          { type: 'uint128', name: 'executeAfter' },\n          { type: 'uint128', name: 'executeBefore' },\n        ],\n        caveat.terms as Hex,\n      );\n      const executeBefore = decoded[1] as bigint;\n      if (executeBefore > 0n) {\n        if (earliestExpiry === undefined || executeBefore < earliestExpiry) {\n          earliestExpiry = executeBefore;\n        }\n      }\n    } catch {\n      // Couldn't decode — skip\n    }\n  }\n\n  if (earliestExpiry !== undefined) {\n    return new Date(Number(earliestExpiry) * 1000).toISOString();\n  }\n  return undefined;\n}\n\n/**\n * Step 3: Store a signed delegation in the policy metadata and get its hash.\n * Persists the full SignedDelegation struct to the delegation store (for\n * later redemption and on-chain revocation) and lightweight metadata on\n * the policy. Attempts to read the delegation hash from DelegationManager.\n */\nexport async function storeDelegation(\n  policy: Policy,\n  userId: string,\n  delegation: SignedDelegation,\n  chainId: number,\n  unmappedRules: string[],\n  expiresAt?: string,\n): Promise<DelegationInfo> {\n  const policyStore = getPolicyStore();\n  const delegationStore = getDelegationStore();\n\n  // Persist the full signed delegation struct for redemption/revocation\n  delegationStore.save(delegation, chainId, policy.id);\n\n  // Try to get the delegation hash from the on-chain contract\n  let hash: string = '0x';\n  try {\n    const client = getDelegationPublicClient(chainId);\n    const onChainHash = await client.readContract({\n      address: DELEGATION_CONTRACTS.DelegationManager,\n      abi: DELEGATION_MANAGER_ABI,\n      functionName: 'getDelegationHash',\n      args: [{\n        delegate: delegation.delegate,\n        delegator: delegation.delegator,\n        authority: delegation.authority,\n        caveats: delegation.caveats,\n        salt: delegation.salt,\n        signature: delegation.signature,\n      }],\n    });\n    hash = onChainHash as string;\n  } catch {\n    // Hash lookup failed — store without it\n  }\n\n  const info: DelegationInfo = {\n    chainId,\n    hash,\n    delegationManager: DELEGATION_CONTRACTS.DelegationManager,\n    status: 'signed',\n    delegate: delegation.delegate,\n    delegator: delegation.delegator,\n    salt: delegation.salt.toString(),\n    createdAt: new Date().toISOString(),\n    expiresAt: expiresAt ?? extractExpiryFromCaveats(delegation.caveats),\n    unmappedRules: unmappedRules.length > 0 ? unmappedRules : undefined,\n  };\n\n  policy.delegation = info;\n  policy.updatedAt = Date.now();\n  policyStore.savePolicy(policy);\n\n  return info;\n}\n\n// ─── Sub-Delegation (V7 — Agent Hierarchy) ─────────────────────────────\n\nexport interface CreateSubDelegationInput {\n  /** The parent signed delegation to derive from. */\n  parentDelegation: SignedDelegation;\n  /** Parent delegation hash (used as authority for chaining). */\n  parentHash: Hex;\n  /** Chain ID for the sub-delegation. */\n  chainId: number;\n  /** Sub-agent's ephemeral wallet address (the new delegate). */\n  subAgentAddress: Address;\n  /** Sub-agent's ephemeral private key (for signing the sub-delegation). */\n  subAgentPrivateKey: Hex;\n  /** Optional: additional caveats to narrow the parent's permissions. */\n  additionalCaveats?: Caveat[];\n  /** Optional: subset of parent's caveats to include (by enforcer address). */\n  caveatFilter?: Address[];\n}\n\nexport interface SubDelegationResult {\n  /** The signed sub-delegation. */\n  delegation: SignedDelegation;\n  /** Chain of delegations (parent + child) for redemption. */\n  chain: SignedDelegation[];\n  /** The parent delegation hash used as authority. */\n  authority: Hex;\n}\n\n/**\n * Create a sub-delegation from a parent delegation.\n *\n * Sub-delegation narrows the parent's permissions by:\n * 1. Setting the `authority` field to the parent delegation's hash\n *    (creating a delegation chain)\n * 2. Inheriting the parent's caveats (optionally filtered)\n * 3. Adding additional restricting caveats (narrowing only — cannot expand)\n *\n * The parent agent (current delegate) signs the sub-delegation, granting\n * the sub-agent a subset of its own permissions.\n *\n * DelegationManager verifies the full chain during redemption:\n *   User → Agent (parent) → Sub-Agent (child)\n *\n * Important: caveats can only be made MORE restrictive in sub-delegations.\n * The on-chain enforcers check both the parent and child caveats during\n * redemption. Adding a wider spending limit on the child delegation is\n * harmless — the parent's enforcer still caps the total.\n */\nexport async function createSubDelegation(\n  input: CreateSubDelegationInput,\n): Promise<SubDelegationResult | { error: string }> {\n  const {\n    parentDelegation,\n    parentHash,\n    chainId,\n    subAgentAddress,\n    subAgentPrivateKey,\n    additionalCaveats,\n    caveatFilter,\n  } = input;\n\n  // Build the child delegation's caveats:\n  // Start with parent's caveats (optionally filtered by enforcer)\n  let childCaveats: Caveat[] = [];\n\n  if (caveatFilter && caveatFilter.length > 0) {\n    const filterSet = new Set(caveatFilter.map(a => a.toLowerCase()));\n    childCaveats = parentDelegation.caveats.filter(\n      c => filterSet.has(c.enforcer.toLowerCase()),\n    );\n  } else {\n    // Inherit all parent caveats\n    childCaveats = [...parentDelegation.caveats];\n  }\n\n  // Add any additional narrowing caveats\n  if (additionalCaveats && additionalCaveats.length > 0) {\n    childCaveats.push(...additionalCaveats);\n  }\n\n  // The sub-delegation's delegator is the parent's delegate (the agent),\n  // and the delegate is the sub-agent's ephemeral address.\n  const salt = BigInt('0x' + Array.from(\n    { length: 32 },\n    () => Math.floor(Math.random() * 256).toString(16).padStart(2, '0'),\n  ).join(''));\n\n  const unsigned: UnsignedDelegation = {\n    delegate: subAgentAddress,\n    delegator: parentDelegation.delegate, // parent agent is the delegator\n    authority: parentHash,                // chain to parent delegation\n    caveats: childCaveats,\n    salt,\n  };\n\n  // Sign with the parent agent's key (the current delegate becomes delegator)\n  const domain = getDelegationDomain(chainId);\n  const message = {\n    delegate: unsigned.delegate,\n    delegator: unsigned.delegator,\n    authority: unsigned.authority,\n    caveats: unsigned.caveats.map(c => ({\n      enforcer: c.enforcer,\n      terms: c.terms,\n      args: c.args,\n    })),\n    salt: unsigned.salt,\n  };\n\n  try {\n    // The delegator of the sub-delegation is the parent agent (parentDelegation.delegate).\n    // The agent's private key (CLAWNCHER_PRIVATE_KEY) is needed to sign.\n    const agentPrivateKey = process.env.CLAWNCHER_PRIVATE_KEY as Hex | undefined;\n    if (!agentPrivateKey) {\n      return { error: 'CLAWNCHER_PRIVATE_KEY is required for sub-delegation signing. The agent must have its own private key.' };\n    }\n\n    const chain = CHAIN_CONFIGS[chainId];\n    if (!chain) {\n      return { error: `No chain config for chainId ${chainId}` };\n    }\n\n    const { privateKeyToAccount } = await import('viem/accounts');\n    const agentSignerClient = createWalletClient({\n      account: privateKeyToAccount(agentPrivateKey),\n      chain,\n      transport: http(),\n    });\n\n    const signature = await agentSignerClient.signTypedData({\n      domain,\n      types: DELEGATION_EIP712_TYPES,\n      primaryType: 'Delegation',\n      message,\n    });\n\n    const signed: SignedDelegation = { ...unsigned, signature };\n\n    return {\n      delegation: signed,\n      chain: [parentDelegation, signed], // ordered: root first, child last\n      authority: parentHash,\n    };\n  } catch (err) {\n    const msg = err instanceof Error ? err.message : String(err);\n    return { error: `Sub-delegation signing failed: ${msg}` };\n  }\n}\n\n/**\n * Revoke a delegation on-chain via DelegationManager.disableDelegation().\n * Requires the delegator's wallet to send the transaction.\n */\nexport async function revokeDelegationOnChain(\n  delegation: SignedDelegation,\n  chainId: number,\n): Promise<{ txHash: string } | { error: string }> {\n  const wallet = await getWallet();\n\n  if (wallet.mode === 'none' || !wallet.walletClient) {\n    return { error: 'No wallet connected. Connect a wallet to revoke on-chain.' };\n  }\n\n  try {\n    const txHash = await wallet.walletClient.writeContract({\n      address: DELEGATION_CONTRACTS.DelegationManager,\n      abi: DELEGATION_MANAGER_ABI,\n      functionName: 'disableDelegation',\n      args: [{\n        delegate: delegation.delegate,\n        delegator: delegation.delegator,\n        authority: delegation.authority,\n        caveats: delegation.caveats,\n        salt: delegation.salt,\n        signature: delegation.signature,\n      }],\n      chain: CHAIN_CONFIGS[chainId],\n    });\n\n    return { txHash: txHash as string };\n  } catch (err) {\n    const msg = err instanceof Error ? err.message : String(err);\n    return { error: `On-chain revocation failed: ${msg}` };\n  }\n}\n\n/**\n * Check delegation status on-chain.\n * Reads the `disabledDelegations` mapping on DelegationManager.\n */\nexport async function checkDelegationStatus(\n  delegationHash: Hex,\n  chainId: number,\n): Promise<DelegationStatus> {\n  if (!SUPPORTED_CHAIN_IDS.has(chainId)) {\n    throw new Error(`Chain ${chainId} not supported`);\n  }\n\n  try {\n    const client = getDelegationPublicClient(chainId);\n    const isDisabled = await client.readContract({\n      address: DELEGATION_CONTRACTS.DelegationManager,\n      abi: DELEGATION_MANAGER_ABI,\n      functionName: 'disabledDelegations',\n      args: [delegationHash],\n    });\n\n    return isDisabled ? 'revoked' : 'active';\n  } catch {\n    return 'signed';\n  }\n}\n\n/**\n * Refresh delegation status for a policy and persist the result.\n */\nexport async function refreshDelegationStatus(\n  policy: Policy,\n  userId: string,\n): Promise<DelegationInfo | null> {\n  if (!policy.delegation) return null;\n  if (!policy.delegation.hash || policy.delegation.hash === '0x') {\n    return policy.delegation;\n  }\n\n  try {\n    const status = await checkDelegationStatus(\n      policy.delegation.hash as Hex,\n      policy.delegation.chainId,\n    );\n\n    policy.delegation.status = status;\n    policy.delegation.lastCheckedAt = new Date().toISOString();\n\n    const store = getPolicyStore();\n    store.savePolicy(policy);\n\n    return policy.delegation;\n  } catch {\n    return policy.delegation;\n  }\n}\n\n/**\n * Build an EIP-7715 wallet_requestExecutionPermissions request payload.\n * Can be sent to wallets that support the EIP-7715 JSON-RPC method.\n */\nexport function buildEip7715Request(\n  compilation: CompilationResult,\n  chainId: number,\n): Record<string, unknown> {\n  // Map caveats to EIP-7715 permission format\n  const permissions = compilation.mappedRules.map(({ rule, caveats }) => {\n    const base: Record<string, unknown> = { type: rule.type };\n\n    if (rule.type === 'spending_limit' || rule.type === 'max_amount') {\n      base.type = 'native-token-allowance';\n      base.data = { allowance: '0x' + caveats[0]?.terms.slice(2, 66) };\n    } else if (rule.type === 'rate_limit') {\n      base.type = 'call-limit';\n      base.data = { count: (rule as any).maxCalls };\n    } else if (rule.type === 'allowlist' && (rule as any).field === 'addresses') {\n      base.type = 'allowed-targets';\n      base.data = { targets: (rule as any).values };\n    }\n\n    return base;\n  });\n\n  return {\n    method: 'wallet_requestExecutionPermissions',\n    params: [{\n      chainId: `0x${chainId.toString(16)}`,\n      permissions,\n      expiry: Math.floor(Date.now() / 1000) + 86400 * 30, // 30 days default\n    }],\n  };\n}\n\n// ─── Revoke By Policy ───────────────────────────────────────────────────\n\n/**\n * Revoke a delegation by policy ID. Loads the full SignedDelegation from the\n * delegation store and calls disableDelegation() on-chain. Also updates the\n * policy metadata and cleans up the stored struct.\n *\n * Returns { txHash } on success, or { error } if wallet/store/chain fails.\n * Falls back to local-only revocation if the full struct isn't stored.\n */\nexport async function revokeByPolicy(\n  policy: Policy,\n  userId: string,\n): Promise<{ txHash: string } | { localOnly: true } | { error: string }> {\n  if (!policy.delegation) {\n    return { error: 'Policy has no delegation to revoke.' };\n  }\n\n  const delegationStore = getDelegationStore();\n  const stored = delegationStore.load(policy.id);\n\n  if (!stored) {\n    // No full struct — can only revoke locally\n    policy.delegation.status = 'revoked';\n    policy.updatedAt = Date.now();\n    getPolicyStore().savePolicy(policy);\n    return { localOnly: true };\n  }\n\n  // Try on-chain revocation\n  const result = await revokeDelegationOnChain(stored.delegation, stored.chainId);\n\n  if ('error' in result) {\n    // On-chain failed — still revoke locally\n    policy.delegation.status = 'revoked';\n    policy.updatedAt = Date.now();\n    getPolicyStore().savePolicy(policy);\n    return result;\n  }\n\n  // On-chain succeeded — update metadata and clean up\n  policy.delegation.status = 'revoked';\n  policy.delegation.lastCheckedAt = new Date().toISOString();\n  policy.updatedAt = Date.now();\n  getPolicyStore().savePolicy(policy);\n  delegationStore.delete(policy.id);\n\n  return result;\n}\n\n// ─── Redemption ─────────────────────────────────────────────────────────\n\n/**\n * Encode the permissionContext for redeemDelegations().\n *\n * The permissionContext is an ABI-encoded delegation chain. Supports both\n * single-delegation (root) and multi-delegation (sub-delegation) chains.\n *\n * For a single root delegation:\n *   abi.encode(Delegation[1])\n *\n * For a sub-delegation chain (User → Agent → Sub-Agent):\n *   abi.encode(Delegation[2])  — ordered [parent, child]\n *\n * The DelegationManager walks the chain, verifying each delegation's\n * authority field matches the hash of its parent.\n */\nfunction encodePermissionContext(delegation: SignedDelegation): Hex {\n  return encodePermissionContextChain([delegation]);\n}\n\n/**\n * Encode a delegation chain as permissionContext.\n * Accepts an array of SignedDelegations ordered from root (parent) to leaf (child).\n * Internally reverses to leaf-first order as required by the DelegationManager\n * (delegations[0].delegate must equal msg.sender).\n * For a single root delegation, pass a 1-element array (no reversal needed).\n */\nexport function encodePermissionContextChain(chain: SignedDelegation[]): Hex {\n  // DM expects leaf-first: [child, parent, grandparent, ...]\n  const ordered = chain.length > 1 ? [...chain].reverse() : chain;\n  const delegationTuples = ordered.map(d => ({\n    delegate: d.delegate,\n    delegator: d.delegator,\n    authority: d.authority,\n    caveats: d.caveats.map(c => ({\n      enforcer: c.enforcer,\n      terms: c.terms,\n      args: c.args,\n    })),\n    salt: d.salt,\n    signature: d.signature,\n  }));\n\n  // Encode as: abi.encode(Delegation[])\n  // The DelegationManager decodes the permissionContext as a delegation chain.\n  return encodeAbiParameters(\n    [{\n      type: 'tuple[]',\n      components: [\n        { name: 'delegate', type: 'address' },\n        { name: 'delegator', type: 'address' },\n        { name: 'authority', type: 'bytes32' },\n        {\n          name: 'caveats', type: 'tuple[]',\n          components: [\n            { name: 'enforcer', type: 'address' },\n            { name: 'terms', type: 'bytes' },\n            { name: 'args', type: 'bytes' },\n          ],\n        },\n        { name: 'salt', type: 'uint256' },\n        { name: 'signature', type: 'bytes' },\n      ],\n    }],\n    [delegationTuples],\n  );\n}\n\n/**\n * Encode execution calldata for a single action.\n * ERC-7579 single execution: abi.encodePacked(target, value, callData).\n */\nfunction encodeExecution(action: ExecutionAction): Hex {\n  return encodePacked(\n    ['address', 'uint256', 'bytes'],\n    [action.target, action.value, action.callData],\n  );\n}\n\n// ─── Error Parsing ──────────────────────────────────────────────────────\n\n/** Known DelegationManager error signatures → human-readable messages. */\nconst DELEGATION_ERROR_SIGS: Record<string, string> = {\n  '0x155ff427': 'Signature verification failed (InvalidERC1271Signature). The delegation signature does not match the delegator account.',\n  '0xded4370e': 'Invalid authority chain (InvalidAuthority). Root delegations must use authority 0xfff...f.',\n  '0x8baa579f': 'Invalid signature (InvalidSignature). ECDSA recovery did not match the delegator.',\n  '0xb5863604': 'Invalid delegate (InvalidDelegate). The caller is not the authorized delegate.',\n  '0xa9e649e9': 'Invalid delegation struct (InvalidDelegation).',\n  '0xac241e11': 'Empty signature (EmptySignature). The delegation has no signature.',\n  '0x0ab29062': 'No delegations provided (NoDelegations).',\n};\n\nfunction parseDelegationError(errMsg: string): string {\n  // Check for known error signatures in the message\n  for (const [sig, humanMsg] of Object.entries(DELEGATION_ERROR_SIGS)) {\n    if (errMsg.includes(sig)) {\n      return `Delegation simulation reverted: ${humanMsg}`;\n    }\n  }\n  // Generic revert\n  if (errMsg.includes('revert')) {\n    return `Delegation simulation reverted: ${errMsg.slice(0, 200)}`;\n  }\n  return `Delegation simulation failed: ${errMsg.slice(0, 200)}`;\n}\n\nexport interface RedemptionResult {\n  /** Transaction hash from the redeemDelegations call. */\n  txHash: string;\n  /** Chain ID where the redemption was executed. */\n  chainId: number;\n}\n\n/**\n * Redeem a delegation to execute an action on-chain.\n *\n * This is the core execution path: the agent calls redeemDelegations() on the\n * DelegationManager, which verifies all caveats and executes the action through\n * the delegator's smart account.\n *\n * The caller must have the delegate's wallet (agent wallet) connected, since\n * the agent is the one redeeming.\n *\n * @param policyId - The policy whose delegation to redeem\n * @param action   - The execution action (target, value, calldata)\n * @returns        - Transaction hash or error\n */\nexport async function redeemDelegation(\n  policyId: string,\n  action: ExecutionAction,\n): Promise<RedemptionResult | { error: string }> {\n  const delegationStore = getDelegationStore();\n  const stored = delegationStore.load(policyId);\n\n  if (!stored) {\n    return { error: `No signed delegation found for policy \"${policyId}\". Create and sign a delegation first.` };\n  }\n\n  const { delegation, chainId } = stored;\n\n  // Check policy status — try wallet address first, fall back to 'owner'\n  const policyStore = getPolicyStore();\n  const wallet = await getWallet();\n  const userId = wallet.address?.toLowerCase() ?? 'owner';\n  let policies = policyStore.listPolicies(userId);\n  if (policies.length === 0 && userId !== 'owner') {\n    policies = policyStore.listPolicies('owner');\n  }\n  const policy = policies.find(p => p.id === policyId);\n  if (policy?.delegation?.status === 'revoked') {\n    return { error: 'Delegation has been revoked. Cannot redeem.' };\n  }\n\n  // P2-3: Check on-chain revocation (catches revocations made outside our tool)\n  // H2: On-chain revocation check with 5s timeout (prevent RPC DoS)\n  try {\n    const publicClient = getDelegationPublicClient(chainId);\n    const revocationCheck = async () => {\n      const delegationHash = await publicClient.readContract({\n        address: DELEGATION_CONTRACTS.DelegationManager,\n        abi: DELEGATION_MANAGER_ABI,\n        functionName: 'getDelegationHash',\n        args: [delegation],\n      });\n      return publicClient.readContract({\n        address: DELEGATION_CONTRACTS.DelegationManager,\n        abi: DELEGATION_MANAGER_ABI,\n        functionName: 'disabledDelegations',\n        args: [delegationHash],\n      });\n    };\n    const timeout = new Promise<false>((resolve) => setTimeout(() => resolve(false), 5000));\n    const isDisabled = await Promise.race([revocationCheck(), timeout]);\n    if (isDisabled) {\n      if (policy?.delegation) {\n        policy.delegation.status = 'revoked' as DelegationStatus;\n      }\n      return { error: 'Delegation has been revoked on-chain. Cannot redeem.' };\n    }\n  } catch {\n    // Non-fatal: proceed and let the contract enforce revocation.\n  }\n\n  // Verify wallet is connected (already fetched above for userId)\n  if (wallet.mode === 'none' || !wallet.walletClient) {\n    return { error: 'No wallet connected. The agent needs a connected wallet to redeem delegations.' };\n  }\n\n  // Encode the redemption parameters\n  const permissionContext = encodePermissionContext(delegation);\n  const executionCallData = encodeExecution(action);\n\n  const contractCallArgs = {\n    address: DELEGATION_CONTRACTS.DelegationManager,\n    abi: DELEGATION_MANAGER_ABI,\n    functionName: 'redeemDelegations' as const,\n    args: [\n      [permissionContext],          // bytes[] _permissionContexts\n      [EXECUTE_MODE_DEFAULT],       // bytes32[] _modes\n      [executionCallData],          // bytes[] _executionCallData\n    ],\n    chain: CHAIN_CONFIGS[chainId],\n  };\n\n  // Simulate first to catch reverts before spending gas\n  try {\n    const publicClient = getDelegationPublicClient(chainId);\n    if (publicClient) {\n      await publicClient.simulateContract({\n        ...contractCallArgs,\n        account: wallet.address!,\n      });\n    }\n  } catch (simErr) {\n    const msg = simErr instanceof Error ? simErr.message : String(simErr);\n    return { error: parseDelegationError(msg) };\n  }\n\n  try {\n    const txHash = await wallet.walletClient.writeContract(contractCallArgs);\n    return { txHash: txHash as string, chainId };\n  } catch (err) {\n    const msg = err instanceof Error ? err.message : String(err);\n    return { error: `Redemption failed: ${msg}` };\n  }\n}\n\n/**\n * Check if a delegation is available for redemption (stored and not revoked).\n */\nexport function canRedeem(policyId: string): { ready: boolean; reason?: string } {\n  const delegationStore = getDelegationStore();\n  if (!delegationStore.has(policyId)) {\n    return { ready: false, reason: 'No signed delegation stored for this policy.' };\n  }\n\n  const stored = delegationStore.load(policyId);\n  if (!stored) {\n    return { ready: false, reason: 'Delegation file corrupted or unreadable.' };\n  }\n\n  return { ready: true };\n}\n\n// ─── Display Helpers ────────────────────────────────────────────────────\n\n/**\n * Format delegation info as a human-readable status block.\n */\nexport function formatDelegationStatus(meta: DelegationInfo): string {\n  const lines: string[] = [];\n\n  const statusLabel = {\n    unsigned: 'UNSIGNED (not yet signed)',\n    signed: 'SIGNED (ready for on-chain use)',\n    active: 'ACTIVE (verified on-chain)',\n    revoked: 'REVOKED (disabled on-chain)',\n    expired: 'EXPIRED',\n  }[meta.status] ?? meta.status;\n\n  lines.push(`  Delegation: [${statusLabel}]`);\n  lines.push(`  Chain: ${CHAIN_NAMES[meta.chainId] ?? meta.chainId}`);\n  lines.push(`  Delegate: \\`${meta.delegate}\\``);\n  lines.push(`  Delegator: \\`${meta.delegator}\\``);\n\n  if (meta.hash && meta.hash !== '0x') {\n    lines.push(`  Hash: \\`${meta.hash}\\``);\n  }\n\n  if (meta.unmappedRules && meta.unmappedRules.length > 0) {\n    lines.push(`  App-layer only: ${meta.unmappedRules.join(', ')}`);\n  }\n\n  if (meta.lastCheckedAt) {\n    lines.push(`  Last verified: ${meta.lastCheckedAt}`);\n  }\n\n  return lines.join('\\n');\n}\n\n/**\n * Get all policies with delegations for a user.\n */\nexport function getDelegatedPolicies(userId: string): Policy[] {\n  const store = getPolicyStore();\n  const policies = store.listPolicies(userId);\n  return policies.filter(p => p.delegation != null);\n}\n\n/**\n * Get supported chains as a formatted string.\n */\nexport function formatSupportedChains(): string {\n  return [...SUPPORTED_CHAIN_IDS]\n    .map(id => `${CHAIN_NAMES[id] ?? id} (${id})`)\n    .join(', ');\n}\n"],"mappings":"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"}