@dynamic-labs/sdk-react-core 4.90.0 → 4.91.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 (34) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +1 -52
  3. package/package.cjs +2 -2
  4. package/package.js +2 -2
  5. package/package.json +13 -13
  6. package/src/lib/client/extension/functions/getSessionKeys/getSessionKeys.cjs +11 -0
  7. package/src/lib/client/extension/functions/getSessionKeys/getSessionKeys.js +7 -0
  8. package/src/lib/client/extension/functions/getSessionPublicKey/getSessionPublicKey.cjs +17 -0
  9. package/src/lib/client/extension/functions/getSessionPublicKey/getSessionPublicKey.d.ts +7 -0
  10. package/src/lib/client/extension/functions/getSessionPublicKey/getSessionPublicKey.js +13 -0
  11. package/src/lib/client/extension/index.d.ts +1 -0
  12. package/src/lib/context/DynamicContext/DynamicContext.cjs +9 -1
  13. package/src/lib/context/DynamicContext/DynamicContext.js +10 -2
  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/functions/getTransactionLink/blockExplorerPatterns.cjs +12 -0
  17. package/src/lib/utils/functions/getTransactionLink/blockExplorerPatterns.js +12 -0
  18. package/src/lib/utils/hooks/useCreateWalletConnectorOptions/utils/verifyZeroDevIsSetup/verifyZeroDevIsSetup.cjs +7 -3
  19. package/src/lib/utils/hooks/useCreateWalletConnectorOptions/utils/verifyZeroDevIsSetup/verifyZeroDevIsSetup.js +7 -3
  20. package/src/lib/utils/hooks/useDynamicWaas/useDynamicWaas.cjs +16 -3
  21. package/src/lib/utils/hooks/useDynamicWaas/useDynamicWaas.d.ts +3 -1
  22. package/src/lib/utils/hooks/useDynamicWaas/useDynamicWaas.js +16 -3
  23. package/src/lib/utils/hooks/useSetWalletConnectorFetchers/useSetWalletConnectorFetchers.cjs +8 -1
  24. package/src/lib/utils/hooks/useSetWalletConnectorFetchers/useSetWalletConnectorFetchers.d.ts +1 -1
  25. package/src/lib/utils/hooks/useSetWalletConnectorFetchers/useSetWalletConnectorFetchers.js +8 -1
  26. package/src/lib/views/TransactionConfirmationView/helpers/transactionErrorMessage.cjs +8 -0
  27. package/src/lib/views/TransactionConfirmationView/helpers/transactionErrorMessage.js +8 -0
  28. package/src/lib/widgets/DynamicWidget/components/ActiveMidnightWalletBalance/ActiveMidnightWalletBalance.cjs +56 -13
  29. package/src/lib/widgets/DynamicWidget/components/ActiveMidnightWalletBalance/ActiveMidnightWalletBalance.js +58 -15
  30. package/src/lib/widgets/DynamicWidget/components/ActiveWalletInformation/ActiveMidnightWalletAddresses/ActiveMidnightWalletAddresses.cjs +40 -2
  31. package/src/lib/widgets/DynamicWidget/components/ActiveWalletInformation/ActiveMidnightWalletAddresses/ActiveMidnightWalletAddresses.d.ts +7 -0
  32. package/src/lib/widgets/DynamicWidget/components/ActiveWalletInformation/ActiveMidnightWalletAddresses/ActiveMidnightWalletAddresses.js +41 -3
  33. package/src/lib/widgets/DynamicWidget/components/ActiveWalletInformation/ActiveWalletInformation.cjs +2 -0
  34. package/src/lib/widgets/DynamicWidget/components/ActiveWalletInformation/ActiveWalletInformation.js +2 -0
@@ -1,9 +1,10 @@
1
1
  'use client'
2
2
  import { __awaiter } from '../../../../../../_virtual/_tslib.js';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
- import { useState } from 'react';
4
+ import { useState, useEffect } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
- import { isMidnightConnector, isMidnightWallet } from '@dynamic-labs/wallet-connector-core';
6
+ import { isMidnightConnector, isMidnightWallet, isDynamicWaasConnector } from '@dynamic-labs/wallet-connector-core';
7
+ import { Button } from '../../../../components/Button/Button.js';
7
8
  import { Skeleton } from '../../../../components/Skeleton/Skeleton.js';
8
9
  import '../../../../context/DynamicContext/useDynamicContext/useDynamicContext.js';
