Skip to content

Counterparty policy does not reach Polymarket fund/order/withdraw/redeem signing or doctor's x402 client #302

Description

@twzrd-sol

Follow-up to #268, per the scope note there.

Enforcement today (v0.12.263, fa0b1468): one site. src/proxy.ts:2323-2325 builds the proxy x402Client and calls registerSpendPolicyHook before registerExactEvmScheme. No other file calls registerSpendPolicyHook or SpendControl.check().

Paths that sign with the same wallet and never consult it:

  1. src/doctor.ts:409-439 — a second x402Client (L409), EVM/SVM schemes (L410/L426), wrapFetchWithPayment (L435), paid /v1/chat/completions (L438-439) at ~$0.003–$0.01/run (DOCTOR_MODELS L370-379). The proxy's shape minus one line.
  2. src/polymarket/fund.ts:122createPaymentPayload() (@blockrun/llm) signs an EIP-3009 authorization to bridge on eip155:8453; L132-133 pays the $0.01 fee via new BlockrunClient({ privateKey }). No SpendControl import.
  3. src/polymarket/orders.ts:433clob.createAndPostOrder(). confirm:true (L407), POLYMARKET_MAX_BET_USD (L377) and reserveBet (L429) are per-order notional caps on a separate ledger, not a counterparty check.
  4. src/polymarket/withdraw.ts:147 and src/polymarket/redeem.ts:155sendTransaction / sendWalletBatch, same shape.

Net: an allowedPayees list that makes the proxy refuse every other payee does nothing here. docs/configuration.md reads wallet-level; enforcement is proxy-level.

Fix

  • doctor.ts: registerSpendPolicyHook(x402, new SpendControl()) before L410 — identical to proxy.ts:2325.
  • Polymarket paths: control.check(amount, { payTo, network, asset }) before the signer — CAIP-2 network, contract addresses from constants.ts; !allowed throws SpendPolicyError, nothing is signed. The fee leg inside BlockrunClient needs its own hook or a doc note — @blockrun/llm 3.13.2 exposes none.
  • Fail closed: no parseable amount with limits configured → refuse, as assertSpendPolicyAllows already does.

Tests — wiring-level, mutation-checked like proxy.spend-policy.test.ts: in-memory SpendControl with blockedPayees matching the counterparty; assert the signer is never called on each path. Deleting each check line must turn the test red.

PR to follow.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions