@dynamic-labs/sdk-react-core 4.80.0 → 4.82.0

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 (68) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/package.cjs +1 -1
  3. package/package.js +1 -1
  4. package/package.json +12 -12
  5. package/src/lib/components/SendBalanceForm/SendBalanceForm.cjs +63 -3
  6. package/src/lib/components/SendBalanceForm/SendBalanceForm.js +63 -3
  7. package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/TransactionModeSegmentedControl.cjs +40 -0
  8. package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/TransactionModeSegmentedControl.d.ts +16 -0
  9. package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/TransactionModeSegmentedControl.js +36 -0
  10. package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/icons.cjs +17 -0
  11. package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/icons.d.ts +8 -0
  12. package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/icons.js +12 -0
  13. package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/index.d.ts +1 -0
  14. package/src/lib/data/api/aleo/getAleoCuratedPrices.cjs +73 -0
  15. package/src/lib/data/api/aleo/getAleoCuratedPrices.d.ts +38 -0
  16. package/src/lib/data/api/aleo/getAleoCuratedPrices.js +69 -0
  17. package/src/lib/shared/assets/index.d.ts +2 -0
  18. package/src/lib/shared/assets/midnight-shielded.cjs +54 -0
  19. package/src/lib/shared/assets/midnight-shielded.js +30 -0
  20. package/src/lib/shared/assets/midnight-unshielded.cjs +54 -0
  21. package/src/lib/shared/assets/midnight-unshielded.js +30 -0
  22. package/src/lib/styles/index.shadow.cjs +1 -1
  23. package/src/lib/styles/index.shadow.js +1 -1
  24. package/src/lib/utils/functions/compareChains/compareChains.cjs +1 -0
  25. package/src/lib/utils/functions/compareChains/compareChains.js +1 -0
  26. package/src/lib/utils/functions/getTransactionLink/blockExplorerPatterns.cjs +12 -0
  27. package/src/lib/utils/functions/getTransactionLink/blockExplorerPatterns.js +12 -0
  28. package/src/lib/utils/hooks/useAleoAutoMergeRecords/index.d.ts +1 -0
  29. package/src/lib/utils/hooks/useAleoAutoMergeRecords/useAleoAutoMergeRecords.cjs +246 -0
  30. package/src/lib/utils/hooks/useAleoAutoMergeRecords/useAleoAutoMergeRecords.d.ts +17 -0
  31. package/src/lib/utils/hooks/useAleoAutoMergeRecords/useAleoAutoMergeRecords.js +242 -0
  32. package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/index.d.ts +1 -0
  33. package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/useAleoAutoShieldSponsoredTokens.cjs +263 -0
  34. package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/useAleoAutoShieldSponsoredTokens.d.ts +59 -0
  35. package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/useAleoAutoShieldSponsoredTokens.js +259 -0
  36. package/src/lib/utils/hooks/useAleoShieldedBalances/index.d.ts +1 -0
  37. package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.cjs +443 -0
  38. package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.d.ts +24 -0
  39. package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.js +439 -0
  40. package/src/lib/utils/hooks/useEmbeddedWallet/useEmbeddedWallet.cjs +1 -0
  41. package/src/lib/utils/hooks/useEmbeddedWallet/useEmbeddedWallet.d.ts +1 -0
  42. package/src/lib/utils/hooks/useEmbeddedWallet/useEmbeddedWallet.js +1 -0
  43. package/src/lib/views/BackupUnsuccessfulView/BackupUnsuccessfulView.cjs +12 -1
  44. package/src/lib/views/BackupUnsuccessfulView/BackupUnsuccessfulView.js +12 -1
  45. package/src/lib/views/SendBalanceView/SendBalanceView.cjs +53 -0
  46. package/src/lib/views/SendBalanceView/SendBalanceView.js +53 -0
  47. package/src/lib/widgets/DynamicWidget/components/ActiveMidnightWalletBalance/ActiveMidnightWalletBalance.cjs +193 -0
  48. package/src/lib/widgets/DynamicWidget/components/ActiveMidnightWalletBalance/ActiveMidnightWalletBalance.d.ts +7 -0
  49. package/src/lib/widgets/DynamicWidget/components/ActiveMidnightWalletBalance/ActiveMidnightWalletBalance.js +189 -0
  50. package/src/lib/widgets/DynamicWidget/components/ActiveMidnightWalletBalance/index.d.ts +1 -0
  51. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/ActiveWalletBalance.cjs +216 -11
  52. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/ActiveWalletBalance.js +216 -11
  53. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceItem/TokenBalanceItem.cjs +5 -2
  54. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceItem/TokenBalanceItem.d.ts +10 -1
  55. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceItem/TokenBalanceItem.js +5 -2
  56. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceItem/index.d.ts +1 -0
  57. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceList/TokenBalanceList.cjs +2 -2
  58. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceList/TokenBalanceList.d.ts +3 -1
  59. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceList/TokenBalanceList.js +2 -2
  60. package/src/lib/widgets/DynamicWidget/components/ActiveWalletInformation/ActiveMidnightWalletAddresses/ActiveMidnightWalletAddresses.cjs +124 -0
  61. package/src/lib/widgets/DynamicWidget/components/ActiveWalletInformation/ActiveMidnightWalletAddresses/ActiveMidnightWalletAddresses.d.ts +9 -0
  62. package/src/lib/widgets/DynamicWidget/components/ActiveWalletInformation/ActiveMidnightWalletAddresses/ActiveMidnightWalletAddresses.js +120 -0
  63. package/src/lib/widgets/DynamicWidget/components/ActiveWalletInformation/ActiveMidnightWalletAddresses/index.d.ts +1 -0
  64. package/src/lib/widgets/DynamicWidget/components/ActiveWalletInformation/ActiveWalletInformation.cjs +21 -10
  65. package/src/lib/widgets/DynamicWidget/components/ActiveWalletInformation/ActiveWalletInformation.js +22 -11
  66. package/src/lib/widgets/DynamicWidget/components/WalletDetailsCard/WalletDetailsCard.cjs +22 -2
  67. package/src/lib/widgets/DynamicWidget/components/WalletDetailsCard/WalletDetailsCard.d.ts +8 -1
  68. package/src/lib/widgets/DynamicWidget/components/WalletDetailsCard/WalletDetailsCard.js +23 -3