9
10
  import { useInternalDynamicContext } from '../../../../context/DynamicContext/useDynamicContext/useInternalDynamicContext/useInternalDynamicContext.js';
@@ -22,6 +23,9 @@ import { classNames } from '../../../../utils/functions/classNames/classNames.js
22
23
  import { usePromise } from '../../../../utils/hooks/usePromise/usePromise.js';
23
24
 
24
25
  const DUST_SEGMENTS = 20;
26
+ // Stable keys for the fixed-length decorative dust bar so the segments don't
27
+ // rely on the array index as their React key.
28
+ const DUST_SEGMENT_KEYS = Array.from({ length: DUST_SEGMENTS }, (_, i) => `dust-segment-${i}`);
25
29
  const truncateToDecimals = (value, decimals) => {
26
30
  const [whole, fractional] = value.split('.');
27
31
  if (!fractional || decimals <= 0)
@@ -57,6 +61,10 @@ const ActiveMidnightWalletBalance = ({ isLoading = false, }) => {
57
61
  const [activeTab, setActiveTab] = useState('shielded');
58
62
  const walletAddress = primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.address;
59
63
  const enabled = Boolean(!isLoading && primaryWallet && isMidnightConnector(primaryWallet.connector));
64
+ // Balance reads resolve on shielded+unshielded; dust finishes in the
65
+ // background. While dust is still syncing we re-fetch on an interval so the
66
+ // dust gauge fills in once it's ready (shielded/unshielded already final).
67
+ const [dustPollTick, setDustPollTick] = useState(0);
60
68
  const { data: balances, isLoading: balancesLoading } = usePromise(() => __awaiter(void 0, void 0, void 0, function* () {
61
69
  if (!primaryWallet ||
62
70
  !isMidnightConnector(primaryWallet.connector) ||
@@ -65,11 +73,31 @@ const ActiveMidnightWalletBalance = ({ isLoading = false, }) => {
65
73
  }
66
74
  return primaryWallet.getFormattedBalances();
67
75
  }), {
68
- deps: [walletAddress, primaryWallet],
76
+ deps: [walletAddress, primaryWallet, dustPollTick],
69
77
  enabled,
70
78
  });
71
- const { dustBalance, shieldedBalance, unshieldedBalance } = balances !== null && balances !== void 0 ? balances : {};
72
- if (isLoading || balancesLoading) {
79
+ const { dustBalance, shieldedBalance, unshieldedBalance, dustSyncing } = balances !== null && balances !== void 0 ? balances : {};
80
+ useEffect(() => {
81
+ if (!dustSyncing)
82
+ return undefined;
83
+ const id = setInterval(() => setDustPollTick((tick) => tick + 1), 15000);
84
+ return () => clearInterval(id);
85
+ }, [dustSyncing]);
86
+ // `registerDust` is a WaaS-only connector method (external/injected Midnight
87
+ // wallets manage dust themselves). When the embedded wallet has no dust
88
+ // registered yet, we surface a "Register DUST" button instead of the gauge.
89
+ const isWaasWallet = Boolean(primaryWallet && isDynamicWaasConnector(primaryWallet.connector));
90
+ const handleRegisterDust = () => __awaiter(void 0, void 0, void 0, function* () {
91
+ const connector = primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.connector;
92
+ if (!(connector === null || connector === void 0 ? void 0 : connector.registerDust))
93
+ return;
94
+ yield connector.registerDust();
95
+ // Dust generation begins after registration; re-fetch so the gauge appears.
96
+ setDustPollTick((tick) => tick + 1);
97
+ });
98
+ // Only show the full skeleton on the very first load; background dust polls
99
+ // keep `balances` populated so the view never flashes back to a skeleton.
100
+ if ((isLoading || balancesLoading) && !balances) {
73
101
  return (jsx("div", { className: 'active-midnight-balance', children: jsx(Skeleton, { className: 'active-midnight-balance__skeleton' }) }));
74
102
  }
75
103
  const dustFill = dustBalance
@@ -82,16 +110,31 @@ const ActiveMidnightWalletBalance = ({ isLoading = false, }) => {
82
110
  }
83
111
  : undefined;
84
112
  const activeBalance = activeTab === 'shielded' ? shieldedBalance : unshieldedBalance;
85
- return (jsx("div", { className: 'active-midnight-balance', children: jsxs("div", { className: 'active-midnight-balance__card', children: [dustBalance && (jsxs(Fragment, { children: [jsxs("div", { className: 'active-midnight-balance__dust', children: [jsxs("div", { className: 'active-midnight-balance__dust-header', children: [jsxs("div", { className: 'active-midnight-balance__dust-title', children: [jsx("svg", { className: 'active-midnight-balance__dust-icon', width: '12', height: '12', viewBox: '0 0 24 24', children: jsx("path", { d: 'M13 2L3 14h9l-1 8 10-12h-9l1-8z' }) }), jsx("span", { className: 'active-midnight-balance__dust-label', "data-copykey": 'dyn_active_wallet_info.midnight_dust_generating', children: t('dyn_active_wallet_info.midnight_dust_generating') })] }), jsxs("span", { className: 'active-midnight-balance__dust-count', children: [dustBalanceDisplay === null || dustBalanceDisplay === void 0 ? void 0 : dustBalanceDisplay.balance, "/", dustBalanceDisplay === null || dustBalanceDisplay === void 0 ? void 0 : dustBalanceDisplay.cap] })] }), jsx("div", { className: 'active-midnight-balance__dust-bar', children: Array.from({ length: DUST_SEGMENTS }, (_, i) => (jsx("div", { className: [
86
- 'active-midnight-balance__dust-segment',
87
- i === 0 && 'active-midnight-balance__dust-segment--first',
88
- i === DUST_SEGMENTS - 1 &&
89
- 'active-midnight-balance__dust-segment--last',
90
- i < dustFill &&
91
- 'active-midnight-balance__dust-segment--filled',
92
- ]
93
- .filter(Boolean)
94
- .join(' ') }, i))) })] }), jsx("div", { className: 'active-midnight-balance__divider' })] })), jsx("div", { className: 'active-midnight-balance__tab-bar', children: TABS.map(({ id, copykey }) => (jsx("button", { className: classNames('active-midnight-balance__tab', {
113
+ // Dust section has three mutually exclusive states (syncing, generating with
114
+ // a balance, and the WaaS "register dust" prompt). Resolved via a helper to
115
+ // avoid nesting ternaries in the JSX below.
116
+ const renderDustSection = () => {
117
+ if (dustSyncing) {
118
+ return (jsxs(Fragment, { children: [jsx("div", { className: 'active-midnight-balance__dust', children: jsx("div", { className: 'active-midnight-balance__dust-header', children: jsxs("div", { className: 'active-midnight-balance__dust-title', children: [jsx("svg", { className: 'active-midnight-balance__dust-icon', width: '12', height: '12', viewBox: '0 0 24 24', children: jsx("path", { d: 'M13 2L3 14h9l-1 8 10-12h-9l1-8z' }) }), jsx("span", { className: 'active-midnight-balance__dust-label', "data-copykey": 'dyn_active_wallet_info.midnight_dust_syncing', children: t('dyn_active_wallet_info.midnight_dust_syncing') })] }) }) }), jsx("div", { className: 'active-midnight-balance__divider' })] }));
119
+ }
120
+ if (dustBalance) {
121
+ return (jsxs(Fragment, { children: [jsxs("div", { className: 'active-midnight-balance__dust', children: [jsxs("div", { className: 'active-midnight-balance__dust-header', children: [jsxs("div", { className: 'active-midnight-balance__dust-title', children: [jsx("svg", { className: 'active-midnight-balance__dust-icon', width: '12', height: '12', viewBox: '0 0 24 24', children: jsx("path", { d: 'M13 2L3 14h9l-1 8 10-12h-9l1-8z' }) }), jsx("span", { className: 'active-midnight-balance__dust-label', "data-copykey": 'dyn_active_wallet_info.midnight_dust_generating', children: t('dyn_active_wallet_info.midnight_dust_generating') })] }), jsxs("span", { className: 'active-midnight-balance__dust-count', children: [dustBalanceDisplay === null || dustBalanceDisplay === void 0 ? void 0 : dustBalanceDisplay.balance, "/", dustBalanceDisplay === null || dustBalanceDisplay === void 0 ? void 0 : dustBalanceDisplay.cap] })] }), jsx("div", { className: 'active-midnight-balance__dust-bar', children: DUST_SEGMENT_KEYS.map((segmentKey, i) => (jsx("div", { className: [
122
+ 'active-midnight-balance__dust-segment',
123
+ i === 0 && 'active-midnight-balance__dust-segment--first',
124
+ i === DUST_SEGMENTS - 1 &&
125
+ 'active-midnight-balance__dust-segment--last',
126
+ i < dustFill &&
127
+ 'active-midnight-balance__dust-segment--filled',
128
+ ]
129
+ .filter(Boolean)
130
+ .join(' ') }, segmentKey))) })] }), jsx("div", { className: 'active-midnight-balance__divider' })] }));
131
+ }
132
+ if (isWaasWallet) {
133
+ return (jsxs(Fragment, { children: [jsxs("div", { className: 'active-midnight-balance__dust', children: [jsx("div", { className: 'active-midnight-balance__dust-header', children: jsxs("div", { className: 'active-midnight-balance__dust-title', children: [jsx("svg", { className: 'active-midnight-balance__dust-icon', width: '12', height: '12', viewBox: '0 0 24 24', children: jsx("path", { d: 'M13 2L3 14h9l-1 8 10-12h-9l1-8z' }) }), jsx("span", { className: 'active-midnight-balance__dust-label', "data-copykey": 'dyn_active_wallet_info.midnight_dust_generating', children: t('dyn_active_wallet_info.midnight_dust_generating') })] }) }), jsx(Button, { buttonPadding: 'small', buttonVariant: 'secondary', buttonClassName: 'active-midnight-balance__register-dust-button', onClick: handleRegisterDust, "data-copykey": 'dyn_active_wallet_info.midnight_register_dust', children: t('dyn_active_wallet_info.midnight_register_dust') })] }), jsx("div", { className: 'active-midnight-balance__divider' })] }));
134
+ }
135
+ return null;
136
+ };
137
+ return (jsx("div", { className: 'active-midnight-balance', children: jsxs("div", { className: 'active-midnight-balance__card', children: [renderDustSection(), jsx("div", { className: 'active-midnight-balance__tab-bar', children: TABS.map(({ id, copykey }) => (jsx("button", { className: classNames('active-midnight-balance__tab', {
95
138
  'active-midnight-balance__tab--active': activeTab === id,
96
139
  }), "data-copykey": copykey, onClick: () => setActiveTab(id), children: t(copykey) }, id))) }), jsxs("div", { className: 'active-midnight-balance__pocket', children: [activeTab === 'shielded' ? (jsx(SvgMidnightShielded, { className: 'active-midnight-balance__pocket-icon' })) : (jsx(SvgMidnightUnshielded, { className: 'active-midnight-balance__pocket-icon' })), jsxs("span", { className: 'active-midnight-balance__amount', children: [activeBalance !== null && activeBalance !== void 0 ? activeBalance : '—', " NIGHT"] })] })] }) }));
97
140
  };
@@ -4,9 +4,10 @@
4
4
  Object.defineProperty(exports, '__esModule', { value: true });
5
5
 
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
+ var React = require('react');
7
8
  var reactI18next = require('react-i18next');
8
9
  require('../../../../../components/Accordion/components/AccordionItem/AccordionItem.cjs');
9
- require('react');
10
+ var copy = require('../../../../../shared/assets/copy.cjs');
10
11
  require('@dynamic-labs/iconic');
11
12
  require('../../../../../context/ViewContext/ViewContext.cjs');
12
13
  require('../../../../../../../_virtual/_tslib.cjs');
@@ -71,6 +72,7 @@ require('../../../../../components/OverlayCardBase/OverlayCardTarget/OverlayCard
71
72
  require('../../../../../context/WalletGroupContext/WalletGroupContext.cjs');
72
73
  require('../../DynamicWidgetHeader/DynamicWidgetHeader.cjs');
73
74
  require('react-focus-lock');
75
+ var Icon = require('../../../../../components/Icon/Icon.cjs');
74
76
  var shortenWalletAddress = require('../../../../../shared/utils/functions/shortenWalletAddress/shortenWalletAddress.cjs');
75
77
  require('../../../context/DynamicWidgetContext.cjs');
76
78
  require('../../../../../components/IconButton/IconButton.cjs');
@@ -95,6 +97,7 @@ require('../../../views/CryptoComOnramp/CryptoComOnramp.cjs');
95
97
  require('../../../../../context/OnrampContext/OnrampContext.cjs');
96
98
  require('../../../../../../index.cjs');
97
99
  require('../../../helpers/convertExchangeKeyAndProviderEnum.cjs');
100
+ var CopyButton = require('../../../../../components/CopyButton/CopyButton.cjs');
98
101
  require('qrcode');
99
102
  require('../../../views/ManagePasskeysMfaWidgetView/ManagePasskeysMfaWidgetView.cjs');
100
103
  require('../../../views/ManageTotpMfaWidgetView/ManageTotpMfaWidgetView.cjs');
@@ -116,13 +119,48 @@ require('../../../../../components/IsBrowser/IsBrowser.cjs');
116
119
  require('../../../../../components/Popper/Popper/Popper.cjs');
117
120
  require('../../../../../components/Popper/PopperContext/PopperContext.cjs');
118
121
 
122
+ /**
123
+ * Midnight wallet address types as string literals.
124
+ * These correspond to WalletAddressType enum values that will be added in the backend.
125
+ */
119
126
  const MIDNIGHT_ADDRESS_TYPE_UNSHIELDED = 'midnight_unshielded';
127
+ const MIDNIGHT_ADDRESS_TYPE_DUST = 'midnight_dust';
128
+ const MIDNIGHT_ADDRESS_TYPE_SHIELDED = 'midnight_shielded';
129
+ /**
130
+ * Gets a Midnight address from the wallet's additional addresses by type.
131
+ * @param type - The address type to find
132
+ * @param wallet - The wallet containing additional addresses
133
+ * @returns The address string or undefined if not found
134
+ */
120
135
  const getMidnightAddressByType = (type, wallet) => { var _a, _b; return (_b = (_a = wallet === null || wallet === void 0 ? void 0 : wallet.additionalAddresses) === null || _a === void 0 ? void 0 : _a.find((addr) => addr.type === type)) === null || _b === void 0 ? void 0 : _b.address; };
136
+ /**
137
+ * Component for displaying Midnight wallet addresses.
138
+ * Midnight supports multiple address types:
139
+ * - Unshielded: For public/transparent transactions
140
+ * - Dust: For gas/fee management
141
+ * - Shielded: For private transfers (Phase 2)
142
+ */
121
143
  const ActiveMidnightWalletAddresses = ({ menuOption, wallet, }) => {
122
144
  var _a;
123
145
  const { t } = reactI18next.useTranslation();
124
146
  const unshieldedAddress = (_a = getMidnightAddressByType(MIDNIGHT_ADDRESS_TYPE_UNSHIELDED, wallet)) !== null && _a !== void 0 ? _a : wallet === null || wallet === void 0 ? void 0 : wallet.address;
125
- return (jsxRuntime.jsxs("div", { className: 'active-wallet-information__address-container', children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx(Typography.Typography, { className: 'active-wallet-information__address', weight: 'regular', variant: 'body_small', color: 'secondary', copykey: 'dyn_active_wallet_info.midnight_unshielded_address', children: t('dyn_active_wallet_info.midnight_unshielded_address') }), jsxRuntime.jsx(Typography.Typography, { className: 'active-wallet-information__address', weight: 'medium', variant: 'body_normal', color: 'primary', children: shortenWalletAddress.shortenWalletAddress(unshieldedAddress) })] }), jsxRuntime.jsx(DotsMenu.DotsMenu, { "data-testid": 'dots-menu', options: menuOption, buttonClassName: 'active-wallet-information__dots-menu', buttonClassNameWithOpenMenu: 'active-wallet-information__dots-menu' })] }));
147
+ const dustAddress = getMidnightAddressByType(MIDNIGHT_ADDRESS_TYPE_DUST, wallet);
148
+ const shieldedAddress = getMidnightAddressByType(MIDNIGHT_ADDRESS_TYPE_SHIELDED, wallet);
149
+ // Collapse dust + shielded behind a toggle so the header shows only the
150
+ // primary (unshielded) address by default — the user reveals the rest on
151
+ // click, instead of all three being shown at once.
152
+ const [expanded, setExpanded] = React.useState(false);
153
+ const hasAdditionalAddresses = Boolean(dustAddress || shieldedAddress);
154
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: 'active-wallet-information__address-container', children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx(Typography.Typography, { className: 'active-wallet-information__address', weight: 'regular', variant: 'body_small', color: 'secondary', copykey: 'dyn_active_wallet_info.midnight_unshielded_address', children: t('dyn_active_wallet_info.midnight_unshielded_address') }), jsxRuntime.jsx(Typography.Typography, { className: 'active-wallet-information__address', weight: 'medium', variant: 'body_normal', color: 'primary', children: shortenWalletAddress.shortenWalletAddress(unshieldedAddress) })] }), jsxRuntime.jsxs("div", { style: { alignItems: 'center', display: 'flex', gap: '4px' }, children: [hasAdditionalAddresses && (jsxRuntime.jsx("button", { type: 'button', "aria-expanded": expanded, "aria-label": t('dyn_active_wallet_info.midnight_toggle_addresses'), onClick: () => setExpanded((prev) => !prev), style: {
155
+ background: 'none',
156
+ border: 'none',
157
+ cursor: 'pointer',
158
+ display: 'flex',
159
+ padding: 0,
160
+ }, children: jsxRuntime.jsx("svg", { width: '16', height: '16', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: '2', style: {
161
+ transform: expanded ? 'rotate(180deg)' : undefined,
162
+ transition: 'transform 0.15s ease',
163
+ }, children: jsxRuntime.jsx("path", { d: 'M6 9l6 6 6-6' }) }) })), jsxRuntime.jsx(DotsMenu.DotsMenu, { "data-testid": 'dots-menu', options: menuOption, buttonClassName: 'active-wallet-information__dots-menu', buttonClassNameWithOpenMenu: 'active-wallet-information__dots-menu' })] })] }), expanded && dustAddress && (jsxRuntime.jsxs("div", { className: 'active-wallet-information__address-container', children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx(Typography.Typography, { className: 'active-wallet-information__address', weight: 'regular', variant: 'body_small', color: 'secondary', copykey: 'dyn_active_wallet_info.midnight_dust_address', children: t('dyn_active_wallet_info.midnight_dust_address') }), jsxRuntime.jsx(Typography.Typography, { className: 'active-wallet-information__address', weight: 'regular', variant: 'body_small', color: 'primary', children: shortenWalletAddress.shortenWalletAddress(dustAddress) })] }), jsxRuntime.jsx(CopyButton.CopyButton, { textToCopy: dustAddress, children: jsxRuntime.jsx(Icon.Icon, { size: 'xsmall', children: jsxRuntime.jsx(copy.ReactComponent, {}) }) })] })), expanded && shieldedAddress && (jsxRuntime.jsxs("div", { className: 'active-wallet-information__address-container', children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx(Typography.Typography, { className: 'active-wallet-information__address', weight: 'regular', variant: 'body_small', color: 'secondary', copykey: 'dyn_active_wallet_info.midnight_shielded_address', children: t('dyn_active_wallet_info.midnight_shielded_address') }), jsxRuntime.jsx(Typography.Typography, { className: 'active-wallet-information__address', weight: 'regular', variant: 'body_small', color: 'primary', children: shortenWalletAddress.shortenWalletAddress(shieldedAddress) })] }), jsxRuntime.jsx(CopyButton.CopyButton, { textToCopy: shieldedAddress, children: jsxRuntime.jsx(Icon.Icon, { size: 'xsmall', children: jsxRuntime.jsx(copy.ReactComponent, {}) }) })] }))] }));
126
164
  };
