@piprail/sdk 2.16.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +343 -0
- package/README.md +1 -0
- package/dist/{algorand-25FMBCT3.js → algorand-HL57PQHE.js} +157 -2
- package/dist/{algorand-Q3TUQLPK.cjs → algorand-W776EEM2.cjs} +205 -50
- package/dist/{aptos-VBJONBFY.cjs → aptos-5QBXJ6NV.cjs} +255 -39
- package/dist/{aptos-SBV6SGDP.js → aptos-H5VLH2QL.js} +217 -1
- package/dist/{chunk-QONQSZHJ.cjs → chunk-6XTNI2OQ.cjs} +44 -44
- package/dist/{chunk-OXEFPLZA.cjs → chunk-6ZRAIQXF.cjs} +4 -4
- package/dist/chunk-GVCGUSTE.js +30 -0
- package/dist/{chunk-V2IJ5HUW.cjs → chunk-MZAJQYM3.cjs} +1 -0
- package/dist/chunk-MZXVXC3C.cjs +30 -0
- package/dist/{chunk-2CX7XRZK.js → chunk-TZDVZCTC.js} +1 -0
- package/dist/{chunk-C52H5TYB.js → chunk-YXBQKBDH.js} +2 -2
- package/dist/index.cjs +2929 -1444
- package/dist/index.d.cts +625 -13
- package/dist/index.d.ts +625 -13
- package/dist/index.js +2506 -1021
- package/dist/{near-OLKCMTBI.js → near-5X2CQGML.js} +197 -1
- package/dist/{near-5LTTDU6G.cjs → near-XSQXEIHT.cjs} +242 -46
- package/dist/{solana-AI2G7V33.cjs → solana-EBV6PUCU.cjs} +211 -52
- package/dist/{solana-HTKDRTD3.js → solana-O6Q6QILH.js} +167 -8
- package/dist/{stellar-E2KWEV2E.cjs → stellar-5C7FQLPS.cjs} +191 -29
- package/dist/{stellar-EUFZLX6J.js → stellar-YF5LOJEM.js} +163 -1
- package/dist/{sui-KCIITCYH.js → sui-JFQSDNSZ.js} +165 -3
- package/dist/{sui-Q3NJOJZS.cjs → sui-WIZEAO7E.cjs} +185 -23
- package/dist/{ton-J7TQWRN4.cjs → ton-AGTKLQA5.cjs} +264 -22
- package/dist/{ton-WH2JVQOO.js → ton-OZKFNRLT.js} +244 -2
- package/dist/{tron-FXBXDNEY.js → tron-HG3IOOCG.js} +283 -1
- package/dist/{tron-HIPMOX7S.cjs → tron-S4WX7OHY.cjs} +323 -41
- package/dist/{xrpl-RUOB37QH.js → xrpl-GOVHMYYK.js} +222 -5
- package/dist/{xrpl-SVVS445B.cjs → xrpl-YS3IXPLV.cjs} +273 -56
- package/package.json +12 -2
- 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-
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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)}.`
|
|
@@ -625,7 +772,7 @@ var solanaDriver = {
|
|
|
625
772
|
}
|
|
626
773
|
};
|
|
627
774
|
function makeSolanaNetwork(preset, rpcUrl) {
|
|
628
|
-
const connection = new
|
|
775
|
+
const connection = new Connection2(rpcUrl, "confirmed");
|
|
629
776
|
const network = preset.caip2;
|
|
630
777
|
return {
|
|
631
778
|
family: "solana",
|
|
@@ -735,6 +882,11 @@ function makeSolanaNetwork(preset, rpcUrl) {
|
|
|
735
882
|
detail: "1 signature + recipient token-account rent (~0.00204 SOL, if not already created)"
|
|
736
883
|
});
|
|
737
884
|
},
|
|
885
|
+
/** The bound wallet's own address — where THIS wallet gets paid. Derived from the key
|
|
886
|
+
* material only: no RPC, nothing moved. See {@link ResolvedNetwork.addressOf}. */
|
|
887
|
+
async addressOf(wallet) {
|
|
888
|
+
return wallet._native.publicKey.toBase58();
|
|
889
|
+
},
|
|
738
890
|
async balanceOf(wallet, asset) {
|
|
739
891
|
const owner = wallet._native.publicKey;
|
|
740
892
|
const native = await connection.getBalance(owner).then((n) => BigInt(n)).catch(() => null);
|
|
@@ -764,6 +916,13 @@ function makeSolanaNetwork(preset, rpcUrl) {
|
|
|
764
916
|
async recipientReady() {
|
|
765
917
|
return { ready: "n/a" };
|
|
766
918
|
},
|
|
919
|
+
/* ---- swap (OPTIONAL, opt-in): via Jupiter, keyless + no platform fee. See ./swap.ts ---- */
|
|
920
|
+
async quoteSwap({ from, to, wantAmount, slippageBps }) {
|
|
921
|
+
return quoteSolanaSwap({ network, from, to, wantAmount, slippageBps });
|
|
922
|
+
},
|
|
923
|
+
async swap(wallet, quote) {
|
|
924
|
+
return swapSolana({ connection, keypair: wallet._native, quote });
|
|
925
|
+
},
|
|
767
926
|
async verify(ref, accept) {
|
|
768
927
|
return verifySolana({ connection, signature: ref, accept });
|
|
769
928
|
},
|
|
@@ -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
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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(
|
|
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 (
|
|
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 (
|
|
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
|
|
222
|
-
} catch (
|
|
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,
|
|
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
|
-
|
|
398
|
+
_chunk6XTNI2OQcjs.assertNoLegacyWalletKey.call(void 0, wallet, "Stellar");
|
|
250
399
|
if (!("key" in wallet) && !("keypair" in wallet)) {
|
|
251
|
-
throw new (0,
|
|
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,17 +407,17 @@ 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,
|
|
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,
|
|
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',
|
|
420
|
+
return _optionalChain([x, 'optionalAccess', _14 => _14.response, 'optionalAccess', _15 => _15.status]) === 404 || _optionalChain([x, 'optionalAccess', _16 => _16.name]) === "NotFoundError";
|
|
272
421
|
}
|
|
273
422
|
var stellarDriver = {
|
|
274
423
|
family: "stellar",
|
|
@@ -317,7 +466,7 @@ function makeStellarNetwork(preset, rpcUrl) {
|
|
|
317
466
|
const info = preset.tokens[token.toUpperCase()];
|
|
318
467
|
if (!info) {
|
|
319
468
|
const known = Object.keys(preset.tokens).join(", ") || "(none built in)";
|
|
320
|
-
throw new (0,
|
|
469
|
+
throw new (0, _chunk6XTNI2OQcjs.UnknownTokenError)(
|
|
321
470
|
`token "${token}" isn't built in for Stellar (known: ${known}). Pass { issuer, code, decimals } for a custom asset, or use 'native'.`
|
|
322
471
|
);
|
|
323
472
|
}
|
|
@@ -327,10 +476,10 @@ function makeStellarNetwork(preset, rpcUrl) {
|
|
|
327
476
|
symbol: info.symbol
|
|
328
477
|
};
|
|
329
478
|
}
|
|
330
|
-
|
|
479
|
+
_chunk6XTNI2OQcjs.rejectForeignToken.call(void 0, token, "stellar", network);
|
|
331
480
|
const t = token;
|
|
332
481
|
if (!t.issuer || !t.code || typeof t.decimals !== "number") {
|
|
333
|
-
throw new (0,
|
|
482
|
+
throw new (0, _chunk6XTNI2OQcjs.WrongFamilyError)(
|
|
334
483
|
`chain ${network} is Stellar; a custom token must be { issuer, code, decimals }.`
|
|
335
484
|
);
|
|
336
485
|
}
|
|
@@ -351,12 +500,12 @@ function makeStellarNetwork(preset, rpcUrl) {
|
|
|
351
500
|
},
|
|
352
501
|
assertValidPayTo(payTo) {
|
|
353
502
|
if (payTo.startsWith("0x")) {
|
|
354
|
-
throw new (0,
|
|
503
|
+
throw new (0, _chunk6XTNI2OQcjs.WrongFamilyError)(
|
|
355
504
|
`chain ${network} is Stellar, but payTo "${payTo}" looks like an EVM address.`
|
|
356
505
|
);
|
|
357
506
|
}
|
|
358
507
|
if (!_stellarsdk.StrKey.isValidEd25519PublicKey(payTo)) {
|
|
359
|
-
throw new (0,
|
|
508
|
+
throw new (0, _chunk6XTNI2OQcjs.WrongFamilyError)(
|
|
360
509
|
`chain ${network} is Stellar, but payTo "${payTo}" is not a valid Stellar account (G\u2026).`
|
|
361
510
|
);
|
|
362
511
|
}
|
|
@@ -373,14 +522,14 @@ function makeStellarNetwork(preset, rpcUrl) {
|
|
|
373
522
|
try {
|
|
374
523
|
const tx = await server.transactions().transaction(ref).call();
|
|
375
524
|
return { height: String(_nullishCoalesce(_nullishCoalesce(tx.ledger_attr, () => ( tx.ledger)), () => ( 0))) };
|
|
376
|
-
} catch (
|
|
525
|
+
} catch (e8) {
|
|
377
526
|
await _chunkCQREG5LEcjs.delay.call(void 0, 1500);
|
|
378
527
|
}
|
|
379
528
|
}
|
|
380
|
-
throw new (0,
|
|
529
|
+
throw new (0, _chunk6XTNI2OQcjs.ConfirmationTimeoutError)(`Stellar tx ${ref} not visible on Horizon in time.`);
|
|
381
530
|
},
|
|
382
531
|
async estimateCost() {
|
|
383
|
-
return
|
|
532
|
+
return _chunk6XTNI2OQcjs.nativeCost.call(void 0, {
|
|
384
533
|
symbol: XLM_SYMBOL,
|
|
385
534
|
decimals: STELLAR_DECIMALS,
|
|
386
535
|
fee: 100n,
|
|
@@ -388,11 +537,16 @@ function makeStellarNetwork(preset, rpcUrl) {
|
|
|
388
537
|
detail: "base fee 100 stroops (1 operation)"
|
|
389
538
|
});
|
|
390
539
|
},
|
|
540
|
+
/** The bound wallet's own address — where THIS wallet gets paid. Derived from the key
|
|
541
|
+
* material only: no RPC, nothing moved. See {@link ResolvedNetwork.addressOf}. */
|
|
542
|
+
async addressOf(wallet) {
|
|
543
|
+
return resolveStellarWallet(wallet._native).publicKey();
|
|
544
|
+
},
|
|
391
545
|
async balanceOf(wallet, asset) {
|
|
392
546
|
let owner;
|
|
393
547
|
try {
|
|
394
548
|
owner = resolveStellarWallet(wallet._native).publicKey();
|
|
395
|
-
} catch (
|
|
549
|
+
} catch (e9) {
|
|
396
550
|
return { token: null, native: null };
|
|
397
551
|
}
|
|
398
552
|
let lines;
|
|
@@ -404,18 +558,18 @@ function makeStellarNetwork(preset, rpcUrl) {
|
|
|
404
558
|
}
|
|
405
559
|
const toBase = (s) => {
|
|
406
560
|
try {
|
|
407
|
-
return s != null ?
|
|
408
|
-
} catch (
|
|
561
|
+
return s != null ? _chunk6XTNI2OQcjs.parseUnits.call(void 0, s, STELLAR_DECIMALS) : 0n;
|
|
562
|
+
} catch (e10) {
|
|
409
563
|
return 0n;
|
|
410
564
|
}
|
|
411
565
|
};
|
|
412
|
-
const native = toBase(_optionalChain([lines, 'access',
|
|
566
|
+
const native = toBase(_optionalChain([lines, 'access', _17 => _17.find, 'call', _18 => _18((b) => b.asset_type === "native"), 'optionalAccess', _19 => _19.balance]));
|
|
413
567
|
if (asset === "native") return { token: native, native };
|
|
414
568
|
const parts = parseStellarAssetId(asset);
|
|
415
569
|
const line = parts ? lines.find(
|
|
416
570
|
(b) => (b.asset_type === "credit_alphanum4" || b.asset_type === "credit_alphanum12") && b.asset_code === parts.code && b.asset_issuer === parts.issuer
|
|
417
571
|
) : void 0;
|
|
418
|
-
return { token: toBase(_optionalChain([line, 'optionalAccess',
|
|
572
|
+
return { token: toBase(_optionalChain([line, 'optionalAccess', _20 => _20.balance])), native };
|
|
419
573
|
},
|
|
420
574
|
async recipientReady(payTo, asset) {
|
|
421
575
|
let lines;
|
|
@@ -434,6 +588,14 @@ function makeStellarNetwork(preset, rpcUrl) {
|
|
|
434
588
|
);
|
|
435
589
|
return hasTrustline ? { ready: true } : { ready: false, reason: "NO_TRUSTLINE" };
|
|
436
590
|
},
|
|
591
|
+
/* ---- swap (OPTIONAL, opt-in): a path payment to yourself. See ./swap.ts ---- */
|
|
592
|
+
async quoteSwap({ from, to, wantAmount, slippageBps }) {
|
|
593
|
+
return quoteStellarSwap({ server, network, from, to, wantAmount, slippageBps });
|
|
594
|
+
},
|
|
595
|
+
async swap(wallet, quote) {
|
|
596
|
+
const keypair = resolveStellarWallet(wallet._native);
|
|
597
|
+
return swapStellar({ server, keypair, quote });
|
|
598
|
+
},
|
|
437
599
|
async verify(_ref, accept) {
|
|
438
600
|
return verifyStellar({ reader, accept });
|
|
439
601
|
}
|