@ledgerhq/live-common 21.18.0 → 21.19.2

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 (118) hide show
  1. package/lib/__tests__/test-helpers/setup.js +1 -0
  2. package/lib/__tests__/test-helpers/setup.js.map +1 -1
  3. package/lib/account/addAccounts.d.ts.map +1 -1
  4. package/lib/account/addAccounts.js +3 -2
  5. package/lib/account/addAccounts.js.map +1 -1
  6. package/lib/account/helpers.d.ts.map +1 -1
  7. package/lib/account/helpers.js +1 -0
  8. package/lib/account/helpers.js.map +1 -1
  9. package/lib/api/Ethereum.d.ts.map +1 -1
  10. package/lib/api/Ethereum.js +2 -1
  11. package/lib/api/Ethereum.js.map +1 -1
  12. package/lib/api/explorerConfig/index.d.ts.map +1 -1
  13. package/lib/api/explorerConfig/index.js +0 -4
  14. package/lib/api/explorerConfig/index.js.map +1 -1
  15. package/lib/bridge/jsHelpers.d.ts.map +1 -1
  16. package/lib/bridge/jsHelpers.js +9 -8
  17. package/lib/bridge/jsHelpers.js.map +1 -1
  18. package/lib/env.d.ts +10 -5
  19. package/lib/env.d.ts.map +1 -1
  20. package/lib/env.js +5 -0
  21. package/lib/env.js.map +1 -1
  22. package/lib/env.react.d.ts +1 -1
  23. package/lib/env.react.d.ts.map +1 -1
  24. package/lib/families/bitcoin/getAccountNetworkInfo.d.ts.map +1 -1
  25. package/lib/families/bitcoin/getAccountNetworkInfo.js +12 -2
  26. package/lib/families/bitcoin/getAccountNetworkInfo.js.map +1 -1
  27. package/lib/families/bitcoin/test-dataset.js +2 -2
  28. package/lib/families/bitcoin/test-dataset.js.map +1 -1
  29. package/lib/families/bitcoin/types.d.ts +1 -0
  30. package/lib/families/bitcoin/types.d.ts.map +1 -1
  31. package/lib/families/bitcoin/types.js.map +1 -1
  32. package/lib/families/bitcoin/wallet-btc/explorer/index.d.ts +1 -0
  33. package/lib/families/bitcoin/wallet-btc/explorer/index.d.ts.map +1 -1
  34. package/lib/families/bitcoin/wallet-btc/explorer/index.js +19 -0
  35. package/lib/families/bitcoin/wallet-btc/explorer/index.js.map +1 -1
  36. package/lib/families/bitcoin/wallet-btc/explorer/types.d.ts +1 -0
  37. package/lib/families/bitcoin/wallet-btc/explorer/types.d.ts.map +1 -1
  38. package/lib/families/ethereum/bridge/js.d.ts.map +1 -1
  39. package/lib/families/ethereum/bridge/js.js +3 -0
  40. package/lib/families/ethereum/bridge/js.js.map +1 -1
  41. package/lib/families/ethereum/modules/erc1155.d.ts.map +1 -1
  42. package/lib/families/ethereum/modules/erc1155.js +21 -9
  43. package/lib/families/ethereum/modules/erc1155.js.map +1 -1
  44. package/lib/families/ethereum/modules/erc721.d.ts +3 -1
  45. package/lib/families/ethereum/modules/erc721.d.ts.map +1 -1
  46. package/lib/families/ethereum/modules/erc721.js +101 -7
  47. package/lib/families/ethereum/modules/erc721.js.map +1 -1
  48. package/lib/families/ethereum/modules/index.d.ts +5 -0
  49. package/lib/families/ethereum/modules/index.d.ts.map +1 -1
  50. package/lib/families/ethereum/modules/index.js +9 -1
  51. package/lib/families/ethereum/modules/index.js.map +1 -1
  52. package/lib/families/ethereum/nft.test.d.ts +2 -0
  53. package/lib/families/ethereum/nft.test.d.ts.map +1 -0
  54. package/lib/families/ethereum/nft.test.js +360 -0
  55. package/lib/families/ethereum/nft.test.js.map +1 -0
  56. package/lib/families/ethereum/signOperation.d.ts.map +1 -1
  57. package/lib/families/ethereum/signOperation.js +3 -12
  58. package/lib/families/ethereum/signOperation.js.map +1 -1
  59. package/lib/families/ethereum/synchronisation.d.ts.map +1 -1
  60. package/lib/families/ethereum/synchronisation.js +21 -38
  61. package/lib/families/ethereum/synchronisation.js.map +1 -1
  62. package/lib/families/ethereum/synchronisation.test.js.map +1 -1
  63. package/lib/families/ethereum/transaction.d.ts.map +1 -1
  64. package/lib/families/ethereum/transaction.js +4 -4
  65. package/lib/families/ethereum/transaction.js.map +1 -1
  66. package/lib/families/ethereum/types.d.ts +2 -0
  67. package/lib/families/ethereum/types.d.ts.map +1 -1
  68. package/lib/families/ethereum/types.js.map +1 -1
  69. package/lib/hw/uninstallApp.d.ts.map +1 -1
  70. package/lib/hw/uninstallApp.js +1 -1
  71. package/lib/hw/uninstallApp.js.map +1 -1
  72. package/lib/nft/helpers.js +2 -3
  73. package/lib/nft/helpers.js.map +1 -1
  74. package/lib/nft/index.d.ts +1 -0
  75. package/lib/nft/index.d.ts.map +1 -1
  76. package/lib/nft/index.js +1 -0
  77. package/lib/nft/index.js.map +1 -1
  78. package/lib/nft/support.d.ts +4 -0
  79. package/lib/nft/support.d.ts.map +1 -0
  80. package/lib/nft/support.js +16 -0
  81. package/lib/nft/support.js.map +1 -0
  82. package/lib/reconciliation.d.ts.map +1 -1
  83. package/lib/reconciliation.js +5 -1
  84. package/lib/reconciliation.js.map +1 -1
  85. package/package.json +4 -4
  86. package/src/.DS_Store +0 -0
  87. package/src/__tests__/.DS_Store +0 -0
  88. package/src/__tests__/__snapshots__/all.libcore.ts.snap +10 -49
  89. package/src/__tests__/test-helpers/setup.ts +1 -0
  90. package/src/account/addAccounts.ts +3 -2
  91. package/src/account/helpers.ts +1 -0
  92. package/src/api/Ethereum.ts +4 -4
  93. package/src/api/explorerConfig/index.ts +0 -4
  94. package/src/bridge/jsHelpers.ts +9 -8
  95. package/src/currencies/{.DS_Store → __snapshots__/.DS_Store} +0 -0
  96. package/src/env.ts +5 -0
  97. package/src/families/bitcoin/getAccountNetworkInfo.ts +8 -1
  98. package/src/families/bitcoin/test-dataset.ts +2 -2
  99. package/src/families/bitcoin/types.ts +1 -0
  100. package/src/families/bitcoin/wallet-btc/explorer/index.ts +7 -0
  101. package/src/families/bitcoin/wallet-btc/explorer/types.ts +1 -0
  102. package/src/families/ethereum/bridge/js.ts +8 -1
  103. package/src/families/ethereum/modules/erc1155.ts +22 -7
  104. package/src/families/ethereum/modules/erc721.ts +42 -4
  105. package/src/families/ethereum/modules/index.ts +20 -0
  106. package/src/families/ethereum/nft.test.ts +263 -0
  107. package/src/families/ethereum/signOperation.ts +3 -16
  108. package/src/families/ethereum/synchronisation.test.ts +1 -0
  109. package/src/families/ethereum/synchronisation.ts +104 -113
  110. package/src/families/ethereum/transaction.ts +8 -4
  111. package/src/families/ethereum/types.ts +2 -0
  112. package/src/hw/uninstallApp.ts +13 -8
  113. package/src/nft/helpers.ts +2 -2
  114. package/src/nft/index.ts +1 -0
  115. package/src/nft/support.ts +16 -0
  116. package/src/reconciliation.ts +4 -1
  117. package/src/types/account.ts +1 -1
  118. package/src/currencies/__snapshots__/sortByMarketcap.test.ts.snap +0 -6152
