@exodus/ethereum-api 2.8.2 → 2.8.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,357 @@
1
+ export default {
2
+ '0xf6c138c36341138ddfc314a11038da8264b7ef09': [
3
+ [
4
+ {
5
+ blockHash: '0x1a7886725a5ebc312d7e407f20988d972fbbbfeabf8b6a98564345aee87e3481',
6
+ blockNumber: '0xe1f4b7',
7
+ timestamp: '0x6286ec8e',
8
+ confirmations: 3712,
9
+ addressIndex: 0,
10
+ hash: '0x2f613acaebb34300a5c1bb25e2fa1c92f48cea469066fedb067d734292f31812',
11
+ nonce: '0x3',
12
+ gasPrice: '0x42426923b',
13
+ gas: '0x5208',
14
+ gasUsed: '0x5208',
15
+ to: '0xf6c138c36341138ddfc314a11038da8264b7ef09',
16
+ from: '0x90e481d9a664ebbe4be180d9501962255463036d',
17
+ value: '0x1d3353f4626400',
18
+ status: 1,
19
+ error: null,
20
+ internal: [],
21
+ erc20: [],
22
+ erc721: [],
23
+ data: '0x',
24
+ },
25
+ ],
26
+ [],
27
+ ],
28
+ '0x90e481d9a664ebbe4be180d9501962255463036d': [
29
+ [
30
+ {
31
+ blockHash: '0x5a28482e44696447a9c2877e4a1493705c27482e22eefbac63cae58e812c6313',
32
+ blockNumber: '0xddae7e',
33
+ timestamp: '0x624ca889',
34
+ confirmations: 283833,
35
+ addressIndex: 0,
36
+ hash: '0x9c700813589ecbb5305305fd8ff39f318bc9908b20c1c08b76e0d6578daf8289',
37
+ nonce: '0x36b824',
38
+ gasPrice: '0x136d414d3c',
39
+ gas: '0x16e8c',
40
+ gasUsed: '0xf6dd',
41
+ to: '0xdac17f958d2ee523a2206206994597c13d831ec7',
42
+ from: '0x2faf487a4414fe77e2327f0bf4ae2a264a776ad2',
43
+ value: '0x0',
44
+ status: 1,
45
+ error: null,
46
+ internal: [],
47
+ erc20: [
48
+ {
49
+ events: true,
50
+ address: '0xdac17f958d2ee523a2206206994597c13d831ec7',
51
+ from: '0x2faf487a4414fe77e2327f0bf4ae2a264a776ad2',
52
+ to: '0x90e481d9a664ebbe4be180d9501962255463036d',
53
+ value: '0xeafc0',
54
+ },
55
+ ],
56
+ erc721: [],
57
+ data:
58
+ '0xa9059cbb00000000000000000000000090e481d9a664ebbe4be180d9501962255463036d00000000000000000000000000000000000000000000000000000000000eafc0',
59
+ },
60
+ {
61
+ blockHash: '0x2395c945108e1ba52586452aee9cd5692e3d08b07414b1c79bca1f91654f5787',
62
+ blockNumber: '0xddae88',
63
+ timestamp: '0x624ca904',
64
+ confirmations: 283823,
65
+ addressIndex: 1,
66
+ hash: '0xa1f9837b6c8cb55ad5b321a94357c1c1860c35916737532c6ea9b644fd172985',
67
+ nonce: '0x192b7e',
68
+ gasPrice: '0x116331c285',
69
+ gas: '0xf618',
70
+ gasUsed: '0x5208',
71
+ to: '0x90e481d9a664ebbe4be180d9501962255463036d',
72
+ from: '0xc098b2a3aa256d2140208c3de6543aaef5cd3a94',
73
+ value: '0x3202a822f86c00',
74
+ status: 1,
75
+ error: null,
76
+ internal: [],
77
+ erc20: [],
78
+ erc721: [],
79
+ data: '0x',
80
+ },
81
+ {
82
+ blockHash: '0xb44ceddff193a9aa84a39e19d175b768b95c66a5438de8cd11391ce502b34259',
83
+ blockNumber: '0xddbeae',
84
+ timestamp: '0x624d82fe',
85
+ confirmations: 279689,
86
+ addressIndex: 2,
87
+ hash: '0x699b4b708812a6c4237f20079785ef28423e340b07cb78bb93bf30c6a949abc0',
88
+ nonce: '0x36c917',
89
+ gasPrice: '0x986b51fbe',
90
+ gas: '0x11e64',
91
+ gasUsed: '0xb411',
92
+ to: '0xdac17f958d2ee523a2206206994597c13d831ec7',
93
+ from: '0x2faf487a4414fe77e2327f0bf4ae2a264a776ad2',
94
+ value: '0x0',
95
+ status: 1,
96
+ error: null,
97
+ internal: [],
98
+ erc20: [
99
+ {
100
+ events: true,
101
+ address: '0xdac17f958d2ee523a2206206994597c13d831ec7',
102
+ from: '0x2faf487a4414fe77e2327f0bf4ae2a264a776ad2',
103
+ to: '0x90e481d9a664ebbe4be180d9501962255463036d',
104
+ value: '0xd39548',
105
+ },
106
+ ],
107
+ erc721: [],
108
+ data:
109
+ '0xa9059cbb00000000000000000000000090e481d9a664ebbe4be180d9501962255463036d0000000000000000000000000000000000000000000000000000000000d39548',
110
+ },
111
+ {
112
+ blockHash: '0x46ac08214e4e853c3848e6fdecefaa55845c6068a5b7bd19faa0c921359b2d29',
113
+ blockNumber: '0xddc2f4',
114
+ timestamp: '0x624dbef2',
115
+ confirmations: 278595,
116
+ addressIndex: 3,
117
+ hash: '0xa2c35470993c37547988f44f92d4e12d6a301293223a4daf19a0e68822eddbef',
118
+ nonce: '0x1c2444',
119
+ gasPrice: '0xf099eb19a',
120
+ gas: '0x5208',
121
+ gasUsed: '0x5208',
122
+ to: '0x90e481d9a664ebbe4be180d9501962255463036d',
123
+ from: '0x59a5208b32e627891c389ebafc644145224006e8',
124
+ value: '0xc0e0570c34a800',
125
+ status: 1,
126
+ error: null,
127
+ internal: [],
128
+ erc20: [],
129
+ erc721: [],
130
+ data: '0x',
131
+ },
132
+ {
133
+ blockHash: '0xfa116b9c4e4d8f66745d7471de5059b7385f2c288a23e7ed27a48cef96dae385',
134
+ blockNumber: '0xde6f3b',
135
+ timestamp: '0x6256d511',
136
+ confirmations: 234492,
137
+ addressIndex: 4,
138
+ hash: '0x4b0b523bb0eca3e2e983f49d2aa33ae297c9402d9fcdcd4816ed20bea067db2c',
139
+ nonce: '0x0',
140
+ gasPrice: '0x11ef52da49',
141
+ gas: '0x11170',
142
+ gasUsed: '0xf6dd',
143
+ to: '0xdac17f958d2ee523a2206206994597c13d831ec7',
144
+ from: '0x90e481d9a664ebbe4be180d9501962255463036d',
145
+ value: '0x0',
146
+ status: 1,
147
+ error: null,
148
+ internal: [],
149
+ erc20: [
150
+ {
151
+ events: true,
152
+ address: '0xdac17f958d2ee523a2206206994597c13d831ec7',
153
+ from: '0x90e481d9a664ebbe4be180d9501962255463036d',
154
+ to: '0xfa56417d077a41a20aa190a8fcd841ebefa2859e',
155
+ value: '0x712284',
156
+ },
157
+ ],
158
+ erc721: [],
159
+ data:
160
+ '0xa9059cbb000000000000000000000000fa56417d077a41a20aa190a8fcd841ebefa2859e0000000000000000000000000000000000000000000000000000000000712284',
161
+ },
162
+ {
163
+ blockHash: '0xe9a9b99bbc766294a151b99c0290531b4529957d792b8de40624b3b2086c73f9',
164
+ blockNumber: '0xdeed29',
165
+ timestamp: '0x625d75aa',
166
+ confirmations: 202254,
167
+ addressIndex: 6,
168
+ hash: '0x974f15a3ac3f0692a4f4162e9f827722101b775dd1ca07fbf246ffebbefa43f0',
169
+ nonce: '0x37e5eb',
170
+ gasPrice: '0x9fb0d0b87',
171
+ gas: '0x13950',
172
+ gasUsed: '0xca80',
173
+ to: '0x0d8775f648430679a709e98d2b0cb6250d2887ef',
174
+ from: '0x2faf487a4414fe77e2327f0bf4ae2a264a776ad2',
175
+ value: '0x0',
176
+ status: 1,
177
+ error: null,
178
+ internal: [],
179
+ erc20: [
180
+ {
181
+ events: true,
182
+ address: '0x0d8775f648430679a709e98d2b0cb6250d2887ef',
183
+ from: '0x2faf487a4414fe77e2327f0bf4ae2a264a776ad2',
184
+ to: '0x90e481d9a664ebbe4be180d9501962255463036d',
185
+ value: '0x74e3b1b53804e000',
186
+ },
187
+ ],
188
+ erc721: [],
189
+ data:
190
+ '0xa9059cbb00000000000000000000000090e481d9a664ebbe4be180d9501962255463036d00000000000000000000000000000000000000000000000074e3b1b53804e000',
191
+ },
192
+ {
193
+ blockHash: '0x172d411fb1ce30311cd0559925dab284e4eeef58c9a9311fd04760be71e9d084',
194
+ blockNumber: '0xdf50cb',
195
+ timestamp: '0x6262bb5d',
196
+ confirmations: 176748,
197
+ addressIndex: 7,
198
+ hash: '0xf7aade9de387d7866043af8b98169d1502cb288cdf6dda0619e327964febd6df',
199
+ nonce: '0x384afa',
200
+ gasPrice: '0x4286ac8ee',
201
+ gas: '0x137d4',
202
+ gasUsed: '0xc944',
203
+ to: '0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9',
204
+ from: '0x2faf487a4414fe77e2327f0bf4ae2a264a776ad2',
205
+ value: '0x0',
206
+ status: 1,
207
+ error: null,
208
+ internal: [],
209
+ erc20: [
210
+ {
211
+ events: true,
212
+ address: '0x50d1c9771902476076ecfc8b2a83ad6b9355a4c9',
213
+ from: '0x2faf487a4414fe77e2327f0bf4ae2a264a776ad2',
214
+ to: '0x90e481d9a664ebbe4be180d9501962255463036d',
215
+ value: '0x293d97f33798c00',
216
+ },
217
+ ],
218
+ erc721: [],
219
+ data:
220
+ '0xa9059cbb00000000000000000000000090e481d9a664ebbe4be180d9501962255463036d0000000000000000000000000000000000000000000000000293d97f33798c00',
221
+ },
222
+ {
223
+ blockHash: '0xb71696b1e9c32298967715232c54740a4ec588e41ce3e5ac1ae4e4efe5334323',
224
+ blockNumber: '0xdffe37',
225
+ timestamp: '0x626befa1',
226
+ confirmations: 132352,
227
+ addressIndex: 8,
228
+ hash: '0x9743dc687f388874298e537eb5df9024d532e79e3ff3e5df33528c80baa70018',
229
+ nonce: '0x1',
230
+ gasPrice: '0xcf3015f43',
231
+ gas: '0x2377b',
232
+ gasUsed: '0x153df',
233
+ to: '0xae7ab96520de3a18e5e111b5eaab095312d7fe84',
234
+ from: '0x92f5d6f5b516e0a106c2d1bb802ff7688067bed6',
235
+ value: '0x0',
236
+ status: 1,
237
+ error: null,
238
+ internal: [],
239
+ erc20: [
240
+ {
241
+ events: true,
242
+ address: '0xae7ab96520de3a18e5e111b5eaab095312d7fe84',
243
+ from: '0x92f5d6f5b516e0a106c2d1bb802ff7688067bed6',
244
+ to: '0x90e481d9a664ebbe4be180d9501962255463036d',
245
+ value: '0xaa87bee538000',
246
+ },
247
+ ],
248
+ erc721: [],
249
+ data:
250
+ '0xa9059cbb00000000000000000000000090e481d9a664ebbe4be180d9501962255463036d000000000000000000000000000000000000000000000000000aa87bee538000',
251
+ },
252
+ {
253
+ blockHash: '0xc4d649e2d9c38b9cdb23c4f22c5da80d3f07ef88ed38627dd7363cd2f06c92f1',
254
+ blockNumber: '0xdffe3d',
255
+ timestamp: '0x626beff1',
256
+ confirmations: 132346,
257
+ addressIndex: 9,
258
+ hash: '0x53c0b38288585793ba01659e70ead0dd59f18d1360d6ab5a648d3480ccd77168',
259
+ nonce: '0x1',
260
+ gasPrice: '0xec570f72a',
261
+ gas: '0x1c5ed',
262
+ gasUsed: '0x153d3',
263
+ to: '0xae7ab96520de3a18e5e111b5eaab095312d7fe84',
264
+ from: '0x90e481d9a664ebbe4be180d9501962255463036d',
265
+ value: '0x0',
266
+ status: 1,
267
+ error: null,
268
+ internal: [],
269
+ erc20: [
270
+ {
271
+ events: true,
272
+ address: '0xae7ab96520de3a18e5e111b5eaab095312d7fe84',
273
+ from: '0x90e481d9a664ebbe4be180d9501962255463036d',
274
+ to: '0xa9866ef5574a256b4b85ad2b80880da2ef1b0011',
275
+ value: '0x38d7ea4c68000',
276
+ },
277
+ ],
278
+ erc721: [],
279
+ data:
280
+ '0xa9059cbb000000000000000000000000a9866ef5574a256b4b85ad2b80880da2ef1b001100000000000000000000000000000000000000000000000000038d7ea4c68000',
281
+ },
282
+ {
283
+ blockHash: '0x719dbca35139355c6c4e38044fa3b26443c9731380b42c77cfb5398b25cfd4a9',
284
+ blockNumber: '0xdfffc6',
285
+ timestamp: '0x626c049a',
286
+ confirmations: 131953,
287
+ addressIndex: 11,
288
+ hash: '0xa4cc4c2e35a9a0a321be60e22c7ab8470b32efd81dbd5f1324f60392465b1b1e',
289
+ nonce: '0x2',
290
+ gasPrice: '0x8e18e8c8c',
291
+ gas: '0x175b7',
292
+ gasUsed: '0x110fb',
293
+ to: '0xae7ab96520de3a18e5e111b5eaab095312d7fe84',
294
+ from: '0x90e481d9a664ebbe4be180d9501962255463036d',
295
+ value: '0x0',
296
+ status: 1,
297
+ error: null,
298
+ internal: [],
299
+ erc20: [
300
+ {
301
+ events: true,
302
+ address: '0xae7ab96520de3a18e5e111b5eaab095312d7fe84',
303
+ from: '0x90e481d9a664ebbe4be180d9501962255463036d',
304
+ to: '0xa9866ef5574a256b4b85ad2b80880da2ef1b0011',
305
+ value: '0x5af3107a4000',
306
+ },
307
+ ],
308
+ erc721: [],
309
+ data:
310
+ '0xa9059cbb000000000000000000000000a9866ef5574a256b4b85ad2b80880da2ef1b001100000000000000000000000000000000000000000000000000005af3107a4000',
311
+ },
312
+ {
313
+ blockHash: '0x1953c1bb935f744629f26d794df5280d3b2165aea45057747d75683785cb9f9a',
314
+ blockNumber: '0xe0671e',
315
+ timestamp: '0x62717f3f',
316
+ confirmations: 105497,
317
+ addressIndex: 13,
318
+ hash: '0x35390bc5ff89d3ecad114fe3b2898b8fe4c96ec176fcecc3e29e55a2d8d51d9e',
319
+ nonce: '0x1bba06',
320
+ gasPrice: '0xf41c06ac0',
321
+ gas: '0xf618',
322
+ gasUsed: '0x5208',
323
+ to: '0x90e481d9a664ebbe4be180d9501962255463036d',
324
+ from: '0xc098b2a3aa256d2140208c3de6543aaef5cd3a94',
325
+ value: '0xfeaf90ad2c000',
326
+ status: 1,
327
+ error: null,
328
+ internal: [],
329
+ erc20: [],
330
+ erc721: [],
331
+ data: '0x',
332
+ },
333
+ {
334
+ blockHash: '0x1a7886725a5ebc312d7e407f20988d972fbbbfeabf8b6a98564345aee87e3481',
335
+ blockNumber: '0xe1f4b7',
336
+ timestamp: '0x6286ec8e',
337
+ confirmations: 3712,
338
+ addressIndex: 14,
339
+ hash: '0x2f613acaebb34300a5c1bb25e2fa1c92f48cea469066fedb067d734292f31812',
340
+ nonce: '0x3',
341
+ gasPrice: '0x42426923b',
342
+ gas: '0x5208',
343
+ gasUsed: '0x5208',
344
+ to: '0xf6c138c36341138ddfc314a11038da8264b7ef09',
345
+ from: '0x90e481d9a664ebbe4be180d9501962255463036d',
346
+ value: '0x1d3353f4626400',
347
+ status: 1,
348
+ error: null,
349
+ internal: [],
350
+ erc20: [],
351
+ erc721: [],
352
+ data: '0x',
353
+ },
354
+ ],
355
+ [],
356
+ ],
357
+ }
@@ -0,0 +1,174 @@
1
+ import { EthereumMonitor } from '../ethereum-monitor'
2
+ import { size, omit } from 'lodash'
3
+ import { AccountState } from '@exodus/models'
4
+ import { once } from 'events'
5
+ import { ethereum as feeData } from '@exodus/ethereum-lib/src/fee-data'
6
+ import assetMap from './assets-for-test-helper'
7
+ import { createAssetClientInterface } from './asset-client-interface-test-helper'
8
+ import { create } from '../../exodus-eth-server/api'
9
+
10
+ const EXODUS_ETH_SERVER_URL = 'https://geth.a.exodus.io/wallet/v1/'
11
+
12
+ jest.setTimeout(10000)
13
+
14
+ export const logger = {
15
+ trace: jest.fn(),
16
+ debug: jest.fn(),
17
+ log: jest.fn(),
18
+ info: jest.fn(),
19
+ warn: jest.fn(),
20
+ error: jest.fn(),
21
+ }
22
+
23
+ afterEach(() => {
24
+ Object.values(logger).forEach((fn) => fn.mockReset())
25
+ })
26
+
27
+ const { ethereum } = assetMap
28
+
29
+ // Replacing default gasPrice to be sure WS will change it
30
+ const dummyGasPrice = ethereum.currency.Gwei(1) // 1 is the min fee...
31
+ const feeDataMock = feeData.update({ gasPrice: dummyGasPrice.toString() })
32
+ expect(feeDataMock.gasPrice).toEqual(dummyGasPrice)
33
+
34
+ export default class EthereumAccountState extends AccountState {
35
+ static defaults = {
36
+ cursor: '',
37
+ balance: ethereum.currency.ZERO,
38
+ tokenBalances: {},
39
+ }
40
+ }
41
+
42
+ ethereum.api = {
43
+ createAccountState: () => EthereumAccountState,
44
+ getConfirmationsNumber: () => 2,
45
+ getFeeData: () => feeDataMock,
46
+ }
47
+
48
+ // Fernando's dev wallet. Profile 1 and Profile 2
49
+ export const walletPublicKeys = {
50
+ ethereum: [
51
+ Buffer.from('0273c38a3c31c31b361dc8d6b93e56c316e34991c478d3a14ea3fcd1ab552bc25e', 'hex'),
52
+ Buffer.from('02f33b1edf1016f6720518c776da30567fc7b7052ae6b596dd22909e0a87164f8d', 'hex'),
53
+ ],
54
+ }
55
+
56
+ describe('ethereum monitor', () => {
57
+ test('can start monitor and update txs', async () => {
58
+ const assetClientInterface = createAssetClientInterface({ logger, walletPublicKeys })
59
+ const server = create(EXODUS_ETH_SERVER_URL)
60
+ const getHistoryV2 = jest.fn(async (...args) => {
61
+ const transactions = await server.getHistoryV2(...args)
62
+ return transactions.filter((tx) => {
63
+ return parseInt(tx.blockNumber, 16) < 14808250
64
+ })
65
+ })
66
+ const monitor = new EthereumMonitor({
67
+ interval: 20,
68
+ asset: ethereum,
69
+ assetClientInterface,
70
+ logger,
71
+ server: { ...server, getHistoryV2 },
72
+ })
73
+ try {
74
+ await monitor.start()
75
+ expect(logger.error).not.toBeCalled()
76
+ expect(logger.warn).not.toBeCalled()
77
+ const toBalanceFromTx = (txSet) => {
78
+ return txSet.getMutations().slice(-1)[0].balance
79
+ }
80
+ // Sintax sugar
81
+ const txs = (walletAccount, assetName) => {
82
+ return assetClientInterface.getTxLog({ walletAccount, assetName })
83
+ }
84
+ const state = (walletAccount, assetName) => {
85
+ return assetClientInterface.getAccountState({ walletAccount, assetName })
86
+ }
87
+
88
+ const expectSameValue = (actual, expected) => {
89
+ expect(actual).toEqual(expected)
90
+ expect(actual.equals(expected)).toEqual(true)
91
+ }
92
+
93
+ expect((await txs('exodus0', 'ethereum')).size).toEqual(7)
94
+ expect((await txs('exodus0', 'bat')).size).toEqual(1)
95
+ expect((await txs('exodus0', 'tetherusd')).size).toEqual(3)
96
+ expect((await txs('exodus1', 'ethereum')).size).toEqual(1)
97
+
98
+ expectSameValue(
99
+ toBalanceFromTx(await txs('exodus0', 'ethereum')),
100
+ ethereum.currency.defaultUnit('0.051201488965893697') // string due to floating error
101
+ )
102
+ expectSameValue(
103
+ toBalanceFromTx(await txs('exodus0', 'bat')),
104
+ assetMap.bat.currency.defaultUnit(8.42277112)
105
+ )
106
+ expectSameValue(
107
+ toBalanceFromTx(await txs('exodus0', 'tetherusd')),
108
+ assetMap.tetherusd.currency.defaultUnit(7.414404)
109
+ )
110
+ expectSameValue(
111
+ toBalanceFromTx(await txs('exodus1', 'ethereum')),
112
+ ethereum.currency.defaultUnit(0.00821921)
113
+ )
114
+
115
+ // It seems eth balances and tokenBalances are not being filled. Clients needs to read tx like above
116
+ expectSameValue(
117
+ (await state('exodus0', 'ethereum')).balance,
118
+ ethereum.currency.defaultUnit(0)
119
+ )
120
+ expect((await state('exodus0', 'ethereum')).tokenBalances).toEqual({})
121
+ expectSameValue(
122
+ (await state('exodus1', 'ethereum')).balance,
123
+ ethereum.currency.defaultUnit(0)
124
+ )
125
+ expect((await state('exodus1', 'ethereum')).tokenBalances).toEqual({})
126
+ expect(size(assetClientInterface.states)).toEqual(2)
127
+ } finally {
128
+ await monitor.stop()
129
+ }
130
+ expect(logger.error).not.toBeCalled()
131
+ expect(logger.warn).not.toBeCalled()
132
+ expect(monitor.timer.isRunning).toEqual(false)
133
+ })
134
+
135
+ test('can start and update gas price', async () => {
136
+ // ws is not reliable enough to finish on time.
137
+ const server = create(EXODUS_ETH_SERVER_URL)
138
+ const assetClientInterface = createAssetClientInterface({ logger, walletPublicKeys })
139
+ const monitor = new EthereumMonitor({
140
+ interval: 20,
141
+ asset: ethereum,
142
+ assetClientInterface,
143
+ logger,
144
+ server,
145
+ })
146
+ try {
147
+ expect(await assetClientInterface.getFeeData({ assetName: ethereum.name })).toEqual(
148
+ feeDataMock
149
+ )
150
+
151
+ const oncePromise = once(assetClientInterface, 'fee-config-updated')
152
+ await monitor.start()
153
+ await oncePromise
154
+ // Once started, feeData gets updated
155
+ expect(await assetClientInterface.getFeeData({ assetName: ethereum.name })).not.toEqual(
156
+ feeDataMock
157
+ )
158
+ // gas price and origin are the changed ones.
159
+ expect(
160
+ omit(
161
+ await assetClientInterface.getFeeData({ assetName: ethereum.name }),
162
+ 'gasPrice',
163
+ 'origin'
164
+ )
165
+ ).toEqual(omit(feeDataMock, 'gasPrice', 'origin'))
166
+ } finally {
167
+ await monitor.stop()
168
+ }
169
+
170
+ expect(logger.error).not.toBeCalled()
171
+ expect(logger.warn).not.toBeCalled()
172
+ expect(monitor.timer.isRunning).toEqual(false)
173
+ })
174
+ })
@@ -0,0 +1,160 @@
1
+ import { EthereumMonitor } from '../ethereum-monitor'
2
+ import { encodePublic } from '@exodus/ethereum-lib'
3
+ import { createAssetClientInterface } from './asset-client-interface-test-helper'
4
+ import assetMap from './assets-for-test-helper'
5
+ import { AccountState } from '@exodus/models'
6
+ import { ethereum as feeData } from '@exodus/ethereum-lib/src/fee-data'
7
+ import historyReturnValuesForTest from './ethereum-history-return-values-for-test-helper'
8
+ import { size, cloneDeep } from 'lodash'
9
+
10
+ const { ethereum } = assetMap
11
+
12
+ export default class EthereumAccountState extends AccountState {
13
+ static defaults = {
14
+ cursor: '',
15
+ balance: ethereum.currency.ZERO,
16
+ tokenBalances: {},
17
+ }
18
+ }
19
+
20
+ ethereum.api = {
21
+ createAccountState: () => EthereumAccountState,
22
+ getConfirmationsNumber: () => 2,
23
+ getFeeData: () => feeData,
24
+ }
25
+
26
+ export const logger = {
27
+ trace: jest.fn(),
28
+ debug: jest.fn(),
29
+ log: jest.fn(),
30
+ info: jest.fn(),
31
+ warn: jest.fn(),
32
+ error: jest.fn((...args) => console.error(args)),
33
+ }
34
+
35
+ afterEach(() => {
36
+ Object.values(logger).forEach((fn) => fn.mockReset())
37
+ })
38
+
39
+ // Fernando's dev wallet. Profile 1 and Profile 2
40
+ export const walletPublicKeys = {
41
+ ethereum: [
42
+ Buffer.from('0273c38a3c31c31b361dc8d6b93e56c316e34991c478d3a14ea3fcd1ab552bc25e', 'hex'),
43
+ Buffer.from('02f33b1edf1016f6720518c776da30567fc7b7052ae6b596dd22909e0a87164f8d', 'hex'),
44
+ ],
45
+ }
46
+
47
+ describe('ethereum monitor', () => {
48
+ test('can create monitor', () => {
49
+ const server = {
50
+ getURL() {
51
+ return 'https://mockMe'
52
+ },
53
+ ws: { watch: jest.fn(), events: { on: jest.fn() } },
54
+
55
+ getHistoryV2: jest.fn(() => {
56
+ return Promise.resolve([])
57
+ }),
58
+ }
59
+ const monitor = new EthereumMonitor({
60
+ interval: 20,
61
+ asset: ethereum,
62
+ assetClientInterface: createAssetClientInterface({ logger }),
63
+ logger,
64
+ server: server,
65
+ })
66
+ expect(monitor.server.getURL()).toEqual('https://mockMe')
67
+
68
+ expect(logger.warn).not.toBeCalled()
69
+ expect(logger.error).not.toBeCalled()
70
+ })
71
+
72
+ test('can start and stop monitor using simulated data', async () => {
73
+ const assetClientInterface = createAssetClientInterface({ logger, walletPublicKeys })
74
+
75
+ const getHistoryV2Returns = cloneDeep(historyReturnValuesForTest)
76
+ const server = {
77
+ getURL() {
78
+ return 'https://mockMe'
79
+ },
80
+ ws: { watch: jest.fn(), events: { on: jest.fn() }, open: jest.fn() },
81
+
82
+ getHistoryV2: jest.fn((address) => {
83
+ const history = getHistoryV2Returns[address]
84
+ const txPage = history?.shift()
85
+ return Promise.resolve(txPage || [])
86
+ }),
87
+ }
88
+
89
+ const monitor = new EthereumMonitor({
90
+ interval: 20,
91
+ asset: ethereum,
92
+ assetClientInterface,
93
+ logger,
94
+ server: server,
95
+ })
96
+ await monitor.start()
97
+ await monitor.stop()
98
+ expect(logger.warn).not.toBeCalled()
99
+ expect(logger.error).not.toBeCalled()
100
+
101
+ const toBalanceFromTx = (txSet) => {
102
+ return txSet.getMutations().slice(-1)[0].balance
103
+ }
104
+
105
+ // Sintax sugar
106
+ const txs = (walletAccount, assetName) => {
107
+ return assetClientInterface.getTxLog({ walletAccount, assetName })
108
+ }
109
+ const state = (walletAccount, assetName) => {
110
+ return assetClientInterface.getAccountState({ walletAccount, assetName })
111
+ }
112
+
113
+ const expectSameValue = (actual, expected) => {
114
+ expect(actual).toEqual(expected)
115
+ expect(actual.equals(expected)).toEqual(true)
116
+ }
117
+
118
+ expect((await txs('exodus0', 'ethereum')).size).toEqual(7)
119
+ expect((await txs('exodus0', 'bat')).size).toEqual(1)
120
+ expect((await txs('exodus0', 'tetherusd')).size).toEqual(3)
121
+ expect((await txs('exodus1', 'ethereum')).size).toEqual(1)
122
+
123
+ expectSameValue(
124
+ toBalanceFromTx(await txs('exodus0', 'ethereum')),
125
+ ethereum.currency.defaultUnit('0.051201488965893697') // string due to floating error
126
+ )
127
+ expectSameValue(
128
+ toBalanceFromTx(await txs('exodus0', 'bat')),
129
+ assetMap.bat.currency.defaultUnit(8.42277112)
130
+ )
131
+ expectSameValue(
132
+ toBalanceFromTx(await txs('exodus0', 'tetherusd')),
133
+ assetMap.tetherusd.currency.defaultUnit(7.414404)
134
+ )
135
+ expectSameValue(
136
+ toBalanceFromTx(await txs('exodus1', 'ethereum')),
137
+ ethereum.currency.defaultUnit(0.00821921)
138
+ )
139
+
140
+ // It seems eth balances and tokenBalances are not being filled. Clients needs to read tx like above
141
+ expectSameValue((await state('exodus0', 'ethereum')).balance, ethereum.currency.defaultUnit(0))
142
+ expect((await state('exodus0', 'ethereum')).tokenBalances).toEqual({})
143
+ expectSameValue((await state('exodus1', 'ethereum')).balance, ethereum.currency.defaultUnit(0))
144
+ expect((await state('exodus1', 'ethereum')).tokenBalances).toEqual({})
145
+ expect(size(assetClientInterface.states)).toEqual(2)
146
+
147
+ expect(logger.error).not.toBeCalled()
148
+ expect(logger.warn).not.toBeCalled()
149
+ expect(monitor.timer.isRunning).toEqual(false)
150
+ })
151
+
152
+ test('validate address', () => {
153
+ expect(encodePublic(walletPublicKeys.ethereum[0])).toEqual(
154
+ '0x90E481d9A664ebbE4Be180d9501962255463036d'
155
+ )
156
+ expect(encodePublic(walletPublicKeys.ethereum[1])).toEqual(
157
+ '0xf6c138C36341138dDFC314a11038dA8264B7Ef09'
158
+ )
159
+ })
160
+ })