@rango-dev/widget-embedded 0.41.1-next.2 → 0.41.1-next.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rango-dev/widget-embedded",
3
- "version": "0.41.1-next.2",
3
+ "version": "0.41.1-next.3",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "source": "./src/index.ts",
@@ -7,13 +7,20 @@ export const keepLastUpdated: <Store, Slice extends { lastUpdatedAt: number }>(
7
7
  config: StateCreator<Store, [], [], Slice>
8
8
  ) => StateCreator<Store, [], [], Slice> = (slice) => (set, get, api) => {
9
9
  const modifedSet: typeof set = (...params) => {
10
+ const [partial, ...restParams] = params;
10
11
  set((state) => {
12
+ // @see https://github.com/pmndrs/zustand/blob/90f8d592d4cde9aa15f236e320f17ccbc86cf0fb/src/vanilla.ts#L69-L72
13
+ type State = ReturnType<typeof get>;
14
+ const nextState =
15
+ typeof partial === 'function'
16
+ ? (partial as (s: State) => State)(state)
17
+ : partial;
18
+
11
19
  return {
12
- ...state,
20
+ ...nextState,
13
21
  lastUpdatedAt: +new Date(),
14
22
  };
15
- });
16
- set(...params);
23
+ }, ...restParams);
17
24
  };
18
25
  return slice(modifedSet, get, api);
19
26
  };
@@ -18,13 +18,12 @@ import { memoizedResult } from '../../utils/common';
18
18
  import { isAccountAndWalletMatched } from '../../utils/wallets';
19
19
  import { keepLastUpdated } from '../middlewares/keepLastUpdated';
20
20
  import {
21
+ computeNextBalancesWithNewPrices,
22
+ computeNextStateAfterWalletBalanceRemoval,
21
23
  createAssetKey,
22
- createBalanceKey,
23
24
  createBalanceStateForNewAccount,
24
25
  extractAssetFromBalanceKey,
25
- removeBalanceFromAggregatedBalance,
26
26
  updateAggregatedBalanceStateForNewAccount,
27
- updateBalancesWithNewPrices,
28
27
  } from '../utils/wallets';
29
28
 
30
29
  type WalletAddress = string;
@@ -353,16 +352,24 @@ export const createWalletsSlice = keepLastUpdated<AppStoreState, WalletsSlice>(
353
352
  return;
354
353
  }
355
354
 
356
- const WalletDetail = {
355
+ const walletDetail = {
357
356
  blockChain: balance.asset.blockchain,
358
357
  balances: [balance],
359
358
  address: walletAddress,
360
359
  };
361
360
 
362
- updateBalancesWithNewPrices(WalletDetail, nextBalances, get);
361
+ const partialCurrentState = {
362
+ _aggregatedBalances: get()._aggregatedBalances,
363
+ findToken: get().findToken,
364
+ };
365
+ computeNextBalancesWithNewPrices(
366
+ partialCurrentState,
367
+ walletDetail,
368
+ nextBalances
369
+ );
363
370
 
364
371
  const balancesForWallet = createBalanceStateForNewAccount(
365
- WalletDetail,
372
+ walletDetail,
366
373
  get
367
374
  );
368
375
 
@@ -435,73 +442,21 @@ export const createWalletsSlice = keepLastUpdated<AppStoreState, WalletsSlice>(
435
442
  });
436
443
  },
