@ledgerhq/live-common 34.54.0-nightly.20251205111238 → 34.54.0-nightly.20251209023841
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/serialization.js +1 -1
- package/lib/account/serialization.js.map +1 -1
- package/lib/account/support.js +1 -1
- package/lib/account/support.js.map +1 -1
- package/lib/domain/getTokensWithFunds.d.ts +7 -1
- package/lib/domain/getTokensWithFunds.d.ts.map +1 -1
- package/lib/domain/getTokensWithFunds.js +15 -4
- package/lib/domain/getTokensWithFunds.js.map +1 -1
- package/lib/domain/getTotalStakeableAssets.d.ts +10 -0
- package/lib/domain/getTotalStakeableAssets.d.ts.map +1 -0
- package/lib/domain/getTotalStakeableAssets.js +35 -0
- package/lib/domain/getTotalStakeableAssets.js.map +1 -0
- package/lib/e2e/index.d.ts +6 -0
- package/lib/e2e/index.d.ts.map +1 -1
- package/lib/exchange/swap/api/v5/fetchCurrencyFrom.js +1 -1
- package/lib/exchange/swap/api/v5/fetchCurrencyFrom.js.map +1 -1
- package/lib/featureFlags/defaultFeatures.d.ts.map +1 -1
- package/lib/featureFlags/defaultFeatures.js +2 -0
- package/lib/featureFlags/defaultFeatures.js.map +1 -1
- package/lib/featureFlags/firebaseFeatureFlags.js +1 -1
- package/lib/featureFlags/firebaseFeatureFlags.js.map +1 -1
- package/lib/featureFlags/useFeature.d.ts +1 -1
- package/lib/featureFlags/useFeature.d.ts.map +1 -1
- package/lib/featureFlags/useHasOverriddenFeatureFlags.js +1 -1
- package/lib/featureFlags/useHasOverriddenFeatureFlags.js.map +1 -1
- package/lib/hw/getBitcoinLikeInfo.js +1 -1
- package/lib/hw/getBitcoinLikeInfo.js.map +1 -1
- package/lib/mock/account.js +1 -1
- package/lib/mock/account.js.map +1 -1
- package/lib/postOnboarding/reducer.d.ts +2 -0
- package/lib/postOnboarding/reducer.d.ts.map +1 -1
- package/lib/wallet-api/Exchange/server.d.ts.map +1 -1
- package/lib/wallet-api/Exchange/server.js +3 -1
- package/lib/wallet-api/Exchange/server.js.map +1 -1
- package/lib/wallet-api/Exchange/tracking.d.ts +7 -6
- package/lib/wallet-api/Exchange/tracking.d.ts.map +1 -1
- package/lib/wallet-api/Exchange/tracking.js +52 -13
- package/lib/wallet-api/Exchange/tracking.js.map +1 -1
- package/lib/wallet-api/logic.d.ts +1 -1
- package/lib/wallet-api/logic.d.ts.map +1 -1
- package/lib/wallet-api/logic.js +5 -5
- package/lib/wallet-api/logic.js.map +1 -1
- package/lib/wallet-api/react.d.ts.map +1 -1
- package/lib/wallet-api/react.js +9 -6
- package/lib/wallet-api/react.js.map +1 -1
- package/lib/wallet-api/tracking.d.ts +5 -5
- package/lib/wallet-api/tracking.d.ts.map +1 -1
- package/lib/wallet-api/tracking.js +30 -10
- package/lib/wallet-api/tracking.js.map +1 -1
- package/lib/wallet-api/useDappLogic.d.ts.map +1 -1
- package/lib/wallet-api/useDappLogic.js +31 -20
- package/lib/wallet-api/useDappLogic.js.map +1 -1
- package/lib/wallet-api/utils/extractDappURLFromManifest.js +3 -3
- package/lib/wallet-api/utils/extractDappURLFromManifest.js.map +1 -1
- package/lib/wallet-api/utils/extractURLFromManifest.js +1 -1
- package/lib/wallet-api/utils/extractURLFromManifest.js.map +1 -1
- package/lib-es/account/serialization.js +1 -1
- package/lib-es/account/serialization.js.map +1 -1
- package/lib-es/account/support.js +1 -1
- package/lib-es/account/support.js.map +1 -1
- package/lib-es/domain/getTokensWithFunds.d.ts +7 -1
- package/lib-es/domain/getTokensWithFunds.d.ts.map +1 -1
- package/lib-es/domain/getTokensWithFunds.js +13 -3
- package/lib-es/domain/getTokensWithFunds.js.map +1 -1
- package/lib-es/domain/getTotalStakeableAssets.d.ts +10 -0
- package/lib-es/domain/getTotalStakeableAssets.d.ts.map +1 -0
- package/lib-es/domain/getTotalStakeableAssets.js +31 -0
- package/lib-es/domain/getTotalStakeableAssets.js.map +1 -0
- package/lib-es/e2e/index.d.ts +6 -0
- package/lib-es/e2e/index.d.ts.map +1 -1
- package/lib-es/exchange/swap/api/v5/fetchCurrencyFrom.js +1 -1
- package/lib-es/exchange/swap/api/v5/fetchCurrencyFrom.js.map +1 -1
- package/lib-es/featureFlags/defaultFeatures.d.ts.map +1 -1
- package/lib-es/featureFlags/defaultFeatures.js +2 -0
- package/lib-es/featureFlags/defaultFeatures.js.map +1 -1
- package/lib-es/featureFlags/firebaseFeatureFlags.js +1 -1
- package/lib-es/featureFlags/firebaseFeatureFlags.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/featureFlags/useHasOverriddenFeatureFlags.js +1 -1
- package/lib-es/featureFlags/useHasOverriddenFeatureFlags.js.map +1 -1
- package/lib-es/hw/getBitcoinLikeInfo.js +1 -1
- package/lib-es/hw/getBitcoinLikeInfo.js.map +1 -1
- package/lib-es/mock/account.js +1 -1
- package/lib-es/mock/account.js.map +1 -1
- package/lib-es/postOnboarding/reducer.d.ts +2 -0
- package/lib-es/postOnboarding/reducer.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 +3 -1
- package/lib-es/wallet-api/Exchange/server.js.map +1 -1
- package/lib-es/wallet-api/Exchange/tracking.d.ts +7 -6
- package/lib-es/wallet-api/Exchange/tracking.d.ts.map +1 -1
- package/lib-es/wallet-api/Exchange/tracking.js +52 -13
- package/lib-es/wallet-api/Exchange/tracking.js.map +1 -1
- package/lib-es/wallet-api/logic.d.ts +1 -1
- package/lib-es/wallet-api/logic.d.ts.map +1 -1
- package/lib-es/wallet-api/logic.js +5 -5
- package/lib-es/wallet-api/logic.js.map +1 -1
- package/lib-es/wallet-api/react.d.ts.map +1 -1
- package/lib-es/wallet-api/react.js +9 -6
- package/lib-es/wallet-api/react.js.map +1 -1
- package/lib-es/wallet-api/tracking.d.ts +5 -5
- package/lib-es/wallet-api/tracking.d.ts.map +1 -1
- package/lib-es/wallet-api/tracking.js +30 -10
- package/lib-es/wallet-api/tracking.js.map +1 -1
- package/lib-es/wallet-api/useDappLogic.d.ts.map +1 -1
- package/lib-es/wallet-api/useDappLogic.js +31 -20
- package/lib-es/wallet-api/useDappLogic.js.map +1 -1
- package/lib-es/wallet-api/utils/extractDappURLFromManifest.js +3 -3
- package/lib-es/wallet-api/utils/extractDappURLFromManifest.js.map +1 -1
- package/lib-es/wallet-api/utils/extractURLFromManifest.js +1 -1
- package/lib-es/wallet-api/utils/extractURLFromManifest.js.map +1 -1
- package/package.json +76 -76
- package/src/account/serialization.ts +1 -1
- package/src/account/support.ts +1 -1
- package/src/domain/getTokensWithFunds.ts +18 -5
- package/src/domain/getTotalStakeableAssets.test.ts +267 -0
- package/src/domain/getTotalStakeableAssets.ts +47 -0
- package/src/exchange/swap/api/v5/fetchCurrencyFrom.ts +1 -1
- package/src/featureFlags/defaultFeatures.ts +2 -0
- package/src/featureFlags/firebaseFeatureFlags.ts +1 -1
- package/src/featureFlags/useHasOverriddenFeatureFlags.ts +1 -1
- package/src/hw/getBitcoinLikeInfo.ts +1 -1
- package/src/mock/account.ts +1 -1
- package/src/wallet-api/Exchange/server.ts +3 -0
- package/src/wallet-api/Exchange/tracking.ts +56 -13
- package/src/wallet-api/logic.ts +5 -4
- package/src/wallet-api/react.ts +10 -5
- package/src/wallet-api/tracking.ts +30 -10
- package/src/wallet-api/useDappLogic.ts +32 -20
- package/src/wallet-api/utils/extractDappURLFromManifest.ts +3 -3
- package/src/wallet-api/utils/extractURLFromManifest.ts +1 -1
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { genAccount } from "@ledgerhq/coin-framework/lib/mocks/account";
|
|
2
|
+
import { getCryptoCurrencyById } from "../currencies/index";
|
|
3
|
+
import { Account } from "@ledgerhq/types-live";
|
|
4
|
+
import type { TokenCurrency } from "@ledgerhq/types-cryptoassets";
|
|
5
|
+
import BigNumber from "bignumber.js";
|
|
6
|
+
import { getTotalStakeableAssets } from "./getTotalStakeableAssets";
|
|
7
|
+
import { setupMockCryptoAssetsStore } from "@ledgerhq/cryptoassets/cal-client/test-helpers";
|
|
8
|
+
|
|
9
|
+
// Setup mock store for unit tests
|
|
10
|
+
setupMockCryptoAssetsStore();
|
|
11
|
+
|
|
12
|
+
const ETH = getCryptoCurrencyById("ethereum");
|
|
13
|
+
const BTC = getCryptoCurrencyById("bitcoin");
|
|
14
|
+
|
|
15
|
+
// Create mock tokens for tests
|
|
16
|
+
const ZRX_TOKEN: TokenCurrency = {
|
|
17
|
+
type: "TokenCurrency",
|
|
18
|
+
id: "ethereum/erc20/0x_project",
|
|
19
|
+
contractAddress: "0xE41d2489571d322189246DaFA5ebDe1F4699F498",
|
|
20
|
+
parentCurrency: ETH,
|
|
21
|
+
tokenType: "erc20",
|
|
22
|
+
name: "0x Project",
|
|
23
|
+
ticker: "ZRX",
|
|
24
|
+
delisted: false,
|
|
25
|
+
disableCountervalue: false,
|
|
26
|
+
units: [{ name: "ZRX", code: "ZRX", magnitude: 18 }],
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const REP_TOKEN: TokenCurrency = {
|
|
30
|
+
type: "TokenCurrency",
|
|
31
|
+
id: "ethereum/erc20/augur",
|
|
32
|
+
contractAddress: "0x1985365e9f78359a9B6AD760e32412f4a445E862",
|
|
33
|
+
parentCurrency: ETH,
|
|
34
|
+
tokenType: "erc20",
|
|
35
|
+
name: "Augur",
|
|
36
|
+
ticker: "REP",
|
|
37
|
+
delisted: false,
|
|
38
|
+
disableCountervalue: false,
|
|
39
|
+
units: [{ name: "REP", code: "REP", magnitude: 18 }],
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const mockedAccounts: Account[] = [
|
|
43
|
+
genAccount("mocked-account-1", {
|
|
44
|
+
currency: ETH,
|
|
45
|
+
tokensData: [ZRX_TOKEN, REP_TOKEN],
|
|
46
|
+
}),
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
describe("getTotalStakeableAssets", () => {
|
|
50
|
+
it("should return empty Set if no accounts", () => {
|
|
51
|
+
const result = getTotalStakeableAssets([], [], []);
|
|
52
|
+
expect(result.combinedIds).toBeInstanceOf(Set);
|
|
53
|
+
expect(result.combinedIds.size).toBe(0);
|
|
54
|
+
expect(result.stakeableAssets).toEqual([]);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("should return empty Set if accounts is null", () => {
|
|
58
|
+
const result = getTotalStakeableAssets(null, [], []);
|
|
59
|
+
expect(result.combinedIds).toBeInstanceOf(Set);
|
|
60
|
+
expect(result.combinedIds.size).toBe(0);
|
|
61
|
+
expect(result.stakeableAssets).toEqual([]);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("should return empty Set if accounts is undefined", () => {
|
|
65
|
+
const result = getTotalStakeableAssets(undefined, [], []);
|
|
66
|
+
expect(result.combinedIds).toBeInstanceOf(Set);
|
|
67
|
+
expect(result.combinedIds.size).toBe(0);
|
|
68
|
+
expect(result.stakeableAssets).toEqual([]);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("should return empty Set if no staking currencies enabled", () => {
|
|
72
|
+
const result = getTotalStakeableAssets(mockedAccounts, [], []);
|
|
73
|
+
expect(result.combinedIds).toBeInstanceOf(Set);
|
|
74
|
+
expect(result.combinedIds.size).toBe(0);
|
|
75
|
+
expect(result.stakeableAssets).toEqual([]);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("should return Set with matching currency ID when staking currency is enabled", () => {
|
|
79
|
+
const account = mockedAccounts[0];
|
|
80
|
+
const stakingCurrenciesEnabled = [ETH.id]; // "ethereum"
|
|
81
|
+
|
|
82
|
+
expect(account.balance).toBeTruthy();
|
|
83
|
+
expect(account.balance instanceof BigNumber).toBe(true);
|
|
84
|
+
expect(account.balance.gt(0)).toBe(true);
|
|
85
|
+
|
|
86
|
+
const result = getTotalStakeableAssets([account], stakingCurrenciesEnabled, []);
|
|
87
|
+
|
|
88
|
+
expect(result.combinedIds).toBeInstanceOf(Set);
|
|
89
|
+
expect(result.combinedIds.size).toBe(1);
|
|
90
|
+
expect(result.combinedIds.has(ETH.id)).toBe(true);
|
|
91
|
+
expect(result.stakeableAssets.length).toBe(1);
|
|
92
|
+
expect(result.stakeableAssets[0]).toEqual({
|
|
93
|
+
ticker: ETH.ticker,
|
|
94
|
+
networkName: ETH.name,
|
|
95
|
+
id: ETH.id,
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("should return Set with matching token IDs when staking tokens are enabled", () => {
|
|
100
|
+
const account = mockedAccounts[0];
|
|
101
|
+
const stakingCurrenciesEnabled = [ZRX_TOKEN.id, REP_TOKEN.id];
|
|
102
|
+
|
|
103
|
+
expect(account.subAccounts).toBeDefined();
|
|
104
|
+
expect(account.subAccounts?.length).toBe(2);
|
|
105
|
+
|
|
106
|
+
const result = getTotalStakeableAssets([account], stakingCurrenciesEnabled, []);
|
|
107
|
+
|
|
108
|
+
expect(result.combinedIds).toBeInstanceOf(Set);
|
|
109
|
+
expect(result.combinedIds.size).toBe(2);
|
|
110
|
+
expect(result.combinedIds.has(ZRX_TOKEN.id)).toBe(true);
|
|
111
|
+
expect(result.combinedIds.has(REP_TOKEN.id)).toBe(true);
|
|
112
|
+
expect(result.stakeableAssets.length).toBe(2);
|
|
113
|
+
expect(result.stakeableAssets).toEqual(
|
|
114
|
+
expect.arrayContaining([
|
|
115
|
+
expect.objectContaining({ id: ZRX_TOKEN.id, ticker: ZRX_TOKEN.ticker }),
|
|
116
|
+
expect.objectContaining({ id: REP_TOKEN.id, ticker: REP_TOKEN.ticker }),
|
|
117
|
+
]),
|
|
118
|
+
);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("should return Set with both currency and token IDs when both are enabled", () => {
|
|
122
|
+
const account = mockedAccounts[0];
|
|
123
|
+
const stakingCurrenciesEnabled = [ETH.id, ZRX_TOKEN.id, REP_TOKEN.id];
|
|
124
|
+
|
|
125
|
+
const result = getTotalStakeableAssets([account], stakingCurrenciesEnabled, []);
|
|
126
|
+
|
|
127
|
+
expect(result.combinedIds).toBeInstanceOf(Set);
|
|
128
|
+
expect(result.combinedIds.size).toBe(3);
|
|
129
|
+
expect(result.combinedIds.has(ETH.id)).toBe(true);
|
|
130
|
+
expect(result.combinedIds.has(ZRX_TOKEN.id)).toBe(true);
|
|
131
|
+
expect(result.combinedIds.has(REP_TOKEN.id)).toBe(true);
|
|
132
|
+
expect(result.stakeableAssets.length).toBe(3);
|
|
133
|
+
expect(result.stakeableAssets).toEqual(
|
|
134
|
+
expect.arrayContaining([
|
|
135
|
+
expect.objectContaining({ id: ETH.id, ticker: ETH.ticker }),
|
|
136
|
+
expect.objectContaining({ id: ZRX_TOKEN.id, ticker: ZRX_TOKEN.ticker }),
|
|
137
|
+
expect.objectContaining({ id: REP_TOKEN.id, ticker: REP_TOKEN.ticker }),
|
|
138
|
+
]),
|
|
139
|
+
);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("should filter out currencies without funds", () => {
|
|
143
|
+
const account = mockedAccounts[0];
|
|
144
|
+
const accountWithZeroBalance = { ...account, balance: new BigNumber(0) };
|
|
145
|
+
const stakingCurrenciesEnabled = [ETH.id];
|
|
146
|
+
|
|
147
|
+
const result = getTotalStakeableAssets([accountWithZeroBalance], stakingCurrenciesEnabled, []);
|
|
148
|
+
|
|
149
|
+
expect(result.combinedIds).toBeInstanceOf(Set);
|
|
150
|
+
expect(result.combinedIds.size).toBe(0);
|
|
151
|
+
expect(result.stakeableAssets).toEqual([]);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("should filter out tokens without funds", () => {
|
|
155
|
+
const account = mockedAccounts[0];
|
|
156
|
+
const [zrxAccount, repAccount] = account.subAccounts || [];
|
|
157
|
+
const emptyRepAccount = { ...repAccount, balance: new BigNumber(0) };
|
|
158
|
+
const accountWithEmptyToken = { ...account, subAccounts: [zrxAccount, emptyRepAccount] };
|
|
159
|
+
const stakingCurrenciesEnabled = [ZRX_TOKEN.id, REP_TOKEN.id];
|
|
160
|
+
|
|
161
|
+
const result = getTotalStakeableAssets([accountWithEmptyToken], stakingCurrenciesEnabled, []);
|
|
162
|
+
|
|
163
|
+
expect(result.combinedIds).toBeInstanceOf(Set);
|
|
164
|
+
expect(result.combinedIds.size).toBe(1);
|
|
165
|
+
expect(result.combinedIds.has(ZRX_TOKEN.id)).toBe(true);
|
|
166
|
+
expect(result.combinedIds.has(REP_TOKEN.id)).toBe(false);
|
|
167
|
+
expect(result.stakeableAssets.length).toBe(1);
|
|
168
|
+
expect(result.stakeableAssets[0]).toEqual(
|
|
169
|
+
expect.objectContaining({ id: ZRX_TOKEN.id, ticker: ZRX_TOKEN.ticker }),
|
|
170
|
+
);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it("should include partner staking currencies enabled", () => {
|
|
174
|
+
const account = mockedAccounts[0];
|
|
175
|
+
const stakingCurrenciesEnabled = [ETH.id];
|
|
176
|
+
const partnerStakingCurrenciesEnabled = [ZRX_TOKEN.id];
|
|
177
|
+
|
|
178
|
+
const result = getTotalStakeableAssets(
|
|
179
|
+
[account],
|
|
180
|
+
stakingCurrenciesEnabled,
|
|
181
|
+
partnerStakingCurrenciesEnabled,
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
expect(result.combinedIds).toBeInstanceOf(Set);
|
|
185
|
+
expect(result.combinedIds.size).toBe(2);
|
|
186
|
+
expect(result.combinedIds.has(ETH.id)).toBe(true);
|
|
187
|
+
expect(result.combinedIds.has(ZRX_TOKEN.id)).toBe(true);
|
|
188
|
+
expect(result.stakeableAssets.length).toBe(2);
|
|
189
|
+
expect(result.stakeableAssets).toEqual(
|
|
190
|
+
expect.arrayContaining([
|
|
191
|
+
expect.objectContaining({ id: ETH.id, ticker: ETH.ticker }),
|
|
192
|
+
expect.objectContaining({ id: ZRX_TOKEN.id, ticker: ZRX_TOKEN.ticker }),
|
|
193
|
+
]),
|
|
194
|
+
);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("should deduplicate IDs when same currency appears in both lists", () => {
|
|
198
|
+
const account = mockedAccounts[0];
|
|
199
|
+
const stakingCurrenciesEnabled = [ETH.id];
|
|
200
|
+
const partnerStakingCurrenciesEnabled = [ETH.id]; // Same currency
|
|
201
|
+
|
|
202
|
+
const result = getTotalStakeableAssets(
|
|
203
|
+
[account],
|
|
204
|
+
stakingCurrenciesEnabled,
|
|
205
|
+
partnerStakingCurrenciesEnabled,
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
expect(result.combinedIds).toBeInstanceOf(Set);
|
|
209
|
+
expect(result.combinedIds.size).toBe(1);
|
|
210
|
+
expect(result.combinedIds.has(ETH.id)).toBe(true);
|
|
211
|
+
expect(result.stakeableAssets.length).toBe(1);
|
|
212
|
+
expect(result.stakeableAssets[0]).toEqual({
|
|
213
|
+
ticker: ETH.ticker,
|
|
214
|
+
networkName: ETH.name,
|
|
215
|
+
id: ETH.id,
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it("should handle multiple accounts with different currencies", () => {
|
|
220
|
+
const ethAccount = mockedAccounts[0];
|
|
221
|
+
const btcAccount = genAccount("mocked-account-2", {
|
|
222
|
+
currency: BTC,
|
|
223
|
+
});
|
|
224
|
+
const accounts = [ethAccount, btcAccount];
|
|
225
|
+
const stakingCurrenciesEnabled = [ETH.id, BTC.id];
|
|
226
|
+
|
|
227
|
+
const result = getTotalStakeableAssets(accounts, stakingCurrenciesEnabled, []);
|
|
228
|
+
|
|
229
|
+
expect(result.combinedIds).toBeInstanceOf(Set);
|
|
230
|
+
expect(result.combinedIds.size).toBe(2);
|
|
231
|
+
expect(result.combinedIds.has(ETH.id)).toBe(true);
|
|
232
|
+
expect(result.combinedIds.has(BTC.id)).toBe(true);
|
|
233
|
+
expect(result.stakeableAssets.length).toBe(2);
|
|
234
|
+
expect(result.stakeableAssets).toEqual(
|
|
235
|
+
expect.arrayContaining([
|
|
236
|
+
expect.objectContaining({ id: ETH.id, ticker: ETH.ticker }),
|
|
237
|
+
expect.objectContaining({ id: BTC.id, ticker: BTC.ticker }),
|
|
238
|
+
]),
|
|
239
|
+
);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it("should only include IDs that match staking currencies enabled", () => {
|
|
243
|
+
const account = mockedAccounts[0];
|
|
244
|
+
const stakingCurrenciesEnabled = [ZRX_TOKEN.id]; // Only ZRX enabled, not ETH or REP
|
|
245
|
+
|
|
246
|
+
const result = getTotalStakeableAssets([account], stakingCurrenciesEnabled, []);
|
|
247
|
+
|
|
248
|
+
expect(result.combinedIds).toBeInstanceOf(Set);
|
|
249
|
+
expect(result.combinedIds.size).toBe(1);
|
|
250
|
+
expect(result.combinedIds.has(ZRX_TOKEN.id)).toBe(true);
|
|
251
|
+
expect(result.combinedIds.has(ETH.id)).toBe(false);
|
|
252
|
+
expect(result.combinedIds.has(REP_TOKEN.id)).toBe(false);
|
|
253
|
+
expect(result.stakeableAssets.length).toBe(1);
|
|
254
|
+
expect(result.stakeableAssets[0]).toEqual(
|
|
255
|
+
expect.objectContaining({ id: ZRX_TOKEN.id, ticker: ZRX_TOKEN.ticker }),
|
|
256
|
+
);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it("should handle empty arrays for staking currencies", () => {
|
|
260
|
+
const account = mockedAccounts[0];
|
|
261
|
+
const result = getTotalStakeableAssets([account], [], []);
|
|
262
|
+
|
|
263
|
+
expect(result.combinedIds).toBeInstanceOf(Set);
|
|
264
|
+
expect(result.combinedIds.size).toBe(0);
|
|
265
|
+
expect(result.stakeableAssets).toEqual([]);
|
|
266
|
+
});
|
|
267
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { getTokensWithFundsMap } from "./getTokensWithFunds";
|
|
2
|
+
import { Account } from "@ledgerhq/types-live";
|
|
3
|
+
|
|
4
|
+
export function getTotalStakeableAssets(
|
|
5
|
+
accounts: Account[] | null | undefined,
|
|
6
|
+
stakingCurrenciesEnabled: string[],
|
|
7
|
+
partnerStakingCurrenciesEnabled: string[],
|
|
8
|
+
): {
|
|
9
|
+
combinedIds: Set<string>;
|
|
10
|
+
stakeableAssets: { ticker: string; networkName: string; id: string }[];
|
|
11
|
+
} {
|
|
12
|
+
if (!accounts) return { combinedIds: new Set<string>(), stakeableAssets: [] };
|
|
13
|
+
|
|
14
|
+
const accountsWithFundsCurrencies = accounts
|
|
15
|
+
.filter(account => account?.balance.isGreaterThan(0))
|
|
16
|
+
.map(account => account?.currency);
|
|
17
|
+
|
|
18
|
+
const allStakingCurrenciesEnabled = new Set([
|
|
19
|
+
...stakingCurrenciesEnabled,
|
|
20
|
+
...partnerStakingCurrenciesEnabled,
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
const tokenWithFundsMap = getTokensWithFundsMap(accounts);
|
|
24
|
+
const filteredAccountCurrencyIds = [...accountsWithFundsCurrencies].filter(currency =>
|
|
25
|
+
allStakingCurrenciesEnabled.has(currency.id),
|
|
26
|
+
);
|
|
27
|
+
const filteredTokenWithFunds = [...tokenWithFundsMap.values()].filter(token =>
|
|
28
|
+
allStakingCurrenciesEnabled.has(token.id),
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const combined = new Map<string, { ticker: string; networkName: string; id: string }>();
|
|
32
|
+
for (const currency of filteredAccountCurrencyIds) {
|
|
33
|
+
combined.set(currency.id, {
|
|
34
|
+
ticker: currency.ticker,
|
|
35
|
+
networkName: currency.name,
|
|
36
|
+
id: currency.id,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
for (const token of filteredTokenWithFunds) {
|
|
40
|
+
combined.set(token.id, token);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
combinedIds: new Set(Array.from(combined.values(), details => details.id)),
|
|
45
|
+
stakeableAssets: Array.from(combined.values()),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -734,6 +734,8 @@ export const DEFAULT_FEATURES: Features = {
|
|
|
734
734
|
},
|
|
735
735
|
zcashShielded: DEFAULT_FEATURE,
|
|
736
736
|
llmNanoOnboardingFundWallet: DEFAULT_FEATURE,
|
|
737
|
+
lldRebornABtest: DEFAULT_FEATURE,
|
|
738
|
+
llmRebornABtest: DEFAULT_FEATURE,
|
|
737
739
|
};
|
|
738
740
|
|
|
739
741
|
// Firebase SDK treat JSON values as strings
|
package/src/mock/account.ts
CHANGED
|
@@ -199,7 +199,7 @@ export function genAccount(id: number | string, opts: GenAccountOptions = {}): A
|
|
|
199
199
|
if (initAccount) {
|
|
200
200
|
initAccount(account);
|
|
201
201
|
}
|
|
202
|
-
} catch
|
|
202
|
+
} catch {
|
|
203
203
|
// to fix /src/__tests__/cross.ts, skip bridge error if there is no bridge in such currency
|
|
204
204
|
}
|
|
205
205
|
}
|
|
@@ -390,11 +390,13 @@ export const handlers = ({
|
|
|
390
390
|
customFeeConfig,
|
|
391
391
|
swapAppVersion,
|
|
392
392
|
sponsored,
|
|
393
|
+
isEmbedded,
|
|
393
394
|
} = params;
|
|
394
395
|
|
|
395
396
|
const trackingParams = {
|
|
396
397
|
provider: params.provider,
|
|
397
398
|
exchangeType: params.exchangeType,
|
|
399
|
+
isEmbeddedSwap: isEmbedded,
|
|
398
400
|
};
|
|
399
401
|
|
|
400
402
|
tracking.startExchangeRequested(trackingParams);
|
|
@@ -472,6 +474,7 @@ export const handlers = ({
|
|
|
472
474
|
const trackingCompleteParams = {
|
|
473
475
|
provider: params.provider,
|
|
474
476
|
exchangeType: params.exchangeType,
|
|
477
|
+
isEmbeddedSwap: isEmbedded,
|
|
475
478
|
};
|
|
476
479
|
tracking.completeExchangeRequested(trackingCompleteParams);
|
|
477
480
|
|
|
@@ -14,8 +14,15 @@ type TrackExchange = (
|
|
|
14
14
|
interface TrackEventPayload {
|
|
15
15
|
exchangeType: "SELL" | "FUND" | "SWAP";
|
|
16
16
|
provider: string;
|
|
17
|
+
isEmbeddedSwap?: boolean;
|
|
17
18
|
}
|
|
18
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Converts isEmbeddedSwap boolean to string for analytics consistency
|
|
22
|
+
*/
|
|
23
|
+
const formatIsEmbeddedSwap = (isEmbeddedSwap?: boolean): string | undefined =>
|
|
24
|
+
isEmbeddedSwap !== undefined ? String(isEmbeddedSwap) : undefined;
|
|
25
|
+
|
|
19
26
|
function getEventData(manifest: AppManifest) {
|
|
20
27
|
return { walletAPI: manifest.name };
|
|
21
28
|
}
|
|
@@ -29,24 +36,46 @@ function getEventData(manifest: AppManifest) {
|
|
|
29
36
|
// in order to get the exact type matching the tracking wrapper API
|
|
30
37
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
31
38
|
export default function trackingWrapper(trackCall: TrackExchange) {
|
|
32
|
-
const track = (event: string, properties: Record<string, string> | null) => {
|
|
33
|
-
|
|
39
|
+
const track = (event: string, properties: Record<string, string | undefined> | null) => {
|
|
40
|
+
// Filter out undefined values before passing to trackCall
|
|
41
|
+
if (!properties) {
|
|
42
|
+
return trackCall(event, null, null);
|
|
43
|
+
}
|
|
44
|
+
const filteredProperties: Record<string, string> = {};
|
|
45
|
+
for (const [key, value] of Object.entries(properties)) {
|
|
46
|
+
if (value !== undefined) {
|
|
47
|
+
filteredProperties[key] = value;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return trackCall(event, filteredProperties, null);
|
|
34
51
|
};
|
|
35
52
|
|
|
36
53
|
return {
|
|
37
54
|
// Generate Exchange nonce modal open
|
|
38
|
-
startExchangeRequested: ({ provider, exchangeType }: TrackEventPayload) => {
|
|
39
|
-
track(`Starts Exchange ${exchangeType} Nonce request`, {
|
|
55
|
+
startExchangeRequested: ({ provider, exchangeType, isEmbeddedSwap }: TrackEventPayload) => {
|
|
56
|
+
track(`Starts Exchange ${exchangeType} Nonce request`, {
|
|
57
|
+
provider,
|
|
58
|
+
exchangeType,
|
|
59
|
+
isEmbeddedSwap: formatIsEmbeddedSwap(isEmbeddedSwap),
|
|
60
|
+
});
|
|
40
61
|
},
|
|
41
62
|
|
|
42
63
|
// Successfully generated an Exchange app nonce
|
|
43
|
-
startExchangeSuccess: ({ provider, exchangeType }: TrackEventPayload) => {
|
|
44
|
-
track(`Starts Exchange ${exchangeType} Nonce success`, {
|
|
64
|
+
startExchangeSuccess: ({ provider, exchangeType, isEmbeddedSwap }: TrackEventPayload) => {
|
|
65
|
+
track(`Starts Exchange ${exchangeType} Nonce success`, {
|
|
66
|
+
provider,
|
|
67
|
+
exchangeType,
|
|
68
|
+
isEmbeddedSwap: formatIsEmbeddedSwap(isEmbeddedSwap),
|
|
69
|
+
});
|
|
45
70
|
},
|
|
46
71
|
|
|
47
72
|
// Failed to generate an Exchange app nonce
|
|
48
|
-
startExchangeFail: ({ provider, exchangeType }: TrackEventPayload) => {
|
|
49
|
-
track(`Starts Exchange ${exchangeType} Nonce fail`, {
|
|
73
|
+
startExchangeFail: ({ provider, exchangeType, isEmbeddedSwap }: TrackEventPayload) => {
|
|
74
|
+
track(`Starts Exchange ${exchangeType} Nonce fail`, {
|
|
75
|
+
provider,
|
|
76
|
+
exchangeType,
|
|
77
|
+
isEmbeddedSwap: formatIsEmbeddedSwap(isEmbeddedSwap),
|
|
78
|
+
});
|
|
50
79
|
},
|
|
51
80
|
|
|
52
81
|
// No Params to generate an Exchange app nonce
|
|
@@ -54,8 +83,12 @@ export default function trackingWrapper(trackCall: TrackExchange) {
|
|
|
54
83
|
track("Starts Exchange no params", getEventData(manifest));
|
|
55
84
|
},
|
|
56
85
|
|
|
57
|
-
completeExchangeRequested: ({ provider, exchangeType }: TrackEventPayload) => {
|
|
58
|
-
track(`Completes Exchange ${exchangeType} requested`, {
|
|
86
|
+
completeExchangeRequested: ({ provider, exchangeType, isEmbeddedSwap }: TrackEventPayload) => {
|
|
87
|
+
track(`Completes Exchange ${exchangeType} requested`, {
|
|
88
|
+
provider,
|
|
89
|
+
exchangeType,
|
|
90
|
+
isEmbeddedSwap: formatIsEmbeddedSwap(isEmbeddedSwap),
|
|
91
|
+
});
|
|
59
92
|
},
|
|
60
93
|
|
|
61
94
|
// Successfully completed an Exchange
|
|
@@ -63,13 +96,23 @@ export default function trackingWrapper(trackCall: TrackExchange) {
|
|
|
63
96
|
provider,
|
|
64
97
|
exchangeType,
|
|
65
98
|
currency,
|
|
99
|
+
isEmbeddedSwap,
|
|
66
100
|
}: TrackEventPayload & { currency: string }) => {
|
|
67
|
-
track(`Completes Exchange ${exchangeType} success`, {
|
|
101
|
+
track(`Completes Exchange ${exchangeType} success`, {
|
|
102
|
+
provider,
|
|
103
|
+
exchangeType,
|
|
104
|
+
currency,
|
|
105
|
+
isEmbeddedSwap: formatIsEmbeddedSwap(isEmbeddedSwap),
|
|
106
|
+
});
|
|
68
107
|
},
|
|
69
108
|
|
|
70
109
|
// Failed to complete an Exchange
|
|
71
|
-
completeExchangeFail: ({ provider, exchangeType }: TrackEventPayload) => {
|
|
72
|
-
track(`Completes Exchange ${exchangeType} Nonce fail`, {
|
|
110
|
+
completeExchangeFail: ({ provider, exchangeType, isEmbeddedSwap }: TrackEventPayload) => {
|
|
111
|
+
track(`Completes Exchange ${exchangeType} Nonce fail`, {
|
|
112
|
+
provider,
|
|
113
|
+
exchangeType,
|
|
114
|
+
isEmbeddedSwap: formatIsEmbeddedSwap(isEmbeddedSwap),
|
|
115
|
+
});
|
|
73
116
|
},
|
|
74
117
|
|
|
75
118
|
// No Params to complete an Exchange
|
package/src/wallet-api/logic.ts
CHANGED
|
@@ -88,24 +88,25 @@ export async function signTransactionLogic(
|
|
|
88
88
|
},
|
|
89
89
|
) => Promise<SignedOperation>,
|
|
90
90
|
tokenCurrency?: string,
|
|
91
|
+
isEmbeddedSwap?: boolean,
|
|
91
92
|
): Promise<SignedOperation> {
|
|
92
|
-
tracking.signTransactionRequested(manifest);
|
|
93
|
+
tracking.signTransactionRequested(manifest, isEmbeddedSwap);
|
|
93
94
|
|
|
94
95
|
if (!transaction) {
|
|
95
|
-
tracking.signTransactionFail(manifest);
|
|
96
|
+
tracking.signTransactionFail(manifest, isEmbeddedSwap);
|
|
96
97
|
throw new Error("Transaction required");
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
const accountId = getAccountIdFromWalletAccountId(walletAccountId);
|
|
100
101
|
if (!accountId) {
|
|
101
|
-
tracking.signTransactionFail(manifest);
|
|
102
|
+
tracking.signTransactionFail(manifest, isEmbeddedSwap);
|
|
102
103
|
throw new Error(`accountId ${walletAccountId} unknown`);
|
|
103
104
|
}
|
|
104
105
|
|
|
105
106
|
const account = accounts.find(account => account.id === accountId);
|
|
106
107
|
|
|
107
108
|
if (!account) {
|
|
108
|
-
tracking.signTransactionFail(manifest);
|
|
109
|
+
tracking.signTransactionFail(manifest, isEmbeddedSwap);
|
|
109
110
|
throw new Error("Account required");
|
|
110
111
|
}
|
|
111
112
|
|
package/src/wallet-api/react.ts
CHANGED
|
@@ -806,8 +806,12 @@ export function useWalletAPIServer({
|
|
|
806
806
|
|
|
807
807
|
server.setHandler(
|
|
808
808
|
"transaction.signAndBroadcast",
|
|
809
|
-
async ({ accountId, tokenCurrency, transaction, options }) => {
|
|
809
|
+
async ({ accountId, tokenCurrency, transaction, options, meta }) => {
|
|
810
810
|
const sponsored = transaction.family === "ethereum" && transaction.sponsored;
|
|
811
|
+
// isEmbedded is passed via meta (not transaction) as it's a tracking param, not a tx property
|
|
812
|
+
const isEmbeddedSwap =
|
|
813
|
+
transaction.family === "ethereum" &&
|
|
814
|
+
(meta as { isEmbedded?: boolean } | undefined)?.isEmbedded;
|
|
811
815
|
|
|
812
816
|
const signedTransaction = await signTransactionLogic(
|
|
813
817
|
{ manifest, accounts, tracking },
|
|
@@ -824,18 +828,19 @@ export function useWalletAPIServer({
|
|
|
824
828
|
onSuccess: signedOperation => {
|
|
825
829
|
if (done) return;
|
|
826
830
|
done = true;
|
|
827
|
-
tracking.signTransactionSuccess(manifest);
|
|
831
|
+
tracking.signTransactionSuccess(manifest, isEmbeddedSwap);
|
|
828
832
|
resolve(signedOperation);
|
|
829
833
|
},
|
|
830
834
|
onError: error => {
|
|
831
835
|
if (done) return;
|
|
832
836
|
done = true;
|
|
833
|
-
tracking.signTransactionFail(manifest);
|
|
837
|
+
tracking.signTransactionFail(manifest, isEmbeddedSwap);
|
|
834
838
|
reject(error);
|
|
835
839
|
},
|
|
836
840
|
});
|
|
837
841
|
}),
|
|
838
842
|
tokenCurrency,
|
|
843
|
+
isEmbeddedSwap,
|
|
839
844
|
);
|
|
840
845
|
|
|
841
846
|
return broadcastTransactionLogic(
|
|
@@ -858,9 +863,9 @@ export function useWalletAPIServer({
|
|
|
858
863
|
sponsored,
|
|
859
864
|
},
|
|
860
865
|
});
|
|
861
|
-
tracking.broadcastSuccess(manifest);
|
|
866
|
+
tracking.broadcastSuccess(manifest, isEmbeddedSwap);
|
|
862
867
|
} catch (error) {
|
|
863
|
-
tracking.broadcastFail(manifest);
|
|
868
|
+
tracking.broadcastFail(manifest, isEmbeddedSwap);
|
|
864
869
|
throw error;
|
|
865
870
|
}
|
|
866
871
|
}
|
|
@@ -56,18 +56,30 @@ export default function trackingWrapper(trackCall: TrackWalletAPI) {
|
|
|
56
56
|
},
|
|
57
57
|
|
|
58
58
|
// Sign transaction modal open
|
|
59
|
-
signTransactionRequested: (manifest: AppManifest) => {
|
|
60
|
-
|
|
59
|
+
signTransactionRequested: (manifest: AppManifest, isEmbeddedSwap?: boolean) => {
|
|
60
|
+
const properties = {
|
|
61
|
+
...getEventData(manifest),
|
|
62
|
+
...(isEmbeddedSwap !== undefined && { isEmbeddedSwap: String(isEmbeddedSwap) }),
|
|
63
|
+
};
|
|
64
|
+
track("WalletAPI SignTransaction", properties);
|
|
61
65
|
},
|
|
62
66
|
|
|
63
67
|
// Failed to sign transaction (cancel or error)
|
|
64
|
-
signTransactionFail: (manifest: AppManifest) => {
|
|
65
|
-
|
|
68
|
+
signTransactionFail: (manifest: AppManifest, isEmbeddedSwap?: boolean) => {
|
|
69
|
+
const properties = {
|
|
70
|
+
...getEventData(manifest),
|
|
71
|
+
...(isEmbeddedSwap !== undefined && { isEmbeddedSwap: String(isEmbeddedSwap) }),
|
|
72
|
+
};
|
|
73
|
+
track("WalletAPI SignTransaction Fail", properties);
|
|
66
74
|
},
|
|
67
75
|
|
|
68
76
|
// Successfully signed transaction
|
|
69
|
-
signTransactionSuccess: (manifest: AppManifest) => {
|
|
70
|
-
|
|
77
|
+
signTransactionSuccess: (manifest: AppManifest, isEmbeddedSwap?: boolean) => {
|
|
78
|
+
const properties = {
|
|
79
|
+
...getEventData(manifest),
|
|
80
|
+
...(isEmbeddedSwap !== undefined && { isEmbeddedSwap: String(isEmbeddedSwap) }),
|
|
81
|
+
};
|
|
82
|
+
track("WalletAPI SignTransaction Success", properties);
|
|
71
83
|
},
|
|
72
84
|
|
|
73
85
|
// Sign Raw transaction modal open
|
|
@@ -116,13 +128,21 @@ export default function trackingWrapper(trackCall: TrackWalletAPI) {
|
|
|
116
128
|
},
|
|
117
129
|
|
|
118
130
|
// Failed to broadcast a signed transaction
|
|
119
|
-
broadcastFail: (manifest: AppManifest) => {
|
|
120
|
-
|
|
131
|
+
broadcastFail: (manifest: AppManifest, isEmbeddedSwap?: boolean) => {
|
|
132
|
+
const properties = {
|
|
133
|
+
...getEventData(manifest),
|
|
134
|
+
...(isEmbeddedSwap !== undefined && { isEmbeddedSwap: String(isEmbeddedSwap) }),
|
|
135
|
+
};
|
|
136
|
+
track("WalletAPI Broadcast Fail", properties);
|
|
121
137
|
},
|
|
122
138
|
|
|
123
139
|
// Successfully broadcast a signed transaction
|
|
124
|
-
broadcastSuccess: (manifest: AppManifest) => {
|
|
125
|
-
|
|
140
|
+
broadcastSuccess: (manifest: AppManifest, isEmbeddedSwap?: boolean) => {
|
|
141
|
+
const properties = {
|
|
142
|
+
...getEventData(manifest),
|
|
143
|
+
...(isEmbeddedSwap !== undefined && { isEmbeddedSwap: String(isEmbeddedSwap) }),
|
|
144
|
+
};
|
|
145
|
+
track("WalletAPI Broadcast Success", properties);
|
|
126
146
|
},
|
|
127
147
|
|
|
128
148
|
// Successfully broadcast a signed transaction
|