127
165
 
128
166
  exports.ActiveMidnightWalletAddresses = ActiveMidnightWalletAddresses;
@@ -5,5 +5,12 @@ type Props = {
5
5
  menuOption: MenuOption[];
6
6
  wallet?: Wallet;
7
7
  };
8
+ /**
9
+ * Component for displaying Midnight wallet addresses.
10
+ * Midnight supports multiple address types:
11
+ * - Unshielded: For public/transparent transactions
12
+ * - Dust: For gas/fee management
13
+ * - Shielded: For private transfers (Phase 2)
14
+ */
8
15
  export declare const ActiveMidnightWalletAddresses: ({ menuOption, wallet, }: Props) => JSX.Element;
9
16
  export {};
@@ -1,8 +1,9 @@
1
1
  'use client'
2
- import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
3
+ import { useState } from 'react';
3
4
  import { useTranslation } from 'react-i18next';
4
5
  import '../../../../../components/Accordion/components/AccordionItem/AccordionItem.js';
5
- import 'react';
6
+ import { ReactComponent as SvgCopy } from '../../../../../shared/assets/copy.js';
6
7
  import '@dynamic-labs/iconic';
7
8
  import '../../../../../context/ViewContext/ViewContext.js';
8
9
  import '../../../../../../../_virtual/_tslib.js';
