@piprail/sdk 2.15.0 → 2.15.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/CHANGELOG.md +73 -0
- package/README.md +1 -1
- package/dist/{algorand-CSEUTWNW.js → algorand-UF7BLBFN.js} +1 -1
- package/dist/{algorand-I2O24RSM.cjs → algorand-XGSWDMCZ.cjs} +32 -32
- package/dist/{aptos-GA5AEYYL.cjs → aptos-J2QSWHTO.cjs} +31 -31
- package/dist/{aptos-J7QGCWNW.js → aptos-KDLX42CR.js} +1 -1
- package/dist/{chunk-3FR22M3O.cjs → chunk-QONQSZHJ.cjs} +2 -2
- package/dist/{chunk-3ZWM3DKM.js → chunk-QU25LSVS.js} +2 -2
- package/dist/index.cjs +167 -181
- package/dist/index.js +35 -49
- package/dist/{near-NDQLGI4U.cjs → near-5LTTDU6G.cjs} +27 -27
- package/dist/{near-YA4Y4IGC.js → near-OLKCMTBI.js} +1 -1
- package/dist/{solana-OU6IUMQM.cjs → solana-S2T3JNR7.cjs} +32 -32
- package/dist/{solana-MB6G3OA5.js → solana-WO2G7WWZ.js} +1 -1
- package/dist/{stellar-RSNVOIKL.cjs → stellar-E2KWEV2E.cjs} +20 -20
- package/dist/{stellar-WDWSYOED.js → stellar-EUFZLX6J.js} +1 -1
- package/dist/{sui-GVSFNNJX.js → sui-KCIITCYH.js} +6 -2
- package/dist/{sui-MVC46BFJ.cjs → sui-Q3NJOJZS.cjs} +21 -17
- package/dist/{ton-MYOI3U3H.cjs → ton-J7TQWRN4.cjs} +16 -16
- package/dist/{ton-EJMGM3YI.js → ton-WH2JVQOO.js} +1 -1
- package/dist/{tron-VAPVMGJK.js → tron-FXBXDNEY.js} +1 -1
- package/dist/{tron-42X5N4GQ.cjs → tron-HIPMOX7S.cjs} +25 -25
- package/dist/{xrpl-Q2UWPCTJ.js → xrpl-6B2XOXGC.js} +1 -1
- package/dist/{xrpl-MGUBUNSZ.cjs → xrpl-VOUXIUYD.cjs} +20 -20
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,78 @@ All notable changes to `@piprail/sdk` are documented here. The format
|
|
|
4
4
|
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the
|
|
5
5
|
versions follow [Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [2.15.1] — 2026-08-28 — a dead Sui RPC, an RPC failure blamed on the token, and fuzz hardening
|
|
10
|
+
|
|
11
|
+
### Fixed — Sui's shipped default RPC was dead (whole-chain outage)
|
|
12
|
+
|
|
13
|
+
- **`chain: 'sui'` with no `rpcUrl` was 100% non-functional.** The preset shipped
|
|
14
|
+
`https://fullnode.mainnet.sui.io:443`, and Mysten has since **turned JSON-RPC off** on the
|
|
15
|
+
official public fullnodes — *every* method now answers `-32601 Method not found. JSON-RPC on
|
|
16
|
+
public fullnodes has been deprecated`, pointing at gRPC/GraphQL. Since `pay`, `verify`,
|
|
17
|
+
`balanceOf` and `recipientReady` all read through `SuiJsonRpcClient`, nothing on Sui worked
|
|
18
|
+
unless the caller passed their own endpoint. The default is now
|
|
19
|
+
`https://sui-rpc.publicnode.com`, verified for `suix_getBalance`, `suix_getCoinMetadata`,
|
|
20
|
+
`suix_getOwnedObjects` and `sui_getTransactionBlock`.
|
|
21
|
+
No unit test could catch this — they all mock the reader. Caught by the live wallet sweep,
|
|
22
|
+
which reads each driver's `defaultRpc` and does a real balance read; that sweep is now a
|
|
23
|
+
stage of the SDK audit so a dead default surfaces immediately.
|
|
24
|
+
|
|
25
|
+
### Fixed — the gate blamed the token when the RPC was at fault
|
|
26
|
+
|
|
27
|
+
- **A transient RPC failure was reported as "this token isn't EIP-3009".** `readExactDomain`
|
|
28
|
+
fails closed to `null` on two very different causes — the token genuinely isn't EIP-3009, or
|
|
29
|
+
the on-chain read failed (unreachable, rate-limited, or an HTML error page from a proxy) —
|
|
30
|
+
and the gate asserted the first. On Base USDC, which *is* EIP-3009, an unreachable RPC
|
|
31
|
+
produced `this token isn't EIP-3009 (auto-selected Permit2)`: the merchant's gasless rail
|
|
32
|
+
silently downgraded to `onchain-proof` (buyers start paying gas) and they were told to change
|
|
33
|
+
the one thing that was correct. The buyer side already retried once and named both causes;
|
|
34
|
+
the gate now does the same — a single 300 ms retry on the domain read, and a skip reason that
|
|
35
|
+
states both possibilities and how to tell them apart. Behaviour on a healthy RPC is unchanged.
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
### Fixed — hardening found by a new adversarial fuzz sweep
|
|
39
|
+
|
|
40
|
+
`test/fuzz-payment-paths.test.ts` generates thousands of hostile inputs per run against the
|
|
41
|
+
paths that decide "was I actually paid?", seeded so a failure reproduces exactly
|
|
42
|
+
(`FUZZ_SEED=<n>`). It found three things, all fixed here. No API changed; every existing
|
|
43
|
+
call keeps its behaviour.
|
|
44
|
+
|
|
45
|
+
- **A spent proof could be re-redeemed by padding its reference with whitespace.** The
|
|
46
|
+
gate's single-use key was case-folded (EVM hashes are case-insensitive hex) but not
|
|
47
|
+
trimmed, so ` 0xabc…`, `0xabc… ` and `\t0xabc…\n` each hashed to a *different* key than
|
|
48
|
+
`0xabc…` and unlocked the resource a second time for one payment. The ref is now
|
|
49
|
+
canonicalised at the boundary, before the claim and before the driver sees it, so the
|
|
50
|
+
built-in store **and** a caller's custom `isUsed`/`markUsed` both receive one identical
|
|
51
|
+
value. Reaching this on a live EVM gate needed an RPC that accepts a padded hash — a real
|
|
52
|
+
one rejects it — so this was defence-in-depth rather than a known live exploit; the point
|
|
53
|
+
is that at-most-once no longer depends on how strict somebody else's RPC happens to be.
|
|
54
|
+
Six regression cases in `test/server-replay.test.ts`.
|
|
55
|
+
- **`parseUnits` threw a bare `Error`** on the single most likely amount mistake there is —
|
|
56
|
+
pricing at more decimal places than the token has — while its two other rejection branches
|
|
57
|
+
threw `InvalidConfigError`. A caller branching on `err instanceof PipRailError`
|
|
58
|
+
(ERRORS.md §1) missed exactly that case. Now typed, as is the malformed-amount branch of
|
|
59
|
+
`floorUnits`.
|
|
60
|
+
- **The header builders threw a raw `TypeError`** when handed a value `JSON.stringify`
|
|
61
|
+
cannot serialise — a `BigInt` most obviously, and amounts are `bigint` everywhere *inside*
|
|
62
|
+
the SDK, so passing one out is a natural slip. `buildSignatureHeader`,
|
|
63
|
+
`buildExactSignatureHeader` and their siblings now throw `InvalidConfigError` with a
|
|
64
|
+
message that names the fix.
|
|
65
|
+
|
|
66
|
+
### Changed — facilitator registry hygiene
|
|
67
|
+
|
|
68
|
+
- **Two dead facilitators removed** (see 2.14.2): the docs, the website data and a live
|
|
69
|
+
example probe were still advertising them after the registry was corrected. A new
|
|
70
|
+
cross-surface guard (`test/facilitators-surface.test.ts`) now holds all of them to
|
|
71
|
+
`KNOWN_FACILITATORS` — a dead host may appear only inside an explanation of its removal,
|
|
72
|
+
the docs' copy-paste URL list is set-compared against the registry, and the website's
|
|
73
|
+
generated data must match the registry's networks **and URL order** (that order is what
|
|
74
|
+
`firstKeylessFacilitator` returns).
|
|
75
|
+
- All **25** settlement hashes recorded in the registry's notes were re-verified on-chain on
|
|
76
|
+
2026-08-28 — 25/25 present and successful, 0 refuted — by
|
|
77
|
+
`.claude/skills/facilitator-probe/scripts/verify-tx.mjs`.
|
|
78
|
+
|
|
7
79
|
## [2.15.0] — 2026-06-24 — merchant on-ramp: presets, adapters, `gate.selfTest()`
|
|
8
80
|
|
|
9
81
|
### Added — merchant on-ramp (presets, adapters, self-test)
|
|
@@ -1852,6 +1924,7 @@ straight into your wallet. The API is small and self-contained.
|
|
|
1852
1924
|
to your wallet; PipRail never holds funds.
|
|
1853
1925
|
- `viem ^2.21` is a peer dependency. Node 20+ or a modern browser.
|
|
1854
1926
|
|
|
1927
|
+
[2.15.1]: https://www.npmjs.com/package/@piprail/sdk
|
|
1855
1928
|
[2.15.0]: https://www.npmjs.com/package/@piprail/sdk
|
|
1856
1929
|
[2.14.0]: https://www.npmjs.com/package/@piprail/sdk
|
|
1857
1930
|
[2.13.1]: https://www.npmjs.com/package/@piprail/sdk
|
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ app.get('/report',
|
|
|
26
26
|
|
|
27
27
|
That route now costs **0.05 USDC on Base**, paid straight to your wallet. One parameter picks the chain. Add `onPaid` / `onFailed` to be notified the moment a payment settles or is rejected — both carry the same reason, and the buyer's client is notified too. → [Accepting payments](https://docs.piprail.com/accepting-payments/require-payment-and-gate/)
|
|
28
28
|
|
|
29
|
-
> **Don't want to wire it by hand?** `npm create piprail
|
|
29
|
+
> **Don't want to wire it by hand?** `npm create @piprail` scaffolds a complete, mainnet-ready, deployable merchant (node / Cloudflare / Vercel) — paste a public address, no key, no account. → [Scaffold a merchant](https://docs.piprail.com/getting-started/scaffolder/)
|
|
30
30
|
|
|
31
31
|
## Let an agent pay for it
|
|
32
32
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
var
|
|
13
|
+
var _chunkQONQSZHJcjs = require('./chunk-QONQSZHJ.cjs');
|
|
14
14
|
|
|
15
15
|
// src/drivers/algorand/index.ts
|
|
16
16
|
var _algosdk = require('algosdk'); var _algosdk2 = _interopRequireDefault(_algosdk);
|
|
@@ -58,13 +58,13 @@ async function payAlgorand(params) {
|
|
|
58
58
|
} catch (err) {
|
|
59
59
|
const mapped = mapAlgorandError(err, accept.payTo);
|
|
60
60
|
if (mapped) throw mapped;
|
|
61
|
-
throw _nullishCoalesce(
|
|
61
|
+
throw _nullishCoalesce(_chunkQONQSZHJcjs.toInsufficientFundsError.call(void 0, err), () => ( err));
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
function mapAlgorandError(err, payTo) {
|
|
65
65
|
const m = err instanceof Error ? err.message : String(err);
|
|
66
66
|
if (/must optin/i.test(m) || /missing from/i.test(m) && m.includes(payTo)) {
|
|
67
|
-
return new (0,
|
|
67
|
+
return new (0, _chunkQONQSZHJcjs.RecipientNotReadyError)(
|
|
68
68
|
`Algorand recipient ${payTo} hasn't opted into this asset \u2014 it must opt in (a 0-amount asset transfer to itself) before it can receive. (Algorand: ${firstLine(m)})`,
|
|
69
69
|
{ cause: err }
|
|
70
70
|
);
|
|
@@ -72,7 +72,7 @@ function mapAlgorandError(err, payTo) {
|
|
|
72
72
|
if (/overspend|below min|min(imum)? balance|tried to spend|balance \d+ below|asset \d+ missing from|insufficient|underflow/i.test(
|
|
73
73
|
m
|
|
74
74
|
)) {
|
|
75
|
-
return new (0,
|
|
75
|
+
return new (0, _chunkQONQSZHJcjs.InsufficientFundsError)(
|
|
76
76
|
`Algorand payment failed: the sender can't cover it \u2014 token balance, ALGO for fees, the 0.1-ALGO minimum balance, or a missing asset opt-in on the sender. (Algorand: ${firstLine(m)})`,
|
|
77
77
|
{ cause: err }
|
|
78
78
|
);
|
|
@@ -99,33 +99,33 @@ function isSet(addr) {
|
|
|
99
99
|
function randomNote() {
|
|
100
100
|
const g = globalThis.crypto;
|
|
101
101
|
if (!_optionalChain([g, 'optionalAccess', _ => _.getRandomValues])) {
|
|
102
|
-
throw new (0,
|
|
102
|
+
throw new (0, _chunkQONQSZHJcjs.UnsupportedSchemeError)("Algorand exact: no Web Crypto CSPRNG available to generate a unique note.");
|
|
103
103
|
}
|
|
104
104
|
return g.getRandomValues(new Uint8Array(32));
|
|
105
105
|
}
|
|
106
106
|
async function payExactAlgorand(input) {
|
|
107
107
|
const { suggestedParams, sk, sender, accept } = input;
|
|
108
108
|
if (accept.asset === "native") {
|
|
109
|
-
throw new (0,
|
|
109
|
+
throw new (0, _chunkQONQSZHJcjs.UnsupportedSchemeError)(
|
|
110
110
|
"Algorand exact is ASA-only (an asset transfer); native ALGO is not exact-payable. Pay via onchain-proof."
|
|
111
111
|
);
|
|
112
112
|
}
|
|
113
113
|
const feePayer = accept.extra.feePayer;
|
|
114
114
|
if (!feePayer) {
|
|
115
|
-
throw new (0,
|
|
115
|
+
throw new (0, _chunkQONQSZHJcjs.UnsupportedSchemeError)("Algorand exact rail must advertise extra.feePayer (the fee sponsor address).");
|
|
116
116
|
}
|
|
117
117
|
const assetId = parseAlgorandAssetId(accept.asset);
|
|
118
118
|
if (assetId === null) {
|
|
119
|
-
throw new (0,
|
|
119
|
+
throw new (0, _chunkQONQSZHJcjs.UnsupportedSchemeError)(`Algorand exact rail asset "${accept.asset}" must be a numeric ASA id.`);
|
|
120
120
|
}
|
|
121
121
|
if (!_algosdk2.default.isValidAddress(feePayer)) {
|
|
122
|
-
throw new (0,
|
|
122
|
+
throw new (0, _chunkQONQSZHJcjs.UnsupportedSchemeError)(`Algorand exact: extra.feePayer "${feePayer}" is not a valid Algorand address.`);
|
|
123
123
|
}
|
|
124
124
|
if (!_algosdk2.default.isValidAddress(accept.payTo)) {
|
|
125
|
-
throw new (0,
|
|
125
|
+
throw new (0, _chunkQONQSZHJcjs.UnsupportedSchemeError)(`Algorand exact: payTo "${accept.payTo}" is not a valid Algorand address.`);
|
|
126
126
|
}
|
|
127
127
|
if (feePayer === sender) {
|
|
128
|
-
throw new (0,
|
|
128
|
+
throw new (0, _chunkQONQSZHJcjs.UnsupportedSchemeError)(
|
|
129
129
|
"Algorand exact: the fee payer must differ from the payer \u2014 the buyer must pay ZERO ALGO (the sponsor pays the pooled fee)."
|
|
130
130
|
);
|
|
131
131
|
}
|
|
@@ -172,13 +172,13 @@ function decodeElement(bytes) {
|
|
|
172
172
|
async function verifyAndSettleExactAlgorand(input) {
|
|
173
173
|
const { client, feePayerSk, feePayerAddr, payload, accept } = input;
|
|
174
174
|
const railFeePayer = accept.extra.feePayer;
|
|
175
|
-
if (!railFeePayer) throw new (0,
|
|
175
|
+
if (!railFeePayer) throw new (0, _chunkQONQSZHJcjs.SettlementError)("Algorand exact: rail is missing extra.feePayer.");
|
|
176
176
|
if (railFeePayer !== feePayerAddr) {
|
|
177
|
-
throw new (0,
|
|
177
|
+
throw new (0, _chunkQONQSZHJcjs.SettlementError)("Algorand exact: the gate relayer address does not match the rail extra.feePayer \u2014 misconfigured rail.");
|
|
178
178
|
}
|
|
179
179
|
const assetId = parseAlgorandAssetId(accept.asset);
|
|
180
|
-
if (assetId === null) throw new (0,
|
|
181
|
-
if (!_algosdk2.default.isValidAddress(accept.payTo)) throw new (0,
|
|
180
|
+
if (assetId === null) throw new (0, _chunkQONQSZHJcjs.SettlementError)(`Algorand exact: rail asset "${accept.asset}" is not a numeric ASA id.`);
|
|
181
|
+
if (!_algosdk2.default.isValidAddress(accept.payTo)) throw new (0, _chunkQONQSZHJcjs.SettlementError)(`Algorand exact: rail payTo "${accept.payTo}" is invalid.`);
|
|
182
182
|
const { paymentIndex, paymentGroup } = payload;
|
|
183
183
|
if (paymentGroup.length !== GROUP_SIZE) {
|
|
184
184
|
return fail("signature_invalid", `Algorand exact expects a ${GROUP_SIZE}-transaction group (payment + fee), got ${paymentGroup.length}.`);
|
|
@@ -244,7 +244,7 @@ async function verifyAndSettleExactAlgorand(input) {
|
|
|
244
244
|
try {
|
|
245
245
|
feeSigned = fee.signTxn(feePayerSk);
|
|
246
246
|
} catch (err) {
|
|
247
|
-
throw new (0,
|
|
247
|
+
throw new (0, _chunkQONQSZHJcjs.SettlementError)(`Algorand exact settle: the gate could not sign the fee transaction (${shorten(err instanceof Error ? err.message : String(err))}).`, { cause: err });
|
|
248
248
|
}
|
|
249
249
|
const signedGroup = elements.map((el, i) => i === paymentIndex ? payElement.raw : feeSigned);
|
|
250
250
|
try {
|
|
@@ -266,7 +266,7 @@ async function verifyAndSettleExactAlgorand(input) {
|
|
|
266
266
|
if (/signature|sig|auth|malformed/i.test(m)) return fail("signature_invalid", `Settle rejected \u2014 bad signature: ${shorten(m)}.`);
|
|
267
267
|
if (/already in ledger|already committed|duplicate/i.test(m)) return fail("tx_already_used", `This payment was already settled: ${shorten(m)}.`);
|
|
268
268
|
if (/\bround\b|expired|lifetime|stale|validity/i.test(m)) return fail("payment_expired", `Settle rejected \u2014 validity window expired: ${shorten(m)}.`);
|
|
269
|
-
throw new (0,
|
|
269
|
+
throw new (0, _chunkQONQSZHJcjs.SettlementError)(
|
|
270
270
|
`Algorand exact settle: the group failed to submit (${shorten(m)}). The buyer's signed transaction is still valid \u2014 fund/fix the fee payer (${railFeePayer}) and the buyer can re-present it.`,
|
|
271
271
|
{ cause: err }
|
|
272
272
|
);
|
|
@@ -275,10 +275,10 @@ async function verifyAndSettleExactAlgorand(input) {
|
|
|
275
275
|
try {
|
|
276
276
|
round = await client.waitForConfirmation(buyerTxid);
|
|
277
277
|
} catch (err) {
|
|
278
|
-
throw new (0,
|
|
278
|
+
throw new (0, _chunkQONQSZHJcjs.SettlementError)(`Algorand exact settle: submitted ${buyerTxid} but confirmation read failed (${shorten(err instanceof Error ? err.message : String(err))}). It likely landed \u2014 re-verify before re-presenting; do NOT re-pay.`, { cause: err });
|
|
279
279
|
}
|
|
280
280
|
if (round === null) {
|
|
281
|
-
throw new (0,
|
|
281
|
+
throw new (0, _chunkQONQSZHJcjs.SettlementError)(`Algorand exact settle: submitted ${buyerTxid} but it did not confirm in time. It likely landed \u2014 re-verify before re-presenting; do NOT re-pay.`);
|
|
282
282
|
}
|
|
283
283
|
return {
|
|
284
284
|
ok: true,
|
|
@@ -374,13 +374,13 @@ function rpcFailed(nonce) {
|
|
|
374
374
|
|
|
375
375
|
function assertAlgorandWallet(wallet, network) {
|
|
376
376
|
if (typeof wallet !== "object" || wallet === null) {
|
|
377
|
-
throw new (0,
|
|
377
|
+
throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)(
|
|
378
378
|
`chain ${network} is Algorand; wallet must be { key } (25-word mnemonic) or { account }.`
|
|
379
379
|
);
|
|
380
380
|
}
|
|
381
|
-
|
|
381
|
+
_chunkQONQSZHJcjs.assertNoLegacyWalletKey.call(void 0, wallet, "Algorand");
|
|
382
382
|
if (!("key" in wallet) && !("account" in wallet)) {
|
|
383
|
-
throw new (0,
|
|
383
|
+
throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)(
|
|
384
384
|
`chain ${network} is Algorand; wallet must be { key } (25-word mnemonic) or { account }.`
|
|
385
385
|
);
|
|
386
386
|
}
|
|
@@ -395,13 +395,13 @@ function resolveAlgorandWallet(config) {
|
|
|
395
395
|
const { addr, sk } = _algosdk2.default.mnemonicToSecretKey(config.key);
|
|
396
396
|
return { addr: addr.toString(), sk };
|
|
397
397
|
} catch (cause) {
|
|
398
|
-
throw new (0,
|
|
398
|
+
throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)(
|
|
399
399
|
"Algorand wallet { key } is not a valid 25-word Algorand mnemonic.",
|
|
400
400
|
{ cause }
|
|
401
401
|
);
|
|
402
402
|
}
|
|
403
403
|
}
|
|
404
|
-
throw new (0,
|
|
404
|
+
throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)("Algorand wallet needs { key } (25-word mnemonic) or { account }.");
|
|
405
405
|
}
|
|
406
406
|
|
|
407
407
|
// src/drivers/algorand/index.ts
|
|
@@ -472,16 +472,16 @@ function makeAlgorandNetwork(preset, algodUrl) {
|
|
|
472
472
|
const info = preset.tokens[token.toUpperCase()];
|
|
473
473
|
if (!info) {
|
|
474
474
|
const known = Object.keys(preset.tokens).join(", ") || "(none built in)";
|
|
475
|
-
throw new (0,
|
|
475
|
+
throw new (0, _chunkQONQSZHJcjs.UnknownTokenError)(
|
|
476
476
|
`token "${token}" isn't built in for Algorand (known: ${known}). Pass { assetId, decimals } for a custom ASA, or use 'native'.`
|
|
477
477
|
);
|
|
478
478
|
}
|
|
479
479
|
return { asset: algorandAssetId(info.assetId), decimals: info.decimals, symbol: info.symbol };
|
|
480
480
|
}
|
|
481
|
-
|
|
481
|
+
_chunkQONQSZHJcjs.rejectForeignToken.call(void 0, token, "algorand", network);
|
|
482
482
|
const t = token;
|
|
483
483
|
if (typeof t.assetId !== "number" || typeof t.decimals !== "number") {
|
|
484
|
-
throw new (0,
|
|
484
|
+
throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)(
|
|
485
485
|
`chain ${network} is Algorand; a custom token must be { assetId, decimals }.`
|
|
486
486
|
);
|
|
487
487
|
}
|
|
@@ -502,12 +502,12 @@ function makeAlgorandNetwork(preset, algodUrl) {
|
|
|
502
502
|
},
|
|
503
503
|
assertValidPayTo(payTo) {
|
|
504
504
|
if (payTo.startsWith("0x")) {
|
|
505
|
-
throw new (0,
|
|
505
|
+
throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)(
|
|
506
506
|
`chain ${network} is Algorand, but payTo "${payTo}" looks like an EVM address.`
|
|
507
507
|
);
|
|
508
508
|
}
|
|
509
509
|
if (!_algosdk2.default.isValidAddress(payTo)) {
|
|
510
|
-
throw new (0,
|
|
510
|
+
throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)(
|
|
511
511
|
`chain ${network} is Algorand, but payTo "${payTo}" is not a valid Algorand address.`
|
|
512
512
|
);
|
|
513
513
|
}
|
|
@@ -524,14 +524,14 @@ function makeAlgorandNetwork(preset, algodUrl) {
|
|
|
524
524
|
const info = await _algosdk2.default.waitForConfirmation(algod, ref, 10);
|
|
525
525
|
return { height: String(_nullishCoalesce(info.confirmedRound, () => ( 0))) };
|
|
526
526
|
} catch (err) {
|
|
527
|
-
throw new (0,
|
|
527
|
+
throw new (0, _chunkQONQSZHJcjs.ConfirmationTimeoutError)(`Algorand tx ${ref} did not confirm in time.`, {
|
|
528
528
|
cause: err
|
|
529
529
|
});
|
|
530
530
|
}
|
|
531
531
|
},
|
|
532
532
|
async estimateCost(accept) {
|
|
533
533
|
if (accept.scheme === "exact") {
|
|
534
|
-
return
|
|
534
|
+
return _chunkQONQSZHJcjs.nativeCost.call(void 0, {
|
|
535
535
|
symbol: ALGO_SYMBOL,
|
|
536
536
|
decimals: ALGO_DECIMALS,
|
|
537
537
|
fee: 0n,
|
|
@@ -539,7 +539,7 @@ function makeAlgorandNetwork(preset, algodUrl) {
|
|
|
539
539
|
detail: "gasless \u2014 the fee payer (facilitator/relayer) pools the group fee; the buyer pays 0 ALGO"
|
|
540
540
|
});
|
|
541
541
|
}
|
|
542
|
-
return
|
|
542
|
+
return _chunkQONQSZHJcjs.nativeCost.call(void 0, {
|
|
543
543
|
symbol: ALGO_SYMBOL,
|
|
544
544
|
decimals: ALGO_DECIMALS,
|
|
545
545
|
fee: 1000n,
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
var
|
|
12
|
+
var _chunkQONQSZHJcjs = require('./chunk-QONQSZHJ.cjs');
|
|
13
13
|
|
|
14
14
|
// src/drivers/aptos/index.ts
|
|
15
15
|
var _tssdk = require('@aptos-labs/ts-sdk');
|
|
@@ -58,14 +58,14 @@ async function payAptos(params) {
|
|
|
58
58
|
const res = await client.signSubmit({ signer, transaction });
|
|
59
59
|
return res.hash;
|
|
60
60
|
} catch (err) {
|
|
61
|
-
if (err instanceof
|
|
61
|
+
if (err instanceof _chunkQONQSZHJcjs.InsufficientFundsError) throw err;
|
|
62
62
|
if (isAptosAffordability(err)) {
|
|
63
|
-
throw new (0,
|
|
63
|
+
throw new (0, _chunkQONQSZHJcjs.InsufficientFundsError)(
|
|
64
64
|
err instanceof Error ? err.message : "Insufficient APT/token balance for the payment.",
|
|
65
65
|
{ cause: err }
|
|
66
66
|
);
|
|
67
67
|
}
|
|
68
|
-
throw _nullishCoalesce(
|
|
68
|
+
throw _nullishCoalesce(_chunkQONQSZHJcjs.toInsufficientFundsError.call(void 0, err), () => ( err));
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
function isAptosAffordability(err) {
|
|
@@ -103,24 +103,24 @@ function parseAddr(addr) {
|
|
|
103
103
|
async function payExactAptos(input) {
|
|
104
104
|
const { client, sender, accept } = input;
|
|
105
105
|
if (accept.asset === "native") {
|
|
106
|
-
throw new (0,
|
|
106
|
+
throw new (0, _chunkQONQSZHJcjs.UnsupportedSchemeError)(
|
|
107
107
|
"Aptos exact is Fungible-Asset only (a primary_fungible_store transfer); native APT is not exact-payable. Pay via onchain-proof."
|
|
108
108
|
);
|
|
109
109
|
}
|
|
110
110
|
const feePayer = accept.extra.feePayer;
|
|
111
111
|
if (!feePayer) {
|
|
112
|
-
throw new (0,
|
|
112
|
+
throw new (0, _chunkQONQSZHJcjs.UnsupportedSchemeError)("Aptos exact rail must advertise extra.feePayer (the gas sponsor address).");
|
|
113
113
|
}
|
|
114
114
|
const feePayerAddr = parseAddr(feePayer);
|
|
115
|
-
if (!feePayerAddr) throw new (0,
|
|
115
|
+
if (!feePayerAddr) throw new (0, _chunkQONQSZHJcjs.UnsupportedSchemeError)(`Aptos exact: extra.feePayer "${feePayer}" is not a valid Aptos address.`);
|
|
116
116
|
const payToAddr = parseAddr(accept.payTo);
|
|
117
|
-
if (!payToAddr) throw new (0,
|
|
117
|
+
if (!payToAddr) throw new (0, _chunkQONQSZHJcjs.UnsupportedSchemeError)(`Aptos exact: payTo "${accept.payTo}" is not a valid Aptos address.`);
|
|
118
118
|
const metadataAddr = parseAddr(accept.asset);
|
|
119
|
-
if (!metadataAddr) throw new (0,
|
|
119
|
+
if (!metadataAddr) throw new (0, _chunkQONQSZHJcjs.UnsupportedSchemeError)(`Aptos exact: asset "${accept.asset}" is not a valid FA metadata address.`);
|
|
120
120
|
const senderAddr = parseAddr(sender);
|
|
121
|
-
if (!senderAddr) throw new (0,
|
|
121
|
+
if (!senderAddr) throw new (0, _chunkQONQSZHJcjs.UnsupportedSchemeError)(`Aptos exact: payer "${sender}" is not a valid Aptos address.`);
|
|
122
122
|
if (feePayerAddr.equals(senderAddr)) {
|
|
123
|
-
throw new (0,
|
|
123
|
+
throw new (0, _chunkQONQSZHJcjs.UnsupportedSchemeError)(
|
|
124
124
|
"Aptos exact: the fee payer must differ from the payer \u2014 the buyer must pay ZERO APT (the sponsor pays gas)."
|
|
125
125
|
);
|
|
126
126
|
}
|
|
@@ -158,16 +158,16 @@ function argBytes(arg) {
|
|
|
158
158
|
async function verifyAndSettleExactAptos(input) {
|
|
159
159
|
const { client, feePayerAddr, payload, accept } = input;
|
|
160
160
|
const railFeePayer = accept.extra.feePayer;
|
|
161
|
-
if (!railFeePayer) throw new (0,
|
|
161
|
+
if (!railFeePayer) throw new (0, _chunkQONQSZHJcjs.SettlementError)("Aptos exact: rail is missing extra.feePayer.");
|
|
162
162
|
if (railFeePayer !== feePayerAddr) {
|
|
163
|
-
throw new (0,
|
|
163
|
+
throw new (0, _chunkQONQSZHJcjs.SettlementError)("Aptos exact: the gate relayer address does not match the rail extra.feePayer \u2014 misconfigured rail.");
|
|
164
164
|
}
|
|
165
|
-
if (accept.asset === "native") throw new (0,
|
|
165
|
+
if (accept.asset === "native") throw new (0, _chunkQONQSZHJcjs.SettlementError)("Aptos exact: native APT is not exact-payable (misconfigured rail).");
|
|
166
166
|
const railFeePayerAddr = parseAddr(railFeePayer);
|
|
167
167
|
const railPayTo = parseAddr(accept.payTo);
|
|
168
168
|
const railMetadata = parseAddr(accept.asset);
|
|
169
169
|
if (!railFeePayerAddr || !railPayTo || !railMetadata) {
|
|
170
|
-
throw new (0,
|
|
170
|
+
throw new (0, _chunkQONQSZHJcjs.SettlementError)("Aptos exact: rail feePayer/payTo/asset is not a valid Aptos address (misconfigured rail).");
|
|
171
171
|
}
|
|
172
172
|
let tx;
|
|
173
173
|
let senderAuth;
|
|
@@ -241,7 +241,7 @@ async function verifyAndSettleExactAptos(input) {
|
|
|
241
241
|
try {
|
|
242
242
|
feePayerAuth = client.signAsFeePayer({ transaction: tx });
|
|
243
243
|
} catch (err) {
|
|
244
|
-
throw new (0,
|
|
244
|
+
throw new (0, _chunkQONQSZHJcjs.SettlementError)(`Aptos exact settle: the gate could not sign as fee payer (${shorten(err instanceof Error ? err.message : String(err))}).`, { cause: err });
|
|
245
245
|
}
|
|
246
246
|
if (senderAuth instanceof _tssdk.AccountAuthenticatorEd25519) {
|
|
247
247
|
try {
|
|
@@ -264,7 +264,7 @@ async function verifyAndSettleExactAptos(input) {
|
|
|
264
264
|
if (/signature|invalid.*auth|INVALID_SIGNATURE/i.test(m)) return fail("signature_invalid", `Settle rejected \u2014 bad signature: ${shorten(m)}.`);
|
|
265
265
|
if (/SEQUENCE_NUMBER_TOO_OLD|already.*(committed|ledger)|duplicate/i.test(m)) return fail("tx_already_used", `This payment was already settled: ${shorten(m)}.`);
|
|
266
266
|
if (/EXPIRED|expired|TOO_NEW/i.test(m)) return fail("payment_expired", `Settle rejected \u2014 expired/stale: ${shorten(m)}.`);
|
|
267
|
-
throw new (0,
|
|
267
|
+
throw new (0, _chunkQONQSZHJcjs.SettlementError)(
|
|
268
268
|
`Aptos exact settle: the transaction failed to submit (${shorten(m)}). The buyer's signed transaction is still valid \u2014 fund/fix the fee payer (${railFeePayer}) and the buyer can re-present it.`,
|
|
269
269
|
{ cause: err }
|
|
270
270
|
);
|
|
@@ -273,10 +273,10 @@ async function verifyAndSettleExactAptos(input) {
|
|
|
273
273
|
try {
|
|
274
274
|
confirmed = await client.waitForConfirmation(hash);
|
|
275
275
|
} catch (err) {
|
|
276
|
-
throw new (0,
|
|
276
|
+
throw new (0, _chunkQONQSZHJcjs.SettlementError)(`Aptos exact settle: submitted ${hash} but confirmation read failed (${shorten(err instanceof Error ? err.message : String(err))}). It likely landed \u2014 re-verify before re-presenting; do NOT re-pay.`, { cause: err });
|
|
277
277
|
}
|
|
278
278
|
if (confirmed === null) {
|
|
279
|
-
throw new (0,
|
|
279
|
+
throw new (0, _chunkQONQSZHJcjs.SettlementError)(`Aptos exact settle: submitted ${hash} but it did not confirm in time. It likely landed \u2014 re-verify before re-presenting; do NOT re-pay.`);
|
|
280
280
|
}
|
|
281
281
|
if (!confirmed.success) {
|
|
282
282
|
return fail("tx_reverted", `Settle tx ${hash} reverted on-chain (a post-simulate race).`);
|
|
@@ -372,13 +372,13 @@ function txNotFound(hash) {
|
|
|
372
372
|
|
|
373
373
|
function assertAptosWallet(wallet, network) {
|
|
374
374
|
if (typeof wallet !== "object" || wallet === null) {
|
|
375
|
-
throw new (0,
|
|
375
|
+
throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)(
|
|
376
376
|
`chain ${network} is Aptos; wallet must be { key } (ed25519-priv-0x\u2026) or { account }.`
|
|
377
377
|
);
|
|
378
378
|
}
|
|
379
|
-
|
|
379
|
+
_chunkQONQSZHJcjs.assertNoLegacyWalletKey.call(void 0, wallet, "Aptos");
|
|
380
380
|
if (!("key" in wallet) && !("account" in wallet)) {
|
|
381
|
-
throw new (0,
|
|
381
|
+
throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)(
|
|
382
382
|
`chain ${network} is Aptos; wallet must be { key } (ed25519-priv-0x\u2026) or { account }.`
|
|
383
383
|
);
|
|
384
384
|
}
|
|
@@ -390,13 +390,13 @@ function resolveAptosAccount(config) {
|
|
|
390
390
|
try {
|
|
391
391
|
return _tssdk.Account.fromPrivateKey({ privateKey: new (0, _tssdk.Ed25519PrivateKey)(config.key) });
|
|
392
392
|
} catch (cause) {
|
|
393
|
-
throw new (0,
|
|
393
|
+
throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)(
|
|
394
394
|
"Aptos wallet { key } is not a valid ed25519 secret (ed25519-priv-0x\u2026 or 0x\u2026 hex).",
|
|
395
395
|
{ cause }
|
|
396
396
|
);
|
|
397
397
|
}
|
|
398
398
|
}
|
|
399
|
-
throw new (0,
|
|
399
|
+
throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)("Aptos wallet needs { key } (ed25519-priv-0x\u2026) or { account }.");
|
|
400
400
|
}
|
|
401
401
|
|
|
402
402
|
// src/drivers/aptos/index.ts
|
|
@@ -468,16 +468,16 @@ function makeAptosNetwork(preset, rpcUrl) {
|
|
|
468
468
|
const info = preset.tokens[token.toUpperCase()];
|
|
469
469
|
if (!info) {
|
|
470
470
|
const known = Object.keys(preset.tokens).join(", ") || "(none built in)";
|
|
471
|
-
throw new (0,
|
|
471
|
+
throw new (0, _chunkQONQSZHJcjs.UnknownTokenError)(
|
|
472
472
|
`token "${token}" isn't built in for Aptos (known: ${known}). Pass { metadata, decimals } for a custom Fungible Asset, or use 'native'.`
|
|
473
473
|
);
|
|
474
474
|
}
|
|
475
475
|
return { asset: info.metadata, decimals: info.decimals, symbol: info.symbol };
|
|
476
476
|
}
|
|
477
|
-
|
|
477
|
+
_chunkQONQSZHJcjs.rejectForeignToken.call(void 0, token, "aptos", network);
|
|
478
478
|
const t = token;
|
|
479
479
|
if (!t.metadata || typeof t.decimals !== "number") {
|
|
480
|
-
throw new (0,
|
|
480
|
+
throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)(
|
|
481
481
|
`chain ${network} is Aptos; a custom token must be { metadata, decimals }.`
|
|
482
482
|
);
|
|
483
483
|
}
|
|
@@ -504,7 +504,7 @@ function makeAptosNetwork(preset, rpcUrl) {
|
|
|
504
504
|
valid = false;
|
|
505
505
|
}
|
|
506
506
|
if (!valid || evmLike) {
|
|
507
|
-
throw new (0,
|
|
507
|
+
throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)(
|
|
508
508
|
`chain ${network} is Aptos, but payTo "${payTo}" is not a valid Aptos address (0x + 32 bytes).`
|
|
509
509
|
);
|
|
510
510
|
}
|
|
@@ -526,12 +526,12 @@ function makeAptosNetwork(preset, rpcUrl) {
|
|
|
526
526
|
const tx = await aptos.waitForTransaction({ transactionHash: ref });
|
|
527
527
|
return { height: String(_nullishCoalesce(tx.version, () => ( "0"))) };
|
|
528
528
|
} catch (err) {
|
|
529
|
-
throw new (0,
|
|
529
|
+
throw new (0, _chunkQONQSZHJcjs.ConfirmationTimeoutError)(`Aptos tx ${ref} did not finalize in time.`, { cause: err });
|
|
530
530
|
}
|
|
531
531
|
},
|
|
532
532
|
async estimateCost(accept) {
|
|
533
533
|
if (accept.scheme === "exact") {
|
|
534
|
-
return
|
|
534
|
+
return _chunkQONQSZHJcjs.nativeCost.call(void 0, {
|
|
535
535
|
symbol: APT_SYMBOL,
|
|
536
536
|
decimals: APT_DECIMALS,
|
|
537
537
|
fee: 0n,
|
|
@@ -539,7 +539,7 @@ function makeAptosNetwork(preset, rpcUrl) {
|
|
|
539
539
|
detail: "gasless \u2014 the fee payer (facilitator/relayer) sponsors gas; the buyer pays 0 APT"
|
|
540
540
|
});
|
|
541
541
|
}
|
|
542
|
-
return
|
|
542
|
+
return _chunkQONQSZHJcjs.nativeCost.call(void 0, {
|
|
543
543
|
symbol: APT_SYMBOL,
|
|
544
544
|
decimals: APT_DECIMALS,
|
|
545
545
|
fee: 100000n,
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
nativeCost,
|
|
10
10
|
rejectForeignToken,
|
|
11
11
|
toInsufficientFundsError
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-QU25LSVS.js";
|
|
13
13
|
|
|
14
14
|
// src/drivers/aptos/index.ts
|
|
15
15
|
import { Aptos, AptosConfig, Network, AccountAddress as AccountAddress2 } from "@aptos-labs/ts-sdk";
|
|
@@ -179,7 +179,7 @@ function parseUnits(value, decimals) {
|
|
|
179
179
|
}
|
|
180
180
|
const [whole, frac = ""] = value.split(".");
|
|
181
181
|
if (frac.length > decimals) {
|
|
182
|
-
throw new
|
|
182
|
+
throw new InvalidConfigError(
|
|
183
183
|
`parseUnits: "${value}" has more than ${decimals} decimal places.`
|
|
184
184
|
);
|
|
185
185
|
}
|
|
@@ -190,7 +190,7 @@ function floorUnits(value, decimals) {
|
|
|
190
190
|
assertValidDecimals(decimals, "floorUnits");
|
|
191
191
|
value = expandScientific(value);
|
|
192
192
|
if (!/^\d+(\.\d+)?$/.test(value)) {
|
|
193
|
-
throw new
|
|
193
|
+
throw new InvalidConfigError(`floorUnits: "${value}" is not a non-negative decimal amount.`);
|
|
194
194
|
}
|
|
195
195
|
const [whole, frac = ""] = value.split(".");
|
|
196
196
|
const fracTrunc = frac.slice(0, decimals).padEnd(decimals, "0");
|
|
@@ -179,7 +179,7 @@ function parseUnits(value, decimals) {
|
|
|
179
179
|
}
|
|
180
180
|
const [whole, frac = ""] = value.split(".");
|
|
181
181
|
if (frac.length > decimals) {
|
|
182
|
-
throw new
|
|
182
|
+
throw new InvalidConfigError(
|
|
183
183
|
`parseUnits: "${value}" has more than ${decimals} decimal places.`
|
|
184
184
|
);
|
|
185
185
|
}
|
|
@@ -190,7 +190,7 @@ function floorUnits(value, decimals) {
|
|
|
190
190
|
assertValidDecimals(decimals, "floorUnits");
|
|
191
191
|
value = expandScientific(value);
|
|
192
192
|
if (!/^\d+(\.\d+)?$/.test(value)) {
|
|
193
|
-
throw new
|
|
193
|
+
throw new InvalidConfigError(`floorUnits: "${value}" is not a non-negative decimal amount.`);
|
|
194
194
|
}
|
|
195
195
|
const [whole, frac = ""] = value.split(".");
|
|
196
196
|
const fracTrunc = frac.slice(0, decimals).padEnd(decimals, "0");
|