@ledgerhq/live-common 21.17.2 → 21.19.1
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/lib/__tests__/test-helpers/setup.js +1 -0
- package/lib/__tests__/test-helpers/setup.js.map +1 -1
- package/lib/account/addAccounts.d.ts.map +1 -1
- package/lib/account/addAccounts.js +3 -2
- package/lib/account/addAccounts.js.map +1 -1
- package/lib/account/helpers.d.ts.map +1 -1
- package/lib/account/helpers.js +1 -0
- package/lib/account/helpers.js.map +1 -1
- package/lib/api/Ethereum.d.ts.map +1 -1
- package/lib/api/Ethereum.js +2 -1
- package/lib/api/Ethereum.js.map +1 -1
- package/lib/api/explorerConfig/index.d.ts.map +1 -1
- package/lib/api/explorerConfig/index.js +0 -4
- package/lib/api/explorerConfig/index.js.map +1 -1
- package/lib/bridge/jsHelpers.d.ts.map +1 -1
- package/lib/bridge/jsHelpers.js +9 -8
- package/lib/bridge/jsHelpers.js.map +1 -1
- package/lib/env.d.ts +10 -5
- package/lib/env.d.ts.map +1 -1
- package/lib/env.js +5 -0
- package/lib/env.js.map +1 -1
- package/lib/env.react.d.ts +1 -1
- package/lib/env.react.d.ts.map +1 -1
- package/lib/families/bitcoin/getAccountNetworkInfo.d.ts.map +1 -1
- package/lib/families/bitcoin/getAccountNetworkInfo.js +12 -2
- package/lib/families/bitcoin/getAccountNetworkInfo.js.map +1 -1
- package/lib/families/bitcoin/test-dataset.js +2 -2
- package/lib/families/bitcoin/test-dataset.js.map +1 -1
- package/lib/families/bitcoin/types.d.ts +1 -0
- package/lib/families/bitcoin/types.d.ts.map +1 -1
- package/lib/families/bitcoin/types.js.map +1 -1
- package/lib/families/bitcoin/wallet-btc/explorer/index.d.ts +1 -0
- package/lib/families/bitcoin/wallet-btc/explorer/index.d.ts.map +1 -1
- package/lib/families/bitcoin/wallet-btc/explorer/index.js +19 -0
- package/lib/families/bitcoin/wallet-btc/explorer/index.js.map +1 -1
- package/lib/families/bitcoin/wallet-btc/explorer/types.d.ts +1 -0
- package/lib/families/bitcoin/wallet-btc/explorer/types.d.ts.map +1 -1
- package/lib/families/ethereum/bridge/js.d.ts.map +1 -1
- package/lib/families/ethereum/bridge/js.js +3 -0
- package/lib/families/ethereum/bridge/js.js.map +1 -1
- package/lib/families/ethereum/cli-transaction.d.ts.map +1 -1
- package/lib/families/ethereum/cli-transaction.js +10 -0
- package/lib/families/ethereum/cli-transaction.js.map +1 -1
- package/lib/families/ethereum/modules/erc1155.d.ts +4 -0
- package/lib/families/ethereum/modules/erc1155.d.ts.map +1 -0
- package/lib/families/ethereum/modules/erc1155.js +129 -0
- package/lib/families/ethereum/modules/erc1155.js.map +1 -0
- package/lib/families/ethereum/modules/erc721.d.ts +6 -0
- package/lib/families/ethereum/modules/erc721.d.ts.map +1 -0
- package/lib/families/ethereum/modules/erc721.js +189 -0
- package/lib/families/ethereum/modules/erc721.js.map +1 -0
- package/lib/families/ethereum/modules/index.d.ts +8 -1
- package/lib/families/ethereum/modules/index.d.ts.map +1 -1
- package/lib/families/ethereum/modules/index.js +14 -2
- package/lib/families/ethereum/modules/index.js.map +1 -1
- package/lib/families/ethereum/nft.test.d.ts +2 -0
- package/lib/families/ethereum/nft.test.d.ts.map +1 -0
- package/lib/families/ethereum/nft.test.js +353 -0
- package/lib/families/ethereum/nft.test.js.map +1 -0
- package/lib/families/ethereum/signOperation.d.ts.map +1 -1
- package/lib/families/ethereum/signOperation.js +3 -12
- package/lib/families/ethereum/signOperation.js.map +1 -1
- package/lib/families/ethereum/synchronisation.d.ts.map +1 -1
- package/lib/families/ethereum/synchronisation.js +21 -38
- package/lib/families/ethereum/synchronisation.js.map +1 -1
- package/lib/families/ethereum/synchronisation.test.js.map +1 -1
- package/lib/families/ethereum/transaction.d.ts.map +1 -1
- package/lib/families/ethereum/transaction.js +25 -8
- package/lib/families/ethereum/transaction.js.map +1 -1
- package/lib/families/ethereum/types.d.ts +8 -0
- package/lib/families/ethereum/types.d.ts.map +1 -1
- package/lib/families/ethereum/types.js.map +1 -1
- package/lib/hw/uninstallApp.d.ts.map +1 -1
- package/lib/hw/uninstallApp.js +1 -1
- package/lib/hw/uninstallApp.js.map +1 -1
- package/lib/nft/helpers.js +1 -2
- package/lib/nft/helpers.js.map +1 -1
- package/lib/nft/index.d.ts +1 -0
- package/lib/nft/index.d.ts.map +1 -1
- package/lib/nft/index.js +1 -0
- package/lib/nft/index.js.map +1 -1
- package/lib/nft/support.d.ts +4 -0
- package/lib/nft/support.d.ts.map +1 -0
- package/lib/nft/support.js +16 -0
- package/lib/nft/support.js.map +1 -0
- package/package.json +4 -4
- package/src/.DS_Store +0 -0
- package/src/__tests__/.DS_Store +0 -0
- package/src/__tests__/__snapshots__/all.libcore.ts.snap +10 -49
- package/src/__tests__/test-helpers/setup.ts +1 -0
- package/src/account/addAccounts.ts +3 -2
- package/src/account/helpers.ts +1 -0
- package/src/api/Ethereum.ts +4 -4
- package/src/api/explorerConfig/index.ts +0 -4
- package/src/bridge/jsHelpers.ts +9 -8
- package/src/currencies/{.DS_Store → __snapshots__/.DS_Store} +0 -0
- package/src/env.ts +5 -0
- package/src/families/bitcoin/getAccountNetworkInfo.ts +8 -1
- package/src/families/bitcoin/test-dataset.ts +2 -2
- package/src/families/bitcoin/types.ts +1 -0
- package/src/families/bitcoin/wallet-btc/explorer/index.ts +7 -0
- package/src/families/bitcoin/wallet-btc/explorer/types.ts +1 -0
- package/src/families/ethereum/bridge/js.ts +8 -1
- package/src/families/ethereum/cli-transaction.ts +10 -0
- package/src/families/ethereum/modules/erc1155.ts +157 -0
- package/src/families/ethereum/modules/erc721.ts +146 -0
- package/src/families/ethereum/modules/index.ts +32 -1
- package/src/families/ethereum/nft.test.ts +259 -0
- package/src/families/ethereum/signOperation.ts +3 -16
- package/src/families/ethereum/synchronisation.test.ts +1 -0
- package/src/families/ethereum/synchronisation.ts +104 -113
- package/src/families/ethereum/transaction.ts +42 -8
- package/src/families/ethereum/types.ts +8 -0
- package/src/hw/uninstallApp.ts +13 -8
- package/src/nft/helpers.ts +1 -1
- package/src/nft/index.ts +1 -0
- package/src/nft/support.ts +16 -0
- package/src/types/account.ts +1 -1
- package/src/currencies/__snapshots__/sortByMarketcap.test.ts.snap +0 -6150
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import eip55 from "eip55";
|
|
2
|
+
import abi from "ethereumjs-abi";
|
|
3
|
+
import invariant from "invariant";
|
|
4
|
+
import BigNumber from "bignumber.js";
|
|
5
|
+
import {
|
|
6
|
+
createCustomErrorClass,
|
|
7
|
+
NotEnoughBalanceInParentAccount,
|
|
8
|
+
} from "@ledgerhq/errors";
|
|
9
|
+
import { validateRecipient } from "../transaction";
|
|
10
|
+
import type { ModeModule, Transaction } from "../types";
|
|
11
|
+
import type { Account } from "../../../types";
|
|
12
|
+
import { apiForCurrency } from "../../../api/Ethereum";
|
|
13
|
+
|
|
14
|
+
const notOwnedNft = createCustomErrorClass("NotOwnedNft");
|
|
15
|
+
|
|
16
|
+
export type Modes = "erc721.transfer";
|
|
17
|
+
|
|
18
|
+
export async function prepareTransaction(
|
|
19
|
+
account: Account,
|
|
20
|
+
transaction: Transaction
|
|
21
|
+
): Promise<Transaction> {
|
|
22
|
+
let t = transaction;
|
|
23
|
+
const { collection, collectionName, tokenIds } = transaction;
|
|
24
|
+
if (collection && tokenIds && typeof collectionName === "undefined") {
|
|
25
|
+
const api = apiForCurrency(account.currency);
|
|
26
|
+
const [{ status, result }] = await api.getNFTMetadata([
|
|
27
|
+
{
|
|
28
|
+
contract: collection,
|
|
29
|
+
tokenId: tokenIds[0],
|
|
30
|
+
},
|
|
31
|
+
]);
|
|
32
|
+
let collectionName = ""; // default value fallback if issue
|
|
33
|
+
if (status === 200) {
|
|
34
|
+
collectionName = result?.tokenName || "";
|
|
35
|
+
}
|
|
36
|
+
t = { ...t, collectionName };
|
|
37
|
+
}
|
|
38
|
+
return Promise.resolve(t);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const erc721Transfer: ModeModule = {
|
|
42
|
+
/**
|
|
43
|
+
* Tx data is filled during the buildEthereumTx
|
|
44
|
+
*/
|
|
45
|
+
fillTransactionData(a, t, tx) {
|
|
46
|
+
const data = serializeTransactionData(a, t);
|
|
47
|
+
invariant(data, "serializeTransactionData provided no data");
|
|
48
|
+
tx.data = "0x" + (data as Buffer).toString("hex");
|
|
49
|
+
tx.to = t.collection;
|
|
50
|
+
tx.value = "0x00";
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Tx status is filled after the buildEthereumTx
|
|
55
|
+
*/
|
|
56
|
+
fillTransactionStatus: (a, t, result) => {
|
|
57
|
+
validateRecipient(a.currency, t.recipient, result);
|
|
58
|
+
|
|
59
|
+
if (!result.errors.recipient) {
|
|
60
|
+
result.totalSpent = result.estimatedFees;
|
|
61
|
+
result.amount = new BigNumber(t.amount);
|
|
62
|
+
|
|
63
|
+
if (result.estimatedFees.gt(a.spendableBalance)) {
|
|
64
|
+
result.errors.amount = new NotEnoughBalanceInParentAccount();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (
|
|
68
|
+
!a.nfts?.find?.(
|
|
69
|
+
(n) =>
|
|
70
|
+
n.tokenId === t.tokenIds?.[0] &&
|
|
71
|
+
n.collection.contract === t.collection
|
|
72
|
+
)
|
|
73
|
+
) {
|
|
74
|
+
result.errors.amount = new notOwnedNft();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
prepareTransaction,
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* This will only be used by LLM & LLD, not the HW.
|
|
83
|
+
*/
|
|
84
|
+
fillDeviceTransactionConfig(input, fields) {
|
|
85
|
+
fields.push({
|
|
86
|
+
type: "text",
|
|
87
|
+
label: "Type",
|
|
88
|
+
value: `NFT Transfer`,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
fields.push({
|
|
92
|
+
type: "text",
|
|
93
|
+
label: "To",
|
|
94
|
+
value: input.transaction.recipient ?? "",
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
fields.push({
|
|
98
|
+
type: "text",
|
|
99
|
+
label: "Collection Name",
|
|
100
|
+
value: input.transaction.collectionName || "",
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
fields.push({
|
|
104
|
+
type: "address",
|
|
105
|
+
label: "NFT Address",
|
|
106
|
+
address: input.transaction.collection ?? "",
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
fields.push({
|
|
110
|
+
type: "text",
|
|
111
|
+
label: "NFT ID",
|
|
112
|
+
value: input.transaction.tokenIds?.[0] ?? "",
|
|
113
|
+
});
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Optimistic Operation is filled post signing
|
|
118
|
+
*/
|
|
119
|
+
fillOptimisticOperation(a, t, op) {
|
|
120
|
+
op.type = "FEES";
|
|
121
|
+
op.extra = {
|
|
122
|
+
...op.extra,
|
|
123
|
+
approving: true, // workaround to track the status ENABLING
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
function serializeTransactionData(
|
|
129
|
+
account: Account,
|
|
130
|
+
transaction: Transaction
|
|
131
|
+
): Buffer | null | undefined {
|
|
132
|
+
const from = eip55.encode(account.freshAddress);
|
|
133
|
+
const to = eip55.encode(transaction.recipient);
|
|
134
|
+
|
|
135
|
+
return abi.simpleEncode(
|
|
136
|
+
"safeTransferFrom(address,address,uint256,bytes)",
|
|
137
|
+
from,
|
|
138
|
+
to,
|
|
139
|
+
transaction.tokenIds?.[0],
|
|
140
|
+
"0x00"
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export const modes: Record<Modes, ModeModule> = {
|
|
145
|
+
"erc721.transfer": erc721Transfer,
|
|
146
|
+
};
|
|
@@ -13,15 +13,26 @@ import type { DeviceTransactionField } from "../../../transaction";
|
|
|
13
13
|
import * as compound from "./compound";
|
|
14
14
|
import * as erc20 from "./erc20";
|
|
15
15
|
import * as send from "./send";
|
|
16
|
+
import * as erc721 from "./erc721";
|
|
17
|
+
import * as erc1155 from "./erc1155";
|
|
16
18
|
import type { Modes as CompoundModes } from "./compound";
|
|
17
19
|
import type { Modes as ERC20Modes } from "./erc20";
|
|
18
20
|
import type { Modes as SendModes } from "./send";
|
|
21
|
+
import type { Modes as ERC721Modes } from "./erc721";
|
|
22
|
+
import type { Modes as ERC1155Modes } from "./erc1155";
|
|
19
23
|
const modules = {
|
|
20
24
|
erc20,
|
|
21
25
|
compound,
|
|
22
26
|
send,
|
|
27
|
+
erc721,
|
|
28
|
+
erc1155,
|
|
23
29
|
};
|
|
24
|
-
export type TransactionMode =
|
|
30
|
+
export type TransactionMode =
|
|
31
|
+
| CompoundModes
|
|
32
|
+
| ERC20Modes
|
|
33
|
+
| SendModes
|
|
34
|
+
| ERC721Modes
|
|
35
|
+
| ERC1155Modes;
|
|
25
36
|
|
|
26
37
|
/**
|
|
27
38
|
* A ModeModule enable a new transaction mode in Ethereum family
|
|
@@ -79,6 +90,14 @@ export type ModeModule = {
|
|
|
79
90
|
arg1: Transaction,
|
|
80
91
|
arg2: Operation
|
|
81
92
|
) => void;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* hook to resolve a transaction like the prepareTransaction of the bridge
|
|
96
|
+
*/
|
|
97
|
+
prepareTransaction?: (
|
|
98
|
+
account: Account,
|
|
99
|
+
transaction: Transaction
|
|
100
|
+
) => Promise<Transaction>;
|
|
82
101
|
};
|
|
83
102
|
export const modes: Record<TransactionMode, ModeModule> = {} as Record<
|
|
84
103
|
TransactionMode,
|
|
@@ -126,6 +145,18 @@ export function hydrate(value: unknown, currency: CryptoCurrency): void {
|
|
|
126
145
|
}
|
|
127
146
|
}
|
|
128
147
|
}
|
|
148
|
+
export const prepareTransaction = (
|
|
149
|
+
account: Account,
|
|
150
|
+
transaction: Transaction
|
|
151
|
+
): Promise<Transaction> =>
|
|
152
|
+
values(modules)
|
|
153
|
+
// @ts-expect-error some module implement it
|
|
154
|
+
.map((m) => m.prepareTransaction)
|
|
155
|
+
.filter(Boolean)
|
|
156
|
+
.reduce(
|
|
157
|
+
(p, fn) => p.then((t) => fn(account, t)),
|
|
158
|
+
Promise.resolve(transaction)
|
|
159
|
+
);
|
|
129
160
|
export const prepareTokenAccounts = (
|
|
130
161
|
currency: CryptoCurrency,
|
|
131
162
|
subAccounts: TokenAccount[],
|
|
@@ -0,0 +1,259 @@
|
|
|
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
|
+
|
|
236
|
+
/*
|
|
237
|
+
// this is never ending here... have to disable this test... (backend issue)
|
|
238
|
+
describe("gaspard NFT on polygon", () => {
|
|
239
|
+
let account = fromAccountRaw(gaspardPolygonAccount);
|
|
240
|
+
test("first sync", async () => {
|
|
241
|
+
await cache.prepareCurrency(account.currency);
|
|
242
|
+
account = await sync(account);
|
|
243
|
+
});
|
|
244
|
+
test(".nfts shouldn't be visible", () => {
|
|
245
|
+
expect(account.nfts).toBeFalsy();
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
*/
|
|
249
|
+
|
|
250
|
+
describe("gaspard NFT on bsc", () => {
|
|
251
|
+
let account = fromAccountRaw(gaspardBscAccount);
|
|
252
|
+
test("first sync", async () => {
|
|
253
|
+
await cache.prepareCurrency(account.currency);
|
|
254
|
+
account = await sync(account);
|
|
255
|
+
});
|
|
256
|
+
test(".nfts shouldn't be visible", () => {
|
|
257
|
+
expect(account.nfts).toBeFalsy();
|
|
258
|
+
});
|
|
259
|
+
});
|
|
@@ -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 {
|
|
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 (
|
|
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
|
-
|
|
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 = {};
|