@ledgerhq/live-common 34.54.0-nightly.20251129023709 → 34.54.0-nightly.20251202023925
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/account/index.d.ts +1 -0
- package/lib/account/index.d.ts.map +1 -1
- package/lib/account/index.js +4 -1
- package/lib/account/index.js.map +1 -1
- package/lib/account/recentAddresses.d.ts +10 -0
- package/lib/account/recentAddresses.d.ts.map +1 -0
- package/lib/account/recentAddresses.js +60 -0
- package/lib/account/recentAddresses.js.map +1 -0
- package/lib/e2e/index.d.ts +3 -0
- package/lib/e2e/index.d.ts.map +1 -1
- package/lib/exchange/swap/postSwapState.d.ts.map +1 -1
- package/lib/exchange/swap/postSwapState.js +10 -6
- package/lib/exchange/swap/postSwapState.js.map +1 -1
- package/lib/exchange/swap/types.d.ts +3 -1
- package/lib/exchange/swap/types.d.ts.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/featureFlags/useFeature.d.ts +1 -1
- package/lib/featureFlags/useFeature.d.ts.map +1 -1
- package/lib/wallet-api/Exchange/server.d.ts.map +1 -1
- package/lib/wallet-api/Exchange/server.js +4 -0
- package/lib/wallet-api/Exchange/server.js.map +1 -1
- package/lib-es/account/index.d.ts +1 -0
- package/lib-es/account/index.d.ts.map +1 -1
- package/lib-es/account/index.js +1 -0
- package/lib-es/account/index.js.map +1 -1
- package/lib-es/account/recentAddresses.d.ts +10 -0
- package/lib-es/account/recentAddresses.d.ts.map +1 -0
- package/lib-es/account/recentAddresses.js +55 -0
- package/lib-es/account/recentAddresses.js.map +1 -0
- package/lib-es/e2e/index.d.ts +3 -0
- package/lib-es/e2e/index.d.ts.map +1 -1
- package/lib-es/exchange/swap/postSwapState.d.ts.map +1 -1
- package/lib-es/exchange/swap/postSwapState.js +10 -6
- package/lib-es/exchange/swap/postSwapState.js.map +1 -1
- package/lib-es/exchange/swap/types.d.ts +3 -1
- package/lib-es/exchange/swap/types.d.ts.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/featureFlags/useFeature.d.ts +1 -1
- package/lib-es/featureFlags/useFeature.d.ts.map +1 -1
- package/lib-es/wallet-api/Exchange/server.d.ts.map +1 -1
- package/lib-es/wallet-api/Exchange/server.js +4 -0
- package/lib-es/wallet-api/Exchange/server.js.map +1 -1
- package/package.json +54 -54
- package/src/account/index.ts +6 -0
- package/src/account/recentAddresses.test.ts +104 -0
- package/src/account/recentAddresses.ts +84 -0
- package/src/exchange/swap/postSwapState.ts +10 -5
- package/src/exchange/swap/types.ts +3 -1
- package/src/featureFlags/defaultFeatures.ts +1 -0
- package/src/wallet-api/Exchange/server.ts +5 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { RecentAddressesStore, setupRecentAddressesStore, getRecentAddressesStore } from ".";
|
|
2
|
+
import { RECENT_ADDRESSES_COUNT_LIMIT } from "./recentAddresses";
|
|
3
|
+
|
|
4
|
+
describe("RecentAddressesStore", () => {
|
|
5
|
+
const onAddAddressCompleteMock = jest.fn();
|
|
6
|
+
let store: RecentAddressesStore;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
onAddAddressCompleteMock.mockClear();
|
|
10
|
+
setupRecentAddressesStore({}, onAddAddressCompleteMock);
|
|
11
|
+
store = getRecentAddressesStore();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should add one address and return this only address", async () => {
|
|
15
|
+
const newAddress = "0x66c4371aE8FFeD2ec1c2EBbbcCfb7E494181E1E3";
|
|
16
|
+
await store.addAddress("ethereum", newAddress);
|
|
17
|
+
const addresses = store.getAddresses("ethereum");
|
|
18
|
+
expect(addresses).toEqual([newAddress]);
|
|
19
|
+
expect(onAddAddressCompleteMock).toHaveBeenCalledTimes(1);
|
|
20
|
+
expect(onAddAddressCompleteMock).toHaveBeenCalledWith({ ethereum: [newAddress] });
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should add a second address and return addresses sorted by insertion", async () => {
|
|
24
|
+
const newAddress = "0x66c4371aE8FFeD2ec1c2EBbbcCfb7E494181E1E3";
|
|
25
|
+
await store.addAddress("ethereum", newAddress);
|
|
26
|
+
let addresses = store.getAddresses("ethereum");
|
|
27
|
+
expect(addresses).toEqual([newAddress]);
|
|
28
|
+
expect(onAddAddressCompleteMock).toHaveBeenCalledTimes(1);
|
|
29
|
+
expect(onAddAddressCompleteMock).toHaveBeenCalledWith({ ethereum: [newAddress] });
|
|
30
|
+
|
|
31
|
+
const newAddress2 = "0xB69B37A4Fb4A18b3258f974ff6e9f529AD2647b1";
|
|
32
|
+
await store.addAddress("ethereum", newAddress2);
|
|
33
|
+
addresses = store.getAddresses("ethereum");
|
|
34
|
+
expect(addresses).toEqual([newAddress2, newAddress]);
|
|
35
|
+
expect(onAddAddressCompleteMock).toHaveBeenCalledTimes(2);
|
|
36
|
+
expect(onAddAddressCompleteMock).toHaveBeenCalledWith({ ethereum: [newAddress2, newAddress] });
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("should replace at first place when an address is already saved", async () => {
|
|
40
|
+
const newAddress = "0x66c4371aE8FFeD2ec1c2EBbbcCfb7E494181E1E3";
|
|
41
|
+
await store.addAddress("ethereum", newAddress);
|
|
42
|
+
let addresses = store.getAddresses("ethereum");
|
|
43
|
+
expect(addresses).toEqual([newAddress]);
|
|
44
|
+
expect(onAddAddressCompleteMock).toHaveBeenCalledTimes(1);
|
|
45
|
+
expect(onAddAddressCompleteMock).toHaveBeenCalledWith({ ethereum: [newAddress] });
|
|
46
|
+
|
|
47
|
+
const newAddress2 = "0xB69B37A4Fb4A18b3258f974ff6e9f529AD2647b1";
|
|
48
|
+
await store.addAddress("ethereum", newAddress2);
|
|
49
|
+
addresses = store.getAddresses("ethereum");
|
|
50
|
+
expect(addresses).toEqual([newAddress2, newAddress]);
|
|
51
|
+
expect(onAddAddressCompleteMock).toHaveBeenCalledTimes(2);
|
|
52
|
+
expect(onAddAddressCompleteMock).toHaveBeenCalledWith({ ethereum: [newAddress2, newAddress] });
|
|
53
|
+
|
|
54
|
+
await store.addAddress("ethereum", newAddress);
|
|
55
|
+
addresses = store.getAddresses("ethereum");
|
|
56
|
+
expect(addresses).toEqual([newAddress, newAddress2]);
|
|
57
|
+
expect(onAddAddressCompleteMock).toHaveBeenCalledTimes(3);
|
|
58
|
+
expect(onAddAddressCompleteMock).toHaveBeenCalledWith({ ethereum: [newAddress, newAddress2] });
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("should replace at first place and remove last element when addresses exceed count limit", async () => {
|
|
62
|
+
let expectedAddresses: string[] = [];
|
|
63
|
+
for (let index = 0; index < RECENT_ADDRESSES_COUNT_LIMIT; index++) {
|
|
64
|
+
await store.addAddress("ethereum", `0x66c4371aE8FFeD2ec1c2EBbbcCfb7E494181E1E3${index}`);
|
|
65
|
+
expectedAddresses.unshift(`0x66c4371aE8FFeD2ec1c2EBbbcCfb7E494181E1E3${index}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let addresses = store.getAddresses("ethereum");
|
|
69
|
+
expect(addresses).toEqual(expectedAddresses);
|
|
70
|
+
expect(onAddAddressCompleteMock).toHaveBeenCalledTimes(RECENT_ADDRESSES_COUNT_LIMIT);
|
|
71
|
+
expect(onAddAddressCompleteMock).toHaveBeenCalledWith({ ethereum: expectedAddresses });
|
|
72
|
+
|
|
73
|
+
const newAddress2 = "0xB69B37A4Fb4A18b3258f974ff6e9f529AD2647b1";
|
|
74
|
+
expectedAddresses.splice(expectedAddresses.length - 1, 1);
|
|
75
|
+
expectedAddresses = [newAddress2, ...expectedAddresses];
|
|
76
|
+
|
|
77
|
+
await store.addAddress("ethereum", newAddress2);
|
|
78
|
+
addresses = store.getAddresses("ethereum");
|
|
79
|
+
expect(addresses).toEqual(expectedAddresses);
|
|
80
|
+
expect(onAddAddressCompleteMock).toHaveBeenCalledTimes(RECENT_ADDRESSES_COUNT_LIMIT + 1);
|
|
81
|
+
expect(onAddAddressCompleteMock).toHaveBeenCalledWith({ ethereum: expectedAddresses });
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("should add an address of a different currency", async () => {
|
|
85
|
+
const newAddress = "0x66c4371aE8FFeD2ec1c2EBbbcCfb7E494181E1E3";
|
|
86
|
+
await store.addAddress("ethereum", newAddress);
|
|
87
|
+
|
|
88
|
+
let addresses = store.getAddresses("ethereum");
|
|
89
|
+
expect(addresses).toEqual([newAddress]);
|
|
90
|
+
expect(onAddAddressCompleteMock).toHaveBeenCalledTimes(1);
|
|
91
|
+
expect(onAddAddressCompleteMock).toHaveBeenCalledWith({ ethereum: [newAddress] });
|
|
92
|
+
|
|
93
|
+
const newAddress2 = "bc1pxlmrudqyq8qd8pfsc4mpmlaw56x6vtcr9m8nvp8kj3gckefc4kmqhkg4l7";
|
|
94
|
+
await store.addAddress("bitcoin", newAddress2);
|
|
95
|
+
|
|
96
|
+
addresses = store.getAddresses("bitcoin");
|
|
97
|
+
expect(addresses).toEqual([newAddress2]);
|
|
98
|
+
expect(onAddAddressCompleteMock).toHaveBeenCalledTimes(2);
|
|
99
|
+
expect(onAddAddressCompleteMock).toHaveBeenCalledWith({
|
|
100
|
+
ethereum: [newAddress],
|
|
101
|
+
bitcoin: [newAddress2],
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
});
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
export const RECENT_ADDRESSES_COUNT_LIMIT = 12;
|
|
2
|
+
|
|
3
|
+
export type RecentAddressesCache = Record<string, string[]>;
|
|
4
|
+
|
|
5
|
+
export interface RecentAddressesStore {
|
|
6
|
+
addAddress(currency: string, address: string): void;
|
|
7
|
+
syncAddresses(cache: RecentAddressesCache): void;
|
|
8
|
+
getAddresses(currency: string): string[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
type CallbackMode = "triggerCallback" | "skipCallback";
|
|
12
|
+
|
|
13
|
+
let recentAddressesStore: RecentAddressesStore | null = null;
|
|
14
|
+
|
|
15
|
+
export function getRecentAddressesStore(): RecentAddressesStore {
|
|
16
|
+
if (recentAddressesStore === null) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
"Recent addresses store instance is null, please call function setupRecentAddressesStore in application initialization",
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
return recentAddressesStore;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function setupRecentAddressesStore(
|
|
25
|
+
addressesByCurrency: RecentAddressesCache,
|
|
26
|
+
onAddAddressComplete: (addressesByCurrency: RecentAddressesCache) => void,
|
|
27
|
+
): void {
|
|
28
|
+
recentAddressesStore = new RecentAddressesStoreImpl(addressesByCurrency, onAddAddressComplete);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
class RecentAddressesStoreImpl implements RecentAddressesStore {
|
|
32
|
+
private addressesByCurrency: RecentAddressesCache = {};
|
|
33
|
+
private readonly onAddAddressComplete: (addressesByCurrency: Record<string, string[]>) => void;
|
|
34
|
+
|
|
35
|
+
constructor(
|
|
36
|
+
addressesByCurrency: RecentAddressesCache,
|
|
37
|
+
onAddAddressComplete: (addressesByCurrency: RecentAddressesCache) => void,
|
|
38
|
+
) {
|
|
39
|
+
this.addressesByCurrency = { ...addressesByCurrency };
|
|
40
|
+
this.onAddAddressComplete = onAddAddressComplete;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
addAddress(currency: string, address: string): void {
|
|
44
|
+
this.addAddressToCache(currency, address, "triggerCallback");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
syncAddresses(cache: RecentAddressesCache): void {
|
|
48
|
+
const previousAddresses = { ...this.addressesByCurrency };
|
|
49
|
+
this.addressesByCurrency = { ...cache };
|
|
50
|
+
for (const currency in previousAddresses) {
|
|
51
|
+
for (const address of previousAddresses[currency]) {
|
|
52
|
+
this.addAddressToCache(currency, address, "skipCallback");
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
this.onAddAddressComplete(this.addressesByCurrency);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
getAddresses(currency: string): string[] {
|
|
60
|
+
const addresses = this.addressesByCurrency[currency];
|
|
61
|
+
return addresses ?? [];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private addAddressToCache(currency: string, address: string, callbackMode: CallbackMode): void {
|
|
65
|
+
if (!this.addressesByCurrency[currency]) {
|
|
66
|
+
this.addressesByCurrency[currency] = [];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const addresses = this.addressesByCurrency[currency];
|
|
70
|
+
const addressIndex = addresses.indexOf(address);
|
|
71
|
+
if (addressIndex !== -1) {
|
|
72
|
+
addresses.splice(addressIndex, 1);
|
|
73
|
+
} else if (addresses.length >= RECENT_ADDRESSES_COUNT_LIMIT) {
|
|
74
|
+
addresses.pop();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
addresses.unshift(address);
|
|
78
|
+
this.addressesByCurrency[currency] = [...addresses];
|
|
79
|
+
|
|
80
|
+
if (callbackMode === "triggerCallback") {
|
|
81
|
+
this.onAddAddressComplete(this.addressesByCurrency);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -106,6 +106,7 @@ export const postSwapCancelled: PostSwapCancelled = async ({
|
|
|
106
106
|
seedIdTo,
|
|
107
107
|
refundAddress,
|
|
108
108
|
payoutAddress,
|
|
109
|
+
data,
|
|
109
110
|
...rest
|
|
110
111
|
}) => {
|
|
111
112
|
if (isIntegrationTestEnv()) return mockPostSwapCancelled({ provider, swapId, ...rest });
|
|
@@ -138,7 +139,8 @@ export const postSwapCancelled: PostSwapCancelled = async ({
|
|
|
138
139
|
|
|
139
140
|
const shouldIncludeAddresses =
|
|
140
141
|
rest.statusCode === "WrongDeviceForAccountPayout" ||
|
|
141
|
-
rest.statusCode === "WrongDeviceForAccountRefund"
|
|
142
|
+
rest.statusCode === "WrongDeviceForAccountRefund" ||
|
|
143
|
+
rest.statusCode === "FeeNotLoaded";
|
|
142
144
|
|
|
143
145
|
const requestData = {
|
|
144
146
|
provider,
|
|
@@ -147,11 +149,14 @@ export const postSwapCancelled: PostSwapCancelled = async ({
|
|
|
147
149
|
swapIntentWithoutProvider,
|
|
148
150
|
payloadAddressMatchAccountAddress,
|
|
149
151
|
fromAmount,
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
152
|
+
...(shouldIncludeAddresses && {
|
|
153
|
+
fromAccountAddress,
|
|
154
|
+
toAccountAddress,
|
|
155
|
+
payloadRefundAddress: refundAddress,
|
|
156
|
+
payloadPayoutAddress: payoutAddress,
|
|
157
|
+
}),
|
|
154
158
|
maybeSeedMatch: seedIdFrom === seedIdTo, // Only true if both accounts are from the same seed and from the same chain type
|
|
159
|
+
data,
|
|
155
160
|
...rest,
|
|
156
161
|
};
|
|
157
162
|
|
|
@@ -214,7 +214,9 @@ export type SwapStateAcceptedRequest = SwapStateRequest & {
|
|
|
214
214
|
transactionId: string;
|
|
215
215
|
};
|
|
216
216
|
|
|
217
|
-
export type SwapStateCancelledRequest = SwapStateRequest
|
|
217
|
+
export type SwapStateCancelledRequest = SwapStateRequest & {
|
|
218
|
+
data?: string;
|
|
219
|
+
};
|
|
218
220
|
|
|
219
221
|
export type PostSwapAccepted = (arg0: SwapStateAcceptedRequest) => Promise<null>;
|
|
220
222
|
|
|
@@ -53,6 +53,8 @@ import { getSwapStepFromError } from "../../exchange/error";
|
|
|
53
53
|
import { postSwapCancelled } from "../../exchange/swap";
|
|
54
54
|
import { DeviceModelId } from "@ledgerhq/types-devices";
|
|
55
55
|
import { setBroadcastTransaction } from "../../exchange/swap/setBroadcastTransaction";
|
|
56
|
+
import { Transaction as EvmTransaction } from "@ledgerhq/coin-evm/types/index";
|
|
57
|
+
import { padHexString } from "@ledgerhq/hw-app-eth";
|
|
56
58
|
|
|
57
59
|
export { ExchangeType };
|
|
58
60
|
|
|
@@ -599,6 +601,9 @@ export const handlers = ({
|
|
|
599
601
|
fromAmount,
|
|
600
602
|
seedIdFrom: mainFromAccount.seedIdentifier,
|
|
601
603
|
seedIdTo: toParentAccount?.seedIdentifier || (toAccount as Account)?.seedIdentifier,
|
|
604
|
+
data: (transaction as EvmTransaction).data
|
|
605
|
+
? `0x${padHexString((transaction as EvmTransaction).data?.toString("hex") || "")}`
|
|
606
|
+
: "0x",
|
|
602
607
|
});
|
|
603
608
|
|
|
604
609
|
reject(error);
|