@metalntwx/metal-pay 0.2.0 → 0.3.1

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.
Files changed (75) hide show
  1. package/README.md +104 -38
  2. package/dist/clearing-abi.d.ts +1836 -0
  3. package/dist/clearing-abi.js +2361 -0
  4. package/dist/clearing-client.d.ts +96 -159
  5. package/dist/clearing-client.js +412 -553
  6. package/dist/clearing-codec.d.ts +57 -0
  7. package/dist/clearing-codec.js +173 -0
  8. package/dist/clearing-custody.d.ts +202 -0
  9. package/dist/clearing-custody.js +552 -0
  10. package/dist/clearing-server.d.ts +30 -49
  11. package/dist/clearing-server.js +87 -67
  12. package/dist/clearing-x402.d.ts +38 -0
  13. package/dist/clearing-x402.js +249 -0
  14. package/dist/client.d.ts +14 -15
  15. package/dist/client.js +53 -22
  16. package/dist/index.d.ts +4 -1
  17. package/dist/index.js +4 -1
  18. package/dist/mandates/account.d.ts +9 -4
  19. package/dist/mandates/account.js +15 -11
  20. package/dist/mandates/binding.d.ts +4 -27
  21. package/dist/mandates/binding.js +5 -9
  22. package/dist/mandates/checkout.js +5 -5
  23. package/dist/mandates/client.js +4 -3
  24. package/dist/mandates/l3a.d.ts +2 -2
  25. package/dist/mandates/l3a.js +5 -4
  26. package/dist/mandates/seller.d.ts +1 -1
  27. package/dist/mandates/seller.js +4 -4
  28. package/dist/mandates/verify.d.ts +4 -6
  29. package/dist/mandates/verify.js +147 -82
  30. package/dist/mandates/vi/credential.js +4 -4
  31. package/dist/networks.d.ts +9 -1
  32. package/dist/networks.js +105 -4
  33. package/dist/node.d.ts +11 -0
  34. package/dist/node.js +97 -0
  35. package/package.json +18 -11
  36. package/src/clearing-abi.ts +2361 -0
  37. package/src/clearing-client.test.ts +850 -0
  38. package/src/clearing-client.ts +612 -0
  39. package/src/clearing-codec.test.ts +57 -0
  40. package/src/clearing-codec.ts +251 -0
  41. package/src/clearing-custody.test.ts +763 -0
  42. package/src/clearing-custody.ts +743 -0
  43. package/src/clearing-fixture.json +37 -0
  44. package/src/clearing-server.test.ts +450 -0
  45. package/src/clearing-server.ts +123 -0
  46. package/src/clearing-x402.test.ts +181 -0
  47. package/src/clearing-x402.ts +328 -0
  48. package/src/client.test.ts +333 -0
  49. package/src/client.ts +195 -0
  50. package/src/index.ts +33 -0
  51. package/src/mandates/account.ts +95 -0
  52. package/src/mandates/binding.ts +280 -0
  53. package/src/mandates/chain.ts +68 -0
  54. package/src/mandates/checkout.ts +368 -0
  55. package/src/mandates/client.ts +159 -0
  56. package/src/mandates/extension.ts +48 -0
  57. package/src/mandates/index.ts +121 -0
  58. package/src/mandates/ingest.ts +42 -0
  59. package/src/mandates/jcs.ts +16 -0
  60. package/src/mandates/l3a.ts +216 -0
  61. package/src/mandates/seller.ts +91 -0
  62. package/src/mandates/verify.ts +625 -0
  63. package/src/mandates/vi/credential.ts +477 -0
  64. package/src/mandates/vi/issue.ts +118 -0
  65. package/src/mandates/vi/sd-jwt.ts +189 -0
  66. package/src/networks.test.ts +177 -0
  67. package/src/networks.ts +242 -0
  68. package/src/node.test.ts +24 -0
  69. package/src/node.ts +96 -0
  70. package/src/server.test.ts +223 -0
  71. package/src/server.ts +77 -0
  72. package/dist/clearing.d.ts +0 -204
  73. package/dist/clearing.js +0 -151
  74. package/dist/file-storage.d.ts +0 -39
  75. package/dist/file-storage.js +0 -195
package/README.md CHANGED
@@ -2,10 +2,9 @@
2
2
 
3
3
  Agent payments on Metal for the official x402 packages: registers the Metal