@@ -0,0 +1,263 @@
1
+ import "../../__tests__/test-helpers/setup";
2
+ import BigNumber from "bignumber.js";
3
+ import { reduce } from "rxjs/operators";
4
+ import { fromAccountRaw, toAccountRaw, toNFTRaw } from "../../account";
5
+ import type { Account, AccountRaw, NFT } from "../../types";
6
+ import { getAccountBridge } from "../../bridge";
7
+ import { makeBridgeCacheSystem } from "../../bridge/cache";
8
+ import { patchAccount } from "../../reconciliation";
9
+ import { setEnv } from "../../env";
10
+ import { mergeNfts } from "../../bridge/jsHelpers";
11
+ import { encodeNftId } from "../../nft";
12
+
13
+ jest.setTimeout(120000);
14
+
15
+ const gaspardAccount: AccountRaw = {
16
+ id: "js:1:ethereum:0xb98d10d9f6d07ba283bfd21b2dfec050f9ae282a:",
17
+ seedIdentifier: "0xb98d10d9f6d07ba283bfd21b2dfec050f9ae282a",
18
+ name: "G4sp4rd",
19
+ derivationMode: "",
20
+ index: 0,
21
+ freshAddress: "0xb98d10d9f6d07ba283bfd21b2dfec050f9ae282a",
22
+ freshAddressPath: "44'/60'/0'/0/0",
23
+ freshAddresses: [],
24
+ pendingOperations: [],
25
+ operations: [],
26
+ currencyId: "ethereum",
27
+ unitMagnitude: 18,
28
+ balance: "",
29
+ blockHeight: 0,
30
+ lastSyncDate: "",
31
+ xpub: "",
32
+ };
33
+
34
+ /*
35
+ const gaspardPolygonAccount: AccountRaw = {
36
+ id: "js:1:polygon:0xb98d10d9f6d07ba283bfd21b2dfec050f9ae282a:",
37
+ seedIdentifier: "0xb98d10d9f6d07ba283bfd21b2dfec050f9ae282a",
38
+ name: "G4sp4rd",
39
+ derivationMode: "",
40
+ index: 0,
41
+ freshAddress: "0xb98d10d9f6d07ba283bfd21b2dfec050f9ae282a",
42
+ freshAddressPath: "44'/60'/0'/0/0",
43
+ freshAddresses: [],
44
+ pendingOperations: [],
45
+ operations: [],
46
+ currencyId: "polygon",
47
+ unitMagnitude: 18,
48
+ balance: "",
49
+ blockHeight: 0,
50
+ lastSyncDate: "",
51
+ xpub: "",
52
+ };
53
+ */
54
+
55
+ const gaspardBscAccount: AccountRaw = {
56
+ id: "js:1:bsc:0xb98d10d9f6d07ba283bfd21b2dfec050f9ae282a:",
57
+ seedIdentifier: "0xb98d10d9f6d07ba283bfd21b2dfec050f9ae282a",
58
+ name: "G4sp4rd",
59
+ derivationMode: "",
60
+ index: 0,
61
+ freshAddress: "0xb98d10d9f6d07ba283bfd21b2dfec050f9ae282a",
62
+ freshAddressPath: "44'/60'/0'/0/0",
63
+ freshAddresses: [],
64
+ pendingOperations: [],
65
+ operations: [],
66
+ currencyId: "bsc",
67
+ unitMagnitude: 18,
68
+ balance: "",
69
+ blockHeight: 0,
70
+ lastSyncDate: "",
71
+ xpub: "",
72
+ };
73
+
74
+ async function sync(account, withNFT = true) {
75
+ const bridge = getAccountBridge(account);
76
+ const blacklistedTokenIds = [];
77
+ setEnv("NFT", withNFT);
78
+ const r = await bridge
79
+ .sync(account, {
80
+ paginationConfig: {},
81
+ blacklistedTokenIds,
82
+ })
83
+ .pipe(reduce((a, f: (arg0: Account) => Account) => f(a), account))
84
+ .toPromise();
85
+ setEnv("NFT", false);
86
+ return r;
87
+ }
88
+
89
+ const localCache = {};
90
+ const cache = makeBridgeCacheSystem({
91
+ saveData(c, d) {
92
+ localCache[c.id] = d;
93
+ return Promise.resolve();
94
+ },
95
+ getData(c) {
96
+ return Promise.resolve(localCache[c.id]);
97
+ },
98
+ });
99
+
100
+ describe("nft merging", () => {
101
+ const makeNFT = (tokenId: string, contract: string, amount: number): NFT => ({
102
+ id: encodeNftId("test", contract, tokenId),
103
+ tokenId,
104
+ amount: new BigNumber(amount),
105
+ collection: {
106
+ contract,
107
+ standard: "erc721",
108
+ },
109
+ });
110
+ const oldNfts = [
111
+ makeNFT("1", "contract1", 10),
112
+ makeNFT("2", "contract1", 1),
113
+ makeNFT("3", "contract2", 6),
114
+ ];
115
+
116
+ test("should remove first NFT and return new array with same refs", () => {
117
+ const nfts = [makeNFT("2", "contract1", 1), makeNFT("3", "contract2", 6)];
118
+ const newNfts = mergeNfts(oldNfts, nfts);
119
+
120
+ expect(newNfts.map(toNFTRaw)).toEqual(nfts.map(toNFTRaw));
121
+ expect(oldNfts[1]).toBe(newNfts[0]);
122
+ expect(oldNfts[2]).toBe(newNfts[1]);
123
+ });
124
+
125
+ test("should remove any NFT and return new array with same refs", () => {
126
+ const nfts = [makeNFT("1", "contract1", 10), makeNFT("3", "contract2", 6)];
127
+ const newNfts = mergeNfts(oldNfts, nfts);
128
+
129
+ expect(newNfts.map(toNFTRaw)).toEqual(nfts.map(toNFTRaw));
130
+ expect(oldNfts[0]).toBe(newNfts[0]);
131
+ expect(oldNfts[2]).toBe(newNfts[1]);
132
+ });
133
+
134
+ test("should change NFT amount and return new array with new ref", () => {
135
+ const nfts = [
136
+ makeNFT("1", "contract1", 10),
137
+ makeNFT("2", "contract1", 5),
138
+ makeNFT("3", "contract2", 6),
139
+ ];
140
+ const addToNft1 = mergeNfts(oldNfts, nfts);
141
+
142
+ expect(addToNft1.map(toNFTRaw)).toEqual(nfts.map(toNFTRaw));
143
+ expect(oldNfts[0]).toBe(addToNft1[0]);
144
+ expect(oldNfts[1]).not.toBe(addToNft1[1]);
145
+ expect(oldNfts[2]).toBe(addToNft1[2]);
146
+ });
147
+
148
+ test("should add NFT and return new array with new ref", () => {
149
+ const nfts = [
150
+ makeNFT("1", "contract1", 10),
151
+ makeNFT("2", "contract1", 1),
152
+ makeNFT("3", "contract2", 6),
153
+ makeNFT("4", "contract2", 4),
154
+ ];
155
+ const addToNft1 = mergeNfts(oldNfts, nfts);
156
+
157
+ expect(addToNft1.map(toNFTRaw)).toEqual(
158
+ [
159
+ makeNFT("4", "contract2", 4),
160
+ makeNFT("1", "contract1", 10),
161
+ makeNFT("2", "contract1", 1),
162
+ makeNFT("3", "contract2", 6),
163
+ ].map(toNFTRaw)
164
+ );
165
+ expect(oldNfts[0]).toBe(addToNft1[1]);
166
+ expect(oldNfts[1]).toBe(addToNft1[2]);
167
+ expect(oldNfts[2]).toBe(addToNft1[3]);
168
+ expect(addToNft1[0]).toBe(nfts[3]);
169
+ });
170
+ });
171
+
172
+ describe("gaspard NFT on ethereum", () => {
173
+ let account = fromAccountRaw(gaspardAccount);
174
+
175
+ test("first sync & have nfts", async () => {
176
+ await cache.prepareCurrency(account.currency);
177
+ account = await sync(account);
178
+ expect(account.nfts?.length || 0).not.toBe(0);
179
+ });
180
+
181
+ test("remove half NFTs will restore them with operations still here", async () => {
182
+ const copy = {
183
+ ...account,
184
+ nfts: account.nfts?.slice(Math.ceil((account.nfts?.length || 0) / 2)),
185
+ };
186
+ const resync = await sync(copy);
187
+ expect(resync.nfts).toEqual(account.nfts);
188
+ });
189
+
190
+ test("remove half NFTs will restore them with missing operations too", async () => {
191
+ const copy = {
192
+ ...account,
193
+ operations: [],
194
+ nfts: account.nfts?.slice(Math.ceil((account.nfts?.length || 0) / 2)),
195
+ };
196
+ const resync = await sync(copy);
197
+ expect(resync.nfts).toEqual(account.nfts);
198
+ });
199
+
200
+ test("remove half NFTs will restore them with half operations", async () => {
201
+ const halfOps = Math.ceil(account.operations.length / 2);
202
+ const copy = {
203
+ ...account,
204
+ operations: account.operations.slice(halfOps),
205
+ nfts: account.nfts?.slice(Math.ceil((account.nfts?.length || 0) / 2)),
206
+ };
207
+ const resync = await sync(copy);
208
+ expect(resync.nfts).toEqual(account.nfts);
209
+ });
210
+
211
+ test("patchAccount restore new NFTs correctly", async () => {
212
+ const copy = {
213
+ ...account,
214
+ operations: [],
215
+ nfts: account.nfts?.slice(Math.ceil((account.nfts?.length || 0) / 2)),
216
+ };
217
+ const newAccount = patchAccount(copy, toAccountRaw(account));
218
+ expect(newAccount.nfts).toEqual(account.nfts);
219
+ });
220
+
221
+ test("start account with .nfts and disable the NFT flag should make it disappear", async () => {
222
+ expect(account.nfts).not.toBeFalsy();
223
+ const resync = await sync(account, false);
224
+ expect(resync.nfts).toBeFalsy();
225
+ });
226
+
227
+ test("start account without .nfts and enable the NFT flag should make it appear", async () => {
228
+ const first = await sync(account, false);
229
+ expect(first.nfts).toBeFalsy();
230
+ const second = await sync(first, true);
231
+ expect(second.nfts).not.toBeFalsy();
232
+ expect(second.nfts).toEqual(account.nfts);
233
+ });
234
+
235
+ test("no nft should be on quantity 0 or negative", async () => {
236
+ expect(account.nfts?.find((n) => !n.amount.gt(0))).toEqual(undefined);
237
+ });
238
+ });
239
+
240
+ /*
241
+ // this is never ending here... have to disable this test... (backend issue)
242
+ describe("gaspard NFT on polygon", () => {
243
+ let account = fromAccountRaw(gaspardPolygonAccount);
244
+ test("first sync", async () => {
245
+ await cache.prepareCurrency(account.currency);
246
+ account = await sync(account);
247
+ });
248
+ test(".nfts shouldn't be visible", () => {
249
+ expect(account.nfts).toBeFalsy();
250
+ });
251
+ });
252
+ */
253
+
254
+ describe("gaspard NFT on bsc", () => {
255
+ let account = fromAccountRaw(gaspardBscAccount);
256
+ test("first sync", async () => {
257
+ await cache.prepareCurrency(account.currency);
258
+ account = await sync(account);
259
+ });
260
+ test(".nfts shouldn't be visible", () => {
261
+ expect(account.nfts).toBeFalsy();
262
+ });
263
+ });
@@ -13,7 +13,7 @@ import { getGasLimit, buildEthereumTx } from "./transaction";
13
13
  import { apiForCurrency } from "../../api/Ethereum";
