@atomiqlabs/chain-solana 12.0.13 → 12.0.15

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.
Files changed (114) hide show
  1. package/LICENSE +201 -201
  2. package/dist/index.d.ts +29 -29
  3. package/dist/index.js +45 -45
  4. package/dist/solana/SolanaChainType.d.ts +11 -11
  5. package/dist/solana/SolanaChainType.js +2 -2
  6. package/dist/solana/SolanaChains.d.ts +20 -20
  7. package/dist/solana/SolanaChains.js +25 -25
  8. package/dist/solana/SolanaInitializer.d.ts +18 -18
  9. package/dist/solana/SolanaInitializer.js +63 -63
  10. package/dist/solana/btcrelay/SolanaBtcRelay.d.ts +228 -228
  11. package/dist/solana/btcrelay/SolanaBtcRelay.js +441 -441
  12. package/dist/solana/btcrelay/headers/SolanaBtcHeader.d.ts +29 -29
  13. package/dist/solana/btcrelay/headers/SolanaBtcHeader.js +34 -34
  14. package/dist/solana/btcrelay/headers/SolanaBtcStoredHeader.d.ts +46 -46
  15. package/dist/solana/btcrelay/headers/SolanaBtcStoredHeader.js +78 -78
  16. package/dist/solana/btcrelay/program/programIdl.json +671 -671
  17. package/dist/solana/chain/SolanaAction.d.ts +26 -26
  18. package/dist/solana/chain/SolanaAction.js +86 -86
  19. package/dist/solana/chain/SolanaChainInterface.d.ts +65 -65
  20. package/dist/solana/chain/SolanaChainInterface.js +125 -125
  21. package/dist/solana/chain/SolanaModule.d.ts +14 -14
  22. package/dist/solana/chain/SolanaModule.js +13 -13
  23. package/dist/solana/chain/modules/SolanaAddresses.d.ts +8 -8
  24. package/dist/solana/chain/modules/SolanaAddresses.js +22 -22
  25. package/dist/solana/chain/modules/SolanaBlocks.d.ts +28 -28
  26. package/dist/solana/chain/modules/SolanaBlocks.js +72 -72
  27. package/dist/solana/chain/modules/SolanaEvents.d.ts +68 -68
  28. package/dist/solana/chain/modules/SolanaEvents.js +238 -225
  29. package/dist/solana/chain/modules/SolanaFees.d.ts +121 -121
  30. package/dist/solana/chain/modules/SolanaFees.js +379 -379
  31. package/dist/solana/chain/modules/SolanaSignatures.d.ts +23 -23
  32. package/dist/solana/chain/modules/SolanaSignatures.js +39 -39
  33. package/dist/solana/chain/modules/SolanaSlots.d.ts +31 -31
  34. package/dist/solana/chain/modules/SolanaSlots.js +68 -68
  35. package/dist/solana/chain/modules/SolanaTokens.d.ts +136 -136
  36. package/dist/solana/chain/modules/SolanaTokens.js +248 -248
  37. package/dist/solana/chain/modules/SolanaTransactions.d.ts +124 -124
  38. package/dist/solana/chain/modules/SolanaTransactions.js +323 -323
  39. package/dist/solana/events/SolanaChainEvents.d.ts +88 -88
  40. package/dist/solana/events/SolanaChainEvents.js +256 -256
  41. package/dist/solana/events/SolanaChainEventsBrowser.d.ts +75 -75
  42. package/dist/solana/events/SolanaChainEventsBrowser.js +172 -172
  43. package/dist/solana/program/SolanaProgramBase.d.ts +40 -40
  44. package/dist/solana/program/SolanaProgramBase.js +43 -43
  45. package/dist/solana/program/SolanaProgramModule.d.ts +8 -8
  46. package/dist/solana/program/SolanaProgramModule.js +11 -11
  47. package/dist/solana/program/modules/SolanaProgramEvents.d.ts +53 -53
  48. package/dist/solana/program/modules/SolanaProgramEvents.js +114 -114
  49. package/dist/solana/swaps/SolanaSwapData.d.ts +71 -71
  50. package/dist/solana/swaps/SolanaSwapData.js +292 -292
  51. package/dist/solana/swaps/SolanaSwapModule.d.ts +10 -10
  52. package/dist/solana/swaps/SolanaSwapModule.js +11 -11
  53. package/dist/solana/swaps/SolanaSwapProgram.d.ts +224 -224
  54. package/dist/solana/swaps/SolanaSwapProgram.js +570 -570
  55. package/dist/solana/swaps/SwapTypeEnum.d.ts +11 -11
  56. package/dist/solana/swaps/SwapTypeEnum.js +42 -42
  57. package/dist/solana/swaps/modules/SolanaDataAccount.d.ts +94 -94
  58. package/dist/solana/swaps/modules/SolanaDataAccount.js +231 -231
  59. package/dist/solana/swaps/modules/SolanaLpVault.d.ts +71 -71
  60. package/dist/solana/swaps/modules/SolanaLpVault.js +173 -173
  61. package/dist/solana/swaps/modules/SwapClaim.d.ts +129 -129
  62. package/dist/solana/swaps/modules/SwapClaim.js +291 -291
  63. package/dist/solana/swaps/modules/SwapInit.d.ts +217 -217
  64. package/dist/solana/swaps/modules/SwapInit.js +519 -519
  65. package/dist/solana/swaps/modules/SwapRefund.d.ts +82 -82
  66. package/dist/solana/swaps/modules/SwapRefund.js +262 -262
  67. package/dist/solana/swaps/programIdl.json +945 -945
  68. package/dist/solana/swaps/programTypes.d.ts +943 -943
  69. package/dist/solana/swaps/programTypes.js +945 -945
  70. package/dist/solana/wallet/SolanaKeypairWallet.d.ts +9 -9
  71. package/dist/solana/wallet/SolanaKeypairWallet.js +33 -33
  72. package/dist/solana/wallet/SolanaSigner.d.ts +11 -11
  73. package/dist/solana/wallet/SolanaSigner.js +17 -17
  74. package/dist/utils/Utils.d.ts +53 -53
  75. package/dist/utils/Utils.js +170 -170
  76. package/package.json +41 -41
  77. package/src/index.ts +36 -36
  78. package/src/solana/SolanaChainType.ts +27 -27
  79. package/src/solana/SolanaChains.ts +23 -23
  80. package/src/solana/SolanaInitializer.ts +102 -102
  81. package/src/solana/btcrelay/SolanaBtcRelay.ts +589 -589
  82. package/src/solana/btcrelay/headers/SolanaBtcHeader.ts +57 -57
  83. package/src/solana/btcrelay/headers/SolanaBtcStoredHeader.ts +102 -102
  84. package/src/solana/btcrelay/program/programIdl.json +670 -670
  85. package/src/solana/chain/SolanaAction.ts +108 -108
  86. package/src/solana/chain/SolanaChainInterface.ts +192 -192
  87. package/src/solana/chain/SolanaModule.ts +20 -20
  88. package/src/solana/chain/modules/SolanaAddresses.ts +20 -20
  89. package/src/solana/chain/modules/SolanaBlocks.ts +78 -78
  90. package/src/solana/chain/modules/SolanaEvents.ts +270 -256
  91. package/src/solana/chain/modules/SolanaFees.ts +450 -450
  92. package/src/solana/chain/modules/SolanaSignatures.ts +39 -39
  93. package/src/solana/chain/modules/SolanaSlots.ts +82 -82
  94. package/src/solana/chain/modules/SolanaTokens.ts +307 -307
  95. package/src/solana/chain/modules/SolanaTransactions.ts +365 -365
  96. package/src/solana/events/SolanaChainEvents.ts +299 -299
  97. package/src/solana/events/SolanaChainEventsBrowser.ts +209 -209
  98. package/src/solana/program/SolanaProgramBase.ts +79 -79
  99. package/src/solana/program/SolanaProgramModule.ts +15 -15
  100. package/src/solana/program/modules/SolanaProgramEvents.ts +155 -155
  101. package/src/solana/swaps/SolanaSwapData.ts +430 -430
  102. package/src/solana/swaps/SolanaSwapModule.ts +16 -16
  103. package/src/solana/swaps/SolanaSwapProgram.ts +854 -854
  104. package/src/solana/swaps/SwapTypeEnum.ts +29 -29
  105. package/src/solana/swaps/modules/SolanaDataAccount.ts +307 -307
  106. package/src/solana/swaps/modules/SolanaLpVault.ts +215 -215
  107. package/src/solana/swaps/modules/SwapClaim.ts +389 -389
  108. package/src/solana/swaps/modules/SwapInit.ts +663 -663
  109. package/src/solana/swaps/modules/SwapRefund.ts +323 -323
  110. package/src/solana/swaps/programIdl.json +944 -944
  111. package/src/solana/swaps/programTypes.ts +1885 -1885
  112. package/src/solana/wallet/SolanaKeypairWallet.ts +36 -36
  113. package/src/solana/wallet/SolanaSigner.ts +24 -24
  114. package/src/utils/Utils.ts +180 -180