@@ -67,6 +68,7 @@ import '../../../../../components/OverlayCardBase/OverlayCardTarget/OverlayCardT
67
68
  import '../../../../../context/WalletGroupContext/WalletGroupContext.js';
68
69
  import '../../DynamicWidgetHeader/DynamicWidgetHeader.js';
69
70
  import 'react-focus-lock';
71
+ import { Icon } from '../../../../../components/Icon/Icon.js';
70
72
  import { shortenWalletAddress } from '../../../../../shared/utils/functions/shortenWalletAddress/shortenWalletAddress.js';
71
73
  import '../../../context/DynamicWidgetContext.js';
72
74
  import '../../../../../components/IconButton/IconButton.js';
@@ -91,6 +93,7 @@ import '../../../views/CryptoComOnramp/CryptoComOnramp.js';
91
93
  import '../../../../../context/OnrampContext/OnrampContext.js';
92
94
  import '../../../../../../index.js';
93
95
  import '../../../helpers/convertExchangeKeyAndProviderEnum.js';
96
+ import { CopyButton } from '../../../../../components/CopyButton/CopyButton.js';
94
97
  import 'qrcode';
95
98
  import '../../../views/ManagePasskeysMfaWidgetView/ManagePasskeysMfaWidgetView.js';
96
99
  import '../../../views/ManageTotpMfaWidgetView/ManageTotpMfaWidgetView.js';
