@piprail/sdk 2.15.1 → 2.16.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 +209 -1
- package/README.md +1 -1
- package/dist/{algorand-UF7BLBFN.js → algorand-25FMBCT3.js} +12 -3
- package/dist/{algorand-XGSWDMCZ.cjs → algorand-Q3TUQLPK.cjs} +17 -8
- package/dist/{aptos-KDLX42CR.js → aptos-SBV6SGDP.js} +2 -2
- package/dist/{aptos-J2QSWHTO.cjs → aptos-VBJONBFY.cjs} +5 -5
- package/dist/chunk-2CX7XRZK.js +649 -0
- package/dist/chunk-C52H5TYB.js +474 -0
- package/dist/chunk-OXEFPLZA.cjs +474 -0
- package/dist/chunk-V2IJ5HUW.cjs +649 -0
- package/dist/index.cjs +362 -1181
- package/dist/index.d.cts +39 -6
- package/dist/index.d.ts +39 -6
- package/dist/index.js +178 -997
- package/dist/{ledger-uFtXlIHY.d.cts → ledger-Crc1bZox.d.cts} +164 -10
- package/dist/{ledger-uFtXlIHY.d.ts → ledger-Crc1bZox.d.ts} +164 -10
- package/dist/node.d.cts +2 -2
- package/dist/node.d.ts +2 -2
- package/dist/{solana-S2T3JNR7.cjs → solana-AI2G7V33.cjs} +42 -21
- package/dist/{solana-WO2G7WWZ.js → solana-HTKDRTD3.js} +31 -10
- package/dist/{xrpl-6B2XOXGC.js → xrpl-RUOB37QH.js} +282 -4
- package/dist/{xrpl-VOUXIUYD.cjs → xrpl-SVVS445B.cjs} +292 -14
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,7 +4,213 @@ 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
|
-
## [
|
|
7
|
+
## [2.16.1] — 2026-09-06 — GoPlausible settles Solana, live-proven
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **GoPlausible is now seeded as a keyless Solana facilitator.** They told us directly that they
|
|
12
|
+
settle Solana as well as Algorand and Base, and they were right: their `/supported` advertises
|
|
13
|
+
`solana:5eykt4Us…` `exact` with a sponsor fee payer, and PipRail's own `facilitatorCoverage()`
|
|
14
|
+
reads the same.
|
|
15
|
+
|
|
16
|
+
**Live-proven on Solana mainnet 2026-09-06** rather than taken on trust. A real
|
|
17
|
+
`402 → pay → verify → 200` round trip on the `exact` rail: the merchant received exactly
|
|
18
|
+
0.01 USDC, the **buyer paid 0 SOL**, GoPlausible's sponsor `8a8fFNfk…RAYi` paid the
|
|
19
|
+
10,001-lamport fee (confirmed by reading `accountKeys[0]` on the settled transaction), and a
|
|
20
|
+
replay of the same proof was rejected. Tx
|
|
21
|
+
`3DEGg6Lue8471meBH8hbLxV1bLmZGKvmvmSY3tjg7tQFnxzE9GQXUXokjQnZgTqaEU4SaXuY9F7v3m7JsX5xDgrZ`.
|
|
22
|
+
|
|
23
|
+
Solana previously seeded only PayAI and OpenFacilitator, so this is a third keyless option on
|
|
24
|
+
that chain. No default changes: the seed list is a convenience, and the SDK still depends on no
|
|
25
|
+
facilitator.
|
|
26
|
+
|
|
27
|
+
## [2.16.0] — 2026-09-06 — the XRP Ledger `exact` buyer, and paying the 91% of the x402 web we could not
|
|
28
|
+
|
|
29
|
+
### Added — the XRP Ledger `exact` buyer (stage 04, first family)
|
|
30
|
+
|
|
31
|
+
- **A PipRail agent can now pay a standard x402 `exact` rail on the XRP Ledger** — 1,732 live rails,
|
|
32
|
+
and as far as we can tell the only open-source buyer on that chain. `drivers/xrpl/exact.ts`
|
|
33
|
+
implements `scheme_exact_xrpl.md` in both directions: the buyer signs a complete `Payment` and
|
|
34
|
+
broadcasts nothing; the gate decodes the blob, re-derives every checked field from its own trusted
|
|
35
|
+
accept, submits, and waits for a validated `tesSUCCESS`.
|
|
36
|
+
|
|
37
|
+
XRPL is the family where **the payer pays the fee** (it is a field inside the signed transaction),
|
|
38
|
+
so there is no sponsor, no co-signature, and no fee-drain guard. The scheme replaces those with a
|
|
39
|
+
list of MUST-NOTs the settler enforces — no `Memos`, no `Paths`, no `tfPartialPayment`, no
|
|
40
|
+
`Delegate`, never `Amount` and `DeliverMax` together — each of which is a way a hostile blob could
|
|
41
|
+
underdeliver, and each of which has a test.
|
|
42
|
+
|
|
43
|
+
The challenge binds through `InvoiceID = SHA-256(extra.invoiceId)`, **not** a memo: the scheme has
|
|
44
|
+
settlers reject `Memos`, which is exactly what PipRail's `onchain-proof` XRPL path uses for its
|
|
45
|
+
nonce. The two paths deliberately share no code.
|
|
46
|
+
|
|
47
|
+
**`extra.areFeesSponsored` is required by the scheme and absent from 100% of live rails**, so it is
|
|
48
|
+
read as *false unless present*. Requiring it would have rejected the entire deployed XRPL x402 web
|
|
49
|
+
— the third instance of that bug class this release cycle, and the reason it now has a test of its
|
|
50
|
+
own.
|
|
51
|
+
|
|
52
|
+
**Native XRP only, deliberately.** The two XRPL asset forms use different wire amount conventions
|
|
53
|
+
(native is an integer *drops* string, an issued currency is a *decimal* `value` — both verified
|
|
54
|
+
against live merchant challenges). The SDK prices and spend-caps in base units, so reading an
|
|
55
|
+
IOU's `"12"` as base units would understate a 12-RLUSD payment by 10^15 and slip it under any
|
|
56
|
+
policy cap while the buyer signed the real amount. Issued currencies are therefore dropped at
|
|
57
|
+
gather rather than mispriced; the RLUSD half waits until that decimal path is threaded through
|
|
58
|
+
quoting and the policy.
|
|
59
|
+
|
|
60
|
+
- **`ResolvedNetwork.exactPayableAsset?(asset)`** — a new optional driver hook. The buyer's gather
|
|
61
|
+
used to hard-code "any recognised token is exact-payable, the native coin never is", which was
|
|
62
|
+
true until XRPL, where it is wrong in *both* directions. A driver that declares the hook is
|
|
63
|
+
authoritative for all of its assets; every other family omits it and behaves exactly as before.
|
|
64
|
+
|
|
65
|
+
- **Three conformance fixes found by pointing the buyer at real merchants**, each of which made a
|
|
66
|
+
live XRPL rail unpayable on its own:
|
|
67
|
+
- `describeAsset` and `recipientReady` only knew the native coin as `'native'`. The XRPL x402 web
|
|
68
|
+
writes it `'XRP'` — all 863 native rails do. The first miss dropped every rail at gather ("no
|
|
69
|
+
compatible accept" on a chain we fully support); the second then demanded a **trustline** for a
|
|
70
|
+
coin that cannot have one. Both now go through one `isXrpNative()` predicate.
|
|
71
|
+
- `LastLedgerSequence` was a fixed 20-ledger window. The settler checks it is "within policy
|
|
72
|
+
window", and the merchant's policy is what `maxTimeoutSeconds` announces — so a rail offering
|
|
73
|
+
60s was getting an ~80s blob, one that outlives the merchant's own quote. Now derived, clamped.
|
|
74
|
+
- `Flags` was hard-set to `0`. `tfPartialPayment` is a different bit, so zero was never needed to
|
|
75
|
+
exclude it — but it made our transactions the only ones on the ledger without
|
|
76
|
+
`tfFullyCanonicalSig`. Now set, matching what every other XRPL client sends.
|
|
77
|
+
- `extra.sourceTag` is mirrored into the transaction's `SourceTag`. Not in the scheme's `extra`
|
|
78
|
+
table, but present on **1,728 of the 1,732** live rails — it is how deployed vendors correlate a
|
|
79
|
+
payment back to their own quote.
|
|
80
|
+
- Live-proven on mainnet: settle tx
|
|
81
|
+
`F673064D2E0D982481844A769E829FD8B486EB9FB7B014F866C92F1C49770505` — 0.01 XRP through our own
|
|
82
|
+
gate on the `exact` rail, payer debited 0.010012 XRP (the amount **plus its own 12-drop fee**),
|
|
83
|
+
merchant credited 0.010000, and a genuine replay of the same signed blob refused with a 402.
|
|
84
|
+
- Buyer-side errors are mapped per `ERRORS.md` §9: an unactivated payer account (XRPL reports it as
|
|
85
|
+
`actNotFound`, but on that ledger "does not exist" means "unfunded") becomes
|
|
86
|
+
`InsufficientFundsError` with the base-reserve fix in the message; an `xrpl.js` validation failure
|
|
87
|
+
at signing becomes `UnsupportedSchemeError` carrying the library's reason; any other RPC failure is
|
|
88
|
+
rethrown unchanged rather than disguised as an affordability problem. All three are tested.
|
|
89
|
+
- **Not proven, and it is NOT our bug: a paid round-trip against a THIRD-PARTY XRPL merchant.**
|
|
90
|
+
Two live vendors refuse our payload with `invalid_payload` — from **their own pre-check**, before
|
|
91
|
+
their facilitator ever sees it (proven by routing a v1-shaped body past that pre-check, which then
|
|
92
|
+
returned the facilitator's own schema error: it wants exactly the `{x402Version: 2, accepted,
|
|
93
|
+
payload}` envelope we already send). The decisive test: **the same client, envelope and header pay
|
|
94
|
+
one of those same gateways successfully on its Base rail** (0.001 USDC, HTTP 200). So our envelope
|
|
95
|
+
is correct and the fault is XRPL-specific on their side. Our transaction also matches, field for
|
|
96
|
+
field, a payment that merchant has accepted from another client. Working conclusion: the deployed
|
|
97
|
+
XRPL dialect has drifted from `scheme_exact_xrpl.md` — worth raising upstream.
|
|
98
|
+
**No funds were lost across ~10 refused attempts** — every vendor rejects before settling, and the
|
|
99
|
+
ledger confirms no payment ever left the wallet.
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
### Fixed — the buyer required a field the spec makes optional, and so could not pay 91% of the x402 web
|
|
103
|
+
|
|
104
|
+
- **`schemes: ['exact']` clients now pay the standard x402 web: 26.3% → 98.8% of the resources
|
|
105
|
+
listed on the CDP Bazaar** (15,686 resources / 40,388 `exact` rails, measured 2026-09-06 by
|
|
106
|
+
`npm run x402:coverage`; the figures live in `scripts/x402-corpus/coverage.json`, which owns
|
|
107
|
+
them). Rail-level coverage went 9.2% → 88.9%.
|
|
108
|
+
|
|
109
|
+
The buyer's gather predicate required `extra.assetTransferMethod` on every `exact` rail. The
|
|
110
|
+
ratified scheme says the opposite — `scheme_exact_evm.md`: *"If no `assetTransferMethod` is
|
|
111
|
+
specified in `PaymentRequired.extra`, clients should default to `"eip3009"`"* — and the SVM,
|
|
112
|
+
Algorand, Aptos, NEAR and Hedera schemes never define the key at all (their required extra is
|
|
113
|
+
`feePayer`). Only **9%** of live rails carry it; **79%** carry just the EIP-712 domain. So a
|
|
114
|
+
PipRail agent silently refused every Solana rail, every Arbitrum rail and 85% of Base rails —
|
|
115
|
+
including textbook canonical-USDC EIP-3009 rails it was perfectly able to sign.
|
|
116
|
+
|
|
117
|
+
This was never a pay-path bug: the EVM driver already defaulted to EIP-3009 and re-derives the
|
|
118
|
+
token's EIP-712 domain on-chain. Only the gather refused. A rail that NAMES a method we don't
|
|
119
|
+
implement (the spec's `erc7710`) is still skipped rather than signed blind.
|
|
120
|
+
|
|
121
|
+
Found by probing seven real third-party 402s and paying none of them, while 1,636 unit tests were
|
|
122
|
+
green. The tests agreed with their own hand-built fixtures; nothing checked the fixtures against
|
|
123
|
+
the world. That gap is now closed by `sdk/test/x402-corpus.test.ts` — 62 REAL challenges captured
|
|
124
|
+
from the live index, replayed through the real client.
|
|
125
|
+
|
|
126
|
+
### Fixed — the Solana buyer required `extra.decimals`, which the SVM scheme never defines
|
|
127
|
+
|
|
128
|
+
- **99.3% of live Solana rails planned as payable and then threw at signing time.**
|
|
129
|
+
`payExactSolana` required `extra.decimals` for the TransferChecked and raised
|
|
130
|
+
`UnsupportedSchemeError` without it — but `scheme_exact_svm.md` doesn't define `decimals` at all
|
|
131
|
+
(its one required extra is `feePayer`), and only **41 of the 5,760** live Solana rails carry it.
|
|
132
|
+
The same "we require a field the spec makes optional" mistake as `assetTransferMethod`, one layer
|
|
133
|
+
deeper, and worse because it broke the plan-vs-pay contract: the rail gathered, `planPayment`
|
|
134
|
+
said `payable`, and the payment then failed.
|
|
135
|
+
|
|
136
|
+
The decimals now come **from the mint on-chain**, which is also the safer source — a server that
|
|
137
|
+
understated them could otherwise have the buyer sign a transfer 10^n larger than the quote, and
|
|
138
|
+
TransferChecked would accept it. A rail that states decimals disagreeing with the mint is refused;
|
|
139
|
+
`extra.decimals` survives only as a fallback if the mint read fails.
|
|
140
|
+
|
|
141
|
+
Found by paying a real Solana merchant. No unit test could have caught it — every fixture in the
|
|
142
|
+
suite carried `extra.decimals`, because our own gate always emits it.
|
|
143
|
+
|
|
144
|
+
### Live-proven on mainnet (2026-09-06)
|
|
145
|
+
|
|
146
|
+
Real payments to real third-party merchants, one per wire shape this release unlocks:
|
|
147
|
+
|
|
148
|
+
| shape | merchant | proof |
|
|
149
|
+
|---|---|---|
|
|
150
|
+
| v2 · Base · domain-only (no marker) | `api.onesource.io/api/chain/block-number` | 200, 0.001 USDC, `0x44e9fed18bf9…` |
|
|
151
|
+
| v2 · Base · slug network | `coil.trade/api/crypto/gate` | 200, 0.001 USDC, `0xc38e6da9cbc2…` |
|
|
152
|
+
| **v1** · Base · `X-PAYMENT` wire | `x402factory.ai/base/coinprice` | 200, 0.001 USDC, `eip3009-nonce:0xb6c321fa…` |
|
|
153
|
+
| v2 · Solana · `feePayer`, no marker | `hypernatt.com/api/m2m/liq-radar` | 200, 0.001 USDC, `solana-nonce:3g3Wj5G6G7D…` |
|
|
154
|
+
|
|
155
|
+
Every row is a real body from a real stranger's endpoint, re-run against the FINAL build of this
|
|
156
|
+
release (an earlier run on the same day proved the same four shapes).
|
|
157
|
+
|
|
158
|
+
Own-gate regression, also on mainnet and also re-run on the final build: Base USDC + EURC
|
|
159
|
+
round-tripped gasless via EIP-3009 — payer ETH delta **0**, merchant received, **replay rejected**
|
|
160
|
+
(settle `0x85dfcc2b480f…` / `0x41fa1bdf5ea1…`); Algorand settled live with the enriched receipt and
|
|
161
|
+
a rejected replay (`TBRSSLNUJGCUS6…`).
|
|
162
|
+
|
|
163
|
+
### Added — x402 **v1** challenges on the buyer path
|
|
164
|
+
|
|
165
|
+
- **A v1 server can now be quoted and paid.** PipRail's stated posture has always been "emit strict
|
|
166
|
+
v2, accept liberal v1 + v2", and the gate honoured it — but the buyer's `isValidChallenge`
|
|
167
|
+
hard-required `x402Version === 2`, so every v1 server was an `InvalidEnvelopeError`, and no v1
|
|
168
|
+
header emitter existed to answer one with. 251 of the 15,686 catalogued resources are v1.
|
|
169
|
+
`normalizeV1Challenge` lifts a v1 body (`maxAmountRequired`, slug network, per-accept `resource`
|
|
170
|
+
string) into the standard shape, and `buildV1PaymentHeader` frames the answer on the v1 wire.
|
|
171
|
+
Probed live: a v1 server ignores `PAYMENT-SIGNATURE` and reads only `X-PAYMENT`, so the network
|
|
172
|
+
slug is echoed back exactly as the server sent it (v1 verifiers string-compare it).
|
|
173
|
+
The slug is remembered on a synthetic `wireNetwork` field, which is **stripped from every
|
|
174
|
+
outgoing `accepted` echo** — that block is documented as the merchant's rail returned verbatim,
|
|
175
|
+
and facilitators compare (some hash) it, so a key the merchant never published must not appear
|
|
176
|
+
in it.
|
|
177
|
+
|
|
178
|
+
### Added — the Algorand CAIP-2 id the spec actually uses
|
|
179
|
+
|
|
180
|
+
- `scheme_exact_algo.md` gives Algorand mainnet as the base64 genesis hash **truncated to 32 chars**
|
|
181
|
+
(`algorand:wGHE2Pwdvd7S12BL5FaOP20EGYesN73k`), and the deployed web follows it — 874 live rails on
|
|
182
|
+
the spec form vs 589 on the padded 44-char id PipRail binds. Both forms are now accepted on parse.
|
|
183
|
+
What PipRail *emits* is unchanged (switching that would break deployed 2.x Algorand buyers; it is
|
|
184
|
+
queued for the next major).
|
|
185
|
+
|
|
186
|
+
- **The GATE now matches an echoed network id through the same canonicalisation.** It compared
|
|
187
|
+
`accepted.network` to its own rail with `===`, so a conformant buyer that canonicalised the id
|
|
188
|
+
before echoing it — the Algorand spec form, or TON's superseded `ton:-239` — had a perfectly
|
|
189
|
+
valid payment refused. All three selector sites (`onchain-proof`, `exact`, `upto`) now compare
|
|
190
|
+
through `normalizeNetwork`. This can only widen which of the gate's OWN rails is selected: payTo,
|
|
191
|
+
amount and asset are re-derived from the gate's spec either way, so a wrong network still cannot
|
|
192
|
+
redirect a payment. The Algorand driver's `supports()` accepts both spellings directly too,
|
|
193
|
+
mirroring TON.
|
|
194
|
+
|
|
195
|
+
### Added — coverage is now measured, not asserted
|
|
196
|
+
|
|
197
|
+
- **`npm run x402:coverage`** (`scripts/x402-corpus/audit.mjs`) pages the live CDP Bazaar, classifies
|
|
198
|
+
every rail against the SDK's own exported predicates, and writes `scripts/x402-corpus/coverage.json`.
|
|
199
|
+
Every coverage figure in this repo cites that file. `--live` runs a real read-only `quote()` against
|
|
200
|
+
live third-party 402s (8/9 quotable, the 9th a merchant whose `upto` rail omits the spec-mandated
|
|
201
|
+
`facilitatorAddress`); `--fixture` regenerates the regression corpus.
|
|
202
|
+
- `PayOption.method` reports the transfer method the buyer would actually sign, appending
|
|
203
|
+
`' (default)'` when the rail named none — so the inference is visible instead of implicit.
|
|
204
|
+
- New exports: `exactTransferMethod`, `isSettleableExactMethod`, `KNOWN_EXACT_TRANSFER_METHODS`,
|
|
205
|
+
`DEFAULT_EXACT_TRANSFER_METHOD`, `normalizeV1Challenge`, `buildV1PaymentHeader`.
|
|
206
|
+
|
|
207
|
+
### Changed — types now admit what the wire allows
|
|
208
|
+
|
|
209
|
+
- `X402ExactAcceptEntry.extra` and `extra.assetTransferMethod` are **optional**. A conformant rail may
|
|
210
|
+
ship `extra: {}` or omit the block entirely, and the type said otherwise, which is how a
|
|
211
|
+
bare-`extra` deref came to look like a real hazard. Every read on the buyer path optional-chains.
|
|
212
|
+
Defaults are unchanged: `schemes` still defaults to `['onchain-proof']`, so a zero-config client
|
|
213
|
+
behaves byte-identically.
|
|
8
214
|
|
|
9
215
|
## [2.15.1] — 2026-08-28 — a dead Sui RPC, an RPC failure blamed on the token, and fuzz hardening
|
|
10
216
|
|
|
@@ -1924,6 +2130,8 @@ straight into your wallet. The API is small and self-contained.
|
|
|
1924
2130
|
to your wallet; PipRail never holds funds.
|
|
1925
2131
|
- `viem ^2.21` is a peer dependency. Node 20+ or a modern browser.
|
|
1926
2132
|
|
|
2133
|
+
[2.16.1]: https://www.npmjs.com/package/@piprail/sdk
|
|
2134
|
+
[2.16.0]: https://www.npmjs.com/package/@piprail/sdk
|
|
1927
2135
|
[2.15.1]: https://www.npmjs.com/package/@piprail/sdk
|
|
1928
2136
|
[2.15.0]: https://www.npmjs.com/package/@piprail/sdk
|
|
1929
2137
|
[2.14.0]: https://www.npmjs.com/package/@piprail/sdk
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Accept and make [x402](https://x402.org) crypto payments — on any EVM chain plus Solana, TON, Tron, NEAR, Sui, Aptos, Algorand, Stellar & the XRP Ledger — in a couple of lines.**
|
|
4
4
|
|
|
5
|
-
No middleman, no database, no fee, no account. Payments settle **straight into your wallet**, verified locally against your own RPC. Gate a route to make it paid-only; point an agent at a paid URL and it pays itself.
|
|
5
|
+
No middleman, no database, no fee, no account, no API key. Payments settle **straight into your wallet**, verified locally against your own RPC. Gate a route to make it paid-only; point an agent at a paid URL and it pays itself.
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install @piprail/sdk viem
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ALGORAND_SPEC_CAIP2
|
|
3
|
+
} from "./chunk-2CX7XRZK.js";
|
|
1
4
|
import {
|
|
2
5
|
ConfirmationTimeoutError,
|
|
3
6
|
InsufficientFundsError,
|
|
@@ -110,7 +113,7 @@ async function payExactAlgorand(input) {
|
|
|
110
113
|
"Algorand exact is ASA-only (an asset transfer); native ALGO is not exact-payable. Pay via onchain-proof."
|
|
111
114
|
);
|
|
112
115
|
}
|
|
113
|
-
const feePayer = accept.extra
|
|
116
|
+
const feePayer = accept.extra?.feePayer;
|
|
114
117
|
if (!feePayer) {
|
|
115
118
|
throw new UnsupportedSchemeError("Algorand exact rail must advertise extra.feePayer (the fee sponsor address).");
|
|
116
119
|
}
|
|
@@ -171,7 +174,7 @@ function decodeElement(bytes) {
|
|
|
171
174
|
}
|
|
172
175
|
async function verifyAndSettleExactAlgorand(input) {
|
|
173
176
|
const { client, feePayerSk, feePayerAddr, payload, accept } = input;
|
|
174
|
-
const railFeePayer = accept.extra
|
|
177
|
+
const railFeePayer = accept.extra?.feePayer;
|
|
175
178
|
if (!railFeePayer) throw new SettlementError("Algorand exact: rail is missing extra.feePayer.");
|
|
176
179
|
if (railFeePayer !== feePayerAddr) {
|
|
177
180
|
throw new SettlementError("Algorand exact: the gate relayer address does not match the rail extra.feePayer \u2014 misconfigured rail.");
|
|
@@ -463,7 +466,13 @@ function makeAlgorandNetwork(preset, algodUrl) {
|
|
|
463
466
|
return {
|
|
464
467
|
family: "algorand",
|
|
465
468
|
network,
|
|
466
|
-
|
|
469
|
+
// Accept our padded 44-char genesis-hash id AND the spec's 32-char truncated form
|
|
470
|
+
// (`scheme_exact_algo.md`'s Network Identifiers table — the form 874 of the 1,463 live
|
|
471
|
+
// Algorand rails use), so a caller that bypasses `normalizeNetwork` and hands the raw
|
|
472
|
+
// spec id to the driver still matches. Mirrors TON's legacy-id tolerance; the
|
|
473
|
+
// normalizeNetwork alias remains the canonical seam. We still EMIT the padded form —
|
|
474
|
+
// changing that would break every deployed PipRail 2.x buyer, so it waits for a major.
|
|
475
|
+
supports: (n) => n === network || n === ALGORAND_SPEC_CAIP2,
|
|
467
476
|
resolveToken(token) {
|
|
468
477
|
if (token === "native") {
|
|
469
478
|
return { asset: "native", decimals: ALGO_DECIMALS, symbol: ALGO_SYMBOL };
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
2
|
|
|
3
|
+
var _chunkV2IJ5HUWcjs = require('./chunk-V2IJ5HUW.cjs');
|
|
4
|
+
|
|
5
|
+
|
|
3
6
|
|
|
4
7
|
|
|
5
8
|
|
|
@@ -110,7 +113,7 @@ async function payExactAlgorand(input) {
|
|
|
110
113
|
"Algorand exact is ASA-only (an asset transfer); native ALGO is not exact-payable. Pay via onchain-proof."
|
|
111
114
|
);
|
|
112
115
|
}
|
|
113
|
-
const feePayer = accept.extra.feePayer;
|
|
116
|
+
const feePayer = _optionalChain([accept, 'access', _2 => _2.extra, 'optionalAccess', _3 => _3.feePayer]);
|
|
114
117
|
if (!feePayer) {
|
|
115
118
|
throw new (0, _chunkQONQSZHJcjs.UnsupportedSchemeError)("Algorand exact rail must advertise extra.feePayer (the fee sponsor address).");
|
|
116
119
|
}
|
|
@@ -171,7 +174,7 @@ function decodeElement(bytes) {
|
|
|
171
174
|
}
|
|
172
175
|
async function verifyAndSettleExactAlgorand(input) {
|
|
173
176
|
const { client, feePayerSk, feePayerAddr, payload, accept } = input;
|
|
174
|
-
const railFeePayer = accept.extra.feePayer;
|
|
177
|
+
const railFeePayer = _optionalChain([accept, 'access', _4 => _4.extra, 'optionalAccess', _5 => _5.feePayer]);
|
|
175
178
|
if (!railFeePayer) throw new (0, _chunkQONQSZHJcjs.SettlementError)("Algorand exact: rail is missing extra.feePayer.");
|
|
176
179
|
if (railFeePayer !== feePayerAddr) {
|
|
177
180
|
throw new (0, _chunkQONQSZHJcjs.SettlementError)("Algorand exact: the gate relayer address does not match the rail extra.feePayer \u2014 misconfigured rail.");
|
|
@@ -206,7 +209,7 @@ async function verifyAndSettleExactAlgorand(input) {
|
|
|
206
209
|
return fail("transfer_not_found", `Transfer asset id ${at.assetIndex} \u2260 rail asset ${assetId}.`);
|
|
207
210
|
}
|
|
208
211
|
if (!addrEq(at.receiver, accept.payTo)) {
|
|
209
|
-
return fail("wrong_recipient", `Transfer pays ${_optionalChain([at, 'access',
|
|
212
|
+
return fail("wrong_recipient", `Transfer pays ${_optionalChain([at, 'access', _6 => _6.receiver, 'optionalAccess', _7 => _7.toString, 'call', _8 => _8()])}, not payTo ${accept.payTo}.`);
|
|
210
213
|
}
|
|
211
214
|
if (BigInt(at.amount) < BigInt(accept.amount)) {
|
|
212
215
|
return fail("amount_too_low", `Transfer pays ${at.amount} of the ASA, required ${accept.amount}.`);
|
|
@@ -221,7 +224,7 @@ async function verifyAndSettleExactAlgorand(input) {
|
|
|
221
224
|
return fail("signature_invalid", "The fee transaction must be a payment (pay) transaction.");
|
|
222
225
|
}
|
|
223
226
|
if (!addrEq(fee.sender, railFeePayer)) {
|
|
224
|
-
return fail("signature_invalid", `The fee transaction sender ${_optionalChain([fee, 'access',
|
|
227
|
+
return fail("signature_invalid", `The fee transaction sender ${_optionalChain([fee, 'access', _9 => _9.sender, 'optionalAccess', _10 => _10.toString, 'call', _11 => _11()])} is not the rail fee payer ${railFeePayer}.`);
|
|
225
228
|
}
|
|
226
229
|
if (BigInt(fee.payment.amount) !== 0n) {
|
|
227
230
|
return fail("signature_invalid", "The fee transaction must move 0 ALGO (it only pools the group fee).");
|
|
@@ -447,12 +450,12 @@ function makeAlgorandNetwork(preset, algodUrl) {
|
|
|
447
450
|
const settleClient = {
|
|
448
451
|
async simulate(signedGroup) {
|
|
449
452
|
const resp = await algod.simulateRawTransactions(signedGroup).do();
|
|
450
|
-
const fm = _optionalChain([resp, 'optionalAccess',
|
|
453
|
+
const fm = _optionalChain([resp, 'optionalAccess', _12 => _12.txnGroups, 'optionalAccess', _13 => _13[0], 'optionalAccess', _14 => _14.failureMessage]);
|
|
451
454
|
return { failureMessage: fm && fm.length > 0 ? fm : null };
|
|
452
455
|
},
|
|
453
456
|
async submit(signedGroup) {
|
|
454
457
|
const res = await algod.sendRawTransaction(signedGroup).do();
|
|
455
|
-
return _nullishCoalesce(_optionalChain([res, 'optionalAccess',
|
|
458
|
+
return _nullishCoalesce(_optionalChain([res, 'optionalAccess', _15 => _15.txid]), () => ( ""));
|
|
456
459
|
},
|
|
457
460
|
async waitForConfirmation(txid) {
|
|
458
461
|
const info = await _algosdk2.default.waitForConfirmation(algod, txid, 10);
|
|
@@ -463,7 +466,13 @@ function makeAlgorandNetwork(preset, algodUrl) {
|
|
|
463
466
|
return {
|
|
464
467
|
family: "algorand",
|
|
465
468
|
network,
|
|
466
|
-
|
|
469
|
+
// Accept our padded 44-char genesis-hash id AND the spec's 32-char truncated form
|
|
470
|
+
// (`scheme_exact_algo.md`'s Network Identifiers table — the form 874 of the 1,463 live
|
|
471
|
+
// Algorand rails use), so a caller that bypasses `normalizeNetwork` and hands the raw
|
|
472
|
+
// spec id to the driver still matches. Mirrors TON's legacy-id tolerance; the
|
|
473
|
+
// normalizeNetwork alias remains the canonical seam. We still EMIT the padded form —
|
|
474
|
+
// changing that would break every deployed PipRail 2.x buyer, so it waits for a major.
|
|
475
|
+
supports: (n) => n === network || n === _chunkV2IJ5HUWcjs.ALGORAND_SPEC_CAIP2,
|
|
467
476
|
resolveToken(token) {
|
|
468
477
|
if (token === "native") {
|
|
469
478
|
return { asset: "native", decimals: ALGO_DECIMALS, symbol: ALGO_SYMBOL };
|
|
@@ -575,7 +584,7 @@ function makeAlgorandNetwork(preset, algodUrl) {
|
|
|
575
584
|
const optedIn = (_nullishCoalesce(info.assets, () => ( []))).some((a) => Number(a.assetId) === assetId);
|
|
576
585
|
return optedIn ? { ready: true } : { ready: false, reason: "NOT_OPTED_IN" };
|
|
577
586
|
} catch (e) {
|
|
578
|
-
if (/does not exist|no accounts found|404|account not found/i.test(String(_nullishCoalesce(_optionalChain([e, 'optionalAccess',
|
|
587
|
+
if (/does not exist|no accounts found|404|account not found/i.test(String(_nullishCoalesce(_optionalChain([e, 'optionalAccess', _16 => _16.message]), () => ( e))))) {
|
|
579
588
|
return { ready: false, reason: "NOT_OPTED_IN" };
|
|
580
589
|
}
|
|
581
590
|
return { ready: "unknown" };
|
|
@@ -107,7 +107,7 @@ async function payExactAptos(input) {
|
|
|
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
|
-
const feePayer = accept.extra
|
|
110
|
+
const feePayer = accept.extra?.feePayer;
|
|
111
111
|
if (!feePayer) {
|
|
112
112
|
throw new UnsupportedSchemeError("Aptos exact rail must advertise extra.feePayer (the gas sponsor address).");
|
|
113
113
|
}
|
|
@@ -157,7 +157,7 @@ function argBytes(arg) {
|
|
|
157
157
|
}
|
|
158
158
|
async function verifyAndSettleExactAptos(input) {
|
|
159
159
|
const { client, feePayerAddr, payload, accept } = input;
|
|
160
|
-
const railFeePayer = accept.extra
|
|
160
|
+
const railFeePayer = accept.extra?.feePayer;
|
|
161
161
|
if (!railFeePayer) throw new SettlementError("Aptos exact: rail is missing extra.feePayer.");
|
|
162
162
|
if (railFeePayer !== feePayerAddr) {
|
|
163
163
|
throw new SettlementError("Aptos exact: the gate relayer address does not match the rail extra.feePayer \u2014 misconfigured rail.");
|
|
@@ -107,7 +107,7 @@ async function payExactAptos(input) {
|
|
|
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
|
-
const feePayer = accept.extra.feePayer;
|
|
110
|
+
const feePayer = _optionalChain([accept, 'access', _ => _.extra, 'optionalAccess', _2 => _2.feePayer]);
|
|
111
111
|
if (!feePayer) {
|
|
112
112
|
throw new (0, _chunkQONQSZHJcjs.UnsupportedSchemeError)("Aptos exact rail must advertise extra.feePayer (the gas sponsor address).");
|
|
113
113
|
}
|
|
@@ -151,13 +151,13 @@ function fail(error, detail) {
|
|
|
151
151
|
return { ok: false, error, detail };
|
|
152
152
|
}
|
|
153
153
|
function argBytes(arg) {
|
|
154
|
-
const v = _optionalChain([arg, 'access',
|
|
154
|
+
const v = _optionalChain([arg, 'access', _3 => _3.value, 'optionalAccess', _4 => _4.value]);
|
|
155
155
|
if (v instanceof Uint8Array) return v;
|
|
156
156
|
throw new Error("unexpected entry-function argument shape");
|
|
157
157
|
}
|
|
158
158
|
async function verifyAndSettleExactAptos(input) {
|
|
159
159
|
const { client, feePayerAddr, payload, accept } = input;
|
|
160
|
-
const railFeePayer = accept.extra.feePayer;
|
|
160
|
+
const railFeePayer = _optionalChain([accept, 'access', _5 => _5.extra, 'optionalAccess', _6 => _6.feePayer]);
|
|
161
161
|
if (!railFeePayer) throw new (0, _chunkQONQSZHJcjs.SettlementError)("Aptos exact: rail is missing extra.feePayer.");
|
|
162
162
|
if (railFeePayer !== feePayerAddr) {
|
|
163
163
|
throw new (0, _chunkQONQSZHJcjs.SettlementError)("Aptos exact: the gate relayer address does not match the rail extra.feePayer \u2014 misconfigured rail.");
|
|
@@ -179,7 +179,7 @@ async function verifyAndSettleExactAptos(input) {
|
|
|
179
179
|
}
|
|
180
180
|
const raw = tx.rawTransaction;
|
|
181
181
|
if (!tx.feePayerAddress || !tx.feePayerAddress.equals(railFeePayerAddr)) {
|
|
182
|
-
return fail("signature_invalid", `The transaction fee payer ${_nullishCoalesce(_optionalChain([tx, 'access',
|
|
182
|
+
return fail("signature_invalid", `The transaction fee payer ${_nullishCoalesce(_optionalChain([tx, 'access', _7 => _7.feePayerAddress, 'optionalAccess', _8 => _8.toString, 'call', _9 => _9()]), () => ( "(none)"))} is not the rail fee payer ${railFeePayer}.`);
|
|
183
183
|
}
|
|
184
184
|
const payloadKind = raw.payload;
|
|
185
185
|
if (!(payloadKind instanceof _tssdk.TransactionPayloadEntryFunction)) {
|
|
@@ -620,7 +620,7 @@ function makeAptosNetwork(preset, rpcUrl) {
|
|
|
620
620
|
feePayerPublicKey: feePayerAccount.publicKey,
|
|
621
621
|
transaction
|
|
622
622
|
});
|
|
623
|
-
return { success: _optionalChain([sim, 'optionalAccess',
|
|
623
|
+
return { success: _optionalChain([sim, 'optionalAccess', _10 => _10.success]) === true, vmStatus: String(_nullishCoalesce(_optionalChain([sim, 'optionalAccess', _11 => _11.vm_status]), () => ( ""))) };
|
|
624
624
|
},
|
|
625
625
|
async submit({ transaction, senderAuthenticator, feePayerAuthenticator }) {
|
|
626
626
|
const res = await aptos.transaction.submit.simple({ transaction, senderAuthenticator, feePayerAuthenticator });
|