@atomiqlabs/sdk 1.2.5 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,501 +1,501 @@
1
- # atomiqlabs SDK
2
-
3
- A typescript multichain client for atomiqlabs trustlesss cross-chain swaps.
4
-
5
- ## Installation
6
- ```
7
- npm install @atomiqlabs/sdk
8
- ```
9
-
10
- ## How to use?
11
-
12
- ### Preparations
13
-
14
- Set Solana RPC URL to use
15
-
16
- ```typescript
17
- const solanaRpc = "https://api.mainnet-beta.solana.com";
18
- ```
19
-
20
- #### Browser
21
-
22
- This uses browser's Indexed DB by default
23
-
24
- ```typescript
25
- const swapper: MultichainSwapper = new MultichainSwapper({
26
- chains: {
27
- SOLANA: {
28
- rpcUrl: solanaRpc
29
- }
30
- }
31
- });
32
- ```
33
-
34
- #### NodeJS
35
-
36
- For NodeJS we need to explicitly use filsystem storage
37
-
38
- ```typescript
39
- const swapper: MultichainSwapper = new MultichainSwapper({
40
- chains: {
41
- SOLANA: {
42
- rpcUrl: solanaRpc
43
- }
44
- },
45
- //The following line is important for running on backend node.js,
46
- // because the SDK by default uses browser's Indexed DB
47
- storageCtor: (name: string) => new FileSystemStorageManager(name)
48
- });
49
- ```
50
-
51
- ### Signer
52
-
53
- ```typescript
54
- //React, using solana wallet adapter
55
- const anchorWallet = useAnchorWallet();
56
- const wallet = new SolanaSigner(anchorWallet);
57
- ```
58
-
59
- or
60
-
61
- ```typescript
62
- //Creating a wallet from scratch
63
- const signer = Keypair.fromSecretKey(_privateKey); //Or Keypair.generate() to generate new one
64
- const wallet = new SolanaSigner(signer);
65
- ```
66
-
67
- ### Initialization
68
-
69
- Initialize the swapper
70
-
71
- ```typescript
72
- await swapper.init();
73
- ```
74
-
75
- Now we have the multichain swapper initialized
76
-
77
- ### Extract chain-specific swapper with signer
78
-
79
- 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.
80
-
81
- ```typescript
82
- const solanaSwapper = swapper.withChain("SOLANA").withSigner(signer);
83
- ```
84
-
85
- ### Bitcoin on-chain swaps
86
-
87
- #### Swap Solana -> Bitcoin on-chain
88
-
89
- Initiating & executing the swap.
90
-
91
- ```typescript
92
- const _exactIn = false; //exactIn = false, so we specify the output amount
93
- const _amount = new BN(10000); //Amount in BTC base units - sats
94
- const _address = "bc1qtw67hj77rt8zrkkg3jgngutu0yfgt9czjwusxt"; //BTC address of the recipient
95
-
96
- //Create the swap: swapping SOL to Bitcoin on-chain, receiving _amount of satoshis (smallest unit of bitcoin) to _address
97
- const swap = await solanaSwapper.create(
98
- Tokens.SOLANA.SOL,
99
- Tokens.BITCOIN.BTC,
100
- _amount,
101
- _exactIn,
102
- _address
103
- );
104
-
105
- //Get the amount required to pay and fee
106
- const amountToBePaid: string = swap.getInput().amount; //Human readable amount to be paid on the Solana side (including fee)
107
- const fee: string = swap.getFee().amountInSrcToken.amount; //Human readable swap fee paid on the Solana side (already included in the the above amount)
108
-
109
- //Get swap expiration time
110
- const expiry: number = swap.getExpiry(); //Expiration time of the swap in UNIX milliseconds, swap needs to be initiated before this time
111
-
112
- //Initiate and pay for the swap
113
- await swap.commit();
114
-
115
- //Wait for the swap to conclude
116
- const result: boolean = await swap.waitForPayment();
117
- if(!result) {
118
- //Swap failed, money can be refunded
119
- await swap.refund();
120
- } else {
121
- //Swap successful, we can get the bitcoin txId
122
- const bitcoinTxId = swap.getBitcoinTxId();
123
- }
124
- ```
125
-
126
- ##### Swap states
127
-
128
- - ToBTCSwapState.REFUNDED = -3
129
- - Swap failed and was successfully refunded
130
- - ToBTCSwapState.QUOTE_EXPIRED = -2
131
- - Swap quote expired and cannot be executed anymore
132
- - ToBTCSwapState.QUOTE_SOFT_EXPIRED = -1
133
- - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
134
- - ToBTCSwapState.CREATED = 0
135
- - Swap quote is created, waiting to be executed
136
- - ToBTCSwapState.COMMITED = 1,
137
- - Swap was initiated (init transaction sent)
138
- - ToBTCSwapState.SOFT_CLAIMED = 2,
139
- - Swap was processed by the counterparty but not yet claimed on-chain (bitcoin transaction was sent, but unconfirmed yet)
140
- - ToBTCSwapState.CLAIMED = 3
141
- - Swap was finished and funds were successfully claimed by the counterparty
142
- - ToBTCSwapState.REFUNDABLE = 4
143
- - Swap was initiated but counterparty failed to process it, the user can now refund his funds
144
-
145
- #### Swap Bitcoin on-chain -> Solana
146
-
147
- Initiating & executing the swap.
148
-
149
- ```typescript
150
- const _exactIn = true; //exactIn = true, so we specify the input amount
151
- const _amount = new BN(10000); //Amount in BTC base units - sats
152
-
153
- //Create the swap: swapping _amount of satoshis of Bitcoin on-chain to SOL
154
- const swap = await solanaSwapper.create(
155
- Tokens.BITCOIN.BTC,
156
- Tokens.SOLANA.SOL,
157
- _amount,
158
- _exactIn
159
- );
160
-
161
- //Get the amount required to pay, amount to be received and fee
162
- const amountToBePaidOnBitcoin: string = swap.getInput().amount; //Human readable amount of BTC that needs to be send to the BTC swap address
163
- const amountToBeReceivedOnSolana: string = swap.getOutput().amount; //Human readable amount SOL that will be received on Solana
164
- const fee: string = swap.getFee().amountInSrcToken.amount; //Human readable fee in BTC
165
-
166
- //Get swap offer expiration time
167
- const expiry: number = swap.getExpiry(); //Expiration time of the swap offer in UNIX milliseconds, swap needs to be initiated before this time
168
-
169
- //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
170
- const securityDeposit: string = swap.getSecurityDeposit().amount;
171
- //Get claimer bounty (Human readable amount of SOL reserved as a reward for watchtowers to claim the swap on your behalf)
172
- const claimerBounty: string = swap.getClaimerBounty().amount;
173
-
174
- //Once client is happy with swap offer, we can send a Solana transaction that initiates the swap by opening a bitcoin swap address
175
- await swap.commit();
176
-
177
- //Get the bitcoin address
178
- const receivingAddressOnBitcoin = swap.getAddress();
179
- //Get the QR code data (contains the address and amount)
180
- const qrCodeData = swap.getQrData(); //Data that can be displayed in the form of QR code
181
- //Get the bitcoin swap address timeout (in UNIX millis), a transaction needs to be made in under this time
182
- const expiryTime = swap.getTimeoutTime();
183
-
184
- try {
185
- //Wait for the payment to arrive
186
- await swap.waitForPayment(
187
- null, null,
188
- (
189
- txId: string, //Transaction ID of the received bitcoin transaction
190
- confirmations: number, //Current confirmations of the transaction
191
- targetConfirmations: number, //Required confirmations
192
- transactionETAms: number //Estimated in time (in milliseconds) until when the transaction will receive required amount of confirmations
193
- ) => {
194
- //Callback for transaction updates
195
- }
196
- );
197
- //Swap will get automatically claimed by the watchtowers
198
- await swap.waitTillClaimed();
199
- } catch(e) {
200
- //Error occurred while waiting for payment
201
- }
202
- ```
203
-
204
- ##### Swap states
205
-
206
- - FromBTCSwapState.EXPIRED = -3
207
- - Bitcoin swap address expired
208
- - FromBTCSwapState.QUOTE_EXPIRED = -2
209
- - Swap quote expired and cannot be executed anymore
210
- - FromBTCSwapState.QUOTE_SOFT_EXPIRED = -1
211
- - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
212
- - FromBTCSwapState.PR_CREATED = 0
213
- - Swap quote is created, waiting for the user to open a bitcoin swap address
214
- - FromBTCSwapState.CLAIM_COMMITED = 1
215
- - Bitcoin swap address is opened
216
- - FromBTCSwapState.BTC_TX_CONFIRMED = 2
217
- - Bitcoin transaction sending funds to the swap address is confirmed
218
- - FromBTCSwapState.CLAIM_CLAIMED = 3
219
- - Swap funds are claimed to the user's wallet
220
-
221
- ### Bitcoin lightning network swaps
222
-
223
- #### Swap Solana -> Bitcoin lightning network
224
-
225
- ```typescript
226
- //Destination lightning network invoice, amount needs to be part of the invoice!
227
- const _lightningInvoice = "lnbc10u1pj2q0g9pp5ejs6m677m39cznpzum7muruvh50ys93ln82p4j9ks2luqm56xxlshp52r2anlhddfa9ex9vpw9gstxujff8a0p8s3pzvua930js0kwfea6scqzzsxqyz5vqsp5073zskc5qfgp7lre0t6s8uexxxey80ax564hsjklfwfjq2ew0ewq9qyyssqvzmgs6f8mvuwgfa9uqxhtza07qem4yfhn9wwlpskccmuwplsqmh8pdy6c42kqdu8p73kky9lsnl40qha5396d8lpgn90y27ltfc5rfqqq59cya";
228
-
229
- //Create the swap: swapping SOL to Bitcoin lightning
230
- const swap = await solanaSwapper.create(
231
- Tokens.SOLANA.SOL,
232
- Tokens.BITCOIN.BTCLN,
233
- null,
234
- false,
235
- _lightningInvoice
236
- );
237
-
238
- //Get the amount required to pay and fee
239
- const amountToBePaid: string = swap.getInput().amount; //Human readable amount to be paid on the Solana side (including fee)
240
- const fee: string = swap.getFee().amountInSrcToken.amount; //Human readable swap fee paid on the Solana side (already included in the the above amount)
241
-
242
- //Get swap expiration time
243
- const expiry: number = swap.getExpiry(); //Expiration time of the swap in UNIX milliseconds, swap needs to be initiated before this time
244
-
245
- //Initiate and pay for the swap
246
- await swap.commit();
247
-
248
- //Wait for the swap to conclude
249
- const result: boolean = await swap.waitForPayment();
250
- if(!result) {
251
- //Swap failed, money can be refunded
252
- await swap.refund();
253
- } else {
254
- //Swap successful, we can get the lightning payment secret pre-image, which acts as a proof of payment
255
- const lightningSecret = swap.getSecret();
256
- }
257
- ```
258
-
259
- ##### Swap states
260
-
261
- - ToBTCSwapState.REFUNDED = -3
262
- - Swap failed and was successfully refunded
263
- - ToBTCSwapState.QUOTE_EXPIRED = -2
264
- - Swap quote expired and cannot be executed anymore
265
- - ToBTCSwapState.QUOTE_SOFT_EXPIRED = -1
266
- - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
267
- - ToBTCSwapState.CREATED = 0
268
- - Swap quote is created, waiting to be executed
269
- - ToBTCSwapState.COMMITED = 1,
270
- - Swap was initiated (init transaction sent)
271
- - ToBTCSwapState.SOFT_CLAIMED = 2,
272
- - Swap was processed by the counterparty but not yet claimed on-chain (lightning network payment secret was revealed)
273
- - ToBTCSwapState.CLAIMED = 3
274
- - Swap was finished and funds were successfully claimed by the counterparty
275
- - ToBTCSwapState.REFUNDABLE = 4
276
- - Swap was initiated but counterparty failed to process it, the user can now refund his funds
277
-
278
- #### Swap Bitcoin lightning network -> Solana
279
- ```typescript
280
- const _exactIn = true; //exactIn = true, so we specify the input amount
281
- const _amount = new BN(10000); //Amount in BTC base units - sats
282
-
283
- //Create the swap: swapping _amount of satoshis from Bitcoin lightning network to SOL
284
- const swap = await solanaSwapper.create(
285
- Tokens.BITCOIN.BTCLN,
286
- Tokens.SOLANA.SOL,
287
- _amount,
288
- _exactIn
289
- );
290
-
291
- //Get the bitcoin lightning network invoice (the invoice contains pre-entered amount)
292
- const receivingLightningInvoice: string = swap.getLightningInvoice();
293
- //Get the QR code (contains the lightning network invoice)
294
- const qrCodeData: string = swap.getQrData(); //Data that can be displayed in the form of QR code
295
-
296
- //Get the amount required to pay, amount to be received and fee
297
- const amountToBePaidOnBitcoin: string = swap.getInput().amount; //Human readable amount of BTC that needs to be send to the BTC swap address
298
- const amountToBeReceivedOnSolana: string = swap.getOutput().amount; //Human readable amount SOL that will be received on Solana
299
- const fee: string = swap.getFee().amountInSrcToken.amount; //Human readable fee in BTC
300
-
301
- try {
302
- //Wait for the lightning payment to arrive
303
- await swap.waitForPayment();
304
- //Claim the swap funds - this will initiate 2 Solana transactions
305
- await swap.commitAndClaim();
306
- } catch(e) {
307
- //Error occurred while waiting for payment
308
- }
309
- ```
310
-
311
- ##### Swap states
312
-
313
- - FromBTCLNSwapState.FAILED = -4
314
- - If the claiming of the funds was initiated, but never concluded, the user will get his lightning network payment refunded
315
- - FromBTCLNSwapState.QUOTE_EXPIRED = -3
316
- - Swap quote expired and cannot be executed anymore
317
- - FromBTCLNSwapState.QUOTE_SOFT_EXPIRED = -2
318
- - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
319
- - FromBTCLNSwapState.EXPIRED = -1
320
- - Lightning network invoice expired, meaning the swap is expired
321
- - FromBTCLNSwapState.PR_CREATED = 0
322
- - Swap is created, the user should now pay the provided lightning network invoice
323
- - FromBTCLNSwapState.PR_PAID = 1
324
- - Lightning network invoice payment was received (but cannot be settled by the counterparty yet)
325
- - FromBTCLNSwapState.CLAIM_COMMITED = 2
326
- - Claiming of the funds was initiated
327
- - FromBTCLNSwapState.CLAIM_CLAIMED = 3
328
- - Funds were successfully claimed & lightning network secret pre-image revealed, so the lightning network payment will settle now
329
-
330
- ### Getting state of the swap
331
-
332
- You can get the current state of the swap with:
333
-
334
- ```typescript
335
- const state = swap.getState();
336
- ```
337
-
338
- You can also set a listener to listen for swap state changes:
339
-
340
- ```typescript
341
- swap.events.on("swapState", swap => {
342
- const newState = swap.getState();
343
- });
344
- ```
345
-
346
- For the meaning of the states please refer to the "Swap state" section under each swap type.
347
-
348
- ### LNURLs & readable lightning identifiers
349
-
350
- 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)
351
-
352
- This SDK supports:
353
- * 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))
354
- * LNURL-withdraw ([LUD-3](https://github.com/lnurl/luds/blob/luds/03.md))
355
- * Static internet identifiers ([LUD-16](https://github.com/lnurl/luds/blob/luds/16.md))
356
-
357
- #### Differences
358
-
359
- Lightning invoices:
360
- * One time use only
361
- * Need to have a fixed amount, therefore recipient has to set the amount
362
- * Static and bounded expiration
363
- * You can only pay to a lightning invoice, not withdraw funds from it
364
-
365
- LNURLs & lightning identifiers:
366
- * Reusable
367
- * Programmable expiry
368
- * Allows payer to set an amount
369
- * Supports both, paying (LNURL-pay) and withdrawing (LNURL-withdraw)
370
- * Possibility to attach a message/comment to a payment
371
- * Receive a message/url as a result of the payment
372
-
373
- #### Helpers
374
-
375
- It is good practice to automatically distinguish between lightning network invoices & LNURLs and adjust the UI accordingly.
376
- Therefore there are a few helper functions to help with that:
377
- ```typescript
378
- const isLNInvoice: boolean = swapper.isValidLightningInvoice(_input); //Checks if the input is lightning network invoice
379
- const isLNURL: boolean = swapper.isValidLNURL(_input); //Checks if the input is LNURL or lightning identifier
380
- if(isLNURL) {
381
- //Get the type of the LNURL
382
- const result: (LNURLPay | LNURLWithdraw | null) = await swapper.getLNURLTypeAndData(_input);
383
- if(result.type==="pay") {
384
- const lnurlPayData: LNURLPay = result;
385
- const minPayable: BN = lnurlPayData.min; //Minimum payment amount in satoshis
386
- const maxPayable: BN = lnurlPayData.max; //Maximum payment amount in satoshis
387
- const icon: (string | null) = lnurlPayData.icon; //URL encoded icon that should be displayed on the UI
388
- const shortDescription: (string | null) = lnurlPayData.shortDescription; //Short description of the payment
389
- const longDescription: (string | null) = lnurlPayData.longDescription; //Long description of the payment
390
- const maxCommentLength: (number | 0) = lnurlPayData.commentMaxLength; //Maximum allowed length of the payment message/comment (0 means no comment allowed)
391
- //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
392
- }
393
- if(result.type==="withdraw") {
394
- const lnurlWithdrawData: LNURLWithdraw = result;
395
- const minWithdrawable: BN = lnurlWithdrawData.min;
396
- const maxWithdrawable: BN = lnurlWithdrawData.max;
397
- //Should show a UI allowing the user to choose an amount he wishes to withdraw
398
- }
399
- }
400
- ```
401
-
402
- #### Swap Solana -> Bitcoin lightning network
403
- ```typescript
404
- const _lnurlOrIdentifier: string = "lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkx6rfvdjx2ctvxyesuk0a27"; //Destination LNURL-pay or readable identifier
405
- const _exactIn = false; //exactIn = false, so we specify the output amount
406
- const _amount: BN = new BN(10000); //Amount of satoshis to send (1 BTC = 100 000 000 satoshis)
407
-
408
- //Create the swap: swapping SOL to Bitcoin lightning
409
- const swap = await solanaSwapper.create(
410
- Tokens.SOLANA.SOL,
411
- Tokens.BITCOIN.BTCLN,
412
- _amount,
413
- _exactIn,
414
- _lnurlOrIdentifier
415
- );
416
-
417
- //Get the amount required to pay and fee
418
- const amountToBePaid: string = swap.getInput().amount; //Human readable amount to be paid on the Solana side (including fee)
419
- const fee: string = swap.getFee().amountInSrcToken.amount; //Human readable swap fee paid on the Solana side (already included in the the above amount)
420
-
421
- //Get swap expiration time
422
- const expiry: number = swap.getExpiry(); //Expiration time of the swap in UNIX milliseconds, swap needs to be initiated before this time
423
-
424
- //Initiate and pay for the swap
425
- await swap.commit();
426
-
427
- //Wait for the swap to conclude
428
- const result: boolean = await swap.waitForPayment();
429
- if(!result) {
430
- //Swap failed, money can be refunded
431
- await swap.refund();
432
- } else {
433
- //Swap successful, we can get the lightning payment secret pre-image, which acts as a proof of payment
434
- const lightningSecret = swap.getSecret();
435
- //In case the LNURL contained a success action, we can read it now and display it to user
436
- if(swap.hasSuccessAction()) {
437
- //Contains a success action that should displayed to the user
438
- const successMessage = swap.getSuccessAction();
439
- const description: string = successMessage.description; //Description of the message
440
- const text: (string | null) = successMessage.text; //Main text of the message
441
- const url: (string | null) = successMessage.url; //URL link which should be displayed
442
- }
443
- }
444
- ```
445
-
446
- #### Swap Bitcoin lightning network -> Solana
447
- ```typescript
448
- const _lnurl: string = "lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkx6rfvdjx2ctvxyesuk0a27"; //Destination LNURL-pay or readable identifier
449
- const _exactIn = true; //exactIn = true, so we specify the input amount
450
- const _amount = new BN(10000); //Amount in BTC base units - sats
451
-
452
- //Create the swap: swapping _amount of satoshis from Bitcoin lightning network to SOL
453
- const swap = await solanaSwapper.create(
454
- Tokens.BITCOIN.BTCLN,
455
- Tokens.SOLANA.SOL,
456
- _amount,
457
- _exactIn,
458
- _lnurl
459
- );
460
-
461
- //Get the amount of BTC to be withdrawn from LNURL, amount to be received and fee
462
- const amountToBeWithdrawnOnBitcoin: string = swap.getInput().amount; //Human readable amount of BTC that will be withdrawn from the LNURL
463
- const amountToBeReceivedOnSolana: string = swap.getOutput().amount; //Human readable amount SOL that will be received on Solana
464
- const fee: string = swap.getFee().amountInSrcToken.amount; //Human readable fee in BTC
465
-
466
- try {
467
- //Submit the withdraw request & wait for the payment to arrive
468
- await swap.waitForPayment();
469
- //Claim the swap funds - this will initiate 2 Solana transactions
470
- await swap.commitAndClaim();
471
- } catch(e) {
472
- //Error occurred while waiting for payment
473
- }
474
- ```
475
-
476
- ### Get refundable swaps
477
- You can refund the swaps in one of two cases:
478
- * In case intermediary is non-cooperative and goes offline, you can claim the funds from the swap contract back after some time.
479
- * In case intermediary tried to pay but was unsuccessful, so he sent you signed message with which you can refund now without waiting.
480
-
481
- This call can be checked on every startup and periodically every few minutes.
482
- ```typescript
483
- //Get the swaps
484
- const refundableSwaps = await swapper.getRefundableSwaps();
485
- //Refund all the swaps
486
- for(let swap of refundableSwaps) {
487
- await swap.refund();
488
- }
489
- ```
490
-
491
- ### Get claimable swaps
492
- 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.
493
-
494
- ```typescript
495
- //Get the swaps
496
- const claimableSwaps = await swapper.getClaimableSwaps();
497
- //Claim all the claimable swaps
498
- for(let swap of claimableSwaps) {
499
- await swap.commitAndClaim();
500
- }
501
- ```
1
+ # atomiqlabs SDK
2
+
3
+ A typescript multichain client for atomiqlabs trustlesss cross-chain swaps.
4
+
5
+ ## Installation
6
+ ```
7
+ npm install @atomiqlabs/sdk
8
+ ```
9
+
10
+ ## How to use?
11
+
12
+ ### Preparations
13
+
14
+ Set Solana RPC URL to use
15
+
16
+ ```typescript
17
+ const solanaRpc = "https://api.mainnet-beta.solana.com";
18
+ ```
19
+
20
+ #### Browser
21
+
22
+ This uses browser's Indexed DB by default
23
+
24
+ ```typescript
25
+ const swapper: MultichainSwapper = new MultichainSwapper({
26
+ chains: {
27
+ SOLANA: {
28
+ rpcUrl: solanaRpc
29
+ }
30
+ }
31
+ });
32
+ ```
33
+
34
+ #### NodeJS
35
+
36
+ For NodeJS we need to explicitly use filsystem storage
37
+
38
+ ```typescript
39
+ const swapper: MultichainSwapper = new MultichainSwapper({
40
+ chains: {
41
+ SOLANA: {
42
+ rpcUrl: solanaRpc
43
+ }
44
+ },
45
+ //The following line is important for running on backend node.js,
46
+ // because the SDK by default uses browser's Indexed DB
47
+ storageCtor: (name: string) => new FileSystemStorageManager(name)
48
+ });
49
+ ```
50
+
51
+ ### Signer
52
+
53
+ ```typescript
54
+ //React, using solana wallet adapter
55
+ const anchorWallet = useAnchorWallet();
56
+ const wallet = new SolanaSigner(anchorWallet);
57
+ ```
58
+
59
+ or
60
+
61
+ ```typescript
62
+ //Creating a wallet from scratch
63
+ const signer = Keypair.fromSecretKey(_privateKey); //Or Keypair.generate() to generate new one
64
+ const wallet = new SolanaSigner(signer);
65
+ ```
66
+
67
+ ### Initialization
68
+
69
+ Initialize the swapper
70
+
71
+ ```typescript
72
+ await swapper.init();
73
+ ```
74
+
75
+ Now we have the multichain swapper initialized
76
+
77
+ ### Extract chain-specific swapper with signer
78
+
79
+ 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.
80
+
81
+ ```typescript
82
+ const solanaSwapper = swapper.withChain("SOLANA").withSigner(signer);
83
+ ```
84
+
85
+ ### Bitcoin on-chain swaps
86
+
87
+ #### Swap Solana -> Bitcoin on-chain
88
+
89
+ Initiating & executing the swap.
90
+
91
+ ```typescript
92
+ const _exactIn = false; //exactIn = false, so we specify the output amount
93
+ const _amount = new BN(10000); //Amount in BTC base units - sats
94
+ const _address = "bc1qtw67hj77rt8zrkkg3jgngutu0yfgt9czjwusxt"; //BTC address of the recipient
95
+
96
+ //Create the swap: swapping SOL to Bitcoin on-chain, receiving _amount of satoshis (smallest unit of bitcoin) to _address
97
+ const swap = await solanaSwapper.create(
98
+ Tokens.SOLANA.SOL,
99
+ Tokens.BITCOIN.BTC,
100
+ _amount,
101
+ _exactIn,
102
+ _address
103
+ );
104
+
105
+ //Get the amount required to pay and fee
106
+ const amountToBePaid: string = swap.getInput().amount; //Human readable amount to be paid on the Solana side (including fee)
107
+ const fee: string = swap.getFee().amountInSrcToken.amount; //Human readable swap fee paid on the Solana side (already included in the the above amount)
108
+
109
+ //Get swap expiration time
110
+ const expiry: number = swap.getExpiry(); //Expiration time of the swap in UNIX milliseconds, swap needs to be initiated before this time
111
+
112
+ //Initiate and pay for the swap
113
+ await swap.commit();
114
+
115
+ //Wait for the swap to conclude
116
+ const result: boolean = await swap.waitForPayment();
117
+ if(!result) {
118
+ //Swap failed, money can be refunded
119
+ await swap.refund();
120
+ } else {
121
+ //Swap successful, we can get the bitcoin txId
122
+ const bitcoinTxId = swap.getBitcoinTxId();
123
+ }
124
+ ```
125
+
126
+ ##### Swap states
127
+
128
+ - ToBTCSwapState.REFUNDED = -3
129
+ - Swap failed and was successfully refunded
130
+ - ToBTCSwapState.QUOTE_EXPIRED = -2
131
+ - Swap quote expired and cannot be executed anymore
132
+ - ToBTCSwapState.QUOTE_SOFT_EXPIRED = -1
133
+ - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
134
+ - ToBTCSwapState.CREATED = 0
135
+ - Swap quote is created, waiting to be executed
136
+ - ToBTCSwapState.COMMITED = 1,
137
+ - Swap was initiated (init transaction sent)
138
+ - ToBTCSwapState.SOFT_CLAIMED = 2,
139
+ - Swap was processed by the counterparty but not yet claimed on-chain (bitcoin transaction was sent, but unconfirmed yet)
140
+ - ToBTCSwapState.CLAIMED = 3
141
+ - Swap was finished and funds were successfully claimed by the counterparty
142
+ - ToBTCSwapState.REFUNDABLE = 4
143
+ - Swap was initiated but counterparty failed to process it, the user can now refund his funds
144
+
145
+ #### Swap Bitcoin on-chain -> Solana
146
+
147
+ Initiating & executing the swap.
148
+
149
+ ```typescript
150
+ const _exactIn = true; //exactIn = true, so we specify the input amount
151
+ const _amount = new BN(10000); //Amount in BTC base units - sats
152
+
153
+ //Create the swap: swapping _amount of satoshis of Bitcoin on-chain to SOL
154
+ const swap = await solanaSwapper.create(
155
+ Tokens.BITCOIN.BTC,
156
+ Tokens.SOLANA.SOL,
157
+ _amount,
158
+ _exactIn
159
+ );
160
+
161
+ //Get the amount required to pay, amount to be received and fee
162
+ const amountToBePaidOnBitcoin: string = swap.getInput().amount; //Human readable amount of BTC that needs to be send to the BTC swap address
163
+ const amountToBeReceivedOnSolana: string = swap.getOutput().amount; //Human readable amount SOL that will be received on Solana
164
+ const fee: string = swap.getFee().amountInSrcToken.amount; //Human readable fee in BTC
165
+
166
+ //Get swap offer expiration time
167
+ const expiry: number = swap.getExpiry(); //Expiration time of the swap offer in UNIX milliseconds, swap needs to be initiated before this time
168
+
169
+ //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
170
+ const securityDeposit: string = swap.getSecurityDeposit().amount;
171
+ //Get claimer bounty (Human readable amount of SOL reserved as a reward for watchtowers to claim the swap on your behalf)
172
+ const claimerBounty: string = swap.getClaimerBounty().amount;
173
+
174
+ //Once client is happy with swap offer, we can send a Solana transaction that initiates the swap by opening a bitcoin swap address
175
+ await swap.commit();
176
+
177
+ //Get the bitcoin address
178
+ const receivingAddressOnBitcoin = swap.getAddress();
179
+ //Get the QR code data (contains the address and amount)
180
+ const qrCodeData = swap.getQrData(); //Data that can be displayed in the form of QR code
181
+ //Get the bitcoin swap address timeout (in UNIX millis), a transaction needs to be made in under this time
182
+ const expiryTime = swap.getTimeoutTime();
183
+
184
+ try {
185
+ //Wait for the payment to arrive
186
+ await swap.waitForPayment(
187
+ null, null,
188
+ (
189
+ txId: string, //Transaction ID of the received bitcoin transaction
190
+ confirmations: number, //Current confirmations of the transaction
191
+ targetConfirmations: number, //Required confirmations
192
+ transactionETAms: number //Estimated in time (in milliseconds) until when the transaction will receive required amount of confirmations
193
+ ) => {
194
+ //Callback for transaction updates
195
+ }
196
+ );
197
+ //Swap will get automatically claimed by the watchtowers
198
+ await swap.waitTillClaimed();
199
+ } catch(e) {
200
+ //Error occurred while waiting for payment
201
+ }
202
+ ```
203
+
204
+ ##### Swap states
205
+
206
+ - FromBTCSwapState.EXPIRED = -3
207
+ - Bitcoin swap address expired
208
+ - FromBTCSwapState.QUOTE_EXPIRED = -2
209
+ - Swap quote expired and cannot be executed anymore
210
+ - FromBTCSwapState.QUOTE_SOFT_EXPIRED = -1
211
+ - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
212
+ - FromBTCSwapState.PR_CREATED = 0
213
+ - Swap quote is created, waiting for the user to open a bitcoin swap address
214
+ - FromBTCSwapState.CLAIM_COMMITED = 1
215
+ - Bitcoin swap address is opened
216
+ - FromBTCSwapState.BTC_TX_CONFIRMED = 2
217
+ - Bitcoin transaction sending funds to the swap address is confirmed
218
+ - FromBTCSwapState.CLAIM_CLAIMED = 3
219
+ - Swap funds are claimed to the user's wallet
220
+
221
+ ### Bitcoin lightning network swaps
222
+
223
+ #### Swap Solana -> Bitcoin lightning network
224
+
225
+ ```typescript
226
+ //Destination lightning network invoice, amount needs to be part of the invoice!
227
+ const _lightningInvoice = "lnbc10u1pj2q0g9pp5ejs6m677m39cznpzum7muruvh50ys93ln82p4j9ks2luqm56xxlshp52r2anlhddfa9ex9vpw9gstxujff8a0p8s3pzvua930js0kwfea6scqzzsxqyz5vqsp5073zskc5qfgp7lre0t6s8uexxxey80ax564hsjklfwfjq2ew0ewq9qyyssqvzmgs6f8mvuwgfa9uqxhtza07qem4yfhn9wwlpskccmuwplsqmh8pdy6c42kqdu8p73kky9lsnl40qha5396d8lpgn90y27ltfc5rfqqq59cya";
228
+
229
+ //Create the swap: swapping SOL to Bitcoin lightning
230
+ const swap = await solanaSwapper.create(
231
+ Tokens.SOLANA.SOL,
232
+ Tokens.BITCOIN.BTCLN,
233
+ null,
234
+ false,
235
+ _lightningInvoice
236
+ );
237
+
238
+ //Get the amount required to pay and fee
239
+ const amountToBePaid: string = swap.getInput().amount; //Human readable amount to be paid on the Solana side (including fee)
240
+ const fee: string = swap.getFee().amountInSrcToken.amount; //Human readable swap fee paid on the Solana side (already included in the the above amount)
241
+
242
+ //Get swap expiration time
243
+ const expiry: number = swap.getExpiry(); //Expiration time of the swap in UNIX milliseconds, swap needs to be initiated before this time
244
+
245
+ //Initiate and pay for the swap
246
+ await swap.commit();
247
+
248
+ //Wait for the swap to conclude
249
+ const result: boolean = await swap.waitForPayment();
250
+ if(!result) {
251
+ //Swap failed, money can be refunded
252
+ await swap.refund();
253
+ } else {
254
+ //Swap successful, we can get the lightning payment secret pre-image, which acts as a proof of payment
255
+ const lightningSecret = swap.getSecret();
256
+ }
257
+ ```
258
+
259
+ ##### Swap states
260
+
261
+ - ToBTCSwapState.REFUNDED = -3
262
+ - Swap failed and was successfully refunded
263
+ - ToBTCSwapState.QUOTE_EXPIRED = -2
264
+ - Swap quote expired and cannot be executed anymore
265
+ - ToBTCSwapState.QUOTE_SOFT_EXPIRED = -1
266
+ - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
267
+ - ToBTCSwapState.CREATED = 0
268
+ - Swap quote is created, waiting to be executed
269
+ - ToBTCSwapState.COMMITED = 1,
270
+ - Swap was initiated (init transaction sent)
271
+ - ToBTCSwapState.SOFT_CLAIMED = 2,
272
+ - Swap was processed by the counterparty but not yet claimed on-chain (lightning network payment secret was revealed)
273
+ - ToBTCSwapState.CLAIMED = 3
274
+ - Swap was finished and funds were successfully claimed by the counterparty
275
+ - ToBTCSwapState.REFUNDABLE = 4
276
+ - Swap was initiated but counterparty failed to process it, the user can now refund his funds
277
+
278
+ #### Swap Bitcoin lightning network -> Solana
279
+ ```typescript
280
+ const _exactIn = true; //exactIn = true, so we specify the input amount
281
+ const _amount = new BN(10000); //Amount in BTC base units - sats
282
+
283
+ //Create the swap: swapping _amount of satoshis from Bitcoin lightning network to SOL
284
+ const swap = await solanaSwapper.create(
285
+ Tokens.BITCOIN.BTCLN,
286
+ Tokens.SOLANA.SOL,
287
+ _amount,
288
+ _exactIn
289
+ );
290
+
291
+ //Get the bitcoin lightning network invoice (the invoice contains pre-entered amount)
292
+ const receivingLightningInvoice: string = swap.getLightningInvoice();
293
+ //Get the QR code (contains the lightning network invoice)
294
+ const qrCodeData: string = swap.getQrData(); //Data that can be displayed in the form of QR code
295
+
296
+ //Get the amount required to pay, amount to be received and fee
297
+ const amountToBePaidOnBitcoin: string = swap.getInput().amount; //Human readable amount of BTC that needs to be send to the BTC swap address
298
+ const amountToBeReceivedOnSolana: string = swap.getOutput().amount; //Human readable amount SOL that will be received on Solana
299
+ const fee: string = swap.getFee().amountInSrcToken.amount; //Human readable fee in BTC
300
+
301
+ try {
302
+ //Wait for the lightning payment to arrive
303
+ await swap.waitForPayment();
304
+ //Claim the swap funds - this will initiate 2 Solana transactions
305
+ await swap.commitAndClaim();
306
+ } catch(e) {
307
+ //Error occurred while waiting for payment
308
+ }
309
+ ```
310
+
311
+ ##### Swap states
312
+
313
+ - FromBTCLNSwapState.FAILED = -4
314
+ - If the claiming of the funds was initiated, but never concluded, the user will get his lightning network payment refunded
315
+ - FromBTCLNSwapState.QUOTE_EXPIRED = -3
316
+ - Swap quote expired and cannot be executed anymore
317
+ - FromBTCLNSwapState.QUOTE_SOFT_EXPIRED = -2
318
+ - Swap quote soft-expired (i.e. the quote probably expired, but if there is already an initialization transaction sent it might still succeed)
319
+ - FromBTCLNSwapState.EXPIRED = -1
320
+ - Lightning network invoice expired, meaning the swap is expired
321
+ - FromBTCLNSwapState.PR_CREATED = 0
322
+ - Swap is created, the user should now pay the provided lightning network invoice
323
+ - FromBTCLNSwapState.PR_PAID = 1
324
+ - Lightning network invoice payment was received (but cannot be settled by the counterparty yet)
325
+ - FromBTCLNSwapState.CLAIM_COMMITED = 2
326
+ - Claiming of the funds was initiated
327
+ - FromBTCLNSwapState.CLAIM_CLAIMED = 3
328
+ - Funds were successfully claimed & lightning network secret pre-image revealed, so the lightning network payment will settle now
329
+
330
+ ### Getting state of the swap
331
+
332
+ You can get the current state of the swap with:
333
+
334
+ ```typescript
335
+ const state = swap.getState();
336
+ ```
337
+
338
+ You can also set a listener to listen for swap state changes:
339
+
340
+ ```typescript
341
+ swap.events.on("swapState", swap => {
342
+ const newState = swap.getState();
343
+ });
344
+ ```
345
+
346
+ For the meaning of the states please refer to the "Swap state" section under each swap type.
347
+
348
+ ### LNURLs & readable lightning identifiers
349
+
350
+ 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)
351
+
352
+ This SDK supports:
353
+ * 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))
354
+ * LNURL-withdraw ([LUD-3](https://github.com/lnurl/luds/blob/luds/03.md))
355
+ * Static internet identifiers ([LUD-16](https://github.com/lnurl/luds/blob/luds/16.md))
356
+
357
+ #### Differences
358
+
359
+ Lightning invoices:
360
+ * One time use only
361
+ * Need to have a fixed amount, therefore recipient has to set the amount
362
+ * Static and bounded expiration
363
+ * You can only pay to a lightning invoice, not withdraw funds from it
364
+
365
+ LNURLs & lightning identifiers:
366
+ * Reusable
367
+ * Programmable expiry
368
+ * Allows payer to set an amount
369
+ * Supports both, paying (LNURL-pay) and withdrawing (LNURL-withdraw)
370
+ * Possibility to attach a message/comment to a payment
371
+ * Receive a message/url as a result of the payment
372
+
373
+ #### Helpers
374
+
375
+ It is good practice to automatically distinguish between lightning network invoices & LNURLs and adjust the UI accordingly.
376
+ Therefore there are a few helper functions to help with that:
377
+ ```typescript
378
+ const isLNInvoice: boolean = swapper.isValidLightningInvoice(_input); //Checks if the input is lightning network invoice
379
+ const isLNURL: boolean = swapper.isValidLNURL(_input); //Checks if the input is LNURL or lightning identifier
380
+ if(isLNURL) {
381
+ //Get the type of the LNURL
382
+ const result: (LNURLPay | LNURLWithdraw | null) = await swapper.getLNURLTypeAndData(_input);
383
+ if(result.type==="pay") {
384
+ const lnurlPayData: LNURLPay = result;
385
+ const minPayable: BN = lnurlPayData.min; //Minimum payment amount in satoshis
386
+ const maxPayable: BN = lnurlPayData.max; //Maximum payment amount in satoshis
387
+ const icon: (string | null) = lnurlPayData.icon; //URL encoded icon that should be displayed on the UI
388
+ const shortDescription: (string | null) = lnurlPayData.shortDescription; //Short description of the payment
389
+ const longDescription: (string | null) = lnurlPayData.longDescription; //Long description of the payment
390
+ const maxCommentLength: (number | 0) = lnurlPayData.commentMaxLength; //Maximum allowed length of the payment message/comment (0 means no comment allowed)
391
+ //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
392
+ }
393
+ if(result.type==="withdraw") {
394
+ const lnurlWithdrawData: LNURLWithdraw = result;
395
+ const minWithdrawable: BN = lnurlWithdrawData.min;
396
+ const maxWithdrawable: BN = lnurlWithdrawData.max;
397
+ //Should show a UI allowing the user to choose an amount he wishes to withdraw
398
+ }
399
+ }
400
+ ```
401
+
402
+ #### Swap Solana -> Bitcoin lightning network
403
+ ```typescript
404
+ const _lnurlOrIdentifier: string = "lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkx6rfvdjx2ctvxyesuk0a27"; //Destination LNURL-pay or readable identifier
405
+ const _exactIn = false; //exactIn = false, so we specify the output amount
406
+ const _amount: BN = new BN(10000); //Amount of satoshis to send (1 BTC = 100 000 000 satoshis)
407
+
408
+ //Create the swap: swapping SOL to Bitcoin lightning
409
+ const swap = await solanaSwapper.create(
410
+ Tokens.SOLANA.SOL,
411
+ Tokens.BITCOIN.BTCLN,
412
+ _amount,
413
+ _exactIn,
414
+ _lnurlOrIdentifier
415
+ );
416
+
417
+ //Get the amount required to pay and fee
418
+ const amountToBePaid: string = swap.getInput().amount; //Human readable amount to be paid on the Solana side (including fee)
419
+ const fee: string = swap.getFee().amountInSrcToken.amount; //Human readable swap fee paid on the Solana side (already included in the the above amount)
420
+
421
+ //Get swap expiration time
422
+ const expiry: number = swap.getExpiry(); //Expiration time of the swap in UNIX milliseconds, swap needs to be initiated before this time
423
+
424
+ //Initiate and pay for the swap
425
+ await swap.commit();
426
+
427
+ //Wait for the swap to conclude
428
+ const result: boolean = await swap.waitForPayment();
429
+ if(!result) {
430
+ //Swap failed, money can be refunded
431
+ await swap.refund();
432
+ } else {
433
+ //Swap successful, we can get the lightning payment secret pre-image, which acts as a proof of payment
434
+ const lightningSecret = swap.getSecret();
435
+ //In case the LNURL contained a success action, we can read it now and display it to user
436
+ if(swap.hasSuccessAction()) {
437
+ //Contains a success action that should displayed to the user
438
+ const successMessage = swap.getSuccessAction();
439
+ const description: string = successMessage.description; //Description of the message
440
+ const text: (string | null) = successMessage.text; //Main text of the message
441
+ const url: (string | null) = successMessage.url; //URL link which should be displayed
442
+ }
443
+ }
444
+ ```
445
+
446
+ #### Swap Bitcoin lightning network -> Solana
447
+ ```typescript
448
+ const _lnurl: string = "lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkx6rfvdjx2ctvxyesuk0a27"; //Destination LNURL-pay or readable identifier
449
+ const _exactIn = true; //exactIn = true, so we specify the input amount
450
+ const _amount = new BN(10000); //Amount in BTC base units - sats
451
+
452
+ //Create the swap: swapping _amount of satoshis from Bitcoin lightning network to SOL
453
+ const swap = await solanaSwapper.create(
454
+ Tokens.BITCOIN.BTCLN,
455
+ Tokens.SOLANA.SOL,
456
+ _amount,
457
+ _exactIn,
458
+ _lnurl
459
+ );
460
+
461
+ //Get the amount of BTC to be withdrawn from LNURL, amount to be received and fee
462
+ const amountToBeWithdrawnOnBitcoin: string = swap.getInput().amount; //Human readable amount of BTC that will be withdrawn from the LNURL
463
+ const amountToBeReceivedOnSolana: string = swap.getOutput().amount; //Human readable amount SOL that will be received on Solana
464
+ const fee: string = swap.getFee().amountInSrcToken.amount; //Human readable fee in BTC
465
+
466
+ try {
467
+ //Submit the withdraw request & wait for the payment to arrive
468
+ await swap.waitForPayment();
469
+ //Claim the swap funds - this will initiate 2 Solana transactions
470
+ await swap.commitAndClaim();
471
+ } catch(e) {
472
+ //Error occurred while waiting for payment
473
+ }
474
+ ```
475
+
476
+ ### Get refundable swaps
477
+ You can refund the swaps in one of two cases:
478
+ * In case intermediary is non-cooperative and goes offline, you can claim the funds from the swap contract back after some time.
479
+ * In case intermediary tried to pay but was unsuccessful, so he sent you signed message with which you can refund now without waiting.
480
+
481
+ This call can be checked on every startup and periodically every few minutes.
482
+ ```typescript
483
+ //Get the swaps
484
+ const refundableSwaps = await swapper.getRefundableSwaps();
485
+ //Refund all the swaps
486
+ for(let swap of refundableSwaps) {
487
+ await swap.refund();
488
+ }
489
+ ```
490
+
491
+ ### Get claimable swaps
492
+ 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.
493
+
494
+ ```typescript
495
+ //Get the swaps
496
+ const claimableSwaps = await swapper.getClaimableSwaps();
497
+ //Claim all the claimable swaps
498
+ for(let swap of claimableSwaps) {
499
+ await swap.commitAndClaim();
500
+ }
501
+ ```