@exodus/solana-api 2.5.2 → 2.5.3

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.
@@ -0,0 +1,382 @@
1
+ import lodash from 'lodash'
2
+
3
+ export default {
4
+ setServer: jest.fn(),
5
+ setAssets: jest.fn(),
6
+ setTokens: jest.fn(function(assets) {
7
+ const solTokens = lodash.pickBy(assets, (asset) => asset.assetType === 'SOLANA_TOKEN')
8
+ this.tokens = lodash.mapKeys(solTokens, (v) => v.mintAddress)
9
+ }),
10
+ watchAddress: jest.fn(),
11
+ unwatchAddress: jest.fn(),
12
+ getTransactions: async (...args) => {
13
+ expect(args).toEqual([
14
+ '8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X',
15
+ { cursor: '', includeUnparsed: true },
16
+ ])
17
+ return {
18
+ transactions: [
19
+ {
20
+ timestamp: 1654797546000,
21
+ date: '2022-06-09T17:59:06.000Z',
22
+ id:
23
+ '3fiGCohizfVEeSSq4mrfGHve2tZA439toP9RwS1hFX1ViM4VEWX3Dw172ynsrJQ8evcCphohf7r7VTYg1KmvhnUC',
24
+ slot: 136939890,
25
+ error: false,
26
+ owner: '8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X',
27
+ from: '8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X',
28
+ to: '8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X',
29
+ amount: 134570800,
30
+ fee: 5000,
31
+ staking: {
32
+ method: 'createAccountWithSeed',
33
+ seed: 'exodus:1654797541558',
34
+ stakeAddresses: ['7XHXjJQ7Gzno3QarhCFXXmd4xxBrRDsSGooLLLbYV7XR'],
35
+ stake: 134570800,
36
+ },
37
+ },
38
+ {
39
+ timestamp: 1653925537000,
40
+ date: '2022-05-30T15:45:37.000Z',
41
+ id:
42
+ '2uwzLyasKxnxB4FjxUbvUDbdpEaWmgzi6Te9PTAqwXsGdnYZdbeHh3LGmwBeVBLXqjCZM5kbvDuGR2Uth4bmon8f',
43
+ slot: 135760822,
44
+ error: false,
45
+ owner: '8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X',
46
+ token: {
47
+ tokenAccountAddress: 'DfV8UWiwyn8fiMdNZv3mA3wtNJw3eRYKVtV8itRDVF1R',
48
+ tokenName: 'mean_solana_c5cba5c4',
49
+ ticker: 'MEANsolanaC5CBA5C4',
50
+ mintAddress: 'MEANeD3XDdUmNMsRGjASkSWdC8prLYsoRJ61pPeHctD',
51
+ },
52
+ from: 'DfV8UWiwyn8fiMdNZv3mA3wtNJw3eRYKVtV8itRDVF1R',
53
+ to: '3aSdqidyDDVvsh4ZRVrVNezVNDLKnHmyuoWGeFGi93m7',
54
+ amount: 10000,
55
+ fee: 5000,
56
+ },
57
+ {
58
+ timestamp: 1653353991000,
59
+ date: '2022-05-24T00:59:51.000Z',
60
+ id:
61
+ '4RegBpwrcmFvvq8qs9mGBGLY3sabdbUzFSeThXyFof9J64chQEWGRkBQSUeaq5p7sA4nV3wLH2hyoLex5TGoxTcQ',
62
+ slot: 134970480,
63
+ error: false,
64
+ owner: null,
65
+ token: {
66
+ tokenAccountAddress: 'DfV8UWiwyn8fiMdNZv3mA3wtNJw3eRYKVtV8itRDVF1R',
67
+ tokenName: 'mean_solana_c5cba5c4',
68
+ ticker: 'MEANsolanaC5CBA5C4',
69
+ mintAddress: 'MEANeD3XDdUmNMsRGjASkSWdC8prLYsoRJ61pPeHctD',
70
+ },
71
+ from: '6YrejbdKKuxNT86QBfvPSpQYHLbQVMFSh14ZMJ9vALEt',
72
+ to: 'DfV8UWiwyn8fiMdNZv3mA3wtNJw3eRYKVtV8itRDVF1R',
73
+ amount: 20000,
74
+ fee: 0,
75
+ },
76
+ {
77
+ timestamp: 1653353402000,
78
+ date: '2022-05-24T00:50:02.000Z',
79
+ id:
80
+ 'LA7eSpohaGFFMhgfMdyWV8EbuqKen1DQtLeqcv2V3tb9zQMUV7bj3VW9nq3ksHzubGEqoGmug5UNDXZRNUjnrLG',
81
+ slot: 134969651,
82
+ error: false,
83
+ owner: '8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X',
84
+ token: {
85
+ tokenAccountAddress: 'DfV8UWiwyn8fiMdNZv3mA3wtNJw3eRYKVtV8itRDVF1R',
86
+ tokenName: 'mean_solana_c5cba5c4',
87
+ ticker: 'MEANsolanaC5CBA5C4',
88
+ mintAddress: 'MEANeD3XDdUmNMsRGjASkSWdC8prLYsoRJ61pPeHctD',
89
+ },
90
+ from: 'DfV8UWiwyn8fiMdNZv3mA3wtNJw3eRYKVtV8itRDVF1R',
91
+ to: 'DzEGYQg8QoT8QqFD3ERCcbXsdxDvGnxe3JaeJHd65vDJ',
92
+ amount: 70000,
93
+ fee: 5000,
94
+ },
95
+ {
96
+ timestamp: 1653343974000,
97
+ date: '2022-05-23T22:12:54.000Z',
98
+ id:
99
+ '3ZqxuAWfAGwF1HyHxFmHu3w1CHFh8EPJQe5wuaZ5V6udo17nYGJmEQR77UfrAWbNkH4eY7uXXPKzYpB4ZxWbpuBR',
100
+ slot: 134956663,
101
+ error: false,
102
+ owner: null,
103
+ token: {
104
+ tokenAccountAddress: 'DfV8UWiwyn8fiMdNZv3mA3wtNJw3eRYKVtV8itRDVF1R',
105
+ tokenName: 'mean_solana_c5cba5c4',
106
+ ticker: 'MEANsolanaC5CBA5C4',
107
+ mintAddress: 'MEANeD3XDdUmNMsRGjASkSWdC8prLYsoRJ61pPeHctD',
108
+ },
109
+ from: '6YrejbdKKuxNT86QBfvPSpQYHLbQVMFSh14ZMJ9vALEt',
110
+ to: 'DfV8UWiwyn8fiMdNZv3mA3wtNJw3eRYKVtV8itRDVF1R',
111
+ amount: 600000,
112
+ fee: 0,
113
+ },
114
+ {
115
+ timestamp: 1651246205000,
116
+ date: '2022-04-29T15:30:05.000Z',
117
+ id:
118
+ 'VAok8n3wmVCTfu5FDV9aEiHbjcSpj4ULZkonyoXPmeNynFHrkwakmmfsoLBn7bCnfy9nvRXjjbfo5sn7RKFV3Z6',
119
+ slot: 131819518,
120
+ error: false,
121
+ owner: '8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X',
122
+ token: {
123
+ tokenAccountAddress: '5oq1Kvmmtgp9UtDzLEwYi7QcmcHUm45ZWgmV9yRKL6rS',
124
+ tokenName: '8hgy_solana_43b58185',
125
+ ticker: '8HGYsolana43B58185',
126
+ mintAddress: '8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh',
127
+ },
128
+ from: '5oq1Kvmmtgp9UtDzLEwYi7QcmcHUm45ZWgmV9yRKL6rS',
129
+ to: '7qfQ9QU47Lo9JjiVtj2PTSbbzgbQ4Hmz92Ct6AwwBVAp',
130
+ amount: 1000000,
131
+ fee: 5000,
132
+ },
133
+ {
134
+ timestamp: 1651240748000,
135
+ date: '2022-04-29T13:59:08.000Z',
136
+ id:
137
+ '24GQxKf8UCYu81qfGNNMj11vMPNp2tTBwiBSHiLEQajeYH4MkRmoeUoEedrssn4ZMigscXLZDbTRx836Wrhm7ibe',
138
+ slot: 131811126,
139
+ error: false,
140
+ owner: '8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X',
141
+ token: {
142
+ tokenAccountAddress: '5oq1Kvmmtgp9UtDzLEwYi7QcmcHUm45ZWgmV9yRKL6rS',
143
+ tokenName: '8hgy_solana_43b58185',
144
+ ticker: '8HGYsolana43B58185',
145
+ mintAddress: '8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh',
146
+ },
147
+ from: '5oq1Kvmmtgp9UtDzLEwYi7QcmcHUm45ZWgmV9yRKL6rS',
148
+ to: '7qfQ9QU47Lo9JjiVtj2PTSbbzgbQ4Hmz92Ct6AwwBVAp',
149
+ amount: 5000000,
150
+ fee: 5000,
151
+ },
152
+ {
153
+ timestamp: 1651240452000,
154
+ date: '2022-04-29T13:54:12.000Z',
155
+ id:
156
+ '26mdaEU1sbBj3Y13L3aLM88cgrYWLy6u25teUz95zbiQG8kNoBoDAwHubYYuoLNvpToXBKoHJMdti3hSDHCYrLkf',
157
+ slot: 131810675,
158
+ error: false,
159
+ owner: null,
160
+ token: {
161
+ tokenAccountAddress: '5oq1Kvmmtgp9UtDzLEwYi7QcmcHUm45ZWgmV9yRKL6rS',
162
+ tokenName: '8hgy_solana_43b58185',
163
+ ticker: '8HGYsolana43B58185',
164
+ mintAddress: '8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh',
165
+ },
166
+ from: '5ddWhogjCr3mVGbiTYnJLa2ki9cHxERG2djH7qKNkjqw',
167
+ to: '5oq1Kvmmtgp9UtDzLEwYi7QcmcHUm45ZWgmV9yRKL6rS',
168
+ amount: 15000000,
169
+ fee: 0,
170
+ },
171
+ {
172
+ timestamp: 1650732193000,
173
+ date: '2022-04-23T16:43:13.000Z',
174
+ id:
175
+ 'tqCzG6DhG9mGBTERNw8dBbuWVX5i4Yk1jscKDdCNNceLMk4TFUtG4CG7FPCFmmimH8w3mabRQEf8dVjMYkULGjZ',
176
+ slot: 131018276,
177
+ error: false,
178
+ owner: null,
179
+ token: {
180
+ tokenAccountAddress: '31UvgTXxpucQ3Cr6g26XGJxx1xTHxkUMPBRURRpphmgT',
181
+ tokenName: 'agfe_solana_c5cba5c4',
182
+ ticker: 'AGFEsolanaC5CBA5C4',
183
+ mintAddress: 'AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3',
184
+ },
185
+ from: 'BfWfHz2TyFKK54K6iDWfzgVPg8LN54C8huQvDJVxiRme',
186
+ to: '31UvgTXxpucQ3Cr6g26XGJxx1xTHxkUMPBRURRpphmgT',
187
+ amount: 4000,
188
+ fee: 0,
189
+ },
190
+ {
191
+ timestamp: 1649863458000,
192
+ date: '2022-04-13T15:24:18.000Z',
193
+ id:
194
+ '82SC4G8usbwM2Zsk2J3nURZmMz4omtneSRr7nX1i7sjzfajokAfUiusSYVd2ws5bn4ucaC1dvdiAYSS8pM8yqZS',
195
+ slot: 129572609,
196
+ error: false,
197
+ owner: '8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X',
198
+ token: {
199
+ tokenAccountAddress: '4r6P9xCvb7413MB8bPrR7VCU8qcNbgpaFagkAJa57mPt',
200
+ tokenName: 'raydium',
201
+ ticker: 'RAY',
202
+ mintAddress: '4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R',
203
+ },
204
+ from: '4r6P9xCvb7413MB8bPrR7VCU8qcNbgpaFagkAJa57mPt',
205
+ to: '6do2vExLT9LETSUk1vKkm9A6BxgqtemQazKWndatjWFL',
206
+ amount: 386292,
207
+ fee: 5000,
208
+ },
209
+ {
210
+ timestamp: 1649857428000,
211
+ date: '2022-04-13T13:43:48.000Z',
212
+ id:
213
+ '4LsihvxHQwq58iQRJk3vuAxyvNaj4dxZ87i7BJqjh2UTsFEDouWscoKqu6orVV6zyywpmdNJGQxm3kKvxobg6UD6',
214
+ slot: 129562497,
215
+ error: false,
216
+ owner: '8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X',
217
+ token: {
218
+ tokenAccountAddress: '4r6P9xCvb7413MB8bPrR7VCU8qcNbgpaFagkAJa57mPt',
219
+ tokenName: 'raydium',
220
+ ticker: 'RAY',
221
+ mintAddress: '4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R',
222
+ },
223
+ from: '4r6P9xCvb7413MB8bPrR7VCU8qcNbgpaFagkAJa57mPt',
224
+ to: '6do2vExLT9LETSUk1vKkm9A6BxgqtemQazKWndatjWFL',
225
+ amount: 772585,
226
+ fee: 5000,
227
+ },
228
+ {
229
+ timestamp: 1649857316000,
230
+ date: '2022-04-13T13:41:56.000Z',
231
+ id:
232
+ '25reWK943nzgGEDuJ5e56JCxmskwBzHtqQTQxV1FuhewDnPdfxYDJgSRaUFDVw6cP27qUj1J5vTVCFNumXvZX4BB',
233
+ slot: 129562293,
234
+ error: false,
235
+ owner: null,
236
+ token: {
237
+ tokenAccountAddress: '4r6P9xCvb7413MB8bPrR7VCU8qcNbgpaFagkAJa57mPt',
238
+ tokenName: 'raydium',
239
+ ticker: 'RAY',
240
+ mintAddress: '4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R',
241
+ },
242
+ from: 'Faszfxg7k2HWUT4CSGUn9MAVGUsPijvDQ3i2h7fi46M6',
243
+ to: '4r6P9xCvb7413MB8bPrR7VCU8qcNbgpaFagkAJa57mPt',
244
+ amount: 3545170,
245
+ fee: 0,
246
+ },
247
+ {
248
+ timestamp: 1649425956000,
249
+ date: '2022-04-08T13:52:36.000Z',
250
+ id:
251
+ '2Apnh4WBnVLpjceHMiMuY3rr49kzTJCMjwH4imsgjSHxtd7hvDQkmScTwuNCN22uAWNu4koDLLSvcFG6TwQnQWp5',
252
+ slot: 128799407,
253
+ error: false,
254
+ owner: '7HAULvGEChgLZSXV3zwzkJCnArtWbmMA5RygDpsfryEA',
255
+ from: '7HAULvGEChgLZSXV3zwzkJCnArtWbmMA5RygDpsfryEA',
256
+ to: '8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X',
257
+ amount: 142762920,
258
+ fee: 0,
259
+ },
260
+ {
261
+ timestamp: 1649425849000,
262
+ date: '2022-04-08T13:50:49.000Z',
263
+ id:
264
+ 'UaZAVAZEyBCuXJCbK8xh97KgB2ktMCgeppdomEf6riDsdSyK8HbAGJDVtqVYA54PduN9ZxZsnjuUTHV22LzsPNj',
265
+ slot: 128799211,
266
+ error: false,
267
+ owner: '8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X',
268
+ from: '8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X',
269
+ to: '7HAULvGEChgLZSXV3zwzkJCnArtWbmMA5RygDpsfryEA',
270
+ amount: 152767920,
271
+ fee: 5000,
272
+ },
273
+ {
274
+ timestamp: 1649425475000,
275
+ date: '2022-04-08T13:44:35.000Z',
276
+ id:
277
+ '2GtBQDGgWYA3Sziht49yiFTk4BBoxk2pp8Bx5kLJzqf8PrZofmniKRUKt5ZSi1RjpJpYkwdDBP8PeVLAyiiTuA1c',
278
+ slot: 128798507,
279
+ error: false,
280
+ owner: '6ZRCB7AAqGre6c72PRz3MHLC73VMYvJ8bi9KHf1HFpNk',
281
+ from: '6ZRCB7AAqGre6c72PRz3MHLC73VMYvJ8bi9KHf1HFpNk',
282
+ to: '8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X',
283
+ amount: 162772920,
284
+ fee: 0,
285
+ },
286
+ ],
287
+ newCursor:
288
+ '3fiGCohizfVEeSSq4mrfGHve2tZA439toP9RwS1hFX1ViM4VEWX3Dw172ynsrJQ8evcCphohf7r7VTYg1KmvhnUC',
289
+ }
290
+ },
291
+
292
+ getStakeAccountsInfo: async (...args) => {
293
+ expect(args).toEqual(['8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X'])
294
+ return {
295
+ accounts: {
296
+ '7XHXjJQ7Gzno3QarhCFXXmd4xxBrRDsSGooLLLbYV7XR': {
297
+ activationEpoch: 316,
298
+ deactivationEpoch: 18446744073709552000,
299
+ stake: 132287920,
300
+ voter: '9QU2QSxhb24FUX3Tu2FpczXjpK3VYrvRudywSZaM29mF',
301
+ warmupCooldownRate: 0.25,
302
+ lamports: 134570800,
303
+ state: 'active',
304
+ isDeactivating: false,
305
+ canWithdraw: false,
306
+ },
307
+ },
308
+ totalStake: 132287920,
309
+ locked: 134570800,
310
+ withdrawable: 111,
311
+ pending: 222,
312
+ }
313
+ },
314
+
315
+ getRewards: async (...args) => {
316
+ expect(args).toEqual([['7XHXjJQ7Gzno3QarhCFXXmd4xxBrRDsSGooLLLbYV7XR']])
317
+ return 3333
318
+ },
319
+
320
+ getTokenAccountsByOwner: async (...args) => {
321
+ expect(args).toEqual(['8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X'])
322
+ return [
323
+ {
324
+ tokenAccountAddress: '31UvgTXxpucQ3Cr6g26XGJxx1xTHxkUMPBRURRpphmgT',
325
+ owner: '8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X',
326
+ tokenName: 'agfe_solana_c5cba5c4',
327
+ ticker: 'AGFEsolanaC5CBA5C4',
328
+ balance: '4000',
329
+ mintAddress: 'AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3',
330
+ },
331
+ {
332
+ tokenAccountAddress: '5oq1Kvmmtgp9UtDzLEwYi7QcmcHUm45ZWgmV9yRKL6rS',
333
+ owner: '8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X',
334
+ tokenName: '8hgy_solana_43b58185',
335
+ ticker: '8HGYsolana43B58185',
336
+ balance: '9000000',
337
+ mintAddress: '8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh',
338
+ },
339
+ {
340
+ tokenAccountAddress: 'DfV8UWiwyn8fiMdNZv3mA3wtNJw3eRYKVtV8itRDVF1R',
341
+ owner: '8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X',
342
+ tokenName: 'mean_solana_c5cba5c4',
343
+ ticker: 'MEANsolanaC5CBA5C4',
344
+ balance: '540000',
345
+ mintAddress: 'MEANeD3XDdUmNMsRGjASkSWdC8prLYsoRJ61pPeHctD',
346
+ },
347
+ {
348
+ tokenAccountAddress: '4r6P9xCvb7413MB8bPrR7VCU8qcNbgpaFagkAJa57mPt',
349
+ owner: '8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X',
350
+ tokenName: 'raydium',
351
+ ticker: 'RAY',
352
+ balance: '2386293',
353
+ mintAddress: '4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R',
354
+ },
355
+ ]
356
+ },
357
+
358
+ getWalletTokensList: async () => {
359
+ return [
360
+ 'AGFEad2et2ZJif9jaGpdMixQqvW5i81aBdvKe7PHNfz3',
361
+ '8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh',
362
+ 'MEANeD3XDdUmNMsRGjASkSWdC8prLYsoRJ61pPeHctD',
363
+ '4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R',
364
+ 'UNKNOWN1AAAAyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNL',
365
+ 'UNKNOWN2BBBByjzvzp8eMZWUXbBCjEvwSkkk59S5iCNL',
366
+ ]
367
+ },
368
+
369
+ getTokensBalance: async () => {
370
+ return {
371
+ agfe_solana_c5cba5c4: 4000,
372
+ '8hgy_solana_43b58185': 9000000,
373
+ mean_solana_c5cba5c4: 540000,
374
+ raydium: 2386293,
375
+ }
376
+ },
377
+
378
+ getBalance: async (...args) => {
379
+ expect(args).toEqual(['8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X'])
380
+ return 10000000
381
+ },
382
+ }
@@ -0,0 +1,128 @@
1
+ import { intersection } from 'lodash'
2
+ import wretch from 'wretch'
3
+ import { fetch } from '@exodus/fetch'
4
+ import { InMemoryAssetClientInterface, PlainAddressResolver, logger } from '@exodus/assets-testing'
5
+
6
+ import assets from '../../__tests__/assets'
7
+ import { SolanaAccountState } from '../../account-state'
8
+ import { Api } from '../../api'
9
+ import { SolanaMonitor } from '../solana-monitor'
10
+
11
+ const { solana: asset } = assets
12
+
13
+ wretch().polyfills({
14
+ fetch,
15
+ })
16
+
17
+ jest.setTimeout(60000)
18
+
19
+ asset.api = {
20
+ createAccountState: () => SolanaAccountState,
21
+ }
22
+
23
+ // Fernando's dev wallet. Profile 1
24
+ const walletAddresses = {
25
+ solana: ['8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X'],
26
+ }
27
+
28
+ const api = new Api({ assets })
29
+
30
+ describe('solana monitor', () => {
31
+ test('can start monitor, update txs and balances', async () => {
32
+ const unknownAddress = '8HGyAAB1yoM1ttS7pXjHMa3dukTFGQggnFFH3hJZgzQh'
33
+ const assetsWithoutUnknown = Object.fromEntries(
34
+ Object.values(assets)
35
+ .filter((asset) => {
36
+ const isUnknown =
37
+ asset.assetType === 'SOLANA_TOKEN' && asset.mintAddress === unknownAddress
38
+ return !isUnknown
39
+ })
40
+ .map((asset) => {
41
+ return [asset.name, asset]
42
+ })
43
+ )
44
+ const assetClientInterface = new InMemoryAssetClientInterface({
45
+ assets: assetsWithoutUnknown,
46
+ logger,
47
+ addressResolver: new PlainAddressResolver({ walletAddresses }),
48
+ })
49
+ const monitor = new SolanaMonitor({
50
+ api: api,
51
+ interval: 1000,
52
+ asset,
53
+ assetClientInterface,
54
+ logger,
55
+ })
56
+ try {
57
+ const unknownTokensHandler = jest.fn()
58
+ monitor.on('unknown-tokens', unknownTokensHandler)
59
+
60
+ await monitor.start()
61
+
62
+ expect(logger.error).not.toBeCalled()
63
+
64
+ // Syntax sugar
65
+ const txs = (walletAccount, assetName) => {
66
+ return assetClientInterface.getTxLog({ walletAccount, assetName })
67
+ }
68
+
69
+ const accountState = await assetClientInterface.getAccountState({
70
+ walletAccount: 'exodus0',
71
+ assetName: 'solana',
72
+ })
73
+
74
+ expect(accountState).toBeDefined()
75
+
76
+ expect(accountState.balance.gt(asset.currency.defaultUnit(0))).toEqual(true)
77
+ expect(accountState.cursor).toBeDefined()
78
+
79
+ // Some token balances my account has.
80
+ expect(
81
+ accountState.tokenBalances.agfe_solana_c5cba5c4.gt(
82
+ assets.agfe_solana_c5cba5c4.currency.defaultUnit(0)
83
+ )
84
+ ).toEqual(true)
85
+
86
+ expect(
87
+ accountState.tokenBalances.mean_solana_c5cba5c4.gt(
88
+ assets.mean_solana_c5cba5c4.currency.defaultUnit(0)
89
+ )
90
+ ).toEqual(true)
91
+
92
+ expect(accountState.tokenBalances['8hgy_solana_43b58185']).toEqual(undefined)
93
+
94
+ expect(
95
+ accountState.tokenBalances.agfe_solana_c5cba5c4.gt(
96
+ assets.agfe_solana_c5cba5c4.currency.defaultUnit(0)
97
+ )
98
+ ).toEqual(true)
99
+
100
+ expect((await txs('exodus0', 'solana')).size).toBeGreaterThanOrEqual(10)
101
+ expect((await txs('exodus0', 'raydium')).size).toBeGreaterThanOrEqual(3)
102
+ expect((await txs('exodus0', '8hgy_solana_43b58185')).size).toEqual(0)
103
+ expect((await txs('exodus0', 'agfe_solana_c5cba5c4')).size).toBeGreaterThanOrEqual(1)
104
+
105
+ expect(accountState.mem.loaded).toEqual(true)
106
+ expect(accountState.mem.staking).not.toBeDefined() // why undefined?
107
+ // expect(accountState.mem.isDelegating).toEqual(true)
108
+ // expect(accountState.mem.locked.gt(asset.currency.defaultUnit(0))).toEqual(true)
109
+ expect(accountState.mem.withdrawable).toBeDefined()
110
+ expect(accountState.mem.pending).toBeDefined()
111
+ expect(accountState.mem.earned).toBeDefined()
112
+
113
+ expect(logger.error).not.toBeCalled()
114
+ expect(logger.warn).not.toBeCalled()
115
+
116
+ expect(unknownTokensHandler.mock.calls.length).toBe(1)
117
+
118
+ const expectedAddresses = [unknownAddress]
119
+ expect(intersection(unknownTokensHandler.mock.calls[0][0], expectedAddresses).sort()).toEqual(
120
+ expectedAddresses.sort()
121
+ )
122
+ } finally {
123
+ await monitor.stop()
124
+ }
125
+ expect(logger.error).not.toBeCalled()
126
+ expect(monitor.timer.isRunning).toEqual(false)
127
+ })
128
+ })
@@ -0,0 +1,135 @@
1
+ import { InMemoryAssetClientInterface, PlainAddressResolver, logger } from '@exodus/assets-testing'
2
+
3
+ import assets from '../../__tests__/assets'
4
+ import { SolanaAccountState } from '../../account-state'
5
+ import { SolanaMonitor } from '../solana-monitor'
6
+ import solanaMonitorApiMock from './solana-monitor-api-mock'
7
+
8
+ const { solana: asset } = assets
9
+
10
+ asset.api = {
11
+ createAccountState: () => SolanaAccountState,
12
+ }
13
+
14
+ // Fernando's dev wallet. Profile 1
15
+ const walletAddresses = {
16
+ solana: ['8APBjTndtCF4kfKHaJG9boR2dREGNCK4yFRVfqUfzS4X'],
17
+ }
18
+
19
+ describe('solana monitor', () => {
20
+ test('can start monitor, update txs and balances', async () => {
21
+ const assetClientInterface = new InMemoryAssetClientInterface({
22
+ assets,
23
+ logger,
24
+ addressResolver: new PlainAddressResolver({ walletAddresses }),
25
+ })
26
+
27
+ const monitor = new SolanaMonitor({
28
+ api: solanaMonitorApiMock,
29
+ interval: 1000,
30
+ asset,
31
+ assetClientInterface,
32
+ logger,
33
+ includeUnparsed: true,
34
+ })
35
+
36
+ const unknownTokensHandler = jest.fn()
37
+ monitor.on('unknown-tokens', unknownTokensHandler)
38
+
39
+ try {
40
+ await monitor.start()
41
+ expect(logger.error).not.toBeCalled()
42
+ expect(logger.warn).not.toBeCalled()
43
+
44
+ // Sintax sugar
45
+ const txs = (walletAccount, assetName) => {
46
+ return assetClientInterface.getTxLog({ walletAccount, assetName })
47
+ }
48
+
49
+ const accountState = await assetClientInterface.getAccountState({
50
+ walletAccount: 'exodus0',
51
+ assetName: 'solana',
52
+ })
53
+
54
+ expect(accountState).toBeDefined()
55
+
56
+ const expectSameValue = (actual, expected) => {
57
+ expect(actual).toEqual(expected)
58
+ expect(actual.equals(expected)).toEqual(true)
59
+ }
60
+
61
+ expectSameValue(accountState.balance, asset.currency.defaultUnit('0.144571133'))
62
+ expect(accountState.cursor).toEqual(
63
+ '3fiGCohizfVEeSSq4mrfGHve2tZA439toP9RwS1hFX1ViM4VEWX3Dw172ynsrJQ8evcCphohf7r7VTYg1KmvhnUC'
64
+ )
65
+
66
+ // Some token balances my account has.
67
+ expectSameValue(
68
+ accountState.tokenBalances.agfe_solana_c5cba5c4,
69
+ assets.agfe_solana_c5cba5c4.currency.defaultUnit('0.004')
70
+ )
71
+
72
+ expectSameValue(
73
+ accountState.tokenBalances.mean_solana_c5cba5c4,
74
+ assets.mean_solana_c5cba5c4.currency.defaultUnit('0.54')
75
+ )
76
+ expectSameValue(
77
+ accountState.tokenBalances.raydium,
78
+ assets.raydium.currency.defaultUnit('2.386293')
79
+ )
80
+
81
+ expectSameValue(
82
+ accountState.tokenBalances['8hgy_solana_43b58185'],
83
+ assets['8hgy_solana_43b58185'].currency.defaultUnit('9')
84
+ )
85
+
86
+ const solanaTxs = await txs('exodus0', 'solana')
87
+ expect(solanaTxs.size).toEqual(10)
88
+ expect((await txs('exodus0', 'raydium')).size).toEqual(3)
89
+ expect((await txs('exodus0', '8hgy_solana_43b58185')).size).toEqual(3)
90
+ expect((await txs('exodus0', 'agfe_solana_c5cba5c4')).size).toEqual(1)
91
+
92
+ // A regular solana transaction.
93
+ const regularTransaction = solanaTxs.get(
94
+ '2GtBQDGgWYA3Sziht49yiFTk4BBoxk2pp8Bx5kLJzqf8PrZofmniKRUKt5ZSi1RjpJpYkwdDBP8PeVLAyiiTuA1c'
95
+ )
96
+ expectSameValue(regularTransaction.coinAmount, asset.currency.defaultUnit('0.16277292'))
97
+
98
+ // A transaction for another token has been added to Solana to reflect the paid fees.
99
+ const feeTransaction = solanaTxs.get(
100
+ '4LsihvxHQwq58iQRJk3vuAxyvNaj4dxZ87i7BJqjh2UTsFEDouWscoKqu6orVV6zyywpmdNJGQxm3kKvxobg6UD6'
101
+ )
102
+ expectSameValue(feeTransaction.feeAmount, asset.currency.defaultUnit('0.000005'))
103
+ expect(feeTransaction.tokens).toEqual(['raydium'])
104
+ expectSameValue(
105
+ asset.currency.defaultUnit(feeTransaction.coinAmount.toNumber()),
106
+ asset.currency.defaultUnit(0).toDefault()
107
+ )
108
+
109
+ // Stake info
110
+ expect(accountState.mem.loaded).toEqual(true)
111
+ expect(accountState.mem.staking).not.toBeDefined() // why undefined?
112
+ expect(accountState.mem.isDelegating).toEqual(true)
113
+ expectSameValue(accountState.mem.locked, asset.currency.defaultUnit('0.1345708'))
114
+ expectSameValue(accountState.mem.withdrawable, asset.currency.defaultUnit('0.000000111'))
115
+ expectSameValue(accountState.mem.pending, asset.currency.defaultUnit('0.000000222'))
116
+ expectSameValue(accountState.mem.earned, asset.currency.defaultUnit('0.000003333'))
117
+
118
+ const expectedAddresses = [
119
+ 'UNKNOWN1AAAAyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNL',
120
+ 'UNKNOWN2BBBByjzvzp8eMZWUXbBCjEvwSkkk59S5iCNL',
121
+ ]
122
+
123
+ expect(unknownTokensHandler.mock.calls.length).toBe(1)
124
+ expect(unknownTokensHandler.mock.calls[0][0].sort()).toEqual(expectedAddresses.sort())
125
+
126
+ expect(logger.error).not.toBeCalled()
127
+ expect(logger.warn).not.toBeCalled()
128
+ } finally {
129
+ await monitor.stop()
130
+ }
131
+ expect(logger.error).not.toBeCalled()
132
+ expect(logger.warn).not.toBeCalled()
133
+ expect(monitor.timer.isRunning).toEqual(false)
134
+ })
135
+ })
@@ -67,8 +67,11 @@ export class SolanaMonitor extends BaseMonitor {
67
67
 
68
68
  async emitUnknownTokensEvent({ tokenAccounts }) {
69
69
  const tokensList = await this.api.getWalletTokensList({ tokenAccounts })
70
- if (tokensList.length > 0) {
71
- this.emit('unknown-tokens', tokensList)
70
+ const unknownTokensList = tokensList.filter((mintAddress) => {
71
+ return !this.api.tokens[mintAddress]
72
+ })
73
+ if (unknownTokensList.length > 0) {
74
+ this.emit('unknown-tokens', unknownTokensList)
72
75
  }
73
76
  }
74
77