@dynamic-labs/sdk-react-core 4.80.0 → 4.81.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 (33) hide show
  1. package/CHANGELOG.md +16 -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/styles/index.shadow.cjs +1 -1
  15. package/src/lib/styles/index.shadow.js +1 -1
  16. package/src/lib/utils/hooks/useAleoShieldedBalances/index.d.ts +1 -0
  17. package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.cjs +372 -0
  18. package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.d.ts +24 -0
  19. package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.js +368 -0
  20. package/src/lib/utils/hooks/useEmbeddedWallet/useEmbeddedWallet.cjs +1 -0
  21. package/src/lib/utils/hooks/useEmbeddedWallet/useEmbeddedWallet.d.ts +1 -0
  22. package/src/lib/utils/hooks/useEmbeddedWallet/useEmbeddedWallet.js +1 -0
  23. package/src/lib/views/SendBalanceView/SendBalanceView.cjs +53 -0
  24. package/src/lib/views/SendBalanceView/SendBalanceView.js +53 -0
  25. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/ActiveWalletBalance.cjs +191 -11
  26. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/ActiveWalletBalance.js +191 -11
  27. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceItem/TokenBalanceItem.cjs +5 -2
  28. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceItem/TokenBalanceItem.d.ts +10 -1
  29. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceItem/TokenBalanceItem.js +5 -2
  30. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceItem/index.d.ts +1 -0
  31. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceList/TokenBalanceList.cjs +2 -2
  32. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceList/TokenBalanceList.d.ts +3 -1
  33. package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceList/TokenBalanceList.js +2 -2