@@ -112,13 +115,48 @@ import '../../../../../components/IsBrowser/IsBrowser.js';
112
115
  import '../../../../../components/Popper/Popper/Popper.js';
113
116
  import '../../../../../components/Popper/PopperContext/PopperContext.js';
114
117
 
118
+ /**
119
+ * Midnight wallet address types as string literals.
120
+ * These correspond to WalletAddressType enum values that will be added in the backend.
121
+ */
115
122
  const MIDNIGHT_ADDRESS_TYPE_UNSHIELDED = 'midnight_unshielded';
123
+ const MIDNIGHT_ADDRESS_TYPE_DUST = 'midnight_dust';
124
+ const MIDNIGHT_ADDRESS_TYPE_SHIELDED = 'midnight_shielded';
125
+ /**
126
+ * Gets a Midnight address from the wallet's additional addresses by type.
127
+ * @param type - The address type to find
128
+ * @param wallet - The wallet containing additional addresses
129
+ * @returns The address string or undefined if not found
130
+ */
116
131
  const getMidnightAddressByType = (type, wallet) => { var _a, _b; return (_b = (_a = wallet === null || wallet === void 0 ? void 0 : wallet.additionalAddresses) === null || _a === void 0 ? void 0 : _a.find((addr) => addr.type === type)) === null || _b === void 0 ? void 0 : _b.address; };
