@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.
- package/README.md +104 -38
- package/dist/clearing-abi.d.ts +1836 -0
- package/dist/clearing-abi.js +2361 -0
- package/dist/clearing-client.d.ts +96 -159
- package/dist/clearing-client.js +412 -553
- package/dist/clearing-codec.d.ts +57 -0
- package/dist/clearing-codec.js +173 -0
- package/dist/clearing-custody.d.ts +202 -0
- package/dist/clearing-custody.js +552 -0
- package/dist/clearing-server.d.ts +30 -49
- package/dist/clearing-server.js +87 -67
- package/dist/clearing-x402.d.ts +38 -0
- package/dist/clearing-x402.js +249 -0
- package/dist/client.d.ts +14 -15
- package/dist/client.js +53 -22
- package/dist/index.d.ts +4 -1
- package/dist/index.js +4 -1
- package/dist/mandates/account.d.ts +9 -4
- package/dist/mandates/account.js +15 -11
- package/dist/mandates/binding.d.ts +4 -27
- package/dist/mandates/binding.js +5 -9
- package/dist/mandates/checkout.js +5 -5
- package/dist/mandates/client.js +4 -3
- package/dist/mandates/l3a.d.ts +2 -2
- package/dist/mandates/l3a.js +5 -4
- package/dist/mandates/seller.d.ts +1 -1
- package/dist/mandates/seller.js +4 -4
- package/dist/mandates/verify.d.ts +4 -6
- package/dist/mandates/verify.js +147 -82
- package/dist/mandates/vi/credential.js +4 -4
- package/dist/networks.d.ts +9 -1
- package/dist/networks.js +105 -4
- package/dist/node.d.ts +11 -0
- package/dist/node.js +97 -0
- package/package.json +18 -11
- package/src/clearing-abi.ts +2361 -0
- package/src/clearing-client.test.ts +850 -0
- package/src/clearing-client.ts +612 -0
- package/src/clearing-codec.test.ts +57 -0
- package/src/clearing-codec.ts +251 -0
- package/src/clearing-custody.test.ts +763 -0
- package/src/clearing-custody.ts +743 -0
- package/src/clearing-fixture.json +37 -0
- package/src/clearing-server.test.ts +450 -0
- package/src/clearing-server.ts +123 -0
- package/src/clearing-x402.test.ts +181 -0
- package/src/clearing-x402.ts +328 -0
- package/src/client.test.ts +333 -0
- package/src/client.ts +195 -0
- package/src/index.ts +33 -0
- package/src/mandates/account.ts +95 -0
- package/src/mandates/binding.ts +280 -0
- package/src/mandates/chain.ts +68 -0
- package/src/mandates/checkout.ts +368 -0
- package/src/mandates/client.ts +159 -0
- package/src/mandates/extension.ts +48 -0
- package/src/mandates/index.ts +121 -0
- package/src/mandates/ingest.ts +42 -0
- package/src/mandates/jcs.ts +16 -0
- package/src/mandates/l3a.ts +216 -0
- package/src/mandates/seller.ts +91 -0
- package/src/mandates/verify.ts +625 -0
- package/src/mandates/vi/credential.ts +477 -0
- package/src/mandates/vi/issue.ts +118 -0
- package/src/mandates/vi/sd-jwt.ts +189 -0
- package/src/networks.test.ts +177 -0
- package/src/networks.ts +242 -0
- package/src/node.test.ts +24 -0
- package/src/node.ts +96 -0
- package/src/server.test.ts +223 -0
- package/src/server.ts +77 -0
- package/dist/clearing.d.ts +0 -204
- package/dist/clearing.js +0 -151
- package/dist/file-storage.d.ts +0 -39
- package/dist/file-storage.js +0 -195
|
@@ -1,168 +1,105 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { type
|
|
3
|
-
/** What signs: a viem local account, or anything with an address and
|
|
4
|
-
* EIP-712 `signTypedData`. */
|
|
1
|
+
import { type Hex } from "viem";
|
|
2
|
+
import { type ClearingInvoice, type ClearingReceipt } from "./clearing-codec.js";
|
|
5
3
|
export interface ClearingSigner {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
domain: Record<string, unknown>;
|
|
9
|
-
types: Record<string, unknown>;
|
|
10
|
-
primaryType: string;
|
|
11
|
-
message: Record<string, unknown>;
|
|
12
|
-
}): Promise<Hex>;
|
|
4
|
+
publicKey: Hex;
|
|
5
|
+
sign(namespace: string, message: Hex): Hex | Promise<Hex>;
|
|
13
6
|
}
|
|
14
|
-
export interface
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
/** Where the highest total signed each epoch is remembered. Default: in
|
|
19
|
-
* memory, which does not survive a restart. */
|
|
20
|
-
storage?: ClearingPositionStorage;
|
|
21
|
-
fetch?: typeof globalThis.fetch;
|
|
22
|
-
/** Clock, in milliseconds. Default: wall time. */
|
|
23
|
-
now?: () => number;
|
|
7
|
+
export interface ClearingEntry {
|
|
8
|
+
recipient: Hex;
|
|
9
|
+
cumulative: string;
|
|
10
|
+
count: string;
|
|
24
11
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
/** The running total of the debit signed last. */
|
|
32
|
-
cumulativeDebit: string;
|
|
33
|
-
/** The highest running total ever signed in this epoch. It never goes
|
|
34
|
-
* down, so a stale or low report cannot weaken the check made against it. */
|
|
35
|
-
highestSigned: string;
|
|
12
|
+
export interface ClearingPayment {
|
|
13
|
+
invoice: ClearingInvoice;
|
|
14
|
+
body: Hex;
|
|
15
|
+
payerSignature: Hex;
|
|
16
|
+
invoiceSignature: Hex;
|
|
17
|
+
entries: ClearingEntry[];
|
|
36
18
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
19
|
+
export interface ClearingPaid {
|
|
20
|
+
invoice: ClearingInvoice;
|
|
21
|
+
receipt: ClearingReceipt;
|
|
22
|
+
invoiceSignature: Hex;
|
|
23
|
+
entries: ClearingEntry[];
|
|
24
|
+
previous?: {
|
|
25
|
+
receipt: ClearingReceipt;
|
|
26
|
+
entries: ClearingEntry[];
|
|
27
|
+
};
|
|
46
28
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
29
|
+
export interface ClearingClientState {
|
|
30
|
+
epoch?: string | undefined;
|
|
31
|
+
entries: ClearingEntry[];
|
|
32
|
+
sequence: string;
|
|
33
|
+
/** The payment sent whose outcome is unknown, with the URL it pays for
|
|
34
|
+
* when `pay` was given one. */
|
|
35
|
+
pending?: (ClearingPayment & {
|
|
36
|
+
url?: string | undefined;
|
|
37
|
+
}) | undefined;
|
|
38
|
+
payments: Record<string, ClearingPaid>;
|
|
54
39
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
private readonly facilitator;
|
|
60
|
-
private readonly storage;
|
|
61
|
-
private readonly doFetch;
|
|
62
|
-
private readonly now;
|
|
63
|
-
/** Per payer and contract: the facilitator's last answer, adjusted for
|
|
64
|
-
* what this client has signed since. */
|
|
65
|
-
private readonly positions;
|
|
66
|
-
/** Per payer and contract: until when to pay the standard way. */
|
|
67
|
-
private readonly shortUntil;
|
|
68
|
-
/** Sellers the facilitator settles no clearing for, by network, contract
|
|
69
|
-
* and payee: a seller without Metal's seller token. That holds for as long
|
|
70
|
-
* as the client runs, so they are paid the standard way from then on. */
|
|
71
|
-
private readonly standardOnly;
|
|
72
|
-
/** Per payer and contract: the Debits whose outcome is in doubt, each to
|
|
73
|
-
* be presented again for its own offer. Only an answer about that Debit
|
|
74
|
-
* clears it. */
|
|
75
|
-
private readonly unresolved;
|
|
76
|
-
constructor(signer: ClearingSigner, options: ClearingDebitSchemeOptions);
|
|
77
|
-
/** The selector to give `new x402Client(...)`: the clearing offer, unless
|
|
78
|
-
* custody was lately found short or the seller cannot take clearing, in
|
|
79
|
-
* which case the standard one. A Debit whose outcome is in doubt is always
|
|
80
|
-
* presented again by clearing. */
|
|
81
|
-
readonly prefer: (_x402Version: number, accepts: PaymentRequirements[]) => PaymentRequirements;
|
|
82
|
-
/** One payment at a time per payer and contract: reading the position,
|
|
83
|
-
* signing and recording it must not interleave, or two payments would sign
|
|
84
|
-
* the same index. */
|
|
85
|
-
private readonly queues;
|
|
86
|
-
private exclusive;
|
|
87
|
-
private key;
|
|
88
|
-
private sellerOf;
|
|
89
|
-
/** The fetch to give `wrapFetchWithPayment`. A request carrying a Debit
|
|
90
|
-
* that fails without an answer, or ends in a server error that says
|
|
91
|
-
* nothing about the Debit (a proxy's 502 or 504), may still have been
|
|
92
|
-
* admitted, so its Debit is held in doubt: the next payment for that offer
|
|
93
|
-
* presents it again. It is held in memory, for as long as the client
|
|
94
|
-
* runs. */
|
|
95
|
-
wrapFetch(fetch: typeof globalThis.fetch): typeof globalThis.fetch;
|
|
96
|
-
/** Holds the Debit a request carried, if it carried one of this client's. */
|
|
97
|
-
private holdSent;
|
|
98
|
-
private hold;
|
|
99
|
-
/** Clears a Debit once a seller has answered about it. */
|
|
100
|
-
private release;
|
|
101
|
-
/** What makes two offers the same payment: a Debit signed for one can be
|
|
102
|
-
* presented again for the other. */
|
|
103
|
-
private offerId;
|
|
104
|
-
/** Where the next Debit starts: the facilitator's answer while it is
|
|
105
|
-
* fresh, else a new one. */
|
|
106
|
-
private position;
|
|
107
|
-
createPaymentPayload(x402Version: number, requirements: PaymentRequirements): Promise<PaymentPayloadResult>;
|
|
108
|
-
private sign;
|
|
40
|
+
/** save must complete an atomic durability barrier; one process owns each payer. */
|
|
41
|
+
export interface ClearingClientStore {
|
|
42
|
+
load(): Promise<ClearingClientState | null>;
|
|
43
|
+
save(state: ClearingClientState): Promise<void>;
|
|
109
44
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
* the agent's address. The tokens go from `from` straight into custody under
|
|
113
|
-
* `account`; only `account`'s signature can spend or withdraw them.
|
|
114
|
-
*
|
|
115
|
-
* Two transactions (an approval for exactly this amount, unless that much
|
|
116
|
-
* is already approved, then the deposit), paid for in the network's fee token by `from`. Gas and
|
|
117
|
-
* fees are set here because a Metal node cannot be asked to estimate them.
|
|
118
|
-
*
|
|
119
|
-
* The operator counts a deposit some seconds after its receipt, and refuses
|
|
120
|
-
* clearing payments against it until then. Given `facilitator`, this waits
|
|
121
|
-
* until the facilitator reports the deposit in the payer's position, so the
|
|
122
|
-
* next payment can draw on it. */
|
|
123
|
-
export declare function depositToClearing(opts: {
|
|
45
|
+
export interface ClearingClientConfig {
|
|
46
|
+
serviceUrl: string;
|
|
124
47
|
rpcUrl: string;
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
/** Whose custody is credited. Default: `from` itself. */
|
|
132
|
-
account?: Address;
|
|
133
|
-
amount: bigint;
|
|
134
|
-
/** The facilitator to wait on until it counts the deposit, as for
|
|
135
|
-
* `ClearingDebitScheme`. Only `from`'s own custody can be waited on: the
|
|
136
|
-
* position request is signed by the account it is about. */
|
|
137
|
-
facilitator?: string;
|
|
138
|
-
/** How long to wait for the facilitator to count it. Default: 60 s. */
|
|
139
|
-
timeoutMs?: number;
|
|
140
|
-
/** How often to ask. Default: every second. */
|
|
141
|
-
pollMs?: number;
|
|
142
|
-
fetch?: typeof globalThis.fetch;
|
|
143
|
-
}): Promise<{
|
|
144
|
-
approveTx: Hex | null;
|
|
145
|
-
depositTx: Hex;
|
|
146
|
-
available?: bigint;
|
|
147
|
-
}>;
|
|
148
|
-
/** Take funds out of clearing custody: a payer's unused deposit, or what a
|
|
149
|
-
* seller has been paid. It asks the facilitator what can be withdrawn, signs
|
|
150
|
-
* an Exit for that amount, and submits it; Metal's operator sends the two
|
|
151
|
-
* transactions (request, then release) and pays their gas.
|
|
152
|
-
*
|
|
153
|
-
* Only this wallet's signature moves its funds, and only to the destination
|
|
154
|
-
* it names, which defaults to the wallet itself. */
|
|
155
|
-
export declare function withdrawFromClearing(signer: ClearingSigner, facilitator: string, options: {
|
|
156
|
-
network: string;
|
|
157
|
-
/** Where the funds go. Default: the wallet itself. */
|
|
158
|
-
destination?: Address;
|
|
159
|
-
/** How much to withdraw, in base units. Default: everything available. */
|
|
160
|
-
amount?: bigint;
|
|
48
|
+
network: `eip155:${number}`;
|
|
49
|
+
settlement: Hex;
|
|
50
|
+
asset: Hex;
|
|
51
|
+
signer: ClearingSigner;
|
|
52
|
+
store: ClearingClientStore;
|
|
53
|
+
maxAmount: bigint;
|
|
161
54
|
fetch?: typeof globalThis.fetch;
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
55
|
+
}
|
|
56
|
+
/** Why a clearing payment was not made. */
|
|
57
|
+
export type ClearingRefusalReason = "between_epochs" | "insufficient_deposit" | "payment_held" | "answer_lost";
|
|
58
|
+
/** What to do after a `ClearingRefusal`. */
|
|
59
|
+
export type ClearingRetry =
|
|
60
|
+
/** Nothing was paid: send the request again after `ms`, and wait `ms`
|
|
61
|
+
* again after each further `between_epochs` refusal. */
|
|
62
|
+
{
|
|
63
|
+
action: "retry_after_ms";
|
|
64
|
+
ms: number;
|
|
65
|
+
}
|
|
66
|
+
/** Nothing was paid: deposit more, then send the request again. */
|
|
67
|
+
| {
|
|
68
|
+
action: "deposit";
|
|
69
|
+
}
|
|
70
|
+
/** The wallet holds a payment whose outcome is unknown, `amount` base
|
|
71
|
+
* units for `url` (`null` when `pay` was given none; through
|
|
72
|
+
* `fetchWithPayment`, the URL the request was sent to), and pays nothing
|
|
73
|
+
* else until it goes through: send that request again at that price
|
|
74
|
+
* after `ms`, which sends the same payment, so it is never paid twice. If
|
|
75
|
+
* that URL no longer offers clearing at that price, pass the wallet's
|
|
76
|
+
* `pendingInvoice()` to its `pay`, which sends the held payment itself
|
|
77
|
+
* once more; the wallet pays others once it goes through or is refused. */
|
|
78
|
+
| {
|
|
79
|
+
action: "repeat_same_request";
|
|
80
|
+
url: string | null;
|
|
81
|
+
amount: string;
|
|
82
|
+
ms: number;
|
|
83
|
+
};
|
|
84
|
+
/** A clearing payment the service did not take: `reason` says why, `retry`
|
|
85
|
+
* what to do, and the message both in words. */
|
|
86
|
+
export declare class ClearingRefusal extends Error {
|
|
87
|
+
readonly reason: ClearingRefusalReason;
|
|
88
|
+
readonly retry: ClearingRetry;
|
|
89
|
+
readonly name = "ClearingRefusal";
|
|
90
|
+
constructor(reason: ClearingRefusalReason, retry: ClearingRetry, message: string, options?: ErrorOptions);
|
|
91
|
+
}
|
|
92
|
+
export declare function createClearingClient(config: ClearingClientConfig): {
|
|
93
|
+
account: `0x${string}`;
|
|
94
|
+
pendingInvoice(): Promise<ClearingInvoice | null>;
|
|
95
|
+
/** Why this wallet does not pay `invoice`, or undefined when it does. */
|
|
96
|
+
unpayable: (invoice: ClearingInvoice) => {
|
|
97
|
+
reason: string;
|
|
98
|
+
aboveMaxAmount: boolean;
|
|
99
|
+
} | undefined;
|
|
100
|
+
/** Pay `invoice`; `url`, the request it pays for, is kept with a
|
|
101
|
+
* payment whose outcome is unknown, so a refusal can name it. A payment
|
|
102
|
+
* the service does not take throws a `ClearingRefusal`. */
|
|
103
|
+
pay(invoice: ClearingInvoice, url?: string): Promise<ClearingPaid>;
|
|
104
|
+
request: <T>(path: string, body?: unknown) => Promise<T>;
|
|
105
|
+
};
|