@dvmkit/sdk 0.3.3-rc.10 → 0.4.0-rc.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/dist/{chunk-C2AGARLM.js → chunk-2VGWYG4P.js} +5 -3
- package/dist/{chunk-A4CM2BD3.js → chunk-3MHE725Z.js} +1 -1
- package/dist/{chunk-VAMSJRJT.js → chunk-5LR6P7WN.js} +5 -3
- package/dist/{chunk-YYQG4R7T.js → chunk-74PUEZJ4.js} +6 -4
- package/dist/{chunk-MKI6OVW4.js → chunk-CZULM42S.js} +0 -51
- package/dist/{chunk-M4QDXD2A.js → chunk-FYRR2UEZ.js} +1 -1
- package/dist/{chunk-4UZN2GP5.js → chunk-GAOAYHZA.js} +209 -33
- package/dist/{chunk-Z4BNLUZF.js → chunk-IWQHUSMO.js} +3 -105
- package/dist/{chunk-4J32DTLT.js → chunk-IXR5RFK7.js} +82 -4
- package/dist/{chunk-2SD2W2BG.js → chunk-JH3SX3LY.js} +252 -26
- package/dist/{chunk-UZC4A4DM.js → chunk-K2YX2VRA.js} +2480 -206
- package/dist/chunk-KA6VN5FK.js +245 -0
- package/dist/chunk-LIRAHP7B.js +53 -0
- package/dist/{chunk-MG67KXU7.js → chunk-MZRJR2CW.js} +4 -2
- package/dist/{chunk-JDFLRNAZ.js → chunk-PB4FYZET.js} +67 -7
- package/dist/{chunk-BQ2NMWKE.js → chunk-PLG4XER6.js} +1 -1
- package/dist/{chunk-Z3EHBW2G.js → chunk-R4DQZFAL.js} +7 -5
- package/dist/chunk-RLTSCKRI.js +109 -0
- package/dist/{chunk-2KGG5ORW.js → chunk-TXX4GOUB.js} +3 -3
- package/dist/{chunk-YRDA7EWN.js → chunk-W2EQGDF5.js} +14 -10
- package/dist/{chunk-EAMZZ2B4.js → chunk-X7EZ5CLI.js} +59 -0
- package/dist/{chunk-7X6UDVCQ.js → chunk-Z4ZT5LNT.js} +66 -2
- package/dist/{credit-ledger-A35WH2TI.js → credit-ledger-MI2H7NEC.js} +3 -1
- package/dist/{credit-menu-0-UtJ3hh.d.ts → credit-menu-B8_p_vUz.d.ts} +133 -7
- package/dist/{fx-DhyT1Cjh.d.ts → fx-DuaYHvVn.d.ts} +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/internal/caller.d.ts +15 -7
- package/dist/internal/caller.js +36 -24
- package/dist/internal/index.js +1 -1
- package/dist/internal/server.d.ts +11 -85
- package/dist/internal/server.js +18 -16
- package/dist/{job-store-D3CcZp_g.d.ts → job-store-D6Rjj5Oi.d.ts} +1 -1
- package/dist/{lightning-backend-BhsyrBLa.d.ts → lightning-backend-BaeCPmx7.d.ts} +1 -1
- package/dist/{memory-credit-ledger-2LBZVMKJ.js → memory-credit-ledger-W2BAUYJP.js} +4 -2
- package/dist/{mpp-setup-7CGBKNUP.js → mpp-setup-RF5FXGGV.js} +5 -1
- package/dist/{payout-reporter-ZMOA37GN.js → payout-reporter-3Y2U55ZX.js} +1 -1
- package/dist/{postgres-job-store-MSD2HZOI.js → postgres-job-store-VLXLWXUQ.js} +1 -1
- package/dist/{revenue-reporter-EKJOGQYR.js → revenue-reporter-MAERPYGK.js} +1 -1
- package/dist/server/index.d.ts +14 -10
- package/dist/server/index.js +54 -17
- package/dist/{step-cache-v2yhyhSZ.d.ts → step-cache-Bi43A0JN.d.ts} +1769 -1549
- package/dist/{tempo-charge-store-4WX7FPOV.js → tempo-charge-store-Q3D7KYMH.js} +1 -1
- package/dist/tempo-lifecycle-OTHV757Y.js +14 -0
- package/dist/{tempo-session-store-LCSDHB7G.js → tempo-session-store-ZRNCOX7P.js} +1 -1
- package/dist/{tempo-wallet-RCGBBAJH.js → tempo-wallet-32JWQZKQ.js} +4 -3
- package/dist/testing/index.d.ts +3 -3
- package/dist/{usd-Cu9G6xv2.d.ts → usd-AZPVq4eU.d.ts} +1 -1
- package/dist/{x402-S47Q77UE.js → x402-CEDHGZDI.js} +17 -14
- package/package.json +1 -1
- package/dist/chunk-YHN3WMMF.js +0 -122
- package/dist/tempo-lifecycle-TJ62A7UX.js +0 -13
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
IMPLICIT_CREDIT_TTL_MS
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-3MHE725Z.js";
|
|
4
4
|
import {
|
|
5
5
|
CREDITS_FILE,
|
|
6
|
-
DvmError,
|
|
7
6
|
ensureConfigDir
|
|
8
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-CZULM42S.js";
|
|
8
|
+
import {
|
|
9
|
+
DvmError
|
|
10
|
+
} from "./chunk-LIRAHP7B.js";
|
|
9
11
|
|
|
10
12
|
// src/lib/output.ts
|
|
11
13
|
import { writeSync } from "fs";
|
|
@@ -2,22 +2,24 @@ import {
|
|
|
2
2
|
costAnchor,
|
|
3
3
|
formatUsd,
|
|
4
4
|
msatsToUsd
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-3MHE725Z.js";
|
|
6
6
|
import {
|
|
7
7
|
AGENT_MNEMONIC_FILE,
|
|
8
8
|
BUILDER_CONFIG_DIR,
|
|
9
9
|
BUILDER_FILE,
|
|
10
10
|
BUILDER_KEY_FILE,
|
|
11
|
-
DvmError,
|
|
12
11
|
WALLET_FILE,
|
|
13
12
|
ensureConfigDir
|
|
14
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-CZULM42S.js";
|
|
15
14
|
import {
|
|
16
15
|
canonicaliseForSigning
|
|
17
16
|
} from "./chunk-KXZUCCEY.js";
|
|
18
17
|
import {
|
|
19
18
|
callerLoggers
|
|
20
19
|
} from "./chunk-66HGCPBU.js";
|
|
20
|
+
import {
|
|
21
|
+
DvmError
|
|
22
|
+
} from "./chunk-LIRAHP7B.js";
|
|
21
23
|
import {
|
|
22
24
|
diagnosticConsole
|
|
23
25
|
} from "./chunk-ETXDTUJO.js";
|
|
@@ -2,16 +2,18 @@ import {
|
|
|
2
2
|
isValidEvmPrivateKey,
|
|
3
3
|
loadConfig,
|
|
4
4
|
updateConfig
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-MZRJR2CW.js";
|
|
6
6
|
import {
|
|
7
|
-
DvmError,
|
|
8
7
|
resolveRpcHttpTransportOptions,
|
|
9
8
|
resolveRpcOverride
|
|
10
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-CZULM42S.js";
|
|
11
10
|
import {
|
|
12
11
|
redactUrl,
|
|
13
12
|
redactUrlsInText
|
|
14
13
|
} from "./chunk-FUJ36YDV.js";
|
|
14
|
+
import {
|
|
15
|
+
DvmError
|
|
16
|
+
} from "./chunk-LIRAHP7B.js";
|
|
15
17
|
|
|
16
18
|
// src/lib/payment-rails/tempo-wallet.ts
|
|
17
19
|
var TEMPO_USDC_MAINNET = "0x20C000000000000000000000b9537d11c60E8b50";
|
|
@@ -101,7 +103,7 @@ async function generateTempoKey(opts = {}) {
|
|
|
101
103
|
);
|
|
102
104
|
}
|
|
103
105
|
if (existing && opts.force) {
|
|
104
|
-
const { assertTempoWalletIdle } = await import("./tempo-lifecycle-
|
|
106
|
+
const { assertTempoWalletIdle } = await import("./tempo-lifecycle-OTHV757Y.js");
|
|
105
107
|
await assertTempoWalletIdle("replace");
|
|
106
108
|
}
|
|
107
109
|
const { privateKeyToAccount, generatePrivateKey } = await import("viem/accounts");
|
|
@@ -1,50 +1,3 @@
|
|
|
1
|
-
// src/lib/errors.ts
|
|
2
|
-
var DvmError = class extends Error {
|
|
3
|
-
constructor(code, message, hint, data, display, proseSources) {
|
|
4
|
-
super(message);
|
|
5
|
-
this.code = code;
|
|
6
|
-
this.hint = hint;
|
|
7
|
-
this.data = data;
|
|
8
|
-
this.display = display;
|
|
9
|
-
this.proseSources = proseSources;
|
|
10
|
-
this.name = "DvmError";
|
|
11
|
-
}
|
|
12
|
-
code;
|
|
13
|
-
hint;
|
|
14
|
-
data;
|
|
15
|
-
display;
|
|
16
|
-
proseSources;
|
|
17
|
-
};
|
|
18
|
-
function providerProseSources(...sources) {
|
|
19
|
-
const provenance = {};
|
|
20
|
-
for (const source of sources) {
|
|
21
|
-
if (!source) continue;
|
|
22
|
-
for (const field of ["message", "hint", "display"]) {
|
|
23
|
-
if (typeof source[field] === "string") provenance[field] = "provider";
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
return Object.keys(provenance).length > 0 ? provenance : void 0;
|
|
27
|
-
}
|
|
28
|
-
function isAbortError(err) {
|
|
29
|
-
return err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError");
|
|
30
|
-
}
|
|
31
|
-
function transportErrorCode(err) {
|
|
32
|
-
let current = err;
|
|
33
|
-
const seen = /* @__PURE__ */ new Set();
|
|
34
|
-
for (let depth = 0; depth < 5 && isErrorLike(current) && !seen.has(current); depth++) {
|
|
35
|
-
seen.add(current);
|
|
36
|
-
const code = current.code;
|
|
37
|
-
if (typeof code === "string" && /^(?:E[A-Z0-9_]{1,63}|UND_ERR_[A-Z0-9_]{1,63})$/.test(code)) {
|
|
38
|
-
return code;
|
|
39
|
-
}
|
|
40
|
-
current = current.cause;
|
|
41
|
-
}
|
|
42
|
-
return void 0;
|
|
43
|
-
}
|
|
44
|
-
function isErrorLike(value) {
|
|
45
|
-
return (typeof value === "object" || typeof value === "function") && value !== null;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
1
|
// src/defaults.ts
|
|
49
2
|
import { homedir } from "os";
|
|
50
3
|
import { join } from "path";
|
|
@@ -158,10 +111,6 @@ function resolveRpcHttpTransportOptions(source, envValue) {
|
|
|
158
111
|
}
|
|
159
112
|
|
|
160
113
|
export {
|
|
161
|
-
DvmError,
|
|
162
|
-
providerProseSources,
|
|
163
|
-
isAbortError,
|
|
164
|
-
transportErrorCode,
|
|
165
114
|
CONFIG_DIR,
|
|
166
115
|
CONFIG_FILE,
|
|
167
116
|
CONFIG_BACKUP_FILE,
|
|
@@ -52,9 +52,13 @@ var PostgresX402BatchStore = class {
|
|
|
52
52
|
first_failed_at BIGINT,
|
|
53
53
|
last_error TEXT,
|
|
54
54
|
next_retry_at BIGINT,
|
|
55
|
+
obligation_ids JSONB NOT NULL DEFAULT '[]'::jsonb,
|
|
55
56
|
updated_at BIGINT NOT NULL
|
|
56
57
|
)
|
|
57
58
|
`);
|
|
59
|
+
await this.db.query(
|
|
60
|
+
"ALTER TABLE payout_x402_batches ADD COLUMN IF NOT EXISTS obligation_ids JSONB NOT NULL DEFAULT '[]'::jsonb"
|
|
61
|
+
);
|
|
58
62
|
});
|
|
59
63
|
}
|
|
60
64
|
async get(scope) {
|
|
@@ -71,15 +75,16 @@ var PostgresX402BatchStore = class {
|
|
|
71
75
|
attempts: row.attempts,
|
|
72
76
|
firstFailedAt: row.first_failed_at === null ? null : Number(row.first_failed_at),
|
|
73
77
|
lastError: row.last_error,
|
|
74
|
-
nextRetryAt: row.next_retry_at === null ? null : Number(row.next_retry_at)
|
|
78
|
+
nextRetryAt: row.next_retry_at === null ? null : Number(row.next_retry_at),
|
|
79
|
+
...row.obligation_ids.length ? { obligationIds: row.obligation_ids } : {}
|
|
75
80
|
};
|
|
76
81
|
}
|
|
77
82
|
async put(batch) {
|
|
78
83
|
await this.db.query(
|
|
79
84
|
`INSERT INTO payout_x402_batches (
|
|
80
85
|
scope, batch_id, claimed_native, voucher_count, claims, opened_at,
|
|
81
|
-
attempts, first_failed_at, last_error, next_retry_at, updated_at
|
|
82
|
-
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
|
86
|
+
attempts, first_failed_at, last_error, next_retry_at, obligation_ids, updated_at
|
|
87
|
+
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
|
|
83
88
|
ON CONFLICT (scope) DO UPDATE SET
|
|
84
89
|
batch_id = EXCLUDED.batch_id,
|
|
85
90
|
claimed_native = EXCLUDED.claimed_native,
|
|
@@ -90,6 +95,7 @@ var PostgresX402BatchStore = class {
|
|
|
90
95
|
first_failed_at = EXCLUDED.first_failed_at,
|
|
91
96
|
last_error = EXCLUDED.last_error,
|
|
92
97
|
next_retry_at = EXCLUDED.next_retry_at,
|
|
98
|
+
obligation_ids = EXCLUDED.obligation_ids,
|
|
93
99
|
updated_at = EXCLUDED.updated_at`,
|
|
94
100
|
[
|
|
95
101
|
batch.scope,
|
|
@@ -102,6 +108,7 @@ var PostgresX402BatchStore = class {
|
|
|
102
108
|
batch.firstFailedAt,
|
|
103
109
|
batch.lastError,
|
|
104
110
|
batch.nextRetryAt,
|
|
111
|
+
JSON.stringify(batch.obligationIds ?? []),
|
|
105
112
|
Date.now()
|
|
106
113
|
]
|
|
107
114
|
);
|
|
@@ -142,6 +149,7 @@ var PayoutReporter = class {
|
|
|
142
149
|
ownsBatchStore;
|
|
143
150
|
intervalMs;
|
|
144
151
|
now;
|
|
152
|
+
hostedObligations;
|
|
145
153
|
lastX402SnapshotAt = 0;
|
|
146
154
|
x402;
|
|
147
155
|
tempo;
|
|
@@ -156,6 +164,7 @@ var PayoutReporter = class {
|
|
|
156
164
|
this.batches = opts.batchStore ?? (opts.db ? new PostgresX402BatchStore(opts.db) : new MemoryX402BatchStore());
|
|
157
165
|
this.intervalMs = opts.snapshotIntervalMs ?? PAYOUT_SNAPSHOT_INTERVAL_MS;
|
|
158
166
|
this.now = opts.now ?? Date.now;
|
|
167
|
+
this.hostedObligations = opts.hostedObligations;
|
|
159
168
|
}
|
|
160
169
|
async init() {
|
|
161
170
|
if (this.ownsBatchStore && this.batches instanceof PostgresX402BatchStore) {
|
|
@@ -171,10 +180,12 @@ var PayoutReporter = class {
|
|
|
171
180
|
if (this.timer) return;
|
|
172
181
|
this.warmup = setTimeout(() => {
|
|
173
182
|
void this.snapshot();
|
|
183
|
+
void this.reconcileHosted();
|
|
174
184
|
}, WARMUP_MS);
|
|
175
185
|
this.warmup.unref();
|
|
176
186
|
this.timer = setInterval(() => {
|
|
177
187
|
void this.snapshot();
|
|
188
|
+
void this.reconcileHosted();
|
|
178
189
|
}, this.intervalMs);
|
|
179
190
|
this.timer.unref();
|
|
180
191
|
}
|
|
@@ -184,6 +195,45 @@ var PayoutReporter = class {
|
|
|
184
195
|
if (this.timer) clearInterval(this.timer);
|
|
185
196
|
this.timer = null;
|
|
186
197
|
}
|
|
198
|
+
async reconcileHosted() {
|
|
199
|
+
if (!this.hostedObligations) return;
|
|
200
|
+
try {
|
|
201
|
+
for (const failure of await this.hostedObligations.recoverOriginalX402Refunds()) {
|
|
202
|
+
warn("hosted_refund_recovery_pending", { id: failure.id, error: message(failure.error) });
|
|
203
|
+
}
|
|
204
|
+
for (const candidate of await this.hostedObligations.recoveryCandidates()) {
|
|
205
|
+
if (candidate.blockHash) continue;
|
|
206
|
+
try {
|
|
207
|
+
await this.hostedObligations.observeCanonical(candidate.id);
|
|
208
|
+
} catch (error) {
|
|
209
|
+
warn("hosted_effect_observation_pending", { id: candidate.id, error: message(error) });
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
for (const failure of await this.hostedObligations.reconcileX402Batches()) {
|
|
213
|
+
warn("hosted_batch_recovery_pending", { id: failure.id, error: message(failure.error) });
|
|
214
|
+
}
|
|
215
|
+
for (const candidate of await this.hostedObligations.recoveryCandidates()) {
|
|
216
|
+
if (!candidate.blockHash || candidate.reportId) continue;
|
|
217
|
+
try {
|
|
218
|
+
if (candidate.rail === "tempo" && (candidate.operation === "settle" || candidate.operation === "close") && candidate.deltaNative !== null && BigInt(candidate.deltaNative) > 0n) {
|
|
219
|
+
await this.tempoSettled({
|
|
220
|
+
txHash: candidate.txHash,
|
|
221
|
+
channelId: candidate.channelId,
|
|
222
|
+
trigger: candidate.operation,
|
|
223
|
+
amount: BigInt(candidate.deltaNative),
|
|
224
|
+
delta: BigInt(candidate.deltaNative)
|
|
225
|
+
});
|
|
226
|
+
} else if (candidate.rail === "x402" && candidate.operation === "settle" && this.x402) {
|
|
227
|
+
await this.recordX402Settle(this.x402, candidate.txHash);
|
|
228
|
+
}
|
|
229
|
+
} catch (error) {
|
|
230
|
+
warn("hosted_effect_report_pending", { id: candidate.id, error: message(error) });
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
} catch (error) {
|
|
234
|
+
warn("hosted_effect_recovery_pending", { error: message(error) });
|
|
235
|
+
}
|
|
236
|
+
}
|
|
187
237
|
enqueuePayout(payload, tx) {
|
|
188
238
|
return this.transport.enqueuePayout(payload, tx);
|
|
189
239
|
}
|
|
@@ -263,8 +313,24 @@ var PayoutReporter = class {
|
|
|
263
313
|
*/
|
|
264
314
|
async tempoSettled(event) {
|
|
265
315
|
try {
|
|
316
|
+
let hostedIds;
|
|
317
|
+
if (this.hostedObligations) {
|
|
318
|
+
hostedIds = await this.hostedObligations.submittedIds(
|
|
319
|
+
"tempo",
|
|
320
|
+
event.trigger === "close" ? "close" : "settle",
|
|
321
|
+
event.txHash
|
|
322
|
+
);
|
|
323
|
+
if (hostedIds.length === 1) {
|
|
324
|
+
const observed = await this.hostedObligations.observeCanonical(hostedIds[0]);
|
|
325
|
+
if (BigInt(observed.deltaNative) !== event.delta) {
|
|
326
|
+
throw new Error("Hosted Tempo callback differs from finalized settlement amount");
|
|
327
|
+
}
|
|
328
|
+
} else if (await this.hostedObligations.hasCompleteHistory()) {
|
|
329
|
+
throw new Error("Hosted Tempo payout has no exact original settlement obligation");
|
|
330
|
+
}
|
|
331
|
+
}
|
|
266
332
|
if (event.delta <= 0n) return;
|
|
267
|
-
|
|
333
|
+
const payload = {
|
|
268
334
|
dvmId: this.dvmId,
|
|
269
335
|
payoutId: `tempo:${event.txHash}`,
|
|
270
336
|
rail: "tempo",
|
|
@@ -279,9 +345,23 @@ var PayoutReporter = class {
|
|
|
279
345
|
...this.tempo?.network ? { network: this.tempo.network } : {}
|
|
280
346
|
},
|
|
281
347
|
landedAt: this.now()
|
|
282
|
-
}
|
|
348
|
+
};
|
|
349
|
+
if (this.hostedObligations) {
|
|
350
|
+
if (hostedIds?.length !== 1 || !this.transport.enqueueHostedPayout) {
|
|
351
|
+
if (await this.hostedObligations.hasCompleteHistory()) {
|
|
352
|
+
throw new Error("Hosted Tempo payout has no exact original settlement obligation");
|
|
353
|
+
}
|
|
354
|
+
await this.reportPayout(payload);
|
|
355
|
+
} else {
|
|
356
|
+
await this.transport.enqueueHostedPayout(payload, hostedIds);
|
|
357
|
+
void this.flush();
|
|
358
|
+
}
|
|
359
|
+
} else {
|
|
360
|
+
await this.reportPayout(payload);
|
|
361
|
+
}
|
|
283
362
|
} catch (err) {
|
|
284
363
|
warn("payout_report_failed", { rail: "tempo", kind: event.trigger, error: message(err) });
|
|
364
|
+
if (this.hostedObligations) throw err;
|
|
285
365
|
}
|
|
286
366
|
void this.snapshotTempo();
|
|
287
367
|
}
|
|
@@ -300,29 +380,49 @@ var PayoutReporter = class {
|
|
|
300
380
|
* this does not report the caller refund.
|
|
301
381
|
*/
|
|
302
382
|
async tempoCloseReconciled(event, tx) {
|
|
303
|
-
|
|
383
|
+
let settled = BigInt(event.settledToPayee);
|
|
384
|
+
let hostedIds;
|
|
385
|
+
if (this.hostedObligations) {
|
|
386
|
+
hostedIds = await this.hostedObligations.submittedIds("tempo", "close", event.txHash);
|
|
387
|
+
if (hostedIds.length === 1) {
|
|
388
|
+
const alreadySettled = await this.hostedObligations.originalTempoCloseSettled(
|
|
389
|
+
hostedIds[0],
|
|
390
|
+
event.channelId,
|
|
391
|
+
event.txHash
|
|
392
|
+
);
|
|
393
|
+
settled -= alreadySettled;
|
|
394
|
+
if (settled < 0n) throw new Error("Hosted Tempo repair precedes its original settled amount");
|
|
395
|
+
} else if (await this.hostedObligations.hasCompleteHistory(tx)) {
|
|
396
|
+
throw new Error("Hosted Tempo repair has no original close obligation");
|
|
397
|
+
}
|
|
398
|
+
}
|
|
304
399
|
if (settled <= 0n) return;
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
...this.tempo?.network ? { network: this.tempo.network } : {}
|
|
319
|
-
},
|
|
320
|
-
landedAt: this.now(),
|
|
321
|
-
repaired: true,
|
|
322
|
-
repairKind: "tempo_close_reconciled"
|
|
400
|
+
const payload = {
|
|
401
|
+
dvmId: this.dvmId,
|
|
402
|
+
payoutId: `tempo:${event.txHash}`,
|
|
403
|
+
rail: "tempo",
|
|
404
|
+
kind: "close",
|
|
405
|
+
nativeAmount: Number(settled),
|
|
406
|
+
nativeAsset: "usdc",
|
|
407
|
+
recipient: this.tempo?.recipient ?? null,
|
|
408
|
+
refs: {
|
|
409
|
+
channelId: event.channelId,
|
|
410
|
+
txHash: event.txHash,
|
|
411
|
+
trigger: "close",
|
|
412
|
+
...this.tempo?.network ? { network: this.tempo.network } : {}
|
|
323
413
|
},
|
|
324
|
-
|
|
325
|
-
|
|
414
|
+
landedAt: this.now(),
|
|
415
|
+
repaired: true,
|
|
416
|
+
repairKind: "tempo_close_reconciled"
|
|
417
|
+
};
|
|
418
|
+
if (hostedIds?.length === 1) {
|
|
419
|
+
if (!this.transport.enqueueHostedPayout) {
|
|
420
|
+
throw new Error("Hosted Tempo repair lacks its durable report queue");
|
|
421
|
+
}
|
|
422
|
+
await this.transport.enqueueHostedPayout(payload, hostedIds, tx);
|
|
423
|
+
} else {
|
|
424
|
+
await this.enqueuePayout(payload, tx);
|
|
425
|
+
}
|
|
326
426
|
if (!tx) {
|
|
327
427
|
void this.flush();
|
|
328
428
|
void this.snapshotTempo();
|
|
@@ -343,6 +443,17 @@ var PayoutReporter = class {
|
|
|
343
443
|
const ctx = this.x402;
|
|
344
444
|
if (ctx) await this.recordX402SettleFailure(ctx, error);
|
|
345
445
|
void this.snapshotX402();
|
|
446
|
+
},
|
|
447
|
+
recordRefundClaim: async (transaction, delta) => {
|
|
448
|
+
const ctx = this.x402;
|
|
449
|
+
if (!ctx) throw new Error("Hosted x402 refund has no payout context");
|
|
450
|
+
await this.recordX402Claim(ctx, {
|
|
451
|
+
delta,
|
|
452
|
+
vouchers: 1,
|
|
453
|
+
transactions: [transaction],
|
|
454
|
+
operation: "refund"
|
|
455
|
+
});
|
|
456
|
+
void this.snapshotX402();
|
|
346
457
|
}
|
|
347
458
|
};
|
|
348
459
|
}
|
|
@@ -370,7 +481,8 @@ var PayoutReporter = class {
|
|
|
370
481
|
}
|
|
371
482
|
await this.recordX402Claim(ctx, {
|
|
372
483
|
delta,
|
|
373
|
-
vouchers: results.reduce((sum, r) => sum + r.vouchers, 0)
|
|
484
|
+
vouchers: results.reduce((sum, r) => sum + r.vouchers, 0),
|
|
485
|
+
transactions: results.map((result) => result.transaction)
|
|
374
486
|
});
|
|
375
487
|
void this.snapshotX402();
|
|
376
488
|
}
|
|
@@ -389,10 +501,32 @@ var PayoutReporter = class {
|
|
|
389
501
|
throw err;
|
|
390
502
|
}
|
|
391
503
|
};
|
|
504
|
+
const refund = async (channelIds) => {
|
|
505
|
+
const ctx = this.x402;
|
|
506
|
+
const before = ctx ? await claimedByChannel(ctx.storage) : /* @__PURE__ */ new Map();
|
|
507
|
+
const results = await manager.refund(channelIds);
|
|
508
|
+
if (ctx && this.hostedObligations) {
|
|
509
|
+
for (const result of results) {
|
|
510
|
+
const original = before.get(result.channel.toLowerCase());
|
|
511
|
+
if (!original) throw new Error("Hosted x402 refund lost its original channel snapshot");
|
|
512
|
+
const delta = original.charged - original.claimed;
|
|
513
|
+
if (delta > 0n) {
|
|
514
|
+
await this.recordX402Claim(ctx, {
|
|
515
|
+
delta,
|
|
516
|
+
vouchers: 1,
|
|
517
|
+
transactions: [result.transaction],
|
|
518
|
+
operation: "refund"
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
return results;
|
|
524
|
+
};
|
|
392
525
|
return new Proxy(manager, {
|
|
393
526
|
get(target, prop, receiver) {
|
|
394
527
|
if (prop === "claim") return claim;
|
|
395
528
|
if (prop === "settle") return settle;
|
|
529
|
+
if (prop === "refund" && target.refund) return refund;
|
|
396
530
|
const value = Reflect.get(target, prop, receiver);
|
|
397
531
|
return typeof value === "function" ? value.bind(target) : value;
|
|
398
532
|
}
|
|
@@ -401,7 +535,11 @@ var PayoutReporter = class {
|
|
|
401
535
|
async recordX402Claim(ctx, claim) {
|
|
402
536
|
try {
|
|
403
537
|
const now = this.now();
|
|
404
|
-
const
|
|
538
|
+
const existing = await this.batches.get(ctx.scope);
|
|
539
|
+
if (this.hostedObligations && !existing) {
|
|
540
|
+
throw new Error("Hosted x402 claim lost its pre-effect payout batch");
|
|
541
|
+
}
|
|
542
|
+
const open = existing ?? {
|
|
405
543
|
scope: ctx.scope,
|
|
406
544
|
batchId: randomUUID(),
|
|
407
545
|
claimedNative: 0n,
|
|
@@ -416,9 +554,22 @@ var PayoutReporter = class {
|
|
|
416
554
|
open.claimedNative += claim.delta;
|
|
417
555
|
open.voucherCount += claim.vouchers;
|
|
418
556
|
open.claims += 1;
|
|
557
|
+
if (this.hostedObligations) {
|
|
558
|
+
const ids = (await Promise.all(claim.transactions.map((txHash) => this.hostedObligations.submittedIds(
|
|
559
|
+
"x402",
|
|
560
|
+
claim.operation ?? "claim",
|
|
561
|
+
txHash,
|
|
562
|
+
open.batchId
|
|
563
|
+
)))).flat();
|
|
564
|
+
if (!ids.length || ids.length < claim.vouchers || new Set(ids).size !== ids.length) {
|
|
565
|
+
throw new Error("Hosted x402 claim has no exact reserved voucher set");
|
|
566
|
+
}
|
|
567
|
+
open.obligationIds = [.../* @__PURE__ */ new Set([...open.obligationIds ?? [], ...ids])];
|
|
568
|
+
}
|
|
419
569
|
await this.batches.put(open);
|
|
420
570
|
} catch (err) {
|
|
421
571
|
warn("payout_batch_track_failed", { scope: ctx.scope, error: message(err) });
|
|
572
|
+
if (this.hostedObligations) throw err;
|
|
422
573
|
}
|
|
423
574
|
}
|
|
424
575
|
async recordX402Settle(ctx, transaction) {
|
|
@@ -433,6 +584,23 @@ var PayoutReporter = class {
|
|
|
433
584
|
warn("payout_batch_empty", { scope: ctx.scope, transaction, batchId: open.batchId });
|
|
434
585
|
return;
|
|
435
586
|
}
|
|
587
|
+
if (this.hostedObligations) {
|
|
588
|
+
if (!open.obligationIds?.length) {
|
|
589
|
+
throw new Error("Hosted x402 payout has no original claim identities");
|
|
590
|
+
}
|
|
591
|
+
const settleId = await this.hostedObligations.settlementId(open.batchId, transaction);
|
|
592
|
+
const settled = await this.hostedObligations.observeCanonical(settleId);
|
|
593
|
+
if (BigInt(settled.deltaNative) !== open.claimedNative) {
|
|
594
|
+
throw new Error("Hosted x402 settled amount differs from its original batch");
|
|
595
|
+
}
|
|
596
|
+
let claimed = 0n;
|
|
597
|
+
for (const id of open.obligationIds) {
|
|
598
|
+
claimed += BigInt((await this.hostedObligations.observeCanonical(id)).deltaNative);
|
|
599
|
+
}
|
|
600
|
+
if (claimed !== open.claimedNative) {
|
|
601
|
+
throw new Error("Hosted x402 batch amount differs from finalized original claims");
|
|
602
|
+
}
|
|
603
|
+
}
|
|
436
604
|
const payload = {
|
|
437
605
|
dvmId: this.dvmId,
|
|
438
606
|
payoutId: `x402:batch:${open.batchId}`,
|
|
@@ -450,17 +618,25 @@ var PayoutReporter = class {
|
|
|
450
618
|
},
|
|
451
619
|
landedAt: this.now()
|
|
452
620
|
};
|
|
453
|
-
const closed = await this.batches.settle(
|
|
454
|
-
|
|
455
|
-
open.
|
|
456
|
-
|
|
457
|
-
|
|
621
|
+
const closed = await this.batches.settle(ctx.scope, open.batchId, async (tx) => {
|
|
622
|
+
if (!this.hostedObligations) return this.enqueuePayout(payload, tx);
|
|
623
|
+
if (!this.transport.enqueueHostedPayout || !open.obligationIds?.length) {
|
|
624
|
+
throw new Error("Hosted x402 payout lacks its original claims or durable queue");
|
|
625
|
+
}
|
|
626
|
+
const settleId = await this.hostedObligations.settlementId(open.batchId, transaction);
|
|
627
|
+
await this.transport.enqueueHostedPayout(
|
|
628
|
+
payload,
|
|
629
|
+
[...open.obligationIds, settleId],
|
|
630
|
+
tx
|
|
631
|
+
);
|
|
632
|
+
});
|
|
458
633
|
if (!closed) {
|
|
459
634
|
warn("payout_batch_raced", { scope: ctx.scope, transaction, batchId: open.batchId });
|
|
460
635
|
return;
|
|
461
636
|
}
|
|
462
637
|
} catch (err) {
|
|
463
638
|
warn("payout_report_failed", { rail: "x402", kind: "batch", error: message(err) });
|
|
639
|
+
if (this.hostedObligations) throw err;
|
|
464
640
|
return;
|
|
465
641
|
}
|
|
466
642
|
void this.flush();
|
|
@@ -1,106 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
x402NetworkByCaip2,
|
|
3
|
+
x402NetworkBySlug
|
|
4
|
+
} from "./chunk-RLTSCKRI.js";
|
|
4
5
|
|
|
5
6
|
// src/lib/x402/constants.ts
|
|
6
7
|
var X402_DEFAULT_FACILITATOR = "https://x402.org/facilitator";
|
|
7
8
|
|
|
8
|
-
// src/lib/x402/networks.ts
|
|
9
|
-
var X402_NETWORKS = [
|
|
10
|
-
{
|
|
11
|
-
caip2: "eip155:8453",
|
|
12
|
-
slug: "base",
|
|
13
|
-
label: "Base",
|
|
14
|
-
usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
15
|
-
domainName: "USD Coin",
|
|
16
|
-
domainVersion: "2",
|
|
17
|
-
viemChain: "base",
|
|
18
|
-
nativeGas: "ETH",
|
|
19
|
-
confusable: "USDbC"
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
caip2: "eip155:84532",
|
|
23
|
-
slug: "base-sepolia",
|
|
24
|
-
label: "Base Sepolia",
|
|
25
|
-
usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
26
|
-
domainName: "USDC",
|
|
27
|
-
domainVersion: "2",
|
|
28
|
-
viemChain: "baseSepolia",
|
|
29
|
-
nativeGas: "ETH",
|
|
30
|
-
confusable: null
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
caip2: "eip155:43114",
|
|
34
|
-
slug: "avalanche",
|
|
35
|
-
label: "Avalanche",
|
|
36
|
-
usdc: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
|
|
37
|
-
domainName: "USD Coin",
|
|
38
|
-
domainVersion: "2",
|
|
39
|
-
viemChain: "avalanche",
|
|
40
|
-
nativeGas: "AVAX",
|
|
41
|
-
confusable: "USDC.e"
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
caip2: "eip155:43113",
|
|
45
|
-
slug: "avalanche-fuji",
|
|
46
|
-
label: "Avalanche Fuji",
|
|
47
|
-
usdc: "0x5425890298aed601595a70AB815c96711a31Bc65",
|
|
48
|
-
domainName: "USD Coin",
|
|
49
|
-
domainVersion: "2",
|
|
50
|
-
viemChain: "avalancheFuji",
|
|
51
|
-
nativeGas: "AVAX",
|
|
52
|
-
confusable: null
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
caip2: "eip155:137",
|
|
56
|
-
slug: "polygon",
|
|
57
|
-
label: "Polygon",
|
|
58
|
-
usdc: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
|
|
59
|
-
domainName: "USD Coin (PoS)",
|
|
60
|
-
domainVersion: "2",
|
|
61
|
-
viemChain: "polygon",
|
|
62
|
-
nativeGas: "POL",
|
|
63
|
-
confusable: "USDC.e"
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
caip2: "eip155:80002",
|
|
67
|
-
slug: "polygon-amoy",
|
|
68
|
-
label: "Polygon Amoy",
|
|
69
|
-
usdc: "0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582",
|
|
70
|
-
domainName: "USDC",
|
|
71
|
-
domainVersion: "2",
|
|
72
|
-
viemChain: "polygonAmoy",
|
|
73
|
-
nativeGas: "POL",
|
|
74
|
-
confusable: null
|
|
75
|
-
}
|
|
76
|
-
];
|
|
77
|
-
function x402NetworkByCaip2(caip2) {
|
|
78
|
-
return BY_CAIP2.get(caip2);
|
|
79
|
-
}
|
|
80
|
-
function x402NetworkBySlug(slug) {
|
|
81
|
-
return BY_SLUG.get(slug);
|
|
82
|
-
}
|
|
83
|
-
function x402NetworkLabel(network) {
|
|
84
|
-
const spec = x402NetworkByCaip2(network);
|
|
85
|
-
return spec ? `${spec.label} (${network})` : network;
|
|
86
|
-
}
|
|
87
|
-
function x402NetworkListForCopy() {
|
|
88
|
-
return X402_NETWORKS.map((n) => `${n.caip2} (${n.label})`).join(", ");
|
|
89
|
-
}
|
|
90
|
-
function assertSupportedX402Network(network) {
|
|
91
|
-
if (x402NetworkByCaip2(network)) return;
|
|
92
|
-
throw new DvmError(
|
|
93
|
-
"unsupported_network",
|
|
94
|
-
`Unsupported x402 network: ${network}.`,
|
|
95
|
-
`${x402SupportedNetworksHint()} If a wallet is connected, run 'dvm wallet x402-network <caip2>'. For a first connection, pass --network to 'dvm wallet x402-connect'.`
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
function x402SupportedNetworksHint() {
|
|
99
|
-
return `This rail settles native USDC on: ${x402NetworkListForCopy()}.`;
|
|
100
|
-
}
|
|
101
|
-
var BY_CAIP2 = new Map(X402_NETWORKS.map((n) => [n.caip2, n]));
|
|
102
|
-
var BY_SLUG = new Map(X402_NETWORKS.map((n) => [n.slug, n]));
|
|
103
|
-
|
|
104
9
|
// src/lib/x402/spec.ts
|
|
105
10
|
var X402_VERSION = 2;
|
|
106
11
|
var X402_V1_VERSION = 1;
|
|
@@ -301,13 +206,6 @@ function isOptionalRecord(value) {
|
|
|
301
206
|
|
|
302
207
|
export {
|
|
303
208
|
X402_DEFAULT_FACILITATOR,
|
|
304
|
-
X402_NETWORKS,
|
|
305
|
-
x402NetworkByCaip2,
|
|
306
|
-
x402NetworkBySlug,
|
|
307
|
-
x402NetworkLabel,
|
|
308
|
-
x402NetworkListForCopy,
|
|
309
|
-
assertSupportedX402Network,
|
|
310
|
-
x402SupportedNetworksHint,
|
|
311
209
|
X402_VERSION,
|
|
312
210
|
X402_V1_VERSION,
|
|
313
211
|
X402_DEFAULT_NETWORK,
|