132
+ /**
133
+ * Component for displaying Midnight wallet addresses.
134
+ * Midnight supports multiple address types:
135
+ * - Unshielded: For public/transparent transactions
136
+ * - Dust: For gas/fee management
137
+ * - Shielded: For private transfers (Phase 2)
138
+ */
117
139
  const ActiveMidnightWalletAddresses = ({ menuOption, wallet, }) => {
118
140
  var _a;
119
141
  const { t } = useTranslation();
120
142
  const unshieldedAddress = (_a = getMidnightAddressByType(MIDNIGHT_ADDRESS_TYPE_UNSHIELDED, wallet)) !== null && _a !== void 0 ? _a : wallet === null || wallet === void 0 ? void 0 : wallet.address;
121
- return (jsxs("div", { className: 'active-wallet-information__address-container', children: [jsxs("div", { children: [jsx(Typography, { className: 'active-wallet-information__address', weight: 'regular', variant: 'body_small', color: 'secondary', copykey: 'dyn_active_wallet_info.midnight_unshielded_address', children: t('dyn_active_wallet_info.midnight_unshielded_address') }), jsx(Typography, { className: 'active-wallet-information__address', weight: 'medium', variant: 'body_normal', color: 'primary', children: shortenWalletAddress(unshieldedAddress) })] }), jsx(DotsMenu, { "data-testid": 'dots-menu', options: menuOption, buttonClassName: 'active-wallet-information__dots-menu', buttonClassNameWithOpenMenu: 'active-wallet-information__dots-menu' })] }));
143
+ const dustAddress = getMidnightAddressByType(MIDNIGHT_ADDRESS_TYPE_DUST, wallet);
144
+ const shieldedAddress = getMidnightAddressByType(MIDNIGHT_ADDRESS_TYPE_SHIELDED, wallet);
145
+ // Collapse dust + shielded behind a toggle so the header shows only the
146
+ // primary (unshielded) address by default — the user reveals the rest on
147
+ // click, instead of all three being shown at once.
148
+ const [expanded, setExpanded] = useState(false);
149
+ const hasAdditionalAddresses = Boolean(dustAddress || shieldedAddress);
150
+ return (jsxs(Fragment, { children: [jsxs("div", { className: 'active-wallet-information__address-container', children: [jsxs("div", { children: [jsx(Typography, { className: 'active-wallet-information__address', weight: 'regular', variant: 'body_small', color: 'secondary', copykey: 'dyn_active_wallet_info.midnight_unshielded_address', children: t('dyn_active_wallet_info.midnight_unshielded_address') }), jsx(Typography, { className: 'active-wallet-information__address', weight: 'medium', variant: 'body_normal', color: 'primary', children: shortenWalletAddress(unshieldedAddress) })] }), jsxs("div", { style: { alignItems: 'center', display: 'flex', gap: '4px' }, children: [hasAdditionalAddresses && (jsx("button", { type: 'button', "aria-expanded": expanded, "aria-label": t('dyn_active_wallet_info.midnight_toggle_addresses'), onClick: () => setExpanded((prev) => !prev), style: {
151
+ background: 'none',
152
+ border: 'none',
153
+ cursor: 'pointer',
154
+ display: 'flex',
155
+ padding: 0,
156
+ }, children: jsx("svg", { width: '16', height: '16', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: '2', style: {
157
+ transform: expanded ? 'rotate(180deg)' : undefined,
158
+ transition: 'transform 0.15s ease',
159
+ }, children: jsx("path", { d: 'M6 9l6 6 6-6' }) }) })), jsx(DotsMenu, { "data-testid": 'dots-menu', options: menuOption, buttonClassName: 'active-wallet-information__dots-menu', buttonClassNameWithOpenMenu: 'active-wallet-information__dots-menu' })] })] }), expanded && dustAddress && (jsxs("div", { className: 'active-wallet-information__address-container', children: [jsxs("div", { children: [jsx(Typography, { className: 'active-wallet-information__address', weight: 'regular', variant: 'body_small', color: 'secondary', copykey: 'dyn_active_wallet_info.midnight_dust_address', children: t('dyn_active_wallet_info.midnight_dust_address') }), jsx(Typography, { className: 'active-wallet-information__address', weight: 'regular', variant: 'body_small', color: 'primary', children: shortenWalletAddress(dustAddress) })] }), jsx(CopyButton, { textToCopy: dustAddress, children: jsx(Icon, { size: 'xsmall', children: jsx(SvgCopy, {}) }) })] })), expanded && shieldedAddress && (jsxs("div", { className: 'active-wallet-information__address-container', children: [jsxs("div", { children: [jsx(Typography, { className: 'active-wallet-information__address', weight: 'regular', variant: 'body_small', color: 'secondary', copykey: 'dyn_active_wallet_info.midnight_shielded_address', children: t('dyn_active_wallet_info.midnight_shielded_address') }), jsx(Typography, { className: 'active-wallet-information__address', weight: 'regular', variant: 'body_small', color: 'primary', children: shortenWalletAddress(shieldedAddress) })] }), jsx(CopyButton, { textToCopy: shieldedAddress, children: jsx(Icon, { size: 'xsmall', children: jsx(SvgCopy, {}) }) })] }))] }));
122
160
  };