14
14
  import { withDevice } from "../../hw/deviceAccess";
15
15
  import { modes } from "./modules";
16
- import { getEnv } from "../../env";
16
+ import { isNFTActive } from "../../nft";
17
17
  export const signOperation = ({
18
18
  account,
19
19
  deviceId,
@@ -57,12 +57,11 @@ export const signOperation = ({
57
57
  nonce
58
58
  );
59
59
  const to = eip55.encode("0x" + tx.to.toString("hex"));
60
- const chainId = tx.getChainId();
61
60
  const value = new BigNumber(
62
61
  "0x" + (tx.value.toString("hex") || "0")
63
62
  );
64
63
  const eth = new Eth(transport);
65
- if (getEnv("NFT")) {
64
+ if (isNFTActive(account.currency)) {
66
65
  eth.setLoadConfig({
67
66
  // FIXME drop this after LL-8001
68
67
  nftExplorerBaseURL:
@@ -99,19 +98,7 @@ export const signOperation = ({
99
98
  type: "device-signature-granted",
100
99
  });
101
100
  // Second, we re-set some tx fields from the device signature
102
- let v = result.v;
103
-
104
- if (chainId > 0) {
105
- // EIP155 support. check/recalc signature v value.
106
- const rv = parseInt(v, 16);
107
- let cv = chainId * 2 + 35;
108
-
109
- if (rv !== cv && (rv & cv) !== rv) {
110
- cv += 1; // add signature v bit.
111
- }
112
-
113
- v = cv.toString(16);
114
- }
101
+ const v = result.v;
115
102
 
116
103
  tx.v = Buffer.from(v, "hex");
117
104
  tx.r = Buffer.from(result.r, "hex");
@@ -6,6 +6,7 @@ import type { Account, SubAccount } from "../../types";
6
6
  import { getAccountBridge } from "../../bridge";
7
7
  import { makeBridgeCacheSystem } from "../../bridge/cache";
8
8
  import { ethereum1 } from "./test-dataset";
9
+
9
10
  describe("blacklistedTokenIds functionality", () => {
10
11
  const account = fromAccountRaw(ethereum1);
11
12
  const localCache = {};
@@ -15,13 +15,12 @@ import {
15
15
  } from "../../account";
16
16
  import { listTokensForCryptoCurrency } from "../../currencies";
17
17
  import { encodeAccountId } from "../../account";
18
- import type { Operation, TokenAccount, Account, NFT } from "../../types";
18
+ import type { Operation, TokenAccount, Account } from "../../types";
19
19
  import { API, apiForCurrency, Tx } from "../../api/Ethereum";
20
20
  import { digestTokenAccounts, prepareTokenAccounts } from "./modules";
21
21
  import { findTokenByAddressInCurrency } from "@ledgerhq/cryptoassets";
22
- import { encodeNftId, nftsFromOperations } from "../../nft";
22
+ import { encodeNftId, isNFTActive, nftsFromOperations } from "../../nft";
23
23
  import { NFT_VERSION } from "./versions";
24
- import { getEnv } from "../../env";
25
24
 
26
25
  export const getAccountShape: GetAccountShape = async (
27
26
  infoInput,
@@ -41,24 +40,24 @@ export const getAccountShape: GetAccountShape = async (
41
40
  const initialStableOperations = initialAccount
42
41
  ? stableOperations(initialAccount)
43
42
  : [];
43
+ const shouldNFTBeActive = isNFTActive(currency);
44
44
  // fetch transactions, incrementally if possible
45
45
  const mostRecentStableOperation = initialStableOperations[0];
46
46
  // when new tokens are added / blacklist changes, we need to sync again because we need to go through all operations again
47
47
  const syncHash =
48
48
  JSON.stringify(blacklistedTokenIds || []) +
49
49
  "_" +
50
+ shouldNFTBeActive +
51
+ "_" +
50
52
  listTokensForCryptoCurrency(currency, {
51
53
  withDelisted: true,
52
54
  }).length;
53
- const outdatedBlacklist = initialAccount?.syncHash !== syncHash;
54
- const firstNftSync =
55
- getEnv("NFT") && typeof initialAccount?.nfts === "undefined";
55
+ const outdatedSyncHash = initialAccount?.syncHash !== syncHash;
56
56
  const pullFromBlockHash =
57
57
  initialAccount &&
58
58
  areAllOperationsLoaded(initialAccount) &&
59
59
  mostRecentStableOperation &&
60
- !outdatedBlacklist &&
61
- !firstNftSync &&
60
+ !outdatedSyncHash &&
62
61
  NFT_VERSION
63
62
  ? mostRecentStableOperation.blockHash
64
63
  : undefined;
@@ -83,10 +82,8 @@ export const getAccountShape: GetAccountShape = async (
83
82
  let newOps = flatMap(txs, txToOps({ address, id: accountId, currency }));
84
83
  // extracting out the sub operations by token account
85
84
  const perTokenAccountIdOperations = {};
86
- // extracting and concat all nft operations for an account
87
- const flatNftOps: Operation[] = [];
88
85
  newOps.forEach((op) => {
89
- const { subOperations, nftOperations } = op;
86
+ const { subOperations } = op;
90
87
 
91
88
  if (subOperations?.length) {
92
89
  subOperations.forEach((sop) => {
@@ -97,10 +94,6 @@ export const getAccountShape: GetAccountShape = async (
97
94
  perTokenAccountIdOperations[sop.accountId].push(sop);
98
95
  });
99
96
  }
100
-
101
- if (nftOperations?.length) {
102
- nftOperations.forEach((nop) => flatNftOps.push(nop));
103
- }
104
97
  });
105
98
  const subAccountsExisting = {};
106
99
  initialAccount?.subAccounts?.forEach((a) => {
@@ -173,8 +166,8 @@ export const getAccountShape: GetAccountShape = async (
173
166
  }));
174
167
  const operations = mergeOps(initialStableOperations, newOps);
175
168
 
176
- const nfts = getEnv("NFT")
177
- ? mergeNfts(initialAccount?.nfts, await getNfts(flatNftOps))
169
+ const nfts = isNFTActive(currency)
170
+ ? mergeNfts(initialAccount?.nfts, nftsFromOperations(operations))
178
171
  : undefined;
179
172
 
180
173
  const accountShape: Partial<Account> = {
@@ -334,91 +327,23 @@ const txToOps =
334
327
  });
335
328
 
336
329
  // Creating NFTOps from transfer events related to ERC721 only
337
- const erc721Operations = !erc721_transfer_events
338
- ? []
339
- : flatMap(erc721_transfer_events, (event) => {
340
- const sender = safeEncodeEIP55(event.sender);
341
- const receiver = safeEncodeEIP55(event.receiver);
342
- const contract = safeEncodeEIP55(event.contract);
343
- const tokenId = event.token_id;
344
- const nftId = encodeNftId(id, event.contract, tokenId);
345
- const sending = addr === sender;
346
- const receiving = addr === receiver;
347
-
348
- if (!sending && !receiving) {
349
- return [];
350
- }
351
-
352
- const all: Operation[] = [];
353
-
354
- if (sending) {
355
- const type = "NFT_OUT";
356
- all.push({
357
- id: `${nftId}-${hash}-${type}`,
358
- senders: [sender],
359
- recipients: [receiver],
360
- contract,
361
- fee,
362
- standard: "ERC721",
363
- tokenId,
364
- value: new BigNumber(1),
365
- hash,
366
- type,
367
- blockHeight,
368
- blockHash,
369
- date,
370
- transactionSequenceNumber,
371
- accountId: id,
372
- extra: {},
373
- });
374
- }
375
-
376
- if (receiving) {
377
- const type = "NFT_IN";
378
- all.push({
379
- id: `${nftId}-${hash}-${type}`,
380
- senders: [sender],
381
- recipients: [receiver],
382
- contract,
383
- fee,
384
- standard: "ERC721",
385
- tokenId,
386
- value: new BigNumber(1),
387
- hash,
388
- type,
389
- blockHeight,
390
- blockHash,
391
- date,
392
- transactionSequenceNumber,
393
- accountId: id,
394
- extra: {},
395
- });
396
- }
397
-
398
- return all;
399
- });
400
-
401
- // Creating NFTOps from transfer events related to ERC1155 only
402
- const erc1155Operations = !erc1155_transfer_events
403
- ? []
404
- : flatMap(erc1155_transfer_events, (event) => {
405
- const sender = safeEncodeEIP55(event.sender);
406
- const receiver = safeEncodeEIP55(event.receiver);
407
- const contract = safeEncodeEIP55(event.contract);
408
- const operator = safeEncodeEIP55(event.operator);
409
- const sending = addr === sender;
410
- const receiving = addr === receiver;
411
-
412
- if (!sending && !receiving) {
413
- return [];
414
- }
330
+ const erc721Operations =
331
+ !erc721_transfer_events || !isNFTActive(currency)
332
+ ? []
333
+ : flatMap(erc721_transfer_events, (event) => {
334
+ const sender = safeEncodeEIP55(event.sender);
335
+ const receiver = safeEncodeEIP55(event.receiver);
336
+ const contract = safeEncodeEIP55(event.contract);
337
+ const tokenId = event.token_id;
338
+ const nftId = encodeNftId(id, event.contract, tokenId);
339
+ const sending = addr === sender;
340
+ const receiving = addr === receiver;
415
341
 
416
- const all: Operation[] = [];
342
+ if (!sending && !receiving) {
343
+ return [];
344
+ }
417
345
 
418
- event.transfers.forEach((transfer) => {
419
- const tokenId = transfer.id;
420
- const value = new BigNumber(transfer.value);
421
- const nftId = encodeNftId(id, event.contract, tokenId);
346
+ const all: Operation[] = [];
422
347
 
423
348
  if (sending) {
424
349
  const type = "NFT_OUT";
@@ -428,10 +353,9 @@ const txToOps =
428
353
  recipients: [receiver],
429
354
  contract,
430
355
  fee,
431
- operator,
432
- standard: "ERC1155",
356
+ standard: "ERC721",
433
357
  tokenId,
434
- value,
358
+ value: new BigNumber(1),
435
359
  hash,
436
360
  type,
437
361
  blockHeight,
@@ -451,10 +375,9 @@ const txToOps =
451
375
  recipients: [receiver],
452
376
  contract,
453
377
  fee,
454
- operator,
455
- standard: "ERC1155",
378
+ standard: "ERC721",
456
379
  tokenId,
457
- value,
380
+ value: new BigNumber(1),
458
381
  hash,
459
382
  type,
460
383
  blockHeight,
@@ -465,15 +388,88 @@ const txToOps =
465
388
  extra: {},
466
389
  });
467
390
  }
391
+
392
+ return all;
468
393
  });
469
394
 
470
- return all;
471
- });
395
+ // Creating NFTOps from transfer events related to ERC1155 only
396
+ const erc1155Operations =
397
+ !erc1155_transfer_events || !isNFTActive(currency)
398
+ ? []
399
+ : flatMap(erc1155_transfer_events, (event) => {
400
+ const sender = safeEncodeEIP55(event.sender);
401
+ const receiver = safeEncodeEIP55(event.receiver);
402
+ const contract = safeEncodeEIP55(event.contract);
403
+ const operator = safeEncodeEIP55(event.operator);
404
+ const sending = addr === sender;
405
+ const receiving = addr === receiver;
406
+
407
+ if (!sending && !receiving) {
408
+ return [];
409
+ }
410
+
411
+ const all: Operation[] = [];
412
+
413
+ event.transfers.forEach((transfer) => {
414
+ const tokenId = transfer.id;
415
+ const value = new BigNumber(transfer.value);
416
+ const nftId = encodeNftId(id, event.contract, tokenId);
417
+
418
+ if (sending) {
419
+ const type = "NFT_OUT";
420
+ all.push({
421
+ id: `${nftId}-${hash}-${type}`,
422
+ senders: [sender],
423
+ recipients: [receiver],
424
+ contract,
425
+ fee,
426
+ operator,
427
+ standard: "ERC1155",
428
+ tokenId,
429
+ value,
430
+ hash,
431
+ type,
432
+ blockHeight,
433
+ blockHash,
434
+ date,
435
+ transactionSequenceNumber,
436
+ accountId: id,
437
+ extra: {},
438
+ });
439
+ }
440
+
441
+ if (receiving) {
442
+ const type = "NFT_IN";
443
+ all.push({
444
+ id: `${nftId}-${hash}-${type}`,
445
+ senders: [sender],
446
+ recipients: [receiver],
447
+ contract,
448
+ fee,
449
+ operator,
450
+ standard: "ERC1155",
451
+ tokenId,
452
+ value,
453
+ hash,
454
+ type,
455
+ blockHeight,
456
+ blockHash,
457
+ date,
458
+ transactionSequenceNumber,
459
+ accountId: id,
460
+ extra: {},
461
+ });
462
+ }
463
+ });
464
+
465
+ return all;
466
+ });
472
467
 
473
468
  const nftOperations = erc721Operations
474
469
  .concat(erc1155Operations)
475
470
  /** @warning is this necessary ? Do we need the operations to be chronologically organised for LLD/LLM ? */
476
471
  .sort((a, b) => b.date.getTime() - a.date.getTime());
472
+
477
473
  const ops: Operation[] = [];
478
474
 
479
475
  if (sending) {
@@ -619,11 +615,6 @@ async function loadERC20Balances(tokenAccounts, address, api) {
619
615
  .filter(Boolean);
620
616
  }
621
617
 
622
- function getNfts(nftOperations: Operation[]): NFT[] {
623
- const nfts: NFT[] = nftsFromOperations(nftOperations);
624
- return nfts.filter((nft) => nft.amount.gt(0));
625
- }
626
-
627
618
  const SAFE_REORG_THRESHOLD = 80;
628
619
 
629
620
  function stableOperations(a) {
@@ -90,12 +90,14 @@ export const formatTransaction = (
90
90
  const header = (() => {
91
91
  switch (t.mode) {
92
92
  case "erc721.transfer":
93
- return `${t.mode.toUpperCase()} Collection: ${t.collection} TokenId: ${
94
- t.tokenIds?.[0]
95
- }`;
93
+ return `${t.mode.toUpperCase()} Collection: ${t.collection} (${
94
+ t.collectionName || ""
95
+ }) TokenId: ${t.tokenIds?.[0]}`;
96
96
  case "erc1155.transfer":
97
97
  return (
98
- `${t.mode.toUpperCase()} Collection: ${t.collection}` +
98
+ `${t.mode.toUpperCase()} Collection: ${t.collection} (${
99
+ t.collectionName || ""
100
+ })` +
99
101
  t.tokenIds
100
102
  ?.map((tokenId, index) => {
101
103
  return `\n - TokenId: ${tokenId} Quantity: ${
@@ -153,6 +155,7 @@ export const fromTransactionRaw = (tr: TransactionRaw): Transaction => {
153
155
  feesStrategy: tr.feesStrategy,
154
156
  tokenIds: tr.tokenIds,
155
157
  collection: tr.collection,
158
+ collectionName: tr.collectionName,
156
159
  quantities: tr.quantities?.map((q) => new BigNumber(q)),
157
160
  };
158
161
  };
@@ -180,6 +183,7 @@ export const toTransactionRaw = (t: Transaction): TransactionRaw => {
180
183
  feesStrategy: t.feesStrategy,
181
184
  tokenIds: t.tokenIds,
182
185
  collection: t.collection,
186
+ collectionName: t.collectionName,
183
187
  quantities: t.quantities?.map((q) => q.toString()),
184
188
  };
185
189
  };
@@ -38,6 +38,7 @@ export type Transaction = TransactionCommon & {
38
38
  networkInfo: NetworkInfo | null | undefined;
39
39
  allowZeroAmount?: boolean;
40
40
  collection?: string;
41
+ collectionName?: string;
41
42
  tokenIds?: string[];
42
43
  quantities?: BigNumber[];
43
44
  };
@@ -54,6 +55,7 @@ export type TransactionRaw = TransactionCommonRaw & {
54
55
  allowZeroAmount?: boolean;
55
56
  tokenIds?: string[];
56
57
  collection?: string;
58
+ collectionName?: string;
57
59
  quantities?: string[];
58
60
  };
59
61
  export type TypedMessage = {