@piprail/sdk 1.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.
@@ -0,0 +1,342 @@
1
+ import {
2
+ ConfirmationTimeoutError,
3
+ UnknownTokenError,
4
+ WrongFamilyError,
5
+ nativeCost,
6
+ rejectForeignToken,
7
+ toInsufficientFundsError
8
+ } from "./chunk-3TQJJ4SQ.js";
9
+
10
+ // src/drivers/solana/index.ts
11
+ import { Connection, PublicKey as PublicKey2 } from "@solana/web3.js";
12
+
13
+ // src/drivers/solana/chains.ts
14
+ var SOL_DECIMALS = 9;
15
+ var SOLANA_MAINNET = {
16
+ caip2: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
17
+ defaultRpc: "https://api.mainnet-beta.solana.com",
18
+ tokens: {
19
+ USDC: {
20
+ mint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
21
+ decimals: 6,
22
+ symbol: "USDC"
23
+ },
24
+ USDT: {
25
+ mint: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB",
26
+ decimals: 6,
27
+ symbol: "USDT"
28
+ }
29
+ }
30
+ };
31
+
32
+ // src/drivers/solana/pay.ts
33
+ import {
34
+ PublicKey,
35
+ SystemProgram,
36
+ Transaction
37
+ } from "@solana/web3.js";
38
+ import {
39
+ createAssociatedTokenAccountIdempotentInstruction,
40
+ createTransferCheckedInstruction,
41
+ getAssociatedTokenAddressSync
42
+ } from "@solana/spl-token";
43
+ async function paySolana(params) {
44
+ const { connection, keypair, accept } = params;
45
+ const payTo = new PublicKey(accept.payTo);
46
+ const amount = BigInt(accept.amount);
47
+ const tx = new Transaction();
48
+ if (accept.asset === "native") {
49
+ tx.add(
50
+ SystemProgram.transfer({
51
+ fromPubkey: keypair.publicKey,
52
+ toPubkey: payTo,
53
+ lamports: amount
54
+ })
55
+ );
56
+ } else {
57
+ const mint = new PublicKey(accept.asset);
58
+ const source = getAssociatedTokenAddressSync(mint, keypair.publicKey);
59
+ const dest = getAssociatedTokenAddressSync(mint, payTo);
60
+ tx.add(
61
+ createAssociatedTokenAccountIdempotentInstruction(
62
+ keypair.publicKey,
63
+ // payer for any rent
64
+ dest,
65
+ payTo,
66
+ mint
67
+ )
68
+ );
69
+ tx.add(
70
+ createTransferCheckedInstruction(
71
+ source,
72
+ mint,
73
+ dest,
74
+ keypair.publicKey,
75
+ amount,
76
+ accept.extra.decimals
77
+ )
78
+ );
79
+ }
80
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
81
+ tx.recentBlockhash = blockhash;
82
+ tx.lastValidBlockHeight = lastValidBlockHeight;
83
+ tx.feePayer = keypair.publicKey;
84
+ tx.sign(keypair);
85
+ const signature = await connection.sendRawTransaction(tx.serialize(), {
86
+ maxRetries: 5
87
+ });
88
+ await connection.confirmTransaction(
89
+ { signature, blockhash, lastValidBlockHeight },
90
+ "confirmed"
91
+ );
92
+ return signature;
93
+ }
94
+
95
+ // src/drivers/solana/verify.ts
96
+ async function verifySolana(params) {
97
+ const { connection, signature, accept } = params;
98
+ const required = BigInt(accept.amount);
99
+ let tx;
100
+ try {
101
+ tx = await connection.getParsedTransaction(signature, {
102
+ commitment: "confirmed",
103
+ maxSupportedTransactionVersion: 0
104
+ });
105
+ } catch {
106
+ return notFound(signature);
107
+ }
108
+ if (!tx) return notFound(signature);
109
+ const meta = tx.meta;
110
+ if (!meta) {
111
+ return { ok: false, error: "no_meta", detail: `No metadata for ${signature}.` };
112
+ }
113
+ if (meta.err !== null) {
114
+ return {
115
+ ok: false,
116
+ error: "tx_reverted",
117
+ detail: `Transaction ${signature} failed on-chain.`
118
+ };
119
+ }
120
+ if (typeof tx.blockTime !== "number") {
121
+ return {
122
+ ok: false,
123
+ error: "payment_expired",
124
+ detail: `Cannot determine the age of ${signature} (no blockTime).`
125
+ };
126
+ }
127
+ const ageSeconds = Math.floor(Date.now() / 1e3) - tx.blockTime;
128
+ if (ageSeconds > accept.maxTimeoutSeconds) {
129
+ return {
130
+ ok: false,
131
+ error: "payment_expired",
132
+ detail: `Payment is ${ageSeconds}s old; max allowed is ${accept.maxTimeoutSeconds}s.`
133
+ };
134
+ }
135
+ const accountKeys = tx.transaction.message.accountKeys.map(
136
+ (k) => k.pubkey.toBase58()
137
+ );
138
+ const payer = accountKeys[0] ?? "";
139
+ if (accept.asset === "native") {
140
+ const idx = accountKeys.indexOf(accept.payTo);
141
+ if (idx < 0) {
142
+ return {
143
+ ok: false,
144
+ error: "wrong_recipient",
145
+ detail: `Native payment in ${signature} did not credit ${accept.payTo}.`
146
+ };
147
+ }
148
+ const delta = BigInt(meta.postBalances[idx] ?? 0) - BigInt(meta.preBalances[idx] ?? 0);
149
+ if (delta < required) {
150
+ return {
151
+ ok: false,
152
+ error: "amount_too_low",
153
+ detail: `Credited ${delta} lamports, required ${required}.`
154
+ };
155
+ }
156
+ } else {
157
+ const mint = accept.asset;
158
+ const pre = meta.preTokenBalances ?? [];
159
+ const post = meta.postTokenBalances ?? [];
160
+ let delta = 0n;
161
+ for (const p of post) {
162
+ if (p.mint !== mint || p.owner !== accept.payTo) continue;
163
+ const before = pre.find((x) => x.accountIndex === p.accountIndex);
164
+ delta += BigInt(p.uiTokenAmount.amount) - BigInt(before?.uiTokenAmount.amount ?? "0");
165
+ }
166
+ if (delta < required) {
167
+ return {
168
+ ok: false,
169
+ error: "transfer_not_found",
170
+ detail: `No SPL transfer of >= ${required} (mint ${mint}) to ${accept.payTo} in ${signature}.`
171
+ };
172
+ }
173
+ }
174
+ return {
175
+ ok: true,
176
+ receipt: {
177
+ scheme: "onchain-proof",
178
+ success: true,
179
+ network: accept.network,
180
+ transaction: signature,
181
+ asset: accept.asset,
182
+ amount: accept.amount,
183
+ payer,
184
+ payTo: accept.payTo,
185
+ verifiedAt: (/* @__PURE__ */ new Date()).toISOString()
186
+ }
187
+ };
188
+ }
189
+ function notFound(signature) {
190
+ return {
191
+ ok: false,
192
+ error: "tx_not_found",
193
+ detail: `Signature ${signature} not found or not yet confirmed.`
194
+ };
195
+ }
196
+
197
+ // src/drivers/solana/wallet.ts
198
+ import { Keypair as Keypair2 } from "@solana/web3.js";
199
+ import bs58 from "bs58";
200
+ function toKeypair(wallet, network) {
201
+ if (typeof wallet !== "object" || wallet === null) {
202
+ throw new WrongFamilyError(
203
+ `chain ${network} is Solana; wallet must be { secretKey } or { signer }.`
204
+ );
205
+ }
206
+ if ("privateKey" in wallet || "walletClient" in wallet) {
207
+ throw new WrongFamilyError(
208
+ `chain ${network} is Solana; an EVM wallet can't be used \u2014 pass { secretKey } or { signer }.`
209
+ );
210
+ }
211
+ if ("signer" in wallet) {
212
+ return wallet.signer;
213
+ }
214
+ if ("secretKey" in wallet) {
215
+ const sk = wallet.secretKey;
216
+ const bytes = typeof sk === "string" ? bs58.decode(sk) : sk;
217
+ return Keypair2.fromSecretKey(bytes);
218
+ }
219
+ throw new WrongFamilyError(
220
+ `chain ${network} is Solana; wallet must be { secretKey } or { signer }.`
221
+ );
222
+ }
223
+
224
+ // src/drivers/solana/index.ts
225
+ var solanaDriver = {
226
+ family: "solana",
227
+ resolve(opts) {
228
+ if (opts.chain !== "solana") return null;
229
+ const rpcUrl = opts.rpcUrl ?? SOLANA_MAINNET.defaultRpc;
230
+ return makeSolanaNetwork(SOLANA_MAINNET, rpcUrl);
231
+ }
232
+ };
233
+ function makeSolanaNetwork(preset, rpcUrl) {
234
+ const connection = new Connection(rpcUrl, "confirmed");
235
+ const network = preset.caip2;
236
+ return {
237
+ family: "solana",
238
+ network,
239
+ supports: (n) => n === network,
240
+ resolveToken(token) {
241
+ if (token === "native") {
242
+ return { asset: "native", decimals: SOL_DECIMALS, symbol: "SOL" };
243
+ }
244
+ if (typeof token === "string") {
245
+ const info = preset.tokens[token.toUpperCase()];
246
+ if (!info) {
247
+ const known = Object.keys(preset.tokens).join(", ") || "(none built in)";
248
+ throw new UnknownTokenError(
249
+ `token "${token}" isn't built in for Solana (known: ${known}). Pass { mint, decimals } instead, or use 'native'.`
250
+ );
251
+ }
252
+ return { asset: info.mint, decimals: info.decimals, symbol: info.symbol };
253
+ }
254
+ rejectForeignToken(token, "solana", network);
255
+ if (!("mint" in token)) {
256
+ throw new WrongFamilyError(
257
+ `chain ${network} is Solana; a custom token must be { mint, decimals }.`
258
+ );
259
+ }
260
+ return {
261
+ asset: token.mint,
262
+ decimals: token.decimals,
263
+ ...token.symbol ? { symbol: token.symbol } : {}
264
+ };
265
+ },
266
+ describeAsset(asset) {
267
+ if (asset === "native") return { symbol: "SOL", decimals: SOL_DECIMALS };
268
+ for (const info of Object.values(preset.tokens)) {
269
+ if (info.mint === asset) return { symbol: info.symbol, decimals: info.decimals };
270
+ }
271
+ return null;
272
+ },
273
+ assertValidPayTo(payTo) {
274
+ if (payTo.startsWith("0x")) {
275
+ throw new WrongFamilyError(
276
+ `chain ${network} is Solana, but payTo "${payTo}" looks like an EVM address.`
277
+ );
278
+ }
279
+ try {
280
+ new PublicKey2(payTo);
281
+ } catch {
282
+ throw new WrongFamilyError(
283
+ `chain ${network} is Solana, but payTo "${payTo}" is not a base58 address.`
284
+ );
285
+ }
286
+ },
287
+ bindWallet(wallet) {
288
+ return { _native: toKeypair(wallet, network) };
289
+ },
290
+ async send(wallet, accept) {
291
+ try {
292
+ return await paySolana({ connection, keypair: wallet._native, accept });
293
+ } catch (err) {
294
+ throw toInsufficientFundsError(err) ?? err;
295
+ }
296
+ },
297
+ async confirm(ref) {
298
+ let info;
299
+ try {
300
+ const { value } = await connection.getSignatureStatuses([ref], {
301
+ searchTransactionHistory: true
302
+ });
303
+ info = value[0];
304
+ } catch (err) {
305
+ throw new ConfirmationTimeoutError(
306
+ `Solana payment ${ref} could not be confirmed (RPC read failed).`,
307
+ { cause: err }
308
+ );
309
+ }
310
+ if (!info || info.err || info.confirmationStatus !== "confirmed" && info.confirmationStatus !== "finalized") {
311
+ throw new ConfirmationTimeoutError(`Solana payment ${ref} did not confirm in time.`);
312
+ }
313
+ return { height: String(info.slot) };
314
+ },
315
+ async estimateCost(accept) {
316
+ const base = 5000n;
317
+ if (accept.asset === "native") {
318
+ return nativeCost({
319
+ symbol: "SOL",
320
+ decimals: SOL_DECIMALS,
321
+ fee: base,
322
+ basis: "heuristic",
323
+ detail: "1 signature (5000 lamports)"
324
+ });
325
+ }
326
+ const ataRent = 2039280n;
327
+ return nativeCost({
328
+ symbol: "SOL",
329
+ decimals: SOL_DECIMALS,
330
+ fee: base + ataRent,
331
+ basis: "heuristic",
332
+ detail: "1 signature + recipient token-account rent (~0.00204 SOL, if not already created)"
333
+ });
334
+ },
335
+ async verify(ref, accept) {
336
+ return verifySolana({ connection, signature: ref, accept });
337
+ }
338
+ };
339
+ }
340
+ export {
341
+ solanaDriver
342
+ };
@@ -0,0 +1,342 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+
4
+
5
+
6
+
7
+
8
+ var _chunkWQWNPAYQcjs = require('./chunk-WQWNPAYQ.cjs');
9
+
10
+ // src/drivers/solana/index.ts
11
+ var _web3js = require('@solana/web3.js');
12
+
13
+ // src/drivers/solana/chains.ts
14
+ var SOL_DECIMALS = 9;
15
+ var SOLANA_MAINNET = {
16
+ caip2: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
17
+ defaultRpc: "https://api.mainnet-beta.solana.com",
18
+ tokens: {
19
+ USDC: {
20
+ mint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
21
+ decimals: 6,
22
+ symbol: "USDC"
23
+ },
24
+ USDT: {
25
+ mint: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB",
26
+ decimals: 6,
27
+ symbol: "USDT"
28
+ }
29
+ }
30
+ };
31
+
32
+ // src/drivers/solana/pay.ts
33
+
34
+
35
+
36
+
37
+
38
+
39
+
40
+
41
+
42
+ var _spltoken = require('@solana/spl-token');
43
+ async function paySolana(params) {
44
+ const { connection, keypair, accept } = params;
45
+ const payTo = new (0, _web3js.PublicKey)(accept.payTo);
46
+ const amount = BigInt(accept.amount);
47
+ const tx = new (0, _web3js.Transaction)();
48
+ if (accept.asset === "native") {
49
+ tx.add(
50
+ _web3js.SystemProgram.transfer({
51
+ fromPubkey: keypair.publicKey,
52
+ toPubkey: payTo,
53
+ lamports: amount
54
+ })
55
+ );
56
+ } else {
57
+ const mint = new (0, _web3js.PublicKey)(accept.asset);
58
+ const source = _spltoken.getAssociatedTokenAddressSync.call(void 0, mint, keypair.publicKey);
59
+ const dest = _spltoken.getAssociatedTokenAddressSync.call(void 0, mint, payTo);
60
+ tx.add(
61
+ _spltoken.createAssociatedTokenAccountIdempotentInstruction.call(void 0,
62
+ keypair.publicKey,
63
+ // payer for any rent
64
+ dest,
65
+ payTo,
66
+ mint
67
+ )
68
+ );
69
+ tx.add(
70
+ _spltoken.createTransferCheckedInstruction.call(void 0,
71
+ source,
72
+ mint,
73
+ dest,
74
+ keypair.publicKey,
75
+ amount,
76
+ accept.extra.decimals
77
+ )
78
+ );
79
+ }
80
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
81
+ tx.recentBlockhash = blockhash;
82
+ tx.lastValidBlockHeight = lastValidBlockHeight;
83
+ tx.feePayer = keypair.publicKey;
84
+ tx.sign(keypair);
85
+ const signature = await connection.sendRawTransaction(tx.serialize(), {
86
+ maxRetries: 5
87
+ });
88
+ await connection.confirmTransaction(
89
+ { signature, blockhash, lastValidBlockHeight },
90
+ "confirmed"
91
+ );
92
+ return signature;
93
+ }
94
+
95
+ // src/drivers/solana/verify.ts
96
+ async function verifySolana(params) {
97
+ const { connection, signature, accept } = params;
98
+ const required = BigInt(accept.amount);
99
+ let tx;
100
+ try {
101
+ tx = await connection.getParsedTransaction(signature, {
102
+ commitment: "confirmed",
103
+ maxSupportedTransactionVersion: 0
104
+ });
105
+ } catch (e) {
106
+ return notFound(signature);
107
+ }
108
+ if (!tx) return notFound(signature);
109
+ const meta = tx.meta;
110
+ if (!meta) {
111
+ return { ok: false, error: "no_meta", detail: `No metadata for ${signature}.` };
112
+ }
113
+ if (meta.err !== null) {
114
+ return {
115
+ ok: false,
116
+ error: "tx_reverted",
117
+ detail: `Transaction ${signature} failed on-chain.`
118
+ };
119
+ }
120
+ if (typeof tx.blockTime !== "number") {
121
+ return {
122
+ ok: false,
123
+ error: "payment_expired",
124
+ detail: `Cannot determine the age of ${signature} (no blockTime).`
125
+ };
126
+ }
127
+ const ageSeconds = Math.floor(Date.now() / 1e3) - tx.blockTime;
128
+ if (ageSeconds > accept.maxTimeoutSeconds) {
129
+ return {
130
+ ok: false,
131
+ error: "payment_expired",
132
+ detail: `Payment is ${ageSeconds}s old; max allowed is ${accept.maxTimeoutSeconds}s.`
133
+ };
134
+ }
135
+ const accountKeys = tx.transaction.message.accountKeys.map(
136
+ (k) => k.pubkey.toBase58()
137
+ );
138
+ const payer = _nullishCoalesce(accountKeys[0], () => ( ""));
139
+ if (accept.asset === "native") {
140
+ const idx = accountKeys.indexOf(accept.payTo);
141
+ if (idx < 0) {
142
+ return {
143
+ ok: false,
144
+ error: "wrong_recipient",
145
+ detail: `Native payment in ${signature} did not credit ${accept.payTo}.`
146
+ };
147
+ }
148
+ const delta = BigInt(_nullishCoalesce(meta.postBalances[idx], () => ( 0))) - BigInt(_nullishCoalesce(meta.preBalances[idx], () => ( 0)));
149
+ if (delta < required) {
150
+ return {
151
+ ok: false,
152
+ error: "amount_too_low",
153
+ detail: `Credited ${delta} lamports, required ${required}.`
154
+ };
155
+ }
156
+ } else {
157
+ const mint = accept.asset;
158
+ const pre = _nullishCoalesce(meta.preTokenBalances, () => ( []));
159
+ const post = _nullishCoalesce(meta.postTokenBalances, () => ( []));
160
+ let delta = 0n;
161
+ for (const p of post) {
162
+ if (p.mint !== mint || p.owner !== accept.payTo) continue;
163
+ const before = pre.find((x) => x.accountIndex === p.accountIndex);
164
+ delta += BigInt(p.uiTokenAmount.amount) - BigInt(_nullishCoalesce(_optionalChain([before, 'optionalAccess', _ => _.uiTokenAmount, 'access', _2 => _2.amount]), () => ( "0")));
165
+ }
166
+ if (delta < required) {
167
+ return {
168
+ ok: false,
169
+ error: "transfer_not_found",
170
+ detail: `No SPL transfer of >= ${required} (mint ${mint}) to ${accept.payTo} in ${signature}.`
171
+ };
172
+ }
173
+ }
174
+ return {
175
+ ok: true,
176
+ receipt: {
177
+ scheme: "onchain-proof",
178
+ success: true,
179
+ network: accept.network,
180
+ transaction: signature,
181
+ asset: accept.asset,
182
+ amount: accept.amount,
183
+ payer,
184
+ payTo: accept.payTo,
185
+ verifiedAt: (/* @__PURE__ */ new Date()).toISOString()
186
+ }
187
+ };
188
+ }
189
+ function notFound(signature) {
190
+ return {
191
+ ok: false,
192
+ error: "tx_not_found",
193
+ detail: `Signature ${signature} not found or not yet confirmed.`
194
+ };
195
+ }
196
+
197
+ // src/drivers/solana/wallet.ts
198
+
199
+ var _bs58 = require('bs58'); var _bs582 = _interopRequireDefault(_bs58);
200
+ function toKeypair(wallet, network) {
201
+ if (typeof wallet !== "object" || wallet === null) {
202
+ throw new (0, _chunkWQWNPAYQcjs.WrongFamilyError)(
203
+ `chain ${network} is Solana; wallet must be { secretKey } or { signer }.`
204
+ );
205
+ }
206
+ if ("privateKey" in wallet || "walletClient" in wallet) {
207
+ throw new (0, _chunkWQWNPAYQcjs.WrongFamilyError)(
208
+ `chain ${network} is Solana; an EVM wallet can't be used \u2014 pass { secretKey } or { signer }.`
209
+ );
210
+ }
211
+ if ("signer" in wallet) {
212
+ return wallet.signer;
213
+ }
214
+ if ("secretKey" in wallet) {
215
+ const sk = wallet.secretKey;
216
+ const bytes = typeof sk === "string" ? _bs582.default.decode(sk) : sk;
217
+ return _web3js.Keypair.fromSecretKey(bytes);
218
+ }
219
+ throw new (0, _chunkWQWNPAYQcjs.WrongFamilyError)(
220
+ `chain ${network} is Solana; wallet must be { secretKey } or { signer }.`
221
+ );
222
+ }
223
+
224
+ // src/drivers/solana/index.ts
225
+ var solanaDriver = {
226
+ family: "solana",
227
+ resolve(opts) {
228
+ if (opts.chain !== "solana") return null;
229
+ const rpcUrl = _nullishCoalesce(opts.rpcUrl, () => ( SOLANA_MAINNET.defaultRpc));
230
+ return makeSolanaNetwork(SOLANA_MAINNET, rpcUrl);
231
+ }
232
+ };
233
+ function makeSolanaNetwork(preset, rpcUrl) {
234
+ const connection = new (0, _web3js.Connection)(rpcUrl, "confirmed");
235
+ const network = preset.caip2;
236
+ return {
237
+ family: "solana",
238
+ network,
239
+ supports: (n) => n === network,
240
+ resolveToken(token) {
241
+ if (token === "native") {
242
+ return { asset: "native", decimals: SOL_DECIMALS, symbol: "SOL" };
243
+ }
244
+ if (typeof token === "string") {
245
+ const info = preset.tokens[token.toUpperCase()];
246
+ if (!info) {
247
+ const known = Object.keys(preset.tokens).join(", ") || "(none built in)";
248
+ throw new (0, _chunkWQWNPAYQcjs.UnknownTokenError)(
249
+ `token "${token}" isn't built in for Solana (known: ${known}). Pass { mint, decimals } instead, or use 'native'.`
250
+ );
251
+ }
252
+ return { asset: info.mint, decimals: info.decimals, symbol: info.symbol };
253
+ }
254
+ _chunkWQWNPAYQcjs.rejectForeignToken.call(void 0, token, "solana", network);
255
+ if (!("mint" in token)) {
256
+ throw new (0, _chunkWQWNPAYQcjs.WrongFamilyError)(
257
+ `chain ${network} is Solana; a custom token must be { mint, decimals }.`
258
+ );
259
+ }
260
+ return {
261
+ asset: token.mint,
262
+ decimals: token.decimals,
263
+ ...token.symbol ? { symbol: token.symbol } : {}
264
+ };
265
+ },
266
+ describeAsset(asset) {
267
+ if (asset === "native") return { symbol: "SOL", decimals: SOL_DECIMALS };
268
+ for (const info of Object.values(preset.tokens)) {
269
+ if (info.mint === asset) return { symbol: info.symbol, decimals: info.decimals };
270
+ }
271
+ return null;
272
+ },
273
+ assertValidPayTo(payTo) {
274
+ if (payTo.startsWith("0x")) {
275
+ throw new (0, _chunkWQWNPAYQcjs.WrongFamilyError)(
276
+ `chain ${network} is Solana, but payTo "${payTo}" looks like an EVM address.`
277
+ );
278
+ }
279
+ try {
280
+ new (0, _web3js.PublicKey)(payTo);
281
+ } catch (e2) {
282
+ throw new (0, _chunkWQWNPAYQcjs.WrongFamilyError)(
283
+ `chain ${network} is Solana, but payTo "${payTo}" is not a base58 address.`
284
+ );
285
+ }
286
+ },
287
+ bindWallet(wallet) {
288
+ return { _native: toKeypair(wallet, network) };
289
+ },
290
+ async send(wallet, accept) {
291
+ try {
292
+ return await paySolana({ connection, keypair: wallet._native, accept });
293
+ } catch (err) {
294
+ throw _nullishCoalesce(_chunkWQWNPAYQcjs.toInsufficientFundsError.call(void 0, err), () => ( err));
295
+ }
296
+ },
297
+ async confirm(ref) {
298
+ let info;
299
+ try {
300
+ const { value } = await connection.getSignatureStatuses([ref], {
301
+ searchTransactionHistory: true
302
+ });
303
+ info = value[0];
304
+ } catch (err) {
305
+ throw new (0, _chunkWQWNPAYQcjs.ConfirmationTimeoutError)(
306
+ `Solana payment ${ref} could not be confirmed (RPC read failed).`,
307
+ { cause: err }
308
+ );
309
+ }
310
+ if (!info || info.err || info.confirmationStatus !== "confirmed" && info.confirmationStatus !== "finalized") {
311
+ throw new (0, _chunkWQWNPAYQcjs.ConfirmationTimeoutError)(`Solana payment ${ref} did not confirm in time.`);
312
+ }
313
+ return { height: String(info.slot) };
314
+ },
315
+ async estimateCost(accept) {
316
+ const base = 5000n;
317
+ if (accept.asset === "native") {
318
+ return _chunkWQWNPAYQcjs.nativeCost.call(void 0, {
319
+ symbol: "SOL",
320
+ decimals: SOL_DECIMALS,
321
+ fee: base,
322
+ basis: "heuristic",
323
+ detail: "1 signature (5000 lamports)"
324
+ });
325
+ }
326
+ const ataRent = 2039280n;
327
+ return _chunkWQWNPAYQcjs.nativeCost.call(void 0, {
328
+ symbol: "SOL",
329
+ decimals: SOL_DECIMALS,
330
+ fee: base + ataRent,
331
+ basis: "heuristic",
332
+ detail: "1 signature + recipient token-account rent (~0.00204 SOL, if not already created)"
333
+ });
334
+ },
335
+ async verify(ref, accept) {
336
+ return verifySolana({ connection, signature: ref, accept });
337
+ }
338
+ };
339
+ }
340
+
341
+
342
+ exports.solanaDriver = solanaDriver;