@rozoai/checkout 0.1.15 → 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 +63 -1
- package/package.json +1 -1
- package/scripts/dist/cli.js +1267 -126
- package/scripts/dist/create-order.js +341 -186
- package/scripts/dist/quote.js +9 -0
- package/scripts/dist/receipt.js +1195 -0
- package/scripts/dist/resume.js +1486 -0
- package/scripts/dist/send-evm.js +502 -215
- package/scripts/dist/send-sol.js +324 -229
- package/scripts/dist/status.js +405 -49
package/scripts/dist/send-evm.js
CHANGED
|
@@ -3441,6 +3441,9 @@ function carry(digits) {
|
|
|
3441
3441
|
}
|
|
3442
3442
|
return `1${out.join("")}`;
|
|
3443
3443
|
}
|
|
3444
|
+
function fromGwei(gwei, unit = "wei") {
|
|
3445
|
+
return from(gwei, exponents.gwei - exponents[unit]);
|
|
3446
|
+
}
|
|
3444
3447
|
var exponents, InvalidDecimalNumberError, InvalidDecimalsError;
|
|
3445
3448
|
var init_Value = __esm({
|
|
3446
3449
|
"node_modules/viem/_esm/utils/unit/Value.js"() {
|
|
@@ -10006,7 +10009,20 @@ function redact(text) {
|
|
|
10006
10009
|
);
|
|
10007
10010
|
return s;
|
|
10008
10011
|
}
|
|
10012
|
+
var PublicHash = class {
|
|
10013
|
+
constructor(value) {
|
|
10014
|
+
this.value = value;
|
|
10015
|
+
}
|
|
10016
|
+
toJSON() {
|
|
10017
|
+
return this.value;
|
|
10018
|
+
}
|
|
10019
|
+
};
|
|
10020
|
+
var TX_HASH_VALUE = /^(0x[0-9a-fA-F]{64}|[1-9A-HJ-NP-Za-km-z]{86,88})$/;
|
|
10021
|
+
function publicHash(value) {
|
|
10022
|
+
return typeof value === "string" && TX_HASH_VALUE.test(value) ? new PublicHash(value) : value;
|
|
10023
|
+
}
|
|
10009
10024
|
function redactDeep(value) {
|
|
10025
|
+
if (value instanceof PublicHash) return value.value;
|
|
10010
10026
|
if (typeof value === "string") return redact(value);
|
|
10011
10027
|
if (Array.isArray(value)) return value.map(redactDeep);
|
|
10012
10028
|
if (value && typeof value === "object") {
|
|
@@ -18315,6 +18331,12 @@ function formatUnits(value, decimals) {
|
|
|
18315
18331
|
return format(value, decimals);
|
|
18316
18332
|
}
|
|
18317
18333
|
|
|
18334
|
+
// node_modules/viem/_esm/utils/unit/parseGwei.js
|
|
18335
|
+
init_Value();
|
|
18336
|
+
function parseGwei(ether, unit = "wei") {
|
|
18337
|
+
return fromGwei(ether, unit);
|
|
18338
|
+
}
|
|
18339
|
+
|
|
18318
18340
|
// node_modules/viem/_esm/utils/unit/parseUnits.js
|
|
18319
18341
|
init_Value();
|
|
18320
18342
|
function parseUnits(value, decimals) {
|
|
@@ -18458,7 +18480,7 @@ init_createBatchScheduler();
|
|
|
18458
18480
|
init_stringify();
|
|
18459
18481
|
async function multicall(client, parameters) {
|
|
18460
18482
|
const { account, authorizationList, allowFailure = true, blockHash, blockNumber, blockOverrides, blockTag, requireCanonical, stateOverride } = parameters;
|
|
18461
|
-
const
|
|
18483
|
+
const contracts2 = parameters.contracts;
|
|
18462
18484
|
const batch = typeof client.batch?.multicall === "object" ? client.batch.multicall : {};
|
|
18463
18485
|
const batchSize = parameters.batchSize ?? batch.batchSize ?? 1024;
|
|
18464
18486
|
const deployless = parameters.deployless ?? batch.deployless ?? false;
|
|
@@ -18479,8 +18501,8 @@ async function multicall(client, parameters) {
|
|
|
18479
18501
|
const chunkedCalls = [[]];
|
|
18480
18502
|
let currentChunk = 0;
|
|
18481
18503
|
let currentChunkSize = 0;
|
|
18482
|
-
for (let i = 0; i <
|
|
18483
|
-
const { abi: abi2, address, args, functionName } =
|
|
18504
|
+
for (let i = 0; i < contracts2.length; i++) {
|
|
18505
|
+
const { abi: abi2, address, args, functionName } = contracts2[i];
|
|
18484
18506
|
try {
|
|
18485
18507
|
const callData = encodeFunctionData({ abi: abi2, args, functionName });
|
|
18486
18508
|
currentChunkSize += (callData.length - 2) / 2;
|
|
@@ -18574,7 +18596,7 @@ async function multicall(client, parameters) {
|
|
|
18574
18596
|
for (let j = 0; j < aggregate3Result.length; j++) {
|
|
18575
18597
|
const { returnData, success } = aggregate3Result[j];
|
|
18576
18598
|
const { callData } = batches[i][j];
|
|
18577
|
-
const { abi: abi2, address, functionName, args } =
|
|
18599
|
+
const { abi: abi2, address, functionName, args } = contracts2[results.length];
|
|
18578
18600
|
try {
|
|
18579
18601
|
if (callData === "0x")
|
|
18580
18602
|
throw new AbiDecodingZeroDataError();
|
|
@@ -18601,7 +18623,7 @@ async function multicall(client, parameters) {
|
|
|
18601
18623
|
}
|
|
18602
18624
|
}
|
|
18603
18625
|
}
|
|
18604
|
-
if (results.length !==
|
|
18626
|
+
if (results.length !== contracts2.length)
|
|
18605
18627
|
throw new BaseError2("multicall results mismatch");
|
|
18606
18628
|
return results;
|
|
18607
18629
|
}
|
|
@@ -21895,6 +21917,199 @@ function getJson(url, opts) {
|
|
|
21895
21917
|
return request("GET", url, opts);
|
|
21896
21918
|
}
|
|
21897
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
|
+
|
|
21898
22113
|
// scripts/src/lib/api.mjs
|
|
21899
22114
|
var PKG_VERSION = (() => {
|
|
21900
22115
|
const requireFrom = createRequire(import.meta.url);
|
|
@@ -22244,9 +22459,9 @@ function checkExpiry({
|
|
|
22244
22459
|
}
|
|
22245
22460
|
|
|
22246
22461
|
// scripts/src/lib/blacklist.mjs
|
|
22247
|
-
import
|
|
22248
|
-
import
|
|
22249
|
-
import
|
|
22462
|
+
import fs5 from "node:fs";
|
|
22463
|
+
import path5 from "node:path";
|
|
22464
|
+
import crypto6 from "node:crypto";
|
|
22250
22465
|
import { fileURLToPath } from "node:url";
|
|
22251
22466
|
var BlacklistError = class extends Error {
|
|
22252
22467
|
constructor(code, message) {
|
|
@@ -22281,7 +22496,7 @@ function parseBlacklist(doc) {
|
|
|
22281
22496
|
}
|
|
22282
22497
|
addresses.push(e.address);
|
|
22283
22498
|
}
|
|
22284
|
-
const digest =
|
|
22499
|
+
const digest = crypto6.createHash("sha256").update(JSON.stringify(addresses), "utf8").digest("hex");
|
|
22285
22500
|
if (typeof provenance.addressesSha256 !== "string" || !provenance.addressesSha256) {
|
|
22286
22501
|
throw new BlacklistError("BLACKLIST_UNAVAILABLE", "Blacklist provenance digest is missing.");
|
|
22287
22502
|
}
|
|
@@ -22304,11 +22519,11 @@ function parseBlacklist(doc) {
|
|
|
22304
22519
|
return { entries, index: index2, provenance, digest };
|
|
22305
22520
|
}
|
|
22306
22521
|
function candidatePaths(moduleUrl) {
|
|
22307
|
-
const here =
|
|
22522
|
+
const here = path5.dirname(fileURLToPath(moduleUrl));
|
|
22308
22523
|
return [
|
|
22309
|
-
|
|
22310
|
-
|
|
22311
|
-
|
|
22524
|
+
path5.join(here, "blacklist.json"),
|
|
22525
|
+
path5.join(here, "..", "src", "lib", "blacklist.json"),
|
|
22526
|
+
path5.join(here, "..", "..", "src", "lib", "blacklist.json")
|
|
22312
22527
|
];
|
|
22313
22528
|
}
|
|
22314
22529
|
var cached = null;
|
|
@@ -22319,7 +22534,7 @@ function loadBlacklist(explicitPath) {
|
|
|
22319
22534
|
for (const p of paths) {
|
|
22320
22535
|
let raw;
|
|
22321
22536
|
try {
|
|
22322
|
-
raw =
|
|
22537
|
+
raw = fs5.readFileSync(p, "utf8");
|
|
22323
22538
|
} catch (err) {
|
|
22324
22539
|
lastErr = err;
|
|
22325
22540
|
continue;
|
|
@@ -22366,199 +22581,6 @@ function assertNotBlacklisted(targets, blacklist) {
|
|
|
22366
22581
|
return true;
|
|
22367
22582
|
}
|
|
22368
22583
|
|
|
22369
|
-
// scripts/src/lib/state.mjs
|
|
22370
|
-
import fs5 from "node:fs";
|
|
22371
|
-
import path5 from "node:path";
|
|
22372
|
-
import os3 from "node:os";
|
|
22373
|
-
import crypto6 from "node:crypto";
|
|
22374
|
-
var LOCK_STALE_MS = 6e4;
|
|
22375
|
-
var LOCK_WAIT_MS = 1e4;
|
|
22376
|
-
var LOCK_POLL_MS = 25;
|
|
22377
|
-
function lockPath() {
|
|
22378
|
-
return path5.join(stateRoot(), ".send.lock");
|
|
22379
|
-
}
|
|
22380
|
-
function sleepSync(ms) {
|
|
22381
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
22382
|
-
}
|
|
22383
|
-
function tryAcquire(file) {
|
|
22384
|
-
try {
|
|
22385
|
-
const fd = fs5.openSync(file, "wx", 384);
|
|
22386
|
-
fs5.writeFileSync(fd, JSON.stringify({ pid: process.pid, at: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
22387
|
-
fs5.closeSync(fd);
|
|
22388
|
-
return true;
|
|
22389
|
-
} catch (err) {
|
|
22390
|
-
if (err.code !== "EEXIST") throw err;
|
|
22391
|
-
return false;
|
|
22392
|
-
}
|
|
22393
|
-
}
|
|
22394
|
-
function withLock(fn) {
|
|
22395
|
-
const file = lockPath();
|
|
22396
|
-
fs5.mkdirSync(path5.dirname(file), { recursive: true, mode: 448 });
|
|
22397
|
-
const deadline = Date.now() + LOCK_WAIT_MS;
|
|
22398
|
-
for (; ; ) {
|
|
22399
|
-
if (tryAcquire(file)) break;
|
|
22400
|
-
try {
|
|
22401
|
-
const age = Date.now() - fs5.statSync(file).mtimeMs;
|
|
22402
|
-
if (age > LOCK_STALE_MS) {
|
|
22403
|
-
const stolen = `${file}.stale.${crypto6.randomBytes(4).toString("hex")}`;
|
|
22404
|
-
try {
|
|
22405
|
-
fs5.renameSync(file, stolen);
|
|
22406
|
-
fs5.unlinkSync(stolen);
|
|
22407
|
-
} catch {
|
|
22408
|
-
}
|
|
22409
|
-
continue;
|
|
22410
|
-
}
|
|
22411
|
-
} catch (err) {
|
|
22412
|
-
if (err.code !== "ENOENT") throw err;
|
|
22413
|
-
continue;
|
|
22414
|
-
}
|
|
22415
|
-
if (Date.now() > deadline) {
|
|
22416
|
-
throw new SkillError(
|
|
22417
|
-
"LOCK_TIMEOUT",
|
|
22418
|
-
"Another rozo-checkout process is holding the send lock. Refusing to proceed rather than risk a concurrent second send."
|
|
22419
|
-
);
|
|
22420
|
-
}
|
|
22421
|
-
sleepSync(LOCK_POLL_MS);
|
|
22422
|
-
}
|
|
22423
|
-
try {
|
|
22424
|
-
return fn();
|
|
22425
|
-
} finally {
|
|
22426
|
-
try {
|
|
22427
|
-
fs5.unlinkSync(file);
|
|
22428
|
-
} catch {
|
|
22429
|
-
}
|
|
22430
|
-
}
|
|
22431
|
-
}
|
|
22432
|
-
function stateRoot() {
|
|
22433
|
-
return process.env.ROZO_CHECKOUT_STATE_DIR || path5.join(os3.homedir(), ".rozo-checkout", "state");
|
|
22434
|
-
}
|
|
22435
|
-
function statePath(rozoPaymentId) {
|
|
22436
|
-
if (!/^[A-Za-z0-9-]{8,64}$/.test(String(rozoPaymentId || ""))) {
|
|
22437
|
-
throw new SkillError("BAD_ROZO_PAYMENT_ID", "Refusing to build a state path from that id.");
|
|
22438
|
-
}
|
|
22439
|
-
return path5.join(stateRoot(), `${rozoPaymentId}.json`);
|
|
22440
|
-
}
|
|
22441
|
-
function writeAtomic(file, data) {
|
|
22442
|
-
const dir = path5.dirname(file);
|
|
22443
|
-
fs5.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
22444
|
-
const tmp = path5.join(dir, `.${path5.basename(file)}.${crypto6.randomBytes(6).toString("hex")}.tmp`);
|
|
22445
|
-
const fd = fs5.openSync(tmp, "wx", 384);
|
|
22446
|
-
try {
|
|
22447
|
-
fs5.writeFileSync(fd, JSON.stringify(data, null, 2) + "\n", "utf8");
|
|
22448
|
-
fs5.fsyncSync(fd);
|
|
22449
|
-
} finally {
|
|
22450
|
-
fs5.closeSync(fd);
|
|
22451
|
-
}
|
|
22452
|
-
fs5.renameSync(tmp, file);
|
|
22453
|
-
}
|
|
22454
|
-
function readState(rozoPaymentId) {
|
|
22455
|
-
const file = statePath(rozoPaymentId);
|
|
22456
|
-
let raw;
|
|
22457
|
-
try {
|
|
22458
|
-
raw = fs5.readFileSync(file, "utf8");
|
|
22459
|
-
} catch (err) {
|
|
22460
|
-
if (err.code === "ENOENT") return null;
|
|
22461
|
-
throw new SkillError("STATE_UNREADABLE", `Cannot read local state: ${err.code}`);
|
|
22462
|
-
}
|
|
22463
|
-
try {
|
|
22464
|
-
return JSON.parse(raw);
|
|
22465
|
-
} catch {
|
|
22466
|
-
throw new SkillError(
|
|
22467
|
-
"STATE_CORRUPT",
|
|
22468
|
-
"The local state file for this order is corrupt. Refusing to act; inspect it manually."
|
|
22469
|
-
);
|
|
22470
|
-
}
|
|
22471
|
-
}
|
|
22472
|
-
function depositDigest(source) {
|
|
22473
|
-
const canonical = JSON.stringify({
|
|
22474
|
-
chainId: String(source?.chainId ?? ""),
|
|
22475
|
-
tokenSymbol: String(source?.tokenSymbol ?? "").toUpperCase(),
|
|
22476
|
-
tokenAddress: String(source?.tokenAddress ?? ""),
|
|
22477
|
-
receiverAddress: String(source?.receiverAddress ?? ""),
|
|
22478
|
-
receiverMemo: source?.receiverMemo ?? null,
|
|
22479
|
-
amount: String(source?.amount ?? ""),
|
|
22480
|
-
amountUnit: source?.amountUnit ?? null,
|
|
22481
|
-
lnInvoice: source?.lnInvoice ?? null
|
|
22482
|
-
});
|
|
22483
|
-
return crypto6.createHash("sha256").update(canonical, "utf8").digest("hex");
|
|
22484
|
-
}
|
|
22485
|
-
function claimSend(rozoPaymentId, intent, { skipCaps = false } = {}) {
|
|
22486
|
-
return withLock(() => {
|
|
22487
|
-
const state = readState(rozoPaymentId);
|
|
22488
|
-
if (!state) {
|
|
22489
|
-
throw new SkillError(
|
|
22490
|
-
"NO_ORDER_STATE",
|
|
22491
|
-
"No local record for this order. Run create-order.js in this same session first."
|
|
22492
|
-
);
|
|
22493
|
-
}
|
|
22494
|
-
if (state.send) {
|
|
22495
|
-
throw new SkillError(
|
|
22496
|
-
"ALREADY_SENT",
|
|
22497
|
-
`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.`,
|
|
22498
|
-
{ send: state.send }
|
|
22499
|
-
);
|
|
22500
|
-
}
|
|
22501
|
-
const caps = skipCaps ? null : assertPaymentLimit(state.invoiceAmount);
|
|
22502
|
-
const next = {
|
|
22503
|
-
...state,
|
|
22504
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22505
|
-
send: {
|
|
22506
|
-
status: "claimed",
|
|
22507
|
-
claimedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22508
|
-
chainId: intent.chainId,
|
|
22509
|
-
tokenSymbol: intent.tokenSymbol,
|
|
22510
|
-
from: intent.from,
|
|
22511
|
-
to: intent.to,
|
|
22512
|
-
amountAtomic: intent.amountAtomic,
|
|
22513
|
-
memo: intent.memo ?? null,
|
|
22514
|
-
nonceBefore: intent.nonceBefore ?? null,
|
|
22515
|
-
expectedTxHash: intent.expectedTxHash ?? null,
|
|
22516
|
-
txHash: null
|
|
22517
|
-
}
|
|
22518
|
-
};
|
|
22519
|
-
writeAtomic(statePath(rozoPaymentId), next);
|
|
22520
|
-
return { state: next, caps };
|
|
22521
|
-
});
|
|
22522
|
-
}
|
|
22523
|
-
function recordSendResult(rozoPaymentId, { status, txHash = null, note = null }) {
|
|
22524
|
-
return withLock(() => {
|
|
22525
|
-
const state = readState(rozoPaymentId);
|
|
22526
|
-
if (!state || !state.send) {
|
|
22527
|
-
throw new SkillError("NO_SEND_CLAIM", "No send claim to update for this order.");
|
|
22528
|
-
}
|
|
22529
|
-
const next = {
|
|
22530
|
-
...state,
|
|
22531
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22532
|
-
send: {
|
|
22533
|
-
...state.send,
|
|
22534
|
-
status,
|
|
22535
|
-
txHash: txHash ?? state.send.txHash,
|
|
22536
|
-
note,
|
|
22537
|
-
resolvedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
22538
|
-
}
|
|
22539
|
-
};
|
|
22540
|
-
writeAtomic(statePath(rozoPaymentId), next);
|
|
22541
|
-
return next;
|
|
22542
|
-
});
|
|
22543
|
-
}
|
|
22544
|
-
var MAX_PAYMENT_USD = 1100;
|
|
22545
|
-
function assertPaymentLimit(invoiceUsd) {
|
|
22546
|
-
if (invoiceUsd === null || invoiceUsd === void 0 || String(invoiceUsd).trim() === "") {
|
|
22547
|
-
throw new SkillError("BAD_INVOICE_AMOUNT", "Cannot evaluate the payment limit without a USD amount.");
|
|
22548
|
-
}
|
|
22549
|
-
const usd = Number(invoiceUsd);
|
|
22550
|
-
if (!Number.isFinite(usd) || usd < 0) {
|
|
22551
|
-
throw new SkillError("BAD_INVOICE_AMOUNT", "Cannot evaluate the payment limit without a USD amount.");
|
|
22552
|
-
}
|
|
22553
|
-
if (usd > MAX_PAYMENT_USD) {
|
|
22554
|
-
throw new SkillError(
|
|
22555
|
-
"CAP_PER_TX",
|
|
22556
|
-
`$${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.`
|
|
22557
|
-
);
|
|
22558
|
-
}
|
|
22559
|
-
return { usd, limitUsd: MAX_PAYMENT_USD };
|
|
22560
|
-
}
|
|
22561
|
-
|
|
22562
22584
|
// scripts/src/lib/bitrefill.mjs
|
|
22563
22585
|
var BITREFILL_DESTINATION = Object.freeze({ chainId: "8453", tokenSymbol: "USDC" });
|
|
22564
22586
|
var BITREFILL_MIN_EXPIRY_MS = 5 * 60 * 1e3;
|
|
@@ -22802,6 +22824,256 @@ function broadcastOutcome({ receiptStatus, executionError = null, receiptSeen =
|
|
|
22802
22824
|
};
|
|
22803
22825
|
}
|
|
22804
22826
|
|
|
22827
|
+
// scripts/src/lib/gas.mjs
|
|
22828
|
+
var EVM_FEE_COIN = Object.freeze({
|
|
22829
|
+
1: { symbol: "ETH", network: "Ethereum" },
|
|
22830
|
+
56: { symbol: "BNB", network: "BNB Chain" },
|
|
22831
|
+
137: { symbol: "POL", network: "Polygon" },
|
|
22832
|
+
8453: { symbol: "ETH", network: "Base" }
|
|
22833
|
+
});
|
|
22834
|
+
var DEFAULT_GAS_BUFFER_PCT = 20;
|
|
22835
|
+
var MAX_GAS_BUFFER_PCT = 200;
|
|
22836
|
+
function gasBufferPct(env = process.env) {
|
|
22837
|
+
const raw = env?.ROZO_CHECKOUT_GAS_BUFFER_PCT;
|
|
22838
|
+
if (raw === void 0 || raw === "") return DEFAULT_GAS_BUFFER_PCT;
|
|
22839
|
+
const n = Number(raw);
|
|
22840
|
+
if (!Number.isInteger(n) || n < 0 || n > MAX_GAS_BUFFER_PCT) return DEFAULT_GAS_BUFFER_PCT;
|
|
22841
|
+
return n;
|
|
22842
|
+
}
|
|
22843
|
+
function formatAtomic(atomic, decimals) {
|
|
22844
|
+
const neg = atomic < 0n;
|
|
22845
|
+
const v = neg ? -atomic : atomic;
|
|
22846
|
+
const base = 10n ** BigInt(decimals);
|
|
22847
|
+
const whole = v / base;
|
|
22848
|
+
const frac = (v % base).toString().padStart(decimals, "0").replace(/0+$/, "");
|
|
22849
|
+
return `${neg ? "-" : ""}${whole}${frac ? `.${frac}` : ""}`;
|
|
22850
|
+
}
|
|
22851
|
+
function evmFeeRequirement({ gasEstimate, maxFeePerGas, gasPrice, bufferPct = DEFAULT_GAS_BUFFER_PCT }) {
|
|
22852
|
+
const perGas = typeof maxFeePerGas === "bigint" ? maxFeePerGas : typeof gasPrice === "bigint" ? gasPrice : null;
|
|
22853
|
+
if (typeof gasEstimate !== "bigint" || perGas === null) return null;
|
|
22854
|
+
const gasLimit = (gasEstimate * BigInt(100 + bufferPct) + 99n) / 100n;
|
|
22855
|
+
return { gasLimit, perGas, pricing: typeof maxFeePerGas === "bigint" ? "eip1559" : "legacy", fee: gasLimit * perGas };
|
|
22856
|
+
}
|
|
22857
|
+
function assessFee({ balance, required, decimals, symbol, network }) {
|
|
22858
|
+
const ok = required === null ? balance > 0n : balance >= required;
|
|
22859
|
+
const details = {
|
|
22860
|
+
network,
|
|
22861
|
+
feeCoin: symbol,
|
|
22862
|
+
balance: formatAtomic(balance, decimals),
|
|
22863
|
+
required: required === null ? null : formatAtomic(required, decimals),
|
|
22864
|
+
shortfall: required === null || ok ? null : formatAtomic(required - balance, decimals)
|
|
22865
|
+
};
|
|
22866
|
+
return { ok, details };
|
|
22867
|
+
}
|
|
22868
|
+
function insufficient(details, extra) {
|
|
22869
|
+
const need = details.required ? `about ${details.required} ${details.feeCoin}` : `some ${details.feeCoin}`;
|
|
22870
|
+
return new SkillError(
|
|
22871
|
+
"INSUFFICIENT_GAS",
|
|
22872
|
+
`This wallet holds ${details.balance} ${details.feeCoin} on ${details.network} but needs ${need} for the network fee${details.shortfall ? ` (short by ${details.shortfall} ${details.feeCoin})` : ""}. Nothing was signed. Add ${details.feeCoin} on ${details.network} to this wallet and re-run, or pay with a different coin.` + (extra ? ` ${extra}` : ""),
|
|
22873
|
+
details
|
|
22874
|
+
);
|
|
22875
|
+
}
|
|
22876
|
+
function unavailable(network, err) {
|
|
22877
|
+
return new SkillError(
|
|
22878
|
+
"GAS_CHECK_UNAVAILABLE",
|
|
22879
|
+
`Could not check the network fee on ${network}: ${redact(err?.shortMessage || err?.message || "unknown error")}. This is not evidence of a shortfall. Nothing was signed. Retry, pass --rpc <url>, or pay by hand from your wallet.`,
|
|
22880
|
+
{ network }
|
|
22881
|
+
);
|
|
22882
|
+
}
|
|
22883
|
+
async function estimateFees(client) {
|
|
22884
|
+
try {
|
|
22885
|
+
return await client.estimateFeesPerGas();
|
|
22886
|
+
} catch (err) {
|
|
22887
|
+
if (err?.name !== "Eip1559FeesNotSupportedError") throw err;
|
|
22888
|
+
return client.estimateFeesPerGas({ type: "legacy" });
|
|
22889
|
+
}
|
|
22890
|
+
}
|
|
22891
|
+
var OP_STACK_GAS_PRICE_ORACLE = "0x420000000000000000000000000000000000000F";
|
|
22892
|
+
var OP_STACK_CHAIN_IDS = /* @__PURE__ */ new Set([8453]);
|
|
22893
|
+
async function evmGasPrecheck({
|
|
22894
|
+
client,
|
|
22895
|
+
chainId,
|
|
22896
|
+
from: from15,
|
|
22897
|
+
to,
|
|
22898
|
+
data,
|
|
22899
|
+
value = 0n,
|
|
22900
|
+
bufferPct = gasBufferPct(),
|
|
22901
|
+
estimateL1Fee: estimateL1Fee2 = null
|
|
22902
|
+
}) {
|
|
22903
|
+
const coin = EVM_FEE_COIN[Number(chainId)] ?? { symbol: "native coin", network: `chain ${chainId}` };
|
|
22904
|
+
let balance;
|
|
22905
|
+
try {
|
|
22906
|
+
balance = await client.getBalance({ address: from15 });
|
|
22907
|
+
} catch (err) {
|
|
22908
|
+
throw unavailable(coin.network, err);
|
|
22909
|
+
}
|
|
22910
|
+
let gasEstimate;
|
|
22911
|
+
let fees;
|
|
22912
|
+
try {
|
|
22913
|
+
gasEstimate = await client.estimateGas({ account: from15, to, data, value });
|
|
22914
|
+
fees = await estimateFees(client);
|
|
22915
|
+
} catch (err) {
|
|
22916
|
+
if (balance === 0n) {
|
|
22917
|
+
throw insufficient(
|
|
22918
|
+
assessFee({ balance, required: null, decimals: 18, symbol: coin.symbol, network: coin.network }).details
|
|
22919
|
+
);
|
|
22920
|
+
}
|
|
22921
|
+
throw unavailable(coin.network, err);
|
|
22922
|
+
}
|
|
22923
|
+
const req = evmFeeRequirement({
|
|
22924
|
+
gasEstimate,
|
|
22925
|
+
maxFeePerGas: fees?.maxFeePerGas,
|
|
22926
|
+
gasPrice: fees?.gasPrice,
|
|
22927
|
+
bufferPct
|
|
22928
|
+
});
|
|
22929
|
+
if (!req) throw unavailable(coin.network, new Error("the node returned no fee price"));
|
|
22930
|
+
let l1Fee = 0n;
|
|
22931
|
+
if (OP_STACK_CHAIN_IDS.has(Number(chainId))) {
|
|
22932
|
+
if (typeof estimateL1Fee2 !== "function") {
|
|
22933
|
+
throw unavailable(coin.network, new Error("no L1 data fee estimator for this OP-stack chain"));
|
|
22934
|
+
}
|
|
22935
|
+
try {
|
|
22936
|
+
l1Fee = (await estimateL1Fee2() * BigInt(100 + bufferPct) + 99n) / 100n;
|
|
22937
|
+
} catch (err) {
|
|
22938
|
+
throw unavailable(coin.network, err);
|
|
22939
|
+
}
|
|
22940
|
+
}
|
|
22941
|
+
const required = req.fee + l1Fee + value;
|
|
22942
|
+
const { ok, details } = assessFee({ balance, required, decimals: 18, symbol: coin.symbol, network: coin.network });
|
|
22943
|
+
const full = {
|
|
22944
|
+
...details,
|
|
22945
|
+
gasLimit: req.gasLimit.toString(),
|
|
22946
|
+
pricing: req.pricing,
|
|
22947
|
+
bufferPct,
|
|
22948
|
+
l1DataFee: OP_STACK_CHAIN_IDS.has(Number(chainId)) ? formatAtomic(l1Fee, 18) : null
|
|
22949
|
+
};
|
|
22950
|
+
if (!ok) throw insufficient(full);
|
|
22951
|
+
return full;
|
|
22952
|
+
}
|
|
22953
|
+
|
|
22954
|
+
// node_modules/viem/_esm/op-stack/contracts.js
|
|
22955
|
+
var contracts = {
|
|
22956
|
+
gasPriceOracle: { address: "0x420000000000000000000000000000000000000F" },
|
|
22957
|
+
l1Block: { address: "0x4200000000000000000000000000000000000015" },
|
|
22958
|
+
l2CrossDomainMessenger: {
|
|
22959
|
+
address: "0x4200000000000000000000000000000000000007"
|
|
22960
|
+
},
|
|
22961
|
+
l2Erc721Bridge: { address: "0x4200000000000000000000000000000000000014" },
|
|
22962
|
+
l2StandardBridge: { address: "0x4200000000000000000000000000000000000010" },
|
|
22963
|
+
l2ToL1MessagePasser: {
|
|
22964
|
+
address: "0x4200000000000000000000000000000000000016"
|
|
22965
|
+
}
|
|
22966
|
+
};
|
|
22967
|
+
|
|
22968
|
+
// node_modules/viem/_esm/op-stack/abis.js
|
|
22969
|
+
var gasPriceOracleAbi = [
|
|
22970
|
+
{ inputs: [], stateMutability: "nonpayable", type: "constructor" },
|
|
22971
|
+
{
|
|
22972
|
+
inputs: [],
|
|
22973
|
+
name: "DECIMALS",
|
|
22974
|
+
outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
|
|
22975
|
+
stateMutability: "view",
|
|
22976
|
+
type: "function"
|
|
22977
|
+
},
|
|
22978
|
+
{
|
|
22979
|
+
inputs: [],
|
|
22980
|
+
name: "baseFee",
|
|
22981
|
+
outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
|
|
22982
|
+
stateMutability: "view",
|
|
22983
|
+
type: "function"
|
|
22984
|
+
},
|
|
22985
|
+
{
|
|
22986
|
+
inputs: [],
|
|
22987
|
+
name: "decimals",
|
|
22988
|
+
outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
|
|
22989
|
+
stateMutability: "pure",
|
|
22990
|
+
type: "function"
|
|
22991
|
+
},
|
|
22992
|
+
{
|
|
22993
|
+
inputs: [],
|
|
22994
|
+
name: "gasPrice",
|
|
22995
|
+
outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
|
|
22996
|
+
stateMutability: "view",
|
|
22997
|
+
type: "function"
|
|
22998
|
+
},
|
|
22999
|
+
{
|
|
23000
|
+
inputs: [{ internalType: "bytes", name: "_data", type: "bytes" }],
|
|
23001
|
+
name: "getL1Fee",
|
|
23002
|
+
outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
|
|
23003
|
+
stateMutability: "view",
|
|
23004
|
+
type: "function"
|
|
23005
|
+
},
|
|
23006
|
+
{
|
|
23007
|
+
inputs: [{ internalType: "bytes", name: "_data", type: "bytes" }],
|
|
23008
|
+
name: "getL1GasUsed",
|
|
23009
|
+
outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
|
|
23010
|
+
stateMutability: "view",
|
|
23011
|
+
type: "function"
|
|
23012
|
+
},
|
|
23013
|
+
{
|
|
23014
|
+
inputs: [],
|
|
23015
|
+
name: "l1BaseFee",
|
|
23016
|
+
outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
|
|
23017
|
+
stateMutability: "view",
|
|
23018
|
+
type: "function"
|
|
23019
|
+
},
|
|
23020
|
+
{
|
|
23021
|
+
inputs: [],
|
|
23022
|
+
name: "overhead",
|
|
23023
|
+
outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
|
|
23024
|
+
stateMutability: "view",
|
|
23025
|
+
type: "function"
|
|
23026
|
+
},
|
|
23027
|
+
{
|
|
23028
|
+
inputs: [],
|
|
23029
|
+
name: "scalar",
|
|
23030
|
+
outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
|
|
23031
|
+
stateMutability: "view",
|
|
23032
|
+
type: "function"
|
|
23033
|
+
},
|
|
23034
|
+
{
|
|
23035
|
+
inputs: [],
|
|
23036
|
+
name: "version",
|
|
23037
|
+
outputs: [{ internalType: "string", name: "", type: "string" }],
|
|
23038
|
+
stateMutability: "view",
|
|
23039
|
+
type: "function"
|
|
23040
|
+
}
|
|
23041
|
+
];
|
|
23042
|
+
|
|
23043
|
+
// node_modules/viem/_esm/op-stack/actions/estimateL1Fee.js
|
|
23044
|
+
init_getChainContractAddress();
|
|
23045
|
+
async function estimateL1Fee(client, args) {
|
|
23046
|
+
const { chain = client.chain, gasPriceOracleAddress: gasPriceOracleAddress_ } = args;
|
|
23047
|
+
const gasPriceOracleAddress = (() => {
|
|
23048
|
+
if (gasPriceOracleAddress_)
|
|
23049
|
+
return gasPriceOracleAddress_;
|
|
23050
|
+
if (chain)
|
|
23051
|
+
return getChainContractAddress({
|
|
23052
|
+
chain,
|
|
23053
|
+
contract: "gasPriceOracle"
|
|
23054
|
+
});
|
|
23055
|
+
return contracts.gasPriceOracle.address;
|
|
23056
|
+
})();
|
|
23057
|
+
const transaction = serializeTransaction({
|
|
23058
|
+
...args,
|
|
23059
|
+
chainId: chain?.id ?? 1,
|
|
23060
|
+
type: "eip1559",
|
|
23061
|
+
// Set upper-limit-ish stub values. Shouldn't affect the estimate too much as we are
|
|
23062
|
+
// tweaking dust bytes here (as opposed to long `data` bytes).
|
|
23063
|
+
// See: https://github.com/ethereum-optimism/optimism/blob/54d02df55523c9e1b4b38ed082c12a42087323a0/packages/contracts-bedrock/src/L2/GasPriceOracle.sol#L242-L248.
|
|
23064
|
+
gas: args.data ? 300000n : 21000n,
|
|
23065
|
+
maxFeePerGas: parseGwei("5"),
|
|
23066
|
+
maxPriorityFeePerGas: parseGwei("1"),
|
|
23067
|
+
nonce: 1
|
|
23068
|
+
});
|
|
23069
|
+
return readContract(client, {
|
|
23070
|
+
abi: gasPriceOracleAbi,
|
|
23071
|
+
address: gasPriceOracleAddress,
|
|
23072
|
+
functionName: "getL1Fee",
|
|
23073
|
+
args: [transaction]
|
|
23074
|
+
});
|
|
23075
|
+
}
|
|
23076
|
+
|
|
22805
23077
|
// node_modules/viem/_esm/accounts/privateKeyToAccount.js
|
|
22806
23078
|
init_secp256k1();
|
|
22807
23079
|
init_toHex();
|
|
@@ -23073,6 +23345,25 @@ async function main(argv) {
|
|
|
23073
23345
|
`Sender holds ${balance} atomic units of ${source.tokenSymbol} on ${chainName(chainId)}; ${amountAtomic} are required.`
|
|
23074
23346
|
);
|
|
23075
23347
|
}
|
|
23348
|
+
const data = encodeFunctionData({
|
|
23349
|
+
abi: ERC20_TRANSFER_ABI,
|
|
23350
|
+
functionName: "transfer",
|
|
23351
|
+
args: [to, amountAtomic]
|
|
23352
|
+
});
|
|
23353
|
+
const networkFee = await evmGasPrecheck({
|
|
23354
|
+
client: pub,
|
|
23355
|
+
chainId,
|
|
23356
|
+
from: sender,
|
|
23357
|
+
to: tokenAddress,
|
|
23358
|
+
data,
|
|
23359
|
+
estimateL1Fee: OP_STACK_CHAIN_IDS.has(chainId) ? () => estimateL1Fee(pub, {
|
|
23360
|
+
account: sender,
|
|
23361
|
+
to: tokenAddress,
|
|
23362
|
+
data,
|
|
23363
|
+
chain,
|
|
23364
|
+
gasPriceOracleAddress: OP_STACK_GAS_PRICE_ORACLE
|
|
23365
|
+
}) : null
|
|
23366
|
+
});
|
|
23076
23367
|
if (dryRun) {
|
|
23077
23368
|
emit({
|
|
23078
23369
|
success: true,
|
|
@@ -23088,6 +23379,7 @@ async function main(argv) {
|
|
|
23088
23379
|
toMasked: maskAddress(to),
|
|
23089
23380
|
fromMasked: maskAddress(sender)
|
|
23090
23381
|
},
|
|
23382
|
+
networkFee,
|
|
23091
23383
|
confirmedAt: state.confirmation?.confirmedAt ?? null,
|
|
23092
23384
|
keySource,
|
|
23093
23385
|
// Key NAMES only — a value from a .env is never echoed.
|
|
@@ -23097,11 +23389,6 @@ async function main(argv) {
|
|
|
23097
23389
|
});
|
|
23098
23390
|
}
|
|
23099
23391
|
const wallet = createWalletClient({ account, chain, transport: http(rpcUrl) });
|
|
23100
|
-
const data = encodeFunctionData({
|
|
23101
|
-
abi: ERC20_TRANSFER_ABI,
|
|
23102
|
-
functionName: "transfer",
|
|
23103
|
-
args: [to, amountAtomic]
|
|
23104
|
-
});
|
|
23105
23392
|
const request2 = await wallet.prepareTransactionRequest({
|
|
23106
23393
|
to: tokenAddress,
|
|
23107
23394
|
data,
|
|
@@ -23160,7 +23447,7 @@ async function main(argv) {
|
|
|
23160
23447
|
code: landed === false ? "BROADCAST_FAILED" : "BROADCAST_AMBIGUOUS",
|
|
23161
23448
|
message: redact(err?.shortMessage || err?.message || "broadcast failed")
|
|
23162
23449
|
},
|
|
23163
|
-
signedTxHash: expectedTxHash,
|
|
23450
|
+
signedTxHash: publicHash(expectedTxHash),
|
|
23164
23451
|
nonceBefore,
|
|
23165
23452
|
foundOnChain: landed,
|
|
23166
23453
|
guidance: landed === false ? "Nothing appears to have been broadcast, but this order is now locked against a second automated send. Verify the signed hash on a block explorer first." : "The signed transaction may already be in flight. Do NOT resend. Look up the signed hash above on a block explorer and poll status.js."
|
|
@@ -23184,7 +23471,7 @@ async function main(argv) {
|
|
|
23184
23471
|
confirmed: false,
|
|
23185
23472
|
rozoPaymentId,
|
|
23186
23473
|
linkId: state.linkId,
|
|
23187
|
-
txHash,
|
|
23474
|
+
txHash: publicHash(txHash),
|
|
23188
23475
|
guidance: "Broadcast but not confirmed within the wait window. Do NOT resend. Poll status.js; receipt truth is the backend confirmedAt/amountReceived, not this response."
|
|
23189
23476
|
},
|
|
23190
23477
|
EXIT_UNCONFIRMED
|
|
@@ -23205,7 +23492,7 @@ async function main(argv) {
|
|
|
23205
23492
|
confirmed: succeeded,
|
|
23206
23493
|
rozoPaymentId,
|
|
23207
23494
|
linkId: state.linkId,
|
|
23208
|
-
txHash,
|
|
23495
|
+
txHash: publicHash(txHash),
|
|
23209
23496
|
blockNumber: receipt.blockNumber?.toString?.() ?? null,
|
|
23210
23497
|
...succeeded ? {} : { error: { code: outcome.code, message: "The transfer reverted on chain." } },
|
|
23211
23498
|
sent: {
|