@exodus/ethereum-api 2.10.0 → 2.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/exodus-eth-server/api.js +6 -1
- package/src/tx-log/__tests__/asset-client-interface-test-helper.js +0 -22
- package/src/tx-log/__tests__/assets-for-test-helper.js +0 -30
- package/src/tx-log/__tests__/bsc-history-return-values-for-test-helper.js +0 -94
- package/src/tx-log/__tests__/bsc-monitor.integration.test.js +0 -166
- package/src/tx-log/__tests__/bsc-monitor.test.js +0 -184
- package/src/tx-log/__tests__/ethereum-history-return-values-for-test-helper.js +0 -357
- package/src/tx-log/__tests__/ethereum-history-unknown-token-helper.js +0 -612
- package/src/tx-log/__tests__/ethereum-monitor.integration.test.js +0 -174
- package/src/tx-log/__tests__/ethereum-monitor.test.js +0 -241
- package/src/tx-log/__tests__/in-memory-asset-client-interface.js +0 -196
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/ethereum-api",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.0",
|
|
4
4
|
"description": "Ethereum Api",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"author": "Exodus Movement, Inc.",
|
|
@@ -27,5 +27,5 @@
|
|
|
27
27
|
"@exodus/assets-base": "^8.0.136",
|
|
28
28
|
"@exodus/models": "^8.7.2"
|
|
29
29
|
},
|
|
30
|
-
"gitHead": "
|
|
30
|
+
"gitHead": "de5323b963812c9da9e7554664b5b562605a52bd"
|
|
31
31
|
}
|
|
@@ -69,6 +69,10 @@ export function create(defaultURL) {
|
|
|
69
69
|
return requestWithRetry('balance', { address, from: opts.startblock, to: opts.endblock })
|
|
70
70
|
},
|
|
71
71
|
|
|
72
|
+
async getBalanceProxied(address, tag = 'latest') {
|
|
73
|
+
return requestWithRetry('proxy', { method: 'eth_getBalance', address, tag })
|
|
74
|
+
},
|
|
75
|
+
|
|
72
76
|
async balanceOf(address, tokenAddress, tag = 'latest') {
|
|
73
77
|
const contract = simpleErc20(tokenAddress)
|
|
74
78
|
const callData = contract.balanceOf.build(address)
|
|
@@ -136,7 +140,8 @@ export function create(defaultURL) {
|
|
|
136
140
|
},
|
|
137
141
|
|
|
138
142
|
async sendRawTransaction(data) {
|
|
139
|
-
|
|
143
|
+
const hex = data.startsWith('0x') ? data : '0x' + data
|
|
144
|
+
return requestWithRetry('proxy', { method: 'eth_sendRawTransaction', hex })
|
|
140
145
|
},
|
|
141
146
|
|
|
142
147
|
async estimateGas(data, tag = 'latest') {
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { InMemoryAssetClientInterface } from './in-memory-asset-client-interface'
|
|
2
|
-
import assetMap from './assets-for-test-helper'
|
|
3
|
-
import assert from 'minimalistic-assert'
|
|
4
|
-
|
|
5
|
-
export const createAssetClientInterface = ({ logger, walletPublicKeys }) =>
|
|
6
|
-
new InMemoryAssetClientInterface({
|
|
7
|
-
logger,
|
|
8
|
-
assets: assetMap,
|
|
9
|
-
walletAccounts: { exodus0: { index: 0 }, exodus1: { index: 1 } },
|
|
10
|
-
wallet: {
|
|
11
|
-
genPublicKey: async ({ accountIndex, baseAssetName }) => {
|
|
12
|
-
const publicKey = walletPublicKeys[baseAssetName][accountIndex]
|
|
13
|
-
assert(
|
|
14
|
-
publicKey,
|
|
15
|
-
`public key for asset ${baseAssetName} index ${accountIndex} cannot be resolved!`
|
|
16
|
-
)
|
|
17
|
-
return Promise.resolve({
|
|
18
|
-
publicKey,
|
|
19
|
-
})
|
|
20
|
-
},
|
|
21
|
-
},
|
|
22
|
-
})
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { mapValues } from 'lodash'
|
|
2
|
-
import rawAssetMap from '@exodus/assets'
|
|
3
|
-
import { encodePublic, isEthereumLike } from '@exodus/ethereum-lib'
|
|
4
|
-
|
|
5
|
-
const copiedAssetMap = mapValues(rawAssetMap, (rawAsset) => ({ ...rawAsset }))
|
|
6
|
-
|
|
7
|
-
export const keys = {
|
|
8
|
-
encodePublic,
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
// simulates how clients transform assets from @exodus/assets
|
|
12
|
-
const expandRawAsset = (asset) => {
|
|
13
|
-
const rawAsset = rawAssetMap[asset.name]
|
|
14
|
-
asset.baseAsset = rawAssetMap[rawAsset.baseAsset.name]
|
|
15
|
-
asset.feeAsset = rawAssetMap[rawAsset.feeAsset.name]
|
|
16
|
-
if (asset.isCombined) {
|
|
17
|
-
asset.combinedAssetNames = asset.combinedAssetNames.filter((assetName) => asset[assetName])
|
|
18
|
-
asset.combinedAssets = asset.combinedAssetNames.map((assetName) => asset[assetName])
|
|
19
|
-
}
|
|
20
|
-
if (isEthereumLike(asset)) {
|
|
21
|
-
asset.keys = keys
|
|
22
|
-
}
|
|
23
|
-
if (asset.contract?.current) {
|
|
24
|
-
// transformation hack
|
|
25
|
-
asset.contract.address = asset.contract.current
|
|
26
|
-
}
|
|
27
|
-
return [asset.name, asset]
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export default Object.fromEntries(Object.values(copiedAssetMap).map(expandRawAsset))
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
'0x90e481d9a664ebbe4be180d9501962255463036d': [
|
|
3
|
-
[
|
|
4
|
-
{
|
|
5
|
-
blockHash: '0xe8487b0e2a6f8410b2e05536e06fd75eaf2f091d6ab8d91c920b9916673e2757',
|
|
6
|
-
blockNumber: '0x10208d9',
|
|
7
|
-
timestamp: '0x6256c8f5',
|
|
8
|
-
confirmations: 1142596,
|
|
9
|
-
addressIndex: 0,
|
|
10
|
-
hash: '0xcf8d3f903e38b15ed0a32a0137faed35d74ebc15dec8b99f0300eb72be19b0b0',
|
|
11
|
-
nonce: '0x109',
|
|
12
|
-
gasPrice: '0x174876e80',
|
|
13
|
-
gas: '0x6f952',
|
|
14
|
-
gasUsed: '0x5cfc5',
|
|
15
|
-
to: '0xc748673057861a797275cd8a068abb95a902e8de',
|
|
16
|
-
from: '0xa9866ef5574a256b4b85ad2b80880da2ef1b0011',
|
|
17
|
-
value: '0x0',
|
|
18
|
-
status: 1,
|
|
19
|
-
error: null,
|
|
20
|
-
internal: [],
|
|
21
|
-
erc20: [
|
|
22
|
-
{
|
|
23
|
-
events: true,
|
|
24
|
-
address: '0xc748673057861a797275cd8a068abb95a902e8de',
|
|
25
|
-
from: '0xa9866ef5574a256b4b85ad2b80880da2ef1b0011',
|
|
26
|
-
to: '0x90e481d9a664ebbe4be180d9501962255463036d',
|
|
27
|
-
value: '0xcc74a8c9c5124',
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
events: false,
|
|
31
|
-
address: '0xc748673057861a797275cd8a068abb95a902e8de',
|
|
32
|
-
from: '0xa9866ef5574a256b4b85ad2b80880da2ef1b0011',
|
|
33
|
-
to: '0x90e481d9a664ebbe4be180d9501962255463036d',
|
|
34
|
-
value: '0xe32c49c3be860',
|
|
35
|
-
},
|
|
36
|
-
],
|
|
37
|
-
erc721: [],
|
|
38
|
-
data:
|
|
39
|
-
'0xa9059cbb00000000000000000000000090e481d9a664ebbe4be180d9501962255463036d000000000000000000000000000000000000000000000000000e32c49c3be860',
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
blockHash: '0x499b9ba9c99064eeaded737c8a3135b52a10bbed460a064b14efe08810887ef3',
|
|
43
|
-
blockNumber: '0x1051668',
|
|
44
|
-
timestamp: '0x6260033c',
|
|
45
|
-
confirmations: 942517,
|
|
46
|
-
addressIndex: 2,
|
|
47
|
-
hash: '0xd9602fd41cb44e8d17e965de0c057245d4cb39c1250a3874b7c9f2dc3c9fe78e',
|
|
48
|
-
nonce: '0x4873d6',
|
|
49
|
-
gasPrice: '0x2540be400',
|
|
50
|
-
gas: '0x32918',
|
|
51
|
-
gasUsed: '0x5208',
|
|
52
|
-
to: '0x90e481d9a664ebbe4be180d9501962255463036d',
|
|
53
|
-
from: '0xa180fe01b906a1be37be6c534a3300785b20d947',
|
|
54
|
-
value: '0x21c0331d5dc000',
|
|
55
|
-
status: 1,
|
|
56
|
-
error: null,
|
|
57
|
-
internal: [],
|
|
58
|
-
erc20: [],
|
|
59
|
-
erc721: [],
|
|
60
|
-
data: '0x',
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
blockHash: '0x0b4e6b2aa26af46f803e55a644312fcda2b4b905b0023a9b995bdf38ccf0f8f7',
|
|
64
|
-
blockNumber: '0x1052328',
|
|
65
|
-
timestamp: '0x62602980',
|
|
66
|
-
confirmations: 939253,
|
|
67
|
-
addressIndex: 3,
|
|
68
|
-
hash: '0x7bcca25c1672d3de101a9a848c04413b40667fa77e97b939a366e775b89d62cd',
|
|
69
|
-
nonce: '0x88e362',
|
|
70
|
-
gasPrice: '0x2540be400',
|
|
71
|
-
gas: '0x32918',
|
|
72
|
-
gasUsed: '0xc7ab',
|
|
73
|
-
to: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82',
|
|
74
|
-
from: '0xe2fc31f816a9b94326492132018c3aecc4a93ae1',
|
|
75
|
-
value: '0x0',
|
|
76
|
-
status: 1,
|
|
77
|
-
error: null,
|
|
78
|
-
internal: [],
|
|
79
|
-
erc20: [
|
|
80
|
-
{
|
|
81
|
-
events: true,
|
|
82
|
-
address: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82',
|
|
83
|
-
from: '0xe2fc31f816a9b94326492132018c3aecc4a93ae1',
|
|
84
|
-
to: '0x90e481d9a664ebbe4be180d9501962255463036d',
|
|
85
|
-
value: '0x1fdd07d5d44c0000',
|
|
86
|
-
},
|
|
87
|
-
],
|
|
88
|
-
erc721: [],
|
|
89
|
-
data:
|
|
90
|
-
'0xa9059cbb00000000000000000000000090e481d9a664ebbe4be180d9501962255463036d0000000000000000000000000000000000000000000000001fdd07d5d44c0000',
|
|
91
|
-
},
|
|
92
|
-
],
|
|
93
|
-
],
|
|
94
|
-
}
|
|
@@ -1,166 +0,0 @@
|
|
|
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 { bsc 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_BSC_SERVER_URL = 'https://bsc.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 { bsc } = assetMap
|
|
28
|
-
|
|
29
|
-
// Replacing default gasPrice to be sure WS will change it
|
|
30
|
-
const dummyGasPrice = bsc.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: bsc.currency.ZERO,
|
|
38
|
-
tokenBalances: {},
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
bsc.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
|
-
bsc: [
|
|
51
|
-
Buffer.from('0273c38a3c31c31b361dc8d6b93e56c316e34991c478d3a14ea3fcd1ab552bc25e', 'hex'),
|
|
52
|
-
Buffer.from('02f33b1edf1016f6720518c776da30567fc7b7052ae6b596dd22909e0a87164f8d', 'hex'),
|
|
53
|
-
],
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
describe('bsc monitor', () => {
|
|
57
|
-
test('can start monitor and update txs', async () => {
|
|
58
|
-
const assetClientInterface = createAssetClientInterface({ logger, walletPublicKeys })
|
|
59
|
-
const server = create(EXODUS_BSC_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) < 0x1052330
|
|
64
|
-
})
|
|
65
|
-
})
|
|
66
|
-
const monitor = new EthereumMonitor({
|
|
67
|
-
interval: 20,
|
|
68
|
-
asset: bsc,
|
|
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.toDefault()).toEqual(expected.toDefault())
|
|
90
|
-
expect(actual.equals(expected)).toEqual(true)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
expect((await txs('exodus0', 'bsc')).size).toEqual(1)
|
|
94
|
-
expect((await txs('exodus0', 'pancakeswap')).size).toEqual(1)
|
|
95
|
-
expect((await txs('exodus0', 'babydoge_bsc')).size).toEqual(1)
|
|
96
|
-
|
|
97
|
-
expectSameValue(
|
|
98
|
-
toBalanceFromTx(await txs('exodus0', 'bsc')),
|
|
99
|
-
bsc.currency.baseUnit(9500000000000000)
|
|
100
|
-
)
|
|
101
|
-
expectSameValue(
|
|
102
|
-
toBalanceFromTx(await txs('exodus0', 'pancakeswap')),
|
|
103
|
-
assetMap.pancakeswap.currency.defaultUnit(2.296)
|
|
104
|
-
)
|
|
105
|
-
const txBabyDodge = assetMap.babydoge_bsc.currency.defaultUnit('3596822.721089828')
|
|
106
|
-
expectSameValue(toBalanceFromTx(await txs('exodus0', 'babydoge_bsc')), txBabyDodge)
|
|
107
|
-
|
|
108
|
-
// Bsc and babydoge_bsc are special. Balance is loaded from getBalance RPC, not from transaction.
|
|
109
|
-
// see isRpcBalanceAsset
|
|
110
|
-
// It seems eth balances and tokenBalances are not being filled. Clients need to read tx like above
|
|
111
|
-
// NOTE THAT THESE BALANCE ASSERTIONS MAY FAIL IF TRANSFERING FUNDS..
|
|
112
|
-
expectSameValue(
|
|
113
|
-
(await state('exodus0', 'bsc')).balance,
|
|
114
|
-
assetMap.bsc.currency.defaultUnit(0.0095)
|
|
115
|
-
)
|
|
116
|
-
// Baby dodge balance is greater than tx balance due to the offchain rewards...
|
|
117
|
-
expect((await state('exodus0', 'bsc')).tokenBalances.babydoge_bsc.gt(txBabyDodge)).toEqual(
|
|
118
|
-
true
|
|
119
|
-
)
|
|
120
|
-
expectSameValue((await state('exodus1', 'bsc')).balance, bsc.currency.baseUnit(0))
|
|
121
|
-
expect((await state('exodus1', 'bsc')).tokenBalances).toEqual({
|
|
122
|
-
babydoge_bsc: assetMap.babydoge_bsc.currency.baseUnit(0),
|
|
123
|
-
})
|
|
124
|
-
expect(size(assetClientInterface.states)).toEqual(2)
|
|
125
|
-
} finally {
|
|
126
|
-
await monitor.stop()
|
|
127
|
-
}
|
|
128
|
-
expect(logger.error).not.toBeCalled()
|
|
129
|
-
expect(logger.warn).not.toBeCalled()
|
|
130
|
-
expect(monitor.timer.isRunning).toEqual(false)
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
test('can start and update gas price', async () => {
|
|
134
|
-
// ws is not reliable enough to finish on time.
|
|
135
|
-
const server = create(EXODUS_BSC_SERVER_URL)
|
|
136
|
-
const assetClientInterface = createAssetClientInterface({ logger, walletPublicKeys })
|
|
137
|
-
const monitor = new EthereumMonitor({
|
|
138
|
-
interval: 20,
|
|
139
|
-
asset: bsc,
|
|
140
|
-
assetClientInterface,
|
|
141
|
-
logger,
|
|
142
|
-
server,
|
|
143
|
-
})
|
|
144
|
-
try {
|
|
145
|
-
expect(await assetClientInterface.getFeeData({ assetName: bsc.name })).toEqual(feeDataMock)
|
|
146
|
-
|
|
147
|
-
const oncePromise = once(assetClientInterface, 'fee-config-updated')
|
|
148
|
-
await monitor.start()
|
|
149
|
-
await oncePromise
|
|
150
|
-
// Once started, feeData gets updated
|
|
151
|
-
expect(await assetClientInterface.getFeeData({ assetName: bsc.name })).not.toEqual(
|
|
152
|
-
feeDataMock
|
|
153
|
-
)
|
|
154
|
-
// gas price and origin are the changed ones.
|
|
155
|
-
expect(
|
|
156
|
-
omit(await assetClientInterface.getFeeData({ assetName: bsc.name }), 'gasPrice', 'origin')
|
|
157
|
-
).toEqual(omit(feeDataMock, 'gasPrice', 'origin'))
|
|
158
|
-
} finally {
|
|
159
|
-
await monitor.stop()
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
expect(logger.error).not.toBeCalled()
|
|
163
|
-
expect(logger.warn).not.toBeCalled()
|
|
164
|
-
expect(monitor.timer.isRunning).toEqual(false)
|
|
165
|
-
})
|
|
166
|
-
})
|
|
@@ -1,184 +0,0 @@
|
|
|
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 { bsc as feeData } from '@exodus/ethereum-lib/src/fee-data'
|
|
7
|
-
import historyReturnValuesForTest from './bsc-history-return-values-for-test-helper'
|
|
8
|
-
import { size, cloneDeep } from 'lodash'
|
|
9
|
-
|
|
10
|
-
const { bsc } = assetMap
|
|
11
|
-
|
|
12
|
-
export default class EthereumAccountState extends AccountState {
|
|
13
|
-
static defaults = {
|
|
14
|
-
cursor: '',
|
|
15
|
-
balance: bsc.currency.ZERO,
|
|
16
|
-
tokenBalances: {},
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
bsc.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
|
-
bsc: [
|
|
42
|
-
Buffer.from('0273c38a3c31c31b361dc8d6b93e56c316e34991c478d3a14ea3fcd1ab552bc25e', 'hex'),
|
|
43
|
-
Buffer.from('02f33b1edf1016f6720518c776da30567fc7b7052ae6b596dd22909e0a87164f8d', 'hex'),
|
|
44
|
-
],
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
describe('bsc 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: bsc,
|
|
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
|
-
balanceOf: jest.fn((walletAddress, contractAddress) => {
|
|
89
|
-
// jest doesn't to have when-some-arg-then-some-value kind of mocking
|
|
90
|
-
// https://github.com/facebook/jest/issues/6180
|
|
91
|
-
const balances = {
|
|
92
|
-
[`${encodePublic(walletPublicKeys.bsc[0])}-${
|
|
93
|
-
assetMap.babydoge_bsc.contract.address
|
|
94
|
-
}`.toLowerCase()]: 3610932917151657,
|
|
95
|
-
}
|
|
96
|
-
const expectedKey = `${walletAddress}-${contractAddress}`.toLowerCase()
|
|
97
|
-
const balance = balances[expectedKey] || 0
|
|
98
|
-
return Promise.resolve({
|
|
99
|
-
confirmed: {
|
|
100
|
-
[contractAddress]: balance,
|
|
101
|
-
},
|
|
102
|
-
})
|
|
103
|
-
}),
|
|
104
|
-
|
|
105
|
-
getBalance: jest.fn((walletAddress) => {
|
|
106
|
-
const balances = {
|
|
107
|
-
[encodePublic(walletPublicKeys.bsc[0]).toLowerCase()]: 10500000000000000,
|
|
108
|
-
}
|
|
109
|
-
const balance = `${balances[walletAddress.toLowerCase()] || 0}`
|
|
110
|
-
return Promise.resolve({ confirmed: { value: balance } })
|
|
111
|
-
}),
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const monitor = new EthereumMonitor({
|
|
115
|
-
interval: 20,
|
|
116
|
-
asset: bsc,
|
|
117
|
-
assetClientInterface,
|
|
118
|
-
logger,
|
|
119
|
-
server: server,
|
|
120
|
-
})
|
|
121
|
-
await monitor.start()
|
|
122
|
-
await monitor.stop()
|
|
123
|
-
expect(logger.warn).not.toBeCalled()
|
|
124
|
-
expect(logger.error).not.toBeCalled()
|
|
125
|
-
|
|
126
|
-
const toBalanceFromTx = (txSet) => {
|
|
127
|
-
return txSet.getMutations().slice(-1)[0].balance
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Sintax sugar
|
|
131
|
-
const txs = (walletAccount, assetName) => {
|
|
132
|
-
return assetClientInterface.getTxLog({ walletAccount, assetName })
|
|
133
|
-
}
|
|
134
|
-
const state = (walletAccount, assetName) => {
|
|
135
|
-
return assetClientInterface.getAccountState({ walletAccount, assetName })
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const expectSameValue = (actual, expected) => {
|
|
139
|
-
expect(actual.toDefault()).toEqual(expected.toDefault())
|
|
140
|
-
expect(actual.equals(expected)).toEqual(true)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
expect((await txs('exodus0', 'bsc')).size).toEqual(1)
|
|
144
|
-
expect((await txs('exodus0', 'pancakeswap')).size).toEqual(1)
|
|
145
|
-
expect((await txs('exodus0', 'babydoge_bsc')).size).toEqual(1)
|
|
146
|
-
|
|
147
|
-
expectSameValue(toBalanceFromTx(await txs('exodus0', 'bsc')), bsc.currency.defaultUnit(0.0095))
|
|
148
|
-
expectSameValue(
|
|
149
|
-
toBalanceFromTx(await txs('exodus0', 'pancakeswap')),
|
|
150
|
-
assetMap.pancakeswap.currency.defaultUnit(2.296)
|
|
151
|
-
)
|
|
152
|
-
expectSameValue(
|
|
153
|
-
toBalanceFromTx(await txs('exodus0', 'babydoge_bsc')),
|
|
154
|
-
assetMap.babydoge_bsc.currency.defaultUnit('3596822.721089828')
|
|
155
|
-
)
|
|
156
|
-
|
|
157
|
-
// Bsc and babydoge_bsc are special. Balance is loaded from getBalance RPC, not from transaction.
|
|
158
|
-
// see isRpcBalanceAsset
|
|
159
|
-
// It seems eth balances and tokenBalances are not being filled. Clients need to read tx like above
|
|
160
|
-
expectSameValue((await state('exodus0', 'bsc')).balance, bsc.currency.defaultUnit(0.0105))
|
|
161
|
-
// balance is grater than transaction balance due to the off-chain rewards.
|
|
162
|
-
expect((await state('exodus0', 'bsc')).tokenBalances).toEqual({
|
|
163
|
-
babydoge_bsc: assetMap.babydoge_bsc.currency.baseUnit(3610932917151657),
|
|
164
|
-
})
|
|
165
|
-
expectSameValue((await state('exodus1', 'bsc')).balance, assetMap.bsc.currency.baseUnit(0))
|
|
166
|
-
expect((await state('exodus1', 'bsc')).tokenBalances).toEqual({
|
|
167
|
-
babydoge_bsc: assetMap.babydoge_bsc.currency.baseUnit(0),
|
|
168
|
-
})
|
|
169
|
-
expect(size(assetClientInterface.states)).toEqual(2)
|
|
170
|
-
|
|
171
|
-
expect(logger.error).not.toBeCalled()
|
|
172
|
-
expect(logger.warn).not.toBeCalled()
|
|
173
|
-
expect(monitor.timer.isRunning).toEqual(false)
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
test('validate address', () => {
|
|
177
|
-
expect(encodePublic(walletPublicKeys.bsc[0])).toEqual(
|
|
178
|
-
'0x90E481d9A664ebbE4Be180d9501962255463036d'
|
|
179
|
-
)
|
|
180
|
-
expect(encodePublic(walletPublicKeys.bsc[1])).toEqual(
|
|
181
|
-
'0xf6c138C36341138dDFC314a11038dA8264B7Ef09'
|
|
182
|
-
)
|
|
183
|
-
})
|
|
184
|
-
})
|