@atomiqlabs/chain-solana 13.5.13 → 13.5.14

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