@@ -0,0 +1,368 @@
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 '../../../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
+
109
+ const MICROCREDITS_PER_CREDIT = 1000000;
110
+ const ALEO_CREDITS_LOGO = 'https://app.dynamic.xyz/assets/networks/aleo.svg';
111
+ // Generic dark "?" token icon — matches redcoast's `DEFAULT_TOKEN_LOGO_URI`
112
+ // used by the multichain endpoint when an unshielded token has no curated
113
+ // logo. Reusing it here keeps the Shielded tab visually consistent with
114
+ // the Unshielded tab for the same token.
115
+ const UNKNOWN_TOKEN_LOGO = 'https://app.dynamic.xyz/assets/tokens/unknown.svg';
116
+ const TOKEN_REGISTRY_PROGRAM = 'token_registry.aleo';
117
+ const TOKEN_REGISTRY_RECORD = 'Token';
118
+ // Non-credits tokens deliberately omit `logoURI` — Aleo doesn't have a
119
+ // curated icon list yet, so leaving it undefined surfaces the widget's
120
+ // generic placeholder (`?` skeleton) consistent with the unshielded feed.
121
+ const KNOWN_SHIELDED_TOKENS = [
122
+ {
123
+ contractAddress: 'usad_stablecoin.aleo',
124
+ decimals: 6,
125
+ name: 'USAD',
126
+ programName: 'usad_stablecoin.aleo',
127
+ recordName: 'Token',
128
+ symbol: 'USAD',
129
+ },
130
+ {
131
+ contractAddress: 'test_usad_stablecoin.aleo',
132
+ decimals: 6,
133
+ name: 'USAD',
134
+ programName: 'test_usad_stablecoin.aleo',
135
+ recordName: 'Token',
136
+ symbol: 'USAD',
137
+ },
138
+ {
139
+ contractAddress: 'usdcx_stablecoin.aleo',
140
+ decimals: 6,
141
+ name: 'USDCx',
142
+ programName: 'usdcx_stablecoin.aleo',
143
+ recordName: 'Token',
144
+ symbol: 'USDCx',
145
+ },
146
+ {
147
+ contractAddress: 'test_usdcx_stablecoin.aleo',
148
+ decimals: 6,
149
+ name: 'USDCx',
150
+ programName: 'test_usdcx_stablecoin.aleo',
151
+ recordName: 'Token',
152
+ symbol: 'USDCx',
153
+ },
154
+ // ARC-21 (Hyperlane warp routes) — mainnet only. Token IDs match the
155
+ // values pinned in `packages/aleo/src/utils/aleoSendableTokens` and the
156
+ // redcoast `aleoArc21Tokens` registry. Decimals match each token's
157
+ // `token_info` metadata on-chain.
158
+ {
159
+ contractAddress: 'hyp_warp_token_sol.aleo',
160
+ decimals: 9,
161
+ name: 'Wrapped SOL',
162
+ programName: TOKEN_REGISTRY_PROGRAM,
163
+ recordName: TOKEN_REGISTRY_RECORD,
164
+ symbol: 'wSOL',
165
+ tokenId: '2045969100091121326225168054634646230244820821909676777152465722877810201564field',
166
+ },
167
+ {
168
+ contractAddress: 'hyp_warp_token_eth.aleo',
169
+ decimals: 18,
170
+ name: 'Wrapped ETH',
171
+ programName: TOKEN_REGISTRY_PROGRAM,
172
+ recordName: TOKEN_REGISTRY_RECORD,
173
+ symbol: 'wETH',
174
+ tokenId: '8189585964265444162798552221009403350643900573290534096996249214099143169251field',
175
+ },
176
+ {
177
+ contractAddress: 'hyp_warp_token_wbtc.aleo',
178
+ decimals: 8,
179
+ name: 'Wrapped BTC',
180
+ programName: TOKEN_REGISTRY_PROGRAM,
181
+ recordName: TOKEN_REGISTRY_RECORD,
182
+ symbol: 'wBTC',
183
+ tokenId: '3491859903473482085250871387962132231204352466326026409883548131580582527809field',
184
+ },
185
+ {
186
+ contractAddress: 'hyp_warp_token_usdt.aleo',
187
+ decimals: 6,
188
+ name: 'Tether USD',
189
+ programName: TOKEN_REGISTRY_PROGRAM,
190
+ recordName: TOKEN_REGISTRY_RECORD,
191
+ symbol: 'USDT',
192
+ tokenId: '7881654794448182580124231856035865816599796419758925654292946277940935117913field',
193
+ },
194
+ {
195
+ contractAddress: 'hyp_warp_token_usdc.aleo',
196
+ decimals: 6,
197
+ name: 'USD Coin',
198
+ programName: TOKEN_REGISTRY_PROGRAM,
199
+ recordName: TOKEN_REGISTRY_RECORD,
200
+ symbol: 'USDC',
201
+ tokenId: '4697275201844475848710842677807162058146139844643350200269139278887318953049field',
202
+ },
203
+ ];
204
+ /**
205
+ * Match a record to a shielded-token spec. Stablecoins match on
206
+ * (program, record); ARC-21 entries additionally require the spec's
207
+ * `tokenId` to appear inside `record_plaintext` (since every ARC-21 token
208
+ * shares `token_registry.aleo / Token`).
209
+ */
210
+ const findTokenSpec = (record) => {
211
+ for (const spec of KNOWN_SHIELDED_TOKENS) {
212
+ if (record.program_name !== spec.programName)
213
+ continue;
214
+ if (record.record_name !== spec.recordName)
215
+ continue;
216
+ if (spec.tokenId) {
217
+ if (typeof record.record_plaintext !== 'string' ||
218
+ !record.record_plaintext.includes(`token_id: ${spec.tokenId}`)) {
219
+ continue;
220
+ }
221
+ }
222
+ return spec;
223
+ }
224
+ return undefined;
225
+ };
226
+ /**
227
+ * Hook that returns the active wallet's shielded (private) Aleo token
228
+ * balances as a `TokenBalance[]` so the widget can render them through the
229
+ * same TokenBalanceList path it uses for unshielded balances.
230
+ *
231
+ * - Records come from the iframe via `connector.listOwnedRecords()` (the
232
+ * Provable RecordScanner; view key never leaves the iframe).
233
+ * - Aggregates `credits.aleo/credits` (sum `microcredits` → ALEO) plus any
234
+ * tier-3 stablecoin Token records (sum `amount` per program → USAD/USDCx).
235
+ * ARC-21 multi-token grouped-by-`token_id` is Phase 2B.
236
+ *
237
+ * Returns an empty list when:
238
+ * - The wallet isn't Aleo
239
+ * - The connector doesn't expose `listOwnedRecords` (e.g. external Aleo wallet)
240
+ * - The user owns no records that match a known program/record pair
241
+ */
242
+ const useAleoShieldedBalances = () => {
243
+ const { primaryWallet, network } = useInternalDynamicContext();
244
+ const [tokenBalances, setTokenBalances] = useState([]);
245
+ const [isLoading, setIsLoading] = useState(false);
246
+ const [error, setError] = useState();
247
+ const connector = primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.connector;
248
+ const isAleo = (connector === null || connector === void 0 ? void 0 : connector.connectedChain) === ChainEnum.Aleo;
249
+ const supportsShielded = isAleo &&
250
+ typeof (connector === null || connector === void 0 ? void 0 : connector.listOwnedRecords) === 'function';
251
+ // Mirror the live connector into a ref so `fetchShielded` can read it
252
+ // without depending on the (often unstable) object reference. Some test
253
+ // setups mock context with a factory that returns a fresh `primaryWallet`
254
+ // every render — depending on that ref directly turned this into an
255
+ // infinite render loop.
256
+ const connectorRef = useRef(connector);
257
+ connectorRef.current = connector;
258
+ const connectorKey = connector === null || connector === void 0 ? void 0 : connector.key;
259
+ const networkKey = network !== undefined && network !== null ? String(network) : undefined;
260
+ const fetchShielded = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
261
+ var _a, _b, _c;
262
+ const liveConnector = connectorRef.current;
263
+ if (!supportsShielded || !liveConnector) {
264
+ setTokenBalances((prev) => (prev.length === 0 ? prev : []));
265
+ return;
266
+ }
267
+ setIsLoading(true);
268
+ setError(undefined);
269
+ try {
270
+ const result = yield liveConnector.listOwnedRecords();
271
+ const records = (_a = result === null || result === void 0 ? void 0 : result.records) !== null && _a !== void 0 ? _a : [];
272
+ const networkIdNumeric = Number(networkKey);
273
+ const safeNetworkId = Number.isFinite(networkIdNumeric)
274
+ ? networkIdNumeric
275
+ : undefined;
276
+ const balances = [];
277
+ // Tier 1: native credits — sum microcredits across credits.aleo records.
278
+ const creditsRecords = records.filter((r) => (r === null || r === void 0 ? void 0 : r.program_name) === 'credits.aleo' &&
279
+ (r === null || r === void 0 ? void 0 : r.record_name) === 'credits' &&
280
+ typeof (r === null || r === void 0 ? void 0 : r.microcredits) === 'string');
281
+ if (creditsRecords.length > 0) {
282
+ const totalMicrocredits = creditsRecords.reduce((sum, r) => sum + BigInt(r.microcredits), BigInt(0));
283
+ // BigInt → number for the TokenBalance shape. Aleo balances stay well
284
+ // below Number.MAX_SAFE_INTEGER for a single wallet (max u64 supply is
285
+ // 1.5B credits = 1.5e15 microcredits; Number can hold up to ~9e15).
286
+ const rawBalance = Number(totalMicrocredits);
287
+ balances.push({
288
+ address: '0x0',
289
+ balance: rawBalance / MICROCREDITS_PER_CREDIT,
290
+ decimals: 6,
291
+ isNative: true,
292
+ logoURI: ALEO_CREDITS_LOGO,
293
+ name: 'Aleo Credits',
294
+ networkId: safeNetworkId,
295
+ rawBalance,
296
+ symbol: 'ALEO',
297
+ });
298
+ }
299
+ // Tier 3 + ARC-21: Token records. Each record matches at most one
300
+ // spec (stablecoin programs disambiguate by program; ARC-21 records
301
+ // share `token_registry.aleo / Token` and disambiguate by tokenId
302
+ // inside the plaintext). Sum the `amount` field per spec.
303
+ const sumsByContract = new Map();
304
+ const specsByContract = new Map();
305
+ for (const r of records) {
306
+ const spec = findTokenSpec(r);
307
+ if (!spec || typeof r.amount !== 'string')
308
+ continue;
309
+ try {
310
+ const prev = (_b = sumsByContract.get(spec.contractAddress)) !== null && _b !== void 0 ? _b : BigInt(0);
311
+ sumsByContract.set(spec.contractAddress, prev + BigInt(r.amount));
312
+ specsByContract.set(spec.contractAddress, spec);
313
+ }
314
+ catch (_d) {
315
+ /* ignore — malformed amount string */
316
+ }
317
+ }
318
+ for (const [contractAddress, total] of sumsByContract.entries()) {
319
+ const spec = specsByContract.get(contractAddress);
320
+ if (!spec)
321
+ continue;
322
+ const rawBalance = Number(total);
323
+ balances.push({
324
+ address: spec.contractAddress,
325
+ balance: rawBalance / Math.pow(10, spec.decimals),
326
+ decimals: spec.decimals,
327
+ // Use redcoast's `DEFAULT_TOKEN_LOGO_URI` for stablecoins + ARC-21
328
+ // so they render the same dark "?" icon the Unshielded tab shows
329
+ // for these tokens (the multichain endpoint applies that fallback
330
+ // itself; we mirror it here for visual parity).
331
+ logoURI: (_c = spec.logoURI) !== null && _c !== void 0 ? _c : UNKNOWN_TOKEN_LOGO,
332
+ name: spec.name,
333
+ networkId: safeNetworkId,
334
+ rawBalance,
335
+ symbol: spec.symbol,
336
+ });
337
+ }
338
+ setTokenBalances(balances);
339
+ }
340
+ catch (err) {
341
+ const msg = err instanceof Error ? err.message : String(err);
342
+ setError(msg);
343
+ setTokenBalances((prev) => (prev.length === 0 ? prev : []));
344
+ }
345
+ finally {
346
+ setIsLoading(false);
347
+ }
348
+ }), [connectorKey, networkKey, supportsShielded]);
349
+ useEffect(() => {
350
+ if (!supportsShielded) {
351
+ setTokenBalances((prev) => (prev.length === 0 ? prev : []));
352
+ return;
353
+ }
354
+ fetchShielded().catch(() => {
355
+ // fetchShielded already records the error in component state;
356
+ // the .catch keeps the fire-and-forget shape lint-clean.
357
+ });
358
+ }, [supportsShielded, fetchShielded]);
359
+ return {
360
+ error,
361
+ isLoading,
362
+ refetch: fetchShielded,
363
+ supportsShielded,
364
+ tokenBalances,
365
+ };
366
+ };
367
+
368
+ 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
@@ -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) => {