@ledgerhq/coin-evm 2.8.0 → 2.9.0-nightly.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/CHANGELOG.md +6 -0
- package/lib/__tests__/coin-tester/indexer.js +1 -1
- package/lib/__tests__/coin-tester/indexer.js.map +1 -1
- package/lib/__tests__/unit/synchronization.unit.test.js +98 -5
- package/lib/__tests__/unit/synchronization.unit.test.js.map +1 -1
- package/lib/api/explorer/etherscan.d.ts.map +1 -1
- package/lib/api/explorer/etherscan.js +4 -0
- package/lib/api/explorer/etherscan.js.map +1 -1
- package/lib/api/explorer/index.d.ts.map +1 -1
- package/lib/api/explorer/index.js +3 -0
- package/lib/api/explorer/index.js.map +1 -1
- package/lib/api/explorer/none.d.ts +8 -0
- package/lib/api/explorer/none.d.ts.map +1 -0
- package/lib/api/explorer/none.js +29 -0
- package/lib/api/explorer/none.js.map +1 -0
- package/lib/config.d.ts +4 -0
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js.map +1 -1
- package/lib-es/__tests__/coin-tester/indexer.js +1 -1
- package/lib-es/__tests__/coin-tester/indexer.js.map +1 -1
- package/lib-es/__tests__/unit/synchronization.unit.test.js +98 -5
- package/lib-es/__tests__/unit/synchronization.unit.test.js.map +1 -1
- package/lib-es/api/explorer/etherscan.d.ts.map +1 -1
- package/lib-es/api/explorer/etherscan.js +4 -0
- package/lib-es/api/explorer/etherscan.js.map +1 -1
- package/lib-es/api/explorer/index.d.ts.map +1 -1
- package/lib-es/api/explorer/index.js +3 -0
- package/lib-es/api/explorer/index.js.map +1 -1
- package/lib-es/api/explorer/none.d.ts +8 -0
- package/lib-es/api/explorer/none.d.ts.map +1 -0
- package/lib-es/api/explorer/none.js +25 -0
- package/lib-es/api/explorer/none.js.map +1 -0
- package/lib-es/config.d.ts +4 -0
- package/lib-es/config.d.ts.map +1 -1
- package/lib-es/config.js.map +1 -1
- package/package.json +4 -4
- package/src/__tests__/coin-tester/indexer.ts +1 -1
- package/src/__tests__/unit/synchronization.unit.test.ts +134 -7
- package/src/api/explorer/etherscan.ts +5 -0
- package/src/api/explorer/index.ts +3 -0
- package/src/api/explorer/none.ts +19 -0
- package/src/config.ts +5 -0
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { AssertionError, fail } from "assert";
|
|
2
2
|
import BigNumber from "bignumber.js";
|
|
3
3
|
import { getEnv } from "@ledgerhq/live-env";
|
|
4
|
+
import { TokenAccount } from "@ledgerhq/types-live";
|
|
5
|
+
import { TokenCurrency } from "@ledgerhq/types-cryptoassets";
|
|
4
6
|
import { decodeAccountId } from "@ledgerhq/coin-framework/account/accountId";
|
|
5
7
|
import { AccountShapeInfo } from "@ledgerhq/coin-framework/bridge/jsHelpers";
|
|
6
|
-
import { TokenCurrency } from "@ledgerhq/types-cryptoassets";
|
|
7
|
-
import { TokenAccount } from "@ledgerhq/types-live";
|
|
8
8
|
import { makeTokenAccount } from "../fixtures/common.fixtures";
|
|
9
9
|
import * as etherscanAPI from "../../api/explorer/etherscan";
|
|
10
|
+
import { UnknownExplorer, UnknownNode } from "../../errors";
|
|
10
11
|
import * as synchronization from "../../synchronization";
|
|
12
|
+
import * as noneExplorer from "../../api/explorer/none";
|
|
11
13
|
import * as nodeApi from "../../api/node/rpc.common";
|
|
14
|
+
import { createSwapHistoryMap } from "../../logic";
|
|
12
15
|
import {
|
|
13
16
|
account,
|
|
14
17
|
coinOperations,
|
|
@@ -23,10 +26,8 @@ import {
|
|
|
23
26
|
internalOperations,
|
|
24
27
|
swapHistory,
|
|
25
28
|
} from "../fixtures/synchronization.fixtures";
|
|
26
|
-
import { UnknownNode } from "../../errors";
|
|
27
|
-
import * as logic from "../../logic";
|
|
28
29
|
import { getCoinConfig } from "../../config";
|
|
29
|
-
import
|
|
30
|
+
import * as logic from "../../logic";
|
|
30
31
|
|
|
31
32
|
jest.mock("../../api/node/rpc.common");
|
|
32
33
|
jest.useFakeTimers().setSystemTime(new Date("2014-04-21"));
|
|
@@ -102,9 +103,13 @@ describe("EVM Family", () => {
|
|
|
102
103
|
});
|
|
103
104
|
|
|
104
105
|
it("should throw for currency with unsupported explorer", async () => {
|
|
105
|
-
mockGetConfig.
|
|
106
|
+
mockGetConfig.mockImplementation((): any => {
|
|
106
107
|
return {
|
|
107
108
|
info: {
|
|
109
|
+
node: {
|
|
110
|
+
type: "external",
|
|
111
|
+
uri: "https://my-rpc.com",
|
|
112
|
+
},
|
|
108
113
|
explorer: {
|
|
109
114
|
uri: "http://nope.com",
|
|
110
115
|
type: "unsupported" as any,
|
|
@@ -131,12 +136,54 @@ describe("EVM Family", () => {
|
|
|
131
136
|
if (e instanceof AssertionError) {
|
|
132
137
|
throw e;
|
|
133
138
|
}
|
|
134
|
-
expect(e).toBeInstanceOf(
|
|
139
|
+
expect(e).toBeInstanceOf(UnknownExplorer);
|
|
135
140
|
}
|
|
136
141
|
});
|
|
137
142
|
|
|
143
|
+
it("shouldn't throw for none explorer config", async () => {
|
|
144
|
+
mockGetConfig.mockImplementation((): any => {
|
|
145
|
+
return {
|
|
146
|
+
info: {
|
|
147
|
+
node: {
|
|
148
|
+
type: "external",
|
|
149
|
+
uri: "https://my-rpc.com",
|
|
150
|
+
},
|
|
151
|
+
explorer: {
|
|
152
|
+
type: "none",
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
});
|
|
157
|
+
const spy = jest.spyOn(noneExplorer?.default, "getLastOperations");
|
|
158
|
+
|
|
159
|
+
await synchronization.getAccountShape(
|
|
160
|
+
{
|
|
161
|
+
...getAccountShapeParameters,
|
|
162
|
+
currency: {
|
|
163
|
+
...currency,
|
|
164
|
+
ethereumLikeInfo: {
|
|
165
|
+
chainId: 1,
|
|
166
|
+
} as any,
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
{} as any,
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
173
|
+
expect(spy).toHaveReturnedWith(
|
|
174
|
+
Promise.resolve({
|
|
175
|
+
lastCoinOperations: [],
|
|
176
|
+
lastTokenOperations: [],
|
|
177
|
+
lastNftOperations: [],
|
|
178
|
+
lastInternalOperations: [],
|
|
179
|
+
}),
|
|
180
|
+
);
|
|
181
|
+
});
|
|
182
|
+
|
|
138
183
|
describe("With no transactions fetched", () => {
|
|
139
184
|
beforeAll(() => {
|
|
185
|
+
// @ts-expect-error reseting cache
|
|
186
|
+
etherscanAPI?.default.getLastOperations.reset();
|
|
140
187
|
jest.spyOn(etherscanAPI, "getLastOperations").mockImplementation(() =>
|
|
141
188
|
Promise.resolve({
|
|
142
189
|
lastCoinOperations: [],
|
|
@@ -265,6 +312,8 @@ describe("EVM Family", () => {
|
|
|
265
312
|
|
|
266
313
|
describe("With transactions fetched", () => {
|
|
267
314
|
beforeAll(() => {
|
|
315
|
+
// @ts-expect-error reseting cache
|
|
316
|
+
etherscanAPI?.default.getLastOperations.reset();
|
|
268
317
|
jest
|
|
269
318
|
.spyOn(etherscanAPI, "getLastCoinOperations")
|
|
270
319
|
.mockImplementation(() =>
|
|
@@ -524,6 +573,84 @@ describe("EVM Family", () => {
|
|
|
524
573
|
expect(accountShape.operations).toEqual([coinOperations[0]]);
|
|
525
574
|
});
|
|
526
575
|
});
|
|
576
|
+
|
|
577
|
+
describe("With Blockscout", () => {
|
|
578
|
+
beforeAll(() => {
|
|
579
|
+
// @ts-expect-error reseting cache
|
|
580
|
+
etherscanAPI?.default.getLastOperations.reset();
|
|
581
|
+
jest
|
|
582
|
+
.spyOn(etherscanAPI, "getLastCoinOperations")
|
|
583
|
+
.mockImplementation(() =>
|
|
584
|
+
Promise.resolve([{ ...coinOperations[0] }, { ...coinOperations[1] }]),
|
|
585
|
+
);
|
|
586
|
+
jest
|
|
587
|
+
.spyOn(etherscanAPI, "getLastTokenOperations")
|
|
588
|
+
.mockImplementation(() =>
|
|
589
|
+
Promise.resolve([{ ...tokenOperations[0] }, { ...tokenOperations[1] }]),
|
|
590
|
+
);
|
|
591
|
+
|
|
592
|
+
jest
|
|
593
|
+
.spyOn(etherscanAPI, "getLastERC721Operations")
|
|
594
|
+
.mockImplementation(() =>
|
|
595
|
+
Promise.resolve([
|
|
596
|
+
{ ...erc721Operations[0] },
|
|
597
|
+
{ ...erc721Operations[1] },
|
|
598
|
+
{ ...erc721Operations[2] },
|
|
599
|
+
]),
|
|
600
|
+
);
|
|
601
|
+
jest
|
|
602
|
+
.spyOn(etherscanAPI, "getLastInternalOperations")
|
|
603
|
+
.mockImplementation(() =>
|
|
604
|
+
Promise.resolve([
|
|
605
|
+
{ ...internalOperations[0] },
|
|
606
|
+
{ ...internalOperations[1] },
|
|
607
|
+
{ ...internalOperations[2] },
|
|
608
|
+
]),
|
|
609
|
+
);
|
|
610
|
+
jest
|
|
611
|
+
.spyOn(nodeApi, "getTokenBalance")
|
|
612
|
+
.mockImplementation(async (a, b, contractAddress) => {
|
|
613
|
+
if (contractAddress === tokenCurrencies[0].contractAddress) {
|
|
614
|
+
return new BigNumber(10000);
|
|
615
|
+
}
|
|
616
|
+
throw new Error("Shouldn't be trying to fetch this token balance");
|
|
617
|
+
});
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
afterAll(() => {
|
|
621
|
+
jest.restoreAllMocks();
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
it("should never call ERC1155 endpoint", async () => {
|
|
625
|
+
mockGetConfig.mockImplementation((): any => {
|
|
626
|
+
return {
|
|
627
|
+
info: {
|
|
628
|
+
node: {
|
|
629
|
+
type: "external",
|
|
630
|
+
uri: "https://my-rpc.com",
|
|
631
|
+
},
|
|
632
|
+
explorer: {
|
|
633
|
+
type: "blockscout",
|
|
634
|
+
uri: "https://api.com",
|
|
635
|
+
},
|
|
636
|
+
},
|
|
637
|
+
};
|
|
638
|
+
});
|
|
639
|
+
console.log(etherscanAPI?.default.getLastOperations);
|
|
640
|
+
const spy = jest.spyOn(etherscanAPI, "getLastERC1155Operations");
|
|
641
|
+
|
|
642
|
+
await synchronization.getAccountShape(
|
|
643
|
+
{
|
|
644
|
+
...getAccountShapeParameters,
|
|
645
|
+
initialAccount: account,
|
|
646
|
+
},
|
|
647
|
+
{} as any,
|
|
648
|
+
);
|
|
649
|
+
|
|
650
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
651
|
+
expect(spy).toHaveReturnedWith(Promise.resolve([]));
|
|
652
|
+
});
|
|
653
|
+
});
|
|
527
654
|
});
|
|
528
655
|
|
|
529
656
|
describe("getSubAccounts", () => {
|
|
@@ -211,6 +211,11 @@ export const getLastERC1155Operations = async (
|
|
|
211
211
|
throw new EtherscanLikeExplorerUsedIncorrectly();
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
+
// Blockscout has no ERC1155 support yet
|
|
215
|
+
if (explorer.type === "blockscout") {
|
|
216
|
+
return [];
|
|
217
|
+
}
|
|
218
|
+
|
|
214
219
|
const ops = await fetchWithRetries<EtherscanERC1155Event[]>({
|
|
215
220
|
method: "GET",
|
|
216
221
|
url: `${explorer.uri}?module=account&action=token1155tx&address=${address}`,
|
|
@@ -4,6 +4,7 @@ import { getCoinConfig } from "../../config";
|
|
|
4
4
|
import etherscanLikeApi from "./etherscan";
|
|
5
5
|
import ledgerExplorerApi from "./ledger";
|
|
6
6
|
import { ExplorerApi } from "./types";
|
|
7
|
+
import noExplorerAPI from "./none";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Switch to select one of the compatible explorer
|
|
@@ -20,6 +21,8 @@ export const getExplorerApi = (currency: CryptoCurrency): ExplorerApi => {
|
|
|
20
21
|
return etherscanLikeApi;
|
|
21
22
|
case "ledger":
|
|
22
23
|
return ledgerExplorerApi;
|
|
24
|
+
case "none":
|
|
25
|
+
return noExplorerAPI;
|
|
23
26
|
|
|
24
27
|
default:
|
|
25
28
|
throw new UnknownExplorer(`Unknown explorer for currency: ${currency.id}`);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ExplorerApi } from "./types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Returns all operation types from an address
|
|
5
|
+
*/
|
|
6
|
+
export const getLastOperations: ExplorerApi["getLastOperations"] = async () => {
|
|
7
|
+
return {
|
|
8
|
+
lastCoinOperations: [],
|
|
9
|
+
lastTokenOperations: [],
|
|
10
|
+
lastNftOperations: [],
|
|
11
|
+
lastInternalOperations: [],
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const noExplorerAPI: ExplorerApi = {
|
|
16
|
+
getLastOperations,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default noExplorerAPI;
|