@dynamic-labs/sdk-react-core 4.83.2-alpha.0 → 4.84.1

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.
Files changed (39) hide show
  1. package/CHANGELOG.md +36 -1
  2. package/package.cjs +1 -1
  3. package/package.js +1 -1
  4. package/package.json +12 -12
  5. package/src/index.cjs +4 -0
  6. package/src/index.d.ts +2 -2
  7. package/src/index.js +2 -0
  8. package/src/lib/components/SendBalanceForm/SendBalanceForm.cjs +26 -1
  9. package/src/lib/components/SendBalanceForm/SendBalanceForm.js +26 -1
  10. package/src/lib/components/SendBalancePageLayout/SendBalancePageLayout.cjs +6 -1
  11. package/src/lib/components/SendBalancePageLayout/SendBalancePageLayout.js +6 -1
  12. package/src/lib/main.global.cjs +1 -1
  13. package/src/lib/main.global.js +1 -1
  14. package/src/lib/utils/hooks/index.d.ts +2 -0
  15. package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/pollOnShielded.cjs +24 -4
  16. package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/pollOnShielded.d.ts +10 -2
  17. package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/pollOnShielded.js +24 -4
  18. package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/useAleoAutoShieldSponsoredTokens.cjs +14 -3
  19. package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/useAleoAutoShieldSponsoredTokens.d.ts +5 -1
  20. package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/useAleoAutoShieldSponsoredTokens.js +14 -3
  21. package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.cjs +14 -0
  22. package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.js +14 -0
  23. package/src/lib/utils/hooks/usePrivateTokenBalances/index.d.ts +2 -0
  24. package/src/lib/utils/hooks/usePrivateTokenBalances/usePrivateTokenBalances.cjs +19 -0
  25. package/src/lib/utils/hooks/usePrivateTokenBalances/usePrivateTokenBalances.d.ts +9 -0
  26. package/src/lib/utils/hooks/usePrivateTokenBalances/usePrivateTokenBalances.js +15 -0
  27. package/src/lib/utils/hooks/useSyncDeviceRegistrationFlow/useSyncDeviceRegistrationFlow.cjs +8 -0
  28. package/src/lib/utils/hooks/useSyncDeviceRegistrationFlow/useSyncDeviceRegistrationFlow.js +9 -1
  29. package/src/lib/utils/hooks/useWalletDelegation/useWalletDelegation.cjs +19 -16
  30. package/src/lib/utils/hooks/useWalletDelegation/useWalletDelegation.d.ts +8 -0
  31. package/src/lib/utils/hooks/useWalletDelegation/useWalletDelegation.js +19 -17
  32. package/src/lib/utils/hooks/useWalletPassword/useWalletPassword.d.ts +4 -4
  33. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/ActiveWalletBalance.cjs +138 -21
  34. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/ActiveWalletBalance.js +139 -22
  35. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/optimisticShield.cjs +134 -0
  36. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/optimisticShield.d.ts +69 -0
  37. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/optimisticShield.js +127 -0
  38. package/src/lib/widgets/DynamicWidget/views/ManageTrustedDevicesView/ManageTrustedDevicesView.cjs +12 -8
  39. package/src/lib/widgets/DynamicWidget/views/ManageTrustedDevicesView/ManageTrustedDevicesView.js +8 -4
@@ -9,7 +9,7 @@ var _tslib = require('../../../../../_virtual/_tslib.cjs');
9
9
  // when the relay accepts the broadcast, not when the public→private
10
10
  // transition confirms on-chain. Aleo block time + RecordScanner indexer
11
11
  // lag means the immediate post-broadcast fetch usually returns the
12
- // pre-confirmation balance, so we re-poll for ~45s before giving up.
12
+ // pre-confirmation balance, so we re-poll on a backoff schedule.
13
13
  //
14
14
  // Shared between the auto-shield hook (background) and the widget's
15
15
  // manual Shield Manually CTA (foreground), so both flows update the
@@ -17,23 +17,41 @@ var _tslib = require('../../../../../_virtual/_tslib.cjs');
17
17
  // the manual flow refreshed exactly once and the unshielded row
18
18
  // stayed at its pre-broadcast value for the full RecordScanner lag,
19
19
  // making a successful shield look like a no-op.
20
+ //
21
+ // Total window ≈106s. Provable's mapping endpoint typically reflects
22
+ // a `transfer_public_to_private` within ~30s of broadcast, but the
23
+ // RecordScanner index lag for the new private record can stretch to
24
+ // ~90s in the worst case. The tail entries (25s, 35s) keep the poll
25
+ // alive across the upper end of that range without spamming requests
26
+ // during the common case (most balances converge inside the first
27
+ // three iterations and the convergence predicate exits the loop).
20
28
  const REFRESH_DELAYS_MS = [
21
- 3000, 5000, 8000, 12000, 18000,
29
+ 3000, 5000, 8000, 12000, 18000, 25000, 35000,
22
30
  ];
