@ledgerhq/live-common 34.52.0-nightly.1 → 34.52.0-nightly.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.
- package/lib/bridge/generic-alpaca/alpaca/network/network-alpaca.d.ts +2 -1
- package/lib/bridge/generic-alpaca/alpaca/network/network-alpaca.d.ts.map +1 -1
- package/lib/bridge/generic-alpaca/alpaca/network/network-alpaca.js +3 -0
- package/lib/bridge/generic-alpaca/alpaca/network/network-alpaca.js.map +1 -1
- package/lib/dada-client/hooks/useAssetsData.d.ts +4 -10
- package/lib/dada-client/hooks/useAssetsData.d.ts.map +1 -1
- package/lib/dada-client/hooks/useAssetsData.js +2 -1
- package/lib/dada-client/hooks/useAssetsData.js.map +1 -1
- package/lib/dada-client/state-manager/api.d.ts.map +1 -1
- package/lib/dada-client/state-manager/api.js +3 -0
- package/lib/dada-client/state-manager/api.js.map +1 -1
- package/lib/dada-client/state-manager/types.d.ts +1 -0
- package/lib/dada-client/state-manager/types.d.ts.map +1 -1
- package/lib/e2e/data/deviceLabelsData.d.ts.map +1 -1
- package/lib/e2e/data/deviceLabelsData.js +3 -4
- package/lib/e2e/data/deviceLabelsData.js.map +1 -1
- package/lib/e2e/deviceInteraction/TouchDeviceSimulator.d.ts.map +1 -1
- package/lib/e2e/deviceInteraction/TouchDeviceSimulator.js +13 -5
- package/lib/e2e/deviceInteraction/TouchDeviceSimulator.js.map +1 -1
- package/lib/e2e/speculos.d.ts.map +1 -1
- package/lib/e2e/speculos.js +14 -15
- package/lib/e2e/speculos.js.map +1 -1
- package/lib/generated/deviceTransactionConfig.d.ts +1 -1
- package/lib/hooks/useDeviceTransactionConfig.d.ts +19 -0
- package/lib/hooks/useDeviceTransactionConfig.d.ts.map +1 -0
- package/lib/hooks/useDeviceTransactionConfig.js +45 -0
- package/lib/hooks/useDeviceTransactionConfig.js.map +1 -0
- package/lib/modularDrawer/__mocks__/currencies.mock.d.ts +3 -0
- package/lib/modularDrawer/__mocks__/currencies.mock.d.ts.map +1 -1
- package/lib/modularDrawer/__mocks__/currencies.mock.js +40 -1
- package/lib/modularDrawer/__mocks__/currencies.mock.js.map +1 -1
- package/lib/modularDrawer/utils/index.d.ts +3 -2
- package/lib/modularDrawer/utils/index.d.ts.map +1 -1
- package/lib/modularDrawer/utils/index.js +6 -10
- package/lib/modularDrawer/utils/index.js.map +1 -1
- package/lib/transaction/deviceTransactionConfig.d.ts +1 -1
- package/lib/transaction/deviceTransactionConfig.d.ts.map +1 -1
- package/lib/transaction/deviceTransactionConfig.js +2 -2
- package/lib/transaction/deviceTransactionConfig.js.map +1 -1
- package/lib-es/bridge/generic-alpaca/alpaca/network/network-alpaca.d.ts +2 -1
- package/lib-es/bridge/generic-alpaca/alpaca/network/network-alpaca.d.ts.map +1 -1
- package/lib-es/bridge/generic-alpaca/alpaca/network/network-alpaca.js +3 -0
- package/lib-es/bridge/generic-alpaca/alpaca/network/network-alpaca.js.map +1 -1
- package/lib-es/dada-client/hooks/useAssetsData.d.ts +4 -10
- package/lib-es/dada-client/hooks/useAssetsData.d.ts.map +1 -1
- package/lib-es/dada-client/hooks/useAssetsData.js +2 -1
- package/lib-es/dada-client/hooks/useAssetsData.js.map +1 -1
- package/lib-es/dada-client/state-manager/api.d.ts.map +1 -1
- package/lib-es/dada-client/state-manager/api.js +3 -0
- package/lib-es/dada-client/state-manager/api.js.map +1 -1
- package/lib-es/dada-client/state-manager/types.d.ts +1 -0
- package/lib-es/dada-client/state-manager/types.d.ts.map +1 -1
- package/lib-es/e2e/data/deviceLabelsData.d.ts.map +1 -1
- package/lib-es/e2e/data/deviceLabelsData.js +3 -4
- package/lib-es/e2e/data/deviceLabelsData.js.map +1 -1
- package/lib-es/e2e/deviceInteraction/TouchDeviceSimulator.d.ts.map +1 -1
- package/lib-es/e2e/deviceInteraction/TouchDeviceSimulator.js +13 -5
- package/lib-es/e2e/deviceInteraction/TouchDeviceSimulator.js.map +1 -1
- package/lib-es/e2e/speculos.d.ts.map +1 -1
- package/lib-es/e2e/speculos.js +14 -15
- package/lib-es/e2e/speculos.js.map +1 -1
- package/lib-es/generated/deviceTransactionConfig.d.ts +1 -1
- package/lib-es/hooks/useDeviceTransactionConfig.d.ts +19 -0
- package/lib-es/hooks/useDeviceTransactionConfig.d.ts.map +1 -0
- package/lib-es/hooks/useDeviceTransactionConfig.js +41 -0
- package/lib-es/hooks/useDeviceTransactionConfig.js.map +1 -0
- package/lib-es/modularDrawer/__mocks__/currencies.mock.d.ts +3 -0
- package/lib-es/modularDrawer/__mocks__/currencies.mock.d.ts.map +1 -1
- package/lib-es/modularDrawer/__mocks__/currencies.mock.js +39 -0
- package/lib-es/modularDrawer/__mocks__/currencies.mock.js.map +1 -1
- package/lib-es/modularDrawer/utils/index.d.ts +3 -2
- package/lib-es/modularDrawer/utils/index.d.ts.map +1 -1
- package/lib-es/modularDrawer/utils/index.js +4 -9
- package/lib-es/modularDrawer/utils/index.js.map +1 -1
- package/lib-es/transaction/deviceTransactionConfig.d.ts +1 -1
- package/lib-es/transaction/deviceTransactionConfig.d.ts.map +1 -1
- package/lib-es/transaction/deviceTransactionConfig.js +2 -2
- package/lib-es/transaction/deviceTransactionConfig.js.map +1 -1
- package/package.json +48 -48
- package/src/account/serialization.test.ts +1 -0
- package/src/bridge/generic-alpaca/alpaca/network/network-alpaca.ts +4 -0
- package/src/dada-client/hooks/useAssetsData.ts +4 -8
- package/src/dada-client/state-manager/api.ts +3 -0
- package/src/dada-client/state-manager/types.ts +1 -0
- package/src/e2e/data/deviceLabelsData.ts +3 -4
- package/src/e2e/deviceInteraction/TouchDeviceSimulator.ts +12 -5
- package/src/e2e/speculos.ts +18 -16
- package/src/families/bitcoin/satstack.test.ts +1 -0
- package/src/hooks/useDeviceTransactionConfig.test.tsx +200 -0
- package/src/hooks/useDeviceTransactionConfig.ts +65 -0
- package/src/modularDrawer/__mocks__/currencies.mock.ts +40 -0
- package/src/modularDrawer/utils/index.ts +6 -10
- package/src/transaction/deviceTransactionConfig.ts +3 -3
- package/src/modularDrawer/utils/index.test.ts +0 -43
|
@@ -114,7 +114,7 @@ export const DEVICE_LABELS_CONFIG: DeviceLabelsConfig = {
|
|
|
114
114
|
[AppInfos.ETHEREUM.name]: DeviceLabels.VERIFY_ETHEREUM,
|
|
115
115
|
[AppInfos.POLKADOT.name]: DeviceLabels.PLEASE_REVIEW,
|
|
116
116
|
[AppInfos.POLYGON.name]: DeviceLabels.VERIFY_POLYGON,
|
|
117
|
-
[AppInfos.SOLANA.name]: DeviceLabels.
|
|
117
|
+
[AppInfos.SOLANA.name]: DeviceLabels.PUBKEY,
|
|
118
118
|
default: DeviceLabels.ADDRESS,
|
|
119
119
|
},
|
|
120
120
|
receiveConfirm: {
|
|
@@ -124,14 +124,13 @@ export const DEVICE_LABELS_CONFIG: DeviceLabelsConfig = {
|
|
|
124
124
|
[AppInfos.ETHEREUM.name]: DeviceLabels.CONFIRM,
|
|
125
125
|
[AppInfos.POLKADOT.name]: DeviceLabels.CAPS_APPROVE,
|
|
126
126
|
[AppInfos.POLYGON.name]: DeviceLabels.CONFIRM,
|
|
127
|
-
[AppInfos.SOLANA.name]: DeviceLabels.CONFIRM,
|
|
128
127
|
default: DeviceLabels.APPROVE,
|
|
129
128
|
},
|
|
130
129
|
delegateVerify: {
|
|
131
130
|
[AppInfos.COSMOS.name]: DeviceLabels.PLEASE_REVIEW,
|
|
132
131
|
[AppInfos.MULTIVERS_X.name]: DeviceLabels.RECEIVER,
|
|
133
132
|
[AppInfos.NEAR.name]: DeviceLabels.VIEW_HEADER,
|
|
134
|
-
[AppInfos.SOLANA.name]: DeviceLabels.
|
|
133
|
+
[AppInfos.SOLANA.name]: DeviceLabels.DELEGATE_FROM,
|
|
135
134
|
default: DeviceLabels.REVIEW_OPERATION,
|
|
136
135
|
},
|
|
137
136
|
delegateConfirm: {
|
|
@@ -141,7 +140,6 @@ export const DEVICE_LABELS_CONFIG: DeviceLabelsConfig = {
|
|
|
141
140
|
[AppInfos.INJECTIVE.name]: DeviceLabels.CAPS_APPROVE,
|
|
142
141
|
[AppInfos.MULTIVERS_X.name]: DeviceLabels.SIGN,
|
|
143
142
|
[AppInfos.NEAR.name]: DeviceLabels.CONTINUE_TO_ACTION,
|
|
144
|
-
[AppInfos.SOLANA.name]: DeviceLabels.SIGN_TRANSACTION,
|
|
145
143
|
[AppInfos.OSMOSIS.name]: DeviceLabels.CAPS_APPROVE,
|
|
146
144
|
default: DeviceLabels.APPROVE,
|
|
147
145
|
},
|
|
@@ -160,6 +158,7 @@ export const DEVICE_LABELS_CONFIG: DeviceLabelsConfig = {
|
|
|
160
158
|
[AppInfos.BITCOIN.name]: DeviceLabels.SIGN_TRANSACTION,
|
|
161
159
|
[AppInfos.KASPA.name]: DeviceLabels.APPROVE,
|
|
162
160
|
[AppInfos.DOGECOIN.name]: DeviceLabels.ACCEPT,
|
|
161
|
+
[AppInfos.BITCOIN_CASH.name]: DeviceLabels.ACCEPT,
|
|
163
162
|
default: DeviceLabels.CAPS_APPROVE,
|
|
164
163
|
},
|
|
165
164
|
},
|
|
@@ -12,14 +12,21 @@ function getSpeculosInfo(): {
|
|
|
12
12
|
}
|
|
13
13
|
export async function pressAndRelease(deviceLabel: string, x?: number, y?: number) {
|
|
14
14
|
const { speculosApiPort, speculosAddress } = getSpeculosInfo();
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
let xCoord: number;
|
|
16
|
+
let yCoord: number;
|
|
17
|
+
if (x && y) {
|
|
18
|
+
xCoord = x;
|
|
19
|
+
yCoord = y;
|
|
20
|
+
} else {
|
|
21
|
+
const coords = await getDeviceLabelCoordinates(deviceLabel, speculosApiPort);
|
|
22
|
+
xCoord = coords.x;
|
|
23
|
+
yCoord = coords.y;
|
|
24
|
+
}
|
|
18
25
|
await retryAxiosRequest(() =>
|
|
19
26
|
axios.post(`${speculosAddress}:${speculosApiPort}/finger`, {
|
|
20
27
|
action: "press-and-release",
|
|
21
|
-
x:
|
|
22
|
-
y:
|
|
28
|
+
x: xCoord,
|
|
29
|
+
y: yCoord,
|
|
23
30
|
}),
|
|
24
31
|
);
|
|
25
32
|
}
|
package/src/e2e/speculos.ts
CHANGED
|
@@ -654,7 +654,12 @@ export async function activateLedgerSync() {
|
|
|
654
654
|
export async function activateExpertMode() {
|
|
655
655
|
if (isTouchDevice()) {
|
|
656
656
|
await goToSettings();
|
|
657
|
-
|
|
657
|
+
const SettingsToggle1Coordinates = { x: 344, y: 136 };
|
|
658
|
+
await pressAndRelease(
|
|
659
|
+
DeviceLabels.SETTINGS_TOGGLE_1,
|
|
660
|
+
SettingsToggle1Coordinates.x,
|
|
661
|
+
SettingsToggle1Coordinates.y,
|
|
662
|
+
);
|
|
658
663
|
} else {
|
|
659
664
|
await pressUntilTextFound(DeviceLabels.EXPERT_MODE);
|
|
660
665
|
await pressBoth();
|
|
@@ -723,26 +728,23 @@ export function getDeviceLabels(appInfo: AppInfos): DeviceLabelsReturn {
|
|
|
723
728
|
export async function expectValidAddressDevice(account: Account, addressDisplayed: string) {
|
|
724
729
|
if (account.currency === Currency.SUI_USDC) {
|
|
725
730
|
providePublicKey();
|
|
731
|
+
}
|
|
732
|
+
const { receiveVerifyLabel, receiveConfirmLabel } = getDeviceLabels(account.currency.speculosApp);
|
|
733
|
+
await waitFor(receiveVerifyLabel);
|
|
734
|
+
if (isTouchDevice()) {
|
|
735
|
+
const events = await pressUntilTextFound(receiveConfirmLabel);
|
|
736
|
+
const isAddressCorrect = containsSubstringInEvent(addressDisplayed, events);
|
|
737
|
+
expect(isAddressCorrect).toBeTruthy();
|
|
738
|
+
await pressAndRelease(DeviceLabels.CONFIRM);
|
|
726
739
|
} else {
|
|
727
740
|
const { receiveVerifyLabel, receiveConfirmLabel } = getDeviceLabels(
|
|
728
741
|
account.currency.speculosApp,
|
|
729
742
|
);
|
|
730
743
|
await waitFor(receiveVerifyLabel);
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
await pressAndRelease(DeviceLabels.CONFIRM);
|
|
736
|
-
} else {
|
|
737
|
-
const { receiveVerifyLabel, receiveConfirmLabel } = getDeviceLabels(
|
|
738
|
-
account.currency.speculosApp,
|
|
739
|
-
);
|
|
740
|
-
await waitFor(receiveVerifyLabel);
|
|
741
|
-
const events = await pressUntilTextFound(receiveConfirmLabel);
|
|
742
|
-
const isAddressCorrect = containsSubstringInEvent(addressDisplayed, events);
|
|
743
|
-
expect(isAddressCorrect).toBeTruthy();
|
|
744
|
-
await pressBoth();
|
|
745
|
-
}
|
|
744
|
+
const events = await pressUntilTextFound(receiveConfirmLabel);
|
|
745
|
+
const isAddressCorrect = containsSubstringInEvent(addressDisplayed, events);
|
|
746
|
+
expect(isAddressCorrect).toBeTruthy();
|
|
747
|
+
await pressBoth();
|
|
746
748
|
}
|
|
747
749
|
}
|
|
748
750
|
|
|
@@ -236,6 +236,7 @@ describe("editSatStackConfig", () => {
|
|
|
236
236
|
setCryptoAssetsStoreForCoinFramework({
|
|
237
237
|
findTokenById: (_: string) => undefined,
|
|
238
238
|
findTokenByAddressInCurrency: (_: string, __: string) => undefined,
|
|
239
|
+
getTokensSyncHash: (_: string) => Promise.resolve("0"),
|
|
239
240
|
} as CryptoAssetsStore);
|
|
240
241
|
const config = {
|
|
241
242
|
node: { ...mockConfig, tls: false },
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jest-environment jsdom
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { TextDecoder, TextEncoder } from "util";
|
|
6
|
+
|
|
7
|
+
// Polyfill for TextDecoder/TextEncoder required by Cardano dependencies
|
|
8
|
+
global.TextDecoder = TextDecoder as any;
|
|
9
|
+
global.TextEncoder = TextEncoder as any;
|
|
10
|
+
|
|
11
|
+
// Mock the deviceTransactionConfig module before importing anything else
|
|
12
|
+
jest.mock("../transaction/deviceTransactionConfig", () => ({
|
|
13
|
+
getDeviceTransactionConfig: jest.fn(),
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
import { renderHook, waitFor } from "@testing-library/react";
|
|
17
|
+
import { useDeviceTransactionConfig } from "./useDeviceTransactionConfig";
|
|
18
|
+
import { getDeviceTransactionConfig } from "../transaction/deviceTransactionConfig";
|
|
19
|
+
import { Account } from "@ledgerhq/types-live";
|
|
20
|
+
import { Transaction, TransactionStatus } from "../generated/types";
|
|
21
|
+
import BigNumber from "bignumber.js";
|
|
22
|
+
import { getCryptoCurrencyById } from "../currencies/index";
|
|
23
|
+
|
|
24
|
+
const mockGetDeviceTransactionConfig = getDeviceTransactionConfig as jest.MockedFunction<
|
|
25
|
+
typeof getDeviceTransactionConfig
|
|
26
|
+
>;
|
|
27
|
+
|
|
28
|
+
const btc = getCryptoCurrencyById("bitcoin");
|
|
29
|
+
|
|
30
|
+
describe("useDeviceTransactionConfig", () => {
|
|
31
|
+
const mockAccount: Account = {
|
|
32
|
+
type: "Account",
|
|
33
|
+
id: "test-account-id",
|
|
34
|
+
seedIdentifier: "seed-id",
|
|
35
|
+
derivationMode: "" as const,
|
|
36
|
+
index: 0,
|
|
37
|
+
freshAddress: "test-address",
|
|
38
|
+
freshAddressPath: "44'/0'/0'/0/0",
|
|
39
|
+
used: true,
|
|
40
|
+
balance: new BigNumber(1000000),
|
|
41
|
+
spendableBalance: new BigNumber(1000000),
|
|
42
|
+
creationDate: new Date(),
|
|
43
|
+
blockHeight: 100,
|
|
44
|
+
currency: btc,
|
|
45
|
+
operationsCount: 0,
|
|
46
|
+
operations: [],
|
|
47
|
+
pendingOperations: [],
|
|
48
|
+
lastSyncDate: new Date(),
|
|
49
|
+
balanceHistoryCache: {
|
|
50
|
+
HOUR: { latestDate: null, balances: [] },
|
|
51
|
+
DAY: { latestDate: null, balances: [] },
|
|
52
|
+
WEEK: { latestDate: null, balances: [] },
|
|
53
|
+
},
|
|
54
|
+
swapHistory: [],
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const mockTransaction: Transaction = {
|
|
58
|
+
family: "bitcoin" as any,
|
|
59
|
+
amount: new BigNumber(100),
|
|
60
|
+
recipient: "test-recipient",
|
|
61
|
+
useAllAmount: false,
|
|
62
|
+
} as Transaction;
|
|
63
|
+
|
|
64
|
+
const mockStatus: TransactionStatus = {
|
|
65
|
+
errors: {},
|
|
66
|
+
warnings: {},
|
|
67
|
+
estimatedFees: new BigNumber(10),
|
|
68
|
+
amount: new BigNumber(100),
|
|
69
|
+
totalSpent: new BigNumber(110),
|
|
70
|
+
} as TransactionStatus;
|
|
71
|
+
|
|
72
|
+
beforeEach(() => {
|
|
73
|
+
jest.clearAllMocks();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("should load device transaction config fields successfully", async () => {
|
|
77
|
+
const mockFields = [
|
|
78
|
+
{ type: "amount", label: "Amount" },
|
|
79
|
+
{ type: "fees", label: "Fees" },
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
mockGetDeviceTransactionConfig.mockResolvedValue(mockFields as any);
|
|
83
|
+
|
|
84
|
+
const { result } = renderHook(() =>
|
|
85
|
+
useDeviceTransactionConfig({
|
|
86
|
+
account: mockAccount,
|
|
87
|
+
parentAccount: null,
|
|
88
|
+
transaction: mockTransaction,
|
|
89
|
+
status: mockStatus,
|
|
90
|
+
}),
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
// Initially loading
|
|
94
|
+
expect(result.current.loading).toBe(true);
|
|
95
|
+
expect(result.current.fields).toEqual([]);
|
|
96
|
+
|
|
97
|
+
// Wait for async operation
|
|
98
|
+
await waitFor(() => {
|
|
99
|
+
expect(result.current.loading).toBe(false);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
expect(result.current.fields).toEqual(mockFields);
|
|
103
|
+
expect(mockGetDeviceTransactionConfig).toHaveBeenCalledWith({
|
|
104
|
+
account: mockAccount,
|
|
105
|
+
parentAccount: null,
|
|
106
|
+
transaction: mockTransaction,
|
|
107
|
+
status: mockStatus,
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("should handle errors gracefully", async () => {
|
|
112
|
+
const consoleErrorSpy = jest.spyOn(console, "error").mockImplementation();
|
|
113
|
+
mockGetDeviceTransactionConfig.mockRejectedValue(new Error("Test error"));
|
|
114
|
+
|
|
115
|
+
const { result } = renderHook(() =>
|
|
116
|
+
useDeviceTransactionConfig({
|
|
117
|
+
account: mockAccount,
|
|
118
|
+
parentAccount: null,
|
|
119
|
+
transaction: mockTransaction,
|
|
120
|
+
status: mockStatus,
|
|
121
|
+
}),
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
expect(result.current.loading).toBe(true);
|
|
125
|
+
|
|
126
|
+
await waitFor(() => {
|
|
127
|
+
expect(result.current.loading).toBe(false);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
expect(result.current.fields).toEqual([]);
|
|
131
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
132
|
+
"Failed to load device transaction config:",
|
|
133
|
+
expect.any(Error),
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
consoleErrorSpy.mockRestore();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("should reload fields when dependencies change", async () => {
|
|
140
|
+
const mockFields1 = [{ type: "amount", label: "Amount 1" }];
|
|
141
|
+
const mockFields2 = [{ type: "amount", label: "Amount 2" }];
|
|
142
|
+
|
|
143
|
+
mockGetDeviceTransactionConfig
|
|
144
|
+
.mockResolvedValueOnce(mockFields1 as any)
|
|
145
|
+
.mockResolvedValueOnce(mockFields2 as any);
|
|
146
|
+
|
|
147
|
+
const { result, rerender } = renderHook(
|
|
148
|
+
({ transaction }) =>
|
|
149
|
+
useDeviceTransactionConfig({
|
|
150
|
+
account: mockAccount,
|
|
151
|
+
parentAccount: null,
|
|
152
|
+
transaction,
|
|
153
|
+
status: mockStatus,
|
|
154
|
+
}),
|
|
155
|
+
{
|
|
156
|
+
initialProps: { transaction: mockTransaction },
|
|
157
|
+
},
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
await waitFor(() => {
|
|
161
|
+
expect(result.current.loading).toBe(false);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
expect(result.current.fields).toEqual(mockFields1);
|
|
165
|
+
|
|
166
|
+
// Change transaction
|
|
167
|
+
const newTransaction = {
|
|
168
|
+
...mockTransaction,
|
|
169
|
+
amount: new BigNumber(200),
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
rerender({ transaction: newTransaction });
|
|
173
|
+
|
|
174
|
+
await waitFor(() => {
|
|
175
|
+
expect(result.current.loading).toBe(false);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
expect(result.current.fields).toEqual(mockFields2);
|
|
179
|
+
expect(mockGetDeviceTransactionConfig).toHaveBeenCalledTimes(2);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("should cleanup on unmount", async () => {
|
|
183
|
+
const mockFields = [{ type: "amount", label: "Amount" }];
|
|
184
|
+
mockGetDeviceTransactionConfig.mockResolvedValue(mockFields as any);
|
|
185
|
+
|
|
186
|
+
const { unmount } = renderHook(() =>
|
|
187
|
+
useDeviceTransactionConfig({
|
|
188
|
+
account: mockAccount,
|
|
189
|
+
parentAccount: null,
|
|
190
|
+
transaction: mockTransaction,
|
|
191
|
+
status: mockStatus,
|
|
192
|
+
}),
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
unmount();
|
|
196
|
+
|
|
197
|
+
// Should not throw any errors
|
|
198
|
+
expect(mockGetDeviceTransactionConfig).toHaveBeenCalled();
|
|
199
|
+
});
|
|
200
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { useState, useEffect } from "react";
|
|
2
|
+
import { Account, AccountLike } from "@ledgerhq/types-live";
|
|
3
|
+
import { Transaction, TransactionStatus } from "../generated/types";
|
|
4
|
+
import {
|
|
5
|
+
getDeviceTransactionConfig,
|
|
6
|
+
DeviceTransactionField,
|
|
7
|
+
} from "../transaction/deviceTransactionConfig";
|
|
8
|
+
|
|
9
|
+
type UseDeviceTransactionConfigParams = {
|
|
10
|
+
account: AccountLike;
|
|
11
|
+
parentAccount: Account | null | undefined;
|
|
12
|
+
transaction: Transaction;
|
|
13
|
+
status: TransactionStatus;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Hook to fetch device transaction configuration fields asynchronously.
|
|
18
|
+
* This anticipates the future async nature of crypto assets store operations.
|
|
19
|
+
*/
|
|
20
|
+
export function useDeviceTransactionConfig({
|
|
21
|
+
account,
|
|
22
|
+
parentAccount,
|
|
23
|
+
transaction,
|
|
24
|
+
status,
|
|
25
|
+
}: UseDeviceTransactionConfigParams): {
|
|
26
|
+
fields: DeviceTransactionField[];
|
|
27
|
+
loading: boolean;
|
|
28
|
+
} {
|
|
29
|
+
const [fields, setFields] = useState<DeviceTransactionField[]>([]);
|
|
30
|
+
const [loading, setLoading] = useState(true);
|
|
31
|
+
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
let mounted = true;
|
|
34
|
+
|
|
35
|
+
async function loadFields() {
|
|
36
|
+
try {
|
|
37
|
+
setLoading(true);
|
|
38
|
+
const result = await getDeviceTransactionConfig({
|
|
39
|
+
account,
|
|
40
|
+
parentAccount,
|
|
41
|
+
transaction,
|
|
42
|
+
status,
|
|
43
|
+
});
|
|
44
|
+
if (mounted) {
|
|
45
|
+
setFields(result);
|
|
46
|
+
setLoading(false);
|
|
47
|
+
}
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error("Failed to load device transaction config:", error);
|
|
50
|
+
if (mounted) {
|
|
51
|
+
setFields([]);
|
|
52
|
+
setLoading(false);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
loadFields();
|
|
58
|
+
|
|
59
|
+
return () => {
|
|
60
|
+
mounted = false;
|
|
61
|
+
};
|
|
62
|
+
}, [account, parentAccount, transaction, status]);
|
|
63
|
+
|
|
64
|
+
return { fields, loading };
|
|
65
|
+
}
|
|
@@ -7,6 +7,7 @@ export const mockArbitrumCryptoCurrency = getCryptoCurrencyById("arbitrum");
|
|
|
7
7
|
export const mockBaseCryptoCurrency = getCryptoCurrencyById("base");
|
|
8
8
|
export const mockScrollCryptoCurrency = getCryptoCurrencyById("scroll");
|
|
9
9
|
export const mockInjectiveCryptoCurrency = getCryptoCurrencyById("injective");
|
|
10
|
+
export const mockBscCryptoCurrency = getCryptoCurrencyById("bsc");
|
|
10
11
|
|
|
11
12
|
export const arbitrumToken: TokenCurrency = {
|
|
12
13
|
type: "TokenCurrency",
|
|
@@ -41,6 +42,45 @@ export const usdcToken: TokenCurrency = {
|
|
|
41
42
|
],
|
|
42
43
|
};
|
|
43
44
|
|
|
45
|
+
export const maticEth: TokenCurrency = {
|
|
46
|
+
type: "TokenCurrency" as const,
|
|
47
|
+
id: "ethereum/erc20/matic",
|
|
48
|
+
ledgerSignature: "",
|
|
49
|
+
contractAddress: "0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0",
|
|
50
|
+
parentCurrency: mockEthCryptoCurrency,
|
|
51
|
+
tokenType: "erc20" as const,
|
|
52
|
+
name: "Matic",
|
|
53
|
+
ticker: "MATIC",
|
|
54
|
+
delisted: false,
|
|
55
|
+
disableCountervalue: false,
|
|
56
|
+
units: [
|
|
57
|
+
{
|
|
58
|
+
name: "Matic",
|
|
59
|
+
code: "MATIC",
|
|
60
|
+
magnitude: 18,
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const maticBsc: TokenCurrency = {
|
|
66
|
+
type: "TokenCurrency" as const,
|
|
67
|
+
id: "bsc/bep20/matic_token",
|
|
68
|
+
ledgerSignature: "",
|
|
69
|
+
contractAddress: "0xCC42724C6683B7E57334c4E856f4c9965ED682bD",
|
|
70
|
+
parentCurrency: mockBscCryptoCurrency,
|
|
71
|
+
tokenType: "bep20" as const,
|
|
72
|
+
name: "Matic Token",
|
|
73
|
+
ticker: "MATIC",
|
|
74
|
+
delisted: false,
|
|
75
|
+
disableCountervalue: false,
|
|
76
|
+
units: [
|
|
77
|
+
{
|
|
78
|
+
name: "Matic Token",
|
|
79
|
+
code: "MATIC",
|
|
80
|
+
magnitude: 18,
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
};
|
|
44
84
|
export const findCryptoCurrencyById = (id: string) =>
|
|
45
85
|
[mockBtcCryptoCurrency, mockEthCryptoCurrency, mockArbitrumCryptoCurrency].find(a => a.id === id);
|
|
46
86
|
export const getTokenOrCryptoCurrencyById = (id: string) =>
|
|
@@ -2,17 +2,13 @@ import { CryptoOrTokenCurrency } from "@ledgerhq/types-cryptoassets";
|
|
|
2
2
|
export { groupCurrenciesByProvider } from "./groupCurrenciesByProvider";
|
|
3
3
|
export { sortAccountsByFiatValue } from "./sortAccountsByFiatValue";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
const getBaseId = (currency: CryptoOrTokenCurrency) =>
|
|
6
|
+
currency.type === "CryptoCurrency" ? currency.id : currency.parentCurrency.id;
|
|
7
|
+
|
|
8
|
+
function belongsToSameNetwork(
|
|
6
9
|
elem: CryptoOrTokenCurrency,
|
|
7
10
|
network: CryptoOrTokenCurrency,
|
|
8
11
|
): boolean {
|
|
9
|
-
|
|
10
|
-
return elem.parentCurrency?.id === network.id || elem.id === network.id;
|
|
11
|
-
}
|
|
12
|
-
if (elem.type === "CryptoCurrency") {
|
|
13
|
-
return elem.id === network.id;
|
|
14
|
-
}
|
|
15
|
-
return false;
|
|
12
|
+
return getBaseId(elem) === getBaseId(network);
|
|
16
13
|
}
|
|
17
|
-
|
|
18
|
-
export { isCorrespondingCurrency };
|
|
14
|
+
export { getBaseId, belongsToSameNetwork };
|
|
@@ -6,14 +6,14 @@ import { getMainAccount } from "../account";
|
|
|
6
6
|
import type { Account, AccountLike } from "@ledgerhq/types-live";
|
|
7
7
|
|
|
8
8
|
export type DeviceTransactionField = CommonDeviceTransactionField | ExtraDeviceTransactionField;
|
|
9
|
-
export function getDeviceTransactionConfig(arg: {
|
|
9
|
+
export async function getDeviceTransactionConfig(arg: {
|
|
10
10
|
account: AccountLike;
|
|
11
11
|
parentAccount: Account | null | undefined;
|
|
12
12
|
transaction: Transaction;
|
|
13
13
|
status: TransactionStatus;
|
|
14
|
-
}): Array<DeviceTransactionField
|
|
14
|
+
}): Promise<Array<DeviceTransactionField>> {
|
|
15
15
|
const mainAccount = getMainAccount(arg.account, arg.parentAccount);
|
|
16
16
|
const f = perFamily[mainAccount.currency.family];
|
|
17
17
|
if (!f) return [];
|
|
18
|
-
return f(arg);
|
|
18
|
+
return await f(arg);
|
|
19
19
|
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { isCorrespondingCurrency } from "./index";
|
|
2
|
-
|
|
3
|
-
import { createFixtureCryptoCurrency } from "../../mock/fixtures/cryptoCurrencies";
|
|
4
|
-
import { cryptocurrenciesById } from "@ledgerhq/cryptoassets";
|
|
5
|
-
import type { CryptoOrTokenCurrency } from "@ledgerhq/types-cryptoassets";
|
|
6
|
-
|
|
7
|
-
describe("isCorrespondingCurrency", () => {
|
|
8
|
-
const evmCurrency = createFixtureCryptoCurrency("evm");
|
|
9
|
-
const usdcToken: CryptoOrTokenCurrency = {
|
|
10
|
-
type: "TokenCurrency",
|
|
11
|
-
id: "ethereum/erc20/usdc",
|
|
12
|
-
contractAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
13
|
-
parentCurrency: evmCurrency,
|
|
14
|
-
tokenType: "erc20",
|
|
15
|
-
name: "USD Coin",
|
|
16
|
-
ticker: "USDC",
|
|
17
|
-
units: [{ name: "USD Coin", code: "USDC", magnitude: 6 }],
|
|
18
|
-
};
|
|
19
|
-
const evmCrypto: CryptoOrTokenCurrency = evmCurrency;
|
|
20
|
-
|
|
21
|
-
it("returns true for a token whose parentCurrency.id matches the reference crypto", () => {
|
|
22
|
-
expect(isCorrespondingCurrency(usdcToken, evmCurrency)).toBe(true);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it("returns true for a token whose id matches the reference crypto", () => {
|
|
26
|
-
expect(isCorrespondingCurrency(usdcToken, usdcToken)).toBe(true);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it("returns true for a crypto whose id matches the reference crypto", () => {
|
|
30
|
-
expect(isCorrespondingCurrency(evmCrypto, evmCurrency)).toBe(true);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it("returns false for a token whose parentCurrency is different", () => {
|
|
34
|
-
const bitcoinCurrency = cryptocurrenciesById["bitcoin"];
|
|
35
|
-
const tokenWithOtherParent = { ...usdcToken, parentCurrency: bitcoinCurrency };
|
|
36
|
-
expect(isCorrespondingCurrency(tokenWithOtherParent, evmCurrency)).toBe(false);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it("returns false for a crypto whose id is different", () => {
|
|
40
|
-
const bitcoinCurrency = cryptocurrenciesById["bitcoin"];
|
|
41
|
-
expect(isCorrespondingCurrency(bitcoinCurrency, evmCurrency)).toBe(false);
|
|
42
|
-
});
|
|
43
|
-
});
|