437
444
  removeBalancesForWallet: (walletType, options) => {
438
- let walletsNeedsToBeRemoved = get().connectedWallets.filter(
439
- (connectedWallet) => connectedWallet.walletType === walletType
440
- );
441
- /*
442
- * We only need to delete balances where there is no connected wallets with same chain and address for that balance.
443
- * Consider both Metamask and Solana having support for `0xblahblahblahblah` for Ethereum.
444
- * If Phantom is disconnecting, we should keep the balance since Metamask has access to same address yet.
445
- * So we only delete balance when there is no connected wallet that has access to that specific chain and address.
446
- */
447
- get().connectedWallets.forEach((connectedWallet) => {
448
- if (connectedWallet.walletType !== walletType) {
449
- walletsNeedsToBeRemoved = walletsNeedsToBeRemoved.filter((wallet) => {
450
- const isAnotherWalletHasSameAddressAndChain =
451
- wallet.chain === connectedWallet.chain &&
452
- wallet.address === connectedWallet.address;
453
- return !isAnotherWalletHasSameAddressAndChain;
454
- });
455
- }
456
- });
457
-
458
- if (!!options?.chains && options.chains.length > 0) {
459
- walletsNeedsToBeRemoved = walletsNeedsToBeRemoved.filter((wallet) => {
460
- return options.chains?.includes(wallet.chain);
461
- });
462
- }
463
-
464
- if (!!options?.namespaces && options.namespaces.length > 0) {
465
- walletsNeedsToBeRemoved = walletsNeedsToBeRemoved.filter((wallet) => {
466
- if (wallet.namespace) {
467
- return options.namespaces?.includes(wallet.namespace);
468
- }
469
- return false;
470
- });
471
- }
472
-
473
- const nextBalancesState: BalanceState = {};
474
- let nextAggregatedBalanceState: AggregatedBalanceState =
475
- get()._aggregatedBalances;
476
- const currentBalancesState = get()._balances;
477
- const balanceKeys = Object.keys(currentBalancesState) as BalanceKey[];
478
-
479
- balanceKeys.forEach((key) => {
480
- const asset = extractAssetFromBalanceKey(key);
481
-
482
- const shouldBalanceBeRemoved = !!walletsNeedsToBeRemoved.find(
483
- (wallet) =>
484
- createBalanceKey(wallet.address, {
485
- address: asset.address,
486
- blockchain: wallet.chain,
487
- symbol: asset.symbol,
488
- }) === key
445
+ const partialCurrentState = {
446
+ _balances: get()._balances,
447
+ _aggregatedBalances: get()._aggregatedBalances,
448
+ connectedWallets: get().connectedWallets,
449
+ };
450
+ const { _balances, _aggregatedBalances } =
451
+ computeNextStateAfterWalletBalanceRemoval(
452
+ partialCurrentState,
453
+ walletType,
454
+ options
489
455
  );
490
456
 
491
- // if a balance should be removed, we need to remove its caches in _aggregatedBalances as wel.
492
- if (shouldBalanceBeRemoved) {
493
- nextAggregatedBalanceState = removeBalanceFromAggregatedBalance(
494
- nextAggregatedBalanceState,
495
- key
496
- );
497
- } else {
498
- nextBalancesState[key] = currentBalancesState[key];
499
- }
500
- });
501
-
502
457
  set({
503
- _balances: nextBalancesState,
504
- _aggregatedBalances: nextAggregatedBalanceState,
458
+ _balances,
459
+ _aggregatedBalances,
505
460
  });
506
461
  },
507
462
  disconnectNamespaces: (walletType, requestedNamesapces) => {
@@ -644,7 +599,6 @@ export const createWalletsSlice = keepLastUpdated<AppStoreState, WalletsSlice>(
644
599
  console.error(`Request for fetching balances failed. cause: ${e}`);
645
600
  return;
646
601
  }
647
-
648
602
  const walletsDetails = response.wallets;
649
603
 
650
604
  if (walletsDetails) {
@@ -672,12 +626,30 @@ export const createWalletsSlice = keepLastUpdated<AppStoreState, WalletsSlice>(
672
626
  return;
673
627
  }
674
628
 
675
- updateBalancesWithNewPrices(wallet, nextBalances, get);
629
+ const partialCurrentState = {
630
+ _balances: nextBalances,
631
+ _aggregatedBalances: nextAggregatedBalances,
632
+ connectedWallets: get().connectedWallets,
633
+ findToken: get().findToken,
634
+ };
635
+
636
+ computeNextBalancesWithNewPrices(
637
+ partialCurrentState,
638
+ wallet,
639
+ nextBalances
640
+ );
676
641
 
677
642
  // Remove old balances for current wallet and blockchain
678
- get().removeBalancesForWallet(walletType, {
679
- chains: [wallet.blockChain],
680
- });
643
+ const { _balances, _aggregatedBalances } =
644
+ computeNextStateAfterWalletBalanceRemoval(
645
+ partialCurrentState,
646
+ walletType,
647
+ {
648
+ chains: [wallet.blockChain],
649
+ }
650
+ );
651
+ nextAggregatedBalances = _aggregatedBalances;
652
+ nextBalances = _balances;
681
653
 
682
654
  /*
683
655
  * Check if after fetching balance for an account, the account still exists.
@@ -1,17 +1,20 @@
1
1
  import type { Balance } from '../../types';
2
2
  import type { AppStoreState } from '../app';
3
+ import type { FindToken } from '../slices/data';
4
+ import type {
5
+ AggregatedBalanceState,
6
+ AssetKey,
7
+ BalanceKey,
8
+ BalanceState,
9
+ ConnectedWallet,
10
+ } from '../slices/wallets';
11
+ import type { Namespace } from '@rango-dev/wallets-core/namespaces/common';
3
12
  import type { Asset, WalletDetail } from 'rango-types';
4
13
 
5
14
  import BigNumber from 'bignumber.js';
6
15
 
7
16
  import { ZERO } from '../../constants/numbers';
8
17
  import { BALANCE_SEPARATOR } from '../../constants/wallets';
9
- import {
10
- type AggregatedBalanceState,
11
- type AssetKey,
12
- type BalanceKey,
13
- type BalanceState,
14
- } from '../slices/wallets';
15
18
 
16
19
  /**
17
20
  * Note: We need to use `symbol` as well since native coins and cosmos blockchains don't have `address`
@@ -44,16 +47,19 @@ export function extractAssetFromBalanceKey(key: BalanceKey): Asset {
44
47
  };
45
48
  }
46
49
 
47
- export function updateBalancesWithNewPrices(
50
+ export function computeNextBalancesWithNewPrices(
51
+ paritalCurrentState: {
52
+ findToken: FindToken;
53
+ _aggregatedBalances: AggregatedBalanceState;
54
+ },
48
55
  wallet: Omit<WalletDetail, 'failed' | 'explorerUrl'>,
49
- balanceState: BalanceState,
50
- store: () => AppStoreState
56
+ balanceState: BalanceState
51
57
  ): BalanceState {
52
58
  wallet.balances?.forEach((balance) => {
53
59
  const usdPrice =
54
- balance.price ?? store().findToken(balance.asset)?.usdPrice;
60
+ balance.price ?? paritalCurrentState.findToken(balance.asset)?.usdPrice;
55
61
  const balancesToUpdate =
56
- store()._aggregatedBalances[createAssetKey(balance.asset)];
62
+ paritalCurrentState._aggregatedBalances[createAssetKey(balance.asset)];
57
63
 
58
64
  balancesToUpdate?.forEach((balanceKey) => {
59
65
  if (balanceState[balanceKey]) {
@@ -139,3 +145,89 @@ export function removeBalanceFromAggregatedBalance(
139
145
 
140
146
  return aggregatedBalances;
141
147
  }
148
+
149
+ /**
150
+ * We made a util to remvoe balances to be able batch with other state updates.
151
+ */
152
+ export function computeNextStateAfterWalletBalanceRemoval(
153
+ paritalCurrentState: {
154
+ _balances: BalanceState;
155
+ _aggregatedBalances: AggregatedBalanceState;
156
+ connectedWallets: ConnectedWallet[];
157
+ },
158
+ walletType: string,
159
+ options?: {
160
+ chains?: string[];
161
+ namespaces?: Namespace[];
162
+ }
163
+ ) {
164
+ let walletsNeedsToBeRemoved = paritalCurrentState.connectedWallets.filter(
165
+ (connectedWallet) => connectedWallet.walletType === walletType
166
+ );
167
+
168
+ /*
169
+ * We only need to delete balances where there is no connected wallets with same chain and address for that balance.
170
+ * Consider both Metamask and Solana having support for `0xblahblahblahblah` for Ethereum.
171
+ * If Phantom is disconnecting, we should keep the balance since Metamask has access to same address yet.
172
+ * So we only delete balance when there is no connected wallet that has access to that specific chain and address.
173
+ */
174
+ paritalCurrentState.connectedWallets.forEach((connectedWallet) => {
175
+ if (connectedWallet.walletType !== walletType) {
176
+ walletsNeedsToBeRemoved = walletsNeedsToBeRemoved.filter((wallet) => {
177
+ const isAnotherWalletHasSameAddressAndChain =
178
+ wallet.chain === connectedWallet.chain &&
179
+ wallet.address === connectedWallet.address;
180
+ return !isAnotherWalletHasSameAddressAndChain;
181
+ });
182
+ }
183
+ });
184
+
185
+ if (!!options?.chains && options.chains.length > 0) {
186
+ walletsNeedsToBeRemoved = walletsNeedsToBeRemoved.filter((wallet) => {
187
+ return options.chains?.includes(wallet.chain);
188
+ });
189
+ }
190
+
191
+ if (!!options?.namespaces && options.namespaces.length > 0) {
192
+ walletsNeedsToBeRemoved = walletsNeedsToBeRemoved.filter((wallet) => {
193
+ if (wallet.namespace) {
194
+ return options.namespaces?.includes(wallet.namespace);
195
+ }
196
+ return false;
197
+ });
198
+ }
199
+
200
+ const nextBalancesState: BalanceState = {};
201
+ let nextAggregatedBalanceState: AggregatedBalanceState =
202
+ paritalCurrentState._aggregatedBalances;
203
+ const currentBalancesState = paritalCurrentState._balances;
204
+ const balanceKeys = Object.keys(currentBalancesState) as BalanceKey[];
205
+
206
+ balanceKeys.forEach((key) => {
207
+ const asset = extractAssetFromBalanceKey(key);
208
+
209
+ const shouldBalanceBeRemoved = !!walletsNeedsToBeRemoved.find(
210
+ (wallet) =>
211
+ createBalanceKey(wallet.address, {
212
+ address: asset.address,
213
+ blockchain: wallet.chain,
214
+ symbol: asset.symbol,
215
+ }) === key
216
+ );
217
+
218
+ // if a balance should be removed, we need to remove its caches in _aggregatedBalances as wel.
219
+ if (shouldBalanceBeRemoved) {
220
+ nextAggregatedBalanceState = removeBalanceFromAggregatedBalance(
221
+ nextAggregatedBalanceState,
222
+ key
223
+ );
224
+ } else {
225
+ nextBalancesState[key] = currentBalancesState[key];
226
+ }
227
+ });
228
+
229
+ return {
230
+ _balances: nextBalancesState,
231
+ _aggregatedBalances: nextAggregatedBalanceState,
232
+ };
233
+ }