23
31
  /**
24
32
  * After a successful shield broadcast, poll `onShielded` on a backoff
25
33
  * schedule so the consumer sees both the shielded and unshielded balances
26
- * update without a manual refresh click. Stops early on cancel; swallows
34
+ * update without a manual refresh click. Stops early on cancel or when
35
+ * the optional `hasConverged` predicate returns true; swallows
27
36
  * per-iteration errors (refresh is best-effort).
28
37
  *
29
38
  * `isCancelled` is a thunk so callers can hook it up to whatever liveness
30
39
  * signal they have (effect cleanup `cancelled` flag, abort signal, mount
31
40
  * ref, etc.) without this module having to know about React lifecycle.
41
+ *
42
+ * `hasConverged` is optional and lets callers exit early once the
43
+ * post-shield state has actually materialized (e.g. the just-shielded
44
+ * token's unshielded balance has dropped). When omitted, the schedule
45
+ * runs to completion. Checked both before each delay and after each
46
+ * refresh so a refresh that produces the converged state ends the loop
47
+ * immediately.
32
48
  */
33
- const pollOnShielded = (onShielded, isCancelled) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
49
+ const pollOnShielded = (onShielded, isCancelled, hasConverged) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
34
50
  for (const delay of REFRESH_DELAYS_MS) {
35
51
  if (isCancelled())
36
52
  return;
53
+ if (hasConverged === null || hasConverged === void 0 ? void 0 : hasConverged())
54
+ return;
37
55
  yield new Promise((resolve) => setTimeout(resolve, delay));
38
56
  if (isCancelled())
39
57
  return;
@@ -43,6 +61,8 @@ const pollOnShielded = (onShielded, isCancelled) => _tslib.__awaiter(void 0, voi
43
61
  catch (_a) {
44
62
  /* swallow — refresh is best-effort */
45
63
  }
64
+ if (hasConverged === null || hasConverged === void 0 ? void 0 : hasConverged())
65
+ return;
46
66
  }
47
67
  });
48
68
 
@@ -2,11 +2,19 @@ export declare const REFRESH_DELAYS_MS: ReadonlyArray<number>;
2
2
  /**
3
3
  * After a successful shield broadcast, poll `onShielded` on a backoff
4
4
  * schedule so the consumer sees both the shielded and unshielded balances
5
- * update without a manual refresh click. Stops early on cancel; swallows
5
+ * update without a manual refresh click. Stops early on cancel or when
6
+ * the optional `hasConverged` predicate returns true; swallows
6
7
  * per-iteration errors (refresh is best-effort).
7
8
  *
8
9
  * `isCancelled` is a thunk so callers can hook it up to whatever liveness
9
10
  * signal they have (effect cleanup `cancelled` flag, abort signal, mount
10
11
  * ref, etc.) without this module having to know about React lifecycle.
12
+ *
13
+ * `hasConverged` is optional and lets callers exit early once the
14
+ * post-shield state has actually materialized (e.g. the just-shielded
15
+ * token's unshielded balance has dropped). When omitted, the schedule
16
+ * runs to completion. Checked both before each delay and after each
17
+ * refresh so a refresh that produces the converged state ends the loop
18
+ * immediately.
11
19
  */
12
- export declare const pollOnShielded: (onShielded: () => Promise<void> | void, isCancelled: () => boolean) => Promise<void>;
20
+ export declare const pollOnShielded: (onShielded: () => Promise<void> | void, isCancelled: () => boolean, hasConverged?: () => boolean) => Promise<void>;
@@ -5,7 +5,7 @@ import { __awaiter } from '../../../../../_virtual/_tslib.js';
5
5
  // when the relay accepts the broadcast, not when the public→private
6
6
  // transition confirms on-chain. Aleo block time + RecordScanner indexer
7
7
  // lag means the immediate post-broadcast fetch usually returns the
8
- // pre-confirmation balance, so we re-poll for ~45s before giving up.
8
+ // pre-confirmation balance, so we re-poll on a backoff schedule.
9
9
  //
10
10
  // Shared between the auto-shield hook (background) and the widget's
11
11
  // manual Shield Manually CTA (foreground), so both flows update the
@@ -13,23 +13,41 @@ import { __awaiter } from '../../../../../_virtual/_tslib.js';
13
13
  // the manual flow refreshed exactly once and the unshielded row
14
14
  // stayed at its pre-broadcast value for the full RecordScanner lag,
15
15
  // making a successful shield look like a no-op.
16
+ //
17
+ // Total window ≈106s. Provable's mapping endpoint typically reflects
18
+ // a `transfer_public_to_private` within ~30s of broadcast, but the
19
+ // RecordScanner index lag for the new private record can stretch to
20
+ // ~90s in the worst case. The tail entries (25s, 35s) keep the poll
21
+ // alive across the upper end of that range without spamming requests
22
+ // during the common case (most balances converge inside the first
23
+ // three iterations and the convergence predicate exits the loop).
16
24
  const REFRESH_DELAYS_MS = [
17
- 3000, 5000, 8000, 12000, 18000,
25
+ 3000, 5000, 8000, 12000, 18000, 25000, 35000,
18
26
  ];
19
27
  /**
20
28
  * After a successful shield broadcast, poll `onShielded` on a backoff
21
29
  * schedule so the consumer sees both the shielded and unshielded balances
22
- * update without a manual refresh click. Stops early on cancel; swallows
30
+ * update without a manual refresh click. Stops early on cancel or when
31
+ * the optional `hasConverged` predicate returns true; swallows
23
32
  * per-iteration errors (refresh is best-effort).
24
33
  *
25
34
  * `isCancelled` is a thunk so callers can hook it up to whatever liveness
26
35
  * signal they have (effect cleanup `cancelled` flag, abort signal, mount
27
36
  * ref, etc.) without this module having to know about React lifecycle.
37
+ *
38
+ * `hasConverged` is optional and lets callers exit early once the
39
+ * post-shield state has actually materialized (e.g. the just-shielded
40
+ * token's unshielded balance has dropped). When omitted, the schedule
41
+ * runs to completion. Checked both before each delay and after each
42
+ * refresh so a refresh that produces the converged state ends the loop
43
+ * immediately.
28
44
  */
