@ledgerhq/live-common 34.55.0-nightly.20251210120335 → 34.55.0-nightly.20251212024049
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/accountBridge.d.ts.map +1 -1
- package/lib/bridge/generic-alpaca/accountBridge.js +2 -1
- package/lib/bridge/generic-alpaca/accountBridge.js.map +1 -1
- package/lib/bridge/generic-alpaca/signer/index.d.ts +4 -0
- package/lib/bridge/generic-alpaca/signer/index.d.ts.map +1 -1
- package/lib/bridge/generic-alpaca/signer/index.js +22 -1
- package/lib/bridge/generic-alpaca/signer/index.js.map +1 -1
- package/lib/bridge/mockHelpers.d.ts +1 -1
- package/lib/bridge/mockHelpers.d.ts.map +1 -1
- package/lib/bridge/mockHelpers.js +2 -6
- package/lib/bridge/mockHelpers.js.map +1 -1
- package/lib/bridge/validateAddress.d.ts +4 -0
- package/lib/bridge/validateAddress.d.ts.map +1 -0
- package/lib/bridge/validateAddress.js +14 -0
- package/lib/bridge/validateAddress.js.map +1 -0
- package/lib/e2e/speculos.d.ts.map +1 -1
- package/lib/e2e/speculos.js +0 -1
- package/lib/e2e/speculos.js.map +1 -1
- package/lib/e2e/speculosAppVersion.d.ts +1 -0
- package/lib/e2e/speculosAppVersion.d.ts.map +1 -1
- package/lib/e2e/speculosAppVersion.js +38 -14
- package/lib/e2e/speculosAppVersion.js.map +1 -1
- package/lib/e2e/speculosCI.d.ts.map +1 -1
- package/lib/e2e/speculosCI.js +1 -6
- package/lib/e2e/speculosCI.js.map +1 -1
- package/lib/families/algorand/bridge/mock.d.ts.map +1 -1
- package/lib/families/algorand/bridge/mock.js +2 -0
- package/lib/families/algorand/bridge/mock.js.map +1 -1
- package/lib/families/bitcoin/bridge/mock.d.ts.map +1 -1
- package/lib/families/bitcoin/bridge/mock.js +2 -0
- package/lib/families/bitcoin/bridge/mock.js.map +1 -1
- package/lib/families/canton/bridge/mock.d.ts.map +1 -1
- package/lib/families/canton/bridge/mock.js +2 -0
- package/lib/families/canton/bridge/mock.js.map +1 -1
- package/lib/families/canton/react.d.ts +7 -1
- package/lib/families/canton/react.d.ts.map +1 -1
- package/lib/families/canton/react.js +38 -1
- package/lib/families/canton/react.js.map +1 -1
- package/lib/families/cardano/bridge/mock.d.ts.map +1 -1
- package/lib/families/cardano/bridge/mock.js +2 -0
- package/lib/families/cardano/bridge/mock.js.map +1 -1
- package/lib/families/casper/bridge/mock.d.ts.map +1 -1
- package/lib/families/casper/bridge/mock.js +2 -0
- package/lib/families/casper/bridge/mock.js.map +1 -1
- package/lib/families/cosmos/bridge/mock.d.ts.map +1 -1
- package/lib/families/cosmos/bridge/mock.js +2 -0
- package/lib/families/cosmos/bridge/mock.js.map +1 -1
- package/lib/families/evm/bridge/mock.d.ts.map +1 -1
- package/lib/families/evm/bridge/mock.js +2 -0
- package/lib/families/evm/bridge/mock.js.map +1 -1
- package/lib/families/icon/bridge/mock.d.ts.map +1 -1
- package/lib/families/icon/bridge/mock.js +2 -0
- package/lib/families/icon/bridge/mock.js.map +1 -1
- package/lib/families/multiversx/bridge/mock.d.ts.map +1 -1
- package/lib/families/multiversx/bridge/mock.js +2 -0
- package/lib/families/multiversx/bridge/mock.js.map +1 -1
- package/lib/families/polkadot/bridge/mock.d.ts.map +1 -1
- package/lib/families/polkadot/bridge/mock.js +2 -0
- package/lib/families/polkadot/bridge/mock.js.map +1 -1
- package/lib/families/solana/bridge/mock.d.ts +1 -0
- package/lib/families/solana/bridge/mock.d.ts.map +1 -1
- package/lib/families/stellar/bridge/mock.d.ts.map +1 -1
- package/lib/families/stellar/bridge/mock.js +2 -0
- package/lib/families/stellar/bridge/mock.js.map +1 -1
- package/lib/families/tezos/bridge/mock.d.ts.map +1 -1
- package/lib/families/tezos/bridge/mock.js +2 -0
- package/lib/families/tezos/bridge/mock.js.map +1 -1
- package/lib/families/tron/bridge/mock.d.ts.map +1 -1
- package/lib/families/tron/bridge/mock.js +2 -0
- package/lib/families/tron/bridge/mock.js.map +1 -1
- package/lib/families/xrp/bridge/mock.d.ts.map +1 -1
- package/lib/families/xrp/bridge/mock.js +2 -0
- package/lib/families/xrp/bridge/mock.js.map +1 -1
- package/lib/featureFlags/defaultFeatures.d.ts.map +1 -1
- package/lib/featureFlags/defaultFeatures.js +1 -0
- package/lib/featureFlags/defaultFeatures.js.map +1 -1
- package/lib/generated/bridge/mock.d.ts +1 -0
- package/lib/generated/bridge/mock.d.ts.map +1 -1
- package/lib/generated/mock.d.ts +3 -3
- package/lib/hw/connectAppEventMapper.d.ts.map +1 -1
- package/lib/hw/connectAppEventMapper.js +21 -2
- package/lib/hw/connectAppEventMapper.js.map +1 -1
- package/lib/modularDrawer/hooks/useLeftAccounts.d.ts.map +1 -1
- package/lib/modularDrawer/hooks/useLeftAccounts.js +1 -0
- package/lib/modularDrawer/hooks/useLeftAccounts.js.map +1 -1
- package/lib/modularDrawer/hooks/useLeftAccountsApy.d.ts +1 -1
- package/lib/modularDrawer/hooks/useLeftAccountsApy.d.ts.map +1 -1
- package/lib/modularDrawer/hooks/useLeftAccountsApy.js +6 -1
- package/lib/modularDrawer/hooks/useLeftAccountsApy.js.map +1 -1
- package/lib/modularDrawer/modules/createNetworkConfiguration.d.ts +2 -0
- package/lib/modularDrawer/modules/createNetworkConfiguration.d.ts.map +1 -1
- package/lib/modularDrawer/modules/createNetworkConfiguration.js +1 -1
- package/lib/modularDrawer/modules/createNetworkConfiguration.js.map +1 -1
- package/lib/modularDrawer/utils/type.d.ts +8 -1
- package/lib/modularDrawer/utils/type.d.ts.map +1 -1
- package/lib-es/bridge/generic-alpaca/accountBridge.d.ts.map +1 -1
- package/lib-es/bridge/generic-alpaca/accountBridge.js +3 -2
- package/lib-es/bridge/generic-alpaca/accountBridge.js.map +1 -1
- package/lib-es/bridge/generic-alpaca/signer/index.d.ts +4 -0
- package/lib-es/bridge/generic-alpaca/signer/index.d.ts.map +1 -1
- package/lib-es/bridge/generic-alpaca/signer/index.js +20 -0
- package/lib-es/bridge/generic-alpaca/signer/index.js.map +1 -1
- package/lib-es/bridge/mockHelpers.d.ts +1 -1
- package/lib-es/bridge/mockHelpers.d.ts.map +1 -1
- package/lib-es/bridge/mockHelpers.js +1 -5
- package/lib-es/bridge/mockHelpers.js.map +1 -1
- package/lib-es/bridge/validateAddress.d.ts +4 -0
- package/lib-es/bridge/validateAddress.d.ts.map +1 -0
- package/lib-es/bridge/validateAddress.js +9 -0
- package/lib-es/bridge/validateAddress.js.map +1 -0
- package/lib-es/e2e/speculos.d.ts.map +1 -1
- package/lib-es/e2e/speculos.js +0 -1
- package/lib-es/e2e/speculos.js.map +1 -1
- package/lib-es/e2e/speculosAppVersion.d.ts +1 -0
- package/lib-es/e2e/speculosAppVersion.d.ts.map +1 -1
- package/lib-es/e2e/speculosAppVersion.js +36 -13
- package/lib-es/e2e/speculosAppVersion.js.map +1 -1
- package/lib-es/e2e/speculosCI.d.ts.map +1 -1
- package/lib-es/e2e/speculosCI.js +1 -6
- package/lib-es/e2e/speculosCI.js.map +1 -1
- package/lib-es/families/algorand/bridge/mock.d.ts.map +1 -1
- package/lib-es/families/algorand/bridge/mock.js +2 -0
- package/lib-es/families/algorand/bridge/mock.js.map +1 -1
- package/lib-es/families/bitcoin/bridge/mock.d.ts.map +1 -1
- package/lib-es/families/bitcoin/bridge/mock.js +2 -0
- package/lib-es/families/bitcoin/bridge/mock.js.map +1 -1
- package/lib-es/families/canton/bridge/mock.d.ts.map +1 -1
- package/lib-es/families/canton/bridge/mock.js +2 -0
- package/lib-es/families/canton/bridge/mock.js.map +1 -1
- package/lib-es/families/canton/react.d.ts +7 -1
- package/lib-es/families/canton/react.d.ts.map +1 -1
- package/lib-es/families/canton/react.js +34 -1
- package/lib-es/families/canton/react.js.map +1 -1
- package/lib-es/families/cardano/bridge/mock.d.ts.map +1 -1
- package/lib-es/families/cardano/bridge/mock.js +2 -0
- package/lib-es/families/cardano/bridge/mock.js.map +1 -1
- package/lib-es/families/casper/bridge/mock.d.ts.map +1 -1
- package/lib-es/families/casper/bridge/mock.js +2 -0
- package/lib-es/families/casper/bridge/mock.js.map +1 -1
- package/lib-es/families/cosmos/bridge/mock.d.ts.map +1 -1
- package/lib-es/families/cosmos/bridge/mock.js +2 -0
- package/lib-es/families/cosmos/bridge/mock.js.map +1 -1
- package/lib-es/families/evm/bridge/mock.d.ts.map +1 -1
- package/lib-es/families/evm/bridge/mock.js +2 -0
- package/lib-es/families/evm/bridge/mock.js.map +1 -1
- package/lib-es/families/icon/bridge/mock.d.ts.map +1 -1
- package/lib-es/families/icon/bridge/mock.js +2 -0
- package/lib-es/families/icon/bridge/mock.js.map +1 -1
- package/lib-es/families/multiversx/bridge/mock.d.ts.map +1 -1
- package/lib-es/families/multiversx/bridge/mock.js +2 -0
- package/lib-es/families/multiversx/bridge/mock.js.map +1 -1
- package/lib-es/families/polkadot/bridge/mock.d.ts.map +1 -1
- package/lib-es/families/polkadot/bridge/mock.js +2 -0
- package/lib-es/families/polkadot/bridge/mock.js.map +1 -1
- package/lib-es/families/solana/bridge/mock.d.ts +1 -0
- package/lib-es/families/solana/bridge/mock.d.ts.map +1 -1
- package/lib-es/families/stellar/bridge/mock.d.ts.map +1 -1
- package/lib-es/families/stellar/bridge/mock.js +2 -0
- package/lib-es/families/stellar/bridge/mock.js.map +1 -1
- package/lib-es/families/tezos/bridge/mock.d.ts.map +1 -1
- package/lib-es/families/tezos/bridge/mock.js +2 -0
- package/lib-es/families/tezos/bridge/mock.js.map +1 -1
- package/lib-es/families/tron/bridge/mock.d.ts.map +1 -1
- package/lib-es/families/tron/bridge/mock.js +2 -0
- package/lib-es/families/tron/bridge/mock.js.map +1 -1
- package/lib-es/families/xrp/bridge/mock.d.ts.map +1 -1
- package/lib-es/families/xrp/bridge/mock.js +2 -0
- package/lib-es/families/xrp/bridge/mock.js.map +1 -1
- package/lib-es/featureFlags/defaultFeatures.d.ts.map +1 -1
- package/lib-es/featureFlags/defaultFeatures.js +1 -0
- package/lib-es/featureFlags/defaultFeatures.js.map +1 -1
- package/lib-es/generated/bridge/mock.d.ts +1 -0
- package/lib-es/generated/bridge/mock.d.ts.map +1 -1
- package/lib-es/generated/mock.d.ts +3 -3
- package/lib-es/hw/connectAppEventMapper.d.ts.map +1 -1
- package/lib-es/hw/connectAppEventMapper.js +23 -4
- package/lib-es/hw/connectAppEventMapper.js.map +1 -1
- package/lib-es/modularDrawer/hooks/useLeftAccounts.d.ts.map +1 -1
- package/lib-es/modularDrawer/hooks/useLeftAccounts.js +1 -0
- package/lib-es/modularDrawer/hooks/useLeftAccounts.js.map +1 -1
- package/lib-es/modularDrawer/hooks/useLeftAccountsApy.d.ts +1 -1
- package/lib-es/modularDrawer/hooks/useLeftAccountsApy.d.ts.map +1 -1
- package/lib-es/modularDrawer/hooks/useLeftAccountsApy.js +6 -1
- package/lib-es/modularDrawer/hooks/useLeftAccountsApy.js.map +1 -1
- package/lib-es/modularDrawer/modules/createNetworkConfiguration.d.ts +2 -0
- package/lib-es/modularDrawer/modules/createNetworkConfiguration.d.ts.map +1 -1
- package/lib-es/modularDrawer/modules/createNetworkConfiguration.js +1 -1
- package/lib-es/modularDrawer/modules/createNetworkConfiguration.js.map +1 -1
- package/lib-es/modularDrawer/utils/type.d.ts +8 -1
- package/lib-es/modularDrawer/utils/type.d.ts.map +1 -1
- package/package.json +74 -74
- package/src/bridge/generic-alpaca/accountBridge.ts +2 -1
- package/src/bridge/generic-alpaca/signer/index.ts +29 -0
- package/src/bridge/mockHelpers.ts +2 -4
- package/src/bridge/validateAddress.test.ts +24 -0
- package/src/bridge/validateAddress.ts +13 -0
- package/src/e2e/speculos.ts +0 -1
- package/src/e2e/speculosAppVersion.ts +58 -13
- package/src/e2e/speculosCI.ts +1 -6
- package/src/families/algorand/bridge/mock.ts +2 -0
- package/src/families/bitcoin/bridge/mock.ts +2 -0
- package/src/families/canton/bridge/mock.ts +2 -0
- package/src/families/canton/react.ts +53 -3
- package/src/families/cardano/bridge/mock.ts +2 -0
- package/src/families/casper/bridge/mock.ts +2 -0
- package/src/families/cosmos/bridge/mock.ts +2 -0
- package/src/families/evm/bridge/mock.ts +3 -0
- package/src/families/icon/bridge/mock.ts +2 -0
- package/src/families/multiversx/bridge/mock.ts +2 -0
- package/src/families/polkadot/bridge/mock.ts +2 -0
- package/src/families/stellar/bridge/mock.ts +2 -0
- package/src/families/tezos/bridge/mock.ts +2 -0
- package/src/families/tron/bridge/mock.ts +2 -0
- package/src/families/xrp/bridge/mock.ts +2 -0
- package/src/featureFlags/defaultFeatures.ts +1 -0
- package/src/hw/connectAppEventMapper.ts +28 -4
- package/src/modularDrawer/hooks/useLeftAccounts.tsx +1 -0
- package/src/modularDrawer/hooks/useLeftAccountsApy.tsx +6 -0
- package/src/modularDrawer/modules/createNetworkConfiguration.ts +16 -2
- package/src/modularDrawer/utils/type.ts +8 -1
|
@@ -11,6 +11,11 @@ import { DerivationType, LedgerSigner as TaquitoLedgerSigner } from "@taquito/le
|
|
|
11
11
|
import tezosGetAddress from "@ledgerhq/coin-tezos/signer/getAddress";
|
|
12
12
|
import Tezos from "@ledgerhq/hw-app-tezos";
|
|
13
13
|
import { context as evmContext, getAddress as evmGetAddress } from "./Eth";
|
|
14
|
+
import { AddressValidationCurrencyParameters } from "@ledgerhq/types-live";
|
|
15
|
+
import { validateAddress as tezosValidateAddress } from "@ledgerhq/coin-tezos/logic/validateAddress";
|
|
16
|
+
import { validateAddress as xrpValidateAddress } from "@ledgerhq/coin-xrp/logic/validateAddress";
|
|
17
|
+
import { validateAddress as stellarValidateAddress } from "@ledgerhq/coin-stellar/logic/validateAddress";
|
|
18
|
+
import { validateAddress as evmValidateAddress } from "@ledgerhq/coin-evm/logic/validateAddress";
|
|
14
19
|
|
|
15
20
|
const createSignerXrp: CreateSigner<Xrp> = (transport: Transport) => {
|
|
16
21
|
return new Xrp(transport);
|
|
@@ -107,3 +112,27 @@ export function getSigner(network: string): AlpacaSigner {
|
|
|
107
112
|
}
|
|
108
113
|
throw new Error(`signer for ${network} not implemented`);
|
|
109
114
|
}
|
|
115
|
+
|
|
116
|
+
type ValidateAddressFunction = (
|
|
117
|
+
address: string,
|
|
118
|
+
parameters: Partial<AddressValidationCurrencyParameters>,
|
|
119
|
+
) => Promise<boolean>;
|
|
120
|
+
|
|
121
|
+
const validateAddressByNetwork = new Map<string, ValidateAddressFunction>();
|
|
122
|
+
validateAddressByNetwork.set("stellar", stellarValidateAddress);
|
|
123
|
+
validateAddressByNetwork.set("xrp", xrpValidateAddress);
|
|
124
|
+
validateAddressByNetwork.set("tezos", tezosValidateAddress);
|
|
125
|
+
validateAddressByNetwork.set("evm", evmValidateAddress);
|
|
126
|
+
validateAddressByNetwork.set("ethereum", evmValidateAddress); // for the coin tester
|
|
127
|
+
validateAddressByNetwork.set("sonic", evmValidateAddress); // for the coin tester
|
|
128
|
+
validateAddressByNetwork.set("polygon", evmValidateAddress); // for the coin tester
|
|
129
|
+
validateAddressByNetwork.set("core", evmValidateAddress); // for the coin tester
|
|
130
|
+
|
|
131
|
+
export function getValidateAddress(network: string): ValidateAddressFunction {
|
|
132
|
+
const validateAddress = validateAddressByNetwork.get(network);
|
|
133
|
+
if (!validateAddress) {
|
|
134
|
+
throw new Error(`No validate address function for network ${network}`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return validateAddress;
|
|
138
|
+
}
|
|
@@ -110,10 +110,8 @@ export const signOperation: AccountBridge<any>["signOperation"] = ({ account, tr
|
|
|
110
110
|
cancelled = true;
|
|
111
111
|
};
|
|
112
112
|
});
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
return recipient.includes("invalid") || recipient.length <= 3;
|
|
116
|
-
};
|
|
113
|
+
|
|
114
|
+
export { isInvalidRecipient } from "./validateAddress";
|
|
117
115
|
|
|
118
116
|
const subtractOneYear = date =>
|
|
119
117
|
new Date(new Date(date).setFullYear(new Date(date).getFullYear() - 1));
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as validateAddress from "./validateAddress";
|
|
2
|
+
|
|
3
|
+
describe("validateAddress", () => {
|
|
4
|
+
const spiedIsInvalidRecipient = jest.spyOn(validateAddress, "isInvalidRecipient");
|
|
5
|
+
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
spiedIsInvalidRecipient.mockClear();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it.each([true, false])(
|
|
11
|
+
"should call isInvalidRecipient and return expected value (%s)",
|
|
12
|
+
async (expectedValue: boolean) => {
|
|
13
|
+
spiedIsInvalidRecipient.mockReturnValueOnce(expectedValue);
|
|
14
|
+
|
|
15
|
+
const address = "some random address";
|
|
16
|
+
const parameters = {};
|
|
17
|
+
const result = await validateAddress.validateAddress(address, parameters);
|
|
18
|
+
expect(result).toEqual(expectedValue);
|
|
19
|
+
|
|
20
|
+
expect(spiedIsInvalidRecipient).toHaveBeenCalledTimes(1);
|
|
21
|
+
expect(spiedIsInvalidRecipient).toHaveBeenCalledWith(address);
|
|
22
|
+
},
|
|
23
|
+
);
|
|
24
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AddressValidationCurrencyParameters } from "@ledgerhq/types-live";
|
|
2
|
+
|
|
3
|
+
export const isInvalidRecipient = (recipient: string) => {
|
|
4
|
+
if (recipient.includes("criticalcrash")) throw new Error("isInvalidRecipient_mock_criticalcrash");
|
|
5
|
+
return recipient.includes("invalid") || recipient.length <= 3;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export async function validateAddress(
|
|
9
|
+
address: string,
|
|
10
|
+
_parameters: Partial<AddressValidationCurrencyParameters>,
|
|
11
|
+
): Promise<boolean> {
|
|
12
|
+
return isInvalidRecipient(address);
|
|
13
|
+
}
|
package/src/e2e/speculos.ts
CHANGED
|
@@ -59,24 +59,63 @@ export async function getNanoAppCatalog(
|
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
const firmwareVersionCache: Map<DeviceModelId, string> = new Map();
|
|
63
|
+
|
|
64
|
+
export async function getDeviceFirmwareVersion(device: DeviceModelId): Promise<string> {
|
|
65
|
+
const cached = firmwareVersionCache.get(device);
|
|
66
|
+
if (cached) return cached;
|
|
67
|
+
|
|
68
|
+
const providerId = 1;
|
|
69
|
+
const repository = new HttpManagerApiRepository(getEnv("MANAGER_API_BASE"), version);
|
|
70
|
+
|
|
71
|
+
const deviceVersion = await repository.getDeviceVersion({
|
|
72
|
+
targetId: getDeviceTargetId(device),
|
|
73
|
+
providerId,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const firmwareIds = deviceVersion.se_firmware_final_versions;
|
|
77
|
+
if (!Array.isArray(firmwareIds) || firmwareIds.length === 0) {
|
|
78
|
+
throw new Error(`No firmware versions found for device ${device}`);
|
|
66
79
|
}
|
|
67
|
-
|
|
80
|
+
|
|
81
|
+
const firmwares = await Promise.all(firmwareIds.map(id => repository.getFinalFirmwareById(id)));
|
|
82
|
+
|
|
83
|
+
// Only firmwares matching providerId
|
|
84
|
+
const providerFirmwares = firmwares.filter(
|
|
85
|
+
fw => Array.isArray(fw.providers) && fw.providers.includes(providerId),
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
if (providerFirmwares.length === 0) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
`No firmware versions found for device version ${deviceVersion.id} for device ${device}`,
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Latest is chosen by highest numeric ID
|
|
95
|
+
const latestFirmware = providerFirmwares.reduce((latest, current) =>
|
|
96
|
+
current.id > latest.id ? current : latest,
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
firmwareVersionCache.set(device, latestFirmware.version);
|
|
100
|
+
process.env.SPECULOS_FIRMWARE_VERSION = latestFirmware.version;
|
|
101
|
+
|
|
102
|
+
return latestFirmware.version;
|
|
68
103
|
}
|
|
69
104
|
|
|
70
105
|
export async function createNanoAppJsonFile(nanoAppFilePath: string): Promise<void> {
|
|
106
|
+
const jsonFilePath = path.resolve(process.cwd(), nanoAppFilePath);
|
|
107
|
+
|
|
71
108
|
try {
|
|
109
|
+
if (fs.existsSync(jsonFilePath)) {
|
|
110
|
+
return; // File already exists
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
fs.mkdirSync(path.dirname(jsonFilePath), { recursive: true });
|
|
114
|
+
|
|
72
115
|
const device = getSpeculosModel();
|
|
73
|
-
const firmware = getDeviceFirmwareVersion();
|
|
116
|
+
const firmware = await getDeviceFirmwareVersion(device);
|
|
74
117
|
const appCatalog = await getNanoAppCatalog(device, firmware);
|
|
75
|
-
|
|
76
|
-
const dirPath = path.dirname(jsonFilePath);
|
|
77
|
-
if (!fs.existsSync(dirPath)) {
|
|
78
|
-
fs.mkdirSync(dirPath, { recursive: true });
|
|
79
|
-
}
|
|
118
|
+
|
|
80
119
|
fs.writeFileSync(jsonFilePath, JSON.stringify(appCatalog, null, 2), "utf8");
|
|
81
120
|
} catch (error) {
|
|
82
121
|
console.error("Unable to create app version file:", sanitizeError(error));
|
|
@@ -87,10 +126,16 @@ export async function getAppVersionFromCatalog(
|
|
|
87
126
|
currency: string,
|
|
88
127
|
nanoAppFilePath: string,
|
|
89
128
|
): Promise<string | undefined> {
|
|
129
|
+
const jsonFilePath = path.resolve(process.cwd(), nanoAppFilePath);
|
|
130
|
+
|
|
90
131
|
try {
|
|
91
132
|
await createNanoAppJsonFile(nanoAppFilePath);
|
|
92
|
-
|
|
93
|
-
|
|
133
|
+
|
|
134
|
+
if (!fs.existsSync(jsonFilePath)) {
|
|
135
|
+
console.error(`Catalog file not found: ${jsonFilePath}`);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
94
139
|
type CatalogApp = { versionDisplayName: string; version: string };
|
|
95
140
|
const raw = fs.readFileSync(jsonFilePath, "utf8");
|
|
96
141
|
const catalog: CatalogApp[] = JSON.parse(raw);
|
package/src/e2e/speculosCI.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
import { SpeculosDevice } from "./speculos";
|
|
8
8
|
import https from "https";
|
|
9
9
|
|
|
10
|
-
const {
|
|
10
|
+
const { GITHUB_TOKEN, SPECULOS_IMAGE_TAG } = process.env;
|
|
11
11
|
const GIT_API_URL = "https://api.github.com/repos/LedgerHQ/actions/actions/";
|
|
12
12
|
const START_WORKFLOW_ID = "workflows/161487603/dispatches";
|
|
13
13
|
const STOP_WORKFLOW_ID = "workflows/161487604/dispatches";
|
|
@@ -152,9 +152,6 @@ function createStartPayload(deviceParams: DeviceParams, runId: string) {
|
|
|
152
152
|
coin_app_version: appVersion,
|
|
153
153
|
device: reverseModelMap[model],
|
|
154
154
|
device_os_version: firmware,
|
|
155
|
-
aws_role: AWS_ROLE,
|
|
156
|
-
cluster: CLUSTER,
|
|
157
|
-
seed: SEED,
|
|
158
155
|
run_id: runId,
|
|
159
156
|
additional_args,
|
|
160
157
|
},
|
|
@@ -192,8 +189,6 @@ export async function releaseSpeculosDeviceCI(runId: string) {
|
|
|
192
189
|
ref: GITHUB_REF,
|
|
193
190
|
inputs: {
|
|
194
191
|
run_id: runId.toString(),
|
|
195
|
-
aws_role: AWS_ROLE,
|
|
196
|
-
cluster: CLUSTER,
|
|
197
192
|
},
|
|
198
193
|
};
|
|
199
194
|
await githubApiRequest({ urlSuffix: STOP_WORKFLOW_ID, data });
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
import { getMainAccount } from "@ledgerhq/coin-framework/account/index";
|
|
25
25
|
import { assignToAccountRaw, assignFromAccountRaw } from "@ledgerhq/coin-algorand/serialization";
|
|
26
26
|
import { initAccount } from "@ledgerhq/coin-algorand/initAccount";
|
|
27
|
+
import { validateAddress } from "../../../bridge/validateAddress";
|
|
27
28
|
|
|
28
29
|
const receive = makeAccountBridgeReceive();
|
|
29
30
|
|
|
@@ -110,6 +111,7 @@ const accountBridge: AccountBridge<AlgorandTransaction, any> = {
|
|
|
110
111
|
signRawOperation,
|
|
111
112
|
broadcast,
|
|
112
113
|
getSerializedAddressParameters,
|
|
114
|
+
validateAddress,
|
|
113
115
|
};
|
|
114
116
|
const currencyBridge: CurrencyBridge = {
|
|
115
117
|
scanAccounts,
|
|
@@ -27,6 +27,7 @@ import cryptoFactory from "@ledgerhq/coin-bitcoin/wallet-btc/crypto/factory";
|
|
|
27
27
|
import { Currency } from "@ledgerhq/coin-bitcoin/wallet-btc/index";
|
|
28
28
|
import { computeDustAmount } from "@ledgerhq/coin-bitcoin/wallet-btc/utils";
|
|
29
29
|
import { getFeeItems } from "./api";
|
|
30
|
+
import { validateAddress } from "../../../bridge/validateAddress";
|
|
30
31
|
|
|
31
32
|
const receive = makeAccountBridgeReceive();
|
|
32
33
|
|
|
@@ -133,6 +134,7 @@ const accountBridge: AccountBridge<Transaction> = {
|
|
|
133
134
|
signRawOperation,
|
|
134
135
|
broadcast,
|
|
135
136
|
getSerializedAddressParameters,
|
|
137
|
+
validateAddress,
|
|
136
138
|
};
|
|
137
139
|
const currencyBridge: CurrencyBridge = {
|
|
138
140
|
scanAccounts,
|
|
@@ -3,6 +3,7 @@ import { createApi } from "@ledgerhq/coin-canton/api/index";
|
|
|
3
3
|
import { Transaction as CantonTransaction, CantonAccount } from "@ledgerhq/coin-canton/types";
|
|
4
4
|
import type { AccountBridge } from "@ledgerhq/types-live";
|
|
5
5
|
import { BigNumber } from "bignumber.js";
|
|
6
|
+
import { validateAddress } from "../../../bridge/validateAddress";
|
|
6
7
|
|
|
7
8
|
// The calls data can be copied to mock-data.ts from the file.
|
|
8
9
|
// This function creates a live API with logging for generating mock data
|
|
@@ -174,6 +175,7 @@ const accountBridge: AccountBridge<CantonTransaction, CantonAccount> = {
|
|
|
174
175
|
},
|
|
175
176
|
broadcast,
|
|
176
177
|
getSerializedAddressParameters,
|
|
178
|
+
validateAddress,
|
|
177
179
|
};
|
|
178
180
|
|
|
179
181
|
const currencyBridge = {
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { useCallback, useState, useEffect } from "react";
|
|
1
|
+
import { useCallback, useState, useEffect, useMemo } from "react";
|
|
2
2
|
import { getCurrencyBridge } from "../../bridge";
|
|
3
|
-
import { CantonCurrencyBridge } from "@ledgerhq/coin-canton/types";
|
|
3
|
+
import { CantonCurrencyBridge, CantonAccount } from "@ledgerhq/coin-canton/types";
|
|
4
|
+
import { isCantonAccount } from "@ledgerhq/coin-canton";
|
|
4
5
|
import { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
|
|
5
|
-
import { Account } from "@ledgerhq/types-live";
|
|
6
|
+
import { Account, AccountLike } from "@ledgerhq/types-live";
|
|
7
|
+
import { getParentAccount } from "@ledgerhq/coin-framework/account/helpers";
|
|
8
|
+
import BigNumber from "bignumber.js";
|
|
6
9
|
|
|
7
10
|
export type UseCantonAcceptOrRejectOfferOptions = {
|
|
8
11
|
currency: CryptoCurrency;
|
|
@@ -92,3 +95,50 @@ export const useTimeRemaining = (expiresAtMicros = 0, isExpired = false): string
|
|
|
92
95
|
|
|
93
96
|
return timeRemaining;
|
|
94
97
|
};
|
|
98
|
+
|
|
99
|
+
type TransferProposal = {
|
|
100
|
+
sender: string;
|
|
101
|
+
amount: string;
|
|
102
|
+
expires_at_micros: number;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
type CantonTokenAccountLike = AccountLike & {
|
|
106
|
+
cantonResources?: { pendingTransferProposals?: TransferProposal[] };
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const hasCantonResources = (
|
|
110
|
+
account: AccountLike,
|
|
111
|
+
): account is CantonAccount | CantonTokenAccountLike => {
|
|
112
|
+
if (account.type === "Account") {
|
|
113
|
+
return isCantonAccount(account);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return "cantonResources" in account && !!account.cantonResources;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Hook to calculate withdrawable balance from expired outgoing offers.
|
|
121
|
+
* Withdrawable balance is the sum of amounts from offers the user sent that have expired.
|
|
122
|
+
*/
|
|
123
|
+
export const useWithdrawableBalance = (account: AccountLike, accounts: Account[]): BigNumber => {
|
|
124
|
+
return useMemo(() => {
|
|
125
|
+
if (!hasCantonResources(account)) return new BigNumber(0);
|
|
126
|
+
|
|
127
|
+
const proposals = account.cantonResources?.pendingTransferProposals ?? [];
|
|
128
|
+
|
|
129
|
+
// For token accounts, use parent account's xpub; for main accounts, use account's xpub
|
|
130
|
+
const parentAccount = getParentAccount(account, accounts);
|
|
131
|
+
const mainAccount = parentAccount ?? account;
|
|
132
|
+
const accountXpub = "xpub" in mainAccount ? (mainAccount.xpub as string) ?? "" : "";
|
|
133
|
+
const currentTime = Date.now();
|
|
134
|
+
|
|
135
|
+
return proposals.reduce((sum, proposal) => {
|
|
136
|
+
const isOutgoing = proposal.sender === accountXpub;
|
|
137
|
+
const isExpired = currentTime > proposal.expires_at_micros / 1000;
|
|
138
|
+
if (isOutgoing && isExpired) {
|
|
139
|
+
return sum.plus(new BigNumber(proposal.amount));
|
|
140
|
+
}
|
|
141
|
+
return sum;
|
|
142
|
+
}, new BigNumber(0));
|
|
143
|
+
}, [account, accounts]);
|
|
144
|
+
};
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
sync,
|
|
31
31
|
makeAccountBridgeReceive,
|
|
32
32
|
} from "../../../bridge/mockHelpers";
|
|
33
|
+
import { validateAddress } from "../../../bridge/validateAddress";
|
|
33
34
|
|
|
34
35
|
const receive = makeAccountBridgeReceive();
|
|
35
36
|
|
|
@@ -172,6 +173,7 @@ const accountBridge: AccountBridge<CardanoTransaction> = {
|
|
|
172
173
|
signRawOperation,
|
|
173
174
|
broadcast,
|
|
174
175
|
getSerializedAddressParameters,
|
|
176
|
+
validateAddress,
|
|
175
177
|
};
|
|
176
178
|
|
|
177
179
|
const currencyBridge: CurrencyBridge = {
|
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
CASPER_MINIMUM_VALID_AMOUNT_MOTES,
|
|
36
36
|
} from "../consts";
|
|
37
37
|
import { getMainAccount } from "../../../account";
|
|
38
|
+
import { validateAddress } from "../../../bridge/validateAddress";
|
|
38
39
|
|
|
39
40
|
const receive = makeAccountBridgeReceive();
|
|
40
41
|
|
|
@@ -172,6 +173,7 @@ const accountBridge: AccountBridge<Transaction> = {
|
|
|
172
173
|
broadcast,
|
|
173
174
|
estimateMaxSpendable,
|
|
174
175
|
getSerializedAddressParameters,
|
|
176
|
+
validateAddress,
|
|
175
177
|
};
|
|
176
178
|
export default {
|
|
177
179
|
currencyBridge,
|
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
sync,
|
|
37
37
|
} from "../../../bridge/mockHelpers";
|
|
38
38
|
import { getCurrencyConfiguration } from "../../../config";
|
|
39
|
+
import { validateAddress } from "../../../bridge/validateAddress";
|
|
39
40
|
|
|
40
41
|
const receive = makeAccountBridgeReceive();
|
|
41
42
|
|
|
@@ -132,6 +133,7 @@ const accountBridge: AccountBridge<Transaction> = {
|
|
|
132
133
|
assignFromAccountRaw,
|
|
133
134
|
assignToAccountRaw,
|
|
134
135
|
getSerializedAddressParameters,
|
|
136
|
+
validateAddress,
|
|
135
137
|
};
|
|
136
138
|
const currencyBridge: CurrencyBridge = {
|
|
137
139
|
scanAccounts,
|
|
@@ -20,6 +20,8 @@ import { getTypedTransaction } from "@ledgerhq/coin-evm/transaction";
|
|
|
20
20
|
import { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
|
|
21
21
|
import { getCurrencyConfiguration } from "../../../config";
|
|
22
22
|
import { EvmConfigInfo, setCoinConfig } from "@ledgerhq/coin-evm/config";
|
|
23
|
+
import { validateAddress } from "../../../bridge/validateAddress";
|
|
24
|
+
|
|
23
25
|
const receive = makeAccountBridgeReceive();
|
|
24
26
|
const defaultGetFees = (_a, t: any) => (t.gasPrice || new BigNumber(0)).times(getGasLimit(t));
|
|
25
27
|
|
|
@@ -135,6 +137,7 @@ const accountBridge: AccountBridge<Transaction> = {
|
|
|
135
137
|
signRawOperation,
|
|
136
138
|
broadcast,
|
|
137
139
|
getSerializedAddressParameters,
|
|
140
|
+
validateAddress,
|
|
138
141
|
};
|
|
139
142
|
const currencyBridge: CurrencyBridge = {
|
|
140
143
|
preload: () => Promise.resolve({}),
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
import { getMainAccount } from "../../../account";
|
|
18
18
|
|
|
19
19
|
import { makeAccountBridgeReceive } from "../../../bridge/mockHelpers";
|
|
20
|
+
import { validateAddress } from "../../../bridge/validateAddress";
|
|
20
21
|
|
|
21
22
|
const receive = makeAccountBridgeReceive();
|
|
22
23
|
|
|
@@ -83,6 +84,7 @@ const accountBridge: AccountBridge<Transaction> = {
|
|
|
83
84
|
signRawOperation,
|
|
84
85
|
broadcast,
|
|
85
86
|
getSerializedAddressParameters,
|
|
87
|
+
validateAddress,
|
|
86
88
|
};
|
|
87
89
|
|
|
88
90
|
const currencyBridge: CurrencyBridge = {
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
} from "@ledgerhq/coin-framework/bridge/jsHelpers";
|
|
20
20
|
import { getMainAccount } from "@ledgerhq/coin-framework/account/index";
|
|
21
21
|
import { assignToAccountRaw, assignFromAccountRaw } from "@ledgerhq/coin-multiversx/serialization";
|
|
22
|
+
import { validateAddress } from "../../../bridge/validateAddress";
|
|
22
23
|
|
|
23
24
|
const receive = makeAccountBridgeReceive();
|
|
24
25
|
|
|
@@ -103,6 +104,7 @@ const accountBridge: AccountBridge<Transaction, any> = {
|
|
|
103
104
|
signRawOperation,
|
|
104
105
|
broadcast,
|
|
105
106
|
getSerializedAddressParameters,
|
|
107
|
+
validateAddress,
|
|
106
108
|
};
|
|
107
109
|
const currencyBridge: CurrencyBridge = {
|
|
108
110
|
scanAccounts,
|
|
@@ -17,6 +17,7 @@ import { getMainAccount } from "@ledgerhq/coin-framework/account/index";
|
|
|
17
17
|
import { getSerializedAddressParameters } from "@ledgerhq/coin-framework/bridge/jsHelpers";
|
|
18
18
|
import { assignToAccountRaw, assignFromAccountRaw } from "@ledgerhq/coin-polkadot/serialization";
|
|
19
19
|
import { hydrate } from "@ledgerhq/coin-polkadot/preload";
|
|
20
|
+
import { validateAddress } from "../../../bridge/validateAddress";
|
|
20
21
|
|
|
21
22
|
const receive = makeAccountBridgeReceive();
|
|
22
23
|
|
|
@@ -102,6 +103,7 @@ const accountBridge: AccountBridge<Transaction> = {
|
|
|
102
103
|
signRawOperation,
|
|
103
104
|
broadcast,
|
|
104
105
|
getSerializedAddressParameters,
|
|
106
|
+
validateAddress,
|
|
105
107
|
};
|
|
106
108
|
|
|
107
109
|
const preload = () => {
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
isInvalidRecipient,
|
|
26
26
|
makeAccountBridgeReceive,
|
|
27
27
|
} from "../../../bridge/mockHelpers";
|
|
28
|
+
import { validateAddress } from "../../../bridge/validateAddress";
|
|
28
29
|
|
|
29
30
|
const receive = makeAccountBridgeReceive();
|
|
30
31
|
|
|
@@ -222,6 +223,7 @@ const accountBridge: AccountBridge<Transaction> = {
|
|
|
222
223
|
broadcast,
|
|
223
224
|
estimateMaxSpendable,
|
|
224
225
|
getSerializedAddressParameters,
|
|
226
|
+
validateAddress,
|
|
225
227
|
};
|
|
226
228
|
export default {
|
|
227
229
|
currencyBridge,
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
updateTransaction,
|
|
30
30
|
} from "@ledgerhq/coin-framework/bridge/jsHelpers";
|
|
31
31
|
import { isAccountDelegating } from "../staking";
|
|
32
|
+
import { validateAddress } from "../../../bridge/validateAddress";
|
|
32
33
|
|
|
33
34
|
const isAccountBalanceSignificant = (a: AccountLike): boolean => a.balance.gt(100);
|
|
34
35
|
|
|
@@ -209,6 +210,7 @@ const accountBridge: AccountBridge<Transaction> = {
|
|
|
209
210
|
signRawOperation,
|
|
210
211
|
broadcast,
|
|
211
212
|
getSerializedAddressParameters,
|
|
213
|
+
validateAddress,
|
|
212
214
|
};
|
|
213
215
|
const currencyBridge: CurrencyBridge = {
|
|
214
216
|
preload: () => Promise.resolve({}),
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
isInvalidRecipient,
|
|
13
13
|
} from "../../../bridge/mockHelpers";
|
|
14
14
|
import { makeAccountBridgeReceive } from "../../../bridge/mockHelpers";
|
|
15
|
+
import { validateAddress } from "../../../bridge/validateAddress";
|
|
15
16
|
|
|
16
17
|
const receive = makeAccountBridgeReceive();
|
|
17
18
|
|
|
@@ -118,6 +119,7 @@ const accountBridge: AccountBridge<Transaction> = {
|
|
|
118
119
|
signRawOperation,
|
|
119
120
|
broadcast,
|
|
120
121
|
getSerializedAddressParameters,
|
|
122
|
+
validateAddress,
|
|
121
123
|
};
|
|
122
124
|
|
|
123
125
|
const currencyBridge: CurrencyBridge = {
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
isInvalidRecipient,
|
|
27
27
|
makeAccountBridgeReceive,
|
|
28
28
|
} from "../../../bridge/mockHelpers";
|
|
29
|
+
import { validateAddress } from "../../../bridge/validateAddress";
|
|
29
30
|
|
|
30
31
|
const receive = makeAccountBridgeReceive();
|
|
31
32
|
const notCreatedAddresses: string[] = [];
|
|
@@ -147,6 +148,7 @@ const accountBridge: AccountBridge<Transaction> = {
|
|
|
147
148
|
signRawOperation,
|
|
148
149
|
broadcast,
|
|
149
150
|
getSerializedAddressParameters,
|
|
151
|
+
validateAddress,
|
|
150
152
|
};
|
|
151
153
|
const currencyBridge: CurrencyBridge = {
|
|
152
154
|
preload: () => Promise.resolve({}),
|
|
@@ -11,11 +11,10 @@ import type {
|
|
|
11
11
|
} from "@ledgerhq/device-management-kit";
|
|
12
12
|
import {
|
|
13
13
|
DeviceActionStatus,
|
|
14
|
-
DeviceDisconnectedWhileSendingError,
|
|
15
14
|
DeviceSessionStateType,
|
|
16
15
|
UserInteractionRequired,
|
|
17
16
|
OutOfMemoryDAError,
|
|
18
|
-
|
|
17
|
+
DeviceModelId,
|
|
19
18
|
} from "@ledgerhq/device-management-kit";
|
|
20
19
|
import type {
|
|
21
20
|
ConnectAppDAOutput,
|
|
@@ -27,12 +26,14 @@ import {
|
|
|
27
26
|
UserRefusedAllowManager,
|
|
28
27
|
UserRefusedOnDevice,
|
|
29
28
|
LatestFirmwareVersionRequired,
|
|
29
|
+
UnsupportedFeatureError,
|
|
30
30
|
} from "@ledgerhq/errors";
|
|
31
31
|
|
|
32
32
|
import type { SkippedAppOp } from "../apps/types";
|
|
33
33
|
import { SkipReason } from "../apps/types";
|
|
34
34
|
import { parseDeviceInfo } from "../deviceSDK/tasks/getDeviceInfo";
|
|
35
35
|
import { ConnectAppEvent } from "./connectApp";
|
|
36
|
+
import { NoSuchAppOnProvider } from "../errors";
|
|
36
37
|
|
|
37
38
|
export class ConnectAppEventMapper {
|
|
38
39
|
private openAppRequested: boolean = false;
|
|
@@ -241,7 +242,8 @@ export class ConnectAppEventMapper {
|
|
|
241
242
|
});
|
|
242
243
|
this.eventSubject.complete();
|
|
243
244
|
} else if (
|
|
244
|
-
|
|
245
|
+
"_tag" in error &&
|
|
246
|
+
error._tag === "UnsupportedFirmwareDAError" &&
|
|
245
247
|
deviceState.sessionStateType !== DeviceSessionStateType.Connected
|
|
246
248
|
) {
|
|
247
249
|
this.eventSubject.error(
|
|
@@ -252,12 +254,34 @@ export class ConnectAppEventMapper {
|
|
|
252
254
|
deviceState.firmwareUpdateContext!.currentFirmware.version,
|
|
253
255
|
}),
|
|
254
256
|
);
|
|
257
|
+
} else if (
|
|
258
|
+
"_tag" in error &&
|
|
259
|
+
error._tag === "UnsupportedApplicationDAError" &&
|
|
260
|
+
deviceState.sessionStateType !== DeviceSessionStateType.Connected
|
|
261
|
+
) {
|
|
262
|
+
if (deviceState.deviceModelId === DeviceModelId.NANO_S) {
|
|
263
|
+
// This will show an error modal with upsell link
|
|
264
|
+
this.eventSubject.error(
|
|
265
|
+
new NoSuchAppOnProvider(`Ledger Nano S does not support this feature`, {
|
|
266
|
+
appName: this.appName,
|
|
267
|
+
}),
|
|
268
|
+
);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
// This will show an error modal with contact support link
|
|
272
|
+
this.eventSubject.error(
|
|
273
|
+
new UnsupportedFeatureError(`App ${this.appName} not supported on this device`, {
|
|
274
|
+
appName: this.appName,
|
|
275
|
+
deviceModelId: deviceState.deviceModelId,
|
|
276
|
+
deviceVersion: deviceState.firmwareVersion?.os,
|
|
277
|
+
}),
|
|
278
|
+
);
|
|
255
279
|
} else if ("_tag" in error && error._tag === "DeviceLockedError") {
|
|
256
280
|
this.eventSubject.next({ type: "lockedDevice" });
|
|
257
281
|
this.eventSubject.complete();
|
|
258
282
|
} else if ("_tag" in error && error._tag === "RefusedByUserDAError") {
|
|
259
283
|
this.eventSubject.error(new UserRefusedAllowManager());
|
|
260
|
-
} else if (error
|
|
284
|
+
} else if ("_tag" in error && error._tag === "DeviceDisconnectedWhileSendingError") {
|
|
261
285
|
this.eventSubject.next({ type: "disconnected", expected: false });
|
|
262
286
|
} else if ("_tag" in error && error._tag === "WebHidSendReportError") {
|
|
263
287
|
this.eventSubject.next({ type: "disconnected", expected: false });
|
|
@@ -11,6 +11,7 @@ export function useLeftAccountsApyModule(
|
|
|
11
11
|
params: AccountModuleParams,
|
|
12
12
|
useAccountData: (params: AccountModuleParams) => AccountDataItem[],
|
|
13
13
|
accountsCountAndApy: CreateAccountsCountAndApy,
|
|
14
|
+
accountsApy: CreateAccountsCountAndApy,
|
|
14
15
|
): Array<NetworkWithCount> {
|
|
15
16
|
const { networks } = params;
|
|
16
17
|
const accountData = useAccountData(params);
|
|
@@ -35,6 +36,11 @@ export function useLeftAccountsApyModule(
|
|
|
35
36
|
value: interestRatePercentageRounded,
|
|
36
37
|
type: interestRate?.type,
|
|
37
38
|
}),
|
|
39
|
+
description: count > 0 ? label : undefined,
|
|
40
|
+
apy: accountsApy({
|
|
41
|
+
value: interestRatePercentageRounded,
|
|
42
|
+
type: interestRate?.type,
|
|
43
|
+
}),
|
|
38
44
|
count,
|
|
39
45
|
};
|
|
40
46
|
});
|