@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/LICENSE +201 -201
- package/README.md +501 -501
- package/dist/MultichainSwapper.d.ts +45 -45
- package/dist/MultichainSwapper.js +73 -70
- package/dist/SmartChainAssets.d.ts +54 -54
- package/dist/SmartChainAssets.js +50 -50
- package/dist/chains/ChainInitializer.d.ts +13 -13
- package/dist/chains/ChainInitializer.js +2 -2
- package/dist/chains/solana/SolanaChainInitializer.d.ts +41 -42
- package/dist/chains/solana/SolanaChainInitializer.js +60 -60
- package/dist/chains/solana/SolanaChains.d.ts +14 -16
- package/dist/chains/solana/SolanaChains.js +18 -20
- package/dist/example/BrowserExample.d.ts +1 -1
- package/dist/example/BrowserExample.js +104 -104
- package/dist/example/NodeJSExample.d.ts +1 -1
- package/dist/example/NodeJSExample.js +104 -104
- package/dist/index.d.ts +4 -4
- package/dist/index.js +20 -20
- package/package.json +32 -32
- package/src/MultichainSwapper.ts +145 -139
- package/src/SmartChainAssets.ts +57 -57
- package/src/chains/ChainInitializer.ts +16 -16
- package/src/chains/solana/SolanaChainInitializer.ts +99 -101
- package/src/chains/solana/SolanaChains.ts +16 -18
- package/src/example/BrowserExample.ts +120 -120
- package/src/example/NodeJSExample.ts +120 -120
- package/src/index.ts +4 -4
- package/dist/example/test.d.ts +0 -1
- package/dist/example/test.js +0 -28
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
|
+
```
|