123
161
 
124
162
  export { ActiveMidnightWalletAddresses };
@@ -216,6 +216,8 @@ const ActiveWalletInformation = ({ isLoading = false, }) => {
216
216
  if (isBitcoin && !isWaasWallet) {
217
217
  return (jsxRuntime.jsx(ActiveBitcoinWalletAddresses.ActiveBitcoinWalletAddresses, { wallet: primaryWallet, menuOption: options }));
218
218
  }
219
+ // Midnight wallets (WaaS and external/injected alike) expose multiple
220
+ // address types (Unshielded, Dust, Shielded) via additionalAddresses.
219
221
  if (isMidnight) {
220
222
  return (jsxRuntime.jsx(ActiveMidnightWalletAddresses.ActiveMidnightWalletAddresses, { wallet: primaryWallet, menuOption: options }));
221
223
  }
@@ -212,6 +212,8 @@ const ActiveWalletInformation = ({ isLoading = false, }) => {
212
212
  if (isBitcoin && !isWaasWallet) {
213
213
  return (jsx(ActiveBitcoinWalletAddresses, { wallet: primaryWallet, menuOption: options }));
214
214
  }
215
+ // Midnight wallets (WaaS and external/injected alike) expose multiple
216
+ // address types (Unshielded, Dust, Shielded) via additionalAddresses.
215
217
  if (isMidnight) {
216
218
  return (jsx(ActiveMidnightWalletAddresses, { wallet: primaryWallet, menuOption: options }));
217
219
  }