4
4
  devnet (`eip155:1337`) and testnet (`eip155:63825`) for the `exact` scheme,
5
- priced in `*USDZ`, for both sides of a payment, and adds Metal's clearing
6
- lane for payers who pay per call without a transaction each time, and
7
- mandates, which let an agent pay from its owner's account within limits
8
- Metal enforces.
5
+ priced in `*USDZ`, for both sides of an on-chain payment, and mandates,
6
+ which let an agent pay from its owner's account within limits Metal
7
+ enforces.
9
8
 
10
9
  ```bash
11
10
  npm install @metalntwx/metal-pay @x402/core viem
@@ -16,11 +15,14 @@ client; `registerMetalNetworks(client, { signer, networks? })`
16
15
  registers the scheme on an `x402Client` you already have. Both refuse,
17
16
  before signing, a Metal `exact` offer in any token but `*USDZ` or under any
18
17
  EIP-712 domain but USDZ's. `createMetalPaymentClient` also refuses any offer
19
- above `maxAmount`, a `bigint` in `*USDZ` base units. The default is
20
- `DEFAULT_MAX_PAYMENT`, 1 `*USDZ`. It works with `@x402/*` 2.21 and later.
21
- From 2.23 the stock client pays only tokens in its own table unless its spend
22
- controls list others; `createMetalPaymentClient` lists `*USDZ` there, capped
23
- at `maxAmount`. On a client of your own, add
18
+ above `maxAmount`, a `bigint` in `*USDZ` base units, except a clearing
19
+ offer, which its wallet's own `maxAmount` caps. The default is
20
+ `DEFAULT_MAX_PAYMENT`, 1 `*USDZ`. It works with `@x402/core`, `@x402/evm`
21
+ and `@x402/fetch` from 2.28 up to the next major, installed as its peers
22
+ (npm 7+ and pnpm do that themselves). The stock client pays only tokens in
23
+ its own table unless its spend controls list others;
24
+ `createMetalPaymentClient` turns them off on its client, so its own refusals
25
+ name the offer. On a client of your own, add
24
26
  `{ network, asset: USDZ.address }` to `setSpendControls({ allowedAssets })`.
25
27
  A paid request is never redirected to another origin, so no other site
26
28
  receives the payment. `createMandatePaymentClient` does the same.
@@ -46,42 +48,98 @@ registers `ExactEvmScheme` for other networks, add
46
48
  `facilitatorUrl` is Metal's x402 facilitator for it:
47
49
  `https://x402-testnet.metalntwx.com/x402/facilitator` on testnet, and
48
50
  `http://127.0.0.1:7090/x402/facilitator` on devnet, where
49
- `just x402-facilitator` runs it. It settles `exact` payments for any
50
- seller; a seller Metal issued a token to sends it with `sellerToken(token)`,
51
- the `createAuthHeaders` option, and clearing settlement needs one.
51
+ `just x402-facilitator` runs it. It settles payments for any seller, in
52
+ either scheme; a seller Metal issued a token to sends it with
53
+ `sellerToken(token)`, the `createAuthHeaders` option, and `GET
54
+ /settlements` then lists its payments under that label. To also take
55
+ clearing, register `new ClearingServerScheme(network)` on that network
56
+ beside `exact` and list a `bajillion` offer whose `payTo` is the seller's
57
+ clearing key; the offer names the Clearing deployment the facilitator lists
58
+ in `/supported` and binds its invoices to the resource.
52
59
 
53
60
  ```typescript
54
61
  import { HTTPFacilitatorClient, x402ResourceServer } from "@x402/core/server";
55
62
  import { paymentMiddleware } from "@x402/hono";
56
63
  import { METAL_NETWORKS, registerMetalScheme } from "@metalntwx/metal-pay";
57
64
 
58
- const facilitator = new HTTPFacilitatorClient({ url: METAL_NETWORKS.devnet.facilitatorUrl });
65
+ const facilitator = new HTTPFacilitatorClient({
66
+ url: METAL_NETWORKS.devnet.facilitatorUrl,
67
+ });
59
68
  const server = registerMetalScheme(new x402ResourceServer(facilitator));
60
69
  app.use(
61
70
  paymentMiddleware(
62
- { "GET /quote": { accepts: { scheme: "exact", network: "eip155:1337", payTo: "0x…", price: "0.01" } } },
71
+ {
72
+ "GET /quote": {
73
+ accepts: {
74
+ scheme: "exact",
75
+ network: "eip155:1337",
76
+ payTo: "0x…",
77
+ price: "0.01",
78
+ },
79
+ },
80
+ },
63
81
  server,
64
82
  ),
65
83
  );
66
84
  ```
67
85
 
68
- **Clearing.** Sellers register `ClearingDebitServerScheme` next to the `exact`
69
- scheme and list a `clearing-debit` offer in a route's `accepts`; payers pass a
70
- `ClearingDebitScheme` as `createMetalPaymentClient`'s `clearing`, which pays
71
- by clearing, and by `exact` while custody is short or when the seller cannot
72
- take clearing (the facilitator settles clearing only for sellers Metal issued
73
- a token), and fund custody with `depositToClearing`. Given the facilitator, it
74
- waits until the facilitator counts the deposit, so the next payment can draw
75
- on it. On an x402 client of your own, give it the scheme's selector,
76
- `new x402Client(clearing.prefer)`, and its fetch,
77
- `wrapFetchWithPayment(clearing.wrapFetch(fetch), client)`, so a Debit whose
78
- answer never arrived, or arrived as a bare server error, is presented again
79
- rather than paid twice, for as long as the client runs. `withdrawFromClearing` takes custody out
80
- once the epoch holding it has closed and passed its challenge window, and says so
81
- when that has not happened yet. `@metalntwx/metal-pay/file-storage` keeps a
82
- clearing payer's record across restarts (Node only). The facilitator's
83
- [README](https://github.com/mx56db/metal/tree/main/apps/x402-facilitator)
84
- covers the lane.
86
+ ## Native Bajillion payments
87
+
88
+ `createClearingClient` signs cumulative P-256 payments and retains the exact
89
+ pending authorization across transport errors. Supply trusted `serviceUrl`,
90
+ `rpcUrl`, `network`, `settlement`, `asset`, a signer, an atomic store and a
91
+ `maxAmount` limit. In Node 22.13 or later (23.4 or later on Node 23),
92
+ `openClearingWallet(directory)` from `@metalntwx/metal-pay/node` supplies a
93
+ persistent signer and store with exclusive
94
+ process ownership. Preserve that directory across restarts; call `close()` on
95
+ shutdown. A payment the service does not take throws a `ClearingRefusal`,
96
+ whose `reason` is `between_epochs`, `insufficient_deposit`, `answer_lost`
97
+ or `payment_held` and whose `retry` says what to do: wait `retry.ms`
98
+ (again after each further `between_epochs`), deposit, or send the held
99
+ request, `retry.url` at `retry.amount`, again after `retry.ms` before any
100
+ other. If that URL no longer offers clearing at that price, pass the
101
+ client's `pendingInvoice()` to its `pay`. A held payment sent again is
102
+ settled from the service's receipt when it kept one, and released when it
103
+ has none and its epoch has closed or is no longer the service's live one.
104
+ A wallet's record is for one Clearing deployment: open a new wallet for a
105
+ replacement. Through `createMetalPaymentClient`'s `fetchWithPayment` it is
106
+ the thrown error's `cause`.
107
+
108
+ `clearingRequirements` and `clearingInvoice` bind an invoice to a resource,
109
+ recipient, amount and deployment. `registerClearingClient` adds the `bajillion`
110
+ scheme to an official x402 client, which then pays by clearing wherever its
111
+ wallet can pay the offer and refuses any other request on that
112
+ registration's network, unless given `{ exactFallback: true }` to pay it by
113
+ `exact`. Behind the stock middleware,
114
+ Metal's facilitator verifies and deduplicates clearing payments before the
115
+ handler runs. A seller that verifies them itself calls
116
+ `verifyClearingPayment` with its own trusted
117
+ RPC/service configuration and deduplicates `clearingPaymentId` in durable
118
+ storage before delivering. The returned receipt is **preconfirmed**;
119
+ watch `Clearing.finalizedCount` before labeling its epoch finalized. It is not
120
+ an EVM transaction hash.
121
+
122
+ `depositToClearing` funds a clearing account from an EVM account, waiting
123
+ for the contract's deposit window; `clearingSpendable` reads the service's
124
+ estimate of what the account can spend, in token base units, which counts
125
+ a deposit from the epoch after it lands and can read low around an
126
+ epoch's close, and
127
+ `clearingBalance` the finalized balance and its proof, in clearing units
128
+ (`Clearing.unit()` base units each, a millionth of `*USDZ`);
129
+ `withdrawFromClearing` queues a withdrawal of the finalized balance and,
130
+ once its epoch has finalized, claims it, for payer and seller alike; it
131
+ answers `empty` when there is nothing finalized to claim or queue. A
132
+ queue or claim refused because an epoch finalized under its proof moved
133
+ nothing, and its error says to call again after the next epoch.
134
+ `clearingClose` and `clearingLogProof` are the pieces it is built from.
135
+ `recoverFromClearing` takes an account's funds out of a deployment whose
136
+ service has missed a deadline: it faults the deployment, starts recovery,
137
+ and takes the payout of the account's finalized withdrawal, its last
138
+ finalized balance and its uncounted deposits, with proofs from the service
139
+ or the first of several validators that retained the epoch. The clearing
140
+ service's README, `apps/clearing-service/README.md` in the Metal
141
+ repository, describes operator/validator setup, receipt retention and proof
142
+ endpoints.
85
143
 
86
144
  **Mandates.** `@metalntwx/metal-pay/mandates` lets an agent pay from its
87
145
  owner's account with a P-256 key of its own, within limits Metal enforces on
@@ -90,23 +148,31 @@ budget, how many payments, an expiry) as a Verifiable Intent mandate;
90
148
  `ingestCredential` verifies one against the issuers the owner trusts, and
91
149
  `bindCall`, `replaceCall` and `revokeCall` build the owner's transactions to its own
92
150
  MetalAccount. Wrap those calls with `authorizeMandateCall(client, trustedFactory,
93
- call, signQuorum)` to authorize an account self-call, or a list of them as one
151
+ call, validUntil, signQuorum)` to authorize an account self-call, or a list of them as one
94
152
  batch that runs whole or not at all, with its existing weighted quorum. The
95
- client must name its chain: the digest the quorum signs is computed from it,
96
- never read from the RPC endpoint. The callback supports the same EOA, P-256 and passkey signatures as
97
- ordinary account execution. Factory-created clones share an immutable VI
153
+ account refuses the signed batch after `validUntil` (unix seconds, a `bigint`), so
154
+ give it a short deadline. The client must name its chain: the digest the quorum
155
+ signs is computed from it, never read from the RPC endpoint. The callback
156
+ supports the same EOA, P-256 and passkey signatures as ordinary account
157
+ execution. Factory-created clones share an immutable VI
98
158
  verifier; budgets and replay protection live in each account. `createMandatePaymentClient({ credential, signDigest, network })`
99
159
  is the payer, and `MandateExactScheme` the same payer as a scheme for an
100
160
  `x402Client` of your own: each payment is an ERC-3009 authorization from the
101
- owner's account whose signature is the agent's per-payment mandate, which
102
- the account accepts or refuses through ERC-1271. Sellers and facilitators
103
- see an ordinary `exact` payment. The client sets no limit of its own.
161
+ owner's account whose signature is the agent's per-payment mandate; Metal's
162
+ facilitator submits it as `pull` on the owner's account, which checks it
163
+ against the mandate, spends the budget and hands the token the
164
+ authorization. Sellers see an ordinary `exact` payment. The client sets no
165
+ limit of its own.
104
166
  `readCheck` names the limit behind a refusal, `readMandateState` reads the
105
167
  spend, and `pullCall` builds a direct payment with no seller. A credential's amounts
106
168
  are decimal, to the cent. `verifyMandate` and `verifyMandatePayment` trust the
107
169
  MetalAccountFactory `METAL_NETWORKS` names for the chain, or the
108
170
  `accountFactory` given, check the account's clone code against the
109
171
  factory's current implementation, and match the successful token transfer to the seller's requirements.
172
+ `verifyMandatePayment` checks a `checkoutMandate` against the payment, failing one of another
173
+ payment as such; its step 4 says when none was given, so no order was checked.
174
+ An event under the mandate that the SDK does not decode, as an account of
175
+ another version emits, fails the verification with its topic and the account.
110
176
  The module runs on Node only.
111
177
 
112
178
  **RPC.** Neither payers nor payees need one. Each network's `rpc` is its