@blockrun/clawrouter 0.12.256 → 0.12.257

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,6 +12,7 @@ Complete reference for ClawRouter configuration options.
12
12
  - [Routing Configuration](#routing-configuration)
13
13
  - [Tier Overrides](#tier-overrides)
14
14
  - [Scoring Weights](#scoring-weights)
15
+ - [Spend Control & Counterparty Policy](#spend-control--counterparty-policy)
15
16
  - [Testing Configuration](#testing-configuration)
16
17
 
17
18
  ---
@@ -540,6 +541,86 @@ routing:
540
541
 
541
542
  ---
542
543
 
544
+ ## Spend Control & Counterparty Policy
545
+
546
+ Amount caps bound **how much** the agent may pay. Counterparty policy bounds
547
+ **whom** it may pay, and on which network and asset. Both are evaluated before
548
+ the wallet signs anything: a refusal aborts the payment at the x402 pre-sign
549
+ hook, so no authorization is ever produced.
550
+
551
+ Everything here is **off by default**. An unconfigured list is not consulted.
552
+
553
+ State lives in `~/.openclaw/blockrun/spending.json` (mode 0600), read once at
554
+ proxy startup — **edit it, then restart the proxy** for changes to take effect.
555
+
556
+ ```json
557
+ {
558
+ "limits": {
559
+ "perRequest": 0.05,
560
+ "hourly": 2.0,
561
+ "daily": 20.0,
562
+ "session": 5.0,
563
+ "allowedPayees": ["0x1111111111111111111111111111111111111111"],
564
+ "blockedPayees": ["0x2222222222222222222222222222222222222222"],
565
+ "allowedNetworks": ["eip155:8453"],
566
+ "allowedAssets": ["0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"]
567
+ },
568
+ "history": []
569
+ }
570
+ ```
571
+
572
+ | Field | Meaning |
573
+ | --------------------------------------------- | ---------------------------------------------------------------------------------- |
574
+ | `perRequest` / `hourly` / `daily` / `session` | USD caps. Rolling 1h and 24h windows; session resets on restart. |
575
+ | `allowedPayees` | Only these `payTo` addresses may be paid. |
576
+ | `blockedPayees` | These may never be paid. **Wins over `allowedPayees`** when an address is on both. |
577
+ | `allowedNetworks` | CAIP-2 ids only. |
578
+ | `allowedAssets` | Token contract addresses of the asset being paid in. |
579
+
580
+ **Networks are CAIP-2, not nicknames.** `base` does not match `eip155:8453`
581
+ and fails closed. Use `eip155:8453` for Base and
582
+ `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d` for Solana mainnet; both
583
+ are exported as `CAIP2_BASE` and `CAIP2_SOLANA_MAINNET`.
584
+
585
+ EVM addresses in `allowedPayees`, `blockedPayees` and `allowedAssets` are
586
+ compared case-insensitively, so checksummed and lowercase forms both match.
587
+ Solana base58 addresses are case-sensitive and compared exactly.
588
+
589
+ ### Fail-closed behavior
590
+
591
+ - A configured list with **no matching value on the payment** refuses, rather
592
+ than skipping the check.
593
+ - A payment quote whose amount is not a canonical decimal integer refuses
594
+ whenever an amount cap is set. (`parseInt` and the signer's `BigInt` disagree
595
+ on `0x`-style values, so an unparseable quote is never treated as $0.)
596
+ - A **malformed** policy list in `spending.json` refuses every paid request
597
+ until the file is repaired. The proxy still starts and free models keep
598
+ working; the error names the offending field. An empty array (`[]`) is not
599
+ malformed — it means "not configured", and is how you clear a list by hand.
600
+
601
+ ### Programmatic use
602
+
603
+ ```ts
604
+ import { SpendControl, registerSpendPolicyHook, CAIP2_BASE } from "@blockrun/clawrouter";
605
+
606
+ const control = new SpendControl();
607
+ control.setLimit("daily", 20);
608
+ control.setPolicy("allowedNetworks", [CAIP2_BASE]);
609
+
610
+ // startProxy does this for you; only needed on your own x402 client.
611
+ registerSpendPolicyHook(x402, control);
612
+ ```
613
+
614
+ A refusal reaches the caller as HTTP 403 with
615
+ `{"error": {"type": "spend_policy_denied", ...}}`. It is deliberately **not**
616
+ retried against other models: a policy denial is a decision, not an outage.
617
+
618
+ **Scope:** this governs payments made by the proxy. Local tools that sign with
619
+ the same wallet outside the proxy's x402 client (Polymarket funding and order
620
+ placement, `clawrouter doctor`'s probe) are not covered.
621
+
622
+ ---
623
+
543
624
  ## Testing Configuration
544
625
 
545
626
  ### Dry Run (No Payments)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/clawrouter",
3
- "version": "0.12.256",
3
+ "version": "0.12.257",
4
4
  "description": "Smart LLM router — save 88% on inference costs. 71 models (5 free), one wallet, x402 micropayments.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",