@atomiqlabs/sdk 5.0.0-dev.4 → 5.0.0-dev.5

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,1242 +1,1242 @@
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/blob/main/src/index.ts)
6
-
7
- ## Installation
8
- ```
9
- npm install @atomiqlabs/sdk@dev
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@dev
18
- npm install @atomiqlabs/chain-starknet@dev
19
- npm install @atomiqlabs/chain-evm@dev
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
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 StarknetSigner(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
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
- or also with signer
190
-
191
- ```typescript
192
- const starknetSwapperWithSigner = swapper.withChain<"STARKNET">("STARKNET").withSigner(signer);
193
- ```
194
-
195
- ### Bitcoin on-chain swaps
196
-
197
- #### Swap Smart chain -> Bitcoin on-chain
198
-
199
- Getting swap quote
200
-
201
- ```typescript
202
- const _exactIn = false; //exactIn = false, so we specify the output amount
203
- const _amount = 10000n; //Amount in BTC base units - sats (10000 sats = 0.0001 BTC)
204
- const _address = "bc1qtw67hj77rt8zrkkg3jgngutu0yfgt9czjwusxt"; //BTC address of the recipient
205
-
206
- //Create the swap: swapping SOL to Bitcoin on-chain, receiving _amount of satoshis (smallest unit of bitcoin) to _address
207
- const swap = await swapper.swap(
208
- Tokens.SOLANA.SOL, //From specified source token
209
- Tokens.BITCOIN.BTC, //Swap to BTC
210
- _amount,
211
- _exactIn,
212
- solanaSigner.getAddress(), //Source address and smart chain signer
213
- _address //Destination of the swap
214
- );
215
-
216
- //Get the amount required to pay and fee
217
- const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
218
- const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
219
- const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
220
-
221
- const output: string = swap.getOutput().toString(); //Total output amount
222
-
223
- //Get swap expiration time
224
- const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
225
-
226
- //Get pricing info
227
- const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
228
- const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
229
- const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
230
- ```
231
-
232
- Initiating the swap
233
-
234
- ```typescript
235
- //Initiate and pay for the swap
236
- await swap.commit(solanaSigner);
237
- ```
238
-
239
- or [sign and send transaction manually](#manually-signing-smart-chain-transactions)
240
-
241
- Wait for the swap to execute, refund in case of failure
242
-
243
- ```typescript
244
- //Wait for the swap to conclude
245
- const result: boolean = await swap.waitForPayment();
246
- if(!result) {
247
- //Swap failed, money can be refunded
248
- await swap.refund();
249
- } else {
250
- //Swap successful, we can get the bitcoin txId
251
- const bitcoinTxId = swap.getBitcoinTxId();
252
- }
253
- ```
254
-
255
- ##### Swap states
256
-
257
- - ToBTCSwapState.REFUNDED = -3
258
- - Swap failed and was successfully refunded
259
- - ToBTCSwapState.QUOTE_EXPIRED = -2
260
- - Swap quote expired and cannot be executed anymore
261
- - ToBTCSwapState.QUOTE_SOFT_EXPIRED = -1
262
- - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
263
- - ToBTCSwapState.CREATED = 0
264
- - Swap quote is created, waiting to be executed
265
- - ToBTCSwapState.COMMITED = 1,
266
- - Swap was initiated (init transaction sent)
267
- - ToBTCSwapState.SOFT_CLAIMED = 2,
268
- - Swap was processed by the counterparty but not yet claimed on-chain (bitcoin transaction was sent, but unconfirmed yet)
269
- - ToBTCSwapState.CLAIMED = 3
270
- - Swap was finished and funds were successfully claimed by the counterparty
271
- - ToBTCSwapState.REFUNDABLE = 4
272
- - Swap was initiated but counterparty failed to process it, the user can now refund his funds
273
-
274
- #### Swap Bitcoin on-chain -> Solana
275
-
276
- 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.
277
-
278
- Getting swap quote
279
-
280
- ```typescript
281
- const _exactIn = true; //exactIn = true, so we specify the input amount
282
- const _amount = fromHumanReadableString("0.0001", Tokens.BITCOIN.BTC); //Amount in BTC base units - sats, we can also use a utility function here
283
-
284
- //Create the swap: swapping _amount of satoshis of Bitcoin on-chain to SOL
285
- const swap = await swapper.swap(
286
- Tokens.BITCOIN.BTC, //Swap from BTC
287
- Tokens.SOLANA.SOL, //Into specified destination token
288
- _amount,
289
- _exactIn, //Whether we define an input or output amount
290
- undefined, //Source address for the swap, not used for swaps from BTC
291
- solanaSigner.getAddress() //Destination address
292
- );
293
-
294
- //Get the amount required to pay and fee
295
- const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
296
- const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
297
- const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
298
-
299
- const output: string = swap.getOutput().toString(); //Total output amount
300
-
301
- //Get swap expiration time
302
- const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
303
-
304
- //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
305
- const securityDeposit: string = swap.getSecurityDeposit().toString();
306
- //Get claimer bounty (Human readable amount of SOL reserved as a reward for watchtowers to claim the swap on your behalf)
307
- const claimerBounty: string = swap.getClaimerBounty().toString();
308
-
309
- //Get pricing info
310
- const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
311
- const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
312
- const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
313
- ```
314
-
315
- Initiating the swap
316
-
317
- ```typescript
318
- //Initiate the swap on the destination chain (Solana) by opening up the bitcoin swap address
319
- await swap.commit(solanaSigner);
320
- ```
321
-
322
- or [sign and send transaction manually](#manually-signing-smart-chain-transactions)
323
-
324
- Sending bitcoin
325
-
326
- ```typescript
327
- //Get the bitcoin address
328
- const receivingAddressOnBitcoin = swap.getAddress();
329
- //Get the QR code data (contains the address and amount)
330
- const qrCodeData = swap.getHyperlink(); //Data that can be displayed in the form of QR code
331
- //Send the exact amount of BTC to the provided address
332
- ```
333
-
334
- or get a psbt and sign it
335
-
336
- ```typescript
337
- //Or obtain the funded PSBT (input already added) - ready for signing
338
- const {psbt, signInputs} = await swap.getFundedPsbt({address: "", publicKey: ""});
339
- for(let signIdx of signInputs) {
340
- psbt.signIdx(..., signIdx); //Or pass it to external signer
341
- }
342
- const bitcoinTxId = await swap.submitPsbt(psbt);
343
- ```
344
-
345
- Waiting for swap execution
346
-
347
- ```typescript
348
- try {
349
- //Wait for the payment to arrive
350
- await swap.waitForBitcoinTransaction(
351
- null, null,
352
- (
353
- txId: string, //Transaction ID of the received bitcoin transaction
354
- confirmations: number, //Current confirmations of the transaction
355
- targetConfirmations: number, //Required confirmations
356
- transactionETAms: number //Estimated in time (in milliseconds) until when the transaction will receive required amount of confirmations
357
- ) => {
358
- //Callback for transaction updates
359
- }
360
- );
361
- } catch(e) {
362
- //Error occurred while waiting for payment, this is most likely due to network errors
363
- return;
364
- }
365
-
366
- //Swap should get automatically claimed by the watchtowers, if not we can call swap.claim() ourselves
367
- try {
368
- await swap.waitTillClaimed(timeoutSignal(30*1000));
369
- } catch (e) {
370
- //Claim ourselves when automatic claim doesn't happen in 30 seconds
371
- await swap.claim(solanaSigner);
372
- }
373
- ```
374
-
375
- ##### Swap states
376
-
377
- - FromBTCSwapState.EXPIRED = -3
378
- - Bitcoin swap address expired
379
- - FromBTCSwapState.QUOTE_EXPIRED = -2
380
- - Swap quote expired and cannot be executed anymore
381
- - FromBTCSwapState.QUOTE_SOFT_EXPIRED = -1
382
- - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
383
- - FromBTCSwapState.PR_CREATED = 0
384
- - Swap quote is created, waiting for the user to open a bitcoin swap address
385
- - FromBTCSwapState.CLAIM_COMMITED = 1
386
- - Bitcoin swap address is opened
387
- - FromBTCSwapState.BTC_TX_CONFIRMED = 2
388
- - Bitcoin transaction sending funds to the swap address is confirmed
389
- - FromBTCSwapState.CLAIM_CLAIMED = 3
390
- - Swap funds are claimed to the user's wallet
391
-
392
-
393
- #### Swap Bitcoin on-chain -> Starknet/EVM
394
-
395
- 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!
396
-
397
- Getting swap quote
398
-
399
- ```typescript
400
- const _exactIn = true; //exactIn = true, so we specify the input amount
401
- const _amount = fromHumanReadableString("0.0001", Tokens.BITCOIN.BTC); //Amount in BTC base units - sats, we can also use a utility function here
402
-
403
- //Create the swap: swapping _amount of satoshis of Bitcoin on-chain to SOL
404
- const swap = await swapper.swap(
405
- Tokens.BITCOIN.BTC, //Swap from BTC
406
- Tokens.STARKNET.STRK, //Into specified destination token
407
- _amount,
408
- _exactIn, //Whether we define an input or output amount
409
- undefined, //Source address for the swap, not used for swaps from BTC
410
- starknetSigner.getAddress(), //Destination address
411
- {
412
- gasAmount: 1_000_000_000_000_000_000n //We can also request a gas drop on the destination chain (here requesting 1 STRK)
413
- }
414
- );
415
-
416
- //Get the amount required to pay and fee
417
- const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
418
- const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
419
- const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
420
-
421
- const output: string = swap.getOutput().toString(); //Total output amount
422
-
423
- //Get swap expiration time
424
- const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
425
-
426
- //Get pricing info
427
- const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
428
- const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
429
- const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
430
- ```
431
-
432
- Initiating the swap
433
-
434
- ```typescript
435
- //Obtain the funded PSBT (input already added) - ready for signing
436
- const {psbt, signInputs} = await swap.getFundedPsbt({address: "", publicKey: ""});
437
- for(let signIdx of signInputs) {
438
- psbt.signIdx(..., signIdx); //Or pass it to external signer
439
- }
440
- const bitcoinTxId = await swap.submitPsbt(psbt);
441
- ```
442
-
443
- or get raw PSBT and add inputs manually
444
-
445
- ```typescript
446
- //Or obtain raw PSBT to which inputs still need to be added
447
- const {psbt, in1sequence} = await swap.getPsbt();
448
- psbt.addInput(...);
449
- //Make sure the second input's sequence (index 1) is as specified in the in1sequence variable
450
- psbt.updateInput(1, {sequence: in1sequence});
451
- //Sign the PSBT, sign every input except the first one
452
- for(let i=1;i<psbt.inputsLength; i++) psbt.signIdx(..., i); //Or pass it to external signer
453
- //Submit the signed PSBT
454
- const bitcoinTxId = await swap.submitPsbt(psbt);
455
- ```
456
-
457
- Waiting for swap execution
458
-
459
- ```typescript
460
- try {
461
- //Wait for the payment to arrive
462
- await swap.waitForBitcoinTransaction(
463
- null, null,
464
- (
465
- txId: string, //Transaction ID of the received bitcoin transaction
466
- confirmations: number, //Current confirmations of the transaction
467
- targetConfirmations: number, //Required confirmations
468
- transactionETAms: number //Estimated in time (in milliseconds) until when the transaction will receive required amount of confirmations
469
- ) => {
470
- //Callback for transaction updates
471
- }
472
- );
473
- } catch(e) {
474
- //Error occurred while waiting for payment, this is most likely due to network errors
475
- return;
476
- }
477
-
478
- //Swap should get automatically claimed by the watchtowers, if not we can call swap.claim() ourselves
479
- try {
480
- await swap.waitTillClaimedOrFronted(timeoutSignal(30*1000));
481
- } catch (e) {
482
- //Claim ourselves when automatic claim doesn't happen in 30 seconds
483
- await swap.claim(starknetSigner);
484
- }
485
- ```
486
-
487
- ##### Swap states
488
-
489
- - SpvFromBTCSwapState.CLOSED = -5
490
- - Catastrophic failure during swap, shall never happen
491
- - SpvFromBTCSwapState.FAILED = -4
492
- - Bitcoin transaction was sent, but was double-spent later, therefore the swap was failed (no BTC was sent)
493
- - SpvFromBTCSwapState.DECLINED = -3
494
- - LP declined to process the swap transaction, no BTC was sent
495
- - SpvFromBTCSwapState.QUOTE_EXPIRED = -2
496
- - Swap quote expired and cannot be executed anymore
497
- - SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED = -1
498
- - Swap quote soft-expired (i.e. the quote probably expired, but if there is a bitcoin transaction being submitted it might still succeed)
499
- - SpvFromBTCSwapState.CREATED = 0
500
- - Swap quote is created, waiting on user to sign the bitcoin swap transaction
501
- - SpvFromBTCSwapState.SIGNED = 1
502
- - Bitcoin swap transaction was signed by the client
503
- - SpvFromBTCSwapState.POSTED = 2
504
- - Bitcoin swap transaction was posted to the LP
505
- - SpvFromBTCSwapState.BROADCASTED = 3
506
- - LP broadcasted the bitcoin swap transaction
507
- - SpvFromBTCSwapState.FRONTED = 4
508
- - Swap funds have been deposited to the user's wallet in front of the time
509
- - SpvFromBTCSwapState.BTC_TX_CONFIRMED = 5
510
- - Bitcoin swap transaction is confirmed
511
- - SpvFromBTCSwapState.CLAIM_CLAIMED = 6
512
- - Swap funds are claimed to the user's wallet
513
-
514
- ### Bitcoin lightning network swaps
515
-
516
- #### Swap Smart chain -> Bitcoin lightning network
517
-
518
- Getting swap quote
519
-
520
- ```typescript
521
- //Destination lightning network invoice, amount needs to be part of the invoice!
522
- const _lightningInvoice = "lnbc10u1pj2q0g9pp5ejs6m677m39cznpzum7muruvh50ys93ln82p4j9ks2luqm56xxlshp52r2anlhddfa9ex9vpw9gstxujff8a0p8s3pzvua930js0kwfea6scqzzsxqyz5vqsp5073zskc5qfgp7lre0t6s8uexxxey80ax564hsjklfwfjq2ew0ewq9qyyssqvzmgs6f8mvuwgfa9uqxhtza07qem4yfhn9wwlpskccmuwplsqmh8pdy6c42kqdu8p73kky9lsnl40qha5396d8lpgn90y27ltfc5rfqqq59cya";
523
-
524
- //Create the swap: swapping SOL to Bitcoin lightning
525
- const swap = await swapper.swap(
526
- Tokens.SOLANA.SOL, //From specified source token
527
- Tokens.BITCOIN.BTCLN, //Swap to BTC-LN
528
- undefined, //Amount is specified in the lightning network invoice!
529
- false, //Make sure we use exactIn=false for swaps to BTC-LN, if you want to use exactIn=true and set an amount, use LNURL-pay!
530
- solanaSigner.getAddress(), //Source address and smart chain signer
531
- _lightningInvoice //Destination of the swap
532
- );
533
-
534
- //Get the amount required to pay and fee
535
- const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
536
- const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
537
- const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
538
-
539
- const output: string = swap.getOutput().toString(); //Total output amount
540
-
541
- //Get swap expiration time
542
- const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
543
-
544
- //Get pricing info
545
- const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
546
- const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
547
- const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
548
- ```
549
-
550
- Initiating the swap
551
-
552
- ```typescript
553
- //Initiate and pay for the swap
554
- await swap.commit(solanaSigner);
555
- ```
556
-
557
- or [sign and send transaction manually](#manually-signing-smart-chain-transactions)
558
-
559
- Wait for the swap to execute, refund in case of failure
560
-
561
- ```typescript
562
- //Wait for the swap to conclude
563
- const result: boolean = await swap.waitForPayment();
564
- if(!result) {
565
- //Swap failed, money can be refunded
566
- await swap.refund(solanaSigner);
567
- } else {
568
- //Swap successful, we can get the lightning payment secret pre-image, which acts as a proof of payment
569
- const lightningSecret = swap.getSecret();
570
- }
571
- ```
572
-
573
- ##### Swap states
574
-
575
- - ToBTCSwapState.REFUNDED = -3
576
- - Swap failed and was successfully refunded
577
- - ToBTCSwapState.QUOTE_EXPIRED = -2
578
- - Swap quote expired and cannot be executed anymore
579
- - ToBTCSwapState.QUOTE_SOFT_EXPIRED = -1
580
- - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
581
- - ToBTCSwapState.CREATED = 0
582
- - Swap quote is created, waiting to be executed
583
- - ToBTCSwapState.COMMITED = 1,
584
- - Swap was initiated (init transaction sent)
585
- - ToBTCSwapState.SOFT_CLAIMED = 2,
586
- - Swap was processed by the counterparty but not yet claimed on-chain (lightning network payment secret was revealed)
587
- - ToBTCSwapState.CLAIMED = 3
588
- - Swap was finished and funds were successfully claimed by the counterparty
589
- - ToBTCSwapState.REFUNDABLE = 4
590
- - Swap was initiated but counterparty failed to process it, the user can now refund his funds
591
-
592
- #### Swap Bitcoin lightning network -> Solana
593
-
594
- 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.
595
-
596
- Getting swap quote
597
-
598
- ```typescript
599
- const _exactIn = true; //exactIn = true, so we specify the input amount
600
- const _amount = 10000n; //Amount in BTC base units - sats
601
-
602
- const swap = await swapper.swap(
603
- Tokens.BITCOIN.BTCLN, //Swap from BTC-LN
604
- Tokens.SOLANA.SOL, //Into specified destination token
605
- _amount,
606
- _exactIn, //Whether we define an input or output amount
607
- undefined, //Source address for the swap, not used for swaps from BTC-LN
608
- signer.getAddress() //Destination address
609
- );
610
-
611
- //Get the bitcoin lightning network invoice (the invoice contains pre-entered amount)
612
- const receivingLightningInvoice: string = swap.getAddress();
613
- //Get the URI hyperlink (contains the lightning network invoice) which can be displayed also as QR code
614
- const qrCodeData: string = swap.getHyperlink();
615
-
616
- //Get the amount required to pay and fee
617
- const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
618
- const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
619
- const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
620
-
621
- const output: string = swap.getOutput().toString(); //Total output amount
622
-
623
- //Get swap expiration time
624
- const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
625
-
626
- //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
627
- const securityDeposit: string = swap.getSecurityDeposit().toString();
628
-
629
- //Get pricing info
630
- const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
631
- const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
632
- const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
633
- ```
634
-
635
- Pay the displayed lightning network invoice from an external wallet
636
-
637
- Wait for the payment to be received
638
-
639
- ```typescript
640
- //Start listening to incoming lightning network payment
641
- const success = await swap.waitForPayment();
642
- if(!success) {
643
- //Lightning network payment not received in time and quote expired!
644
- return;
645
- }
646
- ```
647
-
648
- Claim the funds on the destination smart chains, this settles the swap and lightning network payment
649
-
650
- ```typescript
651
- try {
652
- //Claim the swap funds - this will initiate 2 transactions
653
- if(swap.canCommitAndClaimInOneShot()) {
654
- //Some chains (e.g. Solana) support signing multiple transactions in one flow
655
- await swap.commitAndClaim(solanaSigner);
656
- } else {
657
- //Other chains (e.g. Starknet) don't support signing multiple transaction in one flow, therefore you need to sign one-by-one
658
- await swap.commit(starknetSigner);
659
- await swap.claim(starknetSigner);
660
- }
661
- } catch(e) {
662
- //Error occurred while waiting for payment
663
- }
664
- ```
665
-
666
- or [sign and send transactions manually](#manually-signing-smart-chain-transactions)
667
-
668
- ##### Swap states
669
-
670
- - FromBTCLNSwapState.FAILED = -4
671
- - If the claiming of the funds was initiated, but never concluded, the user will get his lightning network payment refunded
672
- - FromBTCLNSwapState.QUOTE_EXPIRED = -3
673
- - Swap quote expired and cannot be executed anymore
674
- - FromBTCLNSwapState.QUOTE_SOFT_EXPIRED = -2
675
- - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
676
- - FromBTCLNSwapState.EXPIRED = -1
677
- - Lightning network invoice expired, meaning the swap is expired
678
- - FromBTCLNSwapState.PR_CREATED = 0
679
- - Swap is created, the user should now pay the provided lightning network invoice
680
- - FromBTCLNSwapState.PR_PAID = 1
681
- - Lightning network invoice payment was received (but cannot be settled by the counterparty yet)
682
- - FromBTCLNSwapState.CLAIM_COMMITED = 2
683
- - Claiming of the funds was initiated
684
- - FromBTCLNSwapState.CLAIM_CLAIMED = 3
685
- - Funds were successfully claimed & lightning network secret pre-image revealed, so the lightning network payment will settle now
686
-
687
-
688
- #### Swap Bitcoin lightning network -> Starknet/EVM
689
-
690
- Getting swap quote
691
-
692
- ```typescript
693
- const _exactIn = true; //exactIn = true, so we specify the input amount
694
- const _amount = 10000n; //Amount in BTC base units - sats
695
-
696
- const swap = await swapper.swap(
697
- Tokens.BITCOIN.BTCLN, //Swap from BTC-LN
698
- Tokens.STARKNET.STRK, //Into specified destination token
699
- _amount,
700
- _exactIn, //Whether we define an input or output amount
701
- undefined, //Source address for the swap, not used for swaps from BTC-LN
702
- signer.getAddress(), //Destination address
703
- {
704
- gasAmount: 1_000_000_000_000_000_000n //We can also request a gas drop on the destination chain (here requesting 1 STRK)
705
- }
706
- );
707
-
708
- //Get the bitcoin lightning network invoice (the invoice contains pre-entered amount)
709
- const receivingLightningInvoice: string = swap.getAddress();
710
- //Get the URI hyperlink (contains the lightning network invoice) which can be displayed also as QR code
711
- const qrCodeData: string = swap.getHyperlink();
712
-
713
- //Get the amount required to pay and fee
714
- const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
715
- const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
716
- const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
717
-
718
- const output: string = swap.getOutput().toString(); //Total output amount
719
-
720
- //Get swap expiration time
721
- const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
722
-
723
- //Get pricing info
724
- const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
725
- const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
726
- const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
727
- ```
728
-
729
- Pay the displayed lightning network invoice from an external lightning network wallet
730
-
731
- Wait for the payment to be received and settle the swap.
732
-
733
- ```typescript
734
- //Start listening to incoming lightning network payment
735
- const success = await swap.waitForPayment();
736
- if(!success) {
737
- //Lightning network payment not received in time and quote expired!
738
- return;
739
- }
740
-
741
- //Swap should get automatically claimed by the watchtowers, if not we can call swap.claim() to claim the swap ourselves
742
- try {
743
- await swap.waitTillClaimed(timeoutSignal(30*1000));
744
- } catch (e) {
745
- //Claim ourselves when automatic claim doesn't happen in 30 seconds
746
- await swap.claim(starknetSigner);
747
- }
748
- ```
749
-
750
- ##### Swap states
751
-
752
- - FromBTCLNAutoSwapState.FAILED = -4
753
- - If the claiming of the funds was initiated, but never concluded, the user will get his lightning network payment refunded
754
- - FromBTCLNAutoSwapState.QUOTE_EXPIRED = -3
755
- - Swap quote expired and cannot be executed anymore
756
- - FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED = -2
757
- - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
758
- - FromBTCLNAutoSwapState.EXPIRED = -1
759
- - Lightning network invoice expired, meaning the swap is expired
760
- - FromBTCLNAutoSwapState.PR_CREATED = 0
761
- - Swap is created, the user should now pay the provided lightning network invoice
762
- - FromBTCLNAutoSwapState.PR_PAID = 1
763
- - Lightning network invoice payment was received (but cannot be settled by the counterparty yet)
764
- - FromBTCLNAutoSwapState.CLAIM_COMMITED = 2
765
- - A swap HTLC was offered by the LP to the user
766
- - FromBTCLNAutoSwapState.CLAIM_CLAIMED = 3
767
- - Funds were successfully claimed & lightning network secret pre-image revealed, so the lightning network payment will settle now
768
-
769
- ### LNURLs & readable lightning identifiers
770
-
771
- 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)
772
-
773
- This SDK supports:
774
- * 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))
775
- * LNURL-withdraw ([LUD-3](https://github.com/lnurl/luds/blob/luds/03.md))
776
- * Static internet identifiers ([LUD-16](https://github.com/lnurl/luds/blob/luds/16.md))
777
-
778
- You can parse LNURLs and lightning invoices automatically using the [Unified address parser](#unified-address-parser)
779
-
780
- #### Differences
781
-
782
- Lightning invoices:
783
- * One time use only
784
- * Need to have a fixed amount, therefore recipient has to set the amount
785
- * Static and bounded expiration
786
- * You can only pay to a lightning invoice, not withdraw funds from it
787
-
788
- LNURLs & lightning identifiers:
789
- * Reusable
790
- * Programmable expiry
791
- * Allows payer to set an amount
792
- * Supports both, paying (LNURL-pay) and withdrawing (LNURL-withdraw)
793
- * Possibility to attach a message/comment to a payment
794
- * Receive a message/url as a result of the payment
795
-
796
- #### Swap Smart chain -> Bitcoin lightning network
797
-
798
- Getting swap quote
799
-
800
- ```typescript
801
- const _lnurlOrIdentifier: string = "lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkx6rfvdjx2ctvxyesuk0a27"; //Destination LNURL-pay or readable identifier
802
- const _exactIn = false; //exactIn = false, so we specify the output amount
803
- const _amount: bigint = 10000n; //Amount of satoshis to send (1 BTC = 100 000 000 satoshis)
804
-
805
- //Create the swap: swapping SOL to Bitcoin lightning
806
- const swap = await swapper.swap(
807
- Tokens.SOLANA.SOL, //From specified source token
808
- Tokens.BITCOIN.BTCLN, //Swap to BTC-LN
809
- _amount, //Now we can specify an amount for a lightning network payment!
810
- _exactIn, //We can also use exactIn=true here and set an amount in input token
811
- solanaSigner.getAddress(), //Source address and smart chain signer
812
- _lnurlOrIdentifier, //Destination of the swap
813
- {
814
- comment: "Hello world" //For LNURL-pay we can also pass a comment to the recipient
815
- }
816
- );
817
-
818
- //Get the amount required to pay and fee
819
- const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
820
- const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
821
- const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
822
-
823
- const output: string = swap.getOutput().toString(); //Total output amount
824
-
825
- //Get swap expiration time
826
- const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
827
-
828
- //Get pricing info
829
- const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
830
- const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
831
- const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
832
- ```
833
-
834
- Initiating the swap
835
-
836
- ```typescript
837
- //Initiate and pay for the swap
838
- await swap.commit(solanaSigner);
839
- ```
840
-
841
- or [sign and send transaction manually](#manually-signing-smart-chain-transactions)
842
-
843
- Wait for the swap to execute, refund in case of failure
844
-
845
- ```typescript
846
- //Wait for the swap to conclude
847
- const result: boolean = await swap.waitForPayment();
848
- if(!result) {
849
- //Swap failed, money can be refunded
850
- await swap.refund(solanaSigner);
851
- } else {
852
- //Swap successful, we can get the lightning payment secret pre-image, which acts as a proof of payment
853
- const lightningSecret = swap.getSecret();
854
- //In case the LNURL contained a success action, we can read it now and display it to user
855
- if(swap.hasSuccessAction()) {
856
- //Contains a success action that should displayed to the user
857
- const successMessage = swap.getSuccessAction();
858
- const description: string = successMessage.description; //Description of the message
859
- const text: (string | null) = successMessage.text; //Main text of the message
860
- const url: (string | null) = successMessage.url; //URL link which should be displayed
861
- }
862
- }
863
- ```
864
-
865
- #### Swap Bitcoin lightning network -> Solana
866
-
867
- 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.
868
-
869
- Getting swap quote
870
-
871
- ```typescript
872
- const _lnurl: string = "lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkx6rfvdjx2ctvxyesuk0a27"; //Destination LNURL-pay or readable identifier
873
- const _exactIn = true; //exactIn = true, so we specify the input amount
874
- const _amount = 10000n; //Amount in BTC base units - sats
875
-
876
- const swap = await swapper.swap(
877
- Tokens.BITCOIN.BTCLN, //Swap from BTC-LN
878
- Tokens.SOLANA.SOL, //Into specified destination token
879
- _amount,
880
- _exactIn, //Whether we define an input or output amount
881
- _lnurl, //Source LNURL for the swap
882
- signer.getAddress(), //Destination address
883
- );
884
-
885
- //Get the amount required to pay and fee
886
- const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
887
- const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
888
- const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
889
-
890
- const output: string = swap.getOutput().toString(); //Total output amount
891
-
892
- //Get swap expiration time
893
- const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
894
-
895
- //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
896
- const securityDeposit: string = swap.getSecurityDeposit().toString();
897
-
898
- //Get pricing info
899
- const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
900
- const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
901
- const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
902
- ```
903
-
904
- Wait for the payment to be received
905
-
906
- ```typescript
907
- //Start listening to incoming lightning network payment
908
- const success = await swap.waitForPayment();
909
- if(!success) {
910
- //Lightning network payment not received in time and quote expired!
911
- return;
912
- }
913
- ```
914
-
915
- Claim the funds on the destination smart chains, this settles the swap and lightning network payment
916
-
917
- ```typescript
918
- try {
919
- //Claim the swap funds - this will initiate 2 transactions
920
- if(swap.canCommitAndClaimInOneShot()) {
921
- //Some chains (e.g. Solana) support signing multiple transactions in one flow
922
- await swap.commitAndClaim(solanaSigner);
923
- } else {
924
- //Other chains (e.g. Starknet) don't support signing multiple transaction in one flow, therefore you need to sign one-by-one
925
- await swap.commit(starknetSigner);
926
- await swap.claim(starknetSigner);
927
- }
928
- } catch(e) {
929
- //Error occurred while waiting for payment
930
- }
931
- ```
932
-
933
- or [sign and send transactions manually](#manually-signing-smart-chain-transactions)
934
-
935
- #### Swap Bitcoin lightning network -> Starknet/EVM
936
-
937
- Getting swap quote
938
-
939
- ```typescript
940
- const _lnurl: string = "lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkx6rfvdjx2ctvxyesuk0a27"; //Destination LNURL-pay or readable identifier
941
- const _exactIn = true; //exactIn = true, so we specify the input amount
942
- const _amount = 10000n; //Amount in BTC base units - sats
943
-
944
- const swap = await swapper.swap(
945
- Tokens.BITCOIN.BTCLN, //Swap from BTC-LN
946
- Tokens.STARKNET.STRK, //Into specified destination token
947
- _amount,
948
- _exactIn, //Whether we define an input or output amount
949
- _lnurl, //Source LNURL for the swap
950
- signer.getAddress(), //Destination address
951
- {
952
- gasAmount: 1_000_000_000_000_000_000n //We can also request a gas drop on the destination chain (here requesting 1 STRK)
953
- }
954
- );
955
-
956
- //Get the amount required to pay and fee
957
- const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
958
- const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
959
- const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
960
-
961
- const output: string = swap.getOutput().toString(); //Total output amount
962
-
963
- //Get swap expiration time
964
- const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
965
-
966
- //Get pricing info
967
- const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
968
- const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
969
- const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
970
- ```
971
-
972
- Wait for the payment to be received & settle the swap.
973
-
974
- ```typescript
975
- //Start listening to incoming lightning network payment
976
- const success = await swap.waitForPayment();
977
- if(!success) {
978
- //Lightning network payment not received in time and quote expired!
979
- return;
980
- }
981
-
982
- //Swap should get automatically claimed by the watchtowers, if not we can call swap.claim() to claim the swap ourselves
983
- try {
984
- await swap.waitTillClaimed(timeoutSignal(30*1000));
985
- } catch (e) {
986
- //Claim ourselves when automatic claim doesn't happen in 30 seconds
987
- await swap.claim(starknetSigner);
988
- }
989
- ```
990
-
991
- ### Getting state of the swap
992
-
993
- You can get the current state of the swap with:
994
-
995
- ```typescript
996
- const state = swap.getState();
997
- ```
998
-
999
- You can also set a listener to listen for swap state changes:
1000
-
1001
- ```typescript
1002
- swap.events.on("swapState", swap => {
1003
- const newState = swap.getState();
1004
- });
1005
- ```
1006
-
1007
- For the meaning of the states please refer to the "Swap state" section under each swap type.
1008
-
1009
- ### Swap size limits
1010
-
1011
- Swap sizes are limited by the LPs you are connected to, they are advertised in BTC terms by LPs during handshake
1012
-
1013
- ```typescript
1014
- const swapLimits = swapper.getSwapLimits(srcToken, dstToken);
1015
- const inputMin = swapLimits.input.min;
1016
- const inputMax = swapLimits.input.max;
1017
- const outputMin = swapLimits.output.min;
1018
- const outputMax = swapLimits.output.max;
1019
- ```
1020
-
1021
- 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.
1022
-
1023
- ```typescript
1024
- let swapLimits = swapper.getSwapLimits(Tokens.BITCOIN.BTC, Tokens.SOLANA.SOL);
1025
- let inputMin = swapLimits.input.min; //Immediately available
1026
- let inputMax = swapLimits.input.max; //Immediately available
1027
- let outputMin = swapLimits.output.min; //Not available from the get-go
1028
- let outputMax = swapLimits.output.max; //Not available from the get-go
1029
-
1030
- //You can also listen to swap limit changes (optional)
1031
- swapper.on("swapLimitsChanged", () => {
1032
- //New limits available with swapper.getSwapLimits(srcToken, dstToken)
1033
- //Useful in e.g. a react application where you want to dynamically set min/max swappable amount
1034
- })
1035
-
1036
- //Try to swap really small amount of SOL with exactOut swap
1037
- try {
1038
- const swap = await swapper.swap(
1039
- Tokens.BITCOIN.BTC, //Swap from BTC
1040
- Tokens.SOLANA.SOL, //Into specified destination token
1041
- 1n, //1 lamport = 0.000000001 SOL
1042
- false, //Whether we define an input or output amount
1043
- undefined, //Source address for the swap, not used for swaps from BTC
1044
- solanaSigner.getAddress() //Destination address
1045
- );
1046
- } catch (e) {
1047
- //Fails with OutOfBoundsError
1048
- }
1049
-
1050
- swapLimits = swapper.getSwapLimits(Tokens.BITCOIN.BTC, Tokens.SOLANA.SOL);
1051
- inputMin = swapLimits.input.min; //Immediately available
1052
- inputMax = swapLimits.input.max; //Immediately available
1053
- outputMin = swapLimits.output.min; //Now available due to failed quote
1054
- outputMax = swapLimits.output.max; //Now available due to failed quote
1055
- ```
1056
-
1057
- ### Stored swaps
1058
-
1059
- #### Get swap by ID
1060
-
1061
- You can retrieve a swap by it's id, you can get an ID of the swap with
1062
-
1063
- ```typescript
1064
- const swapId = swap.getId();
1065
- ```
1066
-
1067
- And then later retrieve it from the storage
1068
-
1069
- ```typescript
1070
- const swap = await swapper.getSwapById(id);
1071
- ```
1072
-
1073
- #### Get refundable swaps
1074
- You can refund the swaps in one of two cases:
1075
- * In case intermediary is non-cooperative and goes offline, you can claim the funds from the swap contract back after some time.
1076
- * In case intermediary tried to pay but was unsuccessful, so he sent you signed message with which you can refund now without waiting.
1077
-
1078
- This call can be checked on every startup and periodically every few minutes.
1079
- ```typescript
1080
- //Get refundable swaps and refund them
1081
- const refundableSolanaSwaps = await swapper.getRefundableSwaps("SOLANA", solanaSigner.getAddress());
1082
- for(let swap of refundableSolanaSwaps) await swap.refund(solanaSigner);
1083
- const refundableStarknetSwaps = await swapper.getRefundableSwaps("STARKNET", starknetSigner.getAddress());
1084
- for(let swap of refundableStarknetSwaps) await swap.refund(starknetSigner);
1085
- ```
1086
-
1087
- #### Get claimable swaps
1088
- 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.
1089
-
1090
- ```typescript
1091
- //Get the swaps
1092
- const claimableSolanaSwaps = await solanaSwapper.getClaimableSwaps("SOLANA", solanaSigner.getAddress());
1093
- //Claim all the claimable swaps
1094
- for(let swap of claimableSolanaSwaps) {
1095
- if(swap.canCommit()) await swap.commit(solanaSigner); //This is for Bitcoin (lightning) -> Smart chain swaps, where commit & claim procedure might be needed
1096
- await swap.claim(solanaSigner);
1097
- }
1098
- //Get the swaps
1099
- const claimableStarknetSwaps = await solanaSwapper.getClaimableSwaps("STARKNET", starknetSigner.getAddress());
1100
- //Claim all the claimable swaps
1101
- for(let swap of claimableStarknetSwaps) {
1102
- if(swap.canCommit()) await swap.commit(starknetSigner); //This is for Bitcoin (lightning) -> Smart chain swaps, where commit & claim procedure might be needed
1103
- await swap.claim(starknetSigner);
1104
- }
1105
- ```
1106
-
1107
- ### Helpers
1108
-
1109
- #### Getting wallet balances
1110
-
1111
- The SDK also contains helper functions for getting the maximum spendable balance of wallets
1112
-
1113
- ```typescript
1114
- //Spendable balance of the starknet wallet address (discounting transaction fees)
1115
- const strkBalance = await swapper.Utils.getSpendableBalance(starknetSigner, Tokens.STARKNET.STRK);
1116
- //Spendable balance of the solana wallet address (discounting transaction fees)
1117
- const solBalance = await swapper.Utils.getSpendableBalance(solanaSigner, Tokens.SOLANA.SOL);
1118
- //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)
1119
- const {balance: btcBalance, feeRate: btcFeeRate} = await swapper.Utils.getBitcoinSpendableBalance(bitcoinWalletAddress, "SOLANA");
1120
- ```
1121
-
1122
- #### Unified address parser
1123
-
1124
- A common way for parsing all address formats supported by the SDK, automatically recognizes:
1125
- - Bitcoin on-chain L1 address formats (p2pkh, p2wpkh, p2wsh, p2wsh, p2tr)
1126
- - [BIP-21](https://en.bitcoin.it/wiki/BIP_0021) bitcoin payment URI
1127
- - BOLT11 lightning network invoices
1128
- - [LUD-6](https://github.com/lnurl/luds/blob/luds/06.md) LNURL-pay links
1129
- - [LUD-3](https://github.com/lnurl/luds/blob/luds/03.md) LNURL-withdraw links
1130
- - [LUD-16](https://github.com/lnurl/luds/blob/luds/16.md) Lightning static internet identifiers
1131
- - Smart chain addresses (Solana, Starknet, etc.)
1132
-
1133
- ```typescript
1134
- const res = await swapper.Utils.parseAddress(address);
1135
- switch(res.type) {
1136
- case "BITCOIN":
1137
- //Bitcoin on-chain L1 address or BIP-21 URI scheme with amount
1138
- const btcAmount = res.amount;
1139
- break;
1140
- case "LIGHTNING":
1141
- //BOLT11 lightning network invoice with pre-set amount
1142
- const lnAmount = res.amount;
1143
- break;
1144
- case "LNURL":
1145
- //LNURL payment or withdrawal link
1146
- if(isLNURLWithdraw(res.lnurl)) {
1147
- //LNURL-withdraw allowing withdrawals over the lightning network
1148
- const lnurlWithdrawData: LNURLWithdraw = res.lnurl;
1149
- const minWithdrawable = res.min; //Minimum payment amount
1150
- const maxWithdrawable = res.max; //Maximum payment amount
1151
- const fixedAmount = res.amount; //If res.min===res.max, an fixed amount is returned instead
1152
- //Should show a UI allowing the user to choose an amount he wishes to withdraw
1153
- }
1154
- if(isLNURLPay(res.lnurl)) {
1155
- //LNURL-pay or static lightning internet identifier allowing repeated payments over the lightning network
1156
- const lnurlPayData: LNURLPay = res.lnurl;
1157
- const minPayable = res.min; //Minimum payment amount
1158
- const maxPayable = res.max; //Maximum payment amount
1159
- const fixedAmount = res.amount; //If res.min===res.max, an fixed amount is returned instead
1160
- const icon: (string | null) = res.lnurl.icon; //URL encoded icon that should be displayed on the UI
1161
- const shortDescription: (string | null) = res.lnurl.shortDescription; //Short description of the payment
1162
- const longDescription: (string | null) = res.lnurl.longDescription; //Long description of the payment
1163
- const maxCommentLength: (number | 0) = res.lnurl.commentMaxLength; //Maximum allowed length of the payment message/comment (0 means no comment allowed)
1164
- //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
1165
- }
1166
- break;
1167
- default:
1168
- //Addresses for smart chains
1169
- break;
1170
- }
1171
- ```
1172
-
1173
- ### Manually signing smart chain transactions
1174
-
1175
- 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.:
1176
- - commit() -> txsCommit()
1177
- - claim() -> txsClaim()
1178
- - commitAndClaim -> txsCommitAndClaim()
1179
- - refund() -> txsRefund()
1180
-
1181
- 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.:
1182
-
1183
- - commit() -> waitTillCommited()
1184
- - claim() -> waitTillClaimed()
1185
- - commitAndClaim -> waitTillClaimed()
1186
- - refund() -> waitTillRefunded()
1187
-
1188
- ```typescript
1189
- //Example for Solana
1190
- const txns = await swap.txsCommit(); //Also works with txsClaim, txsRefund, txCommitAndClaim
1191
- txns.forEach(val => val.tx.sign(...val.signers));
1192
- const signedTransactions = await solanaSigner.wallet.signAllTransactions(txns.map(val => val.tx));
1193
- for(let tx of signedTransactions) {
1194
- const res = await solanaRpc.sendRawTransaction(tx.serialize());
1195
- await solanaRpc.confirmTransaction(res);
1196
- }
1197
- await swap.waitTillCommited(); //Or other relevant waitTillClaimed, waitTillRefunded
1198
-
1199
- //Example for Starknet
1200
- const txns = await swap.txsCommit(); //Also works with txsClaim, txsRefund, txCommitAndClaim
1201
- for(let tx of txns) {
1202
- if(tx.type==="INVOKE") await starknetSigner.account.execute(tx.tx, tx.details);
1203
- if(tx.type==="DEPLOY_ACCOUNT") await starknetSigner.account.deployAccount(tx.tx, tx.details);
1204
- }
1205
- await swap.waitTillCommited(); //Or other relevant waitTillClaimed, waitTillRefunded
1206
-
1207
- //Example for EVM
1208
- const txns = await swap.txsCommit(); //Also works with txsClaim, txsRefund, txCommitAndClaim
1209
- for(let tx of txns) {
1210
- await evmSigner.account.sendTransaction(tx);
1211
- }
1212
- await swap.waitTillCommited(); //Or other relevant waitTillClaimed, waitTillRefunded
1213
- ```
1214
-
1215
- ### Additional swapper options
1216
-
1217
- You can further customize the swapper instance with these options, you can:
1218
- - adjust the maximum accepted pricing difference from the LPs
1219
- - use custom mempool.space instance
1220
- - use custom pricing API
1221
- - use own LP node for swaps
1222
- - adjust HTTP request timeouts
1223
- - add parameters to be sent with each LP request
1224
-
1225
- ```typescript
1226
- const swapper = Factory.newSwapper({
1227
- ...
1228
- //Additional optional options
1229
- pricingFeeDifferencePPM: 20000n, //Maximum allowed pricing difference for quote (between swap & market price) in ppm (parts per million) (20000 == 2%)
1230
- mempoolApi: new MempoolApi("<url to custom mempool.space instance>"), //Set the SDK to use a custom mempool.space instance instead of the public one
1231
- getPriceFn: (tickers: string[], abortSignal?: AbortSignal) => customPricingApi.getUsdPriceForTickers(tickers) //Overrides the default pricing API engine with a custom price getter
1232
-
1233
- intermediaryUrl: "<url to custom LP node>",
1234
- registryUrl: "<url to custom LP node registry>",
1235
-
1236
- getRequestTimeout: 10000, //Timeout in milliseconds for GET requests
1237
- postRequestTimeout: 10000, //Timeout in milliseconds for POST requests
1238
- defaultAdditionalParameters: {lpData: "Pls give gud price"}, //Additional request data sent to LPs
1239
-
1240
- defaultTrustedIntermediaryUrl: "<url to custom LP node>" //LP node/intermediary to use for trusted gas swaps
1241
- });
1242
- ```
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/blob/main/src/index.ts)
6
+
7
+ ## Installation
8
+ ```
9
+ npm install @atomiqlabs/sdk@dev
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@dev
18
+ npm install @atomiqlabs/chain-starknet@dev
19
+ npm install @atomiqlabs/chain-evm@dev
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
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 StarknetSigner(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
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
+ or also with signer
190
+
191
+ ```typescript
192
+ const starknetSwapperWithSigner = swapper.withChain<"STARKNET">("STARKNET").withSigner(signer);
193
+ ```
194
+
195
+ ### Bitcoin on-chain swaps
196
+
197
+ #### Swap Smart chain -> Bitcoin on-chain
198
+
199
+ Getting swap quote
200
+
201
+ ```typescript
202
+ const _exactIn = false; //exactIn = false, so we specify the output amount
203
+ const _amount = 10000n; //Amount in BTC base units - sats (10000 sats = 0.0001 BTC)
204
+ const _address = "bc1qtw67hj77rt8zrkkg3jgngutu0yfgt9czjwusxt"; //BTC address of the recipient
205
+
206
+ //Create the swap: swapping SOL to Bitcoin on-chain, receiving _amount of satoshis (smallest unit of bitcoin) to _address
207
+ const swap = await swapper.swap(
208
+ Tokens.SOLANA.SOL, //From specified source token
209
+ Tokens.BITCOIN.BTC, //Swap to BTC
210
+ _amount,
211
+ _exactIn,
212
+ solanaSigner.getAddress(), //Source address and smart chain signer
213
+ _address //Destination of the swap
214
+ );
215
+
216
+ //Get the amount required to pay and fee
217
+ const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
218
+ const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
219
+ const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
220
+
221
+ const output: string = swap.getOutput().toString(); //Total output amount
222
+
223
+ //Get swap expiration time
224
+ const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
225
+
226
+ //Get pricing info
227
+ const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
228
+ const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
229
+ const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
230
+ ```
231
+
232
+ Initiating the swap
233
+
234
+ ```typescript
235
+ //Initiate and pay for the swap
236
+ await swap.commit(solanaSigner);
237
+ ```
238
+
239
+ or [sign and send transaction manually](#manually-signing-smart-chain-transactions)
240
+
241
+ Wait for the swap to execute, refund in case of failure
242
+
243
+ ```typescript
244
+ //Wait for the swap to conclude
245
+ const result: boolean = await swap.waitForPayment();
246
+ if(!result) {
247
+ //Swap failed, money can be refunded
248
+ await swap.refund();
249
+ } else {
250
+ //Swap successful, we can get the bitcoin txId
251
+ const bitcoinTxId = swap.getBitcoinTxId();
252
+ }
253
+ ```
254
+
255
+ ##### Swap states
256
+
257
+ - ToBTCSwapState.REFUNDED = -3
258
+ - Swap failed and was successfully refunded
259
+ - ToBTCSwapState.QUOTE_EXPIRED = -2
260
+ - Swap quote expired and cannot be executed anymore
261
+ - ToBTCSwapState.QUOTE_SOFT_EXPIRED = -1
262
+ - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
263
+ - ToBTCSwapState.CREATED = 0
264
+ - Swap quote is created, waiting to be executed
265
+ - ToBTCSwapState.COMMITED = 1,
266
+ - Swap was initiated (init transaction sent)
267
+ - ToBTCSwapState.SOFT_CLAIMED = 2,
268
+ - Swap was processed by the counterparty but not yet claimed on-chain (bitcoin transaction was sent, but unconfirmed yet)
269
+ - ToBTCSwapState.CLAIMED = 3
270
+ - Swap was finished and funds were successfully claimed by the counterparty
271
+ - ToBTCSwapState.REFUNDABLE = 4
272
+ - Swap was initiated but counterparty failed to process it, the user can now refund his funds
273
+
274
+ #### Swap Bitcoin on-chain -> Solana
275
+
276
+ 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.
277
+
278
+ Getting swap quote
279
+
280
+ ```typescript
281
+ const _exactIn = true; //exactIn = true, so we specify the input amount
282
+ const _amount = fromHumanReadableString("0.0001", Tokens.BITCOIN.BTC); //Amount in BTC base units - sats, we can also use a utility function here
283
+
284
+ //Create the swap: swapping _amount of satoshis of Bitcoin on-chain to SOL
285
+ const swap = await swapper.swap(
286
+ Tokens.BITCOIN.BTC, //Swap from BTC
287
+ Tokens.SOLANA.SOL, //Into specified destination token
288
+ _amount,
289
+ _exactIn, //Whether we define an input or output amount
290
+ undefined, //Source address for the swap, not used for swaps from BTC
291
+ solanaSigner.getAddress() //Destination address
292
+ );
293
+
294
+ //Get the amount required to pay and fee
295
+ const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
296
+ const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
297
+ const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
298
+
299
+ const output: string = swap.getOutput().toString(); //Total output amount
300
+
301
+ //Get swap expiration time
302
+ const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
303
+
304
+ //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
305
+ const securityDeposit: string = swap.getSecurityDeposit().toString();
306
+ //Get claimer bounty (Human readable amount of SOL reserved as a reward for watchtowers to claim the swap on your behalf)
307
+ const claimerBounty: string = swap.getClaimerBounty().toString();
308
+
309
+ //Get pricing info
310
+ const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
311
+ const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
312
+ const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
313
+ ```
314
+
315
+ Initiating the swap
316
+
317
+ ```typescript
318
+ //Initiate the swap on the destination chain (Solana) by opening up the bitcoin swap address
319
+ await swap.commit(solanaSigner);
320
+ ```
321
+
322
+ or [sign and send transaction manually](#manually-signing-smart-chain-transactions)
323
+
324
+ Sending bitcoin
325
+
326
+ ```typescript
327
+ //Get the bitcoin address
328
+ const receivingAddressOnBitcoin = swap.getAddress();
329
+ //Get the QR code data (contains the address and amount)
330
+ const qrCodeData = swap.getHyperlink(); //Data that can be displayed in the form of QR code
331
+ //Send the exact amount of BTC to the provided address
332
+ ```
333
+
334
+ or get a psbt and sign it
335
+
336
+ ```typescript
337
+ //Or obtain the funded PSBT (input already added) - ready for signing
338
+ const {psbt, signInputs} = await swap.getFundedPsbt({address: "", publicKey: ""});
339
+ for(let signIdx of signInputs) {
340
+ psbt.signIdx(..., signIdx); //Or pass it to external signer
341
+ }
342
+ const bitcoinTxId = await swap.submitPsbt(psbt);
343
+ ```
344
+
345
+ Waiting for swap execution
346
+
347
+ ```typescript
348
+ try {
349
+ //Wait for the payment to arrive
350
+ await swap.waitForBitcoinTransaction(
351
+ null, null,
352
+ (
353
+ txId: string, //Transaction ID of the received bitcoin transaction
354
+ confirmations: number, //Current confirmations of the transaction
355
+ targetConfirmations: number, //Required confirmations
356
+ transactionETAms: number //Estimated in time (in milliseconds) until when the transaction will receive required amount of confirmations
357
+ ) => {
358
+ //Callback for transaction updates
359
+ }
360
+ );
361
+ } catch(e) {
362
+ //Error occurred while waiting for payment, this is most likely due to network errors
363
+ return;
364
+ }
365
+
366
+ //Swap should get automatically claimed by the watchtowers, if not we can call swap.claim() ourselves
367
+ try {
368
+ await swap.waitTillClaimed(timeoutSignal(30*1000));
369
+ } catch (e) {
370
+ //Claim ourselves when automatic claim doesn't happen in 30 seconds
371
+ await swap.claim(solanaSigner);
372
+ }
373
+ ```
374
+
375
+ ##### Swap states
376
+
377
+ - FromBTCSwapState.EXPIRED = -3
378
+ - Bitcoin swap address expired
379
+ - FromBTCSwapState.QUOTE_EXPIRED = -2
380
+ - Swap quote expired and cannot be executed anymore
381
+ - FromBTCSwapState.QUOTE_SOFT_EXPIRED = -1
382
+ - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
383
+ - FromBTCSwapState.PR_CREATED = 0
384
+ - Swap quote is created, waiting for the user to open a bitcoin swap address
385
+ - FromBTCSwapState.CLAIM_COMMITED = 1
386
+ - Bitcoin swap address is opened
387
+ - FromBTCSwapState.BTC_TX_CONFIRMED = 2
388
+ - Bitcoin transaction sending funds to the swap address is confirmed
389
+ - FromBTCSwapState.CLAIM_CLAIMED = 3
390
+ - Swap funds are claimed to the user's wallet
391
+
392
+
393
+ #### Swap Bitcoin on-chain -> Starknet/EVM
394
+
395
+ 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!
396
+
397
+ Getting swap quote
398
+
399
+ ```typescript
400
+ const _exactIn = true; //exactIn = true, so we specify the input amount
401
+ const _amount = fromHumanReadableString("0.0001", Tokens.BITCOIN.BTC); //Amount in BTC base units - sats, we can also use a utility function here
402
+
403
+ //Create the swap: swapping _amount of satoshis of Bitcoin on-chain to SOL
404
+ const swap = await swapper.swap(
405
+ Tokens.BITCOIN.BTC, //Swap from BTC
406
+ Tokens.STARKNET.STRK, //Into specified destination token
407
+ _amount,
408
+ _exactIn, //Whether we define an input or output amount
409
+ undefined, //Source address for the swap, not used for swaps from BTC
410
+ starknetSigner.getAddress(), //Destination address
411
+ {
412
+ gasAmount: 1_000_000_000_000_000_000n //We can also request a gas drop on the destination chain (here requesting 1 STRK)
413
+ }
414
+ );
415
+
416
+ //Get the amount required to pay and fee
417
+ const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
418
+ const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
419
+ const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
420
+
421
+ const output: string = swap.getOutput().toString(); //Total output amount
422
+
423
+ //Get swap expiration time
424
+ const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
425
+
426
+ //Get pricing info
427
+ const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
428
+ const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
429
+ const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
430
+ ```
431
+
432
+ Initiating the swap
433
+
434
+ ```typescript
435
+ //Obtain the funded PSBT (input already added) - ready for signing
436
+ const {psbt, signInputs} = await swap.getFundedPsbt({address: "", publicKey: ""});
437
+ for(let signIdx of signInputs) {
438
+ psbt.signIdx(..., signIdx); //Or pass it to external signer
439
+ }
440
+ const bitcoinTxId = await swap.submitPsbt(psbt);
441
+ ```
442
+
443
+ or get raw PSBT and add inputs manually
444
+
445
+ ```typescript
446
+ //Or obtain raw PSBT to which inputs still need to be added
447
+ const {psbt, in1sequence} = await swap.getPsbt();
448
+ psbt.addInput(...);
449
+ //Make sure the second input's sequence (index 1) is as specified in the in1sequence variable
450
+ psbt.updateInput(1, {sequence: in1sequence});
451
+ //Sign the PSBT, sign every input except the first one
452
+ for(let i=1;i<psbt.inputsLength; i++) psbt.signIdx(..., i); //Or pass it to external signer
453
+ //Submit the signed PSBT
454
+ const bitcoinTxId = await swap.submitPsbt(psbt);
455
+ ```
456
+
457
+ Waiting for swap execution
458
+
459
+ ```typescript
460
+ try {
461
+ //Wait for the payment to arrive
462
+ await swap.waitForBitcoinTransaction(
463
+ null, null,
464
+ (
465
+ txId: string, //Transaction ID of the received bitcoin transaction
466
+ confirmations: number, //Current confirmations of the transaction
467
+ targetConfirmations: number, //Required confirmations
468
+ transactionETAms: number //Estimated in time (in milliseconds) until when the transaction will receive required amount of confirmations
469
+ ) => {
470
+ //Callback for transaction updates
471
+ }
472
+ );
473
+ } catch(e) {
474
+ //Error occurred while waiting for payment, this is most likely due to network errors
475
+ return;
476
+ }
477
+
478
+ //Swap should get automatically claimed by the watchtowers, if not we can call swap.claim() ourselves
479
+ try {
480
+ await swap.waitTillClaimedOrFronted(timeoutSignal(30*1000));
481
+ } catch (e) {
482
+ //Claim ourselves when automatic claim doesn't happen in 30 seconds
483
+ await swap.claim(starknetSigner);
484
+ }
485
+ ```
486
+
487
+ ##### Swap states
488
+
489
+ - SpvFromBTCSwapState.CLOSED = -5
490
+ - Catastrophic failure during swap, shall never happen
491
+ - SpvFromBTCSwapState.FAILED = -4
492
+ - Bitcoin transaction was sent, but was double-spent later, therefore the swap was failed (no BTC was sent)
493
+ - SpvFromBTCSwapState.DECLINED = -3
494
+ - LP declined to process the swap transaction, no BTC was sent
495
+ - SpvFromBTCSwapState.QUOTE_EXPIRED = -2
496
+ - Swap quote expired and cannot be executed anymore
497
+ - SpvFromBTCSwapState.QUOTE_SOFT_EXPIRED = -1
498
+ - Swap quote soft-expired (i.e. the quote probably expired, but if there is a bitcoin transaction being submitted it might still succeed)
499
+ - SpvFromBTCSwapState.CREATED = 0
500
+ - Swap quote is created, waiting on user to sign the bitcoin swap transaction
501
+ - SpvFromBTCSwapState.SIGNED = 1
502
+ - Bitcoin swap transaction was signed by the client
503
+ - SpvFromBTCSwapState.POSTED = 2
504
+ - Bitcoin swap transaction was posted to the LP
505
+ - SpvFromBTCSwapState.BROADCASTED = 3
506
+ - LP broadcasted the bitcoin swap transaction
507
+ - SpvFromBTCSwapState.FRONTED = 4
508
+ - Swap funds have been deposited to the user's wallet in front of the time
509
+ - SpvFromBTCSwapState.BTC_TX_CONFIRMED = 5
510
+ - Bitcoin swap transaction is confirmed
511
+ - SpvFromBTCSwapState.CLAIM_CLAIMED = 6
512
+ - Swap funds are claimed to the user's wallet
513
+
514
+ ### Bitcoin lightning network swaps
515
+
516
+ #### Swap Smart chain -> Bitcoin lightning network
517
+
518
+ Getting swap quote
519
+
520
+ ```typescript
521
+ //Destination lightning network invoice, amount needs to be part of the invoice!
522
+ const _lightningInvoice = "lnbc10u1pj2q0g9pp5ejs6m677m39cznpzum7muruvh50ys93ln82p4j9ks2luqm56xxlshp52r2anlhddfa9ex9vpw9gstxujff8a0p8s3pzvua930js0kwfea6scqzzsxqyz5vqsp5073zskc5qfgp7lre0t6s8uexxxey80ax564hsjklfwfjq2ew0ewq9qyyssqvzmgs6f8mvuwgfa9uqxhtza07qem4yfhn9wwlpskccmuwplsqmh8pdy6c42kqdu8p73kky9lsnl40qha5396d8lpgn90y27ltfc5rfqqq59cya";
523
+
524
+ //Create the swap: swapping SOL to Bitcoin lightning
525
+ const swap = await swapper.swap(
526
+ Tokens.SOLANA.SOL, //From specified source token
527
+ Tokens.BITCOIN.BTCLN, //Swap to BTC-LN
528
+ undefined, //Amount is specified in the lightning network invoice!
529
+ false, //Make sure we use exactIn=false for swaps to BTC-LN, if you want to use exactIn=true and set an amount, use LNURL-pay!
530
+ solanaSigner.getAddress(), //Source address and smart chain signer
531
+ _lightningInvoice //Destination of the swap
532
+ );
533
+
534
+ //Get the amount required to pay and fee
535
+ const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
536
+ const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
537
+ const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
538
+
539
+ const output: string = swap.getOutput().toString(); //Total output amount
540
+
541
+ //Get swap expiration time
542
+ const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
543
+
544
+ //Get pricing info
545
+ const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
546
+ const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
547
+ const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
548
+ ```
549
+
550
+ Initiating the swap
551
+
552
+ ```typescript
553
+ //Initiate and pay for the swap
554
+ await swap.commit(solanaSigner);
555
+ ```
556
+
557
+ or [sign and send transaction manually](#manually-signing-smart-chain-transactions)
558
+
559
+ Wait for the swap to execute, refund in case of failure
560
+
561
+ ```typescript
562
+ //Wait for the swap to conclude
563
+ const result: boolean = await swap.waitForPayment();
564
+ if(!result) {
565
+ //Swap failed, money can be refunded
566
+ await swap.refund(solanaSigner);
567
+ } else {
568
+ //Swap successful, we can get the lightning payment secret pre-image, which acts as a proof of payment
569
+ const lightningSecret = swap.getSecret();
570
+ }
571
+ ```
572
+
573
+ ##### Swap states
574
+
575
+ - ToBTCSwapState.REFUNDED = -3
576
+ - Swap failed and was successfully refunded
577
+ - ToBTCSwapState.QUOTE_EXPIRED = -2
578
+ - Swap quote expired and cannot be executed anymore
579
+ - ToBTCSwapState.QUOTE_SOFT_EXPIRED = -1
580
+ - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
581
+ - ToBTCSwapState.CREATED = 0
582
+ - Swap quote is created, waiting to be executed
583
+ - ToBTCSwapState.COMMITED = 1,
584
+ - Swap was initiated (init transaction sent)
585
+ - ToBTCSwapState.SOFT_CLAIMED = 2,
586
+ - Swap was processed by the counterparty but not yet claimed on-chain (lightning network payment secret was revealed)
587
+ - ToBTCSwapState.CLAIMED = 3
588
+ - Swap was finished and funds were successfully claimed by the counterparty
589
+ - ToBTCSwapState.REFUNDABLE = 4
590
+ - Swap was initiated but counterparty failed to process it, the user can now refund his funds
591
+
592
+ #### Swap Bitcoin lightning network -> Solana
593
+
594
+ 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.
595
+
596
+ Getting swap quote
597
+
598
+ ```typescript
599
+ const _exactIn = true; //exactIn = true, so we specify the input amount
600
+ const _amount = 10000n; //Amount in BTC base units - sats
601
+
602
+ const swap = await swapper.swap(
603
+ Tokens.BITCOIN.BTCLN, //Swap from BTC-LN
604
+ Tokens.SOLANA.SOL, //Into specified destination token
605
+ _amount,
606
+ _exactIn, //Whether we define an input or output amount
607
+ undefined, //Source address for the swap, not used for swaps from BTC-LN
608
+ signer.getAddress() //Destination address
609
+ );
610
+
611
+ //Get the bitcoin lightning network invoice (the invoice contains pre-entered amount)
612
+ const receivingLightningInvoice: string = swap.getAddress();
613
+ //Get the URI hyperlink (contains the lightning network invoice) which can be displayed also as QR code
614
+ const qrCodeData: string = swap.getHyperlink();
615
+
616
+ //Get the amount required to pay and fee
617
+ const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
618
+ const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
619
+ const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
620
+
621
+ const output: string = swap.getOutput().toString(); //Total output amount
622
+
623
+ //Get swap expiration time
624
+ const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
625
+
626
+ //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
627
+ const securityDeposit: string = swap.getSecurityDeposit().toString();
628
+
629
+ //Get pricing info
630
+ const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
631
+ const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
632
+ const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
633
+ ```
634
+
635
+ Pay the displayed lightning network invoice from an external wallet
636
+
637
+ Wait for the payment to be received
638
+
639
+ ```typescript
640
+ //Start listening to incoming lightning network payment
641
+ const success = await swap.waitForPayment();
642
+ if(!success) {
643
+ //Lightning network payment not received in time and quote expired!
644
+ return;
645
+ }
646
+ ```
647
+
648
+ Claim the funds on the destination smart chains, this settles the swap and lightning network payment
649
+
650
+ ```typescript
651
+ try {
652
+ //Claim the swap funds - this will initiate 2 transactions
653
+ if(swap.canCommitAndClaimInOneShot()) {
654
+ //Some chains (e.g. Solana) support signing multiple transactions in one flow
655
+ await swap.commitAndClaim(solanaSigner);
656
+ } else {
657
+ //Other chains (e.g. Starknet) don't support signing multiple transaction in one flow, therefore you need to sign one-by-one
658
+ await swap.commit(starknetSigner);
659
+ await swap.claim(starknetSigner);
660
+ }
661
+ } catch(e) {
662
+ //Error occurred while waiting for payment
663
+ }
664
+ ```
665
+
666
+ or [sign and send transactions manually](#manually-signing-smart-chain-transactions)
667
+
668
+ ##### Swap states
669
+
670
+ - FromBTCLNSwapState.FAILED = -4
671
+ - If the claiming of the funds was initiated, but never concluded, the user will get his lightning network payment refunded
672
+ - FromBTCLNSwapState.QUOTE_EXPIRED = -3
673
+ - Swap quote expired and cannot be executed anymore
674
+ - FromBTCLNSwapState.QUOTE_SOFT_EXPIRED = -2
675
+ - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
676
+ - FromBTCLNSwapState.EXPIRED = -1
677
+ - Lightning network invoice expired, meaning the swap is expired
678
+ - FromBTCLNSwapState.PR_CREATED = 0
679
+ - Swap is created, the user should now pay the provided lightning network invoice
680
+ - FromBTCLNSwapState.PR_PAID = 1
681
+ - Lightning network invoice payment was received (but cannot be settled by the counterparty yet)
682
+ - FromBTCLNSwapState.CLAIM_COMMITED = 2
683
+ - Claiming of the funds was initiated
684
+ - FromBTCLNSwapState.CLAIM_CLAIMED = 3
685
+ - Funds were successfully claimed & lightning network secret pre-image revealed, so the lightning network payment will settle now
686
+
687
+
688
+ #### Swap Bitcoin lightning network -> Starknet/EVM
689
+
690
+ Getting swap quote
691
+
692
+ ```typescript
693
+ const _exactIn = true; //exactIn = true, so we specify the input amount
694
+ const _amount = 10000n; //Amount in BTC base units - sats
695
+
696
+ const swap = await swapper.swap(
697
+ Tokens.BITCOIN.BTCLN, //Swap from BTC-LN
698
+ Tokens.STARKNET.STRK, //Into specified destination token
699
+ _amount,
700
+ _exactIn, //Whether we define an input or output amount
701
+ undefined, //Source address for the swap, not used for swaps from BTC-LN
702
+ signer.getAddress(), //Destination address
703
+ {
704
+ gasAmount: 1_000_000_000_000_000_000n //We can also request a gas drop on the destination chain (here requesting 1 STRK)
705
+ }
706
+ );
707
+
708
+ //Get the bitcoin lightning network invoice (the invoice contains pre-entered amount)
709
+ const receivingLightningInvoice: string = swap.getAddress();
710
+ //Get the URI hyperlink (contains the lightning network invoice) which can be displayed also as QR code
711
+ const qrCodeData: string = swap.getHyperlink();
712
+
713
+ //Get the amount required to pay and fee
714
+ const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
715
+ const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
716
+ const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
717
+
718
+ const output: string = swap.getOutput().toString(); //Total output amount
719
+
720
+ //Get swap expiration time
721
+ const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
722
+
723
+ //Get pricing info
724
+ const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
725
+ const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
726
+ const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
727
+ ```
728
+
729
+ Pay the displayed lightning network invoice from an external lightning network wallet
730
+
731
+ Wait for the payment to be received and settle the swap.
732
+
733
+ ```typescript
734
+ //Start listening to incoming lightning network payment
735
+ const success = await swap.waitForPayment();
736
+ if(!success) {
737
+ //Lightning network payment not received in time and quote expired!
738
+ return;
739
+ }
740
+
741
+ //Swap should get automatically claimed by the watchtowers, if not we can call swap.claim() to claim the swap ourselves
742
+ try {
743
+ await swap.waitTillClaimed(timeoutSignal(30*1000));
744
+ } catch (e) {
745
+ //Claim ourselves when automatic claim doesn't happen in 30 seconds
746
+ await swap.claim(starknetSigner);
747
+ }
748
+ ```
749
+
750
+ ##### Swap states
751
+
752
+ - FromBTCLNAutoSwapState.FAILED = -4
753
+ - If the claiming of the funds was initiated, but never concluded, the user will get his lightning network payment refunded
754
+ - FromBTCLNAutoSwapState.QUOTE_EXPIRED = -3
755
+ - Swap quote expired and cannot be executed anymore
756
+ - FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED = -2
757
+ - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
758
+ - FromBTCLNAutoSwapState.EXPIRED = -1
759
+ - Lightning network invoice expired, meaning the swap is expired
760
+ - FromBTCLNAutoSwapState.PR_CREATED = 0
761
+ - Swap is created, the user should now pay the provided lightning network invoice
762
+ - FromBTCLNAutoSwapState.PR_PAID = 1
763
+ - Lightning network invoice payment was received (but cannot be settled by the counterparty yet)
764
+ - FromBTCLNAutoSwapState.CLAIM_COMMITED = 2
765
+ - A swap HTLC was offered by the LP to the user
766
+ - FromBTCLNAutoSwapState.CLAIM_CLAIMED = 3
767
+ - Funds were successfully claimed & lightning network secret pre-image revealed, so the lightning network payment will settle now
768
+
769
+ ### LNURLs & readable lightning identifiers
770
+
771
+ 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)
772
+
773
+ This SDK supports:
774
+ * 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))
775
+ * LNURL-withdraw ([LUD-3](https://github.com/lnurl/luds/blob/luds/03.md))
776
+ * Static internet identifiers ([LUD-16](https://github.com/lnurl/luds/blob/luds/16.md))
777
+
778
+ You can parse LNURLs and lightning invoices automatically using the [Unified address parser](#unified-address-parser)
779
+
780
+ #### Differences
781
+
782
+ Lightning invoices:
783
+ * One time use only
784
+ * Need to have a fixed amount, therefore recipient has to set the amount
785
+ * Static and bounded expiration
786
+ * You can only pay to a lightning invoice, not withdraw funds from it
787
+
788
+ LNURLs & lightning identifiers:
789
+ * Reusable
790
+ * Programmable expiry
791
+ * Allows payer to set an amount
792
+ * Supports both, paying (LNURL-pay) and withdrawing (LNURL-withdraw)
793
+ * Possibility to attach a message/comment to a payment
794
+ * Receive a message/url as a result of the payment
795
+
796
+ #### Swap Smart chain -> Bitcoin lightning network
797
+
798
+ Getting swap quote
799
+
800
+ ```typescript
801
+ const _lnurlOrIdentifier: string = "lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkx6rfvdjx2ctvxyesuk0a27"; //Destination LNURL-pay or readable identifier
802
+ const _exactIn = false; //exactIn = false, so we specify the output amount
803
+ const _amount: bigint = 10000n; //Amount of satoshis to send (1 BTC = 100 000 000 satoshis)
804
+
805
+ //Create the swap: swapping SOL to Bitcoin lightning
806
+ const swap = await swapper.swap(
807
+ Tokens.SOLANA.SOL, //From specified source token
808
+ Tokens.BITCOIN.BTCLN, //Swap to BTC-LN
809
+ _amount, //Now we can specify an amount for a lightning network payment!
810
+ _exactIn, //We can also use exactIn=true here and set an amount in input token
811
+ solanaSigner.getAddress(), //Source address and smart chain signer
812
+ _lnurlOrIdentifier, //Destination of the swap
813
+ {
814
+ comment: "Hello world" //For LNURL-pay we can also pass a comment to the recipient
815
+ }
816
+ );
817
+
818
+ //Get the amount required to pay and fee
819
+ const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
820
+ const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
821
+ const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
822
+
823
+ const output: string = swap.getOutput().toString(); //Total output amount
824
+
825
+ //Get swap expiration time
826
+ const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
827
+
828
+ //Get pricing info
829
+ const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
830
+ const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
831
+ const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
832
+ ```
833
+
834
+ Initiating the swap
835
+
836
+ ```typescript
837
+ //Initiate and pay for the swap
838
+ await swap.commit(solanaSigner);
839
+ ```
840
+
841
+ or [sign and send transaction manually](#manually-signing-smart-chain-transactions)
842
+
843
+ Wait for the swap to execute, refund in case of failure
844
+
845
+ ```typescript
846
+ //Wait for the swap to conclude
847
+ const result: boolean = await swap.waitForPayment();
848
+ if(!result) {
849
+ //Swap failed, money can be refunded
850
+ await swap.refund(solanaSigner);
851
+ } else {
852
+ //Swap successful, we can get the lightning payment secret pre-image, which acts as a proof of payment
853
+ const lightningSecret = swap.getSecret();
854
+ //In case the LNURL contained a success action, we can read it now and display it to user
855
+ if(swap.hasSuccessAction()) {
856
+ //Contains a success action that should displayed to the user
857
+ const successMessage = swap.getSuccessAction();
858
+ const description: string = successMessage.description; //Description of the message
859
+ const text: (string | null) = successMessage.text; //Main text of the message
860
+ const url: (string | null) = successMessage.url; //URL link which should be displayed
861
+ }
862
+ }
863
+ ```
864
+
865
+ #### Swap Bitcoin lightning network -> Solana
866
+
867
+ 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.
868
+
869
+ Getting swap quote
870
+
871
+ ```typescript
872
+ const _lnurl: string = "lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkx6rfvdjx2ctvxyesuk0a27"; //Destination LNURL-pay or readable identifier
873
+ const _exactIn = true; //exactIn = true, so we specify the input amount
874
+ const _amount = 10000n; //Amount in BTC base units - sats
875
+
876
+ const swap = await swapper.swap(
877
+ Tokens.BITCOIN.BTCLN, //Swap from BTC-LN
878
+ Tokens.SOLANA.SOL, //Into specified destination token
879
+ _amount,
880
+ _exactIn, //Whether we define an input or output amount
881
+ _lnurl, //Source LNURL for the swap
882
+ signer.getAddress(), //Destination address
883
+ );
884
+
885
+ //Get the amount required to pay and fee
886
+ const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
887
+ const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
888
+ const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
889
+
890
+ const output: string = swap.getOutput().toString(); //Total output amount
891
+
892
+ //Get swap expiration time
893
+ const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
894
+
895
+ //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
896
+ const securityDeposit: string = swap.getSecurityDeposit().toString();
897
+
898
+ //Get pricing info
899
+ const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
900
+ const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
901
+ const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
902
+ ```
903
+
904
+ Wait for the payment to be received
905
+
906
+ ```typescript
907
+ //Start listening to incoming lightning network payment
908
+ const success = await swap.waitForPayment();
909
+ if(!success) {
910
+ //Lightning network payment not received in time and quote expired!
911
+ return;
912
+ }
913
+ ```
914
+
915
+ Claim the funds on the destination smart chains, this settles the swap and lightning network payment
916
+
917
+ ```typescript
918
+ try {
919
+ //Claim the swap funds - this will initiate 2 transactions
920
+ if(swap.canCommitAndClaimInOneShot()) {
921
+ //Some chains (e.g. Solana) support signing multiple transactions in one flow
922
+ await swap.commitAndClaim(solanaSigner);
923
+ } else {
924
+ //Other chains (e.g. Starknet) don't support signing multiple transaction in one flow, therefore you need to sign one-by-one
925
+ await swap.commit(starknetSigner);
926
+ await swap.claim(starknetSigner);
927
+ }
928
+ } catch(e) {
929
+ //Error occurred while waiting for payment
930
+ }
931
+ ```
932
+
933
+ or [sign and send transactions manually](#manually-signing-smart-chain-transactions)
934
+
935
+ #### Swap Bitcoin lightning network -> Starknet/EVM
936
+
937
+ Getting swap quote
938
+
939
+ ```typescript
940
+ const _lnurl: string = "lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkx6rfvdjx2ctvxyesuk0a27"; //Destination LNURL-pay or readable identifier
941
+ const _exactIn = true; //exactIn = true, so we specify the input amount
942
+ const _amount = 10000n; //Amount in BTC base units - sats
943
+
944
+ const swap = await swapper.swap(
945
+ Tokens.BITCOIN.BTCLN, //Swap from BTC-LN
946
+ Tokens.STARKNET.STRK, //Into specified destination token
947
+ _amount,
948
+ _exactIn, //Whether we define an input or output amount
949
+ _lnurl, //Source LNURL for the swap
950
+ signer.getAddress(), //Destination address
951
+ {
952
+ gasAmount: 1_000_000_000_000_000_000n //We can also request a gas drop on the destination chain (here requesting 1 STRK)
953
+ }
954
+ );
955
+
956
+ //Get the amount required to pay and fee
957
+ const input: string = swap.getInputWithoutFee().toString(); //Input amount excluding fees
958
+ const fee: string = swap.getFee().amountInSrcToken.toString(); //Fees paid on the output
959
+ const inputWithFees: string = swap.getInput().toString(); //Total amount paid including fees
960
+
961
+ const output: string = swap.getOutput().toString(); //Total output amount
962
+
963
+ //Get swap expiration time
964
+ const expiry: number = swap.getQuoteExpiry(); //Expiration time of the swap quote in UNIX milliseconds, swap needs to be initiated before this time
965
+
966
+ //Get pricing info
967
+ const swapPrice = swap.getPriceInfo().swapPrice; //Price of the current swap (excluding fees)
968
+ const marketPrice = swap.getPriceInfo().marketPrice; //Current market price
969
+ const difference = swap.getPriceInfo().difference; //Difference between the swap price & current market price
970
+ ```
971
+
972
+ Wait for the payment to be received & settle the swap.
973
+
974
+ ```typescript
975
+ //Start listening to incoming lightning network payment
976
+ const success = await swap.waitForPayment();
977
+ if(!success) {
978
+ //Lightning network payment not received in time and quote expired!
979
+ return;
980
+ }
981
+
982
+ //Swap should get automatically claimed by the watchtowers, if not we can call swap.claim() to claim the swap ourselves
983
+ try {
984
+ await swap.waitTillClaimed(timeoutSignal(30*1000));
985
+ } catch (e) {
986
+ //Claim ourselves when automatic claim doesn't happen in 30 seconds
987
+ await swap.claim(starknetSigner);
988
+ }
989
+ ```
990
+
991
+ ### Getting state of the swap
992
+
993
+ You can get the current state of the swap with:
994
+
995
+ ```typescript
996
+ const state = swap.getState();
997
+ ```
998
+
999
+ You can also set a listener to listen for swap state changes:
1000
+
1001
+ ```typescript
1002
+ swap.events.on("swapState", swap => {
1003
+ const newState = swap.getState();
1004
+ });
1005
+ ```
1006
+
1007
+ For the meaning of the states please refer to the "Swap state" section under each swap type.
1008
+
1009
+ ### Swap size limits
1010
+
1011
+ Swap sizes are limited by the LPs you are connected to, they are advertised in BTC terms by LPs during handshake
1012
+
1013
+ ```typescript
1014
+ const swapLimits = swapper.getSwapLimits(srcToken, dstToken);
1015
+ const inputMin = swapLimits.input.min;
1016
+ const inputMax = swapLimits.input.max;
1017
+ const outputMin = swapLimits.output.min;
1018
+ const outputMax = swapLimits.output.max;
1019
+ ```
1020
+
1021
+ 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.
1022
+
1023
+ ```typescript
1024
+ let swapLimits = swapper.getSwapLimits(Tokens.BITCOIN.BTC, Tokens.SOLANA.SOL);
1025
+ let inputMin = swapLimits.input.min; //Immediately available
1026
+ let inputMax = swapLimits.input.max; //Immediately available
1027
+ let outputMin = swapLimits.output.min; //Not available from the get-go
1028
+ let outputMax = swapLimits.output.max; //Not available from the get-go
1029
+
1030
+ //You can also listen to swap limit changes (optional)
1031
+ swapper.on("swapLimitsChanged", () => {
1032
+ //New limits available with swapper.getSwapLimits(srcToken, dstToken)
1033
+ //Useful in e.g. a react application where you want to dynamically set min/max swappable amount
1034
+ })
1035
+
1036
+ //Try to swap really small amount of SOL with exactOut swap
1037
+ try {
1038
+ const swap = await swapper.swap(
1039
+ Tokens.BITCOIN.BTC, //Swap from BTC
1040
+ Tokens.SOLANA.SOL, //Into specified destination token
1041
+ 1n, //1 lamport = 0.000000001 SOL
1042
+ false, //Whether we define an input or output amount
1043
+ undefined, //Source address for the swap, not used for swaps from BTC
1044
+ solanaSigner.getAddress() //Destination address
1045
+ );
1046
+ } catch (e) {
1047
+ //Fails with OutOfBoundsError
1048
+ }
1049
+
1050
+ swapLimits = swapper.getSwapLimits(Tokens.BITCOIN.BTC, Tokens.SOLANA.SOL);
1051
+ inputMin = swapLimits.input.min; //Immediately available
1052
+ inputMax = swapLimits.input.max; //Immediately available
1053
+ outputMin = swapLimits.output.min; //Now available due to failed quote
1054
+ outputMax = swapLimits.output.max; //Now available due to failed quote
1055
+ ```
1056
+
1057
+ ### Stored swaps
1058
+
1059
+ #### Get swap by ID
1060
+
1061
+ You can retrieve a swap by it's id, you can get an ID of the swap with
1062
+
1063
+ ```typescript
1064
+ const swapId = swap.getId();
1065
+ ```
1066
+
1067
+ And then later retrieve it from the storage
1068
+
1069
+ ```typescript
1070
+ const swap = await swapper.getSwapById(id);
1071
+ ```
1072
+
1073
+ #### Get refundable swaps
1074
+ You can refund the swaps in one of two cases:
1075
+ * In case intermediary is non-cooperative and goes offline, you can claim the funds from the swap contract back after some time.
1076
+ * In case intermediary tried to pay but was unsuccessful, so he sent you signed message with which you can refund now without waiting.
1077
+
1078
+ This call can be checked on every startup and periodically every few minutes.
1079
+ ```typescript
1080
+ //Get refundable swaps and refund them
1081
+ const refundableSolanaSwaps = await swapper.getRefundableSwaps("SOLANA", solanaSigner.getAddress());
1082
+ for(let swap of refundableSolanaSwaps) await swap.refund(solanaSigner);
1083
+ const refundableStarknetSwaps = await swapper.getRefundableSwaps("STARKNET", starknetSigner.getAddress());
1084
+ for(let swap of refundableStarknetSwaps) await swap.refund(starknetSigner);
1085
+ ```
1086
+
1087
+ #### Get claimable swaps
1088
+ 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.
1089
+
1090
+ ```typescript
1091
+ //Get the swaps
1092
+ const claimableSolanaSwaps = await solanaSwapper.getClaimableSwaps("SOLANA", solanaSigner.getAddress());
1093
+ //Claim all the claimable swaps
1094
+ for(let swap of claimableSolanaSwaps) {
1095
+ if(swap.canCommit()) await swap.commit(solanaSigner); //This is for Bitcoin (lightning) -> Smart chain swaps, where commit & claim procedure might be needed
1096
+ await swap.claim(solanaSigner);
1097
+ }
1098
+ //Get the swaps
1099
+ const claimableStarknetSwaps = await solanaSwapper.getClaimableSwaps("STARKNET", starknetSigner.getAddress());
1100
+ //Claim all the claimable swaps
1101
+ for(let swap of claimableStarknetSwaps) {
1102
+ if(swap.canCommit()) await swap.commit(starknetSigner); //This is for Bitcoin (lightning) -> Smart chain swaps, where commit & claim procedure might be needed
1103
+ await swap.claim(starknetSigner);
1104
+ }
1105
+ ```
1106
+
1107
+ ### Helpers
1108
+
1109
+ #### Getting wallet balances
1110
+
1111
+ The SDK also contains helper functions for getting the maximum spendable balance of wallets
1112
+
1113
+ ```typescript
1114
+ //Spendable balance of the starknet wallet address (discounting transaction fees)
1115
+ const strkBalance = await swapper.Utils.getSpendableBalance(starknetSigner, Tokens.STARKNET.STRK);
1116
+ //Spendable balance of the solana wallet address (discounting transaction fees)
1117
+ const solBalance = await swapper.Utils.getSpendableBalance(solanaSigner, Tokens.SOLANA.SOL);
1118
+ //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)
1119
+ const {balance: btcBalance, feeRate: btcFeeRate} = await swapper.Utils.getBitcoinSpendableBalance(bitcoinWalletAddress, "SOLANA");
1120
+ ```
1121
+
1122
+ #### Unified address parser
1123
+
1124
+ A common way for parsing all address formats supported by the SDK, automatically recognizes:
1125
+ - Bitcoin on-chain L1 address formats (p2pkh, p2wpkh, p2wsh, p2wsh, p2tr)
1126
+ - [BIP-21](https://en.bitcoin.it/wiki/BIP_0021) bitcoin payment URI
1127
+ - BOLT11 lightning network invoices
1128
+ - [LUD-6](https://github.com/lnurl/luds/blob/luds/06.md) LNURL-pay links
1129
+ - [LUD-3](https://github.com/lnurl/luds/blob/luds/03.md) LNURL-withdraw links
1130
+ - [LUD-16](https://github.com/lnurl/luds/blob/luds/16.md) Lightning static internet identifiers
1131
+ - Smart chain addresses (Solana, Starknet, etc.)
1132
+
1133
+ ```typescript
1134
+ const res = await swapper.Utils.parseAddress(address);
1135
+ switch(res.type) {
1136
+ case "BITCOIN":
1137
+ //Bitcoin on-chain L1 address or BIP-21 URI scheme with amount
1138
+ const btcAmount = res.amount;
1139
+ break;
1140
+ case "LIGHTNING":
1141
+ //BOLT11 lightning network invoice with pre-set amount
1142
+ const lnAmount = res.amount;
1143
+ break;
1144
+ case "LNURL":
1145
+ //LNURL payment or withdrawal link
1146
+ if(isLNURLWithdraw(res.lnurl)) {
1147
+ //LNURL-withdraw allowing withdrawals over the lightning network
1148
+ const lnurlWithdrawData: LNURLWithdraw = res.lnurl;
1149
+ const minWithdrawable = res.min; //Minimum payment amount
1150
+ const maxWithdrawable = res.max; //Maximum payment amount
1151
+ const fixedAmount = res.amount; //If res.min===res.max, an fixed amount is returned instead
1152
+ //Should show a UI allowing the user to choose an amount he wishes to withdraw
1153
+ }
1154
+ if(isLNURLPay(res.lnurl)) {
1155
+ //LNURL-pay or static lightning internet identifier allowing repeated payments over the lightning network
1156
+ const lnurlPayData: LNURLPay = res.lnurl;
1157
+ const minPayable = res.min; //Minimum payment amount
1158
+ const maxPayable = res.max; //Maximum payment amount
1159
+ const fixedAmount = res.amount; //If res.min===res.max, an fixed amount is returned instead
1160
+ const icon: (string | null) = res.lnurl.icon; //URL encoded icon that should be displayed on the UI
1161
+ const shortDescription: (string | null) = res.lnurl.shortDescription; //Short description of the payment
1162
+ const longDescription: (string | null) = res.lnurl.longDescription; //Long description of the payment
1163
+ const maxCommentLength: (number | 0) = res.lnurl.commentMaxLength; //Maximum allowed length of the payment message/comment (0 means no comment allowed)
1164
+ //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
1165
+ }
1166
+ break;
1167
+ default:
1168
+ //Addresses for smart chains
1169
+ break;
1170
+ }
1171
+ ```
1172
+
1173
+ ### Manually signing smart chain transactions
1174
+
1175
+ 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.:
1176
+ - commit() -> txsCommit()
1177
+ - claim() -> txsClaim()
1178
+ - commitAndClaim -> txsCommitAndClaim()
1179
+ - refund() -> txsRefund()
1180
+
1181
+ 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.:
1182
+
1183
+ - commit() -> waitTillCommited()
1184
+ - claim() -> waitTillClaimed()
1185
+ - commitAndClaim -> waitTillClaimed()
1186
+ - refund() -> waitTillRefunded()
1187
+
1188
+ ```typescript
1189
+ //Example for Solana
1190
+ const txns = await swap.txsCommit(); //Also works with txsClaim, txsRefund, txCommitAndClaim
1191
+ txns.forEach(val => val.tx.sign(...val.signers));
1192
+ const signedTransactions = await solanaSigner.wallet.signAllTransactions(txns.map(val => val.tx));
1193
+ for(let tx of signedTransactions) {
1194
+ const res = await solanaRpc.sendRawTransaction(tx.serialize());
1195
+ await solanaRpc.confirmTransaction(res);
1196
+ }
1197
+ await swap.waitTillCommited(); //Or other relevant waitTillClaimed, waitTillRefunded
1198
+
1199
+ //Example for Starknet
1200
+ const txns = await swap.txsCommit(); //Also works with txsClaim, txsRefund, txCommitAndClaim
1201
+ for(let tx of txns) {
1202
+ if(tx.type==="INVOKE") await starknetSigner.account.execute(tx.tx, tx.details);
1203
+ if(tx.type==="DEPLOY_ACCOUNT") await starknetSigner.account.deployAccount(tx.tx, tx.details);
1204
+ }
1205
+ await swap.waitTillCommited(); //Or other relevant waitTillClaimed, waitTillRefunded
1206
+
1207
+ //Example for EVM
1208
+ const txns = await swap.txsCommit(); //Also works with txsClaim, txsRefund, txCommitAndClaim
1209
+ for(let tx of txns) {
1210
+ await evmSigner.account.sendTransaction(tx);
1211
+ }
1212
+ await swap.waitTillCommited(); //Or other relevant waitTillClaimed, waitTillRefunded
1213
+ ```
1214
+
1215
+ ### Additional swapper options
1216
+
1217
+ You can further customize the swapper instance with these options, you can:
1218
+ - adjust the maximum accepted pricing difference from the LPs
1219
+ - use custom mempool.space instance
1220
+ - use custom pricing API
1221
+ - use own LP node for swaps
1222
+ - adjust HTTP request timeouts
1223
+ - add parameters to be sent with each LP request
1224
+
1225
+ ```typescript
1226
+ const swapper = Factory.newSwapper({
1227
+ ...
1228
+ //Additional optional options
1229
+ pricingFeeDifferencePPM: 20000n, //Maximum allowed pricing difference for quote (between swap & market price) in ppm (parts per million) (20000 == 2%)
1230
+ mempoolApi: new MempoolApi("<url to custom mempool.space instance>"), //Set the SDK to use a custom mempool.space instance instead of the public one
1231
+ getPriceFn: (tickers: string[], abortSignal?: AbortSignal) => customPricingApi.getUsdPriceForTickers(tickers) //Overrides the default pricing API engine with a custom price getter
1232
+
1233
+ intermediaryUrl: "<url to custom LP node>",
1234
+ registryUrl: "<url to custom LP node registry>",
1235
+
1236
+ getRequestTimeout: 10000, //Timeout in milliseconds for GET requests
1237
+ postRequestTimeout: 10000, //Timeout in milliseconds for POST requests
1238
+ defaultAdditionalParameters: {lpData: "Pls give gud price"}, //Additional request data sent to LPs
1239
+
1240
+ defaultTrustedIntermediaryUrl: "<url to custom LP node>" //LP node/intermediary to use for trusted gas swaps
1241
+ });
1242
+ ```