@rozoai/checkout 0.1.16 → 0.1.17
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 +36 -0
- package/package.json +1 -1
- package/scripts/dist/cli.js +503 -83
- package/scripts/dist/create-order.js +321 -186
- package/scripts/dist/receipt.js +53 -53
- package/scripts/dist/resume.js +1486 -0
- package/scripts/dist/send-evm.js +202 -202
- package/scripts/dist/send-sol.js +202 -202
- package/scripts/dist/status.js +53 -53
package/scripts/dist/send-evm.js
CHANGED
|
@@ -21917,6 +21917,199 @@ function getJson(url, opts) {
|
|
|
21917
21917
|
return request("GET", url, opts);
|
|
21918
21918
|
}
|
|
21919
21919
|
|
|
21920
|
+
// scripts/src/lib/state.mjs
|
|
21921
|
+
import fs4 from "node:fs";
|
|
21922
|
+
import path4 from "node:path";
|
|
21923
|
+
import os3 from "node:os";
|
|
21924
|
+
import crypto5 from "node:crypto";
|
|
21925
|
+
var LOCK_STALE_MS = 6e4;
|
|
21926
|
+
var LOCK_WAIT_MS = 1e4;
|
|
21927
|
+
var LOCK_POLL_MS = 25;
|
|
21928
|
+
function lockPath() {
|
|
21929
|
+
return path4.join(stateRoot(), ".send.lock");
|
|
21930
|
+
}
|
|
21931
|
+
function sleepSync(ms) {
|
|
21932
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
21933
|
+
}
|
|
21934
|
+
function tryAcquire(file) {
|
|
21935
|
+
try {
|
|
21936
|
+
const fd = fs4.openSync(file, "wx", 384);
|
|
21937
|
+
fs4.writeFileSync(fd, JSON.stringify({ pid: process.pid, at: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
21938
|
+
fs4.closeSync(fd);
|
|
21939
|
+
return true;
|
|
21940
|
+
} catch (err) {
|
|
21941
|
+
if (err.code !== "EEXIST") throw err;
|
|
21942
|
+
return false;
|
|
21943
|
+
}
|
|
21944
|
+
}
|
|
21945
|
+
function withLock(fn) {
|
|
21946
|
+
const file = lockPath();
|
|
21947
|
+
fs4.mkdirSync(path4.dirname(file), { recursive: true, mode: 448 });
|
|
21948
|
+
const deadline = Date.now() + LOCK_WAIT_MS;
|
|
21949
|
+
for (; ; ) {
|
|
21950
|
+
if (tryAcquire(file)) break;
|
|
21951
|
+
try {
|
|
21952
|
+
const age = Date.now() - fs4.statSync(file).mtimeMs;
|
|
21953
|
+
if (age > LOCK_STALE_MS) {
|
|
21954
|
+
const stolen = `${file}.stale.${crypto5.randomBytes(4).toString("hex")}`;
|
|
21955
|
+
try {
|
|
21956
|
+
fs4.renameSync(file, stolen);
|
|
21957
|
+
fs4.unlinkSync(stolen);
|
|
21958
|
+
} catch {
|
|
21959
|
+
}
|
|
21960
|
+
continue;
|
|
21961
|
+
}
|
|
21962
|
+
} catch (err) {
|
|
21963
|
+
if (err.code !== "ENOENT") throw err;
|
|
21964
|
+
continue;
|
|
21965
|
+
}
|
|
21966
|
+
if (Date.now() > deadline) {
|
|
21967
|
+
throw new SkillError(
|
|
21968
|
+
"LOCK_TIMEOUT",
|
|
21969
|
+
"Another rozo-checkout process is holding the send lock. Refusing to proceed rather than risk a concurrent second send."
|
|
21970
|
+
);
|
|
21971
|
+
}
|
|
21972
|
+
sleepSync(LOCK_POLL_MS);
|
|
21973
|
+
}
|
|
21974
|
+
try {
|
|
21975
|
+
return fn();
|
|
21976
|
+
} finally {
|
|
21977
|
+
try {
|
|
21978
|
+
fs4.unlinkSync(file);
|
|
21979
|
+
} catch {
|
|
21980
|
+
}
|
|
21981
|
+
}
|
|
21982
|
+
}
|
|
21983
|
+
function stateRoot() {
|
|
21984
|
+
return process.env.ROZO_CHECKOUT_STATE_DIR || path4.join(os3.homedir(), ".rozo-checkout", "state");
|
|
21985
|
+
}
|
|
21986
|
+
function statePath(rozoPaymentId) {
|
|
21987
|
+
if (!/^[A-Za-z0-9-]{8,64}$/.test(String(rozoPaymentId || ""))) {
|
|
21988
|
+
throw new SkillError("BAD_ROZO_PAYMENT_ID", "Refusing to build a state path from that id.");
|
|
21989
|
+
}
|
|
21990
|
+
return path4.join(stateRoot(), `${rozoPaymentId}.json`);
|
|
21991
|
+
}
|
|
21992
|
+
function writeAtomic(file, data) {
|
|
21993
|
+
const dir = path4.dirname(file);
|
|
21994
|
+
fs4.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
21995
|
+
const tmp = path4.join(dir, `.${path4.basename(file)}.${crypto5.randomBytes(6).toString("hex")}.tmp`);
|
|
21996
|
+
const fd = fs4.openSync(tmp, "wx", 384);
|
|
21997
|
+
try {
|
|
21998
|
+
fs4.writeFileSync(fd, JSON.stringify(data, null, 2) + "\n", "utf8");
|
|
21999
|
+
fs4.fsyncSync(fd);
|
|
22000
|
+
} finally {
|
|
22001
|
+
fs4.closeSync(fd);
|
|
22002
|
+
}
|
|
22003
|
+
fs4.renameSync(tmp, file);
|
|
22004
|
+
}
|
|
22005
|
+
function readState(rozoPaymentId) {
|
|
22006
|
+
const file = statePath(rozoPaymentId);
|
|
22007
|
+
let raw;
|
|
22008
|
+
try {
|
|
22009
|
+
raw = fs4.readFileSync(file, "utf8");
|
|
22010
|
+
} catch (err) {
|
|
22011
|
+
if (err.code === "ENOENT") return null;
|
|
22012
|
+
throw new SkillError("STATE_UNREADABLE", `Cannot read local state: ${err.code}`);
|
|
22013
|
+
}
|
|
22014
|
+
try {
|
|
22015
|
+
return JSON.parse(raw);
|
|
22016
|
+
} catch {
|
|
22017
|
+
throw new SkillError(
|
|
22018
|
+
"STATE_CORRUPT",
|
|
22019
|
+
"The local state file for this order is corrupt. Refusing to act; inspect it manually."
|
|
22020
|
+
);
|
|
22021
|
+
}
|
|
22022
|
+
}
|
|
22023
|
+
function depositDigest(source) {
|
|
22024
|
+
const canonical = JSON.stringify({
|
|
22025
|
+
chainId: String(source?.chainId ?? ""),
|
|
22026
|
+
tokenSymbol: String(source?.tokenSymbol ?? "").toUpperCase(),
|
|
22027
|
+
tokenAddress: String(source?.tokenAddress ?? ""),
|
|
22028
|
+
receiverAddress: String(source?.receiverAddress ?? ""),
|
|
22029
|
+
receiverMemo: source?.receiverMemo ?? null,
|
|
22030
|
+
amount: String(source?.amount ?? ""),
|
|
22031
|
+
amountUnit: source?.amountUnit ?? null,
|
|
22032
|
+
lnInvoice: source?.lnInvoice ?? null
|
|
22033
|
+
});
|
|
22034
|
+
return crypto5.createHash("sha256").update(canonical, "utf8").digest("hex");
|
|
22035
|
+
}
|
|
22036
|
+
function claimSend(rozoPaymentId, intent, { skipCaps = false } = {}) {
|
|
22037
|
+
return withLock(() => {
|
|
22038
|
+
const state = readState(rozoPaymentId);
|
|
22039
|
+
if (!state) {
|
|
22040
|
+
throw new SkillError(
|
|
22041
|
+
"NO_ORDER_STATE",
|
|
22042
|
+
"No local record for this order. Run create-order.js in this same session first."
|
|
22043
|
+
);
|
|
22044
|
+
}
|
|
22045
|
+
if (state.send) {
|
|
22046
|
+
throw new SkillError(
|
|
22047
|
+
"ALREADY_SENT",
|
|
22048
|
+
`A send was already recorded for this order at ${state.send.claimedAt} (status: ${state.send.status}). Refusing to send twice. Check the backend for the pay-in before doing anything else.`,
|
|
22049
|
+
{ send: state.send }
|
|
22050
|
+
);
|
|
22051
|
+
}
|
|
22052
|
+
const caps = skipCaps ? null : assertPaymentLimit(state.invoiceAmount);
|
|
22053
|
+
const next = {
|
|
22054
|
+
...state,
|
|
22055
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22056
|
+
send: {
|
|
22057
|
+
status: "claimed",
|
|
22058
|
+
claimedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22059
|
+
chainId: intent.chainId,
|
|
22060
|
+
tokenSymbol: intent.tokenSymbol,
|
|
22061
|
+
from: intent.from,
|
|
22062
|
+
to: intent.to,
|
|
22063
|
+
amountAtomic: intent.amountAtomic,
|
|
22064
|
+
memo: intent.memo ?? null,
|
|
22065
|
+
nonceBefore: intent.nonceBefore ?? null,
|
|
22066
|
+
expectedTxHash: intent.expectedTxHash ?? null,
|
|
22067
|
+
txHash: null
|
|
22068
|
+
}
|
|
22069
|
+
};
|
|
22070
|
+
writeAtomic(statePath(rozoPaymentId), next);
|
|
22071
|
+
return { state: next, caps };
|
|
22072
|
+
});
|
|
22073
|
+
}
|
|
22074
|
+
function recordSendResult(rozoPaymentId, { status, txHash = null, note = null }) {
|
|
22075
|
+
return withLock(() => {
|
|
22076
|
+
const state = readState(rozoPaymentId);
|
|
22077
|
+
if (!state || !state.send) {
|
|
22078
|
+
throw new SkillError("NO_SEND_CLAIM", "No send claim to update for this order.");
|
|
22079
|
+
}
|
|
22080
|
+
const next = {
|
|
22081
|
+
...state,
|
|
22082
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22083
|
+
send: {
|
|
22084
|
+
...state.send,
|
|
22085
|
+
status,
|
|
22086
|
+
txHash: txHash ?? state.send.txHash,
|
|
22087
|
+
note,
|
|
22088
|
+
resolvedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
22089
|
+
}
|
|
22090
|
+
};
|
|
22091
|
+
writeAtomic(statePath(rozoPaymentId), next);
|
|
22092
|
+
return next;
|
|
22093
|
+
});
|
|
22094
|
+
}
|
|
22095
|
+
var MAX_PAYMENT_USD = 1100;
|
|
22096
|
+
function assertPaymentLimit(invoiceUsd) {
|
|
22097
|
+
if (invoiceUsd === null || invoiceUsd === void 0 || String(invoiceUsd).trim() === "") {
|
|
22098
|
+
throw new SkillError("BAD_INVOICE_AMOUNT", "Cannot evaluate the payment limit without a USD amount.");
|
|
22099
|
+
}
|
|
22100
|
+
const usd = Number(invoiceUsd);
|
|
22101
|
+
if (!Number.isFinite(usd) || usd < 0) {
|
|
22102
|
+
throw new SkillError("BAD_INVOICE_AMOUNT", "Cannot evaluate the payment limit without a USD amount.");
|
|
22103
|
+
}
|
|
22104
|
+
if (usd > MAX_PAYMENT_USD) {
|
|
22105
|
+
throw new SkillError(
|
|
22106
|
+
"CAP_PER_TX",
|
|
22107
|
+
`$${usd} is above the $${MAX_PAYMENT_USD} per-payment limit for automated sending. This limit has no override. Pay this invoice from a wallet you control instead \u2014 that path needs no key and has no limit.`
|
|
22108
|
+
);
|
|
22109
|
+
}
|
|
22110
|
+
return { usd, limitUsd: MAX_PAYMENT_USD };
|
|
22111
|
+
}
|
|
22112
|
+
|
|
21920
22113
|
// scripts/src/lib/api.mjs
|
|
21921
22114
|
var PKG_VERSION = (() => {
|
|
21922
22115
|
const requireFrom = createRequire(import.meta.url);
|
|
@@ -22266,9 +22459,9 @@ function checkExpiry({
|
|
|
22266
22459
|
}
|
|
22267
22460
|
|
|
22268
22461
|
// scripts/src/lib/blacklist.mjs
|
|
22269
|
-
import
|
|
22270
|
-
import
|
|
22271
|
-
import
|
|
22462
|
+
import fs5 from "node:fs";
|
|
22463
|
+
import path5 from "node:path";
|
|
22464
|
+
import crypto6 from "node:crypto";
|
|
22272
22465
|
import { fileURLToPath } from "node:url";
|
|
22273
22466
|
var BlacklistError = class extends Error {
|
|
22274
22467
|
constructor(code, message) {
|
|
@@ -22303,7 +22496,7 @@ function parseBlacklist(doc) {
|
|
|
22303
22496
|
}
|
|
22304
22497
|
addresses.push(e.address);
|
|
22305
22498
|
}
|
|
22306
|
-
const digest =
|
|
22499
|
+
const digest = crypto6.createHash("sha256").update(JSON.stringify(addresses), "utf8").digest("hex");
|
|
22307
22500
|
if (typeof provenance.addressesSha256 !== "string" || !provenance.addressesSha256) {
|
|
22308
22501
|
throw new BlacklistError("BLACKLIST_UNAVAILABLE", "Blacklist provenance digest is missing.");
|
|
22309
22502
|
}
|
|
@@ -22326,11 +22519,11 @@ function parseBlacklist(doc) {
|
|
|
22326
22519
|
return { entries, index: index2, provenance, digest };
|
|
22327
22520
|
}
|
|
22328
22521
|
function candidatePaths(moduleUrl) {
|
|
22329
|
-
const here =
|
|
22522
|
+
const here = path5.dirname(fileURLToPath(moduleUrl));
|
|
22330
22523
|
return [
|
|
22331
|
-
|
|
22332
|
-
|
|
22333
|
-
|
|
22524
|
+
path5.join(here, "blacklist.json"),
|
|
22525
|
+
path5.join(here, "..", "src", "lib", "blacklist.json"),
|
|
22526
|
+
path5.join(here, "..", "..", "src", "lib", "blacklist.json")
|
|
22334
22527
|
];
|
|
22335
22528
|
}
|
|
22336
22529
|
var cached = null;
|
|
@@ -22341,7 +22534,7 @@ function loadBlacklist(explicitPath) {
|
|
|
22341
22534
|
for (const p of paths) {
|
|
22342
22535
|
let raw;
|
|
22343
22536
|
try {
|
|
22344
|
-
raw =
|
|
22537
|
+
raw = fs5.readFileSync(p, "utf8");
|
|
22345
22538
|
} catch (err) {
|
|
22346
22539
|
lastErr = err;
|
|
22347
22540
|
continue;
|
|
@@ -22388,199 +22581,6 @@ function assertNotBlacklisted(targets, blacklist) {
|
|
|
22388
22581
|
return true;
|
|
22389
22582
|
}
|
|
22390
22583
|
|
|
22391
|
-
// scripts/src/lib/state.mjs
|
|
22392
|
-
import fs5 from "node:fs";
|
|
22393
|
-
import path5 from "node:path";
|
|
22394
|
-
import os3 from "node:os";
|
|
22395
|
-
import crypto6 from "node:crypto";
|
|
22396
|
-
var LOCK_STALE_MS = 6e4;
|
|
22397
|
-
var LOCK_WAIT_MS = 1e4;
|
|
22398
|
-
var LOCK_POLL_MS = 25;
|
|
22399
|
-
function lockPath() {
|
|
22400
|
-
return path5.join(stateRoot(), ".send.lock");
|
|
22401
|
-
}
|
|
22402
|
-
function sleepSync(ms) {
|
|
22403
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
22404
|
-
}
|
|
22405
|
-
function tryAcquire(file) {
|
|
22406
|
-
try {
|
|
22407
|
-
const fd = fs5.openSync(file, "wx", 384);
|
|
22408
|
-
fs5.writeFileSync(fd, JSON.stringify({ pid: process.pid, at: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
22409
|
-
fs5.closeSync(fd);
|
|
22410
|
-
return true;
|
|
22411
|
-
} catch (err) {
|
|
22412
|
-
if (err.code !== "EEXIST") throw err;
|
|
22413
|
-
return false;
|
|
22414
|
-
}
|
|
22415
|
-
}
|
|
22416
|
-
function withLock(fn) {
|
|
22417
|
-
const file = lockPath();
|
|
22418
|
-
fs5.mkdirSync(path5.dirname(file), { recursive: true, mode: 448 });
|
|
22419
|
-
const deadline = Date.now() + LOCK_WAIT_MS;
|
|
22420
|
-
for (; ; ) {
|
|
22421
|
-
if (tryAcquire(file)) break;
|
|
22422
|
-
try {
|
|
22423
|
-
const age = Date.now() - fs5.statSync(file).mtimeMs;
|
|
22424
|
-
if (age > LOCK_STALE_MS) {
|
|
22425
|
-
const stolen = `${file}.stale.${crypto6.randomBytes(4).toString("hex")}`;
|
|
22426
|
-
try {
|
|
22427
|
-
fs5.renameSync(file, stolen);
|
|
22428
|
-
fs5.unlinkSync(stolen);
|
|
22429
|
-
} catch {
|
|
22430
|
-
}
|
|
22431
|
-
continue;
|
|
22432
|
-
}
|
|
22433
|
-
} catch (err) {
|
|
22434
|
-
if (err.code !== "ENOENT") throw err;
|
|
22435
|
-
continue;
|
|
22436
|
-
}
|
|
22437
|
-
if (Date.now() > deadline) {
|
|
22438
|
-
throw new SkillError(
|
|
22439
|
-
"LOCK_TIMEOUT",
|
|
22440
|
-
"Another rozo-checkout process is holding the send lock. Refusing to proceed rather than risk a concurrent second send."
|
|
22441
|
-
);
|
|
22442
|
-
}
|
|
22443
|
-
sleepSync(LOCK_POLL_MS);
|
|
22444
|
-
}
|
|
22445
|
-
try {
|
|
22446
|
-
return fn();
|
|
22447
|
-
} finally {
|
|
22448
|
-
try {
|
|
22449
|
-
fs5.unlinkSync(file);
|
|
22450
|
-
} catch {
|
|
22451
|
-
}
|
|
22452
|
-
}
|
|
22453
|
-
}
|
|
22454
|
-
function stateRoot() {
|
|
22455
|
-
return process.env.ROZO_CHECKOUT_STATE_DIR || path5.join(os3.homedir(), ".rozo-checkout", "state");
|
|
22456
|
-
}
|
|
22457
|
-
function statePath(rozoPaymentId) {
|
|
22458
|
-
if (!/^[A-Za-z0-9-]{8,64}$/.test(String(rozoPaymentId || ""))) {
|
|
22459
|
-
throw new SkillError("BAD_ROZO_PAYMENT_ID", "Refusing to build a state path from that id.");
|
|
22460
|
-
}
|
|
22461
|
-
return path5.join(stateRoot(), `${rozoPaymentId}.json`);
|
|
22462
|
-
}
|
|
22463
|
-
function writeAtomic(file, data) {
|
|
22464
|
-
const dir = path5.dirname(file);
|
|
22465
|
-
fs5.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
22466
|
-
const tmp = path5.join(dir, `.${path5.basename(file)}.${crypto6.randomBytes(6).toString("hex")}.tmp`);
|
|
22467
|
-
const fd = fs5.openSync(tmp, "wx", 384);
|
|
22468
|
-
try {
|
|
22469
|
-
fs5.writeFileSync(fd, JSON.stringify(data, null, 2) + "\n", "utf8");
|
|
22470
|
-
fs5.fsyncSync(fd);
|
|
22471
|
-
} finally {
|
|
22472
|
-
fs5.closeSync(fd);
|
|
22473
|
-
}
|
|
22474
|
-
fs5.renameSync(tmp, file);
|
|
22475
|
-
}
|
|
22476
|
-
function readState(rozoPaymentId) {
|
|
22477
|
-
const file = statePath(rozoPaymentId);
|
|
22478
|
-
let raw;
|
|
22479
|
-
try {
|
|
22480
|
-
raw = fs5.readFileSync(file, "utf8");
|
|
22481
|
-
} catch (err) {
|
|
22482
|
-
if (err.code === "ENOENT") return null;
|
|
22483
|
-
throw new SkillError("STATE_UNREADABLE", `Cannot read local state: ${err.code}`);
|
|
22484
|
-
}
|
|
22485
|
-
try {
|
|
22486
|
-
return JSON.parse(raw);
|
|
22487
|
-
} catch {
|
|
22488
|
-
throw new SkillError(
|
|
22489
|
-
"STATE_CORRUPT",
|
|
22490
|
-
"The local state file for this order is corrupt. Refusing to act; inspect it manually."
|
|
22491
|
-
);
|
|
22492
|
-
}
|
|
22493
|
-
}
|
|
22494
|
-
function depositDigest(source) {
|
|
22495
|
-
const canonical = JSON.stringify({
|
|
22496
|
-
chainId: String(source?.chainId ?? ""),
|
|
22497
|
-
tokenSymbol: String(source?.tokenSymbol ?? "").toUpperCase(),
|
|
22498
|
-
tokenAddress: String(source?.tokenAddress ?? ""),
|
|
22499
|
-
receiverAddress: String(source?.receiverAddress ?? ""),
|
|
22500
|
-
receiverMemo: source?.receiverMemo ?? null,
|
|
22501
|
-
amount: String(source?.amount ?? ""),
|
|
22502
|
-
amountUnit: source?.amountUnit ?? null,
|
|
22503
|
-
lnInvoice: source?.lnInvoice ?? null
|
|
22504
|
-
});
|
|
22505
|
-
return crypto6.createHash("sha256").update(canonical, "utf8").digest("hex");
|
|
22506
|
-
}
|
|
22507
|
-
function claimSend(rozoPaymentId, intent, { skipCaps = false } = {}) {
|
|
22508
|
-
return withLock(() => {
|
|
22509
|
-
const state = readState(rozoPaymentId);
|
|
22510
|
-
if (!state) {
|
|
22511
|
-
throw new SkillError(
|
|
22512
|
-
"NO_ORDER_STATE",
|
|
22513
|
-
"No local record for this order. Run create-order.js in this same session first."
|
|
22514
|
-
);
|
|
22515
|
-
}
|
|
22516
|
-
if (state.send) {
|
|
22517
|
-
throw new SkillError(
|
|
22518
|
-
"ALREADY_SENT",
|
|
22519
|
-
`A send was already recorded for this order at ${state.send.claimedAt} (status: ${state.send.status}). Refusing to send twice. Check the backend for the pay-in before doing anything else.`,
|
|
22520
|
-
{ send: state.send }
|
|
22521
|
-
);
|
|
22522
|
-
}
|
|
22523
|
-
const caps = skipCaps ? null : assertPaymentLimit(state.invoiceAmount);
|
|
22524
|
-
const next = {
|
|
22525
|
-
...state,
|
|
22526
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22527
|
-
send: {
|
|
22528
|
-
status: "claimed",
|
|
22529
|
-
claimedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22530
|
-
chainId: intent.chainId,
|
|
22531
|
-
tokenSymbol: intent.tokenSymbol,
|
|
22532
|
-
from: intent.from,
|
|
22533
|
-
to: intent.to,
|
|
22534
|
-
amountAtomic: intent.amountAtomic,
|
|
22535
|
-
memo: intent.memo ?? null,
|
|
22536
|
-
nonceBefore: intent.nonceBefore ?? null,
|
|
22537
|
-
expectedTxHash: intent.expectedTxHash ?? null,
|
|
22538
|
-
txHash: null
|
|
22539
|
-
}
|
|
22540
|
-
};
|
|
22541
|
-
writeAtomic(statePath(rozoPaymentId), next);
|
|
22542
|
-
return { state: next, caps };
|
|
22543
|
-
});
|
|
22544
|
-
}
|
|
22545
|
-
function recordSendResult(rozoPaymentId, { status, txHash = null, note = null }) {
|
|
22546
|
-
return withLock(() => {
|
|
22547
|
-
const state = readState(rozoPaymentId);
|
|
22548
|
-
if (!state || !state.send) {
|
|
22549
|
-
throw new SkillError("NO_SEND_CLAIM", "No send claim to update for this order.");
|
|
22550
|
-
}
|
|
22551
|
-
const next = {
|
|
22552
|
-
...state,
|
|
22553
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22554
|
-
send: {
|
|
22555
|
-
...state.send,
|
|
22556
|
-
status,
|
|
22557
|
-
txHash: txHash ?? state.send.txHash,
|
|
22558
|
-
note,
|
|
22559
|
-
resolvedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
22560
|
-
}
|
|
22561
|
-
};
|
|
22562
|
-
writeAtomic(statePath(rozoPaymentId), next);
|
|
22563
|
-
return next;
|
|
22564
|
-
});
|
|
22565
|
-
}
|
|
22566
|
-
var MAX_PAYMENT_USD = 1100;
|
|
22567
|
-
function assertPaymentLimit(invoiceUsd) {
|
|
22568
|
-
if (invoiceUsd === null || invoiceUsd === void 0 || String(invoiceUsd).trim() === "") {
|
|
22569
|
-
throw new SkillError("BAD_INVOICE_AMOUNT", "Cannot evaluate the payment limit without a USD amount.");
|
|
22570
|
-
}
|
|
22571
|
-
const usd = Number(invoiceUsd);
|
|
22572
|
-
if (!Number.isFinite(usd) || usd < 0) {
|
|
22573
|
-
throw new SkillError("BAD_INVOICE_AMOUNT", "Cannot evaluate the payment limit without a USD amount.");
|
|
22574
|
-
}
|
|
22575
|
-
if (usd > MAX_PAYMENT_USD) {
|
|
22576
|
-
throw new SkillError(
|
|
22577
|
-
"CAP_PER_TX",
|
|
22578
|
-
`$${usd} is above the $${MAX_PAYMENT_USD} per-payment limit for automated sending. This limit has no override. Pay this invoice from a wallet you control instead \u2014 that path needs no key and has no limit.`
|
|
22579
|
-
);
|
|
22580
|
-
}
|
|
22581
|
-
return { usd, limitUsd: MAX_PAYMENT_USD };
|
|
22582
|
-
}
|
|
22583
|
-
|
|
22584
22584
|
// scripts/src/lib/bitrefill.mjs
|
|
22585
22585
|
var BITREFILL_DESTINATION = Object.freeze({ chainId: "8453", tokenSymbol: "USDC" });
|
|
22586
22586
|
var BITREFILL_MIN_EXPIRY_MS = 5 * 60 * 1e3;
|