@atomiqlabs/sdk 7.0.8 → 7.0.10

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/README.md CHANGED
@@ -1,1744 +1,1744 @@
1
- # atomiqlabs SDK
2
-
3
- A typescript multichain client for atomiqlabs trustlesss cross-chain swaps. Enables trustless swaps between smart chains (Solana, EVM, Starknet, etc.) and bitcoin (on-chain - L1 and lightning network - L2).
4
-
5
- Example SDK integration in NodeJS available [here](https://github.com/atomiqlabs/atomiq-sdk-demo)
6
-
7
- ## Installation
8
- ```
9
- npm install @atomiqlabs/sdk@latest
10
- ```
11
-
12
- ## Installing chain-specific connectors
13
-
14
- You can install only the chain-specific connectors that your project requires
15
-
16
- ```
17
- npm install @atomiqlabs/chain-solana@latest
18
- npm install @atomiqlabs/chain-starknet@latest
19
- npm install @atomiqlabs/chain-evm@latest
20
- ```
21
-
22
- ## How to use?
23
-
24
- - [Preparations](#preparations)
25
- - [Setting up signers](#signer)
26
- - [Initialization](#initialization)
27
- - Swaps:
28
- - [Smart Chain -> BTC L1](#swap-smart-chain---bitcoin-on-chain)
29
- - [BTC L1 -> Solana (Old swap protocol)](#swap-bitcoin-on-chain---solana)
30
- - [BTC L1 -> Starknet/EVM (New swap protocol)](#swap-bitcoin-on-chain---starknetevm)
31
- - [Smart Chain -> BTC Lightning network L2](#swap-smart-chain---bitcoin-lightning-network)
32
- - [Smart Chain -> BTC Lightning network L2 (LNURL-pay)](#swap-smart-chain---bitcoin-lightning-network-1)
33
- - [BTC Lightning network L2 -> Solana (Old swap protocol)](#swap-bitcoin-lightning-network---solana)
34
- - [BTC Lightning network L2 -> Starknet/EVM (New swap protocol)](#swap-bitcoin-lightning-network---starknetevm)
35
- - [BTC Lightning network L2 (LNURL-withdraw) -> Solana (Old swap protocol)](#swap-bitcoin-lightning-network---solana-1)
36
- - [BTC Lightning network L2 (LNURL-withdraw) -> Starknet/EVM (New swap protocol)](#swap-bitcoin-lightning-network---starknetevm-1)
37
- - [Swap states](#getting-state-of-the-swap)
38
- - [Swap size limits](#swap-size-limits)
39
- - [Stored swaps](#stored-swaps)
40
- - [Get existing swaps](#get-swap-by-id)
41
- - [Refundable swaps](#get-refundable-swaps)
42
- - [Claimable swaps](#get-claimable-swaps)
43
- - [Helpers](#helpers)
44
- - [Wallet spendable balance](#getting-wallet-balances)
45
- - [Unified address parsers](#unified-address-parser)
46
- - [Customize swapper instance](#additional-swapper-options)
47
-
48
- ### Preparations
49
-
50
- Set Solana & Starknet RPC URL to use
51
-
52
- ```typescript
53
- const solanaRpc = "https://api.mainnet-beta.solana.com";
54
- const starknetRpc = "https://starknet-mainnet.public.blastapi.io/rpc/v0_8";
55
- const citreaRpc = "https://rpc.testnet.citrea.xyz";
56
- ```
57
-
58
- Create swapper factory, here we can pick and choose which chains we want to have supported in the SDK, ensure the "as const" keyword is used such that the typescript compiler can properly infer the types.
59
-
60
- ```typescript
61
- import {SolanaInitializer, SolanaInitializerType} from "@atomiqlabs/chain-solana";
62
- import {StarknetInitializer, StarknetInitializerType} from "@atomiqlabs/chain-starknet";
63
- import {CitreaInitializer, CitreaInitializerType} from "@atomiqlabs/chain-evm";
64
- import {SwapperFactory} from "@atomiqlabs/sdk";
65
-
66
- const Factory = new SwapperFactory<[SolanaInitializerType, StarknetInitializerType, CitreaInitializerType]>([SolanaInitializer, StarknetInitializer, CitreaInitializer] as const);
67
- const Tokens = Factory.Tokens; //Get the supported tokens for all the specified chains.
68
- ```
69
-
70
- #### Browser
71
-
72
- This uses browser's Indexed DB by default
73
-
74
- ```typescript
75
- import {BitcoinNetwork} from "@atomiqlabs/sdk";
76
-
77
- const swapper = Factory.newSwapper({
78
- chains: {
79
- SOLANA: {
80
- rpcUrl: solanaRpc //You can also pass Connection object here
81
- },
82
- STARKNET: {
83
- rpcUrl: starknetRpc //You can also pass Provider object here
84
- },
85
- CITREA: {
86
- rpcUrl: citreaRpc, //You can also pass JsonApiProvider object here
87
- }
88
- },
89
- bitcoinNetwork: BitcoinNetwork.TESTNET //or BitcoinNetwork.MAINNET, BitcoinNetwork.TESTNET4 - this also sets the network to use for Solana (solana devnet for bitcoin testnet) & Starknet (sepolia for bitcoin testnet)
90
- });
91
- ```
92
-
93
- if you want to use custom pricing api, mempool.space RPC url, or tune HTTP request timeouts check out [additional options](#additional-swapper-options)
94
-
95
- #### NodeJS
96
-
97
- For NodeJS we need to use sqlite storage, for that we first need to install the sqlite storage adaptor
98
-
99
- ```
100
- npm install @atomiqlabs/storage-sqlite@latest
101
- ```
102
-
103
- Then use pass it in the newSwapper function
104
-
105
- ```typescript
106
- import {SqliteStorageManager, SqliteUnifiedStorage} from "@atomiqlabs/storage-sqlite";
107
- import {BitcoinNetwork} from "@atomiqlabs/sdk";
108
-
109
- const swapper = Factory.newSwapper({
110
- chains: {
111
- SOLANA: {
112
- rpcUrl: solanaRpc //You can also pass Connection object here
113
- },
114
- STARKNET: {
115
- rpcUrl: starknetRpc //You can also pass Provider object here
116
- },
117
- CITREA: {
118
- rpcUrl: citreaRpc, //You can also pass JsonApiProvider object here
119
- }
120
- },
121
- bitcoinNetwork: BitcoinNetwork.TESTNET, //or BitcoinNetwork.MAINNET - this also sets the network to use for Solana (solana devnet for bitcoin testnet) & Starknet (sepolia for bitcoin testnet)
122
- //The following lines are important for running on backend node.js,
123
- // because the SDK by default uses browser's Indexed DB
124
- swapStorage: chainId => new SqliteUnifiedStorage("CHAIN_"+chainId+".sqlite3"),
125
- chainStorageCtor: name => new SqliteStorageManager("STORE_"+name+".sqlite3"),
126
- });
127
- ```
128
-
129
- if you want to use custom pricing api, mempool.space RPC url, or tune HTTP request timeouts check out [additional options](#additional-swapper-options)
130
-
131
- ### Signer
132
-
133
- ```typescript
134
- import {SolanaSigner} from "@atomiqlabs/chain-solana";
135
- //Browser - react, using solana wallet adapter
136
- const anchorWallet = useAnchorWallet();
137
- const wallet = new SolanaSigner(anchorWallet);
138
- ```
139
-
140
- ```typescript
141
- import {WalletAccount} from "starknet";
142
- import {StarknetSigner} from "@atomiqlabs/chain-starknet";
143
- //Browser, using get-starknet
144
- const swo = await connect();
145
- const wallet = new StarknetBrowserSigner(new WalletAccount(starknetRpc, swo.wallet));
146
- ```
147
-
148
- or
149
-
150
- ```typescript
151
- import {Keypair} from "@solana/web3.js";
152
- import {SolanaKeypairWallet, SolanaSigner} from "@atomiqlabs/chain-solana";
153
- //Creating Solana signer from private key
154
- const solanaSigner = new SolanaSigner(new SolanaKeypairWallet(Keypair.fromSecretKey(solanaKey)), Keypair.fromSecretKey(solanaKey));
155
- ```
156
-
157
- ```typescript
158
- import {StarknetSigner, StarknetKeypairWallet} from "@atomiqlabs/chain-starknet";
159
- //Creating Starknet signer from private key
160
- const starknetSigner = new StarknetSigner(new StarknetKeypairWallet(starknetRpc, starknetKey));
161
- ```
162
-
163
- ```typescript
164
- import {BaseWallet, SigningKey} from "ethers";
165
- import {EVMSigner} from "@atomiqlabs/chain-evm";
166
- //Creating EVM signer from private key
167
- const wallet = new BaseWallet(new SigningKey(evmKey));
168
- const evmWallet = new EVMSigner(wallet, wallet.address);
169
- ```
170
-
171
- ### Initialization
172
-
173
- Initialize the swapper, this should be done once when your app starts. Checks existing in-progress swaps and does initial LP discovery
174
-
175
- ```typescript
176
- await swapper.init();
177
- ```
178
-
179
- Now we have the multichain swapper initialized
180
-
181
- ### Extract chain-specific swapper with signer
182
-
183
- To make it easier to do swaps between bitcoin and a specific chain we can extract a chain-specific swapper, and also set a signer. e.g.:
184
-
185
- ```typescript
186
- const solanaSwapper = swapper.withChain<"SOLANA">("SOLANA");
187
- ```
188
-
189
- ### Bitcoin on-chain swaps
190
-
191
- #### Swap Smart chain -> Bitcoin on-chain
192
-
193
- Getting swap quote
194
-
195
- ```typescript
196
- //Create the swap: swapping SOL to Bitcoin on-chain, receiving _amount of satoshis (smallest unit of bitcoin) to _address
197
- const swap = await swapper.swap(
198
- Tokens.SOLANA.SOL, //From specified source token
199
- Tokens.BITCOIN.BTC, //Swap to BTC
200
- "0.0001", //Amount can be either passed in base units as bigint or in decimal format as string
201
- SwapAmountType.EXACT_OUT, //EXACT_OUT, so we specify the output amount
202
- solanaSigner.getAddress(), //Source address and smart chain signer
203
- "bc1qtw67hj77rt8zrkkg3jgngutu0yfgt9czjwusxt" //BTC address of the recipient
204
- );
205
-
206
- //Get the amount required to pay and fee
207
- const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
208
- const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
209
- const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
210
-
211
- const output: string = swap.getOutput().toString(); //Total output amount
212
-
213
- //Get swap expiration time
214
- const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
215
-
216
- //Get pricing info
217
- const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
218
- const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
219
- const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
220
- ```
221
-
222
- Executing the swap (simple)
223
-
224
- ```typescript
225
- const swapSuccessful = await swap.execute(
226
- solanaSigner,
227
- { //Callbacks
228
- onSourceTransactionSent: (txId: string) => {
229
- //Transaction on the source chain was sent
230
- },
231
- onSourceTransactionConfirmed: (txId: string) => {
232
- //Transaction on the source chain was confirmed
233
- },
234
- onSwapSettled: (destinationTxId: string) => {
235
- //Bitcoin transaction on the destination chain was sent and swap settled
236
- }
237
- }
238
- );
239
-
240
- //Refund in case of failure
241
- if(!swapSuccessful) {
242
- //Swap failed, money can be refunded
243
- await swap.refund(solanaSigner);
244
- } else {
245
- //Swap successful!
246
- }
247
- ```
248
-
249
- <details>
250
- <summary>Manual swap execution (advanced)</summary>
251
-
252
- - __1.__ Initiate the swap on the smart-chain side
253
-
254
- - __a.__ Commit with a signer
255
- ```typescript
256
- await swap.commit(solanaSigner);
257
- ```
258
-
259
- - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
260
- ```typescript
261
- const txsCommit = await swap.txsCommit();
262
- //Sign and send these...
263
- ...
264
- //Important to wait till SDK processes the swap initialization
265
- await swap.waitTillCommited();
266
- ```
267
-
268
- - __2.__ Wait for the swap to execute and for the payment to be sent
269
- ```typescript
270
- const swapSuccessful = await swap.waitForPayment();
271
- ```
272
-
273
- - __3.__ In case the swap fails we can refund our funds on the source chain
274
-
275
- - __a.__ Refund with a signer
276
- ```typescript
277
- if(!swapSuccessful) {
278
- await swap.refund(solanaSigner);
279
- return;
280
- }
281
- ```
282
-
283
- - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
284
- ```typescript
285
- if(!swapSuccessful) {
286
- const txsRefund = await swap.txsRefund();
287
- //Sign and send these...
288
- ...
289
- }
290
- ```
291
-
292
- </details>
293
-
294
- <details>
295
- <summary>Swap states</summary>
296
-
297
- - ToBTCSwapState.REFUNDED = -3
298
- - Swap failed and was successfully refunded
299
- - ToBTCSwapState.QUOTE_EXPIRED = -2
300
- - Swap quote expired and cannot be executed anymore
301
- - ToBTCSwapState.QUOTE_SOFT_EXPIRED = -1
302
- - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
303
- - ToBTCSwapState.CREATED = 0
304
- - Swap quote is created, waiting to be executed
305
- - ToBTCSwapState.COMMITED = 1,
306
- - Swap was initiated (init transaction sent)
307
- - ToBTCSwapState.SOFT_CLAIMED = 2,
308
- - Swap was processed by the counterparty but not yet claimed on-chain (bitcoin transaction was sent, but unconfirmed yet)
309
- - ToBTCSwapState.CLAIMED = 3
310
- - Swap was finished and funds were successfully claimed by the counterparty
311
- - ToBTCSwapState.REFUNDABLE = 4
312
- - Swap was initiated but counterparty failed to process it, the user can now refund his funds
313
-
314
- </details>
315
-
316
- #### Swap Bitcoin on-chain -> Solana
317
-
318
- NOTE: Solana uses an old swap protocol for Bitcoin on-chain -> Solana swaps, the flow here is different from the one for Starknet and other chains.
319
-
320
- Getting swap quote
321
-
322
- ```typescript
323
- //Create the swap: swapping _amount of satoshis of Bitcoin on-chain to SOL
324
- const swap = await swapper.swap(
325
- Tokens.BITCOIN.BTC, //Swap from BTC
326
- Tokens.SOLANA.SOL, //Into specified destination token
327
- "0.0001", //Amount can be either passed in base units as bigint or in decimal format as string
328
- SwapAmountType.EXACT_IN, //EXACT_IN, so we specify the input amount
329
- undefined, //Source address for the swap, not used for swaps from BTC
330
- solanaSigner.getAddress() //Destination address
331
- );
332
-
333
- //Get the amount required to pay and fee
334
- const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
335
- const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
336
- const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
337
-
338
- const output: string = swap.getOutput().toString(); //Total output amount
339
-
340
- //Get swap expiration time
341
- const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
342
-
343
- //Get security deposit amount (Human readable amount of SOL that needs to be put down to rent the liquidity from swap intermediary), you will get this deposit back if the swap succeeds
344
- const securityDeposit: string = swap.getSecurityDeposit().toString();
345
- //Get claimer bounty (Human readable amount of SOL reserved as a reward for watchtowers to claim the swap on your behalf)
346
- const claimerBounty: string = swap.getClaimerBounty().toString();
347
-
348
- //Get pricing info
349
- const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
350
- const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
351
- const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
352
- ```
353
-
354
- Executing the swap (simple)
355
-
356
- ```typescript
357
- const automaticSettlementSuccess = await swap.execute(
358
- solanaSigner,
359
- { //Bitcoin wallet, you can also pass null/undefined and send the bitcoin transaction from an external wallet
360
- address: "bc1pscnrk588hdj79mwccucu06007mj5np2jurwfwp5mvhkjldzyphzqyk62m5",
361
- publicKey: "03a2d8b728935f61d5bcba0cfb09c2c443c483b5c31ebd180e1833f37344bd34ba",
362
- signPsbt: (psbt: {psbt, psbtHex: string, psbtBase64: string}, signInputs: number[]) => {
363
- //Sign the PSBT with the bitcoin wallet
364
- ...
365
- //Return the signed PSBT in the hex or base64 format!
366
- return "<signed PSBT>";
367
- }
368
- },
369
- { //Callbacks
370
- onDestinationCommitSent: (swapAddressOpeningTxId: string) => {
371
- //Swap address opening transaction sent on the destination chain
372
- },
373
- onSourceTransactionSent: (txId: string) => {
374
- //Bitcoin transaction sent on the source
375
- },
376
- onSourceTransactionConfirmationStatus: (txId: string, confirmations: number, targetConfirmations: number, txEtaMs: number) => {
377
- //Bitcoin transaction confirmation status updates
378
- },
379
- onSourceTransactionConfirmed: (txId: string) => {
380
- //Bitcoin transaction confirmed
381
- },
382
- onSwapSettled: (destinationTxId: string) => {
383
- //Swap settled on the destination
384
- }
385
- }
386
- );
387
-
388
- //In case the automatic swap settlement fails, we can settle it manually using the wallet of the destination chain
389
- if(!automaticSettlementSuccess) {
390
- await swap.claim(solanaSigner);
391
- }
392
- ```
393
-
394
- <details>
395
- <summary>Manual swap execution (advanced)</summary>
396
-
397
- - __1.__ Initiate the swap on the destination chain (Solana) by opening up the bitcoin swap address
398
-
399
- - __a.__ Commit using signer
400
- ```typescript
401
- await swap.commit(solanaWallet);
402
- ```
403
-
404
- - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
405
- ```typescript
406
- const txsCommit = await swap.txsCommit();
407
- //Sign and send these...
408
- ...
409
- //Important to wait till SDK processes the swap initialization
410
- await swap.waitTillCommited();
411
- ```
412
-
413
- - __2.__ Send bitcoin transaction
414
-
415
- - __a.__ Get funded PSBT and sign it
416
- ```typescript
417
- const {psbt, psbtHex, psbtBase64, signInputs} = await swap.getFundedPsbt({
418
- address: "bc1pscnrk588hdj79mwccucu06007mj5np2jurwfwp5mvhkjldzyphzqyk62m5",
419
- publicKey: "03a2d8b728935f61d5bcba0cfb09c2c443c483b5c31ebd180e1833f37344bd34ba"
420
- });
421
- //Sign the psbt
422
- const signedPsbt = ...; //Can be hex or base64 encoded
423
- const bitcoinTxId = await swap.submitPsbt(signedPsbt);
424
- ```
425
-
426
- - __b.__ Get the bitcoin address or deeplink and send from external wallet
427
- ```typescript
428
- //It is imporant to send the EXACT amount, sending different amount will lead to loss of funds!
429
- const btcSwapAddress = swap.getAddress();
430
- const btcDeepLink = swap.getHyperlink();
431
- ```
432
-
433
- - __3.__ Wait for the bitcoin on-chain transaction to confirm
434
- ```typescript
435
- await swap.waitForBitcoinTransaction(
436
- (txId, confirmations, targetConfirmations, txEtaMs) => {
437
- //Bitcoin transaction confirmation status callback
438
- }
439
- );
440
- ```
441
-
442
- - __4.__ Wait for the automatic settlement of the swap
443
- ```typescript
444
- const automaticSettlementSuccess = await swap.waitTillClaimed(30);
445
- ```
446
-
447
- - __5.__ In case the automatic swap settlement fails, we can settle it manually using the wallet of the destination chain
448
-
449
- - __a.__ Claim with a signer
450
- ```typescript
451
- if(!automaticSettlementSuccess) {
452
- await swap.claim(solanaSigner);
453
- }
454
- ```
455
-
456
- - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
457
- ```typescript
458
- if(!automaticSettlementSuccess) {}
459
- const txsClaim = await swap.txsClaim();
460
- //Sign and send these...
461
- ...
462
- //Important to wait till SDK processes the swap initialization
463
- await swap.waitTillCommited();
464
- }
465
- ```
466
-
467
- </details>
468
-
469
- <details>
470
- <summary>Swap states</summary>
471
-
472
- - FromBTCSwapState.EXPIRED = -3
473
- - Bitcoin swap address expired
474
- - FromBTCSwapState.QUOTE_EXPIRED = -2
475
- - Swap quote expired and cannot be executed anymore
476
- - FromBTCSwapState.QUOTE_SOFT_EXPIRED = -1
477
- - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
478
- - FromBTCSwapState.PR_CREATED = 0
479
- - Swap quote is created, waiting for the user to open a bitcoin swap address
480
- - FromBTCSwapState.CLAIM_COMMITED = 1
481
- - Bitcoin swap address is opened
482
- - FromBTCSwapState.BTC_TX_CONFIRMED = 2
483
- - Bitcoin transaction sending funds to the swap address is confirmed
484
- - FromBTCSwapState.CLAIM_CLAIMED = 3
485
- - Swap funds are claimed to the user's wallet
486
-
487
- </details>
488
-
489
- #### Swap Bitcoin on-chain -> Starknet/EVM
490
-
491
- NOTE: Starknet & EVM uses a new swap protocol for Bitcoin on-chain -> Smart chain swaps, the flow here is different from the one for Solana!
492
-
493
- Getting swap quote
494
-
495
- ```typescript
496
- //Create the swap: swapping _amount of satoshis of Bitcoin on-chain to SOL
497
- const swap = await swapper.swap(
498
- Tokens.BITCOIN.BTC, //Swap from BTC
499
- Tokens.STARKNET.STRK, //Into specified destination token
500
- "0.0001", //Amount can be either passed in base units as bigint or in decimal format as string
501
- SwapAmountType.EXACT_IN, //EXACT_IN, so we specify the input amount
502
- undefined, //Source address for the swap, not used for swaps from BTC
503
- starknetSigner.getAddress(), //Destination address
504
- {
505
- gasAmount: 1_000_000_000_000_000_000n //We can also request a gas drop on the destination chain (here requesting 1 STRK)
506
- }
507
- );
508
-
509
- //Get the amount required to pay and fee
510
- const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
511
- const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
512
- const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
513
-
514
- const output: string = swap.getOutput().toString(); //Total output amount
515
-
516
- //Get swap expiration time
517
- const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
518
-
519
- //Get pricing info
520
- const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
521
- const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
522
- const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
523
- ```
524
-
525
- Executing the swap (simple)
526
-
527
- ```typescript
528
- const automaticSettlementSuccess = await swap.execute(
529
- { //Bitcoin wallet
530
- address: "bc1pscnrk588hdj79mwccucu06007mj5np2jurwfwp5mvhkjldzyphzqyk62m5",
531
- publicKey: "03a2d8b728935f61d5bcba0cfb09c2c443c483b5c31ebd180e1833f37344bd34ba",
532
- signPsbt: (psbt: {psbt, psbtHex: string, psbtBase64: string}, signInputs: number[]) => {
533
- //Sign the PSBT with the bitcoin wallet
534
- ...
535
- //Return the signed PSBT in the hex or base64 format!
536
- return "<signed PSBT>";
537
- }
538
- },
539
- { //Callbacks
540
- onSourceTransactionSent: (txId: string) => {
541
- //Bitcoin transaction sent on the source
542
- },
543
- onSourceTransactionConfirmationStatus: (txId: string, confirmations: number, targetConfirmations: number, txEtaMs: number) => {
544
- //Bitcoin transaction confirmation status updates
545
- },
546
- onSourceTransactionConfirmed: (txId: string) => {
547
- //Bitcoin transaction confirmed
548
- },
549
- onSwapSettled: (destinationTxId: string) => {
550
- //Swap settled on the destination
551
- }
552
- }
553
- );
554
-
555
- //In case the automatic swap settlement fails, we can settle it manually using the wallet of the destination chain
556
- if(!automaticSettlementSuccess) {
557
- await swap.claim(starknetWallet);
558
- }
559
- ```
560
-
561
-
562
- <details>
563
- <summary>Manual swap execution (advanced)</summary>
564
-
565
- - __1.__ Send bitcoin transaction
566
-
567
- - __a.__ Get funded PSBT and sign it using external wallet (e.g. browser-based like Xverse, Unisat, Phantom, etc.)
568
- ```typescript
569
- //Obtain the funded PSBT (input already added) - ready for signing
570
- const {psbt, psbtHex, psbtBase64, signInputs} = await swap.getFundedPsbt({address: "", publicKey: ""});
571
- //Pass `psbtBase64` or `psbtHex` (and also `signInputs`) to an external signer like Xverse, Unisat, etc.
572
- const signedPsbtHexOrBase64 = await <signPsbt function of the external wallet>; //Call the signPsbt function of the external signer with psbtBase64 or psbtHex and signInputs
573
- //The SDK automatically recognizes hex & base64 encoded PSBTs
574
- const bitcoinTxId = await swap.submitPsbt(signedPsbtHexOrBase64);
575
- ```
576
-
577
- - __b.__ Or obtain raw PSBT to which inputs still need to be added
578
- ```typescript
579
- const {psbt, psbtHex, psbtBase64, in1sequence} = await swap.getPsbt();
580
- psbt.addInput(...);
581
- //Make sure the second input's sequence (index 1) is as specified in the in1sequence variable
582
- psbt.updateInput(1, {sequence: in1sequence});
583
- //Sign the PSBT, sign every input except the first one
584
- for(let i=1;i<psbt.inputsLength; i++) psbt.signIdx(..., i); //Or pass it to external signer
585
- //Submit the signed PSBT, can be the Transaction object, or hex/base64 serialized
586
- const bitcoinTxId = await swap.submitPsbt(psbt);
587
- ```
588
-
589
- - __2.__ Wait for the bitcoin on-chain transaction to confirm
590
- ```typescript
591
- await swap.waitForBitcoinTransaction(
592
- (txId, confirmations, targetConfirmations, txEtaMs) => {
593
- //Bitcoin transaction confirmation status callback
594
- }
595
- );
596
- ```
597
-
598
- - __3.__ Wait for the automatic settlement of the swap
599
- ```typescript
600
- const automaticSettlementSuccess = await swap.waitTillClaimed(60);
601
- ```
602
-
603
- - __4.__ In case the automatic swap settlement fails, we can settle it manually using the wallet of the destination chain
604
-
605
- - __a.__ Claim with a signer
606
- ```typescript
607
- if(!automaticSettlementSuccess) {
608
- await swap.claim(starknetSigner);
609
- }
610
- ```
611
-
612
- - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
613
- ```typescript
614
- if(!automaticSettlementSuccess) {}
615
- const txsClaim = await swap.txsClaim();
616
- //Sign and send these...
617
- ...
618
- //Important to wait till SDK processes the swap initialization
619
- await swap.waitTillCommited();
620
- }
621
- ```
622
-
623
- </details>
624
-
625
- <details>
626
- <summary>Swap states</summary>
627
-
628
- - SpvFromBTCSwapState.CLOSED = -5
629
- - Catastrophic failure during swap, shall never happen
630
- - SpvFromBTCSwapState.FAILED = -4
631
- - Bitcoin transaction was sent, but was double-spent later, therefore the swap was failed (no BTC was sent)
632
- - SpvFromBTCSwapState.DECLINED = -3
633
- - LP declined to process the swap transaction, no BTC was sent
634
- - SpvFromBTCSwapState.QUOTE_EXPIRED = -2
635
- - Swap quote expired and cannot be executed anymore
636
- - SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED = -1
637
- - Swap quote soft-expired (i.e. the quote probably expired, but if there is a bitcoin transaction being submitted it might still succeed)
638
- - SpvFromBTCSwapState.CREATED = 0
639
- - Swap quote is created, waiting on user to sign the bitcoin swap transaction
640
- - SpvFromBTCSwapState.SIGNED = 1
641
- - Bitcoin swap transaction was signed by the client
642
- - SpvFromBTCSwapState.POSTED = 2
643
- - Bitcoin swap transaction was posted to the LP
644
- - SpvFromBTCSwapState.BROADCASTED = 3
645
- - LP broadcasted the bitcoin swap transaction
646
- - SpvFromBTCSwapState.FRONTED = 4
647
- - Swap funds have been deposited to the user's wallet in front of the time
648
- - SpvFromBTCSwapState.BTC_TX_CONFIRMED = 5
649
- - Bitcoin swap transaction is confirmed
650
- - SpvFromBTCSwapState.CLAIM_CLAIMED = 6
651
- - Swap funds are claimed to the user's wallet
652
- -
653
- </details>
654
-
655
- ### Bitcoin lightning network swaps
656
-
657
- #### Swap Smart chain -> Bitcoin lightning network
658
-
659
- Getting swap quote
660
-
661
- ```typescript
662
- //Create the swap: swapping SOL to Bitcoin lightning
663
- const swap = await swapper.swap(
664
- Tokens.SOLANA.SOL, //From specified source token
665
- Tokens.BITCOIN.BTCLN, //Swap to BTC-LN
666
- undefined, //Amount is specified in the lightning network invoice!
667
- SwapAmountType.EXACT_OUT, //Make sure we use EXACT_OUT for swaps to BTC-LN, if you want to use EXACT_IN and set an amount, use LNURL-pay!
668
- solanaSigner.getAddress(), //Source address and smart chain signer
669
- //Destination lightning network invoice, amount needs to be part of the invoice!
670
- "lnbc10u1pj2q0g9pp5ejs6m677m39cznpzum7muruvh50ys93ln82p4j9ks2luqm56xxlshp52r2anlhddfa9ex9vpw9gstxujff8a0p8s3pzvua930js0kwfea6scqzzsxqyz5vqsp5073zskc5qfgp7lre0t6s8uexxxey80ax564hsjklfwfjq2ew0ewq9qyyssqvzmgs6f8mvuwgfa9uqxhtza07qem4yfhn9wwlpskccmuwplsqmh8pdy6c42kqdu8p73kky9lsnl40qha5396d8lpgn90y27ltfc5rfqqq59cya"
671
- );
672
-
673
- //Get the amount required to pay and fee
674
- const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
675
- const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
676
- const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
677
-
678
- const output: string = swap.getOutput().toString(); //Total output amount
679
-
680
- //Get swap expiration time
681
- const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
682
-
683
- //Get pricing info
684
- const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
685
- const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
686
- const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
687
- ```
688
-
689
- Executing the swap (simple)
690
-
691
- ```typescript
692
- const swapSuccessful = await swap.execute(
693
- solanaSigner,
694
- { //Callbacks
695
- onSourceTransactionSent: (txId: string) => {
696
- //Transaction on the source chain was sent
697
- },
698
- onSourceTransactionConfirmed: (txId: string) => {
699
- //Transaction on the source chain was confirmed
700
- },
701
- onSwapSettled: (destinationTxId: string) => {
702
- //Lightning payment on the destination chain was sent and swap settled
703
- }
704
- }
705
- );
706
-
707
- //Refund in case of failure
708
- if(!swapSuccessful) {
709
- //Swap failed, money can be refunded
710
- await swap.refund(solanaSigner);
711
- } else {
712
- //Swap successful!
713
- }
714
- ```
715
-
716
- <details>
717
- <summary>Manual swap execution (advanced)</summary>
718
-
719
- - __1.__ Initiate the swap on the smart-chain side
720
-
721
- - __a.__ Commit with a signer
722
- ```typescript
723
- await swap.commit(solanaSigner);
724
- ```
725
-
726
- - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
727
- ```typescript
728
- const txsCommit = await swap.txsCommit();
729
- //Sign and send these...
730
- ...
731
- //Important to wait till SDK processes the swap initialization
732
- await swap.waitTillCommited();
733
- ```
734
-
735
- - __2.__ Wait for the swap to execute and for the payment to be sent
736
- ```typescript
737
- const swapSuccessful = await swap.waitForPayment();
738
- ```
739
-
740
- - __3.__ In case the swap fails we can refund our funds on the source chain
741
-
742
- - __a.__ Refund with a signer
743
- ```typescript
744
- if(!swapSuccessful) {
745
- await swap.refund(solanaSigner);
746
- return;
747
- }
748
- ```
749
-
750
- - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
751
- ```typescript
752
- if(!swapSuccessful) {
753
- const txsRefund = await swap.txsRefund();
754
- //Sign and send these...
755
- ...
756
- }
757
- ```
758
-
759
- </details>
760
-
761
- <details>
762
- <summary>Swap states</summary>
763
-
764
- - ToBTCSwapState.REFUNDED = -3
765
- - Swap failed and was successfully refunded
766
- - ToBTCSwapState.QUOTE_EXPIRED = -2
767
- - Swap quote expired and cannot be executed anymore
768
- - ToBTCSwapState.QUOTE_SOFT_EXPIRED = -1
769
- - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
770
- - ToBTCSwapState.CREATED = 0
771
- - Swap quote is created, waiting to be executed
772
- - ToBTCSwapState.COMMITED = 1,
773
- - Swap was initiated (init transaction sent)
774
- - ToBTCSwapState.SOFT_CLAIMED = 2,
775
- - Swap was processed by the counterparty but not yet claimed on-chain (lightning network payment secret was revealed)
776
- - ToBTCSwapState.CLAIMED = 3
777
- - Swap was finished and funds were successfully claimed by the counterparty
778
- - ToBTCSwapState.REFUNDABLE = 4
779
- - Swap was initiated but counterparty failed to process it, the user can now refund his funds
780
-
781
- </details>
782
-
783
- #### Swap Bitcoin lightning network -> Solana
784
-
785
- NOTE: Solana uses an old swap protocol for Bitcoin lightning network -> Solana swaps, the flow here is different from the one for Starknet and other chains.
786
-
787
- Getting swap quote
788
-
789
- ```typescript
790
- const swap = await swapper.swap(
791
- Tokens.BITCOIN.BTCLN, //Swap from BTC-LN
792
- Tokens.SOLANA.SOL, //Into specified destination token
793
- 10000n, //Amount can be either passed in base units as bigint or in decimal format as string
794
- SwapAmountType.EXACT_IN, //SwapAmountType.EXACT_IN, so we specify the input amount
795
- undefined, //Source address for the swap, not used for swaps from BTC-LN
796
- signer.getAddress() //Destination address
797
- );
798
-
799
- //Get the bitcoin lightning network invoice (the invoice contains pre-entered amount)
800
- const receivingLightningInvoice: string = swap.getAddress();
801
- //Get the URI hyperlink (contains the lightning network invoice) which can be displayed also as QR code
802
- const qrCodeData: string = swap.getHyperlink();
803
-
804
- //Get the amount required to pay and fee
805
- const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
806
- const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
807
- const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
808
-
809
- const output: string = swap.getOutput().toString(); //Total output amount
810
-
811
- //Get swap expiration time
812
- const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
813
-
814
- //Get security deposit amount (Human readable amount of STRK that needs to be put down to rent the liquidity from swap intermediary), you will get this deposit back if the swap succeeds
815
- const securityDeposit: string = swap.getSecurityDeposit().toString();
816
-
817
- //Get pricing info
818
- const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
819
- const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
820
- const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
821
- ```
822
-
823
- Executing the swap (simple)
824
-
825
- ```typescript
826
- await swap.execute(
827
- solanaSigner,
828
- { //Lightning network wallet, you can also pass null/undefined and pay the LN invoice from an external wallet
829
- payInvoice: (bolt11PaymentRequest: string) => {
830
- //Here you would usually call the WebLN or NWC to execute the payment, it's completely fine if the
831
- // promise here would block till the payment is settled
832
- return Promise.resolve("");
833
- }
834
- },
835
- { //Callbacks
836
- onSourceTransactionReceived: (sourceLnPaymentHash: string) => {
837
- //Lightning network payment received by the LP
838
- },
839
- onDestinationCommitSent: (destinationCommitTxId: string) => {
840
- //HTLC initialization transaction sent on the destination chain
841
- },
842
- onDestinationClaimSent: (destinationClaimTxId: string) => {
843
- //HTLC claim transaction sent on the destination chain
844
- },
845
- onSwapSettled: (destinationClaimTxId: string) => {
846
- //Swap settled and funds received on destination
847
- }
848
- }
849
- );
850
- ```
851
-
852
- <details>
853
- <summary>Manual swap execution (advanced)</summary>
854
-
855
- - __1.__ Pay the LN invoice from a lightning network wallet
856
- ```typescript
857
- const lightningInvoice = swap.getAddress();
858
- ```
859
-
860
- - __2.__ Start listening to incoming lightning network payment
861
- ```typescript
862
- const success = await swap.waitForPayment();
863
- if(!success) {
864
- //Lightning network payment not received in time and quote expired
865
- return;
866
- }
867
- ```
868
-
869
- - __3.__ Claim the swap at the destination
870
-
871
- - __a.__ Commit & claim with signer
872
- ```typescript
873
- await swap.commitAndClaim(solanaSigner);
874
- ```
875
-
876
- - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
877
- ```typescript
878
- const txsCommitAndClaim = await swap.txsCommitAndClaim();
879
- //Take EXTRA care to make sure transaction are sent sequentially and in order - always wait
880
- // for prior transaction confirmation before sending the next one
881
- //Sign and send these...
882
- ...
883
- ```
884
-
885
- </details>
886
-
887
- <details>
888
- <summary>Swap states</summary>
889
-
890
- - FromBTCLNSwapState.FAILED = -4
891
- - If the claiming of the funds was initiated, but never concluded, the user will get his lightning network payment refunded
892
- - FromBTCLNSwapState.QUOTE_EXPIRED = -3
893
- - Swap quote expired and cannot be executed anymore
894
- - FromBTCLNSwapState.QUOTE_SOFT_EXPIRED = -2
895
- - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
896
- - FromBTCLNSwapState.EXPIRED = -1
897
- - Lightning network invoice expired, meaning the swap is expired
898
- - FromBTCLNSwapState.PR_CREATED = 0
899
- - Swap is created, the user should now pay the provided lightning network invoice
900
- - FromBTCLNSwapState.PR_PAID = 1
901
- - Lightning network invoice payment was received (but cannot be settled by the counterparty yet)
902
- - FromBTCLNSwapState.CLAIM_COMMITED = 2
903
- - Claiming of the funds was initiated
904
- - FromBTCLNSwapState.CLAIM_CLAIMED = 3
905
- - Funds were successfully claimed & lightning network secret pre-image revealed, so the lightning network payment will settle now
906
-
907
- </details>
908
-
909
- #### Swap Bitcoin lightning network -> Starknet/EVM
910
-
911
- Getting swap quote
912
-
913
- ```typescript
914
- const swap = await swapper.swap(
915
- Tokens.BITCOIN.BTCLN, //Swap from BTC-LN
916
- Tokens.STARKNET.STRK, //Into specified destination token
917
- 10000n, //Amount can be either passed in base units as bigint or in decimal format as string
918
- SwapAmountType.EXACT_IN, //SwapAmountType.EXACT_IN, so we specify the input amount
919
- undefined, //Source address for the swap, not used for swaps from BTC-LN
920
- signer.getAddress(), //Destination address
921
- {
922
- gasAmount: 1_000_000_000_000_000_000n //We can also request a gas drop on the destination chain (here requesting 1 STRK)
923
- }
924
- );
925
-
926
- //Get the bitcoin lightning network invoice (the invoice contains pre-entered amount)
927
- const receivingLightningInvoice: string = swap.getAddress();
928
- //Get the URI hyperlink (contains the lightning network invoice) which can be displayed also as QR code
929
- const qrCodeData: string = swap.getHyperlink();
930
-
931
- //Get the amount required to pay and fee
932
- const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
933
- const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
934
- const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
935
-
936
- const output: string = swap.getOutput().toString(); //Total output amount
937
-
938
- //Get swap expiration time
939
- const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
940
-
941
- //Get pricing info
942
- const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
943
- const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
944
- const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
945
- ```
946
-
947
- Executing the swap (simple)
948
-
949
- ```typescript
950
- const automaticSettlementSuccess = await swap.execute(
951
- { //Lightning network wallet, you can also pass null/undefined and pay the LN invoice from an external wallet
952
- payInvoice: (bolt11PaymentRequest: string) => {
953
- //Here you would usually call the WebLN or NWC to execute the payment, it's completely fine if the
954
- // promise here would block till the payment is settled
955
- return Promise.resolve("");
956
- }
957
- },
958
- { //Callbacks
959
- onSourceTransactionReceived: (sourceLnPaymentHash: string) => {
960
- //Lightning network payment received by the LP
961
- },
962
- onSwapSettled: (destinationClaimTxId: string) => {
963
- //Swap settled and funds received on destination
964
- }
965
- }
966
- );
967
-
968
- //In case the automatic swap settlement fails, we can settle it manually using the wallet of the destination chain
969
- if(!automaticSettlementSuccess) {
970
- await swap.claim(starknetSigner);
971
- }
972
- ```
973
-
974
-
975
- <details>
976
- <summary>Manual swap execution (advanced)</summary>
977
-
978
- - __1.__ Pay the LN invoice from a lightning network wallet
979
- ```typescript
980
- const lightningInvoice = swap.getAddress();
981
- ```
982
-
983
- - __2.__ Start listening to incoming lightning network payment
984
- ```typescript
985
- const success = await swap.waitForPayment();
986
- if(!success) {
987
- //Lightning network payment not received in time and quote expired
988
- return;
989
- }
990
- ```
991
-
992
- - __3.__ Wait for the swap to be automatically settled
993
- ```typescript
994
- const automaticSettlementSuccess = await swap.waitTillClaimed(60);
995
- ```
996
-
997
- - __4.__ In case the automatic swap settlement fails, we can settle it manually using the wallet of the destination chain
998
-
999
- - __a.__ Claim with signer
1000
- ```typescript
1001
- if(!automaticSettlementSuccess) {
1002
- await swap.claim(starknetSigner);
1003
- }
1004
- ```
1005
-
1006
- - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
1007
- ```typescript
1008
- if(!automaticSettlementSuccess) {
1009
- const txsClaim = await swap.txsClaim();
1010
- //Sign and send these...
1011
- ...
1012
- }
1013
- ```
1014
-
1015
- </details>
1016
-
1017
- <details>
1018
- <summary>Swap states</summary>
1019
-
1020
- - FromBTCLNAutoSwapState.FAILED = -4
1021
- - If the claiming of the funds was initiated, but never concluded, the user will get his lightning network payment refunded
1022
- - FromBTCLNAutoSwapState.QUOTE_EXPIRED = -3
1023
- - Swap quote expired and cannot be executed anymore
1024
- - FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED = -2
1025
- - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
1026
- - FromBTCLNAutoSwapState.EXPIRED = -1
1027
- - Lightning network invoice expired, meaning the swap is expired
1028
- - FromBTCLNAutoSwapState.PR_CREATED = 0
1029
- - Swap is created, the user should now pay the provided lightning network invoice
1030
- - FromBTCLNAutoSwapState.PR_PAID = 1
1031
- - Lightning network invoice payment was received (but cannot be settled by the counterparty yet)
1032
- - FromBTCLNAutoSwapState.CLAIM_COMMITED = 2
1033
- - A swap HTLC was offered by the LP to the user
1034
- - FromBTCLNAutoSwapState.CLAIM_CLAIMED = 3
1035
- - Funds were successfully claimed & lightning network secret pre-image revealed, so the lightning network payment will settle now
1036
-
1037
- </details>
1038
-
1039
- ### LNURLs & readable lightning identifiers
1040
-
1041
- LNURLs extend the lightning network functionality by creating static lightning addreses (LNURL-pay & static internet identifiers) and QR codes which allow you to pull funds from them (LNURL-withdraw)
1042
-
1043
- This SDK supports:
1044
- * LNURL-pay ([LUD-6](https://github.com/lnurl/luds/blob/luds/06.md), [LUD-9](https://github.com/lnurl/luds/blob/luds/09.md), [LUD-10](https://github.com/lnurl/luds/blob/luds/10.md), [LUD-12](https://github.com/lnurl/luds/blob/luds/12.md))
1045
- * LNURL-withdraw ([LUD-3](https://github.com/lnurl/luds/blob/luds/03.md))
1046
- * Static internet identifiers ([LUD-16](https://github.com/lnurl/luds/blob/luds/16.md))
1047
-
1048
- You can parse LNURLs and lightning invoices automatically using the [Unified address parser](#unified-address-parser)
1049
-
1050
- #### Differences
1051
-
1052
- Lightning invoices:
1053
- * One time use only
1054
- * Need to have a fixed amount, therefore recipient has to set the amount
1055
- * Static and bounded expiration
1056
- * You can only pay to a lightning invoice, not withdraw funds from it
1057
-
1058
- LNURLs & lightning identifiers:
1059
- * Reusable
1060
- * Programmable expiry
1061
- * Allows payer to set an amount
1062
- * Supports both, paying (LNURL-pay) and withdrawing (LNURL-withdraw)
1063
- * Possibility to attach a message/comment to a payment
1064
- * Receive a message/url as a result of the payment
1065
-
1066
- #### Swap Smart chain -> Bitcoin lightning network
1067
-
1068
- Getting swap quote
1069
-
1070
- ```typescript
1071
- //Create the swap: swapping SOL to Bitcoin lightning
1072
- const swap = await swapper.swap(
1073
- Tokens.SOLANA.SOL, //From specified source token
1074
- Tokens.BITCOIN.BTCLN, //Swap to BTC-LN
1075
- 10000n, //Now we can specify an amount for a lightning network payment!
1076
- SwapAmountType.EXACT_OUT, //We can also use exactIn=true here and set an amount in input token
1077
- solanaSigner.getAddress(), //Source address and smart chain signer
1078
- //Destination LNURL-pay or readable identifier
1079
- "lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkx6rfvdjx2ctvxyesuk0a27",
1080
- {
1081
- comment: "Hello world" //For LNURL-pay we can also pass a comment to the recipient
1082
- }
1083
- );
1084
-
1085
- //Get the amount required to pay and fee
1086
- const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
1087
- const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
1088
- const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
1089
-
1090
- const output: string = swap.getOutput().toString(); //Total output amount
1091
-
1092
- //Get swap expiration time
1093
- const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
1094
-
1095
- //Get pricing info
1096
- const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
1097
- const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
1098
- const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
1099
- ```
1100
-
1101
-
1102
- Executing the swap (simple)
1103
-
1104
- ```typescript
1105
- const swapSuccessful = await swap.execute(
1106
- solanaSigner,
1107
- { //Callbacks
1108
- onSourceTransactionSent: (txId: string) => {
1109
- //Transaction on the source chain was sent
1110
- },
1111
- onSourceTransactionConfirmed: (txId: string) => {
1112
- //Transaction on the source chain was confirmed
1113
- },
1114
- onSwapSettled: (destinationTxId: string) => {
1115
- //Lightning payment on the destination chain was sent and swap settled
1116
- }
1117
- }
1118
- );
1119
-
1120
- //Refund in case of failure
1121
- if(!swapSuccessful) {
1122
- //Swap failed, money can be refunded
1123
- await swap.refund(solanaSigner);
1124
- return;
1125
- }
1126
-
1127
- //Swap successful!
1128
- const lightningSecret = swap.getSecret();
1129
- //In case the LNURL contained a success action, we can read it now and display it to user
1130
- if(swap.hasSuccessAction()) {
1131
- //Contains a success action that should displayed to the user
1132
- const successMessage = swap.getSuccessAction();
1133
- const description: string = successMessage.description; //Description of the message
1134
- const text: (string | null) = successMessage.text; //Main text of the message
1135
- const url: (string | null) = successMessage.url; //URL link which should be displayed
1136
- }
1137
- ```
1138
-
1139
- <details>
1140
- <summary>Manual swap execution (advanced)</summary>
1141
-
1142
- - __1.__ Initiate the swap on the smart-chain side
1143
-
1144
- - __a.__ Commit with a signer
1145
- ```typescript
1146
- await swap.commit(solanaSigner);
1147
- ```
1148
-
1149
- - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
1150
- ```typescript
1151
- const txsCommit = await swap.txsCommit();
1152
- //Sign and send these...
1153
- ...
1154
- //Important to wait till SDK processes the swap initialization
1155
- await swap.waitTillCommited();
1156
- ```
1157
-
1158
- - __2.__ Wait for the swap to execute and for the payment to be sent
1159
-
1160
- ```typescript
1161
- const swapSuccessful = await swap.waitForPayment();
1162
- ```
1163
-
1164
- - __3.__ In case the swap fails we can refund our funds on the source chain
1165
-
1166
- - __a.__ Refund with a signer
1167
- ```typescript
1168
- if(!swapSuccessful) {
1169
- await swap.refund(solanaSigner);
1170
- return;
1171
- }
1172
- ```
1173
-
1174
- - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
1175
- ```typescript
1176
- if(!swapSuccessful) {
1177
- const txsRefund = await swap.txsRefund();
1178
- //Sign and send these...
1179
- ...
1180
- }
1181
- ```
1182
-
1183
- </details>
1184
-
1185
- #### Swap Bitcoin lightning network -> Solana
1186
-
1187
- NOTE: Solana uses an old swap protocol for Bitcoin lightning network -> Solana swaps, the flow here is different from the one for Starknet and other chains.
1188
-
1189
- Getting swap quote
1190
-
1191
- ```typescript
1192
- const swap = await swapper.swap(
1193
- Tokens.BITCOIN.BTCLN, //Swap from BTC-LN
1194
- Tokens.SOLANA.SOL, //Into specified destination token
1195
- 10000n,
1196
- SwapAmountType.EXACT_IN, //EXACT_IN, so we specify the input amount
1197
- //Source LNURL-withdraw link
1198
- "lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkx6rfvdjx2ctvxyesuk0a27",
1199
- signer.getAddress(), //Destination address
1200
- );
1201
-
1202
- //Get the amount required to pay and fee
1203
- const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
1204
- const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
1205
- const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
1206
-
1207
- const output: string = swap.getOutput().toString(); //Total output amount
1208
-
1209
- //Get swap expiration time
1210
- const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
1211
-
1212
- //Get security deposit amount (Human readable amount of STRK that needs to be put down to rent the liquidity from swap intermediary), you will get this deposit back if the swap succeeds
1213
- const securityDeposit: string = swap.getSecurityDeposit().toString();
1214
-
1215
- //Get pricing info
1216
- const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
1217
- const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
1218
- const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
1219
- ```
1220
-
1221
- Executing the swap (simple)
1222
-
1223
- ```typescript
1224
- await swap.execute(
1225
- solanaSigner,
1226
- undefined, //No need to specify a wallet, we are sourcing the fund from LNURL-withdraw link
1227
- { //Callbacks
1228
- onSourceTransactionReceived: (sourceLnPaymentHash: string) => {
1229
- //Lightning network payment received by the LP
1230
- },
1231
- onDestinationCommitSent: (destinationCommitTxId: string) => {
1232
- //HTLC initialization transaction sent on the destination chain
1233
- },
1234
- onDestinationClaimSent: (destinationClaimTxId: string) => {
1235
- //HTLC claim transaction sent on the destination chain
1236
- },
1237
- onSwapSettled: (destinationClaimTxId: string) => {
1238
- //Swap settled and funds received on destination
1239
- }
1240
- }
1241
- );
1242
- ```
1243
-
1244
- <details>
1245
- <summary>Manual swap execution (advanced)</summary>
1246
-
1247
- - __1.__ Start listening to incoming lightning network payment (this also requests the payment from LNURL-withdraw service)
1248
- ```typescript
1249
- const success = await swap.waitForPayment();
1250
- if(!success) {
1251
- //Lightning network payment not received in time and quote expired
1252
- return;
1253
- }
1254
- ```
1255
-
1256
- - __2.__ Claim the swap at the destination
1257
-
1258
- - __a.__ Commit & claim with signer
1259
- ```typescript
1260
- await swap.commitAndClaim(solanaSigner);
1261
- ```
1262
-
1263
- - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
1264
- ```typescript
1265
- const txsCommitAndClaim = await swap.txsCommitAndClaim();
1266
- //Take EXTRA care to make sure transaction are sent sequentially and in order - always wait
1267
- // for prior transaction confirmation before sending the next one
1268
- //Sign and send these...
1269
- ...
1270
- ```
1271
-
1272
- </details>
1273
-
1274
- #### Swap Bitcoin lightning network -> Starknet/EVM
1275
-
1276
- Getting swap quote
1277
-
1278
- ```typescript
1279
- const swap = await swapper.swap(
1280
- Tokens.BITCOIN.BTCLN, //Swap from BTC-LN
1281
- Tokens.STARKNET.STRK, //Into specified destination token
1282
- 10000n,
1283
- SwapAmountType.EXACT_IN, //EXACT_IN, so we specify the input amount
1284
- //Source LNURL-withdraw link
1285
- "lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkx6rfvdjx2ctvxyesuk0a27",
1286
- signer.getAddress(), //Destination address
1287
- {
1288
- gasAmount: 1_000_000_000_000_000_000n //We can also request a gas drop on the destination chain (here requesting 1 STRK)
1289
- }
1290
- );
1291
-
1292
- //Get the amount required to pay and fee
1293
- const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
1294
- const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
1295
- const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
1296
-
1297
- const output: string = swap.getOutput().toString(); //Total output amount
1298
-
1299
- //Get swap expiration time
1300
- const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
1301
-
1302
- //Get pricing info
1303
- const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
1304
- const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
1305
- const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
1306
- ```
1307
-
1308
-
1309
- Executing the swap (simple)
1310
-
1311
- ```typescript
1312
- const automaticSettlementSuccess = await swap.execute(
1313
- undefined, //No need to specify a wallet, we are sourcing the funds from LNURL-withdraw link
1314
- { //Callbacks
1315
- onSourceTransactionReceived: (sourceLnPaymentHash: string) => {
1316
- //Lightning network payment received by the LP
1317
- },
1318
- onSwapSettled: (destinationClaimTxId: string) => {
1319
- //Swap settled and funds received on destination
1320
- }
1321
- }
1322
- );
1323
-
1324
- //In case the automatic swap settlement fails, we can settle it manually using the wallet of the destination chain
1325
- if(!automaticSettlementSuccess) {
1326
- await swap.claim(starknetSigner);
1327
- }
1328
- ```
1329
-
1330
-
1331
- <details>
1332
- <summary>Manual swap execution (advanced)</summary>
1333
-
1334
- - __1.__ Start listening to incoming lightning network payment (this also requests the payment from LNURL-withdraw service)
1335
- ```typescript
1336
- const success = await swap.waitForPayment();
1337
- if(!success) {
1338
- //Lightning network payment not received in time and quote expired
1339
- return;
1340
- }
1341
- ```
1342
-
1343
- - __2.__ Wait for the swap to be automatically settled
1344
- ```typescript
1345
- const automaticSettlementSuccess = await swap.waitTillClaimed(60);
1346
- ```
1347
-
1348
- - __3.__ In case the automatic swap settlement fails, we can settle it manually using the wallet of the destination chain
1349
-
1350
- - __a.__ Claim with signer
1351
- ```typescript
1352
- if(!automaticSettlementSuccess) {
1353
- await swap.claim(starknetSigner);
1354
- }
1355
- ```
1356
-
1357
- - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
1358
- ```typescript
1359
- if(!automaticSettlementSuccess) {
1360
- const txsClaim = await swap.txsClaim();
1361
- //Sign and send these...
1362
- ...
1363
- }
1364
- ```
1365
-
1366
- </details>
1367
-
1368
- ### Exact-In Smart Chain - Lightning swaps
1369
-
1370
- The main limitation of regular lightning network swaps (Smart chains -> Lightning), is the fact that exactIn swaps are not possible (as invoices need to have a fixed amount). LNURL-pay links solve this issue, but are not supported by all the wallets. Therefore, the SDK exposes a hook/callback that can be implemented by lightning wallets directly, which request fixed amount invoices on-demand. This then makes exact input amount swaps possible. The way it works:
1371
-
1372
- 1. SDK sends a request to the LP saying it wants to swap `x` USDC to BTC, with a dummy invoice (either 1 sat or as specified in the `minMsats` parameter - this is requested from the `getInvoice()` function) - this dummy invoice is used to estimate the routing fees by the LP (extra care must be taken for both invoices, dummy and the real one to have the same destination node public key & routing hints).
1373
- 2. LP responds with the output amount of `y` BTC
1374
- 3. SDK calls the provided `getInvoice()` callback to request the real invoice for the `y` amount of BTC (in satoshis)
1375
- 4. SDK forwards the returned fixed amount (`y` BTC) lightning network invoice back to the LP to finish creating the quote
1376
-
1377
- Getting swap quote
1378
-
1379
- ```typescript
1380
- //Create the swap: swapping SOL to Bitcoin lightning
1381
- const swap = await swapper.swap(
1382
- Tokens.SOLANA.SOL, //From specified source token
1383
- Tokens.BITCOIN.BTCLN, //Swap to BTC-LN
1384
- 1_000_000_000n, //We can specify an amount for a lightning network payment!
1385
- SwapAmountType.EXACT_IN, //We can use exactIn=true here and set an amount in input token
1386
- solanaSigner.getAddress(), //Source address and smart chain signer
1387
- //Instead of the destination we pass a handler object
1388
- {
1389
- getInvoice: async (amountSats: number, abortSignal?: AbortSignal) => {
1390
- //Generate invoice with fixed amountSats here!
1391
- ...
1392
- return invoice;
1393
- },
1394
- //Optionally you can also specify minimum and maximum in msats (millisatoshis, 1 sat = 1000 msats)
1395
- minMsats: 1_000_000n,
1396
- maxMsats: 1_000_000_000n
1397
- },
1398
- {
1399
- comment: "Hello world" //For LNURL-pay we can also pass a comment to the recipient
1400
- }
1401
- );
1402
-
1403
- //Get the amount required to pay and fee
1404
- const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
1405
- const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
1406
- const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
1407
-
1408
- const output: string = swap.getOutput().toString(); //Total output amount
1409
-
1410
- //Get swap expiration time
1411
- const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
1412
-
1413
- //Get pricing info
1414
- const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
1415
- const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
1416
- const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
1417
- ```
1418
-
1419
-
1420
- Executing the swap (simple)
1421
-
1422
- ```typescript
1423
- const swapSuccessful = await swap.execute(
1424
- solanaSigner,
1425
- { //Callbacks
1426
- onSourceTransactionSent: (txId: string) => {
1427
- //Transaction on the source chain was sent
1428
- },
1429
- onSourceTransactionConfirmed: (txId: string) => {
1430
- //Transaction on the source chain was confirmed
1431
- },
1432
- onSwapSettled: (destinationTxId: string) => {
1433
- //Lightning payment on the destination chain was sent and swap settled
1434
- }
1435
- }
1436
- );
1437
-
1438
- //Refund in case of failure
1439
- if(!swapSuccessful) {
1440
- //Swap failed, money can be refunded
1441
- await swap.refund(solanaSigner);
1442
- return;
1443
- }
1444
-
1445
- //Swap successful!
1446
- const lightningSecret = swap.getSecret();
1447
- ```
1448
-
1449
- <details>
1450
- <summary>Manual swap execution (advanced)</summary>
1451
-
1452
- - __1.__ Initiate the swap on the smart-chain side
1453
-
1454
- - __a.__ Commit with a signer
1455
- ```typescript
1456
- await swap.commit(solanaSigner);
1457
- ```
1458
-
1459
- - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
1460
- ```typescript
1461
- const txsCommit = await swap.txsCommit();
1462
- //Sign and send these...
1463
- ...
1464
- //Important to wait till SDK processes the swap initialization
1465
- await swap.waitTillCommited();
1466
- ```
1467
-
1468
- - __2.__ Wait for the swap to execute and for the payment to be sent
1469
-
1470
- ```typescript
1471
- const swapSuccessful = await swap.waitForPayment();
1472
- ```
1473
-
1474
- - __3.__ In case the swap fails we can refund our funds on the source chain
1475
-
1476
- - __a.__ Refund with a signer
1477
- ```typescript
1478
- if(!swapSuccessful) {
1479
- await swap.refund(solanaSigner);
1480
- return;
1481
- }
1482
- ```
1483
-
1484
- - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
1485
- ```typescript
1486
- if(!swapSuccessful) {
1487
- const txsRefund = await swap.txsRefund();
1488
- //Sign and send these...
1489
- ...
1490
- }
1491
- ```
1492
-
1493
- </details>
1494
-
1495
- ### Getting state of the swap
1496
-
1497
- You can get the current state of the swap with:
1498
-
1499
- ```typescript
1500
- const state = swap.getState();
1501
- ```
1502
-
1503
- You can also set a listener to listen for swap state changes:
1504
-
1505
- ```typescript
1506
- swap.events.on("swapState", swap => {
1507
- const newState = swap.getState();
1508
- });
1509
- ```
1510
-
1511
- For the meaning of the states please refer to the "Swap state" section under each swap type.
1512
-
1513
- ### Swap size limits
1514
-
1515
- Swap sizes are limited by the LPs you are connected to, they are advertised in BTC terms by LPs during handshake
1516
-
1517
- ```typescript
1518
- const swapLimits = swapper.getSwapLimits(srcToken, dstToken);
1519
- const inputMin = swapLimits.input.min;
1520
- const inputMax = swapLimits.input.max;
1521
- const outputMin = swapLimits.output.min;
1522
- const outputMax = swapLimits.output.max;
1523
- ```
1524
-
1525
- NOTE: swap limits denominated in BTC are retrieved from the LPs during initial handshake, however limits in other tokens are only returned when getting a quote fails due to amount being too low or too high. For example if you want to get swap limits for the BTC -> SOL swap, the input limits will be immediately available, while the output limits will only get populated once a quote request fails due to amount being too low or high.
1526
-
1527
- ```typescript
1528
- let swapLimits = swapper.getSwapLimits(Tokens.BITCOIN.BTC, Tokens.SOLANA.SOL);
1529
- let inputMin = swapLimits.input.min; //Immediately available
1530
- let inputMax = swapLimits.input.max; //Immediately available
1531
- let outputMin = swapLimits.output.min; //Not available from the get-go
1532
- let outputMax = swapLimits.output.max; //Not available from the get-go
1533
-
1534
- //You can also listen to swap limit changes (optional)
1535
- swapper.on("swapLimitsChanged", () => {
1536
- //New limits available with swapper.getSwapLimits(srcToken, dstToken)
1537
- //Useful in e.g. a react application where you want to dynamically set min/max swappable amount
1538
- })
1539
-
1540
- //Try to swap really small amount of SOL with exactOut swap
1541
- try {
1542
- const swap = await swapper.swap(
1543
- Tokens.BITCOIN.BTC, //Swap from BTC
1544
- Tokens.SOLANA.SOL, //Into specified destination token
1545
- 1n, //1 lamport = 0.000000001 SOL
1546
- false, //Whether we define an input or output amount
1547
- undefined, //Source address for the swap, not used for swaps from BTC
1548
- solanaSigner.getAddress() //Destination address
1549
- );
1550
- } catch (e) {
1551
- //Fails with OutOfBoundsError
1552
- }
1553
-
1554
- swapLimits = swapper.getSwapLimits(Tokens.BITCOIN.BTC, Tokens.SOLANA.SOL);
1555
- inputMin = swapLimits.input.min; //Immediately available
1556
- inputMax = swapLimits.input.max; //Immediately available
1557
- outputMin = swapLimits.output.min; //Now available due to failed quote
1558
- outputMax = swapLimits.output.max; //Now available due to failed quote
1559
- ```
1560
-
1561
- ### Stored swaps
1562
-
1563
- #### Get swap by ID
1564
-
1565
- You can retrieve a swap by it's id, you can get an ID of the swap with
1566
-
1567
- ```typescript
1568
- const swapId = swap.getId();
1569
- ```
1570
-
1571
- And then later retrieve it from the storage
1572
-
1573
- ```typescript
1574
- const swap = await swapper.getSwapById(id);
1575
- ```
1576
-
1577
- #### Get refundable swaps
1578
- You can refund the swaps in one of two cases:
1579
- * In case intermediary is non-cooperative and goes offline, you can claim the funds from the swap contract back after some time.
1580
- * In case intermediary tried to pay but was unsuccessful, so he sent you signed message with which you can refund now without waiting.
1581
-
1582
- This call can be checked on every startup and periodically every few minutes.
1583
- ```typescript
1584
- //Get refundable swaps and refund them
1585
- const refundableSolanaSwaps = await swapper.getRefundableSwaps("SOLANA", solanaSigner.getAddress());
1586
- for(let swap of refundableSolanaSwaps) await swap.refund(solanaSigner);
1587
- const refundableStarknetSwaps = await swapper.getRefundableSwaps("STARKNET", starknetSigner.getAddress());
1588
- for(let swap of refundableStarknetSwaps) await swap.refund(starknetSigner);
1589
- ```
1590
-
1591
- #### Get claimable swaps
1592
- Returns swaps that are ready to be claimed by the client, this can happen if client closes the application when a swap is in-progress and the swap is concluded while the client is offline.
1593
-
1594
- ```typescript
1595
- //Get the swaps
1596
- const claimableSolanaSwaps = await solanaSwapper.getClaimableSwaps("SOLANA", solanaSigner.getAddress());
1597
- //Claim all the claimable swaps
1598
- for(let swap of claimableSolanaSwaps) {
1599
- await swap.claim(solanaSigner);
1600
- }
1601
- //Get the swaps
1602
- const claimableStarknetSwaps = await solanaSwapper.getClaimableSwaps("STARKNET", starknetSigner.getAddress());
1603
- //Claim all the claimable swaps
1604
- for(let swap of claimableStarknetSwaps) {
1605
- await swap.claim(starknetSigner);
1606
- }
1607
- ```
1608
-
1609
- ### Helpers
1610
-
1611
- #### Getting wallet balances
1612
-
1613
- The SDK also contains helper functions for getting the maximum spendable balance of wallets
1614
-
1615
- ```typescript
1616
- //Spendable balance of the starknet wallet address (discounting transaction fees)
1617
- const strkBalance = await swapper.Utils.getSpendableBalance(starknetSigner, Tokens.STARKNET.STRK);
1618
- //Spendable balance of the solana wallet address (discounting transaction fees)
1619
- const solBalance = await swapper.Utils.getSpendableBalance(solanaSigner, Tokens.SOLANA.SOL);
1620
- //Spendable balance of the bitcoin wallet - here we also need to specify the destination chain (as there are different swap protocols available with different on-chain footprints)
1621
- const {balance: btcBalance, feeRate: btcFeeRate} = await swapper.Utils.getBitcoinSpendableBalance(bitcoinWalletAddress, "SOLANA");
1622
- ```
1623
-
1624
- #### Unified address parser
1625
-
1626
- A common way for parsing all address formats supported by the SDK, automatically recognizes:
1627
- - Bitcoin on-chain L1 address formats (p2pkh, p2wpkh, p2wsh, p2wsh, p2tr)
1628
- - [BIP-21](https://en.bitcoin.it/wiki/BIP_0021) bitcoin payment URI
1629
- - BOLT11 lightning network invoices
1630
- - [LUD-6](https://github.com/lnurl/luds/blob/luds/06.md) LNURL-pay links
1631
- - [LUD-3](https://github.com/lnurl/luds/blob/luds/03.md) LNURL-withdraw links
1632
- - [LUD-16](https://github.com/lnurl/luds/blob/luds/16.md) Lightning static internet identifiers
1633
- - Smart chain addresses (Solana, Starknet, etc.)
1634
-
1635
- ```typescript
1636
- const res = await swapper.Utils.parseAddress(address);
1637
- switch(res.type) {
1638
- case "BITCOIN":
1639
- //Bitcoin on-chain L1 address or BIP-21 URI scheme with amount
1640
- const btcAmount = res.amount;
1641
- break;
1642
- case "LIGHTNING":
1643
- //BOLT11 lightning network invoice with pre-set amount
1644
- const lnAmount = res.amount;
1645
- break;
1646
- case "LNURL":
1647
- //LNURL payment or withdrawal link
1648
- if(isLNURLWithdraw(res.lnurl)) {
1649
- //LNURL-withdraw allowing withdrawals over the lightning network
1650
- const lnurlWithdrawData: LNURLWithdraw = res.lnurl;
1651
- const minWithdrawable = res.min; //Minimum payment amount
1652
- const maxWithdrawable = res.max; //Maximum payment amount
1653
- const fixedAmount = res.amount; //If res.min===res.max, an fixed amount is returned instead
1654
- //Should show a UI allowing the user to choose an amount he wishes to withdraw
1655
- }
1656
- if(isLNURLPay(res.lnurl)) {
1657
- //LNURL-pay or static lightning internet identifier allowing repeated payments over the lightning network
1658
- const lnurlPayData: LNURLPay = res.lnurl;
1659
- const minPayable = res.min; //Minimum payment amount
1660
- const maxPayable = res.max; //Maximum payment amount
1661
- const fixedAmount = res.amount; //If res.min===res.max, an fixed amount is returned instead
1662
- const icon: (string | null) = res.lnurl.icon; //URL encoded icon that should be displayed on the UI
1663
- const shortDescription: (string | null) = res.lnurl.shortDescription; //Short description of the payment
1664
- const longDescription: (string | null) = res.lnurl.longDescription; //Long description of the payment
1665
- const maxCommentLength: (number | 0) = res.lnurl.commentMaxLength; //Maximum allowed length of the payment message/comment (0 means no comment allowed)
1666
- //Should show a UI displaying the icon, short description, long description, allowing the user to choose an amount he wishes to pay and possibly also a comment
1667
- }
1668
- break;
1669
- default:
1670
- //Addresses for smart chains
1671
- break;
1672
- }
1673
- ```
1674
-
1675
- ### Manually signing smart chain transactions
1676
-
1677
- You can also sign the transactions on smart chain side (Solana, Starknet, etc.) of the SDK externally by a separate wallet. Each function which executes any transaction has its txs(action) counterpart, e.g.:
1678
- - commit() -> txsCommit()
1679
- - claim() -> txsClaim()
1680
- - commitAndClaim -> txsCommitAndClaim()
1681
- - refund() -> txsRefund()
1682
-
1683
- After sending the transactions, you also need to make sure the SDK has enough time to receive an event notification of the transaction being executed, for this you have the waitTill(action) functions, e.g.:
1684
-
1685
- - commit() -> waitTillCommited()
1686
- - claim() -> waitTillClaimed()
1687
- - commitAndClaim -> waitTillClaimed()
1688
- - refund() -> waitTillRefunded()
1689
-
1690
- ```typescript
1691
- //Example for Solana
1692
- const txns = await swap.txsCommit(); //Also works with txsClaim, txsRefund, txCommitAndClaim
1693
- txns.forEach(val => if(val.signers.length>0) { val.tx.sign(...val.signers) });
1694
- const signedTransactions = await solanaSigner.wallet.signAllTransactions(txns.map(val => val.tx));
1695
- for(let tx of signedTransactions) {
1696
- const res = await solanaRpc.sendRawTransaction(tx.serialize());
1697
- await solanaRpc.confirmTransaction(res);
1698
- }
1699
- await swap.waitTillCommited(); //Or other relevant waitTillClaimed, waitTillRefunded
1700
-
1701
- //Example for Starknet
1702
- const txns = await swap.txsCommit(); //Also works with txsClaim, txsRefund, txCommitAndClaim
1703
- for(let tx of txns) {
1704
- if(tx.type==="INVOKE") await starknetSigner.account.execute(tx.tx, tx.details);
1705
- if(tx.type==="DEPLOY_ACCOUNT") await starknetSigner.account.deployAccount(tx.tx, tx.details);
1706
- }
1707
- await swap.waitTillCommited(); //Or other relevant waitTillClaimed, waitTillRefunded
1708
-
1709
- //Example for EVM
1710
- const txns = await swap.txsCommit(); //Also works with txsClaim, txsRefund, txCommitAndClaim
1711
- for(let tx of txns) {
1712
- await evmSigner.account.sendTransaction(tx);
1713
- }
1714
- await swap.waitTillCommited(); //Or other relevant waitTillClaimed, waitTillRefunded
1715
- ```
1716
-
1717
- ### Additional swapper options
1718
-
1719
- You can further customize the swapper instance with these options, you can:
1720
- - adjust the maximum accepted pricing difference from the LPs
1721
- - use custom mempool.space instance
1722
- - use custom pricing API
1723
- - use own LP node for swaps
1724
- - adjust HTTP request timeouts
1725
- - add parameters to be sent with each LP request
1726
-
1727
- ```typescript
1728
- const swapper = Factory.newSwapper({
1729
- ...
1730
- //Additional optional options
1731
- pricingFeeDifferencePPM: 20000n, //Maximum allowed pricing difference for quote (between swap & market price) in ppm (parts per million) (20000 == 2%)
1732
- mempoolApi: new MempoolApi("<url to custom mempool.space instance>"), //Set the SDK to use a custom mempool.space instance instead of the public one
1733
- getPriceFn: (tickers: string[], abortSignal?: AbortSignal) => customPricingApi.getUsdPriceForTickers(tickers) //Overrides the default pricing API engine with a custom price getter
1734
-
1735
- intermediaryUrl: "<url to custom LP node>",
1736
- registryUrl: "<url to custom LP node registry>",
1737
-
1738
- getRequestTimeout: 10000, //Timeout in milliseconds for GET requests
1739
- postRequestTimeout: 10000, //Timeout in milliseconds for POST requests
1740
- defaultAdditionalParameters: {lpData: "Pls give gud price"}, //Additional request data sent to LPs
1741
-
1742
- defaultTrustedIntermediaryUrl: "<url to custom LP node>" //LP node/intermediary to use for trusted gas swaps
1743
- });
1744
- ```
1
+ # atomiqlabs SDK
2
+
3
+ A typescript multichain client for atomiqlabs trustlesss cross-chain swaps. Enables trustless swaps between smart chains (Solana, EVM, Starknet, etc.) and bitcoin (on-chain - L1 and lightning network - L2).
4
+
5
+ Example SDK integration in NodeJS available [here](https://github.com/atomiqlabs/atomiq-sdk-demo)
6
+
7
+ ## Installation
8
+ ```
9
+ npm install @atomiqlabs/sdk@latest
10
+ ```
11
+
12
+ ## Installing chain-specific connectors
13
+
14
+ You can install only the chain-specific connectors that your project requires
15
+
16
+ ```
17
+ npm install @atomiqlabs/chain-solana@latest
18
+ npm install @atomiqlabs/chain-starknet@latest
19
+ npm install @atomiqlabs/chain-evm@latest
20
+ ```
21
+
22
+ ## How to use?
23
+
24
+ - [Preparations](#preparations)
25
+ - [Setting up signers](#signer)
26
+ - [Initialization](#initialization)
27
+ - Swaps:
28
+ - [Smart Chain -> BTC L1](#swap-smart-chain---bitcoin-on-chain)
29
+ - [BTC L1 -> Solana (Old swap protocol)](#swap-bitcoin-on-chain---solana)
30
+ - [BTC L1 -> Starknet/EVM (New swap protocol)](#swap-bitcoin-on-chain---starknetevm)
31
+ - [Smart Chain -> BTC Lightning network L2](#swap-smart-chain---bitcoin-lightning-network)
32
+ - [Smart Chain -> BTC Lightning network L2 (LNURL-pay)](#swap-smart-chain---bitcoin-lightning-network-1)
33
+ - [BTC Lightning network L2 -> Solana (Old swap protocol)](#swap-bitcoin-lightning-network---solana)
34
+ - [BTC Lightning network L2 -> Starknet/EVM (New swap protocol)](#swap-bitcoin-lightning-network---starknetevm)
35
+ - [BTC Lightning network L2 (LNURL-withdraw) -> Solana (Old swap protocol)](#swap-bitcoin-lightning-network---solana-1)
36
+ - [BTC Lightning network L2 (LNURL-withdraw) -> Starknet/EVM (New swap protocol)](#swap-bitcoin-lightning-network---starknetevm-1)
37
+ - [Swap states](#getting-state-of-the-swap)
38
+ - [Swap size limits](#swap-size-limits)
39
+ - [Stored swaps](#stored-swaps)
40
+ - [Get existing swaps](#get-swap-by-id)
41
+ - [Refundable swaps](#get-refundable-swaps)
42
+ - [Claimable swaps](#get-claimable-swaps)
43
+ - [Helpers](#helpers)
44
+ - [Wallet spendable balance](#getting-wallet-balances)
45
+ - [Unified address parsers](#unified-address-parser)
46
+ - [Customize swapper instance](#additional-swapper-options)
47
+
48
+ ### Preparations
49
+
50
+ Set Solana & Starknet RPC URL to use
51
+
52
+ ```typescript
53
+ const solanaRpc = "https://api.mainnet-beta.solana.com";
54
+ const starknetRpc = "https://starknet-mainnet.public.blastapi.io/rpc/v0_8";
55
+ const citreaRpc = "https://rpc.testnet.citrea.xyz";
56
+ ```
57
+
58
+ Create swapper factory, here we can pick and choose which chains we want to have supported in the SDK, ensure the "as const" keyword is used such that the typescript compiler can properly infer the types.
59
+
60
+ ```typescript
61
+ import {SolanaInitializer, SolanaInitializerType} from "@atomiqlabs/chain-solana";
62
+ import {StarknetInitializer, StarknetInitializerType} from "@atomiqlabs/chain-starknet";
63
+ import {CitreaInitializer, CitreaInitializerType} from "@atomiqlabs/chain-evm";
64
+ import {SwapperFactory} from "@atomiqlabs/sdk";
65
+
66
+ const Factory = new SwapperFactory<[SolanaInitializerType, StarknetInitializerType, CitreaInitializerType]>([SolanaInitializer, StarknetInitializer, CitreaInitializer] as const);
67
+ const Tokens = Factory.Tokens; //Get the supported tokens for all the specified chains.
68
+ ```
69
+
70
+ #### Browser
71
+
72
+ This uses browser's Indexed DB by default
73
+
74
+ ```typescript
75
+ import {BitcoinNetwork} from "@atomiqlabs/sdk";
76
+
77
+ const swapper = Factory.newSwapper({
78
+ chains: {
79
+ SOLANA: {
80
+ rpcUrl: solanaRpc //You can also pass Connection object here
81
+ },
82
+ STARKNET: {
83
+ rpcUrl: starknetRpc //You can also pass Provider object here
84
+ },
85
+ CITREA: {
86
+ rpcUrl: citreaRpc, //You can also pass JsonApiProvider object here
87
+ }
88
+ },
89
+ bitcoinNetwork: BitcoinNetwork.TESTNET //or BitcoinNetwork.MAINNET, BitcoinNetwork.TESTNET4 - this also sets the network to use for Solana (solana devnet for bitcoin testnet) & Starknet (sepolia for bitcoin testnet)
90
+ });
91
+ ```
92
+
93
+ if you want to use custom pricing api, mempool.space RPC url, or tune HTTP request timeouts check out [additional options](#additional-swapper-options)
94
+
95
+ #### NodeJS
96
+
97
+ For NodeJS we need to use sqlite storage, for that we first need to install the sqlite storage adaptor
98
+
99
+ ```
100
+ npm install @atomiqlabs/storage-sqlite@latest
101
+ ```
102
+
103
+ Then use pass it in the newSwapper function
104
+
105
+ ```typescript
106
+ import {SqliteStorageManager, SqliteUnifiedStorage} from "@atomiqlabs/storage-sqlite";
107
+ import {BitcoinNetwork} from "@atomiqlabs/sdk";
108
+
109
+ const swapper = Factory.newSwapper({
110
+ chains: {
111
+ SOLANA: {
112
+ rpcUrl: solanaRpc //You can also pass Connection object here
113
+ },
114
+ STARKNET: {
115
+ rpcUrl: starknetRpc //You can also pass Provider object here
116
+ },
117
+ CITREA: {
118
+ rpcUrl: citreaRpc, //You can also pass JsonApiProvider object here
119
+ }
120
+ },
121
+ bitcoinNetwork: BitcoinNetwork.TESTNET, //or BitcoinNetwork.MAINNET - this also sets the network to use for Solana (solana devnet for bitcoin testnet) & Starknet (sepolia for bitcoin testnet)
122
+ //The following lines are important for running on backend node.js,
123
+ // because the SDK by default uses browser's Indexed DB
124
+ swapStorage: chainId => new SqliteUnifiedStorage("CHAIN_"+chainId+".sqlite3"),
125
+ chainStorageCtor: name => new SqliteStorageManager("STORE_"+name+".sqlite3"),
126
+ });
127
+ ```
128
+
129
+ if you want to use custom pricing api, mempool.space RPC url, or tune HTTP request timeouts check out [additional options](#additional-swapper-options)
130
+
131
+ ### Signer
132
+
133
+ ```typescript
134
+ import {SolanaSigner} from "@atomiqlabs/chain-solana";
135
+ //Browser - react, using solana wallet adapter
136
+ const anchorWallet = useAnchorWallet();
137
+ const wallet = new SolanaSigner(anchorWallet);
138
+ ```
139
+
140
+ ```typescript
141
+ import {WalletAccount} from "starknet";
142
+ import {StarknetSigner} from "@atomiqlabs/chain-starknet";
143
+ //Browser, using get-starknet
144
+ const swo = await connect();
145
+ const wallet = new StarknetBrowserSigner(new WalletAccount(starknetRpc, swo.wallet));
146
+ ```
147
+
148
+ or
149
+
150
+ ```typescript
151
+ import {Keypair} from "@solana/web3.js";
152
+ import {SolanaKeypairWallet, SolanaSigner} from "@atomiqlabs/chain-solana";
153
+ //Creating Solana signer from private key
154
+ const solanaSigner = new SolanaSigner(new SolanaKeypairWallet(Keypair.fromSecretKey(solanaKey)), Keypair.fromSecretKey(solanaKey));
155
+ ```
156
+
157
+ ```typescript
158
+ import {StarknetSigner, StarknetKeypairWallet} from "@atomiqlabs/chain-starknet";
159
+ //Creating Starknet signer from private key
160
+ const starknetSigner = new StarknetSigner(new StarknetKeypairWallet(starknetRpc, starknetKey));
161
+ ```
162
+
163
+ ```typescript
164
+ import {BaseWallet, SigningKey} from "ethers";
165
+ import {EVMSigner} from "@atomiqlabs/chain-evm";
166
+ //Creating EVM signer from private key
167
+ const wallet = new BaseWallet(new SigningKey(evmKey));
168
+ const evmWallet = new EVMSigner(wallet, wallet.address);
169
+ ```
170
+
171
+ ### Initialization
172
+
173
+ Initialize the swapper, this should be done once when your app starts. Checks existing in-progress swaps and does initial LP discovery
174
+
175
+ ```typescript
176
+ await swapper.init();
177
+ ```
178
+
179
+ Now we have the multichain swapper initialized
180
+
181
+ ### Extract chain-specific swapper with signer
182
+
183
+ To make it easier to do swaps between bitcoin and a specific chain we can extract a chain-specific swapper, and also set a signer. e.g.:
184
+
185
+ ```typescript
186
+ const solanaSwapper = swapper.withChain<"SOLANA">("SOLANA");
187
+ ```
188
+
189
+ ### Bitcoin on-chain swaps
190
+
191
+ #### Swap Smart chain -> Bitcoin on-chain
192
+
193
+ Getting swap quote
194
+
195
+ ```typescript
196
+ //Create the swap: swapping SOL to Bitcoin on-chain, receiving _amount of satoshis (smallest unit of bitcoin) to _address
197
+ const swap = await swapper.swap(
198
+ Tokens.SOLANA.SOL, //From specified source token
199
+ Tokens.BITCOIN.BTC, //Swap to BTC
200
+ "0.0001", //Amount can be either passed in base units as bigint or in decimal format as string
201
+ SwapAmountType.EXACT_OUT, //EXACT_OUT, so we specify the output amount
202
+ solanaSigner.getAddress(), //Source address and smart chain signer
203
+ "bc1qtw67hj77rt8zrkkg3jgngutu0yfgt9czjwusxt" //BTC address of the recipient
204
+ );
205
+
206
+ //Get the amount required to pay and fee
207
+ const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
208
+ const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
209
+ const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
210
+
211
+ const output: string = swap.getOutput().toString(); //Total output amount
212
+
213
+ //Get swap expiration time
214
+ const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
215
+
216
+ //Get pricing info
217
+ const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
218
+ const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
219
+ const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
220
+ ```
221
+
222
+ Executing the swap (simple)
223
+
224
+ ```typescript
225
+ const swapSuccessful = await swap.execute(
226
+ solanaSigner,
227
+ { //Callbacks
228
+ onSourceTransactionSent: (txId: string) => {
229
+ //Transaction on the source chain was sent
230
+ },
231
+ onSourceTransactionConfirmed: (txId: string) => {
232
+ //Transaction on the source chain was confirmed
233
+ },
234
+ onSwapSettled: (destinationTxId: string) => {
235
+ //Bitcoin transaction on the destination chain was sent and swap settled
236
+ }
237
+ }
238
+ );
239
+
240
+ //Refund in case of failure
241
+ if(!swapSuccessful) {
242
+ //Swap failed, money can be refunded
243
+ await swap.refund(solanaSigner);
244
+ } else {
245
+ //Swap successful!
246
+ }
247
+ ```
248
+
249
+ <details>
250
+ <summary>Manual swap execution (advanced)</summary>
251
+
252
+ - __1.__ Initiate the swap on the smart-chain side
253
+
254
+ - __a.__ Commit with a signer
255
+ ```typescript
256
+ await swap.commit(solanaSigner);
257
+ ```
258
+
259
+ - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
260
+ ```typescript
261
+ const txsCommit = await swap.txsCommit();
262
+ //Sign and send these...
263
+ ...
264
+ //Important to wait till SDK processes the swap initialization
265
+ await swap.waitTillCommited();
266
+ ```
267
+
268
+ - __2.__ Wait for the swap to execute and for the payment to be sent
269
+ ```typescript
270
+ const swapSuccessful = await swap.waitForPayment();
271
+ ```
272
+
273
+ - __3.__ In case the swap fails we can refund our funds on the source chain
274
+
275
+ - __a.__ Refund with a signer
276
+ ```typescript
277
+ if(!swapSuccessful) {
278
+ await swap.refund(solanaSigner);
279
+ return;
280
+ }
281
+ ```
282
+
283
+ - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
284
+ ```typescript
285
+ if(!swapSuccessful) {
286
+ const txsRefund = await swap.txsRefund();
287
+ //Sign and send these...
288
+ ...
289
+ }
290
+ ```
291
+
292
+ </details>
293
+
294
+ <details>
295
+ <summary>Swap states</summary>
296
+
297
+ - ToBTCSwapState.REFUNDED = -3
298
+ - Swap failed and was successfully refunded
299
+ - ToBTCSwapState.QUOTE_EXPIRED = -2
300
+ - Swap quote expired and cannot be executed anymore
301
+ - ToBTCSwapState.QUOTE_SOFT_EXPIRED = -1
302
+ - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
303
+ - ToBTCSwapState.CREATED = 0
304
+ - Swap quote is created, waiting to be executed
305
+ - ToBTCSwapState.COMMITED = 1,
306
+ - Swap was initiated (init transaction sent)
307
+ - ToBTCSwapState.SOFT_CLAIMED = 2,
308
+ - Swap was processed by the counterparty but not yet claimed on-chain (bitcoin transaction was sent, but unconfirmed yet)
309
+ - ToBTCSwapState.CLAIMED = 3
310
+ - Swap was finished and funds were successfully claimed by the counterparty
311
+ - ToBTCSwapState.REFUNDABLE = 4
312
+ - Swap was initiated but counterparty failed to process it, the user can now refund his funds
313
+
314
+ </details>
315
+
316
+ #### Swap Bitcoin on-chain -> Solana
317
+
318
+ NOTE: Solana uses an old swap protocol for Bitcoin on-chain -> Solana swaps, the flow here is different from the one for Starknet and other chains.
319
+
320
+ Getting swap quote
321
+
322
+ ```typescript
323
+ //Create the swap: swapping _amount of satoshis of Bitcoin on-chain to SOL
324
+ const swap = await swapper.swap(
325
+ Tokens.BITCOIN.BTC, //Swap from BTC
326
+ Tokens.SOLANA.SOL, //Into specified destination token
327
+ "0.0001", //Amount can be either passed in base units as bigint or in decimal format as string
328
+ SwapAmountType.EXACT_IN, //EXACT_IN, so we specify the input amount
329
+ undefined, //Source address for the swap, not used for swaps from BTC
330
+ solanaSigner.getAddress() //Destination address
331
+ );
332
+
333
+ //Get the amount required to pay and fee
334
+ const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
335
+ const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
336
+ const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
337
+
338
+ const output: string = swap.getOutput().toString(); //Total output amount
339
+
340
+ //Get swap expiration time
341
+ const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
342
+
343
+ //Get security deposit amount (Human readable amount of SOL that needs to be put down to rent the liquidity from swap intermediary), you will get this deposit back if the swap succeeds
344
+ const securityDeposit: string = swap.getSecurityDeposit().toString();
345
+ //Get claimer bounty (Human readable amount of SOL reserved as a reward for watchtowers to claim the swap on your behalf)
346
+ const claimerBounty: string = swap.getClaimerBounty().toString();
347
+
348
+ //Get pricing info
349
+ const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
350
+ const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
351
+ const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
352
+ ```
353
+
354
+ Executing the swap (simple)
355
+
356
+ ```typescript
357
+ const automaticSettlementSuccess = await swap.execute(
358
+ solanaSigner,
359
+ { //Bitcoin wallet, you can also pass null/undefined and send the bitcoin transaction from an external wallet
360
+ address: "bc1pscnrk588hdj79mwccucu06007mj5np2jurwfwp5mvhkjldzyphzqyk62m5",
361
+ publicKey: "03a2d8b728935f61d5bcba0cfb09c2c443c483b5c31ebd180e1833f37344bd34ba",
362
+ signPsbt: (psbt: {psbt, psbtHex: string, psbtBase64: string}, signInputs: number[]) => {
363
+ //Sign the PSBT with the bitcoin wallet
364
+ ...
365
+ //Return the signed PSBT in the hex or base64 format!
366
+ return "<signed PSBT>";
367
+ }
368
+ },
369
+ { //Callbacks
370
+ onDestinationCommitSent: (swapAddressOpeningTxId: string) => {
371
+ //Swap address opening transaction sent on the destination chain
372
+ },
373
+ onSourceTransactionSent: (txId: string) => {
374
+ //Bitcoin transaction sent on the source
375
+ },
376
+ onSourceTransactionConfirmationStatus: (txId: string, confirmations: number, targetConfirmations: number, txEtaMs: number) => {
377
+ //Bitcoin transaction confirmation status updates
378
+ },
379
+ onSourceTransactionConfirmed: (txId: string) => {
380
+ //Bitcoin transaction confirmed
381
+ },
382
+ onSwapSettled: (destinationTxId: string) => {
383
+ //Swap settled on the destination
384
+ }
385
+ }
386
+ );
387
+
388
+ //In case the automatic swap settlement fails, we can settle it manually using the wallet of the destination chain
389
+ if(!automaticSettlementSuccess) {
390
+ await swap.claim(solanaSigner);
391
+ }
392
+ ```
393
+
394
+ <details>
395
+ <summary>Manual swap execution (advanced)</summary>
396
+
397
+ - __1.__ Initiate the swap on the destination chain (Solana) by opening up the bitcoin swap address
398
+
399
+ - __a.__ Commit using signer
400
+ ```typescript
401
+ await swap.commit(solanaWallet);
402
+ ```
403
+
404
+ - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
405
+ ```typescript
406
+ const txsCommit = await swap.txsCommit();
407
+ //Sign and send these...
408
+ ...
409
+ //Important to wait till SDK processes the swap initialization
410
+ await swap.waitTillCommited();
411
+ ```
412
+
413
+ - __2.__ Send bitcoin transaction
414
+
415
+ - __a.__ Get funded PSBT and sign it
416
+ ```typescript
417
+ const {psbt, psbtHex, psbtBase64, signInputs} = await swap.getFundedPsbt({
418
+ address: "bc1pscnrk588hdj79mwccucu06007mj5np2jurwfwp5mvhkjldzyphzqyk62m5",
419
+ publicKey: "03a2d8b728935f61d5bcba0cfb09c2c443c483b5c31ebd180e1833f37344bd34ba"
420
+ });
421
+ //Sign the psbt
422
+ const signedPsbt = ...; //Can be hex or base64 encoded
423
+ const bitcoinTxId = await swap.submitPsbt(signedPsbt);
424
+ ```
425
+
426
+ - __b.__ Get the bitcoin address or deeplink and send from external wallet
427
+ ```typescript
428
+ //It is imporant to send the EXACT amount, sending different amount will lead to loss of funds!
429
+ const btcSwapAddress = swap.getAddress();
430
+ const btcDeepLink = swap.getHyperlink();
431
+ ```
432
+
433
+ - __3.__ Wait for the bitcoin on-chain transaction to confirm
434
+ ```typescript
435
+ await swap.waitForBitcoinTransaction(
436
+ (txId, confirmations, targetConfirmations, txEtaMs) => {
437
+ //Bitcoin transaction confirmation status callback
438
+ }
439
+ );
440
+ ```
441
+
442
+ - __4.__ Wait for the automatic settlement of the swap
443
+ ```typescript
444
+ const automaticSettlementSuccess = await swap.waitTillClaimed(30);
445
+ ```
446
+
447
+ - __5.__ In case the automatic swap settlement fails, we can settle it manually using the wallet of the destination chain
448
+
449
+ - __a.__ Claim with a signer
450
+ ```typescript
451
+ if(!automaticSettlementSuccess) {
452
+ await swap.claim(solanaSigner);
453
+ }
454
+ ```
455
+
456
+ - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
457
+ ```typescript
458
+ if(!automaticSettlementSuccess) {}
459
+ const txsClaim = await swap.txsClaim();
460
+ //Sign and send these...
461
+ ...
462
+ //Important to wait till SDK processes the swap initialization
463
+ await swap.waitTillCommited();
464
+ }
465
+ ```
466
+
467
+ </details>
468
+
469
+ <details>
470
+ <summary>Swap states</summary>
471
+
472
+ - FromBTCSwapState.EXPIRED = -3
473
+ - Bitcoin swap address expired
474
+ - FromBTCSwapState.QUOTE_EXPIRED = -2
475
+ - Swap quote expired and cannot be executed anymore
476
+ - FromBTCSwapState.QUOTE_SOFT_EXPIRED = -1
477
+ - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
478
+ - FromBTCSwapState.PR_CREATED = 0
479
+ - Swap quote is created, waiting for the user to open a bitcoin swap address
480
+ - FromBTCSwapState.CLAIM_COMMITED = 1
481
+ - Bitcoin swap address is opened
482
+ - FromBTCSwapState.BTC_TX_CONFIRMED = 2
483
+ - Bitcoin transaction sending funds to the swap address is confirmed
484
+ - FromBTCSwapState.CLAIM_CLAIMED = 3
485
+ - Swap funds are claimed to the user's wallet
486
+
487
+ </details>
488
+
489
+ #### Swap Bitcoin on-chain -> Starknet/EVM
490
+
491
+ NOTE: Starknet & EVM uses a new swap protocol for Bitcoin on-chain -> Smart chain swaps, the flow here is different from the one for Solana!
492
+
493
+ Getting swap quote
494
+
495
+ ```typescript
496
+ //Create the swap: swapping _amount of satoshis of Bitcoin on-chain to SOL
497
+ const swap = await swapper.swap(
498
+ Tokens.BITCOIN.BTC, //Swap from BTC
499
+ Tokens.STARKNET.STRK, //Into specified destination token
500
+ "0.0001", //Amount can be either passed in base units as bigint or in decimal format as string
501
+ SwapAmountType.EXACT_IN, //EXACT_IN, so we specify the input amount
502
+ undefined, //Source address for the swap, not used for swaps from BTC
503
+ starknetSigner.getAddress(), //Destination address
504
+ {
505
+ gasAmount: 1_000_000_000_000_000_000n //We can also request a gas drop on the destination chain (here requesting 1 STRK)
506
+ }
507
+ );
508
+
509
+ //Get the amount required to pay and fee
510
+ const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
511
+ const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
512
+ const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
513
+
514
+ const output: string = swap.getOutput().toString(); //Total output amount
515
+
516
+ //Get swap expiration time
517
+ const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
518
+
519
+ //Get pricing info
520
+ const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
521
+ const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
522
+ const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
523
+ ```
524
+
525
+ Executing the swap (simple)
526
+
527
+ ```typescript
528
+ const automaticSettlementSuccess = await swap.execute(
529
+ { //Bitcoin wallet
530
+ address: "bc1pscnrk588hdj79mwccucu06007mj5np2jurwfwp5mvhkjldzyphzqyk62m5",
531
+ publicKey: "03a2d8b728935f61d5bcba0cfb09c2c443c483b5c31ebd180e1833f37344bd34ba",
532
+ signPsbt: (psbt: {psbt, psbtHex: string, psbtBase64: string}, signInputs: number[]) => {
533
+ //Sign the PSBT with the bitcoin wallet
534
+ ...
535
+ //Return the signed PSBT in the hex or base64 format!
536
+ return "<signed PSBT>";
537
+ }
538
+ },
539
+ { //Callbacks
540
+ onSourceTransactionSent: (txId: string) => {
541
+ //Bitcoin transaction sent on the source
542
+ },
543
+ onSourceTransactionConfirmationStatus: (txId: string, confirmations: number, targetConfirmations: number, txEtaMs: number) => {
544
+ //Bitcoin transaction confirmation status updates
545
+ },
546
+ onSourceTransactionConfirmed: (txId: string) => {
547
+ //Bitcoin transaction confirmed
548
+ },
549
+ onSwapSettled: (destinationTxId: string) => {
550
+ //Swap settled on the destination
551
+ }
552
+ }
553
+ );
554
+
555
+ //In case the automatic swap settlement fails, we can settle it manually using the wallet of the destination chain
556
+ if(!automaticSettlementSuccess) {
557
+ await swap.claim(starknetWallet);
558
+ }
559
+ ```
560
+
561
+
562
+ <details>
563
+ <summary>Manual swap execution (advanced)</summary>
564
+
565
+ - __1.__ Send bitcoin transaction
566
+
567
+ - __a.__ Get funded PSBT and sign it using external wallet (e.g. browser-based like Xverse, Unisat, Phantom, etc.)
568
+ ```typescript
569
+ //Obtain the funded PSBT (input already added) - ready for signing
570
+ const {psbt, psbtHex, psbtBase64, signInputs} = await swap.getFundedPsbt({address: "", publicKey: ""});
571
+ //Pass `psbtBase64` or `psbtHex` (and also `signInputs`) to an external signer like Xverse, Unisat, etc.
572
+ const signedPsbtHexOrBase64 = await <signPsbt function of the external wallet>; //Call the signPsbt function of the external signer with psbtBase64 or psbtHex and signInputs
573
+ //The SDK automatically recognizes hex & base64 encoded PSBTs
574
+ const bitcoinTxId = await swap.submitPsbt(signedPsbtHexOrBase64);
575
+ ```
576
+
577
+ - __b.__ Or obtain raw PSBT to which inputs still need to be added
578
+ ```typescript
579
+ const {psbt, psbtHex, psbtBase64, in1sequence} = await swap.getPsbt();
580
+ psbt.addInput(...);
581
+ //Make sure the second input's sequence (index 1) is as specified in the in1sequence variable
582
+ psbt.updateInput(1, {sequence: in1sequence});
583
+ //Sign the PSBT, sign every input except the first one
584
+ for(let i=1;i<psbt.inputsLength; i++) psbt.signIdx(..., i); //Or pass it to external signer
585
+ //Submit the signed PSBT, can be the Transaction object, or hex/base64 serialized
586
+ const bitcoinTxId = await swap.submitPsbt(psbt);
587
+ ```
588
+
589
+ - __2.__ Wait for the bitcoin on-chain transaction to confirm
590
+ ```typescript
591
+ await swap.waitForBitcoinTransaction(
592
+ (txId, confirmations, targetConfirmations, txEtaMs) => {
593
+ //Bitcoin transaction confirmation status callback
594
+ }
595
+ );
596
+ ```
597
+
598
+ - __3.__ Wait for the automatic settlement of the swap
599
+ ```typescript
600
+ const automaticSettlementSuccess = await swap.waitTillClaimed(60);
601
+ ```
602
+
603
+ - __4.__ In case the automatic swap settlement fails, we can settle it manually using the wallet of the destination chain
604
+
605
+ - __a.__ Claim with a signer
606
+ ```typescript
607
+ if(!automaticSettlementSuccess) {
608
+ await swap.claim(starknetSigner);
609
+ }
610
+ ```
611
+
612
+ - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
613
+ ```typescript
614
+ if(!automaticSettlementSuccess) {}
615
+ const txsClaim = await swap.txsClaim();
616
+ //Sign and send these...
617
+ ...
618
+ //Important to wait till SDK processes the swap initialization
619
+ await swap.waitTillCommited();
620
+ }
621
+ ```
622
+
623
+ </details>
624
+
625
+ <details>
626
+ <summary>Swap states</summary>
627
+
628
+ - SpvFromBTCSwapState.CLOSED = -5
629
+ - Catastrophic failure during swap, shall never happen
630
+ - SpvFromBTCSwapState.FAILED = -4
631
+ - Bitcoin transaction was sent, but was double-spent later, therefore the swap was failed (no BTC was sent)
632
+ - SpvFromBTCSwapState.DECLINED = -3
633
+ - LP declined to process the swap transaction, no BTC was sent
634
+ - SpvFromBTCSwapState.QUOTE_EXPIRED = -2
635
+ - Swap quote expired and cannot be executed anymore
636
+ - SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED = -1
637
+ - Swap quote soft-expired (i.e. the quote probably expired, but if there is a bitcoin transaction being submitted it might still succeed)
638
+ - SpvFromBTCSwapState.CREATED = 0
639
+ - Swap quote is created, waiting on user to sign the bitcoin swap transaction
640
+ - SpvFromBTCSwapState.SIGNED = 1
641
+ - Bitcoin swap transaction was signed by the client
642
+ - SpvFromBTCSwapState.POSTED = 2
643
+ - Bitcoin swap transaction was posted to the LP
644
+ - SpvFromBTCSwapState.BROADCASTED = 3
645
+ - LP broadcasted the bitcoin swap transaction
646
+ - SpvFromBTCSwapState.FRONTED = 4
647
+ - Swap funds have been deposited to the user's wallet in front of the time
648
+ - SpvFromBTCSwapState.BTC_TX_CONFIRMED = 5
649
+ - Bitcoin swap transaction is confirmed
650
+ - SpvFromBTCSwapState.CLAIM_CLAIMED = 6
651
+ - Swap funds are claimed to the user's wallet
652
+ -
653
+ </details>
654
+
655
+ ### Bitcoin lightning network swaps
656
+
657
+ #### Swap Smart chain -> Bitcoin lightning network
658
+
659
+ Getting swap quote
660
+
661
+ ```typescript
662
+ //Create the swap: swapping SOL to Bitcoin lightning
663
+ const swap = await swapper.swap(
664
+ Tokens.SOLANA.SOL, //From specified source token
665
+ Tokens.BITCOIN.BTCLN, //Swap to BTC-LN
666
+ undefined, //Amount is specified in the lightning network invoice!
667
+ SwapAmountType.EXACT_OUT, //Make sure we use EXACT_OUT for swaps to BTC-LN, if you want to use EXACT_IN and set an amount, use LNURL-pay!
668
+ solanaSigner.getAddress(), //Source address and smart chain signer
669
+ //Destination lightning network invoice, amount needs to be part of the invoice!
670
+ "lnbc10u1pj2q0g9pp5ejs6m677m39cznpzum7muruvh50ys93ln82p4j9ks2luqm56xxlshp52r2anlhddfa9ex9vpw9gstxujff8a0p8s3pzvua930js0kwfea6scqzzsxqyz5vqsp5073zskc5qfgp7lre0t6s8uexxxey80ax564hsjklfwfjq2ew0ewq9qyyssqvzmgs6f8mvuwgfa9uqxhtza07qem4yfhn9wwlpskccmuwplsqmh8pdy6c42kqdu8p73kky9lsnl40qha5396d8lpgn90y27ltfc5rfqqq59cya"
671
+ );
672
+
673
+ //Get the amount required to pay and fee
674
+ const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
675
+ const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
676
+ const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
677
+
678
+ const output: string = swap.getOutput().toString(); //Total output amount
679
+
680
+ //Get swap expiration time
681
+ const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
682
+
683
+ //Get pricing info
684
+ const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
685
+ const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
686
+ const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
687
+ ```
688
+
689
+ Executing the swap (simple)
690
+
691
+ ```typescript
692
+ const swapSuccessful = await swap.execute(
693
+ solanaSigner,
694
+ { //Callbacks
695
+ onSourceTransactionSent: (txId: string) => {
696
+ //Transaction on the source chain was sent
697
+ },
698
+ onSourceTransactionConfirmed: (txId: string) => {
699
+ //Transaction on the source chain was confirmed
700
+ },
701
+ onSwapSettled: (destinationTxId: string) => {
702
+ //Lightning payment on the destination chain was sent and swap settled
703
+ }
704
+ }
705
+ );
706
+
707
+ //Refund in case of failure
708
+ if(!swapSuccessful) {
709
+ //Swap failed, money can be refunded
710
+ await swap.refund(solanaSigner);
711
+ } else {
712
+ //Swap successful!
713
+ }
714
+ ```
715
+
716
+ <details>
717
+ <summary>Manual swap execution (advanced)</summary>
718
+
719
+ - __1.__ Initiate the swap on the smart-chain side
720
+
721
+ - __a.__ Commit with a signer
722
+ ```typescript
723
+ await swap.commit(solanaSigner);
724
+ ```
725
+
726
+ - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
727
+ ```typescript
728
+ const txsCommit = await swap.txsCommit();
729
+ //Sign and send these...
730
+ ...
731
+ //Important to wait till SDK processes the swap initialization
732
+ await swap.waitTillCommited();
733
+ ```
734
+
735
+ - __2.__ Wait for the swap to execute and for the payment to be sent
736
+ ```typescript
737
+ const swapSuccessful = await swap.waitForPayment();
738
+ ```
739
+
740
+ - __3.__ In case the swap fails we can refund our funds on the source chain
741
+
742
+ - __a.__ Refund with a signer
743
+ ```typescript
744
+ if(!swapSuccessful) {
745
+ await swap.refund(solanaSigner);
746
+ return;
747
+ }
748
+ ```
749
+
750
+ - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
751
+ ```typescript
752
+ if(!swapSuccessful) {
753
+ const txsRefund = await swap.txsRefund();
754
+ //Sign and send these...
755
+ ...
756
+ }
757
+ ```
758
+
759
+ </details>
760
+
761
+ <details>
762
+ <summary>Swap states</summary>
763
+
764
+ - ToBTCSwapState.REFUNDED = -3
765
+ - Swap failed and was successfully refunded
766
+ - ToBTCSwapState.QUOTE_EXPIRED = -2
767
+ - Swap quote expired and cannot be executed anymore
768
+ - ToBTCSwapState.QUOTE_SOFT_EXPIRED = -1
769
+ - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
770
+ - ToBTCSwapState.CREATED = 0
771
+ - Swap quote is created, waiting to be executed
772
+ - ToBTCSwapState.COMMITED = 1,
773
+ - Swap was initiated (init transaction sent)
774
+ - ToBTCSwapState.SOFT_CLAIMED = 2,
775
+ - Swap was processed by the counterparty but not yet claimed on-chain (lightning network payment secret was revealed)
776
+ - ToBTCSwapState.CLAIMED = 3
777
+ - Swap was finished and funds were successfully claimed by the counterparty
778
+ - ToBTCSwapState.REFUNDABLE = 4
779
+ - Swap was initiated but counterparty failed to process it, the user can now refund his funds
780
+
781
+ </details>
782
+
783
+ #### Swap Bitcoin lightning network -> Solana
784
+
785
+ NOTE: Solana uses an old swap protocol for Bitcoin lightning network -> Solana swaps, the flow here is different from the one for Starknet and other chains.
786
+
787
+ Getting swap quote
788
+
789
+ ```typescript
790
+ const swap = await swapper.swap(
791
+ Tokens.BITCOIN.BTCLN, //Swap from BTC-LN
792
+ Tokens.SOLANA.SOL, //Into specified destination token
793
+ 10000n, //Amount can be either passed in base units as bigint or in decimal format as string
794
+ SwapAmountType.EXACT_IN, //SwapAmountType.EXACT_IN, so we specify the input amount
795
+ undefined, //Source address for the swap, not used for swaps from BTC-LN
796
+ signer.getAddress() //Destination address
797
+ );
798
+
799
+ //Get the bitcoin lightning network invoice (the invoice contains pre-entered amount)
800
+ const receivingLightningInvoice: string = swap.getAddress();
801
+ //Get the URI hyperlink (contains the lightning network invoice) which can be displayed also as QR code
802
+ const qrCodeData: string = swap.getHyperlink();
803
+
804
+ //Get the amount required to pay and fee
805
+ const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
806
+ const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
807
+ const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
808
+
809
+ const output: string = swap.getOutput().toString(); //Total output amount
810
+
811
+ //Get swap expiration time
812
+ const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
813
+
814
+ //Get security deposit amount (Human readable amount of STRK that needs to be put down to rent the liquidity from swap intermediary), you will get this deposit back if the swap succeeds
815
+ const securityDeposit: string = swap.getSecurityDeposit().toString();
816
+
817
+ //Get pricing info
818
+ const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
819
+ const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
820
+ const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
821
+ ```
822
+
823
+ Executing the swap (simple)
824
+
825
+ ```typescript
826
+ await swap.execute(
827
+ solanaSigner,
828
+ { //Lightning network wallet, you can also pass null/undefined and pay the LN invoice from an external wallet
829
+ payInvoice: (bolt11PaymentRequest: string) => {
830
+ //Here you would usually call the WebLN or NWC to execute the payment, it's completely fine if the
831
+ // promise here would block till the payment is settled
832
+ return Promise.resolve("");
833
+ }
834
+ },
835
+ { //Callbacks
836
+ onSourceTransactionReceived: (sourceLnPaymentHash: string) => {
837
+ //Lightning network payment received by the LP
838
+ },
839
+ onDestinationCommitSent: (destinationCommitTxId: string) => {
840
+ //HTLC initialization transaction sent on the destination chain
841
+ },
842
+ onDestinationClaimSent: (destinationClaimTxId: string) => {
843
+ //HTLC claim transaction sent on the destination chain
844
+ },
845
+ onSwapSettled: (destinationClaimTxId: string) => {
846
+ //Swap settled and funds received on destination
847
+ }
848
+ }
849
+ );
850
+ ```
851
+
852
+ <details>
853
+ <summary>Manual swap execution (advanced)</summary>
854
+
855
+ - __1.__ Pay the LN invoice from a lightning network wallet
856
+ ```typescript
857
+ const lightningInvoice = swap.getAddress();
858
+ ```
859
+
860
+ - __2.__ Start listening to incoming lightning network payment
861
+ ```typescript
862
+ const success = await swap.waitForPayment();
863
+ if(!success) {
864
+ //Lightning network payment not received in time and quote expired
865
+ return;
866
+ }
867
+ ```
868
+
869
+ - __3.__ Claim the swap at the destination
870
+
871
+ - __a.__ Commit & claim with signer
872
+ ```typescript
873
+ await swap.commitAndClaim(solanaSigner);
874
+ ```
875
+
876
+ - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
877
+ ```typescript
878
+ const txsCommitAndClaim = await swap.txsCommitAndClaim();
879
+ //Take EXTRA care to make sure transaction are sent sequentially and in order - always wait
880
+ // for prior transaction confirmation before sending the next one
881
+ //Sign and send these...
882
+ ...
883
+ ```
884
+
885
+ </details>
886
+
887
+ <details>
888
+ <summary>Swap states</summary>
889
+
890
+ - FromBTCLNSwapState.FAILED = -4
891
+ - If the claiming of the funds was initiated, but never concluded, the user will get his lightning network payment refunded
892
+ - FromBTCLNSwapState.QUOTE_EXPIRED = -3
893
+ - Swap quote expired and cannot be executed anymore
894
+ - FromBTCLNSwapState.QUOTE_SOFT_EXPIRED = -2
895
+ - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
896
+ - FromBTCLNSwapState.EXPIRED = -1
897
+ - Lightning network invoice expired, meaning the swap is expired
898
+ - FromBTCLNSwapState.PR_CREATED = 0
899
+ - Swap is created, the user should now pay the provided lightning network invoice
900
+ - FromBTCLNSwapState.PR_PAID = 1
901
+ - Lightning network invoice payment was received (but cannot be settled by the counterparty yet)
902
+ - FromBTCLNSwapState.CLAIM_COMMITED = 2
903
+ - Claiming of the funds was initiated
904
+ - FromBTCLNSwapState.CLAIM_CLAIMED = 3
905
+ - Funds were successfully claimed & lightning network secret pre-image revealed, so the lightning network payment will settle now
906
+
907
+ </details>
908
+
909
+ #### Swap Bitcoin lightning network -> Starknet/EVM
910
+
911
+ Getting swap quote
912
+
913
+ ```typescript
914
+ const swap = await swapper.swap(
915
+ Tokens.BITCOIN.BTCLN, //Swap from BTC-LN
916
+ Tokens.STARKNET.STRK, //Into specified destination token
917
+ 10000n, //Amount can be either passed in base units as bigint or in decimal format as string
918
+ SwapAmountType.EXACT_IN, //SwapAmountType.EXACT_IN, so we specify the input amount
919
+ undefined, //Source address for the swap, not used for swaps from BTC-LN
920
+ signer.getAddress(), //Destination address
921
+ {
922
+ gasAmount: 1_000_000_000_000_000_000n //We can also request a gas drop on the destination chain (here requesting 1 STRK)
923
+ }
924
+ );
925
+
926
+ //Get the bitcoin lightning network invoice (the invoice contains pre-entered amount)
927
+ const receivingLightningInvoice: string = swap.getAddress();
928
+ //Get the URI hyperlink (contains the lightning network invoice) which can be displayed also as QR code
929
+ const qrCodeData: string = swap.getHyperlink();
930
+
931
+ //Get the amount required to pay and fee
932
+ const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
933
+ const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
934
+ const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
935
+
936
+ const output: string = swap.getOutput().toString(); //Total output amount
937
+
938
+ //Get swap expiration time
939
+ const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
940
+
941
+ //Get pricing info
942
+ const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
943
+ const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
944
+ const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
945
+ ```
946
+
947
+ Executing the swap (simple)
948
+
949
+ ```typescript
950
+ const automaticSettlementSuccess = await swap.execute(
951
+ { //Lightning network wallet, you can also pass null/undefined and pay the LN invoice from an external wallet
952
+ payInvoice: (bolt11PaymentRequest: string) => {
953
+ //Here you would usually call the WebLN or NWC to execute the payment, it's completely fine if the
954
+ // promise here would block till the payment is settled
955
+ return Promise.resolve("");
956
+ }
957
+ },
958
+ { //Callbacks
959
+ onSourceTransactionReceived: (sourceLnPaymentHash: string) => {
960
+ //Lightning network payment received by the LP
961
+ },
962
+ onSwapSettled: (destinationClaimTxId: string) => {
963
+ //Swap settled and funds received on destination
964
+ }
965
+ }
966
+ );
967
+
968
+ //In case the automatic swap settlement fails, we can settle it manually using the wallet of the destination chain
969
+ if(!automaticSettlementSuccess) {
970
+ await swap.claim(starknetSigner);
971
+ }
972
+ ```
973
+
974
+
975
+ <details>
976
+ <summary>Manual swap execution (advanced)</summary>
977
+
978
+ - __1.__ Pay the LN invoice from a lightning network wallet
979
+ ```typescript
980
+ const lightningInvoice = swap.getAddress();
981
+ ```
982
+
983
+ - __2.__ Start listening to incoming lightning network payment
984
+ ```typescript
985
+ const success = await swap.waitForPayment();
986
+ if(!success) {
987
+ //Lightning network payment not received in time and quote expired
988
+ return;
989
+ }
990
+ ```
991
+
992
+ - __3.__ Wait for the swap to be automatically settled
993
+ ```typescript
994
+ const automaticSettlementSuccess = await swap.waitTillClaimed(60);
995
+ ```
996
+
997
+ - __4.__ In case the automatic swap settlement fails, we can settle it manually using the wallet of the destination chain
998
+
999
+ - __a.__ Claim with signer
1000
+ ```typescript
1001
+ if(!automaticSettlementSuccess) {
1002
+ await swap.claim(starknetSigner);
1003
+ }
1004
+ ```
1005
+
1006
+ - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
1007
+ ```typescript
1008
+ if(!automaticSettlementSuccess) {
1009
+ const txsClaim = await swap.txsClaim();
1010
+ //Sign and send these...
1011
+ ...
1012
+ }
1013
+ ```
1014
+
1015
+ </details>
1016
+
1017
+ <details>
1018
+ <summary>Swap states</summary>
1019
+
1020
+ - FromBTCLNAutoSwapState.FAILED = -4
1021
+ - If the claiming of the funds was initiated, but never concluded, the user will get his lightning network payment refunded
1022
+ - FromBTCLNAutoSwapState.QUOTE_EXPIRED = -3
1023
+ - Swap quote expired and cannot be executed anymore
1024
+ - FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED = -2
1025
+ - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
1026
+ - FromBTCLNAutoSwapState.EXPIRED = -1
1027
+ - Lightning network invoice expired, meaning the swap is expired
1028
+ - FromBTCLNAutoSwapState.PR_CREATED = 0
1029
+ - Swap is created, the user should now pay the provided lightning network invoice
1030
+ - FromBTCLNAutoSwapState.PR_PAID = 1
1031
+ - Lightning network invoice payment was received (but cannot be settled by the counterparty yet)
1032
+ - FromBTCLNAutoSwapState.CLAIM_COMMITED = 2
1033
+ - A swap HTLC was offered by the LP to the user
1034
+ - FromBTCLNAutoSwapState.CLAIM_CLAIMED = 3
1035
+ - Funds were successfully claimed & lightning network secret pre-image revealed, so the lightning network payment will settle now
1036
+
1037
+ </details>
1038
+
1039
+ ### LNURLs & readable lightning identifiers
1040
+
1041
+ LNURLs extend the lightning network functionality by creating static lightning addreses (LNURL-pay & static internet identifiers) and QR codes which allow you to pull funds from them (LNURL-withdraw)
1042
+
1043
+ This SDK supports:
1044
+ * LNURL-pay ([LUD-6](https://github.com/lnurl/luds/blob/luds/06.md), [LUD-9](https://github.com/lnurl/luds/blob/luds/09.md), [LUD-10](https://github.com/lnurl/luds/blob/luds/10.md), [LUD-12](https://github.com/lnurl/luds/blob/luds/12.md))
1045
+ * LNURL-withdraw ([LUD-3](https://github.com/lnurl/luds/blob/luds/03.md))
1046
+ * Static internet identifiers ([LUD-16](https://github.com/lnurl/luds/blob/luds/16.md))
1047
+
1048
+ You can parse LNURLs and lightning invoices automatically using the [Unified address parser](#unified-address-parser)
1049
+
1050
+ #### Differences
1051
+
1052
+ Lightning invoices:
1053
+ * One time use only
1054
+ * Need to have a fixed amount, therefore recipient has to set the amount
1055
+ * Static and bounded expiration
1056
+ * You can only pay to a lightning invoice, not withdraw funds from it
1057
+
1058
+ LNURLs & lightning identifiers:
1059
+ * Reusable
1060
+ * Programmable expiry
1061
+ * Allows payer to set an amount
1062
+ * Supports both, paying (LNURL-pay) and withdrawing (LNURL-withdraw)
1063
+ * Possibility to attach a message/comment to a payment
1064
+ * Receive a message/url as a result of the payment
1065
+
1066
+ #### Swap Smart chain -> Bitcoin lightning network
1067
+
1068
+ Getting swap quote
1069
+
1070
+ ```typescript
1071
+ //Create the swap: swapping SOL to Bitcoin lightning
1072
+ const swap = await swapper.swap(
1073
+ Tokens.SOLANA.SOL, //From specified source token
1074
+ Tokens.BITCOIN.BTCLN, //Swap to BTC-LN
1075
+ 10000n, //Now we can specify an amount for a lightning network payment!
1076
+ SwapAmountType.EXACT_OUT, //We can also use exactIn=true here and set an amount in input token
1077
+ solanaSigner.getAddress(), //Source address and smart chain signer
1078
+ //Destination LNURL-pay or readable identifier
1079
+ "lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkx6rfvdjx2ctvxyesuk0a27",
1080
+ {
1081
+ comment: "Hello world" //For LNURL-pay we can also pass a comment to the recipient
1082
+ }
1083
+ );
1084
+
1085
+ //Get the amount required to pay and fee
1086
+ const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
1087
+ const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
1088
+ const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
1089
+
1090
+ const output: string = swap.getOutput().toString(); //Total output amount
1091
+
1092
+ //Get swap expiration time
1093
+ const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
1094
+
1095
+ //Get pricing info
1096
+ const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
1097
+ const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
1098
+ const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
1099
+ ```
1100
+
1101
+
1102
+ Executing the swap (simple)
1103
+
1104
+ ```typescript
1105
+ const swapSuccessful = await swap.execute(
1106
+ solanaSigner,
1107
+ { //Callbacks
1108
+ onSourceTransactionSent: (txId: string) => {
1109
+ //Transaction on the source chain was sent
1110
+ },
1111
+ onSourceTransactionConfirmed: (txId: string) => {
1112
+ //Transaction on the source chain was confirmed
1113
+ },
1114
+ onSwapSettled: (destinationTxId: string) => {
1115
+ //Lightning payment on the destination chain was sent and swap settled
1116
+ }
1117
+ }
1118
+ );
1119
+
1120
+ //Refund in case of failure
1121
+ if(!swapSuccessful) {
1122
+ //Swap failed, money can be refunded
1123
+ await swap.refund(solanaSigner);
1124
+ return;
1125
+ }
1126
+
1127
+ //Swap successful!
1128
+ const lightningSecret = swap.getSecret();
1129
+ //In case the LNURL contained a success action, we can read it now and display it to user
1130
+ if(swap.hasSuccessAction()) {
1131
+ //Contains a success action that should displayed to the user
1132
+ const successMessage = swap.getSuccessAction();
1133
+ const description: string = successMessage.description; //Description of the message
1134
+ const text: (string | null) = successMessage.text; //Main text of the message
1135
+ const url: (string | null) = successMessage.url; //URL link which should be displayed
1136
+ }
1137
+ ```
1138
+
1139
+ <details>
1140
+ <summary>Manual swap execution (advanced)</summary>
1141
+
1142
+ - __1.__ Initiate the swap on the smart-chain side
1143
+
1144
+ - __a.__ Commit with a signer
1145
+ ```typescript
1146
+ await swap.commit(solanaSigner);
1147
+ ```
1148
+
1149
+ - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
1150
+ ```typescript
1151
+ const txsCommit = await swap.txsCommit();
1152
+ //Sign and send these...
1153
+ ...
1154
+ //Important to wait till SDK processes the swap initialization
1155
+ await swap.waitTillCommited();
1156
+ ```
1157
+
1158
+ - __2.__ Wait for the swap to execute and for the payment to be sent
1159
+
1160
+ ```typescript
1161
+ const swapSuccessful = await swap.waitForPayment();
1162
+ ```
1163
+
1164
+ - __3.__ In case the swap fails we can refund our funds on the source chain
1165
+
1166
+ - __a.__ Refund with a signer
1167
+ ```typescript
1168
+ if(!swapSuccessful) {
1169
+ await swap.refund(solanaSigner);
1170
+ return;
1171
+ }
1172
+ ```
1173
+
1174
+ - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
1175
+ ```typescript
1176
+ if(!swapSuccessful) {
1177
+ const txsRefund = await swap.txsRefund();
1178
+ //Sign and send these...
1179
+ ...
1180
+ }
1181
+ ```
1182
+
1183
+ </details>
1184
+
1185
+ #### Swap Bitcoin lightning network -> Solana
1186
+
1187
+ NOTE: Solana uses an old swap protocol for Bitcoin lightning network -> Solana swaps, the flow here is different from the one for Starknet and other chains.
1188
+
1189
+ Getting swap quote
1190
+
1191
+ ```typescript
1192
+ const swap = await swapper.swap(
1193
+ Tokens.BITCOIN.BTCLN, //Swap from BTC-LN
1194
+ Tokens.SOLANA.SOL, //Into specified destination token
1195
+ 10000n,
1196
+ SwapAmountType.EXACT_IN, //EXACT_IN, so we specify the input amount
1197
+ //Source LNURL-withdraw link
1198
+ "lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkx6rfvdjx2ctvxyesuk0a27",
1199
+ signer.getAddress(), //Destination address
1200
+ );
1201
+
1202
+ //Get the amount required to pay and fee
1203
+ const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
1204
+ const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
1205
+ const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
1206
+
1207
+ const output: string = swap.getOutput().toString(); //Total output amount
1208
+
1209
+ //Get swap expiration time
1210
+ const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
1211
+
1212
+ //Get security deposit amount (Human readable amount of STRK that needs to be put down to rent the liquidity from swap intermediary), you will get this deposit back if the swap succeeds
1213
+ const securityDeposit: string = swap.getSecurityDeposit().toString();
1214
+
1215
+ //Get pricing info
1216
+ const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
1217
+ const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
1218
+ const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
1219
+ ```
1220
+
1221
+ Executing the swap (simple)
1222
+
1223
+ ```typescript
1224
+ await swap.execute(
1225
+ solanaSigner,
1226
+ undefined, //No need to specify a wallet, we are sourcing the fund from LNURL-withdraw link
1227
+ { //Callbacks
1228
+ onSourceTransactionReceived: (sourceLnPaymentHash: string) => {
1229
+ //Lightning network payment received by the LP
1230
+ },
1231
+ onDestinationCommitSent: (destinationCommitTxId: string) => {
1232
+ //HTLC initialization transaction sent on the destination chain
1233
+ },
1234
+ onDestinationClaimSent: (destinationClaimTxId: string) => {
1235
+ //HTLC claim transaction sent on the destination chain
1236
+ },
1237
+ onSwapSettled: (destinationClaimTxId: string) => {
1238
+ //Swap settled and funds received on destination
1239
+ }
1240
+ }
1241
+ );
1242
+ ```
1243
+
1244
+ <details>
1245
+ <summary>Manual swap execution (advanced)</summary>
1246
+
1247
+ - __1.__ Start listening to incoming lightning network payment (this also requests the payment from LNURL-withdraw service)
1248
+ ```typescript
1249
+ const success = await swap.waitForPayment();
1250
+ if(!success) {
1251
+ //Lightning network payment not received in time and quote expired
1252
+ return;
1253
+ }
1254
+ ```
1255
+
1256
+ - __2.__ Claim the swap at the destination
1257
+
1258
+ - __a.__ Commit & claim with signer
1259
+ ```typescript
1260
+ await swap.commitAndClaim(solanaSigner);
1261
+ ```
1262
+
1263
+ - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
1264
+ ```typescript
1265
+ const txsCommitAndClaim = await swap.txsCommitAndClaim();
1266
+ //Take EXTRA care to make sure transaction are sent sequentially and in order - always wait
1267
+ // for prior transaction confirmation before sending the next one
1268
+ //Sign and send these...
1269
+ ...
1270
+ ```
1271
+
1272
+ </details>
1273
+
1274
+ #### Swap Bitcoin lightning network -> Starknet/EVM
1275
+
1276
+ Getting swap quote
1277
+
1278
+ ```typescript
1279
+ const swap = await swapper.swap(
1280
+ Tokens.BITCOIN.BTCLN, //Swap from BTC-LN
1281
+ Tokens.STARKNET.STRK, //Into specified destination token
1282
+ 10000n,
1283
+ SwapAmountType.EXACT_IN, //EXACT_IN, so we specify the input amount
1284
+ //Source LNURL-withdraw link
1285
+ "lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkx6rfvdjx2ctvxyesuk0a27",
1286
+ signer.getAddress(), //Destination address
1287
+ {
1288
+ gasAmount: 1_000_000_000_000_000_000n //We can also request a gas drop on the destination chain (here requesting 1 STRK)
1289
+ }
1290
+ );
1291
+
1292
+ //Get the amount required to pay and fee
1293
+ const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
1294
+ const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
1295
+ const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
1296
+
1297
+ const output: string = swap.getOutput().toString(); //Total output amount
1298
+
1299
+ //Get swap expiration time
1300
+ const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
1301
+
1302
+ //Get pricing info
1303
+ const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
1304
+ const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
1305
+ const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
1306
+ ```
1307
+
1308
+
1309
+ Executing the swap (simple)
1310
+
1311
+ ```typescript
1312
+ const automaticSettlementSuccess = await swap.execute(
1313
+ undefined, //No need to specify a wallet, we are sourcing the funds from LNURL-withdraw link
1314
+ { //Callbacks
1315
+ onSourceTransactionReceived: (sourceLnPaymentHash: string) => {
1316
+ //Lightning network payment received by the LP
1317
+ },
1318
+ onSwapSettled: (destinationClaimTxId: string) => {
1319
+ //Swap settled and funds received on destination
1320
+ }
1321
+ }
1322
+ );
1323
+
1324
+ //In case the automatic swap settlement fails, we can settle it manually using the wallet of the destination chain
1325
+ if(!automaticSettlementSuccess) {
1326
+ await swap.claim(starknetSigner);
1327
+ }
1328
+ ```
1329
+
1330
+
1331
+ <details>
1332
+ <summary>Manual swap execution (advanced)</summary>
1333
+
1334
+ - __1.__ Start listening to incoming lightning network payment (this also requests the payment from LNURL-withdraw service)
1335
+ ```typescript
1336
+ const success = await swap.waitForPayment();
1337
+ if(!success) {
1338
+ //Lightning network payment not received in time and quote expired
1339
+ return;
1340
+ }
1341
+ ```
1342
+
1343
+ - __2.__ Wait for the swap to be automatically settled
1344
+ ```typescript
1345
+ const automaticSettlementSuccess = await swap.waitTillClaimed(60);
1346
+ ```
1347
+
1348
+ - __3.__ In case the automatic swap settlement fails, we can settle it manually using the wallet of the destination chain
1349
+
1350
+ - __a.__ Claim with signer
1351
+ ```typescript
1352
+ if(!automaticSettlementSuccess) {
1353
+ await swap.claim(starknetSigner);
1354
+ }
1355
+ ```
1356
+
1357
+ - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
1358
+ ```typescript
1359
+ if(!automaticSettlementSuccess) {
1360
+ const txsClaim = await swap.txsClaim();
1361
+ //Sign and send these...
1362
+ ...
1363
+ }
1364
+ ```
1365
+
1366
+ </details>
1367
+
1368
+ ### Exact-In Smart Chain - Lightning swaps
1369
+
1370
+ The main limitation of regular lightning network swaps (Smart chains -> Lightning), is the fact that exactIn swaps are not possible (as invoices need to have a fixed amount). LNURL-pay links solve this issue, but are not supported by all the wallets. Therefore, the SDK exposes a hook/callback that can be implemented by lightning wallets directly, which request fixed amount invoices on-demand. This then makes exact input amount swaps possible. The way it works:
1371
+
1372
+ 1. SDK sends a request to the LP saying it wants to swap `x` USDC to BTC, with a dummy invoice (either 1 sat or as specified in the `minMsats` parameter - this is requested from the `getInvoice()` function) - this dummy invoice is used to estimate the routing fees by the LP (extra care must be taken for both invoices, dummy and the real one to have the same destination node public key & routing hints).
1373
+ 2. LP responds with the output amount of `y` BTC
1374
+ 3. SDK calls the provided `getInvoice()` callback to request the real invoice for the `y` amount of BTC (in satoshis)
1375
+ 4. SDK forwards the returned fixed amount (`y` BTC) lightning network invoice back to the LP to finish creating the quote
1376
+
1377
+ Getting swap quote
1378
+
1379
+ ```typescript
1380
+ //Create the swap: swapping SOL to Bitcoin lightning
1381
+ const swap = await swapper.swap(
1382
+ Tokens.SOLANA.SOL, //From specified source token
1383
+ Tokens.BITCOIN.BTCLN, //Swap to BTC-LN
1384
+ 1_000_000_000n, //We can specify an amount for a lightning network payment!
1385
+ SwapAmountType.EXACT_IN, //We can use exactIn=true here and set an amount in input token
1386
+ solanaSigner.getAddress(), //Source address and smart chain signer
1387
+ //Instead of the destination we pass a handler object
1388
+ {
1389
+ getInvoice: async (amountSats: number, abortSignal?: AbortSignal) => {
1390
+ //Generate invoice with fixed amountSats here!
1391
+ ...
1392
+ return invoice;
1393
+ },
1394
+ //Optionally you can also specify minimum and maximum in msats (millisatoshis, 1 sat = 1000 msats)
1395
+ minMsats: 1_000_000n,
1396
+ maxMsats: 1_000_000_000n
1397
+ },
1398
+ {
1399
+ comment: "Hello world" //For LNURL-pay we can also pass a comment to the recipient
1400
+ }
1401
+ );
1402
+
1403
+ //Get the amount required to pay and fee
1404
+ const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
1405
+ const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
1406
+ const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
1407
+
1408
+ const output: string = swap.getOutput().toString(); //Total output amount
1409
+
1410
+ //Get swap expiration time
1411
+ const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
1412
+
1413
+ //Get pricing info
1414
+ const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
1415
+ const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
1416
+ const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
1417
+ ```
1418
+
1419
+
1420
+ Executing the swap (simple)
1421
+
1422
+ ```typescript
1423
+ const swapSuccessful = await swap.execute(
1424
+ solanaSigner,
1425
+ { //Callbacks
1426
+ onSourceTransactionSent: (txId: string) => {
1427
+ //Transaction on the source chain was sent
1428
+ },
1429
+ onSourceTransactionConfirmed: (txId: string) => {
1430
+ //Transaction on the source chain was confirmed
1431
+ },
1432
+ onSwapSettled: (destinationTxId: string) => {
1433
+ //Lightning payment on the destination chain was sent and swap settled
1434
+ }
1435
+ }
1436
+ );
1437
+
1438
+ //Refund in case of failure
1439
+ if(!swapSuccessful) {
1440
+ //Swap failed, money can be refunded
1441
+ await swap.refund(solanaSigner);
1442
+ return;
1443
+ }
1444
+
1445
+ //Swap successful!
1446
+ const lightningSecret = swap.getSecret();
1447
+ ```
1448
+
1449
+ <details>
1450
+ <summary>Manual swap execution (advanced)</summary>
1451
+
1452
+ - __1.__ Initiate the swap on the smart-chain side
1453
+
1454
+ - __a.__ Commit with a signer
1455
+ ```typescript
1456
+ await swap.commit(solanaSigner);
1457
+ ```
1458
+
1459
+ - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
1460
+ ```typescript
1461
+ const txsCommit = await swap.txsCommit();
1462
+ //Sign and send these...
1463
+ ...
1464
+ //Important to wait till SDK processes the swap initialization
1465
+ await swap.waitTillCommited();
1466
+ ```
1467
+
1468
+ - __2.__ Wait for the swap to execute and for the payment to be sent
1469
+
1470
+ ```typescript
1471
+ const swapSuccessful = await swap.waitForPayment();
1472
+ ```
1473
+
1474
+ - __3.__ In case the swap fails we can refund our funds on the source chain
1475
+
1476
+ - __a.__ Refund with a signer
1477
+ ```typescript
1478
+ if(!swapSuccessful) {
1479
+ await swap.refund(solanaSigner);
1480
+ return;
1481
+ }
1482
+ ```
1483
+
1484
+ - __b.__ Or get the transactions & [sign and send transaction manually](#manually-signing-smart-chain-transactions)
1485
+ ```typescript
1486
+ if(!swapSuccessful) {
1487
+ const txsRefund = await swap.txsRefund();
1488
+ //Sign and send these...
1489
+ ...
1490
+ }
1491
+ ```
1492
+
1493
+ </details>
1494
+
1495
+ ### Getting state of the swap
1496
+
1497
+ You can get the current state of the swap with:
1498
+
1499
+ ```typescript
1500
+ const state = swap.getState();
1501
+ ```
1502
+
1503
+ You can also set a listener to listen for swap state changes:
1504
+
1505
+ ```typescript
1506
+ swap.events.on("swapState", swap => {
1507
+ const newState = swap.getState();
1508
+ });
1509
+ ```
1510
+
1511
+ For the meaning of the states please refer to the "Swap state" section under each swap type.
1512
+
1513
+ ### Swap size limits
1514
+
1515
+ Swap sizes are limited by the LPs you are connected to, they are advertised in BTC terms by LPs during handshake
1516
+
1517
+ ```typescript
1518
+ const swapLimits = swapper.getSwapLimits(srcToken, dstToken);
1519
+ const inputMin = swapLimits.input.min;
1520
+ const inputMax = swapLimits.input.max;
1521
+ const outputMin = swapLimits.output.min;
1522
+ const outputMax = swapLimits.output.max;
1523
+ ```
1524
+
1525
+ NOTE: swap limits denominated in BTC are retrieved from the LPs during initial handshake, however limits in other tokens are only returned when getting a quote fails due to amount being too low or too high. For example if you want to get swap limits for the BTC -> SOL swap, the input limits will be immediately available, while the output limits will only get populated once a quote request fails due to amount being too low or high.
1526
+
1527
+ ```typescript
1528
+ let swapLimits = swapper.getSwapLimits(Tokens.BITCOIN.BTC, Tokens.SOLANA.SOL);
1529
+ let inputMin = swapLimits.input.min; //Immediately available
1530
+ let inputMax = swapLimits.input.max; //Immediately available
1531
+ let outputMin = swapLimits.output.min; //Not available from the get-go
1532
+ let outputMax = swapLimits.output.max; //Not available from the get-go
1533
+
1534
+ //You can also listen to swap limit changes (optional)
1535
+ swapper.on("swapLimitsChanged", () => {
1536
+ //New limits available with swapper.getSwapLimits(srcToken, dstToken)
1537
+ //Useful in e.g. a react application where you want to dynamically set min/max swappable amount
1538
+ })
1539
+
1540
+ //Try to swap really small amount of SOL with exactOut swap
1541
+ try {
1542
+ const swap = await swapper.swap(
1543
+ Tokens.BITCOIN.BTC, //Swap from BTC
1544
+ Tokens.SOLANA.SOL, //Into specified destination token
1545
+ 1n, //1 lamport = 0.000000001 SOL
1546
+ false, //Whether we define an input or output amount
1547
+ undefined, //Source address for the swap, not used for swaps from BTC
1548
+ solanaSigner.getAddress() //Destination address
1549
+ );
1550
+ } catch (e) {
1551
+ //Fails with OutOfBoundsError
1552
+ }
1553
+
1554
+ swapLimits = swapper.getSwapLimits(Tokens.BITCOIN.BTC, Tokens.SOLANA.SOL);
1555
+ inputMin = swapLimits.input.min; //Immediately available
1556
+ inputMax = swapLimits.input.max; //Immediately available
1557
+ outputMin = swapLimits.output.min; //Now available due to failed quote
1558
+ outputMax = swapLimits.output.max; //Now available due to failed quote
1559
+ ```
1560
+
1561
+ ### Stored swaps
1562
+
1563
+ #### Get swap by ID
1564
+
1565
+ You can retrieve a swap by it's id, you can get an ID of the swap with
1566
+
1567
+ ```typescript
1568
+ const swapId = swap.getId();
1569
+ ```
1570
+
1571
+ And then later retrieve it from the storage
1572
+
1573
+ ```typescript
1574
+ const swap = await swapper.getSwapById(id);
1575
+ ```
1576
+
1577
+ #### Get refundable swaps
1578
+ You can refund the swaps in one of two cases:
1579
+ * In case intermediary is non-cooperative and goes offline, you can claim the funds from the swap contract back after some time.
1580
+ * In case intermediary tried to pay but was unsuccessful, so he sent you signed message with which you can refund now without waiting.
1581
+
1582
+ This call can be checked on every startup and periodically every few minutes.
1583
+ ```typescript
1584
+ //Get refundable swaps and refund them
1585
+ const refundableSolanaSwaps = await swapper.getRefundableSwaps("SOLANA", solanaSigner.getAddress());
1586
+ for(let swap of refundableSolanaSwaps) await swap.refund(solanaSigner);
1587
+ const refundableStarknetSwaps = await swapper.getRefundableSwaps("STARKNET", starknetSigner.getAddress());
1588
+ for(let swap of refundableStarknetSwaps) await swap.refund(starknetSigner);
1589
+ ```
1590
+
1591
+ #### Get claimable swaps
1592
+ Returns swaps that are ready to be claimed by the client, this can happen if client closes the application when a swap is in-progress and the swap is concluded while the client is offline.
1593
+
1594
+ ```typescript
1595
+ //Get the swaps
1596
+ const claimableSolanaSwaps = await solanaSwapper.getClaimableSwaps("SOLANA", solanaSigner.getAddress());
1597
+ //Claim all the claimable swaps
1598
+ for(let swap of claimableSolanaSwaps) {
1599
+ await swap.claim(solanaSigner);
1600
+ }
1601
+ //Get the swaps
1602
+ const claimableStarknetSwaps = await solanaSwapper.getClaimableSwaps("STARKNET", starknetSigner.getAddress());
1603
+ //Claim all the claimable swaps
1604
+ for(let swap of claimableStarknetSwaps) {
1605
+ await swap.claim(starknetSigner);
1606
+ }
1607
+ ```
1608
+
1609
+ ### Helpers
1610
+
1611
+ #### Getting wallet balances
1612
+
1613
+ The SDK also contains helper functions for getting the maximum spendable balance of wallets
1614
+
1615
+ ```typescript
1616
+ //Spendable balance of the starknet wallet address (discounting transaction fees)
1617
+ const strkBalance = await swapper.Utils.getSpendableBalance(starknetSigner, Tokens.STARKNET.STRK);
1618
+ //Spendable balance of the solana wallet address (discounting transaction fees)
1619
+ const solBalance = await swapper.Utils.getSpendableBalance(solanaSigner, Tokens.SOLANA.SOL);
1620
+ //Spendable balance of the bitcoin wallet - here we also need to specify the destination chain (as there are different swap protocols available with different on-chain footprints)
1621
+ const {balance: btcBalance, feeRate: btcFeeRate} = await swapper.Utils.getBitcoinSpendableBalance(bitcoinWalletAddress, "SOLANA");
1622
+ ```
1623
+
1624
+ #### Unified address parser
1625
+
1626
+ A common way for parsing all address formats supported by the SDK, automatically recognizes:
1627
+ - Bitcoin on-chain L1 address formats (p2pkh, p2wpkh, p2wsh, p2wsh, p2tr)
1628
+ - [BIP-21](https://en.bitcoin.it/wiki/BIP_0021) bitcoin payment URI
1629
+ - BOLT11 lightning network invoices
1630
+ - [LUD-6](https://github.com/lnurl/luds/blob/luds/06.md) LNURL-pay links
1631
+ - [LUD-3](https://github.com/lnurl/luds/blob/luds/03.md) LNURL-withdraw links
1632
+ - [LUD-16](https://github.com/lnurl/luds/blob/luds/16.md) Lightning static internet identifiers
1633
+ - Smart chain addresses (Solana, Starknet, etc.)
1634
+
1635
+ ```typescript
1636
+ const res = await swapper.Utils.parseAddress(address);
1637
+ switch(res.type) {
1638
+ case "BITCOIN":
1639
+ //Bitcoin on-chain L1 address or BIP-21 URI scheme with amount
1640
+ const btcAmount = res.amount;
1641
+ break;
1642
+ case "LIGHTNING":
1643
+ //BOLT11 lightning network invoice with pre-set amount
1644
+ const lnAmount = res.amount;
1645
+ break;
1646
+ case "LNURL":
1647
+ //LNURL payment or withdrawal link
1648
+ if(isLNURLWithdraw(res.lnurl)) {
1649
+ //LNURL-withdraw allowing withdrawals over the lightning network
1650
+ const lnurlWithdrawData: LNURLWithdraw = res.lnurl;
1651
+ const minWithdrawable = res.min; //Minimum payment amount
1652
+ const maxWithdrawable = res.max; //Maximum payment amount
1653
+ const fixedAmount = res.amount; //If res.min===res.max, an fixed amount is returned instead
1654
+ //Should show a UI allowing the user to choose an amount he wishes to withdraw
1655
+ }
1656
+ if(isLNURLPay(res.lnurl)) {
1657
+ //LNURL-pay or static lightning internet identifier allowing repeated payments over the lightning network
1658
+ const lnurlPayData: LNURLPay = res.lnurl;
1659
+ const minPayable = res.min; //Minimum payment amount
1660
+ const maxPayable = res.max; //Maximum payment amount
1661
+ const fixedAmount = res.amount; //If res.min===res.max, an fixed amount is returned instead
1662
+ const icon: (string | null) = res.lnurl.icon; //URL encoded icon that should be displayed on the UI
1663
+ const shortDescription: (string | null) = res.lnurl.shortDescription; //Short description of the payment
1664
+ const longDescription: (string | null) = res.lnurl.longDescription; //Long description of the payment
1665
+ const maxCommentLength: (number | 0) = res.lnurl.commentMaxLength; //Maximum allowed length of the payment message/comment (0 means no comment allowed)
1666
+ //Should show a UI displaying the icon, short description, long description, allowing the user to choose an amount he wishes to pay and possibly also a comment
1667
+ }
1668
+ break;
1669
+ default:
1670
+ //Addresses for smart chains
1671
+ break;
1672
+ }
1673
+ ```
1674
+
1675
+ ### Manually signing smart chain transactions
1676
+
1677
+ You can also sign the transactions on smart chain side (Solana, Starknet, etc.) of the SDK externally by a separate wallet. Each function which executes any transaction has its txs(action) counterpart, e.g.:
1678
+ - commit() -> txsCommit()
1679
+ - claim() -> txsClaim()
1680
+ - commitAndClaim -> txsCommitAndClaim()
1681
+ - refund() -> txsRefund()
1682
+
1683
+ After sending the transactions, you also need to make sure the SDK has enough time to receive an event notification of the transaction being executed, for this you have the waitTill(action) functions, e.g.:
1684
+
1685
+ - commit() -> waitTillCommited()
1686
+ - claim() -> waitTillClaimed()
1687
+ - commitAndClaim -> waitTillClaimed()
1688
+ - refund() -> waitTillRefunded()
1689
+
1690
+ ```typescript
1691
+ //Example for Solana
1692
+ const txns = await swap.txsCommit(); //Also works with txsClaim, txsRefund, txCommitAndClaim
1693
+ txns.forEach(val => if(val.signers.length>0) { val.tx.sign(...val.signers) });
1694
+ const signedTransactions = await solanaSigner.wallet.signAllTransactions(txns.map(val => val.tx));
1695
+ for(let tx of signedTransactions) {
1696
+ const res = await solanaRpc.sendRawTransaction(tx.serialize());
1697
+ await solanaRpc.confirmTransaction(res);
1698
+ }
1699
+ await swap.waitTillCommited(); //Or other relevant waitTillClaimed, waitTillRefunded
1700
+
1701
+ //Example for Starknet
1702
+ const txns = await swap.txsCommit(); //Also works with txsClaim, txsRefund, txCommitAndClaim
1703
+ for(let tx of txns) {
1704
+ if(tx.type==="INVOKE") await starknetSigner.account.execute(tx.tx, tx.details);
1705
+ if(tx.type==="DEPLOY_ACCOUNT") await starknetSigner.account.deployAccount(tx.tx, tx.details);
1706
+ }
1707
+ await swap.waitTillCommited(); //Or other relevant waitTillClaimed, waitTillRefunded
1708
+
1709
+ //Example for EVM
1710
+ const txns = await swap.txsCommit(); //Also works with txsClaim, txsRefund, txCommitAndClaim
1711
+ for(let tx of txns) {
1712
+ await evmSigner.account.sendTransaction(tx);
1713
+ }
1714
+ await swap.waitTillCommited(); //Or other relevant waitTillClaimed, waitTillRefunded
1715
+ ```
1716
+
1717
+ ### Additional swapper options
1718
+
1719
+ You can further customize the swapper instance with these options, you can:
1720
+ - adjust the maximum accepted pricing difference from the LPs
1721
+ - use custom mempool.space instance
1722
+ - use custom pricing API
1723
+ - use own LP node for swaps
1724
+ - adjust HTTP request timeouts
1725
+ - add parameters to be sent with each LP request
1726
+
1727
+ ```typescript
1728
+ const swapper = Factory.newSwapper({
1729
+ ...
1730
+ //Additional optional options
1731
+ pricingFeeDifferencePPM: 20000n, //Maximum allowed pricing difference for quote (between swap & market price) in ppm (parts per million) (20000 == 2%)
1732
+ mempoolApi: new MempoolApi("<url to custom mempool.space instance>"), //Set the SDK to use a custom mempool.space instance instead of the public one
1733
+ getPriceFn: (tickers: string[], abortSignal?: AbortSignal) => customPricingApi.getUsdPriceForTickers(tickers) //Overrides the default pricing API engine with a custom price getter
1734
+
1735
+ intermediaryUrl: "<url to custom LP node>",
1736
+ registryUrl: "<url to custom LP node registry>",
1737
+
1738
+ getRequestTimeout: 10000, //Timeout in milliseconds for GET requests
1739
+ postRequestTimeout: 10000, //Timeout in milliseconds for POST requests
1740
+ defaultAdditionalParameters: {lpData: "Pls give gud price"}, //Additional request data sent to LPs
1741
+
1742
+ defaultTrustedIntermediaryUrl: "<url to custom LP node>" //LP node/intermediary to use for trusted gas swaps
1743
+ });
1744
+ ```