29
- const pollOnShielded = (onShielded, isCancelled) => __awaiter(void 0, void 0, void 0, function* () {
45
+ const pollOnShielded = (onShielded, isCancelled, hasConverged) => __awaiter(void 0, void 0, void 0, function* () {
30
46
  for (const delay of REFRESH_DELAYS_MS) {
31
47
  if (isCancelled())
32
48
  return;
49
+ if (hasConverged === null || hasConverged === void 0 ? void 0 : hasConverged())
50
+ return;
33
51
  yield new Promise((resolve) => setTimeout(resolve, delay));
34
52
  if (isCancelled())
35
53
  return;
@@ -39,6 +57,8 @@ const pollOnShielded = (onShielded, isCancelled) => __awaiter(void 0, void 0, vo
39
57
  catch (_a) {
40
58
  /* swallow — refresh is best-effort */
41
59
  }
60
+ if (hasConverged === null || hasConverged === void 0 ? void 0 : hasConverged())
61
+ return;
42
62
  }
43
63
  });
44
64
 
@@ -47,7 +47,7 @@ const buildShieldCandidates = (args) => {
47
47
  */
48
48
  const tryShieldOneToken = (token, deps) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
49
49
  var _a, _b, _c;
50
- const { accountAddress, shieldHandle, seenKeys, isCancelled, inFlightTokenKeys, } = deps;
50
+ const { accountAddress, shieldHandle, seenKeys, isCancelled, inFlightTokenKeys, onShieldDispatched, } = deps;
51
51
  const tokenKey = buildTokenKey.buildTokenKey(token) || nativeTokenKey.nativeTokenKey;
52
52
  const key = `${accountAddress}:${tokenKey}`;
53
53
  seenKeys.add(key);
@@ -80,9 +80,19 @@ const tryShieldOneToken = (token, deps) => _tslib.__awaiter(void 0, void 0, void
80
80
  isNative: token.isNative,
81
81
  tokenAddress: token.address,
82
82
  });
83
+ // Optimistic-UI hand-off: notify the consumer the broadcast was
84
+ // accepted so it can deduct the unshielded balance locally and
85
+ // prepend a synthesised shielded row. Synchronous and best-effort;
86
+ // failures inside the callback don't roll back the shield.
87
+ try {
88
+ onShieldDispatched === null || onShieldDispatched === void 0 ? void 0 : onShieldDispatched({ amount: atomic, token });
89
+ }
90
+ catch (_e) {
91
+ /* swallow — optimistic hand-off is best-effort */
92
+ }
83
93
  return true;
84
94
  }
85
- catch (_e) {
95
+ catch (_f) {
86
96
  seenKeys.delete(key);
87
97
  return false;
88
98
  }
@@ -90,7 +100,7 @@ const tryShieldOneToken = (token, deps) => _tslib.__awaiter(void 0, void 0, void
90
100
  inFlightTokenKeys === null || inFlightTokenKeys === void 0 ? void 0 : inFlightTokenKeys.delete(tokenKey);
91
101
  }
92
102
  });
93
- const useAleoAutoShieldSponsoredTokens = ({ accountAddress, unshieldedTokenBalances, shieldHandle, onShielded, }) => {
103
+ const useAleoAutoShieldSponsoredTokens = ({ accountAddress, unshieldedTokenBalances, shieldHandle, onShielded, onShieldDispatched, }) => {
94
104
  // Tracks `(accountAddress:tokenAddress)` we've already attempted in this
95
105
  // session. Cleared implicitly on a full page reload.
96
106
  const seenKeysRef = React.useRef(new Set());
@@ -218,6 +228,7 @@ const useAleoAutoShieldSponsoredTokens = ({ accountAddress, unshieldedTokenBalan
218
228
  accountAddress,
219
229
  inFlightTokenKeys: inFlightKeysAdapter,
220
230
  isCancelled,
231
+ onShieldDispatched,
221
232
  seenKeys: seenKeysRef.current,
222
233
  shieldHandle,
223
234
  });
@@ -25,6 +25,10 @@ type UseAleoAutoShieldSponsoredTokensArgs = {
25
25
  unshieldedTokenBalances: TokenBalance[];
26
26
  shieldHandle: AleoShieldHandle | undefined;
27
27
  onShielded?: () => Promise<void> | void;
28
+ onShieldDispatched?: (info: {
29
+ token: TokenBalance;
30
+ amount: bigint;
31
+ }) => void;
28
32
  };
29
33
  /**
30
34
  * On Aleo wallet load (and on each subsequent unshielded-balance refresh),
@@ -66,5 +70,5 @@ export type UseAleoAutoShieldSponsoredTokensResult = {
66
70
  */
67
71
  currentlyShieldingTokenKeys: ReadonlySet<string>;
68
72
  };
69
- export declare const useAleoAutoShieldSponsoredTokens: ({ accountAddress, unshieldedTokenBalances, shieldHandle, onShielded, }: UseAleoAutoShieldSponsoredTokensArgs) => UseAleoAutoShieldSponsoredTokensResult;
73
+ export declare const useAleoAutoShieldSponsoredTokens: ({ accountAddress, unshieldedTokenBalances, shieldHandle, onShielded, onShieldDispatched, }: UseAleoAutoShieldSponsoredTokensArgs) => UseAleoAutoShieldSponsoredTokensResult;
70
74
  export {};
@@ -43,7 +43,7 @@ const buildShieldCandidates = (args) => {
43
43
  */
44
44
  const tryShieldOneToken = (token, deps) => __awaiter(void 0, void 0, void 0, function* () {
45
45
  var _a, _b, _c;
46
- const { accountAddress, shieldHandle, seenKeys, isCancelled, inFlightTokenKeys, } = deps;
46
+ const { accountAddress, shieldHandle, seenKeys, isCancelled, inFlightTokenKeys, onShieldDispatched, } = deps;
47
47
  const tokenKey = buildTokenKey(token) || nativeTokenKey;
48
48
  const key = `${accountAddress}:${tokenKey}`;
49
49
  seenKeys.add(key);
@@ -76,9 +76,19 @@ const tryShieldOneToken = (token, deps) => __awaiter(void 0, void 0, void 0, fun
76
76
  isNative: token.isNative,
77
77
  tokenAddress: token.address,
78
78
  });
79
+ // Optimistic-UI hand-off: notify the consumer the broadcast was
80
+ // accepted so it can deduct the unshielded balance locally and
81
+ // prepend a synthesised shielded row. Synchronous and best-effort;
82
+ // failures inside the callback don't roll back the shield.
83
+ try {
84
+ onShieldDispatched === null || onShieldDispatched === void 0 ? void 0 : onShieldDispatched({ amount: atomic, token });
85
+ }
86
+ catch (_e) {
87
+ /* swallow — optimistic hand-off is best-effort */
88
+ }
79
89
  return true;
80
90
  }
81
- catch (_e) {
91
+ catch (_f) {
82
92
  seenKeys.delete(key);
83
93
  return false;
84
94
  }
@@ -86,7 +96,7 @@ const tryShieldOneToken = (token, deps) => __awaiter(void 0, void 0, void 0, fun
86
96
  inFlightTokenKeys === null || inFlightTokenKeys === void 0 ? void 0 : inFlightTokenKeys.delete(tokenKey);
87
97
  }
88
98
  });
89
- const useAleoAutoShieldSponsoredTokens = ({ accountAddress, unshieldedTokenBalances, shieldHandle, onShielded, }) => {
99
+ const useAleoAutoShieldSponsoredTokens = ({ accountAddress, unshieldedTokenBalances, shieldHandle, onShielded, onShieldDispatched, }) => {
90
100
  // Tracks `(accountAddress:tokenAddress)` we've already attempted in this
91
101
  // session. Cleared implicitly on a full page reload.
92
102
  const seenKeysRef = useRef(new Set());
@@ -214,6 +224,7 @@ const useAleoAutoShieldSponsoredTokens = ({ accountAddress, unshieldedTokenBalan
214
224
  accountAddress,
215
225
  inFlightTokenKeys: inFlightKeysAdapter,
216
226
  isCancelled,
227
+ onShieldDispatched,
217
228
  seenKeys: seenKeysRef.current,
218
229
  shieldHandle,
219
230
  });
@@ -173,6 +173,12 @@ const buildCreditsBalance = (records, networkId, lookupCurated) => {
173
173
  if (creditsRecords.length === 0)
174
174
  return undefined;
175
175
  const totalMicrocredits = creditsRecords.reduce((sum, r) => sum + BigInt(r.microcredits), BigInt(0));
176
+ // Skip the row entirely when every credits record summed to zero
177
+ // (typically partially-spent change records the indexer hasn't
178
+ // pruned yet). A "0 ALEO" entry in the Shielded tab is just noise
179
+ // the user can't act on.
180
+ if (totalMicrocredits === BigInt(0))
181
+ return undefined;
176
182
  // BigInt → number for the TokenBalance shape. Aleo balances stay well
177
183
  // below Number.MAX_SAFE_INTEGER for a single wallet (max u64 supply is
178
184
  // 1.5B credits = 1.5e15 microcredits; Number can hold up to ~9e15).
@@ -227,6 +233,14 @@ const buildTokenBalances = (records, networkId, lookupCurated) => {
227
233
  const spec = specsByContract.get(contractAddress);
228
234
  if (!spec)
229
235
  continue;
236
+ // Skip tokens whose every matched record summed to zero. Provable
237
+ // occasionally surfaces serialized records with `amount: 0u128`
238
+ // (e.g. partially-spent change records that haven't been pruned by
239
+ // the indexer yet); without this filter the Shielded tab shows a
240
+ // row with "0 USAD" / "0 USDCx" that the user can't act on, which
241
+ // is just noise.
242
+ if (total === BigInt(0))
243
+ continue;
230
244
  const rawBalance = Number(total);
231
245
  const rawBalanceString = total.toString();
232
246
  const balance = rawBalance / Math.pow(10, spec.decimals);
@@ -169,6 +169,12 @@ const buildCreditsBalance = (records, networkId, lookupCurated) => {
169
169
  if (creditsRecords.length === 0)
170
170
  return undefined;
171
171
  const totalMicrocredits = creditsRecords.reduce((sum, r) => sum + BigInt(r.microcredits), BigInt(0));
172
+ // Skip the row entirely when every credits record summed to zero
173
+ // (typically partially-spent change records the indexer hasn't
174
+ // pruned yet). A "0 ALEO" entry in the Shielded tab is just noise
175
+ // the user can't act on.
176
+ if (totalMicrocredits === BigInt(0))
177
+ return undefined;
172
178
  // BigInt → number for the TokenBalance shape. Aleo balances stay well
173
179
  // below Number.MAX_SAFE_INTEGER for a single wallet (max u64 supply is
174
180
  // 1.5B credits = 1.5e15 microcredits; Number can hold up to ~9e15).
@@ -223,6 +229,14 @@ const buildTokenBalances = (records, networkId, lookupCurated) => {
223
229
  const spec = specsByContract.get(contractAddress);
224
230
  if (!spec)
225
231
  continue;
232
+ // Skip tokens whose every matched record summed to zero. Provable
233
+ // occasionally surfaces serialized records with `amount: 0u128`
234
+ // (e.g. partially-spent change records that haven't been pruned by
235
+ // the indexer yet); without this filter the Shielded tab shows a
236
+ // row with "0 USAD" / "0 USDCx" that the user can't act on, which
237
+ // is just noise.
238
+ if (total === BigInt(0))
239
+ continue;
226
240
  const rawBalance = Number(total);
227
241
  const rawBalanceString = total.toString();
228
242
  const balance = rawBalance / Math.pow(10, spec.decimals);
@@ -0,0 +1,2 @@
1
+ export { usePrivateTokenBalances } from './usePrivateTokenBalances';
2
+ export type { UsePrivateTokenBalancesReturn } from './usePrivateTokenBalances';
@@ -0,0 +1,19 @@
1
+ 'use client'
2
+ 'use strict';
3
+
4
+ Object.defineProperty(exports, '__esModule', { value: true });
5
+
6
+ var useAleoShieldedBalances = require('../useAleoShieldedBalances/useAleoShieldedBalances.cjs');
7
+
8
+ const usePrivateTokenBalances = () => {
9
+ const { tokenBalances, isLoading, error, refetch, supportsShielded } = useAleoShieldedBalances.useAleoShieldedBalances();
10
+ return {
11
+ error,
12
+ isLoading,
13
+ refetch,
14
+ supportsPrivateBalances: supportsShielded,
15
+ tokenBalances,
16
+ };
17
+ };
18
+
19
+ exports.usePrivateTokenBalances = usePrivateTokenBalances;
@@ -0,0 +1,9 @@
1
+ import { TokenBalance } from '@dynamic-labs/sdk-api-core';
2
+ export type UsePrivateTokenBalancesReturn = {
3
+ tokenBalances: TokenBalance[];
4
+ isLoading: boolean;
5
+ error: string | undefined;
6
+ refetch: () => Promise<void>;
7
+ supportsPrivateBalances: boolean;
8
+ };
9
+ export declare const usePrivateTokenBalances: () => UsePrivateTokenBalancesReturn;
@@ -0,0 +1,15 @@
1
+ 'use client'
2
+ import { useAleoShieldedBalances } from '../useAleoShieldedBalances/useAleoShieldedBalances.js';
3
+
4
+ const usePrivateTokenBalances = () => {
5
+ const { tokenBalances, isLoading, error, refetch, supportsShielded } = useAleoShieldedBalances();
6
+ return {
7
+ error,
8
+ isLoading,
9
+ refetch,
10
+ supportsPrivateBalances: supportsShielded,
11
+ tokenBalances,
12
+ };
13
+ };
14
+
15
+ export { usePrivateTokenBalances };
@@ -22,6 +22,10 @@ var hasPendingDeviceRegistration = require('../../../shared/utils/functions/hasP
22
22
  const useSyncDeviceRegistrationFlow = () => {
23
23
  const { setShowAuthFlow, sdkHasLoaded, userWithMissingInfo } = useInternalDynamicContext.useInternalDynamicContext();
24
24
  const { clearStackAndPush } = ViewContext.useViewContext();
25
+ // Device registration tokens are single-use. Track tokens we've already
26
+ // attempted to prevent re-firing if the effect re-runs (e.g. when
27
+ // userWithMissingInfo identity flips after the first call's auth update).
28
+ const attemptedDeviceTokenRef = React.useRef(null);
25
29
  React.useEffect(() => {
26
30
  let cancelled = false;
27
31
  const syncDeviceRegistration = () => _tslib.__awaiter(void 0, void 0, void 0, function* () {
@@ -37,6 +41,10 @@ const useSyncDeviceRegistrationFlow = () => {
37
41
  // complete registration directly without showing the modal
38
42
  if (client.detectDeviceRegistrationRedirect({ url })) {
39
43
  const deviceToken = client.getDeviceRegistrationTokenFromUrl({ url });
44
+ if (attemptedDeviceTokenRef.current === deviceToken) {
45
+ return;
46
+ }
47
+ attemptedDeviceTokenRef.current = deviceToken;
40
48
  try {
41
49
  yield client.completeDeviceRegistration({ deviceToken });
42
50
  /**
@@ -1,6 +1,6 @@
1
1
  'use client'
2
2
  import { __awaiter } from '../../../../../_virtual/_tslib.js';
3
- import { useEffect } from 'react';
3
+ import { useRef, useEffect } from 'react';
4
4
  import { detectDeviceRegistrationRedirect, getDeviceRegistrationTokenFromUrl, completeDeviceRegistration } from '@dynamic-labs-sdk/client';
5
5
  import '../../../context/DynamicContext/useDynamicContext/useDynamicContext.js';
6
6
  import { useInternalDynamicContext } from '../../../context/DynamicContext/useDynamicContext/useInternalDynamicContext/useInternalDynamicContext.js';
@@ -18,6 +18,10 @@ import { hasPendingDeviceRegistration } from '../../../shared/utils/functions/ha
18
18
  const useSyncDeviceRegistrationFlow = () => {
19
19
  const { setShowAuthFlow, sdkHasLoaded, userWithMissingInfo } = useInternalDynamicContext();
20
20
  const { clearStackAndPush } = useViewContext();
21
+ // Device registration tokens are single-use. Track tokens we've already
22
+ // attempted to prevent re-firing if the effect re-runs (e.g. when
23
+ // userWithMissingInfo identity flips after the first call's auth update).
24
+ const attemptedDeviceTokenRef = useRef(null);
21
25
  useEffect(() => {
22
26
  let cancelled = false;
23
27
  const syncDeviceRegistration = () => __awaiter(void 0, void 0, void 0, function* () {
@@ -33,6 +37,10 @@ const useSyncDeviceRegistrationFlow = () => {
33
37
  // complete registration directly without showing the modal
34
38
  if (detectDeviceRegistrationRedirect({ url })) {
35
39
  const deviceToken = getDeviceRegistrationTokenFromUrl({ url });
40
+ if (attemptedDeviceTokenRef.current === deviceToken) {
41
+ return;
42
+ }
43
+ attemptedDeviceTokenRef.current = deviceToken;
36
44
  try {
37
45
  yield completeDeviceRegistration({ deviceToken });
38
46
  /**
@@ -41,6 +41,14 @@ var useDynamicWaas = require('../useDynamicWaas/useDynamicWaas.cjs');
41
41
  var useRefreshAuth = require('../useRefreshAuth/useRefreshAuth.cjs');
42
42
  var DelegationError = require('./DelegationError.cjs');
43
43
 
44
+ // Pre-share-set backends mark delegation via keyShares[].backupLocation='delegated';
45
+ // share-set backends use otherShareSets[].shareSetType='delegated' instead.
46
+ const isWalletDelegated = (walletProperties) => {
47
+ var _a, _b;
48
+ const hasDelegatedKeyShare = (_a = walletProperties === null || walletProperties === void 0 ? void 0 : walletProperties.keyShares) === null || _a === void 0 ? void 0 : _a.some((keyShare) => keyShare.backupLocation === 'delegated');
49
+ const hasDelegatedShareSet = (_b = walletProperties === null || walletProperties === void 0 ? void 0 : walletProperties.otherShareSets) === null || _b === void 0 ? void 0 : _b.some((shareSet) => shareSet.shareSetType === 'delegated');
50
+ return Boolean(hasDelegatedKeyShare || hasDelegatedShareSet);
51
+ };
44
52
  /**
45
53
  * Gets pending wallets that are eligible for delegation.
46
54
  * If wallets are provided and not empty, converts them to WalletWithStatus[] with pending status.
@@ -87,15 +95,11 @@ const useWalletDelegation = () => {
87
95
  const waasCredentials = user.verifiedCredentials.filter((vc) => vc.walletName === 'dynamicwaas' &&
88
96
  vc.format === sdkApiCore.JwtVerifiedCredentialFormatEnum.Blockchain);
89
97
  const hasWalletNeedingDelegation = waasCredentials.some((vc) => {
90
- var _a, _b, _c, _d, _e;
91
- // Check if already delegated (has delegated keyShare)
92
- const hasDelegatedKeyShare = (_b = (_a = vc.walletProperties) === null || _a === void 0 ? void 0 : _a.keyShares) === null || _b === void 0 ? void 0 : _b.some((keyShare) => keyShare.backupLocation === 'delegated');
93
- // Check if denied
94
- const hasDeniedAccess = ((_d = (_c = vc.walletProperties) === null || _c === void 0 ? void 0 : _c.settings) === null || _d === void 0 ? void 0 : _d.hasDeniedDelegatedAccess) === true;
95
- // Check if dismissed this session
96
- const isDismissedThisSession = (_e = sessionState === null || sessionState === void 0 ? void 0 : sessionState.dismissedWallets) === null || _e === void 0 ? void 0 : _e.includes(vc.id);
97
- // Needs delegation if: not delegated, not denied, and not dismissed this session
98
- return (!hasDelegatedKeyShare && !hasDeniedAccess && !isDismissedThisSession);
98
+ var _a, _b, _c;
99
+ const isDelegated = isWalletDelegated(vc.walletProperties);
100
+ const hasDeniedAccess = ((_b = (_a = vc.walletProperties) === null || _a === void 0 ? void 0 : _a.settings) === null || _b === void 0 ? void 0 : _b.hasDeniedDelegatedAccess) === true;
101
+ const isDismissedThisSession = (_c = sessionState === null || sessionState === void 0 ? void 0 : sessionState.dismissedWallets) === null || _c === void 0 ? void 0 : _c.includes(vc.id);
102
+ return !isDelegated && !hasDeniedAccess && !isDismissedThisSession;
99
103
  });
100
104
  return hasWalletNeedingDelegation;
101
105
  }, [user === null || user === void 0 ? void 0 : user.verifiedCredentials, delegatedAccessEnabled, promptUsersOnSignIn]);
@@ -129,20 +133,18 @@ const useWalletDelegation = () => {
129
133
  // Map credentials to wallets with status
130
134
  return waasCredentials
131
135
  .map((vc) => {
132
- var _a, _b, _c, _d, _e;
136
+ var _a, _b, _c;
133
137
  let status = 'pending';
134
- // Check if wallet has delegated keyShare
135
- const hasDelegatedKeyShare = (_b = (_a = vc.walletProperties) === null || _a === void 0 ? void 0 : _a.keyShares) === null || _b === void 0 ? void 0 : _b.some((keyShare) => keyShare.backupLocation === 'delegated');
136
- // Check if user has denied delegation
137
- const hasDeniedAccess = ((_d = (_c = vc.walletProperties) === null || _c === void 0 ? void 0 : _c.settings) === null || _d === void 0 ? void 0 : _d.hasDeniedDelegatedAccess) === true;
138
- if (hasDelegatedKeyShare) {
138
+ const isDelegated = isWalletDelegated(vc.walletProperties);
139
+ const hasDeniedAccess = ((_b = (_a = vc.walletProperties) === null || _a === void 0 ? void 0 : _a.settings) === null || _b === void 0 ? void 0 : _b.hasDeniedDelegatedAccess) === true;
140
+ if (isDelegated) {
139
141
  status = 'delegated';
140
142
  }
141
143
  else if (hasDeniedAccess) {
142
144
  status = 'denied';
143
145
  }
144
146
  // Check if dismissed this session (UI state only)
145
- const isDismissedThisSession = (_e = sessionState === null || sessionState === void 0 ? void 0 : sessionState.dismissedWallets) === null || _e === void 0 ? void 0 : _e.includes(vc.id);
147
+ const isDismissedThisSession = (_c = sessionState === null || sessionState === void 0 ? void 0 : sessionState.dismissedWallets) === null || _c === void 0 ? void 0 : _c.includes(vc.id);
146
148
  // Find corresponding wallet from userWallets
147
149
  const wallet = userWallets.find((w) => w.address === vc.address);
148
150
  if (!wallet) {
@@ -309,4 +311,5 @@ const useWalletDelegation = () => {
309
311
  };
310
312
 
311
313
  exports.getWalletsToDelegate = getWalletsToDelegate;
314
+ exports.isWalletDelegated = isWalletDelegated;
312
315
  exports.useWalletDelegation = useWalletDelegation;
@@ -5,6 +5,14 @@ export type WalletWithStatus = Wallet & {
5
5
  status: WalletDelegationStatus;
6
6
  isDismissedThisSession?: boolean;
7
7
  };
8
+ export declare const isWalletDelegated: (walletProperties: {
9
+ keyShares?: Array<{
10
+ backupLocation?: string;
11
+ }>;
12
+ otherShareSets?: Array<{
13
+ shareSetType?: string;
14
+ }>;
15
+ } | null | undefined) => boolean;
8
16
  /**
9
17
  * Gets pending wallets that are eligible for delegation.
10
18
  * If wallets are provided and not empty, converts them to WalletWithStatus[] with pending status.
@@ -37,6 +37,14 @@ import { useDynamicWaas } from '../useDynamicWaas/useDynamicWaas.js';
37
37
  import { useRefreshAuth } from '../useRefreshAuth/useRefreshAuth.js';
38
38
  import { DelegationError } from './DelegationError.js';
39
39
 
40
+ // Pre-share-set backends mark delegation via keyShares[].backupLocation='delegated';
41
+ // share-set backends use otherShareSets[].shareSetType='delegated' instead.
42
+ const isWalletDelegated = (walletProperties) => {
43
+ var _a, _b;
44
+ const hasDelegatedKeyShare = (_a = walletProperties === null || walletProperties === void 0 ? void 0 : walletProperties.keyShares) === null || _a === void 0 ? void 0 : _a.some((keyShare) => keyShare.backupLocation === 'delegated');
45
+ const hasDelegatedShareSet = (_b = walletProperties === null || walletProperties === void 0 ? void 0 : walletProperties.otherShareSets) === null || _b === void 0 ? void 0 : _b.some((shareSet) => shareSet.shareSetType === 'delegated');
46
+ return Boolean(hasDelegatedKeyShare || hasDelegatedShareSet);
47
+ };
40
48
  /**
41
49
  * Gets pending wallets that are eligible for delegation.
42
50
  * If wallets are provided and not empty, converts them to WalletWithStatus[] with pending status.
@@ -83,15 +91,11 @@ const useWalletDelegation = () => {
83
91
  const waasCredentials = user.verifiedCredentials.filter((vc) => vc.walletName === 'dynamicwaas' &&
84
92
  vc.format === JwtVerifiedCredentialFormatEnum.Blockchain);
85
93
  const hasWalletNeedingDelegation = waasCredentials.some((vc) => {
86
- var _a, _b, _c, _d, _e;
87
- // Check if already delegated (has delegated keyShare)
88
- const hasDelegatedKeyShare = (_b = (_a = vc.walletProperties) === null || _a === void 0 ? void 0 : _a.keyShares) === null || _b === void 0 ? void 0 : _b.some((keyShare) => keyShare.backupLocation === 'delegated');
89
- // Check if denied
90
- const hasDeniedAccess = ((_d = (_c = vc.walletProperties) === null || _c === void 0 ? void 0 : _c.settings) === null || _d === void 0 ? void 0 : _d.hasDeniedDelegatedAccess) === true;
91
- // Check if dismissed this session
92
- const isDismissedThisSession = (_e = sessionState === null || sessionState === void 0 ? void 0 : sessionState.dismissedWallets) === null || _e === void 0 ? void 0 : _e.includes(vc.id);
93
- // Needs delegation if: not delegated, not denied, and not dismissed this session
94
- return (!hasDelegatedKeyShare && !hasDeniedAccess && !isDismissedThisSession);
94
+ var _a, _b, _c;
95
+ const isDelegated = isWalletDelegated(vc.walletProperties);
96
+ const hasDeniedAccess = ((_b = (_a = vc.walletProperties) === null || _a === void 0 ? void 0 : _a.settings) === null || _b === void 0 ? void 0 : _b.hasDeniedDelegatedAccess) === true;
97
+ const isDismissedThisSession = (_c = sessionState === null || sessionState === void 0 ? void 0 : sessionState.dismissedWallets) === null || _c === void 0 ? void 0 : _c.includes(vc.id);
98
+ return !isDelegated && !hasDeniedAccess && !isDismissedThisSession;
95
99
  });
96
100
  return hasWalletNeedingDelegation;
97
101
  }, [user === null || user === void 0 ? void 0 : user.verifiedCredentials, delegatedAccessEnabled, promptUsersOnSignIn]);
@@ -125,20 +129,18 @@ const useWalletDelegation = () => {
125
129
  // Map credentials to wallets with status
126
130
  return waasCredentials
127
131
  .map((vc) => {
128
- var _a, _b, _c, _d, _e;
132
+ var _a, _b, _c;
129
133
  let status = 'pending';
130
- // Check if wallet has delegated keyShare
131
- const hasDelegatedKeyShare = (_b = (_a = vc.walletProperties) === null || _a === void 0 ? void 0 : _a.keyShares) === null || _b === void 0 ? void 0 : _b.some((keyShare) => keyShare.backupLocation === 'delegated');
132
- // Check if user has denied delegation
133
- const hasDeniedAccess = ((_d = (_c = vc.walletProperties) === null || _c === void 0 ? void 0 : _c.settings) === null || _d === void 0 ? void 0 : _d.hasDeniedDelegatedAccess) === true;
134
- if (hasDelegatedKeyShare) {
134
+ const isDelegated = isWalletDelegated(vc.walletProperties);
135
+ const hasDeniedAccess = ((_b = (_a = vc.walletProperties) === null || _a === void 0 ? void 0 : _a.settings) === null || _b === void 0 ? void 0 : _b.hasDeniedDelegatedAccess) === true;
136
+ if (isDelegated) {
135
137
  status = 'delegated';
136
138
  }
137
139
  else if (hasDeniedAccess) {
138
140
  status = 'denied';
139
141
  }
140
142
  // Check if dismissed this session (UI state only)
141
- const isDismissedThisSession = (_e = sessionState === null || sessionState === void 0 ? void 0 : sessionState.dismissedWallets) === null || _e === void 0 ? void 0 : _e.includes(vc.id);
143
+ const isDismissedThisSession = (_c = sessionState === null || sessionState === void 0 ? void 0 : sessionState.dismissedWallets) === null || _c === void 0 ? void 0 : _c.includes(vc.id);
142
144
  // Find corresponding wallet from userWallets
143
145
  const wallet = userWallets.find((w) => w.address === vc.address);
144
146
  if (!wallet) {
@@ -304,4 +306,4 @@ const useWalletDelegation = () => {
304
306
  };
305
307
  };
306
308
 
307
- export { getWalletsToDelegate, useWalletDelegation };
309
+ export { getWalletsToDelegate, isWalletDelegated, useWalletDelegation };
@@ -2,23 +2,23 @@ import { WalletRecoveryState } from '@dynamic-labs-wallet/browser-wallet-client'
2
2
  import { ChainEnum } from '@dynamic-labs/sdk-api-core';
3
3
  export type SetPasswordParams = {
4
4
  accountAddress: string;
5
- chainName: ChainEnum;
5
+ chainName: ChainEnum | string;
6
6
  newPassword: string;
7
7
  };
8
8
  export type UpdatePasswordParams = {
9
9
  accountAddress: string;
10
- chainName: ChainEnum;
10
+ chainName: ChainEnum | string;
11
11
  newPassword: string;
12
12
  existingPassword?: string;
13
13
  };
14
14
  export type UnlockWalletParams = {
15
15
  accountAddress: string;
16
- chainName: ChainEnum;
16
+ chainName: ChainEnum | string;
17
17
  password: string;
18
18
  };
19
19
  export type CheckWalletLockStateParams = {
20
20
  accountAddress: string;
21
- chainName: ChainEnum;
21
+ chainName: ChainEnum | string;
22
22
  };
23
23
  export type WalletPasswordState = {
24
24
  isLoading: boolean;