@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.
- package/CHANGELOG.md +38 -0
- package/package.cjs +1 -1
- package/package.js +1 -1
- package/package.json +12 -12
- package/src/lib/components/SendBalanceForm/SendBalanceForm.cjs +63 -3
- package/src/lib/components/SendBalanceForm/SendBalanceForm.js +63 -3
- package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/TransactionModeSegmentedControl.cjs +40 -0
- package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/TransactionModeSegmentedControl.d.ts +16 -0
- package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/TransactionModeSegmentedControl.js +36 -0
- package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/icons.cjs +17 -0
- package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/icons.d.ts +8 -0
- package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/icons.js +12 -0
- package/src/lib/components/SendBalanceForm/TransactionModeSegmentedControl/index.d.ts +1 -0
- package/src/lib/data/api/aleo/getAleoCuratedPrices.cjs +73 -0
- package/src/lib/data/api/aleo/getAleoCuratedPrices.d.ts +38 -0
- package/src/lib/data/api/aleo/getAleoCuratedPrices.js +69 -0
- package/src/lib/shared/assets/index.d.ts +2 -0
- package/src/lib/shared/assets/midnight-shielded.cjs +54 -0
- package/src/lib/shared/assets/midnight-shielded.js +30 -0
- package/src/lib/shared/assets/midnight-unshielded.cjs +54 -0
- package/src/lib/shared/assets/midnight-unshielded.js +30 -0
- package/src/lib/styles/index.shadow.cjs +1 -1
- package/src/lib/styles/index.shadow.js +1 -1
- package/src/lib/utils/functions/compareChains/compareChains.cjs +1 -0
- package/src/lib/utils/functions/compareChains/compareChains.js +1 -0
- package/src/lib/utils/functions/getTransactionLink/blockExplorerPatterns.cjs +12 -0
- package/src/lib/utils/functions/getTransactionLink/blockExplorerPatterns.js +12 -0
- package/src/lib/utils/hooks/useAleoAutoMergeRecords/index.d.ts +1 -0
- package/src/lib/utils/hooks/useAleoAutoMergeRecords/useAleoAutoMergeRecords.cjs +246 -0
- package/src/lib/utils/hooks/useAleoAutoMergeRecords/useAleoAutoMergeRecords.d.ts +17 -0
- package/src/lib/utils/hooks/useAleoAutoMergeRecords/useAleoAutoMergeRecords.js +242 -0
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/index.d.ts +1 -0
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/useAleoAutoShieldSponsoredTokens.cjs +263 -0
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/useAleoAutoShieldSponsoredTokens.d.ts +59 -0
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/useAleoAutoShieldSponsoredTokens.js +259 -0
- package/src/lib/utils/hooks/useAleoShieldedBalances/index.d.ts +1 -0
- package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.cjs +443 -0
- package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.d.ts +24 -0
- package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.js +439 -0
- package/src/lib/utils/hooks/useEmbeddedWallet/useEmbeddedWallet.cjs +1 -0
- package/src/lib/utils/hooks/useEmbeddedWallet/useEmbeddedWallet.d.ts +1 -0
- package/src/lib/utils/hooks/useEmbeddedWallet/useEmbeddedWallet.js +1 -0
- package/src/lib/views/BackupUnsuccessfulView/BackupUnsuccessfulView.cjs +12 -1
- package/src/lib/views/BackupUnsuccessfulView/BackupUnsuccessfulView.js +12 -1
- package/src/lib/views/SendBalanceView/SendBalanceView.cjs +53 -0
- package/src/lib/views/SendBalanceView/SendBalanceView.js +53 -0
- package/src/lib/widgets/DynamicWidget/components/ActiveMidnightWalletBalance/ActiveMidnightWalletBalance.cjs +193 -0
- package/src/lib/widgets/DynamicWidget/components/ActiveMidnightWalletBalance/ActiveMidnightWalletBalance.d.ts +7 -0
- package/src/lib/widgets/DynamicWidget/components/ActiveMidnightWalletBalance/ActiveMidnightWalletBalance.js +189 -0
- package/src/lib/widgets/DynamicWidget/components/ActiveMidnightWalletBalance/index.d.ts +1 -0
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/ActiveWalletBalance.cjs +216 -11
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/ActiveWalletBalance.js +216 -11
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceItem/TokenBalanceItem.cjs +5 -2
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceItem/TokenBalanceItem.d.ts +10 -1
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceItem/TokenBalanceItem.js +5 -2
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceItem/index.d.ts +1 -0
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceList/TokenBalanceList.cjs +2 -2
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceList/TokenBalanceList.d.ts +3 -1
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/TokenBalanceList/TokenBalanceList.js +2 -2
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletInformation/ActiveMidnightWalletAddresses/ActiveMidnightWalletAddresses.cjs +124 -0
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletInformation/ActiveMidnightWalletAddresses/ActiveMidnightWalletAddresses.d.ts +9 -0
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletInformation/ActiveMidnightWalletAddresses/ActiveMidnightWalletAddresses.js +120 -0
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletInformation/ActiveMidnightWalletAddresses/index.d.ts +1 -0
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletInformation/ActiveWalletInformation.cjs +21 -10
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletInformation/ActiveWalletInformation.js +22 -11
- package/src/lib/widgets/DynamicWidget/components/WalletDetailsCard/WalletDetailsCard.cjs +22 -2
- package/src/lib/widgets/DynamicWidget/components/WalletDetailsCard/WalletDetailsCard.d.ts +8 -1
- package/src/lib/widgets/DynamicWidget/components/WalletDetailsCard/WalletDetailsCard.js +23 -3
package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/ActiveWalletBalance.cjs
CHANGED
|
@@ -15,13 +15,13 @@ var check = require('../../../../shared/assets/check.cjs');
|
|
|
15
15
|
var chevronDown = require('../../../../shared/assets/chevron-down.cjs');
|
|
16
16
|
var reloadIcon = require('../../../../shared/assets/reload-icon.cjs');
|
|
17
17
|
require('../../../../context/ViewContext/ViewContext.cjs');
|
|
18
|
-
require('../../../../shared/logger.cjs');
|
|
18
|
+
var logger = require('../../../../shared/logger.cjs');
|
|
19
19
|
require('@dynamic-labs/wallet-book');
|
|
20
20
|
require('@dynamic-labs/utils');
|
|
21
21
|
require('../../../../utils/constants/colors.cjs');
|
|
22
22
|
require('../../../../utils/constants/values.cjs');
|
|
23
23
|
require('@dynamic-labs/sdk-api-core');
|
|
24
|
-
require('../../../../shared/consts/index.cjs');
|
|
24
|
+
var index = require('../../../../shared/consts/index.cjs');
|
|
25
25
|
require('../../../../events/dynamicEvents.cjs');
|
|
26
26
|
require('../../../../context/CaptchaContext/CaptchaContext.cjs');
|
|
27
27
|
require('../../../../context/ErrorContext/ErrorContext.cjs');
|
|
@@ -63,6 +63,7 @@ require('../../../../context/UserFieldEditorContext/UserFieldEditorContext.cjs')
|
|
|
63
63
|
require('@dynamic-labs/rpc-providers');
|
|
64
64
|
require('../../../../store/state/walletOptions/walletOptions.cjs');
|
|
65
65
|
var AccordionItem = require('../../../../components/Accordion/components/AccordionItem/AccordionItem.cjs');
|
|
66
|
+
var Button = require('../../../../components/Button/Button.cjs');
|
|
66
67
|
require('../../../../components/Alert/Alert.cjs');
|
|
67
68
|
var Typography = require('../../../../components/Typography/Typography.cjs');
|
|
68
69
|
require('../../../../components/ShadowDOM/ShadowDOM.cjs');
|
|
@@ -72,13 +73,15 @@ require('../../../../components/Input/Input.cjs');
|
|
|
72
73
|
require('../../../../components/IsBrowser/IsBrowser.cjs');
|
|
73
74
|
require('../../../../components/MenuList/Dropdown/Dropdown.cjs');
|
|
74
75
|
require('../../../../components/OverlayCard/OverlayCard.cjs');
|
|
76
|
+
var Modal = require('../../../../components/Modal/Modal.cjs');
|
|
77
|
+
var ModalCard = require('../../../../components/ModalCard/ModalCard.cjs');
|
|
75
78
|
require('../../../../components/Transition/ZoomTransition/ZoomTransition.cjs');
|
|
76
79
|
require('../../../../components/Transition/SlideInUpTransition/SlideInUpTransition.cjs');
|
|
77
80
|
require('../../../../components/Transition/OpacityTransition/OpacityTransition.cjs');
|
|
78
81
|
require('../../../../components/PasskeyCreatedSuccessBanner/PasskeyCreatedSuccessBanner.cjs');
|
|
79
82
|
require('../../../../components/Popper/Popper/Popper.cjs');
|
|
80
83
|
require('../../../../components/Popper/PopperContext/PopperContext.cjs');
|
|
81
|
-
require('
|
|
84
|
+
var Portal = require('../../../../components/Portal/Portal.cjs');
|
|
82
85
|
require('qrcode');
|
|
83
86
|
require('formik');
|
|
84
87
|
require('../../../../utils/hooks/useSubdomainCheck/useSubdomainCheck.cjs');
|
|
@@ -117,11 +120,14 @@ require('../../../../store/state/multichainBalances.cjs');
|
|
|
117
120
|
require('@dynamic-labs/store');
|
|
118
121
|
require('../../../../shared/utils/functions/getInitialUrl/getInitialUrl.cjs');
|
|
119
122
|
var useInternalDynamicContext = require('../../../../context/DynamicContext/useDynamicContext/useInternalDynamicContext/useInternalDynamicContext.cjs');
|
|
123
|
+
var useAleoShieldedBalances = require('../../../../utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.cjs');
|
|
124
|
+
var useAleoAutoMergeRecords = require('../../../../utils/hooks/useAleoAutoMergeRecords/useAleoAutoMergeRecords.cjs');
|
|
125
|
+
var useAleoAutoShieldSponsoredTokens = require('../../../../utils/hooks/useAleoAutoShieldSponsoredTokens/useAleoAutoShieldSponsoredTokens.cjs');
|
|
120
126
|
var TokenBalanceList = require('./TokenBalanceList/TokenBalanceList.cjs');
|
|
121
127
|
|
|
122
128
|
/** Component to display token balances for the primary wallet */
|
|
123
129
|
const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
124
|
-
var _a, _b, _c;
|
|
130
|
+
var _a, _b, _c, _d, _e;
|
|
125
131
|
const { t } = reactI18next.useTranslation();
|
|
126
132
|
/** Controls for the multi asset balance accordion */
|
|
127
133
|
const [balanceIsExpanded, setBalanceIsExpanded] = React.useState(false);
|
|
@@ -137,11 +143,152 @@ const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
|
137
143
|
const authMode$1 = authMode.useAuthMode();
|
|
138
144
|
const projectSettings = useProjectSettings.useProjectSettings();
|
|
139
145
|
const { data: testnet } = usePromise.usePromise(() => _tslib.__awaiter(void 0, void 0, void 0, function* () { return Boolean(yield (primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.connector.isTestnet())); }), { deps: [network], initialData: false });
|
|
140
|
-
const { isLoading: isLoadingTokenBalances, tokenBalances, error: errorTokenBalances, fetchAccountBalances, } = useTokenBalances.useTokenBalances({
|
|
146
|
+
const { isLoading: isLoadingTokenBalances, tokenBalances: unshieldedTokenBalances, error: errorTokenBalances, fetchAccountBalances, } = useTokenBalances.useTokenBalances({
|
|
141
147
|
chainName: primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.connector.connectedChain,
|
|
142
148
|
includeFiat: showFiat || !hasNativeToken,
|
|
143
149
|
includeNativeBalance: true,
|
|
144
150
|
});
|
|
151
|
+
const { tokenBalances: shieldedTokenBalances, isLoading: isLoadingShielded, refetch: refetchShielded, supportsShielded, } = useAleoShieldedBalances.useAleoShieldedBalances();
|
|
152
|
+
/**
|
|
153
|
+
* Tab state for chains that have a shielded/unshielded split. Defaults to
|
|
154
|
+
* shielded so Aleo wallets land on their primary balance type. Other
|
|
155
|
+
* chains render unchanged: when `supportsShielded` is false, the
|
|
156
|
+
* `tokenBalances` selector below short-circuits to unshielded
|
|
157
|
+
* regardless of this state, so the default has no visible effect for
|
|
158
|
+
* non-Aleo wallets. Only Aleo wallets see the toggle (gated by
|
|
159
|
+
* `supportsShielded`); they should land on Shielded since that's the
|
|
160
|
+
* privacy-first default for Aleo.
|
|
161
|
+
*/
|
|
162
|
+
const [activeShieldTab, setActiveShieldTab] = React.useState('shielded');
|
|
163
|
+
/**
|
|
164
|
+
* Address of the token currently being shielded (during a click → broadcast
|
|
165
|
+
* cycle on the Unshielded tab's "Shield Manually" CTA). Used to flip that
|
|
166
|
+
* row's button to a `Working…` disabled state. Single-flight: one shield in
|
|
167
|
+
* flight at a time across the entire list — the form-level UX would get
|
|
168
|
+
* confusing otherwise (user-paid fees + multiple in-flight DPS proves).
|
|
169
|
+
*/
|
|
170
|
+
const [shieldingAddress, setShieldingAddress] = React.useState(undefined);
|
|
171
|
+
// Duck-typed handle to the Aleo connector's shield helpers — only present
|
|
172
|
+
// on `DynamicWaasAleoConnector`. We deliberately avoid an `instanceof`
|
|
173
|
+
// check so this file doesn't pull a hard dependency on the Aleo package.
|
|
174
|
+
const aleoShieldHandle = React.useMemo(() => {
|
|
175
|
+
const c = primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.connector;
|
|
176
|
+
if (c &&
|
|
177
|
+
typeof c.canShieldToken === 'function' &&
|
|
178
|
+
typeof c.shieldToken === 'function') {
|
|
179
|
+
return c;
|
|
180
|
+
}
|
|
181
|
+
return undefined;
|
|
182
|
+
}, [primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.connector]);
|
|
183
|
+
// Auto-merge sponsored programs on wallet load. Reads owned records,
|
|
184
|
+
// groups by program, and silently fires `joinRecords` per program with
|
|
185
|
+
// ≥2 records when the Aleo Feemaster covers `join`. Programs that
|
|
186
|
+
// Feemaster doesn't sponsor are skipped — the manual "Merge all
|
|
187
|
+
// records" demo CTA still dispatches user-paid for those.
|
|
188
|
+
useAleoAutoMergeRecords.useAleoAutoMergeRecords();
|
|
189
|
+
// Auto-shield sponsored tokens on wallet load (and on each unshielded
|
|
190
|
+
// balance refresh). Iterates the unshielded list and silently fires
|
|
191
|
+
// `shieldToken` for tokens whose `transfer_public_to_private` is
|
|
192
|
+
// Feemaster-sponsored. Unsponsored tokens stay on the manual Shield
|
|
193
|
+
// Manually CTA, which prompts the user-paid confirmation modal.
|
|
194
|
+
const { isShielding: isAutoShielding } = useAleoAutoShieldSponsoredTokens.useAleoAutoShieldSponsoredTokens({
|
|
195
|
+
accountAddress: primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.address,
|
|
196
|
+
onShielded: React.useCallback(() => _tslib.__awaiter(void 0, void 0, void 0, function* () {
|
|
197
|
+
yield fetchAccountBalances(true);
|
|
198
|
+
yield refetchShielded();
|
|
199
|
+
}), [fetchAccountBalances, refetchShielded]),
|
|
200
|
+
shieldHandle: aleoShieldHandle,
|
|
201
|
+
unshieldedTokenBalances: unshieldedTokenBalances,
|
|
202
|
+
});
|
|
203
|
+
// Token currently awaiting user-paid fee confirmation. Set when
|
|
204
|
+
// Shield Manually is clicked on a token Feemaster doesn't sponsor;
|
|
205
|
+
// cleared on Cancel or after the modal's Shield button dispatches.
|
|
206
|
+
const [pendingShieldToken, setPendingShieldToken] = React.useState(null);
|
|
207
|
+
const handleShieldToken = React.useCallback((token) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
|
|
208
|
+
var _f;
|
|
209
|
+
if (!aleoShieldHandle || shieldingAddress)
|
|
210
|
+
return;
|
|
211
|
+
// `rawBalance` is the atomic-units count redcoast surfaces (number).
|
|
212
|
+
// Convert to bigint via Math.round to absorb any float drift from a
|
|
213
|
+
// decimal-shifted display value. <=0 entries get filtered out before
|
|
214
|
+
// the CTA renders, but the guard here is a safety net.
|
|
215
|
+
const atomic = BigInt(Math.round((_f = token.rawBalance) !== null && _f !== void 0 ? _f : 0));
|
|
216
|
+
if (atomic <= BigInt(0))
|
|
217
|
+
return;
|
|
218
|
+
setShieldingAddress(token.address);
|
|
219
|
+
try {
|
|
220
|
+
yield aleoShieldHandle.shieldToken({
|
|
221
|
+
amount: atomic,
|
|
222
|
+
isNative: token.isNative,
|
|
223
|
+
tokenAddress: token.address,
|
|
224
|
+
});
|
|
225
|
+
// Refresh the unshielded list so the just-shielded balance drops to
|
|
226
|
+
// 0 in the redcoast feed. The shielded side will pick the new
|
|
227
|
+
// record up on its own polling once the RecordScanner indexes.
|
|
228
|
+
yield fetchAccountBalances(true);
|
|
229
|
+
yield refetchShielded();
|
|
230
|
+
}
|
|
231
|
+
catch (err) {
|
|
232
|
+
logger.logger.debug('[ActiveWalletBalance] shieldToken failed', err);
|
|
233
|
+
}
|
|
234
|
+
finally {
|
|
235
|
+
setShieldingAddress(undefined);
|
|
236
|
+
}
|
|
237
|
+
}), [aleoShieldHandle, fetchAccountBalances, refetchShielded, shieldingAddress]);
|
|
238
|
+
const getSecondaryAction = React.useCallback((token) => {
|
|
239
|
+
// Only on the Unshielded tab, only when the connector exposes shield
|
|
240
|
+
// helpers, only for tokens registered as shieldable, only for tokens
|
|
241
|
+
// with a non-zero unshielded balance.
|
|
242
|
+
if (activeShieldTab !== 'unshielded')
|
|
243
|
+
return undefined;
|
|
244
|
+
if (!aleoShieldHandle)
|
|
245
|
+
return undefined;
|
|
246
|
+
if (!aleoShieldHandle.canShieldToken({
|
|
247
|
+
address: token.address,
|
|
248
|
+
isNative: token.isNative,
|
|
249
|
+
}))
|
|
250
|
+
return undefined;
|
|
251
|
+
if (!token.rawBalance || token.rawBalance <= 0)
|
|
252
|
+
return undefined;
|
|
253
|
+
return {
|
|
254
|
+
dataTestId: `shield-manually-${token.symbol}`,
|
|
255
|
+
isLoading: shieldingAddress === token.address,
|
|
256
|
+
label: 'Shield Manually',
|
|
257
|
+
onClick: () => {
|
|
258
|
+
// Pre-check Feemaster sponsorship — if covered, dispatch the
|
|
259
|
+
// shield silently (current behaviour). If not covered (e.g.
|
|
260
|
+
// policy gap, quota exhausted, lookup error), open a user-paid
|
|
261
|
+
// confirmation modal so the user knows they'll pay an ALEO
|
|
262
|
+
// network fee before we sign anything. The connector resolves
|
|
263
|
+
// the registry token's programId internally.
|
|
264
|
+
(() => _tslib.__awaiter(void 0, void 0, void 0, function* () {
|
|
265
|
+
var _a;
|
|
266
|
+
const sponsored = yield ((_a = aleoShieldHandle.isShieldSponsored) === null || _a === void 0 ? void 0 : _a.call(aleoShieldHandle, {
|
|
267
|
+
address: token.address,
|
|
268
|
+
isNative: token.isNative,
|
|
269
|
+
}));
|
|
270
|
+
if (sponsored) {
|
|
271
|
+
handleShieldToken(token).catch(() => {
|
|
272
|
+
/* error surfaced via state inside handleShieldToken */
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
setPendingShieldToken(token);
|
|
277
|
+
}
|
|
278
|
+
}))().catch(() => {
|
|
279
|
+
/* error surfaced via state inside the callback */
|
|
280
|
+
});
|
|
281
|
+
},
|
|
282
|
+
};
|
|
283
|
+
}, [activeShieldTab, aleoShieldHandle, handleShieldToken, shieldingAddress]);
|
|
284
|
+
const tokenBalances = React.useMemo(() => supportsShielded && activeShieldTab === 'shielded'
|
|
285
|
+
? shieldedTokenBalances
|
|
286
|
+
: unshieldedTokenBalances, [
|
|
287
|
+
activeShieldTab,
|
|
288
|
+
shieldedTokenBalances,
|
|
289
|
+
supportsShielded,
|
|
290
|
+
unshieldedTokenBalances,
|
|
291
|
+
]);
|
|
145
292
|
const filteredTokenBalances = React.useMemo(() => (tokenBalances === null || tokenBalances === void 0 ? void 0 : tokenBalances.filter((token) => token.name)) || [], [tokenBalances]);
|
|
146
293
|
const totalValue = React.useMemo(() => filteredTokenBalances.reduce((acc, token) => acc + ((token === null || token === void 0 ? void 0 : token.marketValue) || 0), 0), [filteredTokenBalances]);
|
|
147
294
|
const enableMultiAsset = React.useMemo(() => {
|
|
@@ -183,7 +330,12 @@ const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
|
183
330
|
setIsRefreshing(true);
|
|
184
331
|
setIsSuccess(false);
|
|
185
332
|
try {
|
|
186
|
-
|
|
333
|
+
if (supportsShielded && activeShieldTab === 'shielded') {
|
|
334
|
+
yield refetchShielded();
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
yield fetchAccountBalances(true);
|
|
338
|
+
}
|
|
187
339
|
setIsRefreshing(false);
|
|
188
340
|
setIsSuccess(true);
|
|
189
341
|
successTimeoutRef.current = setTimeout(() => {
|
|
@@ -197,9 +349,19 @@ const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
|
197
349
|
refreshTimeoutRef.current = null;
|
|
198
350
|
}, 1000);
|
|
199
351
|
}
|
|
200
|
-
}), [
|
|
352
|
+
}), [
|
|
353
|
+
isRefreshing,
|
|
354
|
+
isSuccess,
|
|
355
|
+
fetchAccountBalances,
|
|
356
|
+
refetchShielded,
|
|
357
|
+
supportsShielded,
|
|
358
|
+
activeShieldTab,
|
|
359
|
+
]);
|
|
201
360
|
const primaryWalletNativeBalance = () => {
|
|
202
|
-
if (!primaryWallet ||
|
|
361
|
+
if (!primaryWallet ||
|
|
362
|
+
isLoadingTokenBalances ||
|
|
363
|
+
isLoading ||
|
|
364
|
+
(supportsShielded && activeShieldTab === 'shielded' && isLoadingShielded)) {
|
|
203
365
|
return jsxRuntime.jsx(Skeleton.Skeleton, { className: 'balance-container__skeleton' });
|
|
204
366
|
}
|
|
205
367
|
// Chain has no native token - show aggregated fiat token values
|
|
@@ -212,7 +374,11 @@ const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
|
212
374
|
? currencyFormatter.format(parseFloat(totalValue.toFixed(2)))
|
|
213
375
|
: '<$0.01' })) : (jsxRuntime.jsx(Balance.Balance, { className: 'balance-header__balance', wallet: primaryWallet, network: network, variant: 'numbers_display' }));
|
|
214
376
|
};
|
|
215
|
-
const balanceHeaderTitle = () => (jsxRuntime.jsxs("div", { className: 'balance-header__title', children: [isLoadingTokenBalances ||
|
|
377
|
+
const balanceHeaderTitle = () => (jsxRuntime.jsxs("div", { className: 'balance-header__title', children: [isLoadingTokenBalances ||
|
|
378
|
+
isLoading ||
|
|
379
|
+
(supportsShielded &&
|
|
380
|
+
activeShieldTab === 'shielded' &&
|
|
381
|
+
isLoadingShielded) ? (jsxRuntime.jsx(Skeleton.Skeleton, { className: 'balance-header__title-skeleton' })) : (jsxRuntime.jsx(Typography.Typography, { color: 'secondary', variant: 'body_normal', copykey: 'dyn_active_wallet_info.balance', children: t('dyn_active_wallet_info.balance') })), jsxRuntime.jsxs("div", { className: 'balance-header__balance', children: [primaryWalletNativeBalance(), isSuccess ? (jsxRuntime.jsx("div", { className: 'balance-header__success-icon', children: jsxRuntime.jsx(check.ReactComponent, { "data-testid": 'success-icon' }) })) : (jsxRuntime.jsx(reloadIcon.ReactComponent, { "data-testid": 'refresh-balances', className: `balance-header__refresh-icon ${isRefreshing ? 'balance-header__refresh-icon--spinning' : ''}`, onClick: handleRefresh, style: {
|
|
216
382
|
cursor: isRefreshing ? 'not-allowed' : 'pointer',
|
|
217
383
|
opacity: isRefreshing ? 0.5 : 1,
|
|
218
384
|
}, title: 'Refresh balances' }))] })] }));
|
|
@@ -224,8 +390,47 @@ const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
|
224
390
|
if (!showMultiAsset) {
|
|
225
391
|
return jsxRuntime.jsx("div", { className: 'balance-container', children: balanceHeaderTitle() });
|
|
226
392
|
}
|
|
227
|
-
return (jsxRuntime.
|
|
228
|
-
|
|
393
|
+
return (jsxRuntime.jsxs("div", { className: 'balance-container', children: [jsxRuntime.jsxs("div", { className: 'multi-asset-balance-container', children: [jsxRuntime.jsx("div", { className: `${hasShadow ? 'shadow' : ''}`, children: jsxRuntime.jsxs("button", { onClick: toggleBalanceAccordion, className: 'balance-header', "data-testid": 'balance-header', children: [balanceHeaderTitle(), !isLoadingTokenBalances && (jsxRuntime.jsx("div", { className: balanceIsExpanded ? 'balance-header__chevron' : '', children: jsxRuntime.jsx(chevronDown.ReactComponent, {}) }))] }) }), jsxRuntime.jsxs(AccordionItem.AccordionItem, { isOpen: balanceIsExpanded, className: `multi-asset-balance-container__accordion ${'multi-asset-balance-container__accordion' +
|
|
394
|
+
(balanceIsExpanded ? '--expanded' : '--collapsed')}`, handleScroll: handleScroll, ref: contentRef, dataTestId: 'multi-asset-balance-accordion', children: [supportsShielded && (jsxRuntime.jsxs("div", { className: 'shield-tabs', "data-testid": 'shield-tabs', role: 'tablist', style: {
|
|
395
|
+
display: 'flex',
|
|
396
|
+
gap: 16,
|
|
397
|
+
padding: '12px 16px 8px 16px',
|
|
398
|
+
}, children: [jsxRuntime.jsx("button", { type: 'button', role: 'tab', "aria-selected": activeShieldTab === 'shielded', onClick: (e) => {
|
|
399
|
+
e.stopPropagation();
|
|
400
|
+
setActiveShieldTab('shielded');
|
|
401
|
+
}, style: {
|
|
402
|
+
background: 'none',
|
|
403
|
+
border: 'none',
|
|
404
|
+
cursor: 'pointer',
|
|
405
|
+
fontWeight: activeShieldTab === 'shielded' ? 600 : 400,
|
|
406
|
+
opacity: activeShieldTab === 'shielded' ? 1 : 0.5,
|
|
407
|
+
padding: 0,
|
|
408
|
+
}, children: jsxRuntime.jsx(Typography.Typography, { variant: 'body_normal', children: "Shielded" }) }), jsxRuntime.jsx("button", { type: 'button', role: 'tab', "aria-selected": activeShieldTab === 'unshielded', onClick: (e) => {
|
|
409
|
+
e.stopPropagation();
|
|
410
|
+
setActiveShieldTab('unshielded');
|
|
411
|
+
}, style: {
|
|
412
|
+
background: 'none',
|
|
413
|
+
border: 'none',
|
|
414
|
+
cursor: 'pointer',
|
|
415
|
+
fontWeight: activeShieldTab === 'unshielded' ? 600 : 400,
|
|
416
|
+
opacity: activeShieldTab === 'unshielded' ? 1 : 0.5,
|
|
417
|
+
padding: 0,
|
|
418
|
+
}, children: jsxRuntime.jsx(Typography.Typography, { variant: 'body_normal', children: "Unshielded" }) })] })), isAutoShielding && (jsxRuntime.jsx("div", { className: 'auto-shield-status', "data-testid": 'auto-shield-status', style: {
|
|
419
|
+
opacity: 0.7,
|
|
420
|
+
padding: '4px 16px 8px 16px',
|
|
421
|
+
}, children: jsxRuntime.jsx(Typography.Typography, { variant: 'body_small', children: "Auto-shielding\u2026" }) })), jsxRuntime.jsx(TokenBalanceList.TokenBalanceList, { tokenBalances: filteredTokenBalances, getSecondaryAction: getSecondaryAction })] })] }), jsxRuntime.jsx(Portal.Portal, { elementId: 'dynamic-shield-confirm', isShown: Boolean(pendingShieldToken), zIndex: index.authModalZIndex, withBackdrop: true, handleClose: () => setPendingShieldToken(null), children: jsxRuntime.jsx(Modal.Modal, { children: jsxRuntime.jsx(ModalCard.ModalCard, { children: jsxRuntime.jsxs("div", { style: { padding: 24 }, children: [jsxRuntime.jsxs(Typography.Typography, { variant: 'title', weight: 'medium', color: 'primary', children: ["Shield ", (_d = pendingShieldToken === null || pendingShieldToken === void 0 ? void 0 : pendingShieldToken.balance) !== null && _d !== void 0 ? _d : '', ' ', (_e = pendingShieldToken === null || pendingShieldToken === void 0 ? void 0 : pendingShieldToken.symbol) !== null && _e !== void 0 ? _e : ''] }), jsxRuntime.jsx(Typography.Typography, { variant: 'body_normal', color: 'secondary', style: { display: 'block', marginTop: 8 }, children: "This token doesn't support auto-shielding. A network fee is required to shield manually." }), jsxRuntime.jsxs("div", { style: {
|
|
422
|
+
display: 'flex',
|
|
423
|
+
gap: 8,
|
|
424
|
+
marginTop: 24,
|
|
425
|
+
}, children: [jsxRuntime.jsx(Button.Button, { buttonVariant: 'secondary', expanded: true, onClick: () => setPendingShieldToken(null), dataTestId: 'shield-confirm-modal-cancel', children: "Cancel" }), jsxRuntime.jsx(Button.Button, { buttonVariant: 'primary', expanded: true, onClick: () => {
|
|
426
|
+
const target = pendingShieldToken;
|
|
427
|
+
setPendingShieldToken(null);
|
|
428
|
+
if (target) {
|
|
429
|
+
handleShieldToken(target).catch(() => {
|
|
430
|
+
/* error surfaced via state inside handleShieldToken */
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
}, dataTestId: 'shield-confirm-modal-confirm', children: "Shield" })] })] }) }) }) })] }));
|
|
229
434
|
};
|
|
230
435
|
|
|
231
436
|
exports.ActiveWalletBalance = ActiveWalletBalance;
|
|
@@ -11,13 +11,13 @@ import { ReactComponent as SvgCheck } from '../../../../shared/assets/check.js';
|
|
|
11
11
|
import { ReactComponent as SvgChevronDown } from '../../../../shared/assets/chevron-down.js';
|
|
12
12
|
import { ReactComponent as SvgReloadIcon } from '../../../../shared/assets/reload-icon.js';
|
|
13
13
|
import '../../../../context/ViewContext/ViewContext.js';
|
|
14
|
-
import '../../../../shared/logger.js';
|
|
14
|
+
import { logger } from '../../../../shared/logger.js';
|
|
15
15
|
import '@dynamic-labs/wallet-book';
|
|
16
16
|
import '@dynamic-labs/utils';
|
|
17
17
|
import '../../../../utils/constants/colors.js';
|
|
18
18
|
import '../../../../utils/constants/values.js';
|
|
19
19
|
import '@dynamic-labs/sdk-api-core';
|
|
20
|
-
import '../../../../shared/consts/index.js';
|
|
20
|
+
import { authModalZIndex } from '../../../../shared/consts/index.js';
|
|
21
21
|
import '../../../../events/dynamicEvents.js';
|
|
22
22
|
import '../../../../context/CaptchaContext/CaptchaContext.js';
|
|
23
23
|
import '../../../../context/ErrorContext/ErrorContext.js';
|
|
@@ -59,6 +59,7 @@ import '../../../../context/UserFieldEditorContext/UserFieldEditorContext.js';
|
|
|
59
59
|
import '@dynamic-labs/rpc-providers';
|
|
60
60
|
import '../../../../store/state/walletOptions/walletOptions.js';
|
|
61
61
|
import { AccordionItem } from '../../../../components/Accordion/components/AccordionItem/AccordionItem.js';
|
|
62
|
+
import { Button } from '../../../../components/Button/Button.js';
|
|
62
63
|
import '../../../../components/Alert/Alert.js';
|
|
63
64
|
import { Typography } from '../../../../components/Typography/Typography.js';
|
|
64
65
|
import '../../../../components/ShadowDOM/ShadowDOM.js';
|
|
@@ -68,13 +69,15 @@ import '../../../../components/Input/Input.js';
|
|
|
68
69
|
import '../../../../components/IsBrowser/IsBrowser.js';
|
|
69
70
|
import '../../../../components/MenuList/Dropdown/Dropdown.js';
|
|
70
71
|
import '../../../../components/OverlayCard/OverlayCard.js';
|
|
72
|
+
import { Modal } from '../../../../components/Modal/Modal.js';
|
|
73
|
+
import { ModalCard } from '../../../../components/ModalCard/ModalCard.js';
|
|
71
74
|
import '../../../../components/Transition/ZoomTransition/ZoomTransition.js';
|
|
72
75
|
import '../../../../components/Transition/SlideInUpTransition/SlideInUpTransition.js';
|
|
73
76
|
import '../../../../components/Transition/OpacityTransition/OpacityTransition.js';
|
|
74
77
|
import '../../../../components/PasskeyCreatedSuccessBanner/PasskeyCreatedSuccessBanner.js';
|
|
75
78
|
import '../../../../components/Popper/Popper/Popper.js';
|
|
76
79
|
import '../../../../components/Popper/PopperContext/PopperContext.js';
|
|
77
|
-
import '
|
|
80
|
+
import { Portal } from '../../../../components/Portal/Portal.js';
|
|
78
81
|
import 'qrcode';
|
|
79
82
|
import 'formik';
|
|
80
83
|
import '../../../../utils/hooks/useSubdomainCheck/useSubdomainCheck.js';
|
|
@@ -113,11 +116,14 @@ import '../../../../store/state/multichainBalances.js';
|
|
|
113
116
|
import '@dynamic-labs/store';
|
|
114
117
|
import '../../../../shared/utils/functions/getInitialUrl/getInitialUrl.js';
|
|
115
118
|
import { useInternalDynamicContext } from '../../../../context/DynamicContext/useDynamicContext/useInternalDynamicContext/useInternalDynamicContext.js';
|
|
119
|
+
import { useAleoShieldedBalances } from '../../../../utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.js';
|
|
120
|
+
import { useAleoAutoMergeRecords } from '../../../../utils/hooks/useAleoAutoMergeRecords/useAleoAutoMergeRecords.js';
|
|
121
|
+
import { useAleoAutoShieldSponsoredTokens } from '../../../../utils/hooks/useAleoAutoShieldSponsoredTokens/useAleoAutoShieldSponsoredTokens.js';
|
|
116
122
|
import { TokenBalanceList } from './TokenBalanceList/TokenBalanceList.js';
|
|
117
123
|
|
|
118
124
|
/** Component to display token balances for the primary wallet */
|
|
119
125
|
const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
120
|
-
var _a, _b, _c;
|
|
126
|
+
var _a, _b, _c, _d, _e;
|
|
121
127
|
const { t } = useTranslation();
|
|
122
128
|
/** Controls for the multi asset balance accordion */
|
|
123
129
|
const [balanceIsExpanded, setBalanceIsExpanded] = useState(false);
|
|
@@ -133,11 +139,152 @@ const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
|
133
139
|
const authMode = useAuthMode();
|
|
134
140
|
const projectSettings = useProjectSettings();
|
|
135
141
|
const { data: testnet } = usePromise(() => __awaiter(void 0, void 0, void 0, function* () { return Boolean(yield (primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.connector.isTestnet())); }), { deps: [network], initialData: false });
|
|
136
|
-
const { isLoading: isLoadingTokenBalances, tokenBalances, error: errorTokenBalances, fetchAccountBalances, } = useTokenBalances({
|
|
142
|
+
const { isLoading: isLoadingTokenBalances, tokenBalances: unshieldedTokenBalances, error: errorTokenBalances, fetchAccountBalances, } = useTokenBalances({
|
|
137
143
|
chainName: primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.connector.connectedChain,
|
|
138
144
|
includeFiat: showFiat || !hasNativeToken,
|
|
139
145
|
includeNativeBalance: true,
|
|
140
146
|
});
|
|
147
|
+
const { tokenBalances: shieldedTokenBalances, isLoading: isLoadingShielded, refetch: refetchShielded, supportsShielded, } = useAleoShieldedBalances();
|
|
148
|
+
/**
|
|
149
|
+
* Tab state for chains that have a shielded/unshielded split. Defaults to
|
|
150
|
+
* shielded so Aleo wallets land on their primary balance type. Other
|
|
151
|
+
* chains render unchanged: when `supportsShielded` is false, the
|
|
152
|
+
* `tokenBalances` selector below short-circuits to unshielded
|
|
153
|
+
* regardless of this state, so the default has no visible effect for
|
|
154
|
+
* non-Aleo wallets. Only Aleo wallets see the toggle (gated by
|
|
155
|
+
* `supportsShielded`); they should land on Shielded since that's the
|
|
156
|
+
* privacy-first default for Aleo.
|
|
157
|
+
*/
|
|
158
|
+
const [activeShieldTab, setActiveShieldTab] = useState('shielded');
|
|
159
|
+
/**
|
|
160
|
+
* Address of the token currently being shielded (during a click → broadcast
|
|
161
|
+
* cycle on the Unshielded tab's "Shield Manually" CTA). Used to flip that
|
|
162
|
+
* row's button to a `Working…` disabled state. Single-flight: one shield in
|
|
163
|
+
* flight at a time across the entire list — the form-level UX would get
|
|
164
|
+
* confusing otherwise (user-paid fees + multiple in-flight DPS proves).
|
|
165
|
+
*/
|
|
166
|
+
const [shieldingAddress, setShieldingAddress] = useState(undefined);
|
|
167
|
+
// Duck-typed handle to the Aleo connector's shield helpers — only present
|
|
168
|
+
// on `DynamicWaasAleoConnector`. We deliberately avoid an `instanceof`
|
|
169
|
+
// check so this file doesn't pull a hard dependency on the Aleo package.
|
|
170
|
+
const aleoShieldHandle = useMemo(() => {
|
|
171
|
+
const c = primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.connector;
|
|
172
|
+
if (c &&
|
|
173
|
+
typeof c.canShieldToken === 'function' &&
|
|
174
|
+
typeof c.shieldToken === 'function') {
|
|
175
|
+
return c;
|
|
176
|
+
}
|
|
177
|
+
return undefined;
|
|
178
|
+
}, [primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.connector]);
|
|
179
|
+
// Auto-merge sponsored programs on wallet load. Reads owned records,
|
|
180
|
+
// groups by program, and silently fires `joinRecords` per program with
|
|
181
|
+
// ≥2 records when the Aleo Feemaster covers `join`. Programs that
|
|
182
|
+
// Feemaster doesn't sponsor are skipped — the manual "Merge all
|
|
183
|
+
// records" demo CTA still dispatches user-paid for those.
|
|
184
|
+
useAleoAutoMergeRecords();
|
|
185
|
+
// Auto-shield sponsored tokens on wallet load (and on each unshielded
|
|
186
|
+
// balance refresh). Iterates the unshielded list and silently fires
|
|
187
|
+
// `shieldToken` for tokens whose `transfer_public_to_private` is
|
|
188
|
+
// Feemaster-sponsored. Unsponsored tokens stay on the manual Shield
|
|
189
|
+
// Manually CTA, which prompts the user-paid confirmation modal.
|
|
190
|
+
const { isShielding: isAutoShielding } = useAleoAutoShieldSponsoredTokens({
|
|
191
|
+
accountAddress: primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.address,
|
|
192
|
+
onShielded: useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
193
|
+
yield fetchAccountBalances(true);
|
|
194
|
+
yield refetchShielded();
|
|
195
|
+
}), [fetchAccountBalances, refetchShielded]),
|
|
196
|
+
shieldHandle: aleoShieldHandle,
|
|
197
|
+
unshieldedTokenBalances: unshieldedTokenBalances,
|
|
198
|
+
});
|
|
199
|
+
// Token currently awaiting user-paid fee confirmation. Set when
|
|
200
|
+
// Shield Manually is clicked on a token Feemaster doesn't sponsor;
|
|
201
|
+
// cleared on Cancel or after the modal's Shield button dispatches.
|
|
202
|
+
const [pendingShieldToken, setPendingShieldToken] = useState(null);
|
|
203
|
+
const handleShieldToken = useCallback((token) => __awaiter(void 0, void 0, void 0, function* () {
|
|
204
|
+
var _f;
|
|
205
|
+
if (!aleoShieldHandle || shieldingAddress)
|
|
206
|
+
return;
|
|
207
|
+
// `rawBalance` is the atomic-units count redcoast surfaces (number).
|
|
208
|
+
// Convert to bigint via Math.round to absorb any float drift from a
|
|
209
|
+
// decimal-shifted display value. <=0 entries get filtered out before
|
|
210
|
+
// the CTA renders, but the guard here is a safety net.
|
|
211
|
+
const atomic = BigInt(Math.round((_f = token.rawBalance) !== null && _f !== void 0 ? _f : 0));
|
|
212
|
+
if (atomic <= BigInt(0))
|
|
213
|
+
return;
|
|
214
|
+
setShieldingAddress(token.address);
|
|
215
|
+
try {
|
|
216
|
+
yield aleoShieldHandle.shieldToken({
|
|
217
|
+
amount: atomic,
|
|
218
|
+
isNative: token.isNative,
|
|
219
|
+
tokenAddress: token.address,
|
|
220
|
+
});
|
|
221
|
+
// Refresh the unshielded list so the just-shielded balance drops to
|
|
222
|
+
// 0 in the redcoast feed. The shielded side will pick the new
|
|
223
|
+
// record up on its own polling once the RecordScanner indexes.
|
|
224
|
+
yield fetchAccountBalances(true);
|
|
225
|
+
yield refetchShielded();
|
|
226
|
+
}
|
|
227
|
+
catch (err) {
|
|
228
|
+
logger.debug('[ActiveWalletBalance] shieldToken failed', err);
|
|
229
|
+
}
|
|
230
|
+
finally {
|
|
231
|
+
setShieldingAddress(undefined);
|
|
232
|
+
}
|
|
233
|
+
}), [aleoShieldHandle, fetchAccountBalances, refetchShielded, shieldingAddress]);
|
|
234
|
+
const getSecondaryAction = useCallback((token) => {
|
|
235
|
+
// Only on the Unshielded tab, only when the connector exposes shield
|
|
236
|
+
// helpers, only for tokens registered as shieldable, only for tokens
|
|
237
|
+
// with a non-zero unshielded balance.
|
|
238
|
+
if (activeShieldTab !== 'unshielded')
|
|
239
|
+
return undefined;
|
|
240
|
+
if (!aleoShieldHandle)
|
|
241
|
+
return undefined;
|
|
242
|
+
if (!aleoShieldHandle.canShieldToken({
|
|
243
|
+
address: token.address,
|
|
244
|
+
isNative: token.isNative,
|
|
245
|
+
}))
|
|
246
|
+
return undefined;
|
|
247
|
+
if (!token.rawBalance || token.rawBalance <= 0)
|
|
248
|
+
return undefined;
|
|
249
|
+
return {
|
|
250
|
+
dataTestId: `shield-manually-${token.symbol}`,
|
|
251
|
+
isLoading: shieldingAddress === token.address,
|
|
252
|
+
label: 'Shield Manually',
|
|
253
|
+
onClick: () => {
|
|
254
|
+
// Pre-check Feemaster sponsorship — if covered, dispatch the
|
|
255
|
+
// shield silently (current behaviour). If not covered (e.g.
|
|
256
|
+
// policy gap, quota exhausted, lookup error), open a user-paid
|
|
257
|
+
// confirmation modal so the user knows they'll pay an ALEO
|
|
258
|
+
// network fee before we sign anything. The connector resolves
|
|
259
|
+
// the registry token's programId internally.
|
|
260
|
+
(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
261
|
+
var _a;
|
|
262
|
+
const sponsored = yield ((_a = aleoShieldHandle.isShieldSponsored) === null || _a === void 0 ? void 0 : _a.call(aleoShieldHandle, {
|
|
263
|
+
address: token.address,
|
|
264
|
+
isNative: token.isNative,
|
|
265
|
+
}));
|
|
266
|
+
if (sponsored) {
|
|
267
|
+
handleShieldToken(token).catch(() => {
|
|
268
|
+
/* error surfaced via state inside handleShieldToken */
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
setPendingShieldToken(token);
|
|
273
|
+
}
|
|
274
|
+
}))().catch(() => {
|
|
275
|
+
/* error surfaced via state inside the callback */
|
|
276
|
+
});
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
}, [activeShieldTab, aleoShieldHandle, handleShieldToken, shieldingAddress]);
|
|
280
|
+
const tokenBalances = useMemo(() => supportsShielded && activeShieldTab === 'shielded'
|
|
281
|
+
? shieldedTokenBalances
|
|
282
|
+
: unshieldedTokenBalances, [
|
|
283
|
+
activeShieldTab,
|
|
284
|
+
shieldedTokenBalances,
|
|
285
|
+
supportsShielded,
|
|
286
|
+
unshieldedTokenBalances,
|
|
287
|
+
]);
|
|
141
288
|
const filteredTokenBalances = useMemo(() => (tokenBalances === null || tokenBalances === void 0 ? void 0 : tokenBalances.filter((token) => token.name)) || [], [tokenBalances]);
|
|
142
289
|
const totalValue = useMemo(() => filteredTokenBalances.reduce((acc, token) => acc + ((token === null || token === void 0 ? void 0 : token.marketValue) || 0), 0), [filteredTokenBalances]);
|
|
143
290
|
const enableMultiAsset = useMemo(() => {
|
|
@@ -179,7 +326,12 @@ const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
|
179
326
|
setIsRefreshing(true);
|
|
180
327
|
setIsSuccess(false);
|
|
181
328
|
try {
|
|
182
|
-
|
|
329
|
+
if (supportsShielded && activeShieldTab === 'shielded') {
|
|
330
|
+
yield refetchShielded();
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
yield fetchAccountBalances(true);
|
|
334
|
+
}
|
|
183
335
|
setIsRefreshing(false);
|
|
184
336
|
setIsSuccess(true);
|
|
185
337
|
successTimeoutRef.current = setTimeout(() => {
|
|
@@ -193,9 +345,19 @@ const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
|
193
345
|
refreshTimeoutRef.current = null;
|
|
194
346
|
}, 1000);
|
|
195
347
|
}
|
|
196
|
-
}), [
|
|
348
|
+
}), [
|
|
349
|
+
isRefreshing,
|
|
350
|
+
isSuccess,
|
|
351
|
+
fetchAccountBalances,
|
|
352
|
+
refetchShielded,
|
|
353
|
+
supportsShielded,
|
|
354
|
+
activeShieldTab,
|
|
355
|
+
]);
|
|
197
356
|
const primaryWalletNativeBalance = () => {
|
|
198
|
-
if (!primaryWallet ||
|
|
357
|
+
if (!primaryWallet ||
|
|
358
|
+
isLoadingTokenBalances ||
|
|
359
|
+
isLoading ||
|
|
360
|
+
(supportsShielded && activeShieldTab === 'shielded' && isLoadingShielded)) {
|
|
199
361
|
return jsx(Skeleton, { className: 'balance-container__skeleton' });
|
|
200
362
|
}
|
|
201
363
|
// Chain has no native token - show aggregated fiat token values
|
|
@@ -208,7 +370,11 @@ const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
|
208
370
|
? currencyFormatter.format(parseFloat(totalValue.toFixed(2)))
|
|
209
371
|
: '<$0.01' })) : (jsx(Balance, { className: 'balance-header__balance', wallet: primaryWallet, network: network, variant: 'numbers_display' }));
|
|
210
372
|
};
|
|
211
|
-
const balanceHeaderTitle = () => (jsxs("div", { className: 'balance-header__title', children: [isLoadingTokenBalances ||
|
|
373
|
+
const balanceHeaderTitle = () => (jsxs("div", { className: 'balance-header__title', children: [isLoadingTokenBalances ||
|
|
374
|
+
isLoading ||
|
|
375
|
+
(supportsShielded &&
|
|
376
|
+
activeShieldTab === 'shielded' &&
|
|
377
|
+
isLoadingShielded) ? (jsx(Skeleton, { className: 'balance-header__title-skeleton' })) : (jsx(Typography, { color: 'secondary', variant: 'body_normal', copykey: 'dyn_active_wallet_info.balance', children: t('dyn_active_wallet_info.balance') })), jsxs("div", { className: 'balance-header__balance', children: [primaryWalletNativeBalance(), isSuccess ? (jsx("div", { className: 'balance-header__success-icon', children: jsx(SvgCheck, { "data-testid": 'success-icon' }) })) : (jsx(SvgReloadIcon, { "data-testid": 'refresh-balances', className: `balance-header__refresh-icon ${isRefreshing ? 'balance-header__refresh-icon--spinning' : ''}`, onClick: handleRefresh, style: {
|
|
212
378
|
cursor: isRefreshing ? 'not-allowed' : 'pointer',
|
|
213
379
|
opacity: isRefreshing ? 0.5 : 1,
|
|
214
380
|
}, title: 'Refresh balances' }))] })] }));
|
|
@@ -220,8 +386,47 @@ const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
|
220
386
|
if (!showMultiAsset) {
|
|
221
387
|
return jsx("div", { className: 'balance-container', children: balanceHeaderTitle() });
|
|
222
388
|
}
|
|
223
|
-
return (
|
|
224
|
-
|
|
389
|
+
return (jsxs("div", { className: 'balance-container', children: [jsxs("div", { className: 'multi-asset-balance-container', children: [jsx("div", { className: `${hasShadow ? 'shadow' : ''}`, children: jsxs("button", { onClick: toggleBalanceAccordion, className: 'balance-header', "data-testid": 'balance-header', children: [balanceHeaderTitle(), !isLoadingTokenBalances && (jsx("div", { className: balanceIsExpanded ? 'balance-header__chevron' : '', children: jsx(SvgChevronDown, {}) }))] }) }), jsxs(AccordionItem, { isOpen: balanceIsExpanded, className: `multi-asset-balance-container__accordion ${'multi-asset-balance-container__accordion' +
|
|
390
|
+
(balanceIsExpanded ? '--expanded' : '--collapsed')}`, handleScroll: handleScroll, ref: contentRef, dataTestId: 'multi-asset-balance-accordion', children: [supportsShielded && (jsxs("div", { className: 'shield-tabs', "data-testid": 'shield-tabs', role: 'tablist', style: {
|
|
391
|
+
display: 'flex',
|
|
392
|
+
gap: 16,
|
|
393
|
+
padding: '12px 16px 8px 16px',
|
|
394
|
+
}, children: [jsx("button", { type: 'button', role: 'tab', "aria-selected": activeShieldTab === 'shielded', onClick: (e) => {
|
|
395
|
+
e.stopPropagation();
|
|
396
|
+
setActiveShieldTab('shielded');
|
|
397
|
+
}, style: {
|
|
398
|
+
background: 'none',
|
|
399
|
+
border: 'none',
|
|
400
|
+
cursor: 'pointer',
|
|
401
|
+
fontWeight: activeShieldTab === 'shielded' ? 600 : 400,
|
|
402
|
+
opacity: activeShieldTab === 'shielded' ? 1 : 0.5,
|
|
403
|
+
padding: 0,
|
|
404
|
+
}, children: jsx(Typography, { variant: 'body_normal', children: "Shielded" }) }), jsx("button", { type: 'button', role: 'tab', "aria-selected": activeShieldTab === 'unshielded', onClick: (e) => {
|
|
405
|
+
e.stopPropagation();
|
|
406
|
+
setActiveShieldTab('unshielded');
|
|
407
|
+
}, style: {
|
|
408
|
+
background: 'none',
|
|
409
|
+
border: 'none',
|
|
410
|
+
cursor: 'pointer',
|
|
411
|
+
fontWeight: activeShieldTab === 'unshielded' ? 600 : 400,
|
|
412
|
+
opacity: activeShieldTab === 'unshielded' ? 1 : 0.5,
|
|
413
|
+
padding: 0,
|
|
414
|
+
}, children: jsx(Typography, { variant: 'body_normal', children: "Unshielded" }) })] })), isAutoShielding && (jsx("div", { className: 'auto-shield-status', "data-testid": 'auto-shield-status', style: {
|
|
415
|
+
opacity: 0.7,
|
|
416
|
+
padding: '4px 16px 8px 16px',
|
|
417
|
+
}, children: jsx(Typography, { variant: 'body_small', children: "Auto-shielding\u2026" }) })), jsx(TokenBalanceList, { tokenBalances: filteredTokenBalances, getSecondaryAction: getSecondaryAction })] })] }), jsx(Portal, { elementId: 'dynamic-shield-confirm', isShown: Boolean(pendingShieldToken), zIndex: authModalZIndex, withBackdrop: true, handleClose: () => setPendingShieldToken(null), children: jsx(Modal, { children: jsx(ModalCard, { children: jsxs("div", { style: { padding: 24 }, children: [jsxs(Typography, { variant: 'title', weight: 'medium', color: 'primary', children: ["Shield ", (_d = pendingShieldToken === null || pendingShieldToken === void 0 ? void 0 : pendingShieldToken.balance) !== null && _d !== void 0 ? _d : '', ' ', (_e = pendingShieldToken === null || pendingShieldToken === void 0 ? void 0 : pendingShieldToken.symbol) !== null && _e !== void 0 ? _e : ''] }), jsx(Typography, { variant: 'body_normal', color: 'secondary', style: { display: 'block', marginTop: 8 }, children: "This token doesn't support auto-shielding. A network fee is required to shield manually." }), jsxs("div", { style: {
|
|
418
|
+
display: 'flex',
|
|
419
|
+
gap: 8,
|
|
420
|
+
marginTop: 24,
|
|
421
|
+
}, children: [jsx(Button, { buttonVariant: 'secondary', expanded: true, onClick: () => setPendingShieldToken(null), dataTestId: 'shield-confirm-modal-cancel', children: "Cancel" }), jsx(Button, { buttonVariant: 'primary', expanded: true, onClick: () => {
|
|
422
|
+
const target = pendingShieldToken;
|
|
423
|
+
setPendingShieldToken(null);
|
|
424
|
+
if (target) {
|
|
425
|
+
handleShieldToken(target).catch(() => {
|
|
426
|
+
/* error surfaced via state inside handleShieldToken */
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
}, dataTestId: 'shield-confirm-modal-confirm', children: "Shield" })] })] }) }) }) })] }));
|
|
225
430
|
};
|
|
226
431
|
|
|
227
432
|
export { ActiveWalletBalance };
|