@subly_fi/pay 0.4.1 → 0.6.0
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 +18 -6
- package/dist/cli.js +4 -2
- package/dist/deposit.js +192 -11
- package/dist/mcp-server.js +428 -35
- package/dist/pay.js +268 -21
- package/dist/setup-link.js +1494 -0
- package/dist/setup-status.js +27 -0
- package/dist/withdraw.js +175 -11
- package/package.json +2 -2
package/dist/pay.js
CHANGED
|
@@ -1083,14 +1083,18 @@ async function fetchLookupTablesForTransaction(rpc2, serializedTransaction) {
|
|
|
1083
1083
|
|
|
1084
1084
|
// ../../src/client/vault-flows.ts
|
|
1085
1085
|
var VaultFlowClientError = class extends Error {
|
|
1086
|
-
constructor(step, message, detail = null) {
|
|
1086
|
+
constructor(step, message, detail = null, code = null, errorDetails = null) {
|
|
1087
1087
|
super(message);
|
|
1088
1088
|
this.step = step;
|
|
1089
1089
|
this.detail = detail;
|
|
1090
|
+
this.code = code;
|
|
1091
|
+
this.errorDetails = errorDetails;
|
|
1090
1092
|
this.name = "VaultFlowClientError";
|
|
1091
1093
|
}
|
|
1092
1094
|
step;
|
|
1093
1095
|
detail;
|
|
1096
|
+
code;
|
|
1097
|
+
errorDetails;
|
|
1094
1098
|
};
|
|
1095
1099
|
var VaultFlowClient = class {
|
|
1096
1100
|
baseUrl;
|
|
@@ -1107,12 +1111,37 @@ var VaultFlowClient = class {
|
|
|
1107
1111
|
this.pollTimeoutMs = config.pollTimeoutMs ?? 9e4;
|
|
1108
1112
|
this.pollIntervalMs = config.pollIntervalMs ?? 2500;
|
|
1109
1113
|
}
|
|
1110
|
-
/**
|
|
1114
|
+
/**
|
|
1115
|
+
* Moves USDC from the agent wallet into the vault (fee sponsored). Under
|
|
1116
|
+
* depositPolicy "owner_approval_required" the relayer refuses to prepare
|
|
1117
|
+
* without an owner approval; when the caller passes none, an already
|
|
1118
|
+
* APPROVED deposit approval for this exact amount (e.g. the mandate's
|
|
1119
|
+
* initialDeposit — "one Face ID covers mandate + first deposit") is looked
|
|
1120
|
+
* up and used automatically before surfacing deposit_approval_required.
|
|
1121
|
+
*/
|
|
1111
1122
|
async deposit(input) {
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1123
|
+
let approvalId2 = input.approvalId;
|
|
1124
|
+
let prepared;
|
|
1125
|
+
try {
|
|
1126
|
+
prepared = await this.postJson("prepare", "/v1/deposits/prepare", {
|
|
1127
|
+
wallet: this.signer.walletAddress,
|
|
1128
|
+
amountRawUsdc: input.amountRawUsdc.toString(),
|
|
1129
|
+
...approvalId2 === void 0 ? {} : { approvalId: approvalId2 }
|
|
1130
|
+
});
|
|
1131
|
+
} catch (error) {
|
|
1132
|
+
if (!(error instanceof VaultFlowClientError) || error.code !== "deposit_approval_required" || approvalId2 !== void 0) {
|
|
1133
|
+
throw error;
|
|
1134
|
+
}
|
|
1135
|
+
approvalId2 = await this.findApprovedDepositApproval(input.amountRawUsdc);
|
|
1136
|
+
if (approvalId2 === void 0) {
|
|
1137
|
+
throw error;
|
|
1138
|
+
}
|
|
1139
|
+
prepared = await this.postJson("prepare", "/v1/deposits/prepare", {
|
|
1140
|
+
wallet: this.signer.walletAddress,
|
|
1141
|
+
amountRawUsdc: input.amountRawUsdc.toString(),
|
|
1142
|
+
approvalId: approvalId2
|
|
1143
|
+
});
|
|
1144
|
+
}
|
|
1116
1145
|
const signed = await this.signer.signDeposit({
|
|
1117
1146
|
intent: prepared.signingIntent,
|
|
1118
1147
|
serializedTransaction: prepared.serializedTransaction,
|
|
@@ -1151,7 +1180,9 @@ var VaultFlowClient = class {
|
|
|
1151
1180
|
{
|
|
1152
1181
|
wallet: this.signer.walletAddress,
|
|
1153
1182
|
amountRawUsdc: input.amountRawUsdc.toString(),
|
|
1154
|
-
...input.purpose === void 0 ? {} : { purpose: input.purpose }
|
|
1183
|
+
...input.purpose === void 0 ? {} : { purpose: input.purpose },
|
|
1184
|
+
...input.payment === void 0 ? {} : { payment: input.payment },
|
|
1185
|
+
...input.approvalId === void 0 ? {} : { approvalId: input.approvalId }
|
|
1155
1186
|
}
|
|
1156
1187
|
);
|
|
1157
1188
|
const signed = await this.signer.signWithdrawal({
|
|
@@ -1230,6 +1261,70 @@ var VaultFlowClient = class {
|
|
|
1230
1261
|
spendableYieldRawUsdc: body2.budget?.spendableYieldRawUsdc ?? "0"
|
|
1231
1262
|
};
|
|
1232
1263
|
}
|
|
1264
|
+
/** Best-effort audit link: reports the x402 payment tx a realize funded. */
|
|
1265
|
+
async reportPayment(input) {
|
|
1266
|
+
await this.postJson("submit", "/v1/payments/report", {
|
|
1267
|
+
wallet: this.signer.walletAddress,
|
|
1268
|
+
withdrawalId: input.withdrawalId,
|
|
1269
|
+
paymentTxSignature: input.paymentTxSignature
|
|
1270
|
+
});
|
|
1271
|
+
}
|
|
1272
|
+
/** Wallet's approvals as the relayer sees them (optionally by status). */
|
|
1273
|
+
async listApprovals(status) {
|
|
1274
|
+
const body2 = await this.getJson(
|
|
1275
|
+
`/v1/wallets/${this.signer.walletAddress}/approvals${status === void 0 ? "" : `?status=${encodeURIComponent(status)}`}`
|
|
1276
|
+
);
|
|
1277
|
+
return body2.approvals ?? [];
|
|
1278
|
+
}
|
|
1279
|
+
/**
|
|
1280
|
+
* Creates the owner-onboarding setup link (wallet-auth pins the agreed
|
|
1281
|
+
* policy + initial deposit). Paste `setupUrl` into the chat verbatim.
|
|
1282
|
+
*/
|
|
1283
|
+
async createSetupSession(input) {
|
|
1284
|
+
return await this.postJson(
|
|
1285
|
+
"prepare",
|
|
1286
|
+
`/v1/wallets/${this.signer.walletAddress}/setup-sessions`,
|
|
1287
|
+
{
|
|
1288
|
+
...input.policy === void 0 ? {} : { policy: input.policy },
|
|
1289
|
+
...input.enforcementMode === void 0 ? {} : { enforcementMode: input.enforcementMode },
|
|
1290
|
+
...input.mandateTtlDays === void 0 ? {} : { mandateTtlDays: input.mandateTtlDays },
|
|
1291
|
+
...input.initialDepositRawUsdc === void 0 ? {} : { initialDepositRawUsdc: input.initialDepositRawUsdc }
|
|
1292
|
+
}
|
|
1293
|
+
);
|
|
1294
|
+
}
|
|
1295
|
+
/** Polls a setup session (public capability URL — no auth needed). */
|
|
1296
|
+
async getSetupSession(sessionId) {
|
|
1297
|
+
const url2 = `${this.baseUrl}/v1/setup-sessions/${encodeURIComponent(sessionId)}`;
|
|
1298
|
+
const response = await this.fetchImpl(url2);
|
|
1299
|
+
const text = await response.text();
|
|
1300
|
+
if (response.status !== 200) {
|
|
1301
|
+
const parsed = parseRelayerError(text);
|
|
1302
|
+
throw new VaultFlowClientError(
|
|
1303
|
+
"read",
|
|
1304
|
+
parsed.message ?? `setup session read failed with ${response.status}`,
|
|
1305
|
+
text,
|
|
1306
|
+
parsed.code,
|
|
1307
|
+
parsed.details
|
|
1308
|
+
);
|
|
1309
|
+
}
|
|
1310
|
+
return JSON.parse(text);
|
|
1311
|
+
}
|
|
1312
|
+
/**
|
|
1313
|
+
* Finds an APPROVED, unconsumed deposit approval bound to exactly this
|
|
1314
|
+
* amount — the shape the mandate's initialDeposit approval has.
|
|
1315
|
+
*/
|
|
1316
|
+
async findApprovedDepositApproval(amountRawUsdc) {
|
|
1317
|
+
try {
|
|
1318
|
+
const approvals = await this.listApprovals("approved");
|
|
1319
|
+
const match = approvals.find((approval) => {
|
|
1320
|
+
const binding = approval.binding;
|
|
1321
|
+
return binding?.kind === "deposit" && binding.amountRawUsdc === amountRawUsdc.toString();
|
|
1322
|
+
});
|
|
1323
|
+
return match?.approvalId;
|
|
1324
|
+
} catch {
|
|
1325
|
+
return void 0;
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1233
1328
|
/**
|
|
1234
1329
|
* Polls the reconciling GET endpoint until the intent leaves "submitted"
|
|
1235
1330
|
* (each read looks the tx up on-chain) or the timeout elapses.
|
|
@@ -1279,10 +1374,13 @@ var VaultFlowClient = class {
|
|
|
1279
1374
|
});
|
|
1280
1375
|
const text = await response.text();
|
|
1281
1376
|
if (response.status !== 200) {
|
|
1377
|
+
const parsed = parseRelayerError(text);
|
|
1282
1378
|
throw new VaultFlowClientError(
|
|
1283
1379
|
step,
|
|
1284
|
-
`${path} failed with ${response.status}: ${text}`,
|
|
1285
|
-
text
|
|
1380
|
+
parsed.message === null ? `${path} failed with ${response.status}: ${text}` : `${path} failed (${parsed.code ?? response.status}): ${parsed.message}`,
|
|
1381
|
+
text,
|
|
1382
|
+
parsed.code,
|
|
1383
|
+
parsed.details
|
|
1286
1384
|
);
|
|
1287
1385
|
}
|
|
1288
1386
|
try {
|
|
@@ -1295,7 +1393,49 @@ var VaultFlowClient = class {
|
|
|
1295
1393
|
);
|
|
1296
1394
|
}
|
|
1297
1395
|
}
|
|
1396
|
+
async getJson(path) {
|
|
1397
|
+
const url2 = `${this.baseUrl}${path}`;
|
|
1398
|
+
const response = await this.fetchImpl(url2, {
|
|
1399
|
+
headers: await walletAuthHeaders({
|
|
1400
|
+
signer: this.signer,
|
|
1401
|
+
method: "GET",
|
|
1402
|
+
url: url2
|
|
1403
|
+
})
|
|
1404
|
+
});
|
|
1405
|
+
const text = await response.text();
|
|
1406
|
+
if (response.status !== 200) {
|
|
1407
|
+
const parsed = parseRelayerError(text);
|
|
1408
|
+
throw new VaultFlowClientError(
|
|
1409
|
+
"read",
|
|
1410
|
+
parsed.message === null ? `${path} failed with ${response.status}: ${text}` : `${path} failed (${parsed.code ?? response.status}): ${parsed.message}`,
|
|
1411
|
+
text,
|
|
1412
|
+
parsed.code,
|
|
1413
|
+
parsed.details
|
|
1414
|
+
);
|
|
1415
|
+
}
|
|
1416
|
+
try {
|
|
1417
|
+
return JSON.parse(text);
|
|
1418
|
+
} catch {
|
|
1419
|
+
throw new VaultFlowClientError(
|
|
1420
|
+
"read",
|
|
1421
|
+
`${path} returned 200 with a non-JSON body`,
|
|
1422
|
+
text
|
|
1423
|
+
);
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1298
1426
|
};
|
|
1427
|
+
function parseRelayerError(text) {
|
|
1428
|
+
try {
|
|
1429
|
+
const parsed = JSON.parse(text);
|
|
1430
|
+
return {
|
|
1431
|
+
code: typeof parsed.error?.code === "string" ? parsed.error.code : null,
|
|
1432
|
+
message: typeof parsed.error?.message === "string" ? parsed.error.message : null,
|
|
1433
|
+
details: parsed.error?.details ?? null
|
|
1434
|
+
};
|
|
1435
|
+
} catch {
|
|
1436
|
+
return { code: null, message: null, details: null };
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1299
1439
|
|
|
1300
1440
|
// ../../src/client/relayer-yield-realizer.ts
|
|
1301
1441
|
var REALIZE_OVERHEAD_RAW_USDC = 2500n;
|
|
@@ -1329,7 +1469,11 @@ var RelayerYieldRealizer = class {
|
|
|
1329
1469
|
amountRawUsdc: shortfallRawUsdc,
|
|
1330
1470
|
// The relayer refuses to prepare this withdrawal beyond the spendable
|
|
1331
1471
|
// yield — the principal-protection guard the client cannot bypass.
|
|
1332
|
-
purpose: "yield_realize"
|
|
1472
|
+
purpose: "yield_realize",
|
|
1473
|
+
// Declares what is being paid so the relayer's spending-mandate layer
|
|
1474
|
+
// can enforce caps/payee and keep the mandate → payment audit chain.
|
|
1475
|
+
...input.payment === void 0 ? {} : { payment: input.payment },
|
|
1476
|
+
...input.approvalId === void 0 ? {} : { approvalId: input.approvalId }
|
|
1333
1477
|
});
|
|
1334
1478
|
} catch (error) {
|
|
1335
1479
|
throw this.mapWithdrawError(error);
|
|
@@ -1343,9 +1487,18 @@ var RelayerYieldRealizer = class {
|
|
|
1343
1487
|
}
|
|
1344
1488
|
return {
|
|
1345
1489
|
realizedRawUsdc: BigInt(outcome.actualWithdrawRawUsdc ?? "0"),
|
|
1346
|
-
txSignature: outcome.txSignature
|
|
1490
|
+
txSignature: outcome.txSignature,
|
|
1491
|
+
withdrawalId: outcome.withdrawalId
|
|
1347
1492
|
};
|
|
1348
1493
|
}
|
|
1494
|
+
/**
|
|
1495
|
+
* Best-effort report-back of the x402 payment tx this realize funded —
|
|
1496
|
+
* closes the relayer's mandate → realize → payment audit chain. Callers
|
|
1497
|
+
* must never let a failure here affect the payment result.
|
|
1498
|
+
*/
|
|
1499
|
+
async reportPayment(input) {
|
|
1500
|
+
await this.vaultFlows.reportPayment(input);
|
|
1501
|
+
}
|
|
1349
1502
|
/**
|
|
1350
1503
|
* Refuses to realize more than the ledger's spendable yield (principal).
|
|
1351
1504
|
* getBudget syncs the relayer's ledger from chain first (best-effort), so a
|
|
@@ -1380,7 +1533,14 @@ var RelayerYieldRealizer = class {
|
|
|
1380
1533
|
error
|
|
1381
1534
|
);
|
|
1382
1535
|
}
|
|
1383
|
-
const serverCode = errorCodeFrom(error.detail);
|
|
1536
|
+
const serverCode = error.code ?? errorCodeFrom(error.detail);
|
|
1537
|
+
if (serverCode === "approval_required") {
|
|
1538
|
+
return new RelayerRealizeError(
|
|
1539
|
+
"approval_required",
|
|
1540
|
+
"this payment exceeds the owner-approval threshold; nothing was realized or paid. Ask the owner to approve, then retry with the approvalId",
|
|
1541
|
+
error.errorDetails ?? error.detail
|
|
1542
|
+
);
|
|
1543
|
+
}
|
|
1384
1544
|
if (serverCode === "insufficient_yield" || serverCode === "post_state_principal_invariant_failed") {
|
|
1385
1545
|
return new RelayerRealizeError(
|
|
1386
1546
|
"insufficient_yield",
|
|
@@ -1407,6 +1567,12 @@ function errorCodeFrom(detail) {
|
|
|
1407
1567
|
}
|
|
1408
1568
|
}
|
|
1409
1569
|
|
|
1570
|
+
// ../../src/lib/canonical-json.ts
|
|
1571
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
1572
|
+
function sha256HexOf(data) {
|
|
1573
|
+
return createHash4("sha256").update(data, "utf8").digest("hex");
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1410
1576
|
// ../../src/x402/headers.ts
|
|
1411
1577
|
import { z } from "zod";
|
|
1412
1578
|
var PAYMENT_REQUIRED_HEADER = "payment-required";
|
|
@@ -1547,20 +1713,36 @@ function decodeStandardPaymentRequiredHeader(headerValue) {
|
|
|
1547
1713
|
function selectPayableSolanaRequirement(requirements, options) {
|
|
1548
1714
|
const network = options?.network ?? SOLANA_MAINNET_NETWORK;
|
|
1549
1715
|
const usdcMint = options?.usdcMint ?? SUBLY_VAULT.usdcMint;
|
|
1550
|
-
const
|
|
1716
|
+
const matchingRequirements = requirements.filter(
|
|
1551
1717
|
(candidate) => candidate.network === network && candidate.asset === usdcMint
|
|
1552
|
-
)
|
|
1553
|
-
if (
|
|
1718
|
+
);
|
|
1719
|
+
if (matchingRequirements.length === 0) {
|
|
1554
1720
|
throw new StandardX402ChallengeError(
|
|
1555
1721
|
"no_payable_requirement",
|
|
1556
1722
|
`The challenge has no Solana exact requirement on ${network} paying ${usdcMint}`
|
|
1557
1723
|
);
|
|
1558
1724
|
}
|
|
1725
|
+
const requirement = matchingRequirements.find(
|
|
1726
|
+
(candidate) => candidate.extra?.feePayer !== void 0
|
|
1727
|
+
) ?? null;
|
|
1728
|
+
if (requirement === null) {
|
|
1729
|
+
throw new StandardX402ChallengeError(
|
|
1730
|
+
"missing_svm_fee_payer",
|
|
1731
|
+
"The Solana exact requirement does not include extra.feePayer, which the official @x402/svm client requires for gas sponsorship"
|
|
1732
|
+
);
|
|
1733
|
+
}
|
|
1734
|
+
const feePayer = requirement.extra?.feePayer;
|
|
1735
|
+
if (feePayer === void 0) {
|
|
1736
|
+
throw new StandardX402ChallengeError(
|
|
1737
|
+
"missing_svm_fee_payer",
|
|
1738
|
+
"The Solana exact requirement does not include extra.feePayer, which the official @x402/svm client requires for gas sponsorship"
|
|
1739
|
+
);
|
|
1740
|
+
}
|
|
1559
1741
|
return {
|
|
1560
1742
|
requirement,
|
|
1561
1743
|
amountRawUsdc: BigInt(requirement.amount),
|
|
1562
1744
|
payTo: requirement.payTo,
|
|
1563
|
-
feePayer
|
|
1745
|
+
feePayer
|
|
1564
1746
|
};
|
|
1565
1747
|
}
|
|
1566
1748
|
function standardRequirementMatchesSelected(candidate, selected) {
|
|
@@ -1683,9 +1865,23 @@ var StandardX402Payer = class {
|
|
|
1683
1865
|
let realized;
|
|
1684
1866
|
try {
|
|
1685
1867
|
realized = await this.realizer.ensureUsdcAvailable({
|
|
1686
|
-
amountRawUsdc: selected.amountRawUsdc
|
|
1868
|
+
amountRawUsdc: selected.amountRawUsdc,
|
|
1869
|
+
payment: {
|
|
1870
|
+
payTo: selected.payTo,
|
|
1871
|
+
amountRawUsdc: selected.amountRawUsdc.toString(),
|
|
1872
|
+
resourceUrlHash: sha256HexOf(input.url),
|
|
1873
|
+
method: method2
|
|
1874
|
+
},
|
|
1875
|
+
...input.approvalId === void 0 ? {} : { approvalId: input.approvalId }
|
|
1687
1876
|
});
|
|
1688
1877
|
} catch (error) {
|
|
1878
|
+
if (error.code === "approval_required") {
|
|
1879
|
+
throw new StandardX402PayError(
|
|
1880
|
+
"approval_required",
|
|
1881
|
+
"this payment exceeds the owner-approval threshold; NOTHING was paid. Ask the owner to open the approveUrl, then retry the same call with the approvalId",
|
|
1882
|
+
error.detail ?? null
|
|
1883
|
+
);
|
|
1884
|
+
}
|
|
1689
1885
|
throw new StandardX402PayError(
|
|
1690
1886
|
"realize_failed",
|
|
1691
1887
|
`could not realize yield to cover ${selected.amountRawUsdc} raw USDC: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -1741,6 +1937,19 @@ var StandardX402Payer = class {
|
|
|
1741
1937
|
);
|
|
1742
1938
|
}
|
|
1743
1939
|
this.clearDelivered(pendingKey);
|
|
1940
|
+
const paymentTxSignature = extractSettledPaymentTxSignature(response);
|
|
1941
|
+
if (paymentTxSignature !== null && typeof realized.withdrawalId === "string" && this.realizer.reportPayment !== void 0) {
|
|
1942
|
+
try {
|
|
1943
|
+
await this.realizer.reportPayment({
|
|
1944
|
+
withdrawalId: realized.withdrawalId,
|
|
1945
|
+
paymentTxSignature
|
|
1946
|
+
});
|
|
1947
|
+
} catch (error) {
|
|
1948
|
+
console.error(
|
|
1949
|
+
`[subly-x402] payment report-back failed (audit only, payment ok): ${error instanceof Error ? error.message : String(error)}`
|
|
1950
|
+
);
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1744
1953
|
return {
|
|
1745
1954
|
paid: true,
|
|
1746
1955
|
status: response.status,
|
|
@@ -1750,7 +1959,8 @@ var StandardX402Payer = class {
|
|
|
1750
1959
|
payTo: selected.payTo,
|
|
1751
1960
|
feePayer: selected.feePayer,
|
|
1752
1961
|
realizedRawUsdc: realized.realizedRawUsdc.toString(),
|
|
1753
|
-
realizeTxSignature: realized.txSignature
|
|
1962
|
+
realizeTxSignature: realized.txSignature,
|
|
1963
|
+
paymentTxSignature
|
|
1754
1964
|
}
|
|
1755
1965
|
};
|
|
1756
1966
|
}
|
|
@@ -1864,6 +2074,26 @@ var StandardX402Payer = class {
|
|
|
1864
2074
|
function pendingPaymentKey(input) {
|
|
1865
2075
|
return `${input.method}:${input.url}:${input.requestBodyHash}`;
|
|
1866
2076
|
}
|
|
2077
|
+
function extractSettledPaymentTxSignature(response) {
|
|
2078
|
+
const header = response.headers.get("x-payment-response");
|
|
2079
|
+
if (header === null || header.length === 0) {
|
|
2080
|
+
return null;
|
|
2081
|
+
}
|
|
2082
|
+
try {
|
|
2083
|
+
const decoded = JSON.parse(
|
|
2084
|
+
Buffer.from(header, "base64").toString("utf8")
|
|
2085
|
+
);
|
|
2086
|
+
if (typeof decoded.transaction === "string" && decoded.transaction.length > 0) {
|
|
2087
|
+
return decoded.transaction;
|
|
2088
|
+
}
|
|
2089
|
+
if (typeof decoded.txHash === "string" && decoded.txHash.length > 0) {
|
|
2090
|
+
return decoded.txHash;
|
|
2091
|
+
}
|
|
2092
|
+
return null;
|
|
2093
|
+
} catch {
|
|
2094
|
+
return null;
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
1867
2097
|
|
|
1868
2098
|
// ../../src/client/relayer-payer.ts
|
|
1869
2099
|
function createRelayerX402Payer(config) {
|
|
@@ -2021,9 +2251,20 @@ function fail(message) {
|
|
|
2021
2251
|
}
|
|
2022
2252
|
var url = process.argv[2];
|
|
2023
2253
|
if (url === void 0 || !/^https?:\/\//.test(url)) {
|
|
2024
|
-
fail("Usage: pay fetch <url> [maxAmountRawUsdc]");
|
|
2254
|
+
fail("Usage: pay fetch <url> [maxAmountRawUsdc] [apr_<approvalId>]");
|
|
2255
|
+
}
|
|
2256
|
+
var maxAmountArg;
|
|
2257
|
+
var approvalId;
|
|
2258
|
+
for (const arg of process.argv.slice(3)) {
|
|
2259
|
+
if (/^apr_[0-9a-f]+$/i.test(arg)) {
|
|
2260
|
+
approvalId = arg;
|
|
2261
|
+
} else if (/^\d+$/.test(arg)) {
|
|
2262
|
+
maxAmountArg = arg;
|
|
2263
|
+
} else {
|
|
2264
|
+
fail(`unrecognized argument: ${arg}
|
|
2265
|
+
Usage: pay fetch <url> [maxAmountRawUsdc] [apr_<approvalId>]`);
|
|
2266
|
+
}
|
|
2025
2267
|
}
|
|
2026
|
-
var maxAmountArg = process.argv[3];
|
|
2027
2268
|
var relayerBaseUrl = process.env.SUBLY_RELAYER_URL ?? process.env.SUBLY_FACILITATOR_URL ?? "https://api.demo.sublyfi.com";
|
|
2028
2269
|
var rpcUrl = process.env.SOLANA_RPC_URL ?? "https://api.mainnet-beta.solana.com";
|
|
2029
2270
|
var defaultMaxAmountRawUsdc = process.env.SUBLY_MCP_MAX_AMOUNT_RAW_USDC === void 0 ? 10000n : BigInt(process.env.SUBLY_MCP_MAX_AMOUNT_RAW_USDC);
|
|
@@ -2064,6 +2305,7 @@ try {
|
|
|
2064
2305
|
...method === void 0 ? {} : { method },
|
|
2065
2306
|
...body === void 0 ? {} : { body, headers: { "content-type": "application/json" } },
|
|
2066
2307
|
...maxAmountArg === void 0 ? {} : { maxAmountRawUsdc: BigInt(maxAmountArg) },
|
|
2308
|
+
...approvalId === void 0 ? {} : { approvalId },
|
|
2067
2309
|
...process.env.SUBLY_PAY_FORCE_NEW_PAYMENT === "1" ? { forceNewPayment: true } : {}
|
|
2068
2310
|
});
|
|
2069
2311
|
process.stdout.write(`${JSON.stringify(result, null, 2)}
|
|
@@ -2075,7 +2317,12 @@ try {
|
|
|
2075
2317
|
if (error instanceof StandardX402PayError) {
|
|
2076
2318
|
process.stdout.write(
|
|
2077
2319
|
`${JSON.stringify(
|
|
2078
|
-
{
|
|
2320
|
+
{
|
|
2321
|
+
paid: false,
|
|
2322
|
+
reason: error.reason,
|
|
2323
|
+
message: error.message,
|
|
2324
|
+
detail: error.detail ?? null
|
|
2325
|
+
},
|
|
2079
2326
|
null,
|
|
2080
2327
|
2
|
|
2081
2328
|
)}
|