@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,17 +1,22 @@
1
+ import {
2
+ applySlippage
3
+ } from "./chunk-GVCGUSTE.js";
1
4
  import {
2
5
  ConfirmationTimeoutError,
6
+ InsufficientFundsError,
3
7
  SettlementError,
4
8
  UnknownTokenError,
5
9
  UnsupportedSchemeError,
6
10
  WrongFamilyError,
7
11
  assertNoLegacyWalletKey,
12
+ formatUnits,
8
13
  nativeCost,
9
14
  rejectForeignToken,
10
15
  toInsufficientFundsError
11
- } from "./chunk-QU25LSVS.js";
16
+ } from "./chunk-5GRBEMCA.js";
12
17
 
13
18
  // src/drivers/solana/index.ts
14
- import { Connection, PublicKey as PublicKey3 } from "@solana/web3.js";
19
+ import { Connection as Connection2, PublicKey as PublicKey3 } from "@solana/web3.js";
15
20
  import {
16
21
  getAccount,
17
22
  getAssociatedTokenAddressSync as getAssociatedTokenAddressSync3,
@@ -102,6 +107,148 @@ async function paySolana(params) {
102
107
  return signature;
103
108
  }
104
109
 
110
+ // src/drivers/solana/swap.ts
111
+ import { VersionedTransaction } from "@solana/web3.js";
112
+ var JUPITER_API = "https://lite-api.jup.ag/swap/v1";
113
+ var WSOL_MINT = "So11111111111111111111111111111111111111112";
114
+ function sourceFor(platformFee) {
115
+ const charged = platformFee != null && !(typeof platformFee === "object" && Object.keys(platformFee).length === 0);
116
+ return {
117
+ kind: "provider",
118
+ name: "Jupiter",
119
+ note: "Third-party Solana DEX aggregator (lite-api.jup.ag), used keyless. It routes and builds the transaction; your own key signs it and Jupiter never holds your funds. " + (charged ? `\u26A0\uFE0F THIS QUOTE CARRIES A PLATFORM FEE: ${JSON.stringify(platformFee)}. PipRail did not set one.` : "This quote carries no platform fee, and PipRail adds none.")
120
+ };
121
+ }
122
+ function mintFor(t) {
123
+ return t.asset === "native" ? WSOL_MINT : t.asset;
124
+ }
125
+ function side(t, amount) {
126
+ const decimals = t.asset === "native" ? SOL_DECIMALS : t.decimals;
127
+ return {
128
+ asset: t.asset,
129
+ symbol: t.symbol ?? (t.asset === "native" ? "SOL" : t.asset),
130
+ decimals,
131
+ amount: amount.toString(),
132
+ amountFormatted: formatUnits(amount, decimals)
133
+ };
134
+ }
135
+ async function getJson(url, init) {
136
+ const ctrl = new AbortController();
137
+ const timer = setTimeout(() => ctrl.abort(), 1e4);
138
+ try {
139
+ const res = await fetch(url, { ...init ?? {}, signal: ctrl.signal });
140
+ if (!res.ok) return null;
141
+ return await res.json();
142
+ } catch {
143
+ return null;
144
+ } finally {
145
+ clearTimeout(timer);
146
+ }
147
+ }
148
+ async function quoteSolanaSwap(p) {
149
+ if (p.wantAmount <= 0n) return null;
150
+ const inputMint = mintFor(p.from);
151
+ const outputMint = mintFor(p.to);
152
+ if (inputMint === outputMint) return null;
153
+ const url = `${JUPITER_API}/quote?inputMint=${inputMint}&outputMint=${outputMint}&amount=${p.wantAmount.toString()}&swapMode=ExactOut&slippageBps=${p.slippageBps}`;
154
+ const q = await getJson(url);
155
+ if (!q?.otherAmountThreshold || !q.inAmount) return null;
156
+ if (q.swapMode !== "ExactOut") return null;
157
+ if (q.outAmount !== p.wantAmount.toString()) return null;
158
+ let spend;
159
+ let maxSpend;
160
+ try {
161
+ spend = BigInt(q.inAmount);
162
+ const jupCap = BigInt(q.otherAmountThreshold);
163
+ const ourCap = applySlippage(spend, p.slippageBps);
164
+ maxSpend = jupCap > ourCap ? jupCap : ourCap;
165
+ } catch {
166
+ return null;
167
+ }
168
+ if (spend <= 0n) return null;
169
+ const fromDecimals = p.from.asset === "native" ? SOL_DECIMALS : p.from.decimals;
170
+ return {
171
+ source: sourceFor(q.platformFee),
172
+ network: p.network,
173
+ from: side(p.from, spend),
174
+ to: side(p.to, p.wantAmount),
175
+ maxSpend: maxSpend.toString(),
176
+ maxSpendFormatted: formatUnits(maxSpend, fromDecimals),
177
+ slippageBps: p.slippageBps,
178
+ // Jupiter needs its own quote object back verbatim to build the transaction.
179
+ route: q
180
+ };
181
+ }
182
+ async function swapSolana(p) {
183
+ const { connection, keypair, quote } = p;
184
+ const jupQuote = quote.route;
185
+ if (!jupQuote?.otherAmountThreshold) {
186
+ throw new Error("Solana: swap quote is missing its Jupiter routing data \u2014 re-quote before swapping.");
187
+ }
188
+ const built = await getJson(`${JUPITER_API}/swap`, {
189
+ method: "POST",
190
+ headers: { "content-type": "application/json" },
191
+ body: JSON.stringify({
192
+ quoteResponse: jupQuote,
193
+ userPublicKey: keypair.publicKey.toBase58(),
194
+ // Let Jupiter create + close the wrapped-SOL account in the same transaction,
195
+ // so a SOL leg needs no separate setup step from the caller.
196
+ wrapAndUnwrapSol: true,
197
+ dynamicComputeUnitLimit: true
198
+ })
199
+ });
200
+ if (!built?.swapTransaction) {
201
+ throw new InsufficientFundsError(
202
+ "Jupiter could not build this swap transaction (no route, or the market moved). Nothing was spent \u2014 re-quote and retry."
203
+ );
204
+ }
205
+ let tx;
206
+ try {
207
+ tx = VersionedTransaction.deserialize(Buffer.from(built.swapTransaction, "base64"));
208
+ } catch (cause) {
209
+ throw new Error("Solana: Jupiter returned a transaction this SDK could not decode.", { cause });
210
+ }
211
+ tx.sign([keypair]);
212
+ try {
213
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
214
+ const sig = await connection.sendRawTransaction(tx.serialize(), {
215
+ skipPreflight: false,
216
+ maxRetries: 3
217
+ });
218
+ const conf = await connection.confirmTransaction(
219
+ { signature: sig, blockhash, lastValidBlockHeight },
220
+ "confirmed"
221
+ );
222
+ if (conf?.value?.err) {
223
+ throw new InsufficientFundsError(
224
+ `Solana swap failed on-chain (tx ${sig}): ${JSON.stringify(conf.value.err)}. Nothing was swapped. The usual cause is slippage \u2014 re-quote and retry.`
225
+ );
226
+ }
227
+ return {
228
+ transaction: sig,
229
+ network: quote.network,
230
+ source: quote.source,
231
+ from: quote.from,
232
+ to: quote.to
233
+ };
234
+ } catch (err) {
235
+ const msg = String(err?.message ?? err);
236
+ if (/insufficient|0x1\b/i.test(msg)) {
237
+ throw new InsufficientFundsError(
238
+ `Solana swap failed: the wallet can't cover it (token balance, or SOL for fees and rent). (${msg.slice(0, 160)})`,
239
+ { cause: err }
240
+ );
241
+ }
242
+ if (/slippage|0x1771/i.test(msg)) {
243
+ throw new InsufficientFundsError(
244
+ "Solana swap refused: the price moved past your slippage cap, so nothing was spent. Re-quote and retry, or raise slippageBps.",
245
+ { cause: err }
246
+ );
247
+ }
248
+ throw err;
249
+ }
250
+ }
251
+
105
252
  // src/drivers/solana/verify.ts
106
253
  async function verifySolana(params) {
107
254
  const { connection, signature, accept } = params;
@@ -210,7 +357,7 @@ import {
210
357
  PublicKey as PublicKey2,
211
358
  TransactionInstruction,
212
359
  TransactionMessage,
213
- VersionedTransaction
360
+ VersionedTransaction as VersionedTransaction2
214
361
  } from "@solana/web3.js";
215
362
  import {
216
363
  createTransferCheckedInstruction as createTransferCheckedInstruction2,
@@ -348,7 +495,7 @@ async function payExactSolana(input) {
348
495
  recentBlockhash: blockhash,
349
496
  instructions
350
497
  }).compileToV0Message();
351
- const tx = new VersionedTransaction(message);
498
+ const tx = new VersionedTransaction2(message);
352
499
  tx.sign([keypair]);
353
500
  const buyerIndex = message.staticAccountKeys.findIndex((k) => k.equals(keypair.publicKey));
354
501
  if (buyerIndex < 1 || buyerIndex >= message.header.numRequiredSignatures) {
@@ -396,7 +543,7 @@ async function verifyAndSettleExactSolana(input) {
396
543
  const program = tokenProgramFor(accept);
397
544
  let tx;
398
545
  try {
399
- tx = VersionedTransaction.deserialize(Buffer.from(payload.transaction, "base64"));
546
+ tx = VersionedTransaction2.deserialize(Buffer.from(payload.transaction, "base64"));
400
547
  } catch (err) {
401
548
  return fail("signature_invalid", `Unparseable SVM transaction: ${shorten(err instanceof Error ? err.message : String(err))}.`);
402
549
  }
@@ -582,7 +729,7 @@ async function pollConfirmed(connection, signature) {
582
729
  }
583
730
 
584
731
  // src/drivers/solana/wallet.ts
585
- import { Keypair as Keypair3 } from "@solana/web3.js";
732
+ import { Keypair as Keypair4 } from "@solana/web3.js";
586
733
  import bs582 from "bs58";
587
734
  function toKeypair(wallet, network) {
588
735
  if (typeof wallet !== "object" || wallet === null) {
@@ -603,7 +750,7 @@ function toKeypair(wallet, network) {
603
750
  }
604
751
  try {
605
752
  const bytes = typeof sk === "string" ? bs582.decode(sk) : sk;
606
- return Keypair3.fromSecretKey(bytes);
753
+ return Keypair4.fromSecretKey(bytes);
607
754
  } catch (err) {
608
755
  throw new WrongFamilyError(
609
756
  `chain ${network} is Solana; the wallet { key } isn't a valid Solana secret (expected a base58 secret string or a 64-byte Uint8Array): ${err instanceof Error ? err.message : String(err)}.`
@@ -616,6 +763,7 @@ function toKeypair(wallet, network) {
616
763
  }
617
764
 
618
765
  // src/drivers/solana/index.ts
766
+ var RENT_EXEMPT_MIN_LAMPORTS = 890880n;
619
767
  var solanaDriver = {
620
768
  family: "solana",
621
769
  resolve(opts) {
@@ -625,7 +773,7 @@ var solanaDriver = {
625
773
  }
626
774
  };
627
775
  function makeSolanaNetwork(preset, rpcUrl) {
628
- const connection = new Connection(rpcUrl, "confirmed");
776
+ const connection = new Connection2(rpcUrl, "confirmed");
629
777
  const network = preset.caip2;
630
778
  return {
631
779
  family: "solana",
@@ -735,10 +883,20 @@ function makeSolanaNetwork(preset, rpcUrl) {
735
883
  detail: "1 signature + recipient token-account rent (~0.00204 SOL, if not already created)"
736
884
  });
737
885
  },
886
+ /** The bound wallet's own address — where THIS wallet gets paid. Derived from the key
887
+ * material only: no RPC, nothing moved. See {@link ResolvedNetwork.addressOf}. */
888
+ async addressOf(wallet) {
889
+ return wallet._native.publicKey.toBase58();
890
+ },
738
891
  async balanceOf(wallet, asset) {
739
892
  const owner = wallet._native.publicKey;
740
893
  const native = await connection.getBalance(owner).then((n) => BigInt(n)).catch(() => null);
741
- if (asset === "native") return { token: native, native };
894
+ if (asset === "native") {
895
+ if (native === null) return { token: null, native };
896
+ const reserve = await connection.getMinimumBalanceForRentExemption(0).then((n) => BigInt(n)).catch(() => RENT_EXEMPT_MIN_LAMPORTS);
897
+ const spendable = native > reserve ? native - reserve : 0n;
898
+ return { token: spendable, native };
899
+ }
742
900
  let token;
743
901
  try {
744
902
  const mint = new PublicKey3(asset);
@@ -764,6 +922,13 @@ function makeSolanaNetwork(preset, rpcUrl) {
764
922
  async recipientReady() {
765
923
  return { ready: "n/a" };
766
924
  },
925
+ /* ---- swap (OPTIONAL, opt-in): via Jupiter, keyless + no platform fee. See ./swap.ts ---- */
926
+ async quoteSwap({ from, to, wantAmount, slippageBps }) {
927
+ return quoteSolanaSwap({ network, from, to, wantAmount, slippageBps });
928
+ },
929
+ async swap(wallet, quote) {
930
+ return swapSolana({ connection, keypair: wallet._native, quote });
931
+ },
767
932
  async verify(ref, accept) {
768
933
  return verifySolana({ connection, signature: ref, accept });
769
934
  },
@@ -1,5 +1,8 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); 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 _chunkMZXVXC3Ccjs = require('./chunk-MZXVXC3C.cjs');
4
+
5
+
3
6
  var _chunkCQREG5LEcjs = require('./chunk-CQREG5LE.cjs');
4
7
 
5
8
 
@@ -12,7 +15,8 @@ var _chunkCQREG5LEcjs = require('./chunk-CQREG5LE.cjs');
12
15
 
13
16
 
14
17
 
15
- var _chunkQONQSZHJcjs = require('./chunk-QONQSZHJ.cjs');
18
+
19
+ var _chunk6XTNI2OQcjs = require('./chunk-6XTNI2OQ.cjs');
16
20
 
17
21
  // src/drivers/stellar/index.ts
18
22
  var _stellarsdk = require('@stellar/stellar-sdk');
@@ -98,30 +102,30 @@ function mapSubmitError(err) {
98
102
  const seen = codes.join(", ");
99
103
  const has = (re) => codes.some((c) => re.test(c));
100
104
  if (has(/op_no_destination/i)) {
101
- return new (0, _chunkQONQSZHJcjs.RecipientNotReadyError)(
105
+ return new (0, _chunk6XTNI2OQcjs.RecipientNotReadyError)(
102
106
  `Stellar destination account doesn't exist yet \u2014 create it with \u22651 XLM (the base reserve) before it can receive. (Stellar: ${seen})`,
103
107
  { cause: err }
104
108
  );
105
109
  }
106
110
  if (has(/op_(no_trust|line_full|not_authorized)/i) && !has(/src_no_trust/i)) {
107
- return new (0, _chunkQONQSZHJcjs.RecipientNotReadyError)(
111
+ return new (0, _chunk6XTNI2OQcjs.RecipientNotReadyError)(
108
112
  `Stellar destination can't hold this asset \u2014 it needs a trustline for it (and to be authorized) before it can receive. (Stellar: ${seen})`,
109
113
  { cause: err }
110
114
  );
111
115
  }
112
116
  if (has(/underfunded|insufficient|low_reserve|src_no_trust/i)) {
113
- return new (0, _chunkQONQSZHJcjs.InsufficientFundsError)(
117
+ return new (0, _chunk6XTNI2OQcjs.InsufficientFundsError)(
114
118
  `Stellar payment failed: the sender can't cover it \u2014 balance, base reserve, or no trustline to send this asset. (Stellar: ${seen})`,
115
119
  { cause: err }
116
120
  );
117
121
  }
118
122
  if (isAccountNotFound(err)) {
119
- return new (0, _chunkQONQSZHJcjs.InsufficientFundsError)(
123
+ return new (0, _chunk6XTNI2OQcjs.InsufficientFundsError)(
120
124
  "Stellar source account not found on-chain \u2014 fund the sender (\u2265 base reserve) before it can pay.",
121
125
  { cause: err }
122
126
  );
123
127
  }
124
- return _nullishCoalesce(_chunkQONQSZHJcjs.toInsufficientFundsError.call(void 0, err), () => ( err));
128
+ return _nullishCoalesce(_chunk6XTNI2OQcjs.toInsufficientFundsError.call(void 0, err), () => ( err));
125
129
  }
126
130
  function isAccountNotFound(err) {
127
131
  const e = err;
@@ -133,6 +137,151 @@ function extractResultCodes(err) {
133
137
  return [_nullishCoalesce(extras.transaction, () => ( "")), ..._nullishCoalesce(extras.operations, () => ( []))].filter(Boolean);
134
138
  }
135
139
 
140
+ // src/drivers/stellar/swap.ts
141
+
142
+ var SOURCE = {
143
+ kind: "protocol",
144
+ name: "Stellar SDEX",
145
+ note: "Rate from the ledger\u2019s own order books and liquidity pools, read live from Horizon. Order books charge no trading fee; liquidity pools charge a fixed 0.30%."
146
+ };
147
+ function assetForId(asset) {
148
+ if (asset === "native") return _stellarsdk.Asset.native();
149
+ const parts = parseStellarAssetId(asset);
150
+ if (!parts) return null;
151
+ try {
152
+ return new (0, _stellarsdk.Asset)(parts.code, parts.issuer);
153
+ } catch (e2) {
154
+ return null;
155
+ }
156
+ }
157
+ function hopToAsset(h) {
158
+ return h.asset_type === "native" ? _stellarsdk.Asset.native() : new (0, _stellarsdk.Asset)(h.asset_code, h.asset_issuer);
159
+ }
160
+ function side(t, amount) {
161
+ return {
162
+ asset: t.asset,
163
+ symbol: _nullishCoalesce(t.symbol, () => ( (t.asset === "native" ? XLM_SYMBOL : t.asset))),
164
+ decimals: STELLAR_DECIMALS,
165
+ amount: amount.toString(),
166
+ amountFormatted: _chunk6XTNI2OQcjs.formatUnits.call(void 0, amount, STELLAR_DECIMALS)
167
+ };
168
+ }
169
+ async function quoteStellarSwap(p) {
170
+ const fromAsset = assetForId(p.from.asset);
171
+ const toAsset = assetForId(p.to.asset);
172
+ if (!fromAsset || !toAsset) return null;
173
+ if (p.from.asset === p.to.asset) return null;
174
+ if (p.wantAmount <= 0n) return null;
175
+ const wantFormatted = _chunk6XTNI2OQcjs.formatUnits.call(void 0, p.wantAmount, STELLAR_DECIMALS);
176
+ let records;
177
+ try {
178
+ const page = await p.server.strictReceivePaths([fromAsset], toAsset, wantFormatted).call();
179
+ records = page.records;
180
+ } catch (e3) {
181
+ return null;
182
+ }
183
+ if (!_optionalChain([records, 'optionalAccess', _9 => _9.length])) return null;
184
+ let best = null;
185
+ let spend = null;
186
+ for (const r of records) {
187
+ let candidate;
188
+ try {
189
+ candidate = _chunk6XTNI2OQcjs.parseUnits.call(void 0, r.source_amount, STELLAR_DECIMALS);
190
+ } catch (e4) {
191
+ continue;
192
+ }
193
+ if (candidate <= 0n) continue;
194
+ if (spend === null || candidate < spend) {
195
+ spend = candidate;
196
+ best = r;
197
+ }
198
+ }
199
+ if (best === null || spend === null) return null;
200
+ const maxSpend = _chunkMZXVXC3Ccjs.applySlippage.call(void 0, spend, p.slippageBps);
201
+ return {
202
+ source: SOURCE,
203
+ network: p.network,
204
+ from: side(p.from, spend),
205
+ to: side(p.to, p.wantAmount),
206
+ maxSpend: maxSpend.toString(),
207
+ maxSpendFormatted: _chunk6XTNI2OQcjs.formatUnits.call(void 0, maxSpend, STELLAR_DECIMALS),
208
+ slippageBps: p.slippageBps,
209
+ route: _nullishCoalesce(best.path, () => ( []))
210
+ };
211
+ }
212
+ async function swapStellar(p) {
213
+ const { server, keypair, quote } = p;
214
+ const sendAsset = assetForId(quote.from.asset);
215
+ const destAsset = assetForId(quote.to.asset);
216
+ if (!sendAsset || !destAsset) {
217
+ throw new Error(`Stellar: malformed asset id in swap quote (${quote.from.asset} \u2192 ${quote.to.asset}).`);
218
+ }
219
+ const path = Array.isArray(quote.route) ? quote.route.map(hopToAsset) : [];
220
+ try {
221
+ const source = await server.loadAccount(keypair.publicKey());
222
+ const tx = new (0, _stellarsdk.TransactionBuilder)(source, { fee: _stellarsdk.BASE_FEE, networkPassphrase: STELLAR_PASSPHRASE }).addOperation(
223
+ _stellarsdk.Operation.pathPaymentStrictReceive({
224
+ sendAsset,
225
+ // The on-chain slippage cap. Validators enforce it; we do not.
226
+ sendMax: _chunk6XTNI2OQcjs.formatUnits.call(void 0, BigInt(quote.maxSpend), STELLAR_DECIMALS),
227
+ destination: keypair.publicKey(),
228
+ // ← ourselves: this is what makes it a swap
229
+ destAsset,
230
+ destAmount: quote.to.amountFormatted,
231
+ path
232
+ })
233
+ ).setTimeout(120).build();
234
+ tx.sign(keypair);
235
+ const res = await server.submitTransaction(tx);
236
+ return {
237
+ transaction: res.hash,
238
+ network: quote.network,
239
+ source: quote.source,
240
+ // Strict-RECEIVE fixes the output exactly; the input is whatever the market
241
+ // took, bounded by maxSpend. We report the quoted estimate for `from`.
242
+ from: quote.from,
243
+ to: quote.to
244
+ };
245
+ } catch (err) {
246
+ throw mapSwapError(err);
247
+ }
248
+ }
249
+ function mapSwapError(err) {
250
+ const codes = extractResultCodes2(err);
251
+ const seen = codes.join(", ");
252
+ const has = (re) => codes.some((c) => re.test(c));
253
+ if (has(/op_over_sendmax/i)) {
254
+ return new (0, _chunk6XTNI2OQcjs.InsufficientFundsError)(
255
+ `Stellar swap refused: the price moved past your slippage cap, so nothing was spent. Re-quote and retry, or raise slippageBps. (Stellar: ${seen})`,
256
+ { cause: err }
257
+ );
258
+ }
259
+ if (has(/op_too_few_offers|op_no_path/i)) {
260
+ return new (0, _chunk6XTNI2OQcjs.InsufficientFundsError)(
261
+ `Stellar swap refused: not enough liquidity on this pair right now, so nothing was spent. (Stellar: ${seen})`,
262
+ { cause: err }
263
+ );
264
+ }
265
+ if (has(/op_no_(trust|issuer)|op_not_authorized|op_line_full/i)) {
266
+ return new (0, _chunk6XTNI2OQcjs.RecipientNotReadyError)(
267
+ `Stellar swap refused: your account needs a trustline for the asset you're swapping INTO (and authorization) before it can hold it. (Stellar: ${seen})`,
268
+ { cause: err }
269
+ );
270
+ }
271
+ if (has(/underfunded|insufficient|low_reserve|src_no_trust/i)) {
272
+ return new (0, _chunk6XTNI2OQcjs.InsufficientFundsError)(
273
+ `Stellar swap failed: the account can't cover it \u2014 balance, base reserve, or no trustline to send this asset. (Stellar: ${seen})`,
274
+ { cause: err }
275
+ );
276
+ }
277
+ return _nullishCoalesce(_chunk6XTNI2OQcjs.toInsufficientFundsError.call(void 0, err), () => ( err));
278
+ }
279
+ function extractResultCodes2(err) {
280
+ const extras = _optionalChain([err, 'optionalAccess', _10 => _10.response, 'optionalAccess', _11 => _11.data, 'optionalAccess', _12 => _12.extras, 'optionalAccess', _13 => _13.result_codes]);
281
+ if (!extras) return [];
282
+ return [_nullishCoalesce(extras.transaction, () => ( "")), ..._nullishCoalesce(extras.operations, () => ( []))].filter(Boolean);
283
+ }
284
+
136
285
  // src/drivers/stellar/verify.ts
137
286
 
138
287
  function memoCandidatesForNonce(nonce) {
@@ -148,7 +297,7 @@ async function verifyStellar(params) {
148
297
  let txs;
149
298
  try {
150
299
  txs = await reader.transactionsForAccount(accept.payTo, 200);
151
- } catch (e2) {
300
+ } catch (e5) {
152
301
  return rpcFailed(nonce);
153
302
  }
154
303
  const tx = txs.find(
@@ -173,7 +322,7 @@ async function verifyStellar(params) {
173
322
  let payments;
174
323
  try {
175
324
  payments = await reader.paymentsForTransaction(tx.hash);
176
- } catch (e3) {
325
+ } catch (e6) {
177
326
  return rpcFailed(nonce);
178
327
  }
179
328
  const toUs = payments.filter(
@@ -218,8 +367,8 @@ function assetMatches(p, want) {
218
367
  }
219
368
  function parseAmount(amount, decimals) {
220
369
  try {
221
- return _chunkQONQSZHJcjs.parseUnits.call(void 0, amount, decimals);
222
- } catch (e4) {
370
+ return _chunk6XTNI2OQcjs.parseUnits.call(void 0, amount, decimals);
371
+ } catch (e7) {
223
372
  return 0n;
224
373
  }
225
374
  }
@@ -242,13 +391,13 @@ function rpcFailed(nonce) {
242
391
 
243
392
  function assertStellarWallet(wallet, network) {
244
393
  if (typeof wallet !== "object" || wallet === null) {
245
- throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)(
394
+ throw new (0, _chunk6XTNI2OQcjs.WrongFamilyError)(
246
395
  `chain ${network} is Stellar; wallet must be { key } (S\u2026 seed) or { keypair }.`
247
396
  );
248
397
  }
249
- _chunkQONQSZHJcjs.assertNoLegacyWalletKey.call(void 0, wallet, "Stellar");
398
+ _chunk6XTNI2OQcjs.assertNoLegacyWalletKey.call(void 0, wallet, "Stellar");
250
399
  if (!("key" in wallet) && !("keypair" in wallet)) {
251
- throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)(
400
+ throw new (0, _chunk6XTNI2OQcjs.WrongFamilyError)(
252
401
  `chain ${network} is Stellar; wallet must be { key } (S\u2026 seed) or { keypair }.`
253
402
  );
254
403
  }
@@ -258,18 +407,19 @@ function resolveStellarWallet(config) {
258
407
  if (config.keypair) return config.keypair;
259
408
  if (config.key) {
260
409
  if (!_stellarsdk.StrKey.isValidEd25519SecretSeed(config.key)) {
261
- throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)("Stellar wallet { key } is not a valid S\u2026 secret seed.");
410
+ throw new (0, _chunk6XTNI2OQcjs.WrongFamilyError)("Stellar wallet { key } is not a valid S\u2026 secret seed.");
262
411
  }
263
412
  return _stellarsdk.Keypair.fromSecret(config.key);
264
413
  }
265
- throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)("Stellar wallet needs { key } (S\u2026 seed) or { keypair }.");
414
+ throw new (0, _chunk6XTNI2OQcjs.WrongFamilyError)("Stellar wallet needs { key } (S\u2026 seed) or { keypair }.");
266
415
  }
267
416
 
268
417
  // src/drivers/stellar/index.ts
269
418
  function isStellarNotFound(e) {
270
419
  const x = e;
271
- return _optionalChain([x, 'optionalAccess', _9 => _9.response, 'optionalAccess', _10 => _10.status]) === 404 || _optionalChain([x, 'optionalAccess', _11 => _11.name]) === "NotFoundError";
420
+ return _optionalChain([x, 'optionalAccess', _14 => _14.response, 'optionalAccess', _15 => _15.status]) === 404 || _optionalChain([x, 'optionalAccess', _16 => _16.name]) === "NotFoundError";
272
421
  }
422
+ var STELLAR_BASE_RESERVE = 5000000n;
273
423
  var stellarDriver = {
274
424
  family: "stellar",
275
425
  resolve(opts) {
@@ -317,7 +467,7 @@ function makeStellarNetwork(preset, rpcUrl) {
317
467
  const info = preset.tokens[token.toUpperCase()];
318
468
  if (!info) {
319
469
  const known = Object.keys(preset.tokens).join(", ") || "(none built in)";
320
- throw new (0, _chunkQONQSZHJcjs.UnknownTokenError)(
470
+ throw new (0, _chunk6XTNI2OQcjs.UnknownTokenError)(
321
471
  `token "${token}" isn't built in for Stellar (known: ${known}). Pass { issuer, code, decimals } for a custom asset, or use 'native'.`
322
472
  );
323
473
  }
@@ -327,10 +477,10 @@ function makeStellarNetwork(preset, rpcUrl) {
327
477
  symbol: info.symbol
328
478
  };
329
479
  }
330
- _chunkQONQSZHJcjs.rejectForeignToken.call(void 0, token, "stellar", network);
480
+ _chunk6XTNI2OQcjs.rejectForeignToken.call(void 0, token, "stellar", network);
331
481
  const t = token;
332
482
  if (!t.issuer || !t.code || typeof t.decimals !== "number") {
333
- throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)(
483
+ throw new (0, _chunk6XTNI2OQcjs.WrongFamilyError)(
334
484
  `chain ${network} is Stellar; a custom token must be { issuer, code, decimals }.`
335
485
  );
336
486
  }
@@ -351,12 +501,12 @@ function makeStellarNetwork(preset, rpcUrl) {
351
501
  },
352
502
  assertValidPayTo(payTo) {
353
503
  if (payTo.startsWith("0x")) {
354
- throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)(
504
+ throw new (0, _chunk6XTNI2OQcjs.WrongFamilyError)(
355
505
  `chain ${network} is Stellar, but payTo "${payTo}" looks like an EVM address.`
356
506
  );
357
507
  }
358
508
  if (!_stellarsdk.StrKey.isValidEd25519PublicKey(payTo)) {
359
- throw new (0, _chunkQONQSZHJcjs.WrongFamilyError)(
509
+ throw new (0, _chunk6XTNI2OQcjs.WrongFamilyError)(
360
510
  `chain ${network} is Stellar, but payTo "${payTo}" is not a valid Stellar account (G\u2026).`
361
511
  );
362
512
  }
@@ -373,14 +523,14 @@ function makeStellarNetwork(preset, rpcUrl) {
373
523
  try {
374
524
  const tx = await server.transactions().transaction(ref).call();
375
525
  return { height: String(_nullishCoalesce(_nullishCoalesce(tx.ledger_attr, () => ( tx.ledger)), () => ( 0))) };
376
- } catch (e5) {
526
+ } catch (e8) {
377
527
  await _chunkCQREG5LEcjs.delay.call(void 0, 1500);
378
528
  }
379
529
  }
380
- throw new (0, _chunkQONQSZHJcjs.ConfirmationTimeoutError)(`Stellar tx ${ref} not visible on Horizon in time.`);
530
+ throw new (0, _chunk6XTNI2OQcjs.ConfirmationTimeoutError)(`Stellar tx ${ref} not visible on Horizon in time.`);
381
531
  },
382
532
  async estimateCost() {
383
- return _chunkQONQSZHJcjs.nativeCost.call(void 0, {
533
+ return _chunk6XTNI2OQcjs.nativeCost.call(void 0, {
384
534
  symbol: XLM_SYMBOL,
385
535
  decimals: STELLAR_DECIMALS,
386
536
  fee: 100n,
@@ -388,34 +538,46 @@ function makeStellarNetwork(preset, rpcUrl) {
388
538
  detail: "base fee 100 stroops (1 operation)"
389
539
  });
390
540
  },
541
+ /** The bound wallet's own address — where THIS wallet gets paid. Derived from the key
542
+ * material only: no RPC, nothing moved. See {@link ResolvedNetwork.addressOf}. */
543
+ async addressOf(wallet) {
544
+ return resolveStellarWallet(wallet._native).publicKey();
545
+ },
391
546
  async balanceOf(wallet, asset) {
392
547
  let owner;
393
548
  try {
394
549
  owner = resolveStellarWallet(wallet._native).publicKey();
395
- } catch (e6) {
550
+ } catch (e9) {
396
551
  return { token: null, native: null };
397
552
  }
398
553
  let lines;
554
+ let subentryCount;
399
555
  try {
400
556
  const account = await server.loadAccount(owner);
401
557
  lines = account.balances;
558
+ subentryCount = account.subentry_count;
402
559
  } catch (e) {
403
560
  return isStellarNotFound(e) ? { token: 0n, native: 0n } : { token: null, native: null };
404
561
  }
405
562
  const toBase = (s) => {
406
563
  try {
407
- return s != null ? _chunkQONQSZHJcjs.parseUnits.call(void 0, s, STELLAR_DECIMALS) : 0n;
408
- } catch (e7) {
564
+ return s != null ? _chunk6XTNI2OQcjs.parseUnits.call(void 0, s, STELLAR_DECIMALS) : 0n;
565
+ } catch (e10) {
409
566
  return 0n;
410
567
  }
411
568
  };
412
- const native = toBase(_optionalChain([lines, 'access', _12 => _12.find, 'call', _13 => _13((b) => b.asset_type === "native"), 'optionalAccess', _14 => _14.balance]));
413
- if (asset === "native") return { token: native, native };
569
+ const native = toBase(_optionalChain([lines, 'access', _17 => _17.find, 'call', _18 => _18((b) => b.asset_type === "native"), 'optionalAccess', _19 => _19.balance]));
570
+ if (asset === "native") {
571
+ if (native === null) return { token: null, native };
572
+ const subentries = BigInt(_nullishCoalesce(subentryCount, () => ( 0)));
573
+ const min = (2n + subentries) * STELLAR_BASE_RESERVE;
574
+ return { token: native > min ? native - min : 0n, native };
575
+ }
414
576
  const parts = parseStellarAssetId(asset);
415
577
  const line = parts ? lines.find(
416
578
  (b) => (b.asset_type === "credit_alphanum4" || b.asset_type === "credit_alphanum12") && b.asset_code === parts.code && b.asset_issuer === parts.issuer
417
579
  ) : void 0;
418
- return { token: toBase(_optionalChain([line, 'optionalAccess', _15 => _15.balance])), native };
580
+ return { token: toBase(_optionalChain([line, 'optionalAccess', _20 => _20.balance])), native };
419
581
  },
420
582
  async recipientReady(payTo, asset) {
421
583
  let lines;
@@ -434,6 +596,14 @@ function makeStellarNetwork(preset, rpcUrl) {
434
596
  );
435
597
  return hasTrustline ? { ready: true } : { ready: false, reason: "NO_TRUSTLINE" };
436
598
  },
599
+ /* ---- swap (OPTIONAL, opt-in): a path payment to yourself. See ./swap.ts ---- */
600
+ async quoteSwap({ from, to, wantAmount, slippageBps }) {
601
+ return quoteStellarSwap({ server, network, from, to, wantAmount, slippageBps });
602
+ },
603
+ async swap(wallet, quote) {
604
+ const keypair = resolveStellarWallet(wallet._native);
605
+ return swapStellar({ server, keypair, quote });
606
+ },
437
607
  async verify(_ref, accept) {
438
608
  return verifyStellar({ reader, accept });
439
609
  }