@@ -0,0 +1,439 @@
1
+ 'use client'
2
+ import { __awaiter } from '../../../../../_virtual/_tslib.js';
3
+ import { useState, useRef, useCallback, useEffect } from 'react';
4
+ import { ChainEnum } from '@dynamic-labs/sdk-api-core';
5
+ import '../../../context/DynamicContext/DynamicContext.js';
6
+ import '../../../store/state/loadingAndLifecycle/loadingAndLifecycle.js';
7
+ import '@dynamic-labs/iconic';
8
+ import '@dynamic-labs/wallet-connector-core';
9
+ import 'react/jsx-runtime';
10
+ import '../../../context/ViewContext/ViewContext.js';
11
+ import '../../../shared/logger.js';
12
+ import '@dynamic-labs/wallet-book';
13
+ import '@dynamic-labs/utils';
14
+ import '../../constants/colors.js';
15
+ import '../../constants/values.js';
16
+ import '../../../shared/consts/index.js';
17
+ import '../../../events/dynamicEvents.js';
18
+ import '../../../context/CaptchaContext/CaptchaContext.js';
19
+ import '../../../context/ErrorContext/ErrorContext.js';
20
+ import '@dynamic-labs/multi-wallet';
21
+ import 'react-international-phone';
22
+ import '../../../store/state/nonce/nonce.js';
23
+ import '@dynamic-labs-sdk/client/core';
24
+ import 'eventemitter3';
25
+ import '@dynamic-labs-sdk/client';
26
+ import '../../../config/ApiEndpoint.js';
27
+ import '@dynamic-labs/locale';
28
+ import { getEnvironmentId } from '../../../store/state/dynamicContextProps/dynamicContextProps.js';
29
+ import '../../../store/state/primaryWalletId/primaryWalletId.js';
30
+ import '../../../store/state/connectedWalletsInfo/connectedWalletsInfo.js';
31
+ import '../../functions/getWaasAddressTypeLabel/getWaasAddressTypeLabel.js';
32
+ import '../../../context/AccessDeniedContext/AccessDeniedContext.js';
33
+ import '../../../context/AccountExistsContext/AccountExistsContext.js';
34
+ import '../../../context/UserWalletsContext/UserWalletsContext.js';
35
+ import '../../../store/state/authMode/authMode.js';
36
+ import '../../../context/VerificationContext/VerificationContext.js';
37
+ import 'react-dom';
38
+ import '../../functions/compareChains/compareChains.js';
39
+ import '../../../views/Passkey/utils/findPrimaryEmbeddedChain/findPrimaryEmbeddedChain.js';
40
+ import '../../../context/ThemeContext/ThemeContext.js';
41
+ import '../useUserUpdateRequest/useUpdateUser/userFieldsSchema.js';
42
+ import 'bs58';
43
+ import '@dynamic-labs/types';
44
+ import '../../../context/SocialRedirectContext/SocialRedirectContext.js';
45
+ import '../../../context/LoadingContext/LoadingContext.js';
46
+ import '../../../context/WalletContext/WalletContext.js';
47
+ import '../useEmbeddedWallet/useSecureEnclaveEmbeddedWallet/constants.js';
48
+ import 'yup';
49
+ import '../../../context/MockContext/MockContext.js';
50
+ import '../../../views/CollectUserDataView/useFields.js';
51
+ import '../../../context/FieldsStateContext/FieldsStateContext.js';
52
+ import '../../../context/UserFieldEditorContext/UserFieldEditorContext.js';
53
+ import '@dynamic-labs/rpc-providers';
54
+ import '../../../store/state/walletOptions/walletOptions.js';
55
+ import 'react-i18next';
56
+ import '../../../components/Accordion/components/AccordionItem/AccordionItem.js';
57
+ import '../../../components/Alert/Alert.js';
58
+ import '../../../components/ShadowDOM/ShadowDOM.js';
59
+ import '../../../components/IconButton/IconButton.js';
60
+ import '../../../components/InlineWidget/InlineWidget.js';
61
+ import '../../../components/Input/Input.js';
62
+ import '../../../components/IsBrowser/IsBrowser.js';
63
+ import '../../../components/MenuList/Dropdown/Dropdown.js';
64
+ import '../../../components/OverlayCard/OverlayCard.js';
65
+ import '../../../components/Transition/ZoomTransition/ZoomTransition.js';
66
+ import '../../../components/Transition/SlideInUpTransition/SlideInUpTransition.js';
67
+ import '../../../components/Transition/OpacityTransition/OpacityTransition.js';
68
+ import '../../../components/PasskeyCreatedSuccessBanner/PasskeyCreatedSuccessBanner.js';
69
+ import '../../../components/Popper/Popper/Popper.js';
70
+ import '../../../components/Popper/PopperContext/PopperContext.js';
71
+ import 'react-focus-lock';
72
+ import 'qrcode';
73
+ import 'formik';
74
+ import '../useSubdomainCheck/useSubdomainCheck.js';
75
+ import '../../../context/WalletGroupContext/WalletGroupContext.js';
76
+ import '../../../widgets/DynamicWidget/context/DynamicWidgetContext.js';
77
+ import '../useGetMfaToken/useGetMfaToken.js';
78
+ import '../useWalletBackup/useWalletBackup.js';
79
+ import '../useWalletBackup/types.js';
80
+ import '../useWalletBackup/cloudProviders.js';
81
+ import '../../../context/IpConfigurationContext/IpConfigurationContext.js';
82
+ import '../../../context/ConnectWithOtpContext/ConnectWithOtpContext.js';
83
+ import '../../../widgets/DynamicBridgeWidget/views/WalletsView/components/SecondaryWallets/SecondaryWallets.js';
84
+ import '@hcaptcha/react-hcaptcha';
85
+ import '../../../widgets/DynamicWidget/helpers/convertExchangeKeyAndProviderEnum.js';
86
+ import '../../../views/ExchangeWhitelistWarning/ExchangeWhitelistWarning.js';
87
+ import '../../../context/ErrorContext/hooks/useErrorText/useErrorText.js';
88
+ import '../../../context/FooterAnimationContext/index.js';
89
+ import '../../../views/MfaChooseDeviceView/useGetMfaOptions/useGetMfaOptions.js';
90
+ import '../../../context/PasskeyContext/PasskeyContext.js';
91
+ import '../../../context/OnrampContext/OnrampContext.js';
92
+ import '../../../store/state/sendBalances.js';
93
+ import '../../../store/state/connectorsInitializing/connectorsInitializing.js';
94
+ import '../../../components/OverlayCardBase/OverlayCardTarget/OverlayCardTarget.js';
95
+ import '../../../widgets/DynamicWidget/components/DynamicWidgetHeader/DynamicWidgetHeader.js';
96
+ import '../../../views/TransactionConfirmationView/TransactionConfirmationView.js';
97
+ import '../../../widgets/DynamicWidget/components/PasskeyCard/PasskeyCard.js';
98
+ import '../../../widgets/DynamicWidget/views/CryptoComOnramp/CryptoComOnramp.js';
99
+ import '../../../../index.js';
100
+ import '../../../widgets/DynamicWidget/views/ManagePasskeysMfaWidgetView/ManagePasskeysMfaWidgetView.js';
101
+ import '../../../widgets/DynamicWidget/views/ManageTotpMfaWidgetView/ManageTotpMfaWidgetView.js';
102
+ import '../../../widgets/DynamicWidget/views/ReceiveWalletFunds/ReceiveWalletFunds.js';
103
+ import '../../../store/state/tokenBalances.js';
104
+ import '../../../store/state/multichainBalances.js';
105
+ import '@dynamic-labs/store';
106
+ import '../../../shared/utils/functions/getInitialUrl/getInitialUrl.js';
107
+ import { useInternalDynamicContext } from '../../../context/DynamicContext/useDynamicContext/useInternalDynamicContext/useInternalDynamicContext.js';
108
+ import { getAleoCuratedPrices } from '../../../data/api/aleo/getAleoCuratedPrices.js';
109
+
110
+ const MICROCREDITS_PER_CREDIT = 1000000;
111
+ const ALEO_CREDITS_LOGO = 'https://app.dynamic.xyz/assets/networks/aleo.svg';
112
+ // Generic dark "?" token icon — matches redcoast's `DEFAULT_TOKEN_LOGO_URI`
113
+ // used by the multichain endpoint when an unshielded token has no curated
114
+ // logo. Reusing it here keeps the Shielded tab visually consistent with
115
+ // the Unshielded tab for the same token.
116
+ const UNKNOWN_TOKEN_LOGO = 'https://app.dynamic.xyz/assets/tokens/unknown.svg';
117
+ const TOKEN_REGISTRY_PROGRAM = 'token_registry.aleo';
118
+ const TOKEN_REGISTRY_RECORD = 'Token';
119
+ // Non-credits tokens deliberately omit `logoURI` — Aleo doesn't have a
120
+ // curated icon list yet, so leaving it undefined surfaces the widget's
121
+ // generic placeholder (`?` skeleton) consistent with the unshielded feed.
122
+ const KNOWN_SHIELDED_TOKENS = [
123
+ {
124
+ contractAddress: 'usad_stablecoin.aleo',
125
+ decimals: 6,
126
+ name: 'USAD',
127
+ programName: 'usad_stablecoin.aleo',
128
+ recordName: 'Token',
129
+ symbol: 'USAD',
130
+ },
131
+ {
132
+ contractAddress: 'test_usad_stablecoin.aleo',
133
+ decimals: 6,
134
+ name: 'USAD',
135
+ programName: 'test_usad_stablecoin.aleo',
136
+ recordName: 'Token',
137
+ symbol: 'USAD',
138
+ },
139
+ {
140
+ contractAddress: 'usdcx_stablecoin.aleo',
141
+ decimals: 6,
142
+ name: 'USDCx',
143
+ programName: 'usdcx_stablecoin.aleo',
144
+ recordName: 'Token',
145
+ symbol: 'USDCx',
146
+ },
147
+ {
148
+ contractAddress: 'test_usdcx_stablecoin.aleo',
149
+ decimals: 6,
150
+ name: 'USDCx',
151
+ programName: 'test_usdcx_stablecoin.aleo',
152
+ recordName: 'Token',
153
+ symbol: 'USDCx',
154
+ },
155
+ // ARC-21 (Hyperlane warp routes) — mainnet only. Token IDs match the
156
+ // values pinned in `packages/aleo/src/utils/aleoSendableTokens` and the
157
+ // redcoast `aleoArc21Tokens` registry. Decimals match each token's
158
+ // `token_info` metadata on-chain.
159
+ {
160
+ contractAddress: 'hyp_warp_token_sol.aleo',
161
+ decimals: 9,
162
+ name: 'Wrapped SOL',
163
+ programName: TOKEN_REGISTRY_PROGRAM,
164
+ recordName: TOKEN_REGISTRY_RECORD,
165
+ symbol: 'wSOL',
166
+ tokenId: '2045969100091121326225168054634646230244820821909676777152465722877810201564field',
167
+ },
168
+ {
169
+ contractAddress: 'hyp_warp_token_eth.aleo',
170
+ decimals: 18,
171
+ name: 'Wrapped ETH',
172
+ programName: TOKEN_REGISTRY_PROGRAM,
173
+ recordName: TOKEN_REGISTRY_RECORD,
174
+ symbol: 'wETH',
175
+ tokenId: '8189585964265444162798552221009403350643900573290534096996249214099143169251field',
176
+ },
177
+ {
178
+ contractAddress: 'hyp_warp_token_wbtc.aleo',
179
+ decimals: 8,
180
+ name: 'Wrapped BTC',
181
+ programName: TOKEN_REGISTRY_PROGRAM,
182
+ recordName: TOKEN_REGISTRY_RECORD,
183
+ symbol: 'wBTC',
184
+ tokenId: '3491859903473482085250871387962132231204352466326026409883548131580582527809field',
185
+ },
186
+ {
187
+ contractAddress: 'hyp_warp_token_usdt.aleo',
188
+ decimals: 6,
189
+ name: 'Tether USD',
190
+ programName: TOKEN_REGISTRY_PROGRAM,
191
+ recordName: TOKEN_REGISTRY_RECORD,
192
+ symbol: 'USDT',
193
+ tokenId: '7881654794448182580124231856035865816599796419758925654292946277940935117913field',
194
+ },
195
+ {
196
+ contractAddress: 'hyp_warp_token_usdc.aleo',
197
+ decimals: 6,
198
+ name: 'USD Coin',
199
+ programName: TOKEN_REGISTRY_PROGRAM,
200
+ recordName: TOKEN_REGISTRY_RECORD,
201
+ symbol: 'USDC',
202
+ tokenId: '4697275201844475848710842677807162058146139844643350200269139278887318953049field',
203
+ },
204
+ ];
205
+ /**
206
+ * Match a record to a shielded-token spec. Stablecoins match on
207
+ * (program, record); ARC-21 entries additionally require the spec's
208
+ * `tokenId` to appear inside `record_plaintext` (since every ARC-21 token
209
+ * shares `token_registry.aleo / Token`).
210
+ */
211
+ const findTokenSpec = (record) => {
212
+ for (const spec of KNOWN_SHIELDED_TOKENS) {
213
+ if (record.program_name !== spec.programName)
214
+ continue;
215
+ if (record.record_name !== spec.recordName)
216
+ continue;
217
+ if (spec.tokenId) {
218
+ if (typeof record.record_plaintext !== 'string' ||
219
+ !record.record_plaintext.includes(`token_id: ${spec.tokenId}`)) {
220
+ continue;
221
+ }
222
+ }
223
+ return spec;
224
+ }
225
+ return undefined;
226
+ };
227
+ /**
228
+ * Coerces the widget-context `network` value into an Aleo network id
229
+ * (`0 = mainnet`, `1 = testnet`) and the matching param string for the
230
+ * `/waas/aleo/prices` endpoint. Pulled out of the callback to flatten
231
+ * cognitive complexity AND to avoid a SonarCloud-flagged nested
232
+ * ternary.
233
+ */
234
+ const resolveAleoNetwork = (networkKey) => {
235
+ const numeric = Number(networkKey);
236
+ const safeNetworkId = Number.isFinite(numeric) ? numeric : undefined;
237
+ if (safeNetworkId === 0)
238
+ return { aleoNetworkParam: 'mainnet', safeNetworkId };
239
+ if (safeNetworkId === 1)
240
+ return { aleoNetworkParam: 'testnet', safeNetworkId };
241
+ return { aleoNetworkParam: undefined, safeNetworkId };
242
+ };
243
+ /**
244
+ * Build a `(address, isNative) → price` lookup from the curated-prices
245
+ * endpoint response. The key shape matches the multichain balance feed
246
+ * (native ALEO at `'0x0' + isNative=true`, every other token at its
247
+ * program id + `isNative=false`) so the join is a straight read.
248
+ */
249
+ const buildPriceLookup = (priceList) => {
250
+ const priceByKey = new Map();
251
+ for (const entry of priceList) {
252
+ priceByKey.set(`${entry.address}|${entry.isNative ? 1 : 0}`, entry.price);
253
+ }
254
+ return (address, isNative) => { var _a; return (_a = priceByKey.get(`${address}|${isNative ? 1 : 0}`)) !== null && _a !== void 0 ? _a : null; };
255
+ };
256
+ /**
257
+ * Aggregate `credits.aleo / credits` records into the native ALEO
258
+ * `TokenBalance`. Returns `undefined` when the wallet owns no credits
259
+ * records so the caller can omit the row entirely.
260
+ */
261
+ const buildCreditsBalance = (records, networkId, priceFor) => {
262
+ const creditsRecords = records.filter((r) => (r === null || r === void 0 ? void 0 : r.program_name) === 'credits.aleo' &&
263
+ (r === null || r === void 0 ? void 0 : r.record_name) === 'credits' &&
264
+ typeof (r === null || r === void 0 ? void 0 : r.microcredits) === 'string');
265
+ if (creditsRecords.length === 0)
266
+ return undefined;
267
+ const totalMicrocredits = creditsRecords.reduce((sum, r) => sum + BigInt(r.microcredits), BigInt(0));
268
+ // BigInt → number for the TokenBalance shape. Aleo balances stay well
269
+ // below Number.MAX_SAFE_INTEGER for a single wallet (max u64 supply is
270
+ // 1.5B credits = 1.5e15 microcredits; Number can hold up to ~9e15).
271
+ const rawBalance = Number(totalMicrocredits);
272
+ const balance = rawBalance / MICROCREDITS_PER_CREDIT;
273
+ const price = priceFor('0x0', true);
274
+ return {
275
+ address: '0x0',
276
+ balance,
277
+ decimals: 6,
278
+ isNative: true,
279
+ logoURI: ALEO_CREDITS_LOGO,
280
+ marketValue: price !== null ? balance * price : undefined,
281
+ name: 'Aleo Credits',
282
+ networkId,
283
+ price: price !== null ? price : undefined,
284
+ rawBalance,
285
+ symbol: 'ALEO',
286
+ };
287
+ };
288
+ /**
289
+ * Aggregate stablecoin + ARC-21 `Token` records by `(program, tokenId)`
290
+ * and emit one `TokenBalance` per matched spec. Records that don't
291
+ * match a curated spec, lack an `amount`, or have a malformed amount
292
+ * string are silently skipped.
293
+ */
294
+ const buildTokenBalances = (records, networkId, priceFor) => {
295
+ var _a, _b;
296
+ const sumsByContract = new Map();
297
+ const specsByContract = new Map();
298
+ for (const r of records) {
299
+ const spec = findTokenSpec(r);
300
+ if (!spec || typeof r.amount !== 'string')
301
+ continue;
302
+ try {
303
+ const prev = (_a = sumsByContract.get(spec.contractAddress)) !== null && _a !== void 0 ? _a : BigInt(0);
304
+ sumsByContract.set(spec.contractAddress, prev + BigInt(r.amount));
305
+ specsByContract.set(spec.contractAddress, spec);
306
+ }
307
+ catch (_c) {
308
+ /* ignore — malformed amount string */
309
+ }
310
+ }
311
+ const out = [];
312
+ for (const [contractAddress, total] of sumsByContract.entries()) {
313
+ const spec = specsByContract.get(contractAddress);
314
+ if (!spec)
315
+ continue;
316
+ const rawBalance = Number(total);
317
+ const balance = rawBalance / Math.pow(10, spec.decimals);
318
+ const price = priceFor(spec.contractAddress, false);
319
+ out.push({
320
+ address: spec.contractAddress,
321
+ balance,
322
+ decimals: spec.decimals,
323
+ // Use redcoast's `DEFAULT_TOKEN_LOGO_URI` for stablecoins + ARC-21
324
+ // so they render the same dark "?" icon the Unshielded tab shows
325
+ // for these tokens (the multichain endpoint applies that fallback
326
+ // itself; we mirror it here for visual parity).
327
+ logoURI: (_b = spec.logoURI) !== null && _b !== void 0 ? _b : UNKNOWN_TOKEN_LOGO,
328
+ marketValue: price !== null ? balance * price : undefined,
329
+ name: spec.name,
330
+ networkId,
331
+ price: price !== null ? price : undefined,
332
+ rawBalance,
333
+ symbol: spec.symbol,
334
+ });
335
+ }
336
+ return out;
337
+ };
338
+ /**
339
+ * Hook that returns the active wallet's shielded (private) Aleo token
340
+ * balances as a `TokenBalance[]` so the widget can render them through the
341
+ * same TokenBalanceList path it uses for unshielded balances.
342
+ *
343
+ * - Records come from the iframe via `connector.listOwnedRecords()` (the
344
+ * Provable RecordScanner; view key never leaves the iframe).
345
+ * - Aggregates `credits.aleo/credits` (sum `microcredits` → ALEO) plus any
346
+ * tier-3 stablecoin Token records (sum `amount` per program → USAD/USDCx).
347
+ * ARC-21 multi-token grouped-by-`token_id` is Phase 2B.
348
+ *
349
+ * Returns an empty list when:
350
+ * - The wallet isn't Aleo
351
+ * - The connector doesn't expose `listOwnedRecords` (e.g. external Aleo wallet)
352
+ * - The user owns no records that match a known program/record pair
353
+ */
354
+ const useAleoShieldedBalances = () => {
355
+ const { primaryWallet, network } = useInternalDynamicContext();
356
+ const [tokenBalances, setTokenBalances] = useState([]);
357
+ const [isLoading, setIsLoading] = useState(false);
358
+ const [error, setError] = useState();
359
+ const connector = primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.connector;
360
+ const isAleo = (connector === null || connector === void 0 ? void 0 : connector.connectedChain) === ChainEnum.Aleo;
361
+ const supportsShielded = isAleo &&
362
+ typeof (connector === null || connector === void 0 ? void 0 : connector.listOwnedRecords) === 'function';
363
+ // Mirror the live connector into a ref so `fetchShielded` can read it
364
+ // without depending on the (often unstable) object reference. Some test
365
+ // setups mock context with a factory that returns a fresh `primaryWallet`
366
+ // every render — depending on that ref directly turned this into an
367
+ // infinite render loop.
368
+ const connectorRef = useRef(connector);
369
+ connectorRef.current = connector;
370
+ const connectorKey = connector === null || connector === void 0 ? void 0 : connector.key;
371
+ const networkKey = network !== undefined && network !== null ? String(network) : undefined;
372
+ const fetchShielded = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
373
+ var _a;
374
+ const liveConnector = connectorRef.current;
375
+ if (!supportsShielded || !liveConnector) {
376
+ setTokenBalances((prev) => (prev.length === 0 ? prev : []));
377
+ return;
378
+ }
379
+ setIsLoading(true);
380
+ setError(undefined);
381
+ try {
382
+ // Fetch records and the curated-token price list in parallel. The
383
+ // price list comes from the Aleo-only `/waas/aleo/prices` endpoint
384
+ // (independent of balance) so the join works even when the user
385
+ // holds a shielded token with zero unshielded balance — the
386
+ // multichain `/accountBalances` endpoint would have stripped that
387
+ // token row, leaving the widget with no price source. Prices are
388
+ // best-effort: a failure leaves balances unpriced rather than
389
+ // dropping the shielded list entirely.
390
+ const { safeNetworkId, aleoNetworkParam } = resolveAleoNetwork(networkKey);
391
+ const environmentId = getEnvironmentId();
392
+ const shouldFetchPrices = Boolean(aleoNetworkParam && environmentId);
393
+ const [result, priceList] = yield Promise.all([
394
+ liveConnector.listOwnedRecords(),
395
+ shouldFetchPrices && aleoNetworkParam
396
+ ? getAleoCuratedPrices({
397
+ environmentId,
398
+ network: aleoNetworkParam,
399
+ }).catch(() => [])
400
+ : Promise.resolve([]),
401
+ ]);
402
+ const records = (_a = result === null || result === void 0 ? void 0 : result.records) !== null && _a !== void 0 ? _a : [];
403
+ const priceFor = buildPriceLookup(priceList);
404
+ const balances = [];
405
+ const credits = buildCreditsBalance(records, safeNetworkId, priceFor);
406
+ if (credits)
407
+ balances.push(credits);
408
+ balances.push(...buildTokenBalances(records, safeNetworkId, priceFor));
409
+ setTokenBalances(balances);
410
+ }
411
+ catch (err) {
412
+ const msg = err instanceof Error ? err.message : String(err);
413
+ setError(msg);
414
+ setTokenBalances((prev) => (prev.length === 0 ? prev : []));
415
+ }
416
+ finally {
417
+ setIsLoading(false);
418
+ }
419
+ }), [connectorKey, networkKey, supportsShielded]);
420
+ useEffect(() => {
421
+ if (!supportsShielded) {
422
+ setTokenBalances((prev) => (prev.length === 0 ? prev : []));
423
+ return;
424
+ }
425
+ fetchShielded().catch(() => {
426
+ // fetchShielded already records the error in component state;
427
+ // the .catch keeps the fire-and-forget shape lint-clean.
428
+ });
429
+ }, [supportsShielded, fetchShielded]);
430
+ return {
431
+ error,
432
+ isLoading,
433
+ refetch: fetchShielded,
434
+ supportsShielded,
435
+ tokenBalances,
436
+ };
437
+ };
438
+
439
+ export { useAleoShieldedBalances };
@@ -119,6 +119,7 @@ var useInternalDynamicContext = require('../../../context/DynamicContext/useDyna
119
119
 
120
120
  // Hook exposed to customers and used internally to trigger embedded wallet creation
121
121
  /**
122
+ * @deprecated This hook is deprecated and will be removed in a future release. Use `useDynamicWaas` instead.
122
123
  * @returns {
123
124
  * createEmbeddedWallet, - creates Dynamic embedded wallet according to the settings
124
125
  * createOrRestoreSession, - creates or restores session for the embedded wallet
@@ -1,6 +1,7 @@
1
1
  import { EmbeddedWalletChainEnum, EmbeddedWalletVersionEnum } from '@dynamic-labs/sdk-api-core';
2
2
  import { Wallet } from '../../../shared';
3
3
  /**
4
+ * @deprecated This hook is deprecated and will be removed in a future release. Use `useDynamicWaas` instead.
4
5
  * @returns {
5
6
  * createEmbeddedWallet, - creates Dynamic embedded wallet according to the settings
6
7
  * createOrRestoreSession, - creates or restores session for the embedded wallet
@@ -115,6 +115,7 @@ import { useInternalDynamicContext } from '../../../context/DynamicContext/useDy
115
115
 
116
116
  // Hook exposed to customers and used internally to trigger embedded wallet creation
117
117
  /**
118
+ * @deprecated This hook is deprecated and will be removed in a future release. Use `useDynamicWaas` instead.
118
119
  * @returns {
119
120
  * createEmbeddedWallet, - creates Dynamic embedded wallet according to the settings
120
121
  * createOrRestoreSession, - creates or restores session for the embedded wallet
@@ -132,8 +132,19 @@ const BackupUnsuccessfulView = () => {
132
132
  const refreshPage = () => {
133
133
  window.location.reload();
134
134
  };
135
+ const onTryAgainClick = () => {
136
+ logger.logger.instrument('Wallet creation retry modal try again clicked', {
137
+ key: 'wallet_creation_retry_modal_try_again_clicked',
138
+ time: 0,
139
+ });
140
+ refreshPage();
141
+ };
135
142
  // force refresh on component unmount
136
143
  React.useEffect(() => {
144
+ logger.logger.instrument('Wallet creation retry modal shown', {
145
+ key: 'wallet_creation_retry_modal_shown',
146
+ time: 0,
147
+ });
137
148
  const timer = setTimeout(() => {
138
149
  isProperlyMounted.current = true;
139
150
  }, 100);
@@ -154,7 +165,7 @@ const BackupUnsuccessfulView = () => {
154
165
  transform: 'translate(-50%, -50%)',
155
166
  } })] })] }), jsxRuntime.jsx(Typography.Typography, { variant: 'body_normal', className: 'backup-message', color: 'primary', copykey: 'dyn_waas.backup_unsuccessful.description', children: t('dyn_waas.backup_unsuccessful.description') }), jsxRuntime.jsx("div", { className: classNames.classNames('button-group', {
156
167
  'button-group--with-help-section': hasContactInfo,
157
- }), children: jsxRuntime.jsx(TypographyButton.TypographyButton, { buttonClassName: 'retry-button', buttonVariant: 'brand-primary', type: 'submit', onClick: () => refreshPage(), copykey: 'dyn_waas.backup_unsuccessful.try_again', typographyProps: {
168
+ }), children: jsxRuntime.jsx(TypographyButton.TypographyButton, { buttonClassName: 'retry-button', buttonVariant: 'brand-primary', type: 'submit', onClick: onTryAgainClick, copykey: 'dyn_waas.backup_unsuccessful.try_again', typographyProps: {
158
169
  color: 'inherit',
159
170
  }, children: t('dyn_waas.backup_unsuccessful.try_again') }) }), jsxRuntime.jsx("div", { className: classNames.classNames('button-group', 'logout-group', {
160
171
  'button-group--with-help-section': hasContactInfo,
@@ -128,8 +128,19 @@ const BackupUnsuccessfulView = () => {
128
128
  const refreshPage = () => {
129
129
  window.location.reload();
130
130
  };
131
+ const onTryAgainClick = () => {
132
+ logger.instrument('Wallet creation retry modal try again clicked', {
133
+ key: 'wallet_creation_retry_modal_try_again_clicked',
134
+ time: 0,
135
+ });
136
+ refreshPage();
137
+ };
131
138
  // force refresh on component unmount
132
139
  useEffect(() => {
140
+ logger.instrument('Wallet creation retry modal shown', {
141
+ key: 'wallet_creation_retry_modal_shown',
142
+ time: 0,
143
+ });
133
144
  const timer = setTimeout(() => {
134
145
  isProperlyMounted.current = true;
135
146
  }, 100);
@@ -150,7 +161,7 @@ const BackupUnsuccessfulView = () => {
150
161
  transform: 'translate(-50%, -50%)',
151
162
  } })] })] }), jsx(Typography, { variant: 'body_normal', className: 'backup-message', color: 'primary', copykey: 'dyn_waas.backup_unsuccessful.description', children: t('dyn_waas.backup_unsuccessful.description') }), jsx("div", { className: classNames('button-group', {
152
163
  'button-group--with-help-section': hasContactInfo,
153
- }), children: jsx(TypographyButton, { buttonClassName: 'retry-button', buttonVariant: 'brand-primary', type: 'submit', onClick: () => refreshPage(), copykey: 'dyn_waas.backup_unsuccessful.try_again', typographyProps: {
164
+ }), children: jsx(TypographyButton, { buttonClassName: 'retry-button', buttonVariant: 'brand-primary', type: 'submit', onClick: onTryAgainClick, copykey: 'dyn_waas.backup_unsuccessful.try_again', typographyProps: {
154
165
  color: 'inherit',
155
166
  }, children: t('dyn_waas.backup_unsuccessful.try_again') }) }), jsx("div", { className: classNames('button-group', 'logout-group', {
156
167
  'button-group--with-help-section': hasContactInfo,
@@ -183,6 +183,52 @@ const SendBalanceView = ({ initialRecipientAddress = '', initialValue, onClickBa
183
183
  if (orderedTokenBalances)
184
184
  setTokenBalances(orderedTokenBalances);
185
185
  }, [orderedTokenBalances]);
186
+ // Chain override: when the active IUITransaction provides
187
+ // `getSendableTokenBalances`, prefer that list for the picker. Used by
188
+ // chains where the spendable balance source diverges from
189
+ // `useTokenBalances` (e.g. Aleo Send always spends from private
190
+ // records, not the public-balance mapping redcoast returns). Chains
191
+ // that don't implement the method get the default fetcher unchanged.
192
+ //
193
+ // Also re-anchors `currentToken` to the matching entry in the override
194
+ // list. Without this, the picker's row renders the override balance
195
+ // (it reads from `tokenBalances`) but the form's "Available" line
196
+ // renders the original public balance (it reads from `currentToken`),
197
+ // which is stale.
198
+ React.useEffect(() => {
199
+ if (!(transaction === null || transaction === void 0 ? void 0 : transaction.getSendableTokenBalances))
200
+ return;
201
+ let cancelled = false;
202
+ transaction
203
+ .getSendableTokenBalances()
204
+ .then((overrideBalances) => {
205
+ if (cancelled)
206
+ return;
207
+ if (!overrideBalances || overrideBalances.length === 0)
208
+ return;
209
+ setTokenBalances(overrideBalances);
210
+ setCurrentToken((prev) => {
211
+ if (!prev)
212
+ return overrideBalances[0];
213
+ const match = overrideBalances.find((t) => t.address === prev.address);
214
+ if (!match)
215
+ return overrideBalances[0];
216
+ // Skip the swap if values are unchanged — avoids a re-render
217
+ // loop when transaction recreation re-fires this effect.
218
+ if (match.rawBalance === prev.rawBalance &&
219
+ match.balance === prev.balance) {
220
+ return prev;
221
+ }
222
+ return match;
223
+ });
224
+ })
225
+ .catch((err) => {
226
+ logger.logger.debug('[SendBalanceView] getSendableTokenBalances threw — falling back to default token list', err);
227
+ });
228
+ return () => {
229
+ cancelled = true;
230
+ };
231
+ }, [transaction]);
186
232
  React.useEffect(() => {
187
233
  if (!walletConnector)
188
234
  return;
@@ -201,6 +247,13 @@ const SendBalanceView = ({ initialRecipientAddress = '', initialValue, onClickBa
201
247
  transaction.nonNativeValue = BigInt(0);
202
248
  transaction.nonNativeDecimal = currentToken === null || currentToken === void 0 ? void 0 : currentToken.decimals;
203
249
  }
250
+ // Chain hook: tells the transaction which picker entry the user
251
+ // landed on (or just switched to). Aleo uses this to flip submit
252
+ // between credits / stablecoin / ARC-21 program signatures + to
253
+ // re-anchor decimals for parse/format.
254
+ if (currentToken && transaction.setSelectedToken) {
255
+ transaction.setSelectedToken(currentToken.address);
256
+ }
204
257
  setTransaction(transaction);
205
258
  })
206
259
  .catch((error) => {
@@ -179,6 +179,52 @@ const SendBalanceView = ({ initialRecipientAddress = '', initialValue, onClickBa
179
179
  if (orderedTokenBalances)
180
180
  setTokenBalances(orderedTokenBalances);
181
181
  }, [orderedTokenBalances]);
182
+ // Chain override: when the active IUITransaction provides
183
+ // `getSendableTokenBalances`, prefer that list for the picker. Used by
184
+ // chains where the spendable balance source diverges from
185
+ // `useTokenBalances` (e.g. Aleo Send always spends from private
186
+ // records, not the public-balance mapping redcoast returns). Chains
187
+ // that don't implement the method get the default fetcher unchanged.
188
+ //
189
+ // Also re-anchors `currentToken` to the matching entry in the override
190
+ // list. Without this, the picker's row renders the override balance
191
+ // (it reads from `tokenBalances`) but the form's "Available" line
192
+ // renders the original public balance (it reads from `currentToken`),
193
+ // which is stale.
194
+ useEffect(() => {
195
+ if (!(transaction === null || transaction === void 0 ? void 0 : transaction.getSendableTokenBalances))
196
+ return;
197
+ let cancelled = false;
198
+ transaction
199
+ .getSendableTokenBalances()
200
+ .then((overrideBalances) => {
201
+ if (cancelled)
202
+ return;
203
+ if (!overrideBalances || overrideBalances.length === 0)
204
+ return;
205
+ setTokenBalances(overrideBalances);
206
+ setCurrentToken((prev) => {
207
+ if (!prev)
208
+ return overrideBalances[0];
209
+ const match = overrideBalances.find((t) => t.address === prev.address);
210
+ if (!match)
211
+ return overrideBalances[0];
212
+ // Skip the swap if values are unchanged — avoids a re-render
213
+ // loop when transaction recreation re-fires this effect.
214
+ if (match.rawBalance === prev.rawBalance &&
215
+ match.balance === prev.balance) {
216
+ return prev;
217
+ }
218
+ return match;
219
+ });
220
+ })
221
+ .catch((err) => {
222
+ logger.debug('[SendBalanceView] getSendableTokenBalances threw — falling back to default token list', err);
223
+ });
224
+ return () => {
225
+ cancelled = true;
226
+ };
227
+ }, [transaction]);
182
228
  useEffect(() => {
183
229
  if (!walletConnector)
184
230
  return;
@@ -197,6 +243,13 @@ const SendBalanceView = ({ initialRecipientAddress = '', initialValue, onClickBa
197
243
  transaction.nonNativeValue = BigInt(0);
198
244
  transaction.nonNativeDecimal = currentToken === null || currentToken === void 0 ? void 0 : currentToken.decimals;
199
245
  }
246
+ // Chain hook: tells the transaction which picker entry the user
247
+ // landed on (or just switched to). Aleo uses this to flip submit
248
+ // between credits / stablecoin / ARC-21 program signatures + to
249
+ // re-anchor decimals for parse/format.
250
+ if (currentToken && transaction.setSelectedToken) {
251
+ transaction.setSelectedToken(currentToken.address);
252
+ }
200
253
  setTransaction(transaction);
201
254
  })
202
255
  .catch((error) => {