@@ -1,308 +1,308 @@
1
- import {SolanaModule} from "../SolanaModule";
2
- import {PublicKey, SystemProgram} from "@solana/web3.js";
3
- import {
4
- Account, createAssociatedTokenAccountInstruction,
5
- createCloseAccountInstruction, createSyncNativeInstruction, createTransferInstruction,
6
- getAccount, getAssociatedTokenAddressSync,
7
- TokenAccountNotFoundError
8
- } from "@solana/spl-token";
9
- import {SolanaTx} from "./SolanaTransactions";
10
- import {SolanaAction} from "../SolanaAction";
11
- import {tryWithRetries} from "../../../utils/Utils";
12
-
13
- export class SolanaTokens extends SolanaModule {
14
-
15
- public static readonly CUCosts = {
16
- WRAP_SOL: 10000,
17
- ATA_CLOSE: 10000,
18
- ATA_INIT: 40000,
19
- TRANSFER: 50000,
20
- TRANSFER_SOL: 5000
21
- };
22
-
23
- /**
24
- * Creates an ATA for a specific public key & token, the ATA creation is paid for by the underlying provider's
25
- * public key
26
- *
27
- * @param signer
28
- * @param publicKey public key address of the user for which to initiate the ATA
29
- * @param token token identification for which the ATA should be initialized
30
- * @param requiredAta optional required ata address to use, if the address doesn't match it returns null
31
- * @constructor
32
- */
33
- public InitAta(signer: PublicKey, publicKey: PublicKey, token: PublicKey, requiredAta?: PublicKey): SolanaAction | null {
34
- const ata = getAssociatedTokenAddressSync(token, publicKey, true);
35
- if(requiredAta!=null && !ata.equals(requiredAta)) return null;
36
- return new SolanaAction(
37
- signer,
38
- this.root,
39
- createAssociatedTokenAccountInstruction(
40
- signer,
41
- ata,
42
- publicKey,
43
- token
44
- ),
45
- SolanaTokens.CUCosts.ATA_INIT
46
- )
47
- }
48
-
49
- /**
50
- * Action for wrapping SOL to WSOL for a specific public key
51
- *
52
- * @param publicKey public key of the user for which to wrap the SOL
53
- * @param amount amount of SOL in lamports (smallest unit) to wrap
54
- * @param initAta whether we should also initialize the ATA before depositing SOL
55
- * @constructor
56
- */
57
- public Wrap(publicKey: PublicKey, amount: bigint, initAta: boolean): SolanaAction {
58
- const ata = getAssociatedTokenAddressSync(SolanaTokens.WSOL_ADDRESS, publicKey, true);
59
- const action = new SolanaAction(publicKey, this.root);
60
- if(initAta) action.addIx(
61
- createAssociatedTokenAccountInstruction(publicKey, ata, publicKey, SolanaTokens.WSOL_ADDRESS),
62
- SolanaTokens.CUCosts.ATA_INIT
63
- );
64
- action.addIx(
65
- SystemProgram.transfer({
66
- fromPubkey: publicKey,
67
- toPubkey: ata,
68
- lamports: amount
69
- }),
70
- SolanaTokens.CUCosts.WRAP_SOL
71
- );
72
- action.addIx(createSyncNativeInstruction(ata));
73
- return action;
74
- }
75
-
76
- /**
77
- * Action for unwrapping WSOL to SOL for a specific public key
78
- *
79
- * @param publicKey public key of the user for which to unwrap the sol
80
- * @constructor
81
- */
82
- public Unwrap(publicKey: PublicKey): SolanaAction {
83
- const ata = getAssociatedTokenAddressSync(SolanaTokens.WSOL_ADDRESS, publicKey, true);
84
- return new SolanaAction(
85
- publicKey,
86
- this.root,
87
- createCloseAccountInstruction(ata, publicKey, publicKey),
88
- SolanaTokens.CUCosts.ATA_CLOSE
89
- );
90
- }
91
-
92
- public static readonly WSOL_ADDRESS = new PublicKey("So11111111111111111111111111111111111111112");
93
- public static readonly SPL_ATA_RENT_EXEMPT = 2039280;
94
-
95
- /**
96
- * Action for transferring the native SOL token, uses provider's public key as a sender
97
- *
98
- * @param signer
99
- * @param recipient
100
- * @param amount
101
- * @constructor
102
- * @private
103
- */
104
- private SolTransfer(signer: PublicKey, recipient: PublicKey, amount: bigint): SolanaAction {
105
- return new SolanaAction(signer, this.root,
106
- SystemProgram.transfer({
107
- fromPubkey: signer,
108
- toPubkey: recipient,
109
- lamports: amount
110
- }),
111
- SolanaTokens.CUCosts.TRANSFER_SOL
112
- );
113
- }
114
-
115
- /**
116
- * Action for transferring the SPL token, uses provider's public key as a sender
117
- *
118
- * @param signer
119
- * @param recipient
120
- * @param token
121
- * @param amount
122
- * @constructor
123
- * @private
124
- */
125
- private Transfer(signer: PublicKey, recipient: PublicKey, token: PublicKey, amount: bigint): SolanaAction {
126
- const srcAta = getAssociatedTokenAddressSync(token, signer, true)
127
- const dstAta = getAssociatedTokenAddressSync(token, recipient, true);
128
- return new SolanaAction(signer, this.root,
129
- createTransferInstruction(
130
- srcAta,
131
- dstAta,
132
- signer,
133
- amount
134
- ),
135
- SolanaTokens.CUCosts.TRANSFER
136
- );
137
- }
138
-
139
- /**
140
- * Creates transactions for sending SOL (the native token)
141
- *
142
- * @param signer
143
- * @param amount amount of the SOL in lamports (smallest unit) to send
144
- * @param recipient recipient's address
145
- * @param feeRate fee rate to use for the transactions
146
- * @private
147
- */
148
- private async txsTransferSol(signer: PublicKey, amount: bigint, recipient: PublicKey, feeRate?: string): Promise<SolanaTx[]> {
149
- const wsolAta = getAssociatedTokenAddressSync(SolanaTokens.WSOL_ADDRESS, signer, true);
150
-
151
- const shouldUnwrap = await this.ataExists(wsolAta);
152
- const action = new SolanaAction(signer, this.root);
153
- if(shouldUnwrap) {
154
- feeRate = feeRate || await this.root.Fees.getFeeRate([signer, recipient, wsolAta]);
155
- action.add(this.Unwrap(signer));
156
- } else {
157
- feeRate = feeRate || await this.root.Fees.getFeeRate([signer, recipient]);
158
- }
159
- action.add(this.SolTransfer(signer, recipient, amount));
160
-
161
- this.logger.debug("txsTransferSol(): transfer native solana TX created, recipient: "+recipient.toString()+
162
- " amount: "+amount.toString(10)+" unwrapping: "+shouldUnwrap);
163
-
164
- return [await action.tx(feeRate)];
165
- }
166
-
167
- /**
168
- * Creates transactions for sending the over the tokens
169
- *
170
- * @param signer
171
- * @param token token to send
172
- * @param amount amount of the token to send
173
- * @param recipient recipient's address
174
- * @param feeRate fee rate to use for the transactions
175
- * @private
176
- */
177
- private async txsTransferTokens(signer: PublicKey, token: PublicKey, amount: bigint, recipient: PublicKey, feeRate?: string) {
178
- const srcAta = getAssociatedTokenAddressSync(token, signer, true);
179
- const dstAta = getAssociatedTokenAddressSync(token, recipient, true);
180
-
181
- feeRate = feeRate || await this.root.Fees.getFeeRate([signer, srcAta, dstAta]);
182
-
183
- const initAta = !await this.ataExists(dstAta);
184
- const action = new SolanaAction(signer, this.root);
185
- if(initAta) {
186
- action.add(this.InitAta(signer, recipient, token));
187
- }
188
- action.add(this.Transfer(signer, recipient, token, amount));
189
-
190
- this.logger.debug("txsTransferTokens(): transfer TX created, recipient: "+recipient.toString()+
191
- " token: "+token.toString()+ " amount: "+amount.toString(10)+" initAta: "+initAta);
192
-
193
- return [await action.tx(feeRate)];
194
- }
195
-
196
- ///////////////////
197
- //// Tokens
198
- /**
199
- * Checks if the provided string is a valid solana token
200
- *
201
- * @param token
202
- */
203
- public isValidToken(token: string) {
204
- try {
205
- new PublicKey(token);
206
- return true;
207
- } catch (e) {
208
- return false;
209
- }
210
- }
211
-
212
- /**
213
- * Returns the specific ATA or null if it doesn't exist
214
- *
215
- * @param ata
216
- */
217
- public getATAOrNull(ata: PublicKey): Promise<Account | null> {
218
- return getAccount(this.connection, ata).catch(e => {
219
- if(e instanceof TokenAccountNotFoundError) return null;
220
- throw e;
221
- });
222
- }
223
-
224
- /**
225
- * Checks whether the specific ATA exists, uses tryWithRetries so retries on failure
226
- *
227
- * @param ata
228
- */
229
- public async ataExists(ata: PublicKey) {
230
- const account = await tryWithRetries<Account>(
231
- () => this.getATAOrNull(ata),
232
- this.retryPolicy
233
- );
234
- return account!=null;
235
- }
236
-
237
- /**
238
- * Returns the rent exempt deposit required to initiate the ATA
239
- */
240
- public getATARentExemptLamports(): Promise<bigint> {
241
- return Promise.resolve(BigInt(SolanaTokens.SPL_ATA_RENT_EXEMPT));
242
- }
243
-
244
- /**
245
- * Returns the token balance of the public key
246
- *
247
- * @param publicKey
248
- * @param token
249
- */
250
- public async getTokenBalance(publicKey: PublicKey, token: PublicKey): Promise<{balance: bigint, ataExists: boolean}> {
251
- const ata: PublicKey = getAssociatedTokenAddressSync(token, publicKey, true);
252
- const [ataAccount, balance] = await Promise.all<[Promise<Account>, Promise<number>]>([
253
- this.getATAOrNull(ata),
254
- (token!=null && token.equals(SolanaTokens.WSOL_ADDRESS)) ? this.connection.getBalance(publicKey) : Promise.resolve(null)
255
- ]);
256
-
257
- let ataExists: boolean = ataAccount!=null;
258
- let sum: bigint = 0n;
259
- if(ataExists) {
260
- sum += ataAccount.amount;
261
- }
262
-
263
- if(balance!=null) {
264
- let balanceLamports: bigint = BigInt(balance);
265
- if(!ataExists) balanceLamports = balanceLamports - await this.getATARentExemptLamports();
266
- if(balanceLamports >= 0n) sum += balanceLamports;
267
- }
268
-
269
- this.logger.debug("getTokenBalance(): token balance fetched, token: "+token.toString()+
270
- " address: "+publicKey.toString()+" amount: "+sum.toString());
271
-
272
- return {balance: sum, ataExists};
273
- }
274
-
275
- /**
276
- * Returns the native currency address, we use WSOL address as placeholder for SOL
277
- */
278
- public getNativeCurrencyAddress(): PublicKey {
279
- return SolanaTokens.WSOL_ADDRESS;
280
- }
281
-
282
- /**
283
- * Parses string base58 representation of the token address to a PublicKey object
284
- * @param address
285
- */
286
- public toTokenAddress(address: string): PublicKey {
287
- return new PublicKey(address);
288
- }
289
-
290
- ///////////////////
291
- //// Transfers
292
- /**
293
- * Create transactions for sending a specific token to a destination address
294
- *
295
- * @param signer
296
- * @param token token to use for the transfer
297
- * @param amount amount of token in base units to transfer
298
- * @param dstAddress destination address of the recipient
299
- * @param feeRate fee rate to use for the transaction
300
- */
301
- public txsTransfer(signer:PublicKey, token: PublicKey, amount: bigint, dstAddress: PublicKey, feeRate?: string): Promise<SolanaTx[]> {
302
- if(SolanaTokens.WSOL_ADDRESS.equals(token)) {
303
- return this.txsTransferSol(signer, amount, dstAddress, feeRate);
304
- }
305
- return this.txsTransferTokens(signer, token, amount, dstAddress, feeRate);
306
- }
307
-
1
+ import {SolanaModule} from "../SolanaModule";
2
+ import {PublicKey, SystemProgram} from "@solana/web3.js";
3
+ import {
4
+ Account, createAssociatedTokenAccountInstruction,
5
+ createCloseAccountInstruction, createSyncNativeInstruction, createTransferInstruction,
6
+ getAccount, getAssociatedTokenAddressSync,
7
+ TokenAccountNotFoundError
8
+ } from "@solana/spl-token";
9
+ import {SolanaTx} from "./SolanaTransactions";
10
+ import {SolanaAction} from "../SolanaAction";
11
+ import {tryWithRetries} from "../../../utils/Utils";
12
+
13
+ export class SolanaTokens extends SolanaModule {
14
+
15
+ public static readonly CUCosts = {
16
+ WRAP_SOL: 10000,
17
+ ATA_CLOSE: 10000,
18
+ ATA_INIT: 40000,
19
+ TRANSFER: 50000,
20
+ TRANSFER_SOL: 5000
21
+ };
22
+
23
+ /**
24
+ * Creates an ATA for a specific public key & token, the ATA creation is paid for by the underlying provider's
25
+ * public key
26
+ *
27
+ * @param signer
28
+ * @param publicKey public key address of the user for which to initiate the ATA
29
+ * @param token token identification for which the ATA should be initialized
30
+ * @param requiredAta optional required ata address to use, if the address doesn't match it returns null
31
+ * @constructor
32
+ */
33
+ public InitAta(signer: PublicKey, publicKey: PublicKey, token: PublicKey, requiredAta?: PublicKey): SolanaAction | null {
34
+ const ata = getAssociatedTokenAddressSync(token, publicKey, true);
35
+ if(requiredAta!=null && !ata.equals(requiredAta)) return null;
36
+ return new SolanaAction(
37
+ signer,
38
+ this.root,
39
+ createAssociatedTokenAccountInstruction(
40
+ signer,
41
+ ata,
42
+ publicKey,
43
+ token
44
+ ),
45
+ SolanaTokens.CUCosts.ATA_INIT
46
+ )
47
+ }
48
+
49
+ /**
50
+ * Action for wrapping SOL to WSOL for a specific public key
51
+ *
52
+ * @param publicKey public key of the user for which to wrap the SOL
53
+ * @param amount amount of SOL in lamports (smallest unit) to wrap
54
+ * @param initAta whether we should also initialize the ATA before depositing SOL
55
+ * @constructor
56
+ */
57
+ public Wrap(publicKey: PublicKey, amount: bigint, initAta: boolean): SolanaAction {
58
+ const ata = getAssociatedTokenAddressSync(SolanaTokens.WSOL_ADDRESS, publicKey, true);
59
+ const action = new SolanaAction(publicKey, this.root);
60
+ if(initAta) action.addIx(
61
+ createAssociatedTokenAccountInstruction(publicKey, ata, publicKey, SolanaTokens.WSOL_ADDRESS),
62
+ SolanaTokens.CUCosts.ATA_INIT
63
+ );
64
+ action.addIx(
65
+ SystemProgram.transfer({
66
+ fromPubkey: publicKey,
67
+ toPubkey: ata,
68
+ lamports: amount
69
+ }),
70
+ SolanaTokens.CUCosts.WRAP_SOL
71
+ );
72
+ action.addIx(createSyncNativeInstruction(ata));
73
+ return action;
74
+ }
75
+
76
+ /**
77
+ * Action for unwrapping WSOL to SOL for a specific public key
78
+ *
79
+ * @param publicKey public key of the user for which to unwrap the sol
80
+ * @constructor
81
+ */
82
+ public Unwrap(publicKey: PublicKey): SolanaAction {
83
+ const ata = getAssociatedTokenAddressSync(SolanaTokens.WSOL_ADDRESS, publicKey, true);
84
+ return new SolanaAction(
85
+ publicKey,
86
+ this.root,
87
+ createCloseAccountInstruction(ata, publicKey, publicKey),
88
+ SolanaTokens.CUCosts.ATA_CLOSE
89
+ );
90
+ }
91
+
92
+ public static readonly WSOL_ADDRESS = new PublicKey("So11111111111111111111111111111111111111112");
93
+ public static readonly SPL_ATA_RENT_EXEMPT = 2039280;
94
+
95
+ /**
96
+ * Action for transferring the native SOL token, uses provider's public key as a sender
97
+ *
98
+ * @param signer
99
+ * @param recipient
100
+ * @param amount
101
+ * @constructor
102
+ * @private
103
+ */
104
+ private SolTransfer(signer: PublicKey, recipient: PublicKey, amount: bigint): SolanaAction {
105
+ return new SolanaAction(signer, this.root,
106
+ SystemProgram.transfer({
107
+ fromPubkey: signer,
108
+ toPubkey: recipient,
109
+ lamports: amount
110
+ }),
111
+ SolanaTokens.CUCosts.TRANSFER_SOL
112
+ );
113
+ }
114
+
115
+ /**
116
+ * Action for transferring the SPL token, uses provider's public key as a sender
117
+ *
118
+ * @param signer
119
+ * @param recipient
120
+ * @param token
121
+ * @param amount
122
+ * @constructor
123
+ * @private
124
+ */
125
+ private Transfer(signer: PublicKey, recipient: PublicKey, token: PublicKey, amount: bigint): SolanaAction {
126
+ const srcAta = getAssociatedTokenAddressSync(token, signer, true)
127
+ const dstAta = getAssociatedTokenAddressSync(token, recipient, true);
128
+ return new SolanaAction(signer, this.root,
129
+ createTransferInstruction(
130
+ srcAta,
131
+ dstAta,
132
+ signer,
133
+ amount
134
+ ),
135
+ SolanaTokens.CUCosts.TRANSFER
136
+ );
137
+ }
138
+
139
+ /**
140
+ * Creates transactions for sending SOL (the native token)
141
+ *
142
+ * @param signer
143
+ * @param amount amount of the SOL in lamports (smallest unit) to send
144
+ * @param recipient recipient's address
145
+ * @param feeRate fee rate to use for the transactions
146
+ * @private
147
+ */
148
+ private async txsTransferSol(signer: PublicKey, amount: bigint, recipient: PublicKey, feeRate?: string): Promise<SolanaTx[]> {
149
+ const wsolAta = getAssociatedTokenAddressSync(SolanaTokens.WSOL_ADDRESS, signer, true);
150
+
151
+ const shouldUnwrap = await this.ataExists(wsolAta);
152
+ const action = new SolanaAction(signer, this.root);
153
+ if(shouldUnwrap) {
154
+ feeRate = feeRate || await this.root.Fees.getFeeRate([signer, recipient, wsolAta]);
155
+ action.add(this.Unwrap(signer));
156
+ } else {
157
+ feeRate = feeRate || await this.root.Fees.getFeeRate([signer, recipient]);
158
+ }
159
+ action.add(this.SolTransfer(signer, recipient, amount));
160
+
161
+ this.logger.debug("txsTransferSol(): transfer native solana TX created, recipient: "+recipient.toString()+
162
+ " amount: "+amount.toString(10)+" unwrapping: "+shouldUnwrap);
163
+
164
+ return [await action.tx(feeRate)];
165
+ }
166
+
167
+ /**
168
+ * Creates transactions for sending the over the tokens
169
+ *
170
+ * @param signer
171
+ * @param token token to send
172
+ * @param amount amount of the token to send
173
+ * @param recipient recipient's address
174
+ * @param feeRate fee rate to use for the transactions
175
+ * @private
176
+ */
177
+ private async txsTransferTokens(signer: PublicKey, token: PublicKey, amount: bigint, recipient: PublicKey, feeRate?: string) {
178
+ const srcAta = getAssociatedTokenAddressSync(token, signer, true);
179
+ const dstAta = getAssociatedTokenAddressSync(token, recipient, true);
180
+
181
+ feeRate = feeRate || await this.root.Fees.getFeeRate([signer, srcAta, dstAta]);
182
+
183
+ const initAta = !await this.ataExists(dstAta);
184
+ const action = new SolanaAction(signer, this.root);
185
+ if(initAta) {
186
+ action.add(this.InitAta(signer, recipient, token));
187
+ }
188
+ action.add(this.Transfer(signer, recipient, token, amount));
189
+
190
+ this.logger.debug("txsTransferTokens(): transfer TX created, recipient: "+recipient.toString()+
191
+ " token: "+token.toString()+ " amount: "+amount.toString(10)+" initAta: "+initAta);
192
+
193
+ return [await action.tx(feeRate)];
194
+ }
195
+
196
+ ///////////////////
197
+ //// Tokens
198
+ /**
199
+ * Checks if the provided string is a valid solana token
200
+ *
201
+ * @param token
202
+ */
203
+ public isValidToken(token: string) {
204
+ try {
205
+ new PublicKey(token);
206
+ return true;
207
+ } catch (e) {
208
+ return false;
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Returns the specific ATA or null if it doesn't exist
214
+ *
215
+ * @param ata
216
+ */
217
+ public getATAOrNull(ata: PublicKey): Promise<Account | null> {
218
+ return getAccount(this.connection, ata).catch(e => {
219
+ if(e instanceof TokenAccountNotFoundError) return null;
220
+ throw e;
221
+ });
222
+ }
223
+
224
+ /**
225
+ * Checks whether the specific ATA exists, uses tryWithRetries so retries on failure
226
+ *
227
+ * @param ata
228
+ */
229
+ public async ataExists(ata: PublicKey) {
230
+ const account = await tryWithRetries<Account>(
231
+ () => this.getATAOrNull(ata),
232
+ this.retryPolicy
233
+ );
234
+ return account!=null;
235
+ }
236
+
237
+ /**
238
+ * Returns the rent exempt deposit required to initiate the ATA
239
+ */
240
+ public getATARentExemptLamports(): Promise<bigint> {
241
+ return Promise.resolve(BigInt(SolanaTokens.SPL_ATA_RENT_EXEMPT));
242
+ }
243
+
244
+ /**
245
+ * Returns the token balance of the public key
246
+ *
247
+ * @param publicKey
248
+ * @param token
249
+ */
250
+ public async getTokenBalance(publicKey: PublicKey, token: PublicKey): Promise<{balance: bigint, ataExists: boolean}> {
251
+ const ata: PublicKey = getAssociatedTokenAddressSync(token, publicKey, true);
252
+ const [ataAccount, balance] = await Promise.all<[Promise<Account>, Promise<number>]>([
253
+ this.getATAOrNull(ata),
254
+ (token!=null && token.equals(SolanaTokens.WSOL_ADDRESS)) ? this.connection.getBalance(publicKey) : Promise.resolve(null)
255
+ ]);
256
+
257
+ let ataExists: boolean = ataAccount!=null;
258
+ let sum: bigint = 0n;
259
+ if(ataExists) {
260
+ sum += ataAccount.amount;
261
+ }
262
+
263
+ if(balance!=null) {
264
+ let balanceLamports: bigint = BigInt(balance);
265
+ if(!ataExists) balanceLamports = balanceLamports - await this.getATARentExemptLamports();
266
+ if(balanceLamports >= 0n) sum += balanceLamports;
267
+ }
268
+
269
+ this.logger.debug("getTokenBalance(): token balance fetched, token: "+token.toString()+
270
+ " address: "+publicKey.toString()+" amount: "+sum.toString());
271
+
272
+ return {balance: sum, ataExists};
273
+ }
274
+
275
+ /**
276
+ * Returns the native currency address, we use WSOL address as placeholder for SOL
277
+ */
278
+ public getNativeCurrencyAddress(): PublicKey {
279
+ return SolanaTokens.WSOL_ADDRESS;
280
+ }
281
+
282
+ /**
283
+ * Parses string base58 representation of the token address to a PublicKey object
284
+ * @param address
285
+ */
286
+ public toTokenAddress(address: string): PublicKey {
287
+ return new PublicKey(address);
288
+ }
289
+
290
+ ///////////////////
291
+ //// Transfers
292
+ /**
293
+ * Create transactions for sending a specific token to a destination address
294
+ *
295
+ * @param signer
296
+ * @param token token to use for the transfer
297
+ * @param amount amount of token in base units to transfer
298
+ * @param dstAddress destination address of the recipient
299
+ * @param feeRate fee rate to use for the transaction
300
+ */
301
+ public txsTransfer(signer:PublicKey, token: PublicKey, amount: bigint, dstAddress: PublicKey, feeRate?: string): Promise<SolanaTx[]> {
302
+ if(SolanaTokens.WSOL_ADDRESS.equals(token)) {
303
+ return this.txsTransferSol(signer, amount, dstAddress, feeRate);
304
+ }
305
+ return this.txsTransferTokens(signer, token, amount, dstAddress, feeRate);
306
+ }
307
+
308
308
  }