@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/src/node.ts ADDED
@@ -0,0 +1,96 @@
1
+ import { DatabaseSync } from "node:sqlite";
2
+ import { mkdir, open, readFile, rename } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { randomBytes } from "node:crypto";
5
+ import { createClearingSigner } from "./clearing-codec.js";
6
+ import type {
7
+ ClearingClientState,
8
+ ClearingClientStore,
9
+ } from "./clearing-client.js";
10
+ import type { Hex } from "viem";
11
+
12
+ /** A persistent P-256 account and receipt journal for a single server process. */
13
+ export async function openClearingWallet(directory: string) {
14
+ await mkdir(directory, { recursive: true, mode: 0o700 });
15
+ // SQLite holds an OS lock for the wallet lifetime and releases it on crash.
16
+ const owner = new DatabaseSync(join(directory, "owner.sqlite"));
17
+ try {
18
+ owner.exec(
19
+ "PRAGMA locking_mode=EXCLUSIVE; BEGIN EXCLUSIVE; CREATE TABLE IF NOT EXISTS owner (id INTEGER)",
20
+ );
21
+ } catch (error) {
22
+ owner.close();
23
+ throw new Error("clearing wallet is already in use", { cause: error });
24
+ }
25
+ try {
26
+ const keyPath = join(directory, "account.key");
27
+ let key: Hex;
28
+ try {
29
+ key = (await readFile(keyPath, "utf8")).trim() as Hex;
30
+ } catch (error) {
31
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
32
+ for (;;) {
33
+ key = `0x${randomBytes(32).toString("hex")}`;
34
+ try {
35
+ createClearingSigner(key);
36
+ break;
37
+ } catch {
38
+ /* Rejection sample the scalar. */
39
+ }
40
+ }
41
+ const file = await open(keyPath, "wx", 0o600);
42
+ try {
43
+ await file.writeFile(key);
44
+ await file.sync();
45
+ } finally {
46
+ await file.close();
47
+ }
48
+ }
49
+ const parent = await open(directory, "r");
50
+ try {
51
+ await parent.sync();
52
+ } finally {
53
+ await parent.close();
54
+ }
55
+ const signer = createClearingSigner(key);
56
+ const statePath = join(directory, "payments.json");
57
+ const store: ClearingClientStore = {
58
+ async load() {
59
+ try {
60
+ return JSON.parse(
61
+ await readFile(statePath, "utf8"),
62
+ ) as ClearingClientState;
63
+ } catch (error) {
64
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") return null;
65
+ throw error;
66
+ }
67
+ },
68
+ async save(state) {
69
+ const file = await open(statePath + ".next", "w", 0o600);
70
+ try {
71
+ await file.writeFile(JSON.stringify(state));
72
+ await file.sync();
73
+ } finally {
74
+ await file.close();
75
+ }
76
+ await rename(statePath + ".next", statePath);
77
+ const parent = await open(directory, "r");
78
+ try {
79
+ await parent.sync();
80
+ } finally {
81
+ await parent.close();
82
+ }
83
+ },
84
+ };
85
+ return {
86
+ signer,
87
+ store,
88
+ async close() {
89
+ owner.close();
90
+ },
91
+ };
92
+ } catch (error) {
93
+ owner.close();
94
+ throw error;
95
+ }
96
+ }
@@ -0,0 +1,223 @@
1
+ import { createServer, type Server } from "node:http";
2
+ import { afterAll, beforeAll, describe, expect, it } from "vitest";
3
+ import { Hono } from "hono";
4
+ import { paymentMiddleware } from "@x402/hono";
5
+ import { ExactEvmScheme } from "@x402/evm/exact/server";
6
+ import { HTTPFacilitatorClient, x402ResourceServer } from "@x402/core/server";
7
+ import {
8
+ decodePaymentRequiredHeader,
9
+ decodePaymentResponseHeader,
10
+ encodePaymentSignatureHeader,
11
+ } from "@x402/core/http";
12
+ import type { PaymentPayload, PaymentRequirements } from "@x402/core/types";
13
+ import { USDZ } from "./networks.js";
14
+ import { metalUsd, registerMetalScheme } from "./server.js";
15
+
16
+ const PAY_TO = "0x000000000000000000000000000000000000b22b";
17
+ const TX = `0x${"ab".repeat(32)}`;
18
+
19
+ const verified: PaymentPayload[] = [];
20
+ const facilitator = createServer((req, res) => {
21
+ const chunks: Buffer[] = [];
22
+ req.on("data", (c: Buffer) => chunks.push(c));
23
+ req.on("end", () => {
24
+ const body = (chunks.length ? JSON.parse(Buffer.concat(chunks).toString()) : {}) as {
25
+ paymentPayload?: PaymentPayload & { payload: { authorization?: { from?: string } } };
26
+ };
27
+ const payer = body.paymentPayload?.payload.authorization?.from;
28
+ const reply = (status: number, json: unknown) => {
29
+ res.writeHead(status, { "content-type": "application/json" });
30
+ res.end(JSON.stringify(json));
31
+ };
32
+ if (req.url === "/supported") {
33
+ return reply(200, {
34
+ kinds: [{ x402Version: 2, scheme: "exact", network: "eip155:1337" }],
35
+ extensions: [],
36
+ signers: { "eip155:*": ["0x00000000000000000000000000000000000000fa"] },
37
+ });
38
+ }
39
+ if (req.url === "/verify") {
40
+ if (body.paymentPayload) verified.push(body.paymentPayload);
41
+ if (payer?.endsWith("dead")) return reply(200, { isValid: false, invalidReason: "insufficient_funds", payer });
42
+ return reply(200, { isValid: true, payer });
43
+ }
44
+ if (req.url === "/settle") {
45
+ if (payer?.endsWith("f00d")) {
46
+ return reply(200, {
47
+ success: false,
48
+ errorReason: "transaction_failed",
49
+ errorMessage: "transferWithAuthorization reverted",
50
+ transaction: TX,
51
+ network: "eip155:1337",
52
+ payer,
53
+ });
54
+ }
55
+ return reply(200, { success: true, transaction: TX, network: "eip155:1337", payer });
56
+ }
57
+ reply(404, {});
58
+ });
59
+ });
60
+
61
+ let app: Hono;
62
+
63
+ beforeAll(async () => {
64
+ const facilitatorUrl = await listen(facilitator);
65
+ const server = registerMetalScheme(
66
+ new x402ResourceServer(new HTTPFacilitatorClient({ url: facilitatorUrl })),
67
+ { networks: ["devnet"] },
68
+ );
69
+ app = new Hono();
70
+ app.use(
71
+ paymentMiddleware(
72
+ {
73
+ "GET /quote": {
74
+ accepts: { scheme: "exact", network: "eip155:1337", payTo: PAY_TO, price: "0.01", maxTimeoutSeconds: 60 },
75
+ description: "a quote",
76
+ },
77
+ },
78
+ server,
79
+ ),
80
+ );
81
+ app.get("/quote", (c) => c.json({ quote: "hono" }));
82
+ app.get("/free", (c) => c.json({ free: true }));
83
+ });
84
+
85
+ afterAll(() => new Promise<void>((resolve) => facilitator.close(() => resolve())));
86
+
87
+ const fetchQuote = async (headers?: Record<string, string>) => app.request("http://seller.local/quote", { headers });
88
+
89
+ function paymentFor(requirements: PaymentRequirements, from: string): PaymentPayload {
90
+ return {
91
+ x402Version: 2,
92
+ accepted: requirements,
93
+ payload: {
94
+ signature: `0x${"11".repeat(65)}`,
95
+ authorization: {
96
+ from,
97
+ to: requirements.payTo,
98
+ value: requirements.amount,
99
+ validAfter: "0",
100
+ validBefore: "9999999999",
101
+ nonce: `0x${"22".repeat(32)}`,
102
+ },
103
+ },
104
+ };
105
+ }
106
+
107
+ async function challenge(): Promise<PaymentRequirements> {
108
+ const unpaid = await fetchQuote();
109
+ expect(unpaid.status).toBe(402);
110
+ const required = decodePaymentRequiredHeader(unpaid.headers.get("payment-required") as string);
111
+ expect(required.accepts).toHaveLength(1);
112
+ expect(required.accepts[0]).toMatchObject({
113
+ scheme: "exact",
114
+ network: "eip155:1337",
115
+ asset: USDZ.address,
116
+ amount: "10000000000000000",
117
+ payTo: PAY_TO,
118
+ maxTimeoutSeconds: 60,
119
+ extra: { name: USDZ.name, version: USDZ.version, primaryType: "TransferWithAuthorization" },
120
+ });
121
+ return required.accepts[0] as PaymentRequirements;
122
+ }
123
+
124
+ describe("registerMetalScheme under @x402/hono", () => {
125
+ it("leaves free routes alone", async () => {
126
+ const res = await app.request("http://seller.local/free");
127
+ expect(res.status).toBe(200);
128
+ expect(await res.json()).toEqual({ free: true });
129
+ });
130
+
131
+ it("challenges in *USDZ, then serves and settles a verified payment", async () => {
132
+ const offer = await challenge();
133
+ const paid = await fetchQuote({
134
+ "payment-signature": encodePaymentSignatureHeader(
135
+ paymentFor(offer, "0x000000000000000000000000000000000000beef"),
136
+ ),
137
+ });
138
+ expect(paid.status).toBe(200);
139
+ expect(await paid.json()).toEqual({ quote: "hono" });
140
+ const settlement = decodePaymentResponseHeader(paid.headers.get("payment-response") as string);
141
+ expect(settlement).toMatchObject({ success: true, transaction: TX, network: "eip155:1337" });
142
+ expect(verified.at(-1)?.payload).toMatchObject({
143
+ authorization: { from: "0x000000000000000000000000000000000000beef", to: PAY_TO },
144
+ });
145
+ });
146
+
147
+ it("returns the facilitator's reason as a 402", async () => {
148
+ const offer = await challenge();
149
+ const refused = await fetchQuote({
150
+ "payment-signature": encodePaymentSignatureHeader(paymentFor(offer, "0x000000000000000000000000000000000000dead")),
151
+ });
152
+ expect(refused.status).toBe(402);
153
+ expect(decodePaymentRequiredHeader(refused.headers.get("payment-required") as string).error).toBe(
154
+ "insufficient_funds",
155
+ );
156
+ });
157
+
158
+ it("returns a settle refusal as a 402 whose payment-response header carries the reason", async () => {
159
+ const offer = await challenge();
160
+ const refused = await fetchQuote({
161
+ "payment-signature": encodePaymentSignatureHeader(paymentFor(offer, "0x000000000000000000000000000000000000f00d")),
162
+ });
163
+ expect(refused.status).toBe(402);
164
+ expect(refused.headers.get("payment-required")).toBeNull();
165
+ expect(await refused.json()).toEqual({});
166
+ expect(decodePaymentResponseHeader(refused.headers.get("payment-response") as string)).toMatchObject({
167
+ success: false,
168
+ errorReason: "transaction_failed",
169
+ errorMessage: "transferWithAuthorization reverted",
170
+ transaction: TX,
171
+ network: "eip155:1337",
172
+ });
173
+ });
174
+
175
+ it("refuses an unknown network name", () => {
176
+ expect(() => registerMetalScheme(new x402ResourceServer(), { networks: ["mainnet" as never] })).toThrow(
177
+ /unknown Metal network/,
178
+ );
179
+ });
180
+ });
181
+
182
+ describe("metalUsd on the stock exact scheme", () => {
183
+ const scheme = new ExactEvmScheme().registerMoneyParser(metalUsd("eip155:1337"));
184
+
185
+ it("prices dollars on its network in *USDZ under USDZ's EIP-712 domain, as a transfer authorization", async () => {
186
+ expect(await scheme.parsePrice("$0.001", "eip155:1337")).toEqual({
187
+ amount: (10n ** 15n).toString(),
188
+ asset: USDZ.address,
189
+ extra: { name: USDZ.name, version: USDZ.version, primaryType: "TransferWithAuthorization" },
190
+ });
191
+ expect(await scheme.parsePrice(1.5, "eip155:1337")).toMatchObject({ amount: (15n * 10n ** 17n).toString() });
192
+ expect(await scheme.parsePrice(1e-7, "eip155:1337")).toMatchObject({ amount: "100000000000" });
193
+ });
194
+
195
+ it("leaves every other network to the scheme's defaults", async () => {
196
+ expect(await scheme.parsePrice("$0.01", "eip155:8453")).toMatchObject({
197
+ amount: "10000",
198
+ asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
199
+ });
200
+ });
201
+
202
+ it("prices in another dollar token with its own decimals", async () => {
203
+ const usdc = { ...USDZ, address: "0x2222222222222222222222222222222222222222", symbol: "USDC", decimals: 6 } as const;
204
+ const six = new ExactEvmScheme().registerMoneyParser(metalUsd("eip155:1337", usdc));
205
+ expect(await six.parsePrice("$0.01", "eip155:1337")).toMatchObject({ amount: "10000", asset: usdc.address });
206
+ });
207
+
208
+ it("refuses a price the token cannot carry exactly, and a price of zero", async () => {
209
+ await expect(scheme.parsePrice(1e-19, "eip155:1337")).rejects.toThrow(/decimals/);
210
+ await expect(scheme.parsePrice(0, "eip155:1337")).rejects.toThrow("not a price: 0");
211
+ });
212
+ });
213
+
214
+ function listen(server: Server): Promise<string> {
215
+ return new Promise((resolve, reject) => {
216
+ server.once("error", reject);
217
+ server.listen(0, "127.0.0.1", () => {
218
+ const address = server.address();
219
+ if (!address || typeof address === "string") return reject(new Error("no port"));
220
+ resolve(`http://127.0.0.1:${address.port}`);
221
+ });
222
+ });
223
+ }
package/src/server.ts ADDED
@@ -0,0 +1,77 @@
1
+ import type { x402ResourceServer } from "@x402/core/server";
2
+ import type { AssetAmount, MoneyParser, Network } from "@x402/core/types";
3
+ import { numberToDecimalString } from "@x402/core/utils";
4
+ import { ExactEvmScheme } from "@x402/evm/exact/server";
5
+ import {
6
+ METAL_NETWORKS,
7
+ USDZ,
8
+ baseUnits,
9
+ resolveNetwork,
10
+ type DollarToken,
11
+ type MetalNetwork,
12
+ type MetalNetworkName,
13
+ } from "./networks.js";
14
+
15
+ /**
16
+ * A dollar price (`"$0.01"`, `"0.01"`, `0.01`) in base units of `token`.
17
+ * Refuses a price the token cannot carry exactly, and one of zero.
18
+ */
19
+ export function dollarBaseUnits(price: string | number, token: DollarToken): string {
20
+ const units = baseUnits(typeof price === "number" ? numberToDecimalString(price) : price, token);
21
+ if (BigInt(units) === 0n) throw new Error(`not a price: ${String(price)}`);
22
+ return units;
23
+ }
24
+
25
+ /**
26
+ * A money parser that prices dollar amounts on `network` in `token`, and
27
+ * leaves every other network to the scheme's own defaults. The stock seller
28
+ * scheme looks dollar prices up in a table of networks it ships, and Metal is
29
+ * not in it; this is the hook the scheme provides for that:
30
+ *
31
+ * new ExactEvmScheme().registerMoneyParser(metalUsd("eip155:<chain id>"))
32
+ */
33
+ export function metalUsd(network: Network, token: DollarToken = USDZ): MoneyParser {
34
+ return async (amount, on): Promise<AssetAmount | null> =>
35
+ on === network
36
+ ? {
37
+ amount: dollarBaseUnits(amount, token),
38
+ asset: token.address,
39
+ // `primaryType` names the ERC-3009 message the payer signs, so a
40
+ // client need not probe the token for which one it supports.
41
+ extra: { name: token.name, version: token.version, primaryType: "TransferWithAuthorization" },
42
+ }
43
+ : null;
44
+ }
45
+
46
+ /**
47
+ * The `createAuthHeaders` option of the stock `HTTPFacilitatorClient`, for
48
+ * the token Metal's facilitator issued to this seller.
49
+ */
50
+ export function sellerToken(token: string) {
51
+ return async () => {
52
+ const headers = { Authorization: `Bearer ${token}` };
53
+ return { verify: headers, settle: headers };
54
+ };
55
+ }
56
+
57
+ export interface RegisterMetalSchemeConfig {
58
+ /** Which Metal networks to price offers on; both by default. */
59
+ networks?: readonly (MetalNetworkName | MetalNetwork)[];
60
+ }
61
+
62
+ /**
63
+ * Register the stock `exact` scheme on Metal's devnet and testnet (or the
64
+ * named ones) with a resource server, pricing dollar amounts in `*USDZ`, so
65
+ * the official middleware issues Metal offers and settles through the
66
+ * server's facilitator client.
67
+ */
68
+ export function registerMetalScheme(
69
+ server: x402ResourceServer,
70
+ { networks }: RegisterMetalSchemeConfig = {},
71
+ ): x402ResourceServer {
72
+ for (const entry of networks ?? Object.values(METAL_NETWORKS)) {
73
+ const { network } = resolveNetwork(entry);
74
+ server.register(network, new ExactEvmScheme().registerMoneyParser(metalUsd(network)));
75
+ }
76
+ return server;
77
+ }
@@ -1,204 +0,0 @@
1
- import { type Address, type Hex, type TypedDataDomain } from "viem";
2
- /** A Debit as it travels in a payment: uint values as decimal strings. */
3
- export interface DebitWire {
4
- payer: Address;
5
- recipient: Address;
6
- epoch: string;
7
- index: string;
8
- cumulativeDebit: string;
9
- ref: Hex;
10
- }
11
- /** The x402 scheme name of Metal's clearing lane. */
12
- export declare const CLEARING_DEBIT = "clearing-debit";
13
- export declare const CLEARING_DOMAIN_NAME = "MetalClearing";
14
- export declare const DEBIT_TYPES: {
15
- readonly Debit: readonly [{
16
- readonly name: "payer";
17
- readonly type: "address";
18
- }, {
19
- readonly name: "recipient";
20
- readonly type: "address";
21
- }, {
22
- readonly name: "epoch";
23
- readonly type: "uint64";
24
- }, {
25
- readonly name: "index";
26
- readonly type: "uint64";
27
- }, {
28
- readonly name: "cumulativeDebit";
29
- readonly type: "uint256";
30
- }, {
31
- readonly name: "ref";
32
- readonly type: "bytes32";
33
- }];
34
- };
35
- export declare const RECEIPT_TYPES: {
36
- readonly Receipt: readonly [{
37
- readonly name: "recipient";
38
- readonly type: "address";
39
- }, {
40
- readonly name: "epoch";
41
- readonly type: "uint64";
42
- }, {
43
- readonly name: "shard";
44
- readonly type: "uint64";
45
- }, {
46
- readonly name: "index";
47
- readonly type: "uint64";
48
- }, {
49
- readonly name: "cumulativeCredit";
50
- readonly type: "uint256";
51
- }, {
52
- readonly name: "prevReceiptDigest";
53
- readonly type: "bytes32";
54
- }, {
55
- readonly name: "debitDigest";
56
- readonly type: "bytes32";
57
- }];
58
- };
59
- /** The payer's cumulative outgoing authorization for one epoch. */
60
- export interface Debit {
61
- payer: Address;
62
- recipient: Address;
63
- epoch: bigint;
64
- index: bigint;
65
- cumulativeDebit: bigint;
66
- ref: Hex;
67
- }
68
- /** The operator's acknowledgment crediting a recipient's receive shard. */
69
- export interface Receipt {
70
- recipient: Address;
71
- epoch: bigint;
72
- shard: bigint;
73
- index: bigint;
74
- cumulativeCredit: bigint;
75
- prevReceiptDigest: Hex;
76
- debitDigest: Hex;
77
- }
78
- export declare function clearingDomain(chainId: number, contract: Address): TypedDataDomain;
79
- export declare function debitFromWire(wire: DebitWire): Debit;
80
- export declare function debitTypedData(domain: TypedDataDomain, debit: Debit): {
81
- readonly domain: TypedDataDomain;
82
- readonly types: {
83
- readonly Debit: readonly [{
84
- readonly name: "payer";
85
- readonly type: "address";
86
- }, {
87
- readonly name: "recipient";
88
- readonly type: "address";
89
- }, {
90
- readonly name: "epoch";
91
- readonly type: "uint64";
92
- }, {
93
- readonly name: "index";
94
- readonly type: "uint64";
95
- }, {
96
- readonly name: "cumulativeDebit";
97
- readonly type: "uint256";
98
- }, {
99
- readonly name: "ref";
100
- readonly type: "bytes32";
101
- }];
102
- };
103
- readonly primaryType: "Debit";
104
- readonly message: Debit;
105
- };
106
- export declare function receiptTypedData(domain: TypedDataDomain, receipt: Receipt): {
107
- readonly domain: TypedDataDomain;
108
- readonly types: {
109
- readonly Receipt: readonly [{
110
- readonly name: "recipient";
111
- readonly type: "address";
112
- }, {
113
- readonly name: "epoch";
114
- readonly type: "uint64";
115
- }, {
116
- readonly name: "shard";
117
- readonly type: "uint64";
118
- }, {
119
- readonly name: "index";
120
- readonly type: "uint64";
121
- }, {
122
- readonly name: "cumulativeCredit";
123
- readonly type: "uint256";
124
- }, {
125
- readonly name: "prevReceiptDigest";
126
- readonly type: "bytes32";
127
- }, {
128
- readonly name: "debitDigest";
129
- readonly type: "bytes32";
130
- }];
131
- };
132
- readonly primaryType: "Receipt";
133
- readonly message: Receipt;
134
- };
135
- export declare function debitDigest(domain: TypedDataDomain, debit: Debit): Hex;
136
- export declare function receiptDigest(domain: TypedDataDomain, receipt: Receipt): Hex;
137
- /** An account's request to take funds out of clearing custody. Only the
138
- * account can sign it, and it names where the funds go. */
139
- export declare const EXIT_TYPES: {
140
- readonly Exit: readonly [{
141
- readonly name: "account";
142
- readonly type: "address";
143
- }, {
144
- readonly name: "destination";
145
- readonly type: "address";
146
- }, {
147
- readonly name: "amount";
148
- readonly type: "uint256";
149
- }, {
150
- readonly name: "deadline";
151
- readonly type: "uint64";
152
- }];
153
- };
154
- export interface Exit {
155
- account: Address;
156
- destination: Address;
157
- amount: bigint;
158
- deadline: bigint;
159
- }
160
- export declare function exitTypedData(domain: TypedDataDomain, exit: Exit): {
161
- readonly domain: TypedDataDomain;
162
- readonly types: {
163
- readonly Exit: readonly [{
164
- readonly name: "account";
165
- readonly type: "address";
166
- }, {
167
- readonly name: "destination";
168
- readonly type: "address";
169
- }, {
170
- readonly name: "amount";
171
- readonly type: "uint256";
172
- }, {
173
- readonly name: "deadline";
174
- readonly type: "uint64";
175
- }];
176
- };
177
- readonly primaryType: "Exit";
178
- readonly message: Exit;
179
- };
180
- export declare function exitDigest(domain: TypedDataDomain, exit: Exit): Hex;
181
- export declare function recoverExitSigner(domain: TypedDataDomain, exit: Exit, signature: Hex): Promise<Address | null>;
182
- /** An account asking the facilitator about itself: where its next Debit
183
- * starts, or what it can withdraw. Signed under the clearing domain so that
184
- * only the account can read its own position; the deadline keeps a request
185
- * someone else has seen from being used for long. Never sent on chain. */
186
- export declare const ACCOUNT_REQUEST_TYPES: {
187
- readonly AccountRequest: readonly [{
188
- readonly name: "account";
189
- readonly type: "address";
190
- }, {
191
- readonly name: "deadline";
192
- readonly type: "uint64";
193
- }];
194
- };
195
- export declare function recoverAccountRequestSigner(domain: TypedDataDomain, request: {
196
- account: Address;
197
- deadline: bigint;
198
- }, signature: Hex): Promise<Address | null>;
199
- export declare function recoverDebitSigner(domain: TypedDataDomain, debit: Debit, signature: Hex): Promise<Address | null>;
200
- /** Receive shards spread a hot recipient over parallel credit lanes. The
201
- * shard is a pure function of `ref`, so a replayed debit lands on the same
202
- * one. Same formula as the café's. */
203
- export declare const REVENUE_SHARDS = 8n;
204
- export declare function shardFor(ref: Hex): bigint;