@piprail/sdk 2.16.2 → 3.1.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.
Files changed (37) hide show
  1. package/CHANGELOG.md +448 -0
  2. package/README.md +1 -0
  3. package/dist/{algorand-Q3TUQLPK.cjs → algorand-4FTTEV7X.cjs} +212 -51
  4. package/dist/{algorand-25FMBCT3.js → algorand-KJ5XHSMT.js} +164 -3
  5. package/dist/{aptos-VBJONBFY.cjs → aptos-5QBXJ6NV.cjs} +255 -39
  6. package/dist/{aptos-SBV6SGDP.js → aptos-H5VLH2QL.js} +217 -1
  7. package/dist/{chunk-QONQSZHJ.cjs → chunk-6XTNI2OQ.cjs} +44 -44
  8. package/dist/{chunk-OXEFPLZA.cjs → chunk-6ZRAIQXF.cjs} +4 -4
  9. package/dist/chunk-GVCGUSTE.js +30 -0
  10. package/dist/{chunk-V2IJ5HUW.cjs → chunk-MZAJQYM3.cjs} +1 -0
  11. package/dist/chunk-MZXVXC3C.cjs +30 -0
  12. package/dist/{chunk-2CX7XRZK.js → chunk-TZDVZCTC.js} +1 -0
  13. package/dist/{chunk-C52H5TYB.js → chunk-YXBQKBDH.js} +2 -2
  14. package/dist/index.cjs +2906 -1262
  15. package/dist/index.d.cts +679 -21
  16. package/dist/index.d.ts +679 -21
  17. package/dist/index.js +2678 -1034
  18. package/dist/{ledger-Crc1bZox.d.cts → ledger-DkHUORUe.d.cts} +7 -0
  19. package/dist/{ledger-Crc1bZox.d.ts → ledger-DkHUORUe.d.ts} +7 -0
  20. package/dist/{near-OLKCMTBI.js → near-5X2CQGML.js} +197 -1
  21. package/dist/{near-5LTTDU6G.cjs → near-XSQXEIHT.cjs} +242 -46
  22. package/dist/node.d.cts +2 -2
  23. package/dist/node.d.ts +2 -2
  24. package/dist/{solana-AI2G7V33.cjs → solana-TIEJV742.cjs} +218 -53
  25. package/dist/{solana-HTKDRTD3.js → solana-WRXL54MR.js} +174 -9
  26. package/dist/{stellar-E2KWEV2E.cjs → stellar-5GMZJBTA.cjs} +200 -30
  27. package/dist/{stellar-EUFZLX6J.js → stellar-YQLOIFDD.js} +172 -2
  28. package/dist/{sui-KCIITCYH.js → sui-JFQSDNSZ.js} +165 -3
  29. package/dist/{sui-Q3NJOJZS.cjs → sui-WIZEAO7E.cjs} +185 -23
  30. package/dist/{ton-J7TQWRN4.cjs → ton-AGTKLQA5.cjs} +264 -22
  31. package/dist/{ton-WH2JVQOO.js → ton-OZKFNRLT.js} +244 -2
  32. package/dist/{tron-FXBXDNEY.js → tron-HG3IOOCG.js} +283 -1
  33. package/dist/{tron-HIPMOX7S.cjs → tron-S4WX7OHY.cjs} +323 -41
  34. package/dist/{xrpl-RUOB37QH.js → xrpl-5K444RGX.js} +238 -6
  35. package/dist/{xrpl-SVVS445B.cjs → xrpl-G2FKFXRI.cjs} +289 -57
  36. package/package.json +12 -2
  37. package/dist/{chunk-QU25LSVS.js → chunk-5GRBEMCA.js} +44 -44
@@ -1,7 +1,10 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } 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 _chunkOXEFPLZAcjs = require('./chunk-OXEFPLZA.cjs');
4
- require('./chunk-V2IJ5HUW.cjs');
3
+ var _chunk6ZRAIQXFcjs = require('./chunk-6ZRAIQXF.cjs');
4
+ require('./chunk-MZAJQYM3.cjs');
5
+
6
+
7
+ var _chunkMZXVXC3Ccjs = require('./chunk-MZXVXC3C.cjs');
5
8
 
6
9
 
7
10
  var _chunkCQREG5LEcjs = require('./chunk-CQREG5LE.cjs');
@@ -18,7 +21,8 @@ var _chunkCQREG5LEcjs = require('./chunk-CQREG5LE.cjs');
18
21
 
19
22
 
20
23
 
21
- var _chunkQONQSZHJcjs = require('./chunk-QONQSZHJ.cjs');
24
+
25
+ var _chunk6XTNI2OQcjs = require('./chunk-6XTNI2OQ.cjs');
22
26
 
23
27
  // src/drivers/xrpl/index.ts
24
28
  var _xrpl = require('xrpl');
@@ -85,6 +89,13 @@ async function payXrpl(params) {
85
89
  client.feeDrops(),
86
90
  client.currentLedgerIndex()
87
91
  ]);
92
+ for (const [field, value] of [["Sequence", sequence], ["LastLedgerSequence", ledgerIndex]]) {
93
+ if (!Number.isSafeInteger(value) || value < 0) {
94
+ throw new Error(
95
+ `XRPL: could not read ${field} from the ledger (got ${String(value)}) \u2014 the RPC read failed or was throttled. NOTHING was signed or submitted, so this is safe to retry. A dedicated rpcUrl avoids the public cluster's rate limits.`
96
+ );
97
+ }
98
+ }
88
99
  const tx = {
89
100
  TransactionType: "Payment",
90
101
  Account: wallet.classicAddress,
@@ -103,17 +114,17 @@ async function payXrpl(params) {
103
114
  const code = res.engine_result;
104
115
  if (code.startsWith("tes")) return _nullishCoalesce(_optionalChain([res, 'access', _ => _.tx_json, 'optionalAccess', _2 => _2.hash]), () => ( signed.hash));
105
116
  const recipientMsg = recipientNotReadyMessage(code);
106
- if (recipientMsg) throw new (0, _chunkQONQSZHJcjs.RecipientNotReadyError)(recipientMsg, { cause: makeEngineError(res) });
117
+ if (recipientMsg) throw new (0, _chunk6XTNI2OQcjs.RecipientNotReadyError)(recipientMsg, { cause: makeEngineError(res) });
107
118
  if (isAffordabilityCode(code)) {
108
- throw new (0, _chunkQONQSZHJcjs.InsufficientFundsError)(
119
+ throw new (0, _chunk6XTNI2OQcjs.InsufficientFundsError)(
109
120
  `XRPL payment rejected: the sender can't cover it \u2014 balance or the 1 XRP base reserve. (XRPL: ${code})`,
110
121
  { cause: makeEngineError(res) }
111
122
  );
112
123
  }
113
124
  throw makeEngineError(res);
114
125
  } catch (err) {
115
- if (err instanceof _chunkQONQSZHJcjs.InsufficientFundsError || err instanceof _chunkQONQSZHJcjs.RecipientNotReadyError) throw err;
116
- throw _nullishCoalesce(_chunkQONQSZHJcjs.toInsufficientFundsError.call(void 0, err), () => ( err));
126
+ if (err instanceof _chunk6XTNI2OQcjs.InsufficientFundsError || err instanceof _chunk6XTNI2OQcjs.RecipientNotReadyError) throw err;
127
+ throw _nullishCoalesce(_chunk6XTNI2OQcjs.toInsufficientFundsError.call(void 0, err), () => ( err));
117
128
  }
118
129
  }
119
130
  function amountForAccept(accept) {
@@ -150,6 +161,197 @@ function isAffordabilityCode(code) {
150
161
  return /^(tecUNFUNDED|tecINSUFF|terINSUF)/.test(code);
151
162
  }
152
163
 
164
+ // src/drivers/xrpl/swap.ts
165
+ var SOURCE = {
166
+ kind: "protocol",
167
+ name: "XRPL DEX + AMM",
168
+ note: "Rate from the ledger\u2019s own order books and AMM pools, read live via ripple_path_find, with auto-bridging through XRP where cheaper. Order books charge no protocol fee; AMM pools charge a per-pool fee (0%\u20131%) paid to the pool."
169
+ };
170
+ function toAmount(t, base) {
171
+ if (t.asset === "native") return base.toString();
172
+ const parts = parseXrplAssetId(t.asset);
173
+ if (!parts) throw new Error(`XRPL: malformed asset id "${t.asset}".`);
174
+ return { currency: parts.currencyHex, issuer: parts.issuer, value: _chunk6XTNI2OQcjs.formatUnits.call(void 0, base, t.decimals) };
175
+ }
176
+ function parseCeil(value, decimals) {
177
+ const [whole = "0", frac = ""] = value.trim().split(".");
178
+ const kept = frac.slice(0, decimals).padEnd(decimals, "0");
179
+ const rest = frac.slice(decimals);
180
+ const base = BigInt(whole + kept);
181
+ return /[1-9]/.test(rest) ? base + 1n : base;
182
+ }
183
+ function fromAmount(t, a) {
184
+ if (a == null) return null;
185
+ try {
186
+ return typeof a === "string" ? BigInt(a) : parseCeil(a.value, t.decimals);
187
+ } catch (e2) {
188
+ return null;
189
+ }
190
+ }
191
+ function sourceCurrency(t) {
192
+ if (t.asset === "native") return { currency: "XRP" };
193
+ const parts = parseXrplAssetId(t.asset);
194
+ if (!parts) throw new Error(`XRPL: malformed asset id "${t.asset}".`);
195
+ return { currency: parts.currencyHex, issuer: parts.issuer };
196
+ }
197
+ function side(t, amount) {
198
+ return {
199
+ asset: t.asset,
200
+ symbol: _nullishCoalesce(t.symbol, () => ( (t.asset === "native" ? XRP_SYMBOL : t.asset))),
201
+ decimals: t.asset === "native" ? XRP_DECIMALS : t.decimals,
202
+ amount: amount.toString(),
203
+ amountFormatted: _chunk6XTNI2OQcjs.formatUnits.call(void 0, amount, t.asset === "native" ? XRP_DECIMALS : t.decimals)
204
+ };
205
+ }
206
+ async function quoteXrplSwap(p) {
207
+ if (p.from.asset === p.to.asset) return null;
208
+ if (p.wantAmount <= 0n) return null;
209
+ let alternatives = [];
210
+ for (let attempt = 0; attempt < 2; attempt += 1) {
211
+ try {
212
+ const res = await p.client.pathFind({
213
+ source_account: p.owner,
214
+ destination_account: p.owner,
215
+ // ← ourselves: this is what makes it a swap
216
+ destination_amount: toAmount(p.to, p.wantAmount),
217
+ source_currencies: [sourceCurrency(p.from)]
218
+ });
219
+ alternatives = _nullishCoalesce(res.alternatives, () => ( []));
220
+ } catch (e3) {
221
+ alternatives = [];
222
+ }
223
+ if (alternatives.length) break;
224
+ if (attempt === 0) await new Promise((r) => setTimeout(r, 600));
225
+ }
226
+ if (!alternatives.length) return null;
227
+ let best = null;
228
+ let bestSpend = null;
229
+ for (const alt of alternatives) {
230
+ const spend = fromAmount(p.from, alt.source_amount);
231
+ if (spend == null || spend <= 0n) continue;
232
+ if (bestSpend == null || spend < bestSpend) {
233
+ bestSpend = spend;
234
+ best = alt;
235
+ }
236
+ }
237
+ if (!best || bestSpend == null) return null;
238
+ const maxSpend = _chunkMZXVXC3Ccjs.applySlippage.call(void 0, bestSpend, p.slippageBps);
239
+ return {
240
+ source: SOURCE,
241
+ network: p.network,
242
+ from: side(p.from, bestSpend),
243
+ to: side(p.to, p.wantAmount),
244
+ maxSpend: maxSpend.toString(),
245
+ maxSpendFormatted: _chunk6XTNI2OQcjs.formatUnits.call(void 0, maxSpend, p.from.asset === "native" ? XRP_DECIMALS : p.from.decimals),
246
+ slippageBps: p.slippageBps,
247
+ // `paths_computed` drops straight into the transaction's Paths field.
248
+ route: { paths: _nullishCoalesce(best.paths_computed, () => ( [])), from: p.from, to: p.to }
249
+ };
250
+ }
251
+ function sanitizePaths(paths) {
252
+ if (!Array.isArray(paths)) return [];
253
+ return paths.map(
254
+ (path) => (Array.isArray(path) ? path : []).map((raw) => {
255
+ const step = raw;
256
+ const clean = {};
257
+ if (typeof step.account === "string") clean.account = step.account;
258
+ if (typeof step.currency === "string") clean.currency = step.currency;
259
+ if (typeof step.issuer === "string") clean.issuer = step.issuer;
260
+ return clean;
261
+ }).filter((step) => Object.keys(step).length > 0)
262
+ ).filter((path) => path.length > 0);
263
+ }
264
+ async function swapXrpl(p) {
265
+ const { client, wallet, quote } = p;
266
+ const route = quote.route;
267
+ if (!_optionalChain([route, 'optionalAccess', _3 => _3.from]) || !_optionalChain([route, 'optionalAccess', _4 => _4.to])) {
268
+ throw new Error("XRPL: swap quote is missing its routing data \u2014 re-quote before swapping.");
269
+ }
270
+ try {
271
+ const [sequence, feeDrops, ledgerIndex] = await Promise.all([
272
+ client.accountSequence(wallet.classicAddress),
273
+ client.feeDrops(),
274
+ client.currentLedgerIndex()
275
+ ]);
276
+ const tx = {
277
+ TransactionType: "Payment",
278
+ Account: wallet.classicAddress,
279
+ Destination: wallet.classicAddress,
280
+ // ← ourselves: the ledger's own swap idiom
281
+ Amount: toAmount(route.to, BigInt(quote.to.amount)),
282
+ // exact output
283
+ SendMax: toAmount(route.from, BigInt(quote.maxSpend)),
284
+ // the on-chain slippage cap
285
+ // Sanitized: raw path steps from ripple_path_find can break xrpl.js encoding.
286
+ ...sanitizePaths(route.paths).length ? { Paths: sanitizePaths(route.paths) } : {},
287
+ Sequence: sequence,
288
+ Fee: feeForSubmit2(feeDrops),
289
+ LastLedgerSequence: ledgerIndex + 20,
290
+ // NOT tfPartialPayment: we want the full `Amount` delivered or nothing at all.
291
+ Flags: 0
292
+ };
293
+ let signed;
294
+ try {
295
+ signed = wallet.sign(tx);
296
+ } catch (cause) {
297
+ const shape = Object.fromEntries(
298
+ Object.entries(tx).map(([k, v]) => [k, typeof v === "object" ? JSON.stringify(v) : `${typeof v}:${String(v)}`])
299
+ );
300
+ throw new Error(
301
+ `XRPL could not encode the swap transaction: ${String(_nullishCoalesce(_optionalChain([cause, 'optionalAccess', _5 => _5.message]), () => ( cause)))}. Transaction was ${JSON.stringify(shape)}`,
302
+ { cause }
303
+ );
304
+ }
305
+ const res = await client.submit(signed.tx_blob);
306
+ const code = res.engine_result;
307
+ if (code.startsWith("tes")) {
308
+ return {
309
+ transaction: _nullishCoalesce(_optionalChain([res, 'access', _6 => _6.tx_json, 'optionalAccess', _7 => _7.hash]), () => ( signed.hash)),
310
+ network: quote.network,
311
+ source: quote.source,
312
+ from: quote.from,
313
+ to: quote.to
314
+ };
315
+ }
316
+ throw mapEngineResult(code, res);
317
+ } catch (err) {
318
+ if (err instanceof _chunk6XTNI2OQcjs.InsufficientFundsError || err instanceof _chunk6XTNI2OQcjs.RecipientNotReadyError) throw err;
319
+ throw _nullishCoalesce(_chunk6XTNI2OQcjs.toInsufficientFundsError.call(void 0, err), () => ( err));
320
+ }
321
+ }
322
+ function feeForSubmit2(openLedgerFee) {
323
+ try {
324
+ const f = BigInt(openLedgerFee);
325
+ const padded = f * 2n;
326
+ return (padded < 10n ? 10n : padded).toString();
327
+ } catch (e4) {
328
+ return "12";
329
+ }
330
+ }
331
+ function mapEngineResult(code, res) {
332
+ const err = new Error(`XRPL swap rejected: ${code}`);
333
+ err.cause = res;
334
+ if (code === "tecPATH_PARTIAL" || code === "tecPATH_DRY") {
335
+ return new (0, _chunk6XTNI2OQcjs.InsufficientFundsError)(
336
+ `XRPL swap refused: the price moved past your slippage cap, or the path ran dry, so nothing was spent. Re-quote and retry, or raise slippageBps. (XRPL: ${code})`,
337
+ { cause: res }
338
+ );
339
+ }
340
+ if (code === "tecNO_LINE" || code === "tecNO_AUTH" || code === "tecNO_ISSUER") {
341
+ return new (0, _chunk6XTNI2OQcjs.RecipientNotReadyError)(
342
+ `XRPL swap refused: your account needs a trustline for the currency you're swapping INTO before it can hold it. (XRPL: ${code})`,
343
+ { cause: res }
344
+ );
345
+ }
346
+ if (code === "tecUNFUNDED_PAYMENT" || code === "terINSUF_FEE_B" || code === "tecINSUFF_FEE") {
347
+ return new (0, _chunk6XTNI2OQcjs.InsufficientFundsError)(
348
+ `XRPL swap failed: the account can't cover it \u2014 balance or the 1 XRP base reserve. (XRPL: ${code})`,
349
+ { cause: res }
350
+ );
351
+ }
352
+ return err;
353
+ }
354
+
153
355
  // src/drivers/xrpl/exact.ts
154
356
  var _crypto = require('crypto');
155
357
  var SECONDS_PER_LEDGER = 4;
@@ -165,12 +367,12 @@ var MAX_FEE_DROPS = 1e6;
165
367
  var TF_FULLY_CANONICAL_SIG = 2147483648;
166
368
  var TF_PARTIAL_PAYMENT = 131072;
167
369
  function feesAreSponsored(accept) {
168
- return _optionalChain([accept, 'access', _3 => _3.extra, 'optionalAccess', _4 => _4.areFeesSponsored]) === true;
370
+ return _optionalChain([accept, 'access', _8 => _8.extra, 'optionalAccess', _9 => _9.areFeesSponsored]) === true;
169
371
  }
170
372
  function invoiceIdHash(invoiceId) {
171
373
  return _crypto.createHash.call(void 0, "sha256").update(invoiceId, "utf8").digest("hex").toUpperCase();
172
374
  }
173
- function feeForSubmit2(openLedgerFee) {
375
+ function feeForSubmit3(openLedgerFee) {
174
376
  const fee = Number(openLedgerFee);
175
377
  const chosen = Number.isFinite(fee) && fee > MIN_FEE_DROPS ? Math.ceil(fee) : MIN_FEE_DROPS;
176
378
  return String(Math.min(chosen, MAX_FEE_DROPS));
@@ -178,23 +380,23 @@ function feeForSubmit2(openLedgerFee) {
178
380
  async function payExactXrpl(input) {
179
381
  const { client, wallet, accept } = input;
180
382
  if (!isXrpNative(accept.asset)) {
181
- throw new (0, _chunkQONQSZHJcjs.UnsupportedSchemeError)(
383
+ throw new (0, _chunk6XTNI2OQcjs.UnsupportedSchemeError)(
182
384
  `XRPL exact currently signs native XRP only \u2014 ${accept.asset} is an issued currency, whose wire amount is a decimal rather than base units and would misprice the spend cap. Pay it via onchain-proof.`
183
385
  );
184
386
  }
185
387
  if (feesAreSponsored(accept)) {
186
- throw new (0, _chunkQONQSZHJcjs.UnsupportedSchemeError)(
388
+ throw new (0, _chunk6XTNI2OQcjs.UnsupportedSchemeError)(
187
389
  "XRPL exact rail advertises areFeesSponsored:true, but the XRP Ledger charges the fee to the transaction Account \u2014 the scheme requires false and PipRail cannot honour a sponsor here."
188
390
  );
189
391
  }
190
- const method = _chunkOXEFPLZAcjs.exactTransferMethod.call(void 0, accept, "xrpl");
392
+ const method = _chunk6ZRAIQXFcjs.exactTransferMethod.call(void 0, accept, "xrpl");
191
393
  if (method !== "sequence") {
192
- throw new (0, _chunkQONQSZHJcjs.UnsupportedSchemeError)(
394
+ throw new (0, _chunk6XTNI2OQcjs.UnsupportedSchemeError)(
193
395
  `XRPL exact: unsupported assetTransferMethod "${method}". Only "sequence" is signable \u2014 "ticketSequence" needs a Ticket pre-minted on the payer account, which PipRail does not manage.`
194
396
  );
195
397
  }
196
398
  if (!/^[0-9]+$/.test(accept.amount)) {
197
- throw new (0, _chunkQONQSZHJcjs.UnsupportedSchemeError)(
399
+ throw new (0, _chunk6XTNI2OQcjs.UnsupportedSchemeError)(
198
400
  `XRPL exact: native amount "${accept.amount}" is not an integer drops string.`
199
401
  );
200
402
  }
@@ -209,8 +411,8 @@ async function payExactXrpl(input) {
209
411
  client.currentLedgerIndex()
210
412
  ]);
211
413
  } catch (err) {
212
- if (/actNotFound/i.test(String(_nullishCoalesce(_optionalChain([err, 'optionalAccess', _5 => _5.message]), () => ( err))))) {
213
- throw new (0, _chunkQONQSZHJcjs.InsufficientFundsError)(
414
+ if (/actNotFound/i.test(String(_nullishCoalesce(_optionalChain([err, 'optionalAccess', _10 => _10.message]), () => ( err))))) {
415
+ throw new (0, _chunk6XTNI2OQcjs.InsufficientFundsError)(
214
416
  `XRPL exact: the payer account ${wallet.classicAddress} does not exist on the ledger. An XRPL account must hold the base reserve (currently 1 XRP) before it can send anything \u2014 fund it first.`,
215
417
  { cause: err instanceof Error ? err : new Error(String(err)) }
216
418
  );
@@ -224,25 +426,25 @@ async function payExactXrpl(input) {
224
426
  Amount: accept.amount,
225
427
  // integer drops, verbatim from the trusted accept
226
428
  Sequence: sequence,
227
- Fee: feeForSubmit2(openLedgerFee),
429
+ Fee: feeForSubmit3(openLedgerFee),
228
430
  LastLedgerSequence: ledgerIndex + ledgerWindowFor(accept.maxTimeoutSeconds),
229
431
  // tfFullyCanonicalSig ON, tfPartialPayment OFF — the shape every other XRPL client sends.
230
432
  Flags: TF_FULLY_CANONICAL_SIG
231
433
  };
232
- if (typeof _optionalChain([accept, 'access', _6 => _6.extra, 'optionalAccess', _7 => _7.destinationTag]) === "number") {
434
+ if (typeof _optionalChain([accept, 'access', _11 => _11.extra, 'optionalAccess', _12 => _12.destinationTag]) === "number") {
233
435
  tx.DestinationTag = accept.extra.destinationTag;
234
436
  }
235
- if (typeof _optionalChain([accept, 'access', _8 => _8.extra, 'optionalAccess', _9 => _9.sourceTag]) === "number") {
437
+ if (typeof _optionalChain([accept, 'access', _13 => _13.extra, 'optionalAccess', _14 => _14.sourceTag]) === "number") {
236
438
  tx.SourceTag = accept.extra.sourceTag;
237
439
  }
238
- if (typeof _optionalChain([accept, 'access', _10 => _10.extra, 'optionalAccess', _11 => _11.invoiceId]) === "string" && accept.extra.invoiceId.length > 0) {
440
+ if (typeof _optionalChain([accept, 'access', _15 => _15.extra, 'optionalAccess', _16 => _16.invoiceId]) === "string" && accept.extra.invoiceId.length > 0) {
239
441
  tx.InvoiceID = invoiceIdHash(accept.extra.invoiceId);
240
442
  }
241
443
  let signed;
242
444
  try {
243
445
  signed = wallet.sign(tx);
244
446
  } catch (err) {
245
- throw new (0, _chunkQONQSZHJcjs.UnsupportedSchemeError)(
447
+ throw new (0, _chunk6XTNI2OQcjs.UnsupportedSchemeError)(
246
448
  `XRPL exact: could not sign this rail \u2014 ${err instanceof Error ? err.message : String(err)}`,
247
449
  { cause: err instanceof Error ? err : new Error(String(err)) }
248
450
  );
@@ -262,7 +464,7 @@ async function verifyAndSettleExactXrpl(input) {
262
464
  const attempts = _nullishCoalesce(input.pollAttempts, () => ( 8));
263
465
  const sleep = _nullishCoalesce(input.sleep, () => ( ((ms) => new Promise((r) => setTimeout(r, ms)))));
264
466
  if (feesAreSponsored(accept)) {
265
- throw new (0, _chunkQONQSZHJcjs.SettlementError)("XRPL exact: rail advertises areFeesSponsored:true, which this ledger cannot honour.");
467
+ throw new (0, _chunk6XTNI2OQcjs.SettlementError)("XRPL exact: rail advertises areFeesSponsored:true, which this ledger cannot honour.");
266
468
  }
267
469
  let tx;
268
470
  try {
@@ -295,10 +497,10 @@ async function verifyAndSettleExactXrpl(input) {
295
497
  if (tx.Amount !== accept.amount) {
296
498
  return fail("amount_too_low", `XRPL exact: Amount ${String(tx.Amount)} \u2260 the rail's ${accept.amount} drops.`);
297
499
  }
298
- if (typeof _optionalChain([accept, 'access', _12 => _12.extra, 'optionalAccess', _13 => _13.destinationTag]) === "number" && tx.DestinationTag !== accept.extra.destinationTag) {
500
+ if (typeof _optionalChain([accept, 'access', _17 => _17.extra, 'optionalAccess', _18 => _18.destinationTag]) === "number" && tx.DestinationTag !== accept.extra.destinationTag) {
299
501
  return fail("signature_invalid", `XRPL exact: DestinationTag ${String(tx.DestinationTag)} \u2260 the rail's ${accept.extra.destinationTag}.`);
300
502
  }
301
- if (typeof _optionalChain([accept, 'access', _14 => _14.extra, 'optionalAccess', _15 => _15.invoiceId]) === "string" && accept.extra.invoiceId.length > 0) {
503
+ if (typeof _optionalChain([accept, 'access', _19 => _19.extra, 'optionalAccess', _20 => _20.invoiceId]) === "string" && accept.extra.invoiceId.length > 0) {
302
504
  const want = invoiceIdHash(accept.extra.invoiceId);
303
505
  if (String(_nullishCoalesce(tx.InvoiceID, () => ( ""))).toUpperCase() !== want) {
304
506
  return fail("signature_invalid", "XRPL exact: InvoiceID does not bind this challenge.");
@@ -317,24 +519,24 @@ async function verifyAndSettleExactXrpl(input) {
317
519
  `XRPL exact: submit rejected \u2014 ${res.engine_result}${res.engine_result_message ? ` (${res.engine_result_message})` : ""}.`
318
520
  );
319
521
  }
320
- hash = _nullishCoalesce(_optionalChain([res, 'access', _16 => _16.tx_json, 'optionalAccess', _17 => _17.hash]), () => ( ""));
522
+ hash = _nullishCoalesce(_optionalChain([res, 'access', _21 => _21.tx_json, 'optionalAccess', _22 => _22.hash]), () => ( ""));
321
523
  if (!hash) throw new Error("submit returned no transaction hash");
322
524
  } catch (err) {
323
- throw new (0, _chunkQONQSZHJcjs.SettlementError)(`XRPL exact: submit failed (${err instanceof Error ? err.message : String(err)}).`);
525
+ throw new (0, _chunk6XTNI2OQcjs.SettlementError)(`XRPL exact: submit failed (${err instanceof Error ? err.message : String(err)}).`);
324
526
  }
325
527
  for (let i = 0; i < attempts; i += 1) {
326
528
  let record;
327
529
  try {
328
530
  record = await client.txByHash(hash);
329
- } catch (e2) {
531
+ } catch (e5) {
330
532
  record = null;
331
533
  }
332
- if (_optionalChain([record, 'optionalAccess', _18 => _18.validated])) {
333
- const code = _optionalChain([record, 'access', _19 => _19.meta, 'optionalAccess', _20 => _20.TransactionResult]);
534
+ if (_optionalChain([record, 'optionalAccess', _23 => _23.validated])) {
535
+ const code = _optionalChain([record, 'access', _24 => _24.meta, 'optionalAccess', _25 => _25.TransactionResult]);
334
536
  if (code !== "tesSUCCESS") {
335
537
  return fail("transfer_not_found", `XRPL exact: validated with ${String(code)}, not tesSUCCESS.`);
336
538
  }
337
- const delivered = _optionalChain([record, 'access', _21 => _21.meta, 'optionalAccess', _22 => _22.delivered_amount]);
539
+ const delivered = _optionalChain([record, 'access', _26 => _26.meta, 'optionalAccess', _27 => _27.delivered_amount]);
338
540
  if (delivered !== void 0 && typeof delivered === "string" && delivered !== accept.amount) {
339
541
  return fail("amount_too_low", `XRPL exact: delivered ${delivered} drops, expected ${accept.amount}.`);
340
542
  }
@@ -355,7 +557,7 @@ async function verifyAndSettleExactXrpl(input) {
355
557
  }
356
558
  await sleep(1200);
357
559
  }
358
- throw new (0, _chunkQONQSZHJcjs.SettlementError)(
560
+ throw new (0, _chunk6XTNI2OQcjs.SettlementError)(
359
561
  `XRPL exact: submitted ${hash} but it was not validated within ${attempts} polls. It may still settle; retry the request.`
360
562
  );
361
563
  }
@@ -371,7 +573,7 @@ async function verifyXrpl(params) {
371
573
  let txs;
372
574
  try {
373
575
  txs = await reader.transactionsForAccount(accept.payTo, 200);
374
- } catch (e3) {
576
+ } catch (e6) {
375
577
  return rpcFailed(nonce);
376
578
  }
377
579
  const tx = txs.find(
@@ -435,7 +637,7 @@ async function verifyXrpl(params) {
435
637
  }
436
638
  function hasNonceMemo(memos, wantMemo) {
437
639
  if (!memos) return false;
438
- return memos.some((m) => (_nullishCoalesce(_optionalChain([m, 'access', _23 => _23.Memo, 'optionalAccess', _24 => _24.MemoData]), () => ( ""))).toUpperCase() === wantMemo);
640
+ return memos.some((m) => (_nullishCoalesce(_optionalChain([m, 'access', _28 => _28.Memo, 'optionalAccess', _29 => _29.MemoData]), () => ( ""))).toUpperCase() === wantMemo);
439
641
  }
440
642
  function deliveredBaseUnits(delivered, want, decimals) {
441
643
  if (delivered === void 0) return null;
@@ -449,8 +651,8 @@ function deliveredBaseUnits(delivered, want, decimals) {
449
651
  return null;
450
652
  }
451
653
  try {
452
- return _chunkQONQSZHJcjs.floorUnits.call(void 0, delivered.value, decimals);
453
- } catch (e4) {
654
+ return _chunk6XTNI2OQcjs.floorUnits.call(void 0, delivered.value, decimals);
655
+ } catch (e7) {
454
656
  return null;
455
657
  }
456
658
  }
@@ -473,13 +675,13 @@ function rpcFailed(nonce) {
473
675
 
474
676
  function assertXrplWallet(wallet, network) {
475
677
  if (typeof wallet !== "object" || wallet === null) {
476
- throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)(
678
+ throw new (0, _chunk6XTNI2OQcjs.WrongFamilyError)(
477
679
  `chain ${network} is XRPL; wallet must be { key } (s\u2026 seed) or { wallet }.`
478
680
  );
479
681
  }
480
- _chunkQONQSZHJcjs.assertNoLegacyWalletKey.call(void 0, wallet, "XRPL");
682
+ _chunk6XTNI2OQcjs.assertNoLegacyWalletKey.call(void 0, wallet, "XRPL");
481
683
  if (!("key" in wallet) && !("wallet" in wallet)) {
482
- throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)(
684
+ throw new (0, _chunk6XTNI2OQcjs.WrongFamilyError)(
483
685
  `chain ${network} is XRPL; wallet must be { key } (s\u2026 seed) or { wallet }.`
484
686
  );
485
687
  }
@@ -489,17 +691,19 @@ function resolveXrplWallet(config) {
489
691
  if (config.wallet) return config.wallet;
490
692
  if (config.key) {
491
693
  if (!_xrpl.isValidSecret.call(void 0, config.key)) {
492
- throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)("XRPL wallet { key } is not a valid s\u2026 secret seed.");
694
+ throw new (0, _chunk6XTNI2OQcjs.WrongFamilyError)("XRPL wallet { key } is not a valid s\u2026 secret seed.");
493
695
  }
494
696
  return _xrpl.Wallet.fromSeed(config.key);
495
697
  }
496
- throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)("XRPL wallet needs { key } (s\u2026 seed) or { wallet }.");
698
+ throw new (0, _chunk6XTNI2OQcjs.WrongFamilyError)("XRPL wallet needs { key } (s\u2026 seed) or { wallet }.");
497
699
  }
498
700
 
499
701
  // src/drivers/xrpl/index.ts
500
702
  function isXrplActNotFound(e) {
501
- return /actNotFound/i.test(String(_nullishCoalesce(_optionalChain([e, 'optionalAccess', _25 => _25.message]), () => ( e))));
703
+ return /actNotFound/i.test(String(_nullishCoalesce(_optionalChain([e, 'optionalAccess', _30 => _30.message]), () => ( e))));
502
704
  }
705
+ var XRPL_BASE_RESERVE_DROPS = 1000000n;
706
+ var XRPL_OWNER_RESERVE_DROPS = 200000n;
503
707
  var xrplDriver = {
504
708
  family: "xrpl",
505
709
  resolve(opts) {
@@ -520,11 +724,14 @@ function makeXrplNetwork(preset, rpcUrl) {
520
724
  const json = await res.json();
521
725
  const result = json.result;
522
726
  if (!result || result.status === "error" || result.error) {
523
- throw new Error(`XRPL RPC ${method} error: ${_nullishCoalesce(_optionalChain([result, 'optionalAccess', _26 => _26.error]), () => ( "unknown"))}`);
727
+ throw new Error(`XRPL RPC ${method} error: ${_nullishCoalesce(_optionalChain([result, 'optionalAccess', _31 => _31.error]), () => ( "unknown"))}`);
524
728
  }
525
729
  return result;
526
730
  }
527
731
  const payClient = {
732
+ async pathFind(params) {
733
+ return rpc("ripple_path_find", { ...params, ledger_index: "current" });
734
+ },
528
735
  async accountSequence(account) {
529
736
  const r = await rpc("account_info", {
530
737
  account,
@@ -549,7 +756,7 @@ function makeXrplNetwork(preset, rpcUrl) {
549
756
  async txByHash(hash) {
550
757
  try {
551
758
  return await rpc("tx", { transaction: hash, binary: false });
552
- } catch (e5) {
759
+ } catch (e8) {
553
760
  return null;
554
761
  }
555
762
  }
@@ -578,7 +785,7 @@ function makeXrplNetwork(preset, rpcUrl) {
578
785
  const info = preset.tokens[token.toUpperCase()];
579
786
  if (!info) {
580
787
  const known = Object.keys(preset.tokens).join(", ") || "(none built in)";
581
- throw new (0, _chunkQONQSZHJcjs.UnknownTokenError)(
788
+ throw new (0, _chunk6XTNI2OQcjs.UnknownTokenError)(
582
789
  `token "${token}" isn't built in for XRPL (known: ${known}). Pass { issuer, currencyHex, decimals } for a custom IOU, or use 'native'.`
583
790
  );
584
791
  }
@@ -588,10 +795,10 @@ function makeXrplNetwork(preset, rpcUrl) {
588
795
  symbol: info.symbol
589
796
  };
590
797
  }
591
- _chunkQONQSZHJcjs.rejectForeignToken.call(void 0, token, "xrpl", network);
798
+ _chunk6XTNI2OQcjs.rejectForeignToken.call(void 0, token, "xrpl", network);
592
799
  const t = token;
593
800
  if (!t.issuer || !t.currencyHex || typeof t.decimals !== "number") {
594
- throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)(
801
+ throw new (0, _chunk6XTNI2OQcjs.WrongFamilyError)(
595
802
  `chain ${network} is XRPL; a custom token must be { issuer, currencyHex, decimals }.`
596
803
  );
597
804
  }
@@ -612,12 +819,12 @@ function makeXrplNetwork(preset, rpcUrl) {
612
819
  },
613
820
  assertValidPayTo(payTo) {
614
821
  if (payTo.startsWith("0x")) {
615
- throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)(
822
+ throw new (0, _chunk6XTNI2OQcjs.WrongFamilyError)(
616
823
  `chain ${network} is XRPL, but payTo "${payTo}" looks like an EVM address.`
617
824
  );
618
825
  }
619
826
  if (!_xrpl.isValidClassicAddress.call(void 0, payTo)) {
620
- throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)(
827
+ throw new (0, _chunk6XTNI2OQcjs.WrongFamilyError)(
621
828
  `chain ${network} is XRPL, but payTo "${payTo}" is not a valid XRPL account (r\u2026).`
622
829
  );
623
830
  }
@@ -685,26 +892,26 @@ function makeXrplNetwork(preset, rpcUrl) {
685
892
  transaction: ref
686
893
  });
687
894
  if (tx.validated) return { height: String(_nullishCoalesce(tx.ledger_index, () => ( 0))) };
688
- } catch (e6) {
895
+ } catch (e9) {
689
896
  }
690
897
  await _chunkCQREG5LEcjs.delay.call(void 0, 1500);
691
898
  }
692
- throw new (0, _chunkQONQSZHJcjs.ConfirmationTimeoutError)(`XRPL tx ${ref} not validated on-ledger in time.`);
899
+ throw new (0, _chunk6XTNI2OQcjs.ConfirmationTimeoutError)(`XRPL tx ${ref} not validated on-ledger in time.`);
693
900
  },
694
901
  async estimateCost() {
695
902
  try {
696
903
  const drops = await payClient.feeDrops();
697
904
  const n = Number(drops);
698
905
  const fee = BigInt(Number.isFinite(n) && n > 12 ? Math.ceil(n) : 12);
699
- return _chunkQONQSZHJcjs.nativeCost.call(void 0, {
906
+ return _chunk6XTNI2OQcjs.nativeCost.call(void 0, {
700
907
  symbol: XRP_SYMBOL,
701
908
  decimals: XRP_DECIMALS,
702
909
  fee,
703
910
  basis: "estimated",
704
911
  detail: `network fee ${fee} drops`
705
912
  });
706
- } catch (e7) {
707
- return _chunkQONQSZHJcjs.nativeCost.call(void 0, {
913
+ } catch (e10) {
914
+ return _chunk6XTNI2OQcjs.nativeCost.call(void 0, {
708
915
  symbol: XRP_SYMBOL,
709
916
  decimals: XRP_DECIMALS,
710
917
  fee: 12n,
@@ -713,24 +920,35 @@ function makeXrplNetwork(preset, rpcUrl) {
713
920
  });
714
921
  }
715
922
  },
923
+ /** The bound wallet's own address — where THIS wallet gets paid. Derived from the key
924
+ * material only: no RPC, nothing moved. See {@link ResolvedNetwork.addressOf}. */
925
+ async addressOf(wallet) {
926
+ return resolveXrplWallet(wallet._native).classicAddress;
927
+ },
716
928
  async balanceOf(wallet, asset) {
717
929
  let owner;
718
930
  try {
719
931
  owner = resolveXrplWallet(wallet._native).classicAddress;
720
- } catch (e8) {
932
+ } catch (e11) {
721
933
  return { token: null, native: null };
722
934
  }
723
935
  let native = null;
936
+ let ownerCount = 0n;
724
937
  try {
725
938
  const r = await rpc("account_info", {
726
939
  account: owner,
727
940
  ledger_index: "validated"
728
941
  });
729
942
  native = BigInt(r.account_data.Balance);
943
+ ownerCount = BigInt(_nullishCoalesce(r.account_data.OwnerCount, () => ( 0)));
730
944
  } catch (e) {
731
945
  native = isXrplActNotFound(e) ? 0n : null;
732
946
  }
733
- if (isXrpNative(asset)) return { token: native, native };
947
+ if (isXrpNative(asset)) {
948
+ if (native === null) return { token: null, native };
949
+ const reserve = XRPL_BASE_RESERVE_DROPS + XRPL_OWNER_RESERVE_DROPS * ownerCount;
950
+ return { token: native > reserve ? native - reserve : 0n, native };
951
+ }
734
952
  let token = null;
735
953
  try {
736
954
  const [currencyHex, issuer] = asset.split(":");
@@ -741,7 +959,7 @@ function makeXrplNetwork(preset, rpcUrl) {
741
959
  const line = r.lines.find(
742
960
  (l) => l.currency.toUpperCase() === (_nullishCoalesce(currencyHex, () => ( ""))).toUpperCase() && l.account === issuer
743
961
  );
744
- token = line ? _chunkQONQSZHJcjs.floorUnits.call(void 0, line.balance, XRP_DECIMALS) : 0n;
962
+ token = line ? _chunk6XTNI2OQcjs.floorUnits.call(void 0, line.balance, XRP_DECIMALS) : 0n;
745
963
  } catch (e) {
746
964
  token = isXrplActNotFound(e) ? 0n : null;
747
965
  }
@@ -765,10 +983,24 @@ function makeXrplNetwork(preset, rpcUrl) {
765
983
  (l) => l.currency.toUpperCase() === (_nullishCoalesce(currencyHex, () => ( ""))).toUpperCase() && l.account === issuer
766
984
  );
767
985
  return has ? { ready: true } : { ready: false, reason: "NO_TRUSTLINE" };
768
- } catch (e9) {
986
+ } catch (e12) {
769
987
  return { ready: "unknown" };
770
988
  }
771
989
  },
990
+ /* ---- swap (OPTIONAL, opt-in): a cross-currency payment to yourself. See ./swap.ts ---- */
991
+ async quoteSwap({ from, to, wantAmount, slippageBps, wallet }) {
992
+ let owner;
993
+ try {
994
+ owner = resolveXrplWallet(wallet._native).classicAddress;
995
+ } catch (e13) {
996
+ return null;
997
+ }
998
+ return quoteXrplSwap({ client: payClient, network, owner, from, to, wantAmount, slippageBps });
999
+ },
1000
+ async swap(wallet, quote) {
1001
+ const w = resolveXrplWallet(wallet._native);
1002
+ return swapXrpl({ client: payClient, wallet: w, quote });
1003
+ },
772
1004
  async verify(_ref, accept) {
773
1005
  return verifyXrpl({ reader, accept });
774
1006
  }