@dynamic-labs/sdk-react-core 4.81.0 → 4.83.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 +24 -0
- package/package.cjs +2 -2
- package/package.js +2 -2
- package/package.json +13 -13
- 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/useAleoShieldedBalances.cjs +139 -68
- package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.js +139 -68
- package/src/lib/views/BackupUnsuccessfulView/BackupUnsuccessfulView.cjs +12 -1
- package/src/lib/views/BackupUnsuccessfulView/BackupUnsuccessfulView.js +12 -1
- 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 +26 -1
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/ActiveWalletBalance.js +26 -1
- 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
|
@@ -29,7 +29,7 @@ require('eventemitter3');
|
|
|
29
29
|
require('@dynamic-labs-sdk/client');
|
|
30
30
|
require('../../../config/ApiEndpoint.cjs');
|
|
31
31
|
require('@dynamic-labs/locale');
|
|
32
|
-
require('../../../store/state/dynamicContextProps/dynamicContextProps.cjs');
|
|
32
|
+
var dynamicContextProps = require('../../../store/state/dynamicContextProps/dynamicContextProps.cjs');
|
|
33
33
|
require('../../../store/state/primaryWalletId/primaryWalletId.cjs');
|
|
34
34
|
require('../../../store/state/connectedWalletsInfo/connectedWalletsInfo.cjs');
|
|
35
35
|
require('../../functions/getWaasAddressTypeLabel/getWaasAddressTypeLabel.cjs');
|
|
@@ -109,6 +109,7 @@ require('../../../store/state/multichainBalances.cjs');
|
|
|
109
109
|
require('@dynamic-labs/store');
|
|
110
110
|
require('../../../shared/utils/functions/getInitialUrl/getInitialUrl.cjs');
|
|
111
111
|
var useInternalDynamicContext = require('../../../context/DynamicContext/useDynamicContext/useInternalDynamicContext/useInternalDynamicContext.cjs');
|
|
112
|
+
var getAleoCuratedPrices = require('../../../data/api/aleo/getAleoCuratedPrices.cjs');
|
|
112
113
|
|
|
113
114
|
const MICROCREDITS_PER_CREDIT = 1000000;
|
|
114
115
|
const ALEO_CREDITS_LOGO = 'https://app.dynamic.xyz/assets/networks/aleo.svg';
|
|
@@ -227,6 +228,117 @@ const findTokenSpec = (record) => {
|
|
|
227
228
|
}
|
|
228
229
|
return undefined;
|
|
229
230
|
};
|
|
231
|
+
/**
|
|
232
|
+
* Coerces the widget-context `network` value into an Aleo network id
|
|
233
|
+
* (`0 = mainnet`, `1 = testnet`) and the matching param string for the
|
|
234
|
+
* `/waas/aleo/prices` endpoint. Pulled out of the callback to flatten
|
|
235
|
+
* cognitive complexity AND to avoid a SonarCloud-flagged nested
|
|
236
|
+
* ternary.
|
|
237
|
+
*/
|
|
238
|
+
const resolveAleoNetwork = (networkKey) => {
|
|
239
|
+
const numeric = Number(networkKey);
|
|
240
|
+
const safeNetworkId = Number.isFinite(numeric) ? numeric : undefined;
|
|
241
|
+
if (safeNetworkId === 0)
|
|
242
|
+
return { aleoNetworkParam: 'mainnet', safeNetworkId };
|
|
243
|
+
if (safeNetworkId === 1)
|
|
244
|
+
return { aleoNetworkParam: 'testnet', safeNetworkId };
|
|
245
|
+
return { aleoNetworkParam: undefined, safeNetworkId };
|
|
246
|
+
};
|
|
247
|
+
/**
|
|
248
|
+
* Build a `(address, isNative) → price` lookup from the curated-prices
|
|
249
|
+
* endpoint response. The key shape matches the multichain balance feed
|
|
250
|
+
* (native ALEO at `'0x0' + isNative=true`, every other token at its
|
|
251
|
+
* program id + `isNative=false`) so the join is a straight read.
|
|
252
|
+
*/
|
|
253
|
+
const buildPriceLookup = (priceList) => {
|
|
254
|
+
const priceByKey = new Map();
|
|
255
|
+
for (const entry of priceList) {
|
|
256
|
+
priceByKey.set(`${entry.address}|${entry.isNative ? 1 : 0}`, entry.price);
|
|
257
|
+
}
|
|
258
|
+
return (address, isNative) => { var _a; return (_a = priceByKey.get(`${address}|${isNative ? 1 : 0}`)) !== null && _a !== void 0 ? _a : null; };
|
|
259
|
+
};
|
|
260
|
+
/**
|
|
261
|
+
* Aggregate `credits.aleo / credits` records into the native ALEO
|
|
262
|
+
* `TokenBalance`. Returns `undefined` when the wallet owns no credits
|
|
263
|
+
* records so the caller can omit the row entirely.
|
|
264
|
+
*/
|
|
265
|
+
const buildCreditsBalance = (records, networkId, priceFor) => {
|
|
266
|
+
const creditsRecords = records.filter((r) => (r === null || r === void 0 ? void 0 : r.program_name) === 'credits.aleo' &&
|
|
267
|
+
(r === null || r === void 0 ? void 0 : r.record_name) === 'credits' &&
|
|
268
|
+
typeof (r === null || r === void 0 ? void 0 : r.microcredits) === 'string');
|
|
269
|
+
if (creditsRecords.length === 0)
|
|
270
|
+
return undefined;
|
|
271
|
+
const totalMicrocredits = creditsRecords.reduce((sum, r) => sum + BigInt(r.microcredits), BigInt(0));
|
|
272
|
+
// BigInt → number for the TokenBalance shape. Aleo balances stay well
|
|
273
|
+
// below Number.MAX_SAFE_INTEGER for a single wallet (max u64 supply is
|
|
274
|
+
// 1.5B credits = 1.5e15 microcredits; Number can hold up to ~9e15).
|
|
275
|
+
const rawBalance = Number(totalMicrocredits);
|
|
276
|
+
const balance = rawBalance / MICROCREDITS_PER_CREDIT;
|
|
277
|
+
const price = priceFor('0x0', true);
|
|
278
|
+
return {
|
|
279
|
+
address: '0x0',
|
|
280
|
+
balance,
|
|
281
|
+
decimals: 6,
|
|
282
|
+
isNative: true,
|
|
283
|
+
logoURI: ALEO_CREDITS_LOGO,
|
|
284
|
+
marketValue: price !== null ? balance * price : undefined,
|
|
285
|
+
name: 'Aleo Credits',
|
|
286
|
+
networkId,
|
|
287
|
+
price: price !== null ? price : undefined,
|
|
288
|
+
rawBalance,
|
|
289
|
+
symbol: 'ALEO',
|
|
290
|
+
};
|
|
291
|
+
};
|
|
292
|
+
/**
|
|
293
|
+
* Aggregate stablecoin + ARC-21 `Token` records by `(program, tokenId)`
|
|
294
|
+
* and emit one `TokenBalance` per matched spec. Records that don't
|
|
295
|
+
* match a curated spec, lack an `amount`, or have a malformed amount
|
|
296
|
+
* string are silently skipped.
|
|
297
|
+
*/
|
|
298
|
+
const buildTokenBalances = (records, networkId, priceFor) => {
|
|
299
|
+
var _a, _b;
|
|
300
|
+
const sumsByContract = new Map();
|
|
301
|
+
const specsByContract = new Map();
|
|
302
|
+
for (const r of records) {
|
|
303
|
+
const spec = findTokenSpec(r);
|
|
304
|
+
if (!spec || typeof r.amount !== 'string')
|
|
305
|
+
continue;
|
|
306
|
+
try {
|
|
307
|
+
const prev = (_a = sumsByContract.get(spec.contractAddress)) !== null && _a !== void 0 ? _a : BigInt(0);
|
|
308
|
+
sumsByContract.set(spec.contractAddress, prev + BigInt(r.amount));
|
|
309
|
+
specsByContract.set(spec.contractAddress, spec);
|
|
310
|
+
}
|
|
311
|
+
catch (_c) {
|
|
312
|
+
/* ignore — malformed amount string */
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
const out = [];
|
|
316
|
+
for (const [contractAddress, total] of sumsByContract.entries()) {
|
|
317
|
+
const spec = specsByContract.get(contractAddress);
|
|
318
|
+
if (!spec)
|
|
319
|
+
continue;
|
|
320
|
+
const rawBalance = Number(total);
|
|
321
|
+
const balance = rawBalance / Math.pow(10, spec.decimals);
|
|
322
|
+
const price = priceFor(spec.contractAddress, false);
|
|
323
|
+
out.push({
|
|
324
|
+
address: spec.contractAddress,
|
|
325
|
+
balance,
|
|
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: (_b = spec.logoURI) !== null && _b !== void 0 ? _b : UNKNOWN_TOKEN_LOGO,
|
|
332
|
+
marketValue: price !== null ? balance * price : undefined,
|
|
333
|
+
name: spec.name,
|
|
334
|
+
networkId,
|
|
335
|
+
price: price !== null ? price : undefined,
|
|
336
|
+
rawBalance,
|
|
337
|
+
symbol: spec.symbol,
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
return out;
|
|
341
|
+
};
|
|
230
342
|
/**
|
|
231
343
|
* Hook that returns the active wallet's shielded (private) Aleo token
|
|
232
344
|
* balances as a `TokenBalance[]` so the widget can render them through the
|
|
@@ -262,7 +374,7 @@ const useAleoShieldedBalances = () => {
|
|
|
262
374
|
const connectorKey = connector === null || connector === void 0 ? void 0 : connector.key;
|
|
263
375
|
const networkKey = network !== undefined && network !== null ? String(network) : undefined;
|
|
264
376
|
const fetchShielded = React.useCallback(() => _tslib.__awaiter(void 0, void 0, void 0, function* () {
|
|
265
|
-
var _a
|
|
377
|
+
var _a;
|
|
266
378
|
const liveConnector = connectorRef.current;
|
|
267
379
|
if (!supportsShielded || !liveConnector) {
|
|
268
380
|
setTokenBalances((prev) => (prev.length === 0 ? prev : []));
|
|
@@ -271,74 +383,33 @@ const useAleoShieldedBalances = () => {
|
|
|
271
383
|
setIsLoading(true);
|
|
272
384
|
setError(undefined);
|
|
273
385
|
try {
|
|
274
|
-
|
|
386
|
+
// Fetch records and the curated-token price list in parallel. The
|
|
387
|
+
// price list comes from the Aleo-only `/waas/aleo/prices` endpoint
|
|
388
|
+
// (independent of balance) so the join works even when the user
|
|
389
|
+
// holds a shielded token with zero unshielded balance — the
|
|
390
|
+
// multichain `/accountBalances` endpoint would have stripped that
|
|
391
|
+
// token row, leaving the widget with no price source. Prices are
|
|
392
|
+
// best-effort: a failure leaves balances unpriced rather than
|
|
393
|
+
// dropping the shielded list entirely.
|
|
394
|
+
const { safeNetworkId, aleoNetworkParam } = resolveAleoNetwork(networkKey);
|
|
395
|
+
const environmentId = dynamicContextProps.getEnvironmentId();
|
|
396
|
+
const shouldFetchPrices = Boolean(aleoNetworkParam && environmentId);
|
|
397
|
+
const [result, priceList] = yield Promise.all([
|
|
398
|
+
liveConnector.listOwnedRecords(),
|
|
399
|
+
shouldFetchPrices && aleoNetworkParam
|
|
400
|
+
? getAleoCuratedPrices.getAleoCuratedPrices({
|
|
401
|
+
environmentId,
|
|
402
|
+
network: aleoNetworkParam,
|
|
403
|
+
}).catch(() => [])
|
|
404
|
+
: Promise.resolve([]),
|
|
405
|
+
]);
|
|
275
406
|
const records = (_a = result === null || result === void 0 ? void 0 : result.records) !== null && _a !== void 0 ? _a : [];
|
|
276
|
-
const
|
|
277
|
-
const safeNetworkId = Number.isFinite(networkIdNumeric)
|
|
278
|
-
? networkIdNumeric
|
|
279
|
-
: undefined;
|
|
407
|
+
const priceFor = buildPriceLookup(priceList);
|
|
280
408
|
const balances = [];
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
(
|
|
284
|
-
|
|
285
|
-
if (creditsRecords.length > 0) {
|
|
286
|
-
const totalMicrocredits = creditsRecords.reduce((sum, r) => sum + BigInt(r.microcredits), BigInt(0));
|
|
287
|
-
// BigInt → number for the TokenBalance shape. Aleo balances stay well
|
|
288
|
-
// below Number.MAX_SAFE_INTEGER for a single wallet (max u64 supply is
|
|
289
|
-
// 1.5B credits = 1.5e15 microcredits; Number can hold up to ~9e15).
|
|
290
|
-
const rawBalance = Number(totalMicrocredits);
|
|
291
|
-
balances.push({
|
|
292
|
-
address: '0x0',
|
|
293
|
-
balance: rawBalance / MICROCREDITS_PER_CREDIT,
|
|
294
|
-
decimals: 6,
|
|
295
|
-
isNative: true,
|
|
296
|
-
logoURI: ALEO_CREDITS_LOGO,
|
|
297
|
-
name: 'Aleo Credits',
|
|
298
|
-
networkId: safeNetworkId,
|
|
299
|
-
rawBalance,
|
|
300
|
-
symbol: 'ALEO',
|
|
301
|
-
});
|
|
302
|
-
}
|
|
303
|
-
// Tier 3 + ARC-21: Token records. Each record matches at most one
|
|
304
|
-
// spec (stablecoin programs disambiguate by program; ARC-21 records
|
|
305
|
-
// share `token_registry.aleo / Token` and disambiguate by tokenId
|
|
306
|
-
// inside the plaintext). Sum the `amount` field per spec.
|
|
307
|
-
const sumsByContract = new Map();
|
|
308
|
-
const specsByContract = new Map();
|
|
309
|
-
for (const r of records) {
|
|
310
|
-
const spec = findTokenSpec(r);
|
|
311
|
-
if (!spec || typeof r.amount !== 'string')
|
|
312
|
-
continue;
|
|
313
|
-
try {
|
|
314
|
-
const prev = (_b = sumsByContract.get(spec.contractAddress)) !== null && _b !== void 0 ? _b : BigInt(0);
|
|
315
|
-
sumsByContract.set(spec.contractAddress, prev + BigInt(r.amount));
|
|
316
|
-
specsByContract.set(spec.contractAddress, spec);
|
|
317
|
-
}
|
|
318
|
-
catch (_d) {
|
|
319
|
-
/* ignore — malformed amount string */
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
for (const [contractAddress, total] of sumsByContract.entries()) {
|
|
323
|
-
const spec = specsByContract.get(contractAddress);
|
|
324
|
-
if (!spec)
|
|
325
|
-
continue;
|
|
326
|
-
const rawBalance = Number(total);
|
|
327
|
-
balances.push({
|
|
328
|
-
address: spec.contractAddress,
|
|
329
|
-
balance: rawBalance / Math.pow(10, spec.decimals),
|
|
330
|
-
decimals: spec.decimals,
|
|
331
|
-
// Use redcoast's `DEFAULT_TOKEN_LOGO_URI` for stablecoins + ARC-21
|
|
332
|
-
// so they render the same dark "?" icon the Unshielded tab shows
|
|
333
|
-
// for these tokens (the multichain endpoint applies that fallback
|
|
334
|
-
// itself; we mirror it here for visual parity).
|
|
335
|
-
logoURI: (_c = spec.logoURI) !== null && _c !== void 0 ? _c : UNKNOWN_TOKEN_LOGO,
|
|
336
|
-
name: spec.name,
|
|
337
|
-
networkId: safeNetworkId,
|
|
338
|
-
rawBalance,
|
|
339
|
-
symbol: spec.symbol,
|
|
340
|
-
});
|
|
341
|
-
}
|
|
409
|
+
const credits = buildCreditsBalance(records, safeNetworkId, priceFor);
|
|
410
|
+
if (credits)
|
|
411
|
+
balances.push(credits);
|
|
412
|
+
balances.push(...buildTokenBalances(records, safeNetworkId, priceFor));
|
|
342
413
|
setTokenBalances(balances);
|
|
343
414
|
}
|
|
344
415
|
catch (err) {
|
|
@@ -25,7 +25,7 @@ import 'eventemitter3';
|
|
|
25
25
|
import '@dynamic-labs-sdk/client';
|
|
26
26
|
import '../../../config/ApiEndpoint.js';
|
|
27
27
|
import '@dynamic-labs/locale';
|
|
28
|
-
import '../../../store/state/dynamicContextProps/dynamicContextProps.js';
|
|
28
|
+
import { getEnvironmentId } from '../../../store/state/dynamicContextProps/dynamicContextProps.js';
|
|
29
29
|
import '../../../store/state/primaryWalletId/primaryWalletId.js';
|
|
30
30
|
import '../../../store/state/connectedWalletsInfo/connectedWalletsInfo.js';
|
|
31
31
|
import '../../functions/getWaasAddressTypeLabel/getWaasAddressTypeLabel.js';
|
|
@@ -105,6 +105,7 @@ import '../../../store/state/multichainBalances.js';
|
|
|
105
105
|
import '@dynamic-labs/store';
|
|
106
106
|
import '../../../shared/utils/functions/getInitialUrl/getInitialUrl.js';
|
|
107
107
|
import { useInternalDynamicContext } from '../../../context/DynamicContext/useDynamicContext/useInternalDynamicContext/useInternalDynamicContext.js';
|
|
108
|
+
import { getAleoCuratedPrices } from '../../../data/api/aleo/getAleoCuratedPrices.js';
|
|
108
109
|
|
|
109
110
|
const MICROCREDITS_PER_CREDIT = 1000000;
|
|
110
111
|
const ALEO_CREDITS_LOGO = 'https://app.dynamic.xyz/assets/networks/aleo.svg';
|
|
@@ -223,6 +224,117 @@ const findTokenSpec = (record) => {
|
|
|
223
224
|
}
|
|
224
225
|
return undefined;
|
|
225
226
|
};
|
|
227
|
+
/**
|
|
228
|
+
* Coerces the widget-context `network` value into an Aleo network id
|
|
229
|
+
* (`0 = mainnet`, `1 = testnet`) and the matching param string for the
|
|
230
|
+
* `/waas/aleo/prices` endpoint. Pulled out of the callback to flatten
|
|
231
|
+
* cognitive complexity AND to avoid a SonarCloud-flagged nested
|
|
232
|
+
* ternary.
|
|
233
|
+
*/
|
|
234
|
+
const resolveAleoNetwork = (networkKey) => {
|
|
235
|
+
const numeric = Number(networkKey);
|
|
236
|
+
const safeNetworkId = Number.isFinite(numeric) ? numeric : undefined;
|
|
237
|
+
if (safeNetworkId === 0)
|
|
238
|
+
return { aleoNetworkParam: 'mainnet', safeNetworkId };
|
|
239
|
+
if (safeNetworkId === 1)
|
|
240
|
+
return { aleoNetworkParam: 'testnet', safeNetworkId };
|
|
241
|
+
return { aleoNetworkParam: undefined, safeNetworkId };
|
|
242
|
+
};
|
|
243
|
+
/**
|
|
244
|
+
* Build a `(address, isNative) → price` lookup from the curated-prices
|
|
245
|
+
* endpoint response. The key shape matches the multichain balance feed
|
|
246
|
+
* (native ALEO at `'0x0' + isNative=true`, every other token at its
|
|
247
|
+
* program id + `isNative=false`) so the join is a straight read.
|
|
248
|
+
*/
|
|
249
|
+
const buildPriceLookup = (priceList) => {
|
|
250
|
+
const priceByKey = new Map();
|
|
251
|
+
for (const entry of priceList) {
|
|
252
|
+
priceByKey.set(`${entry.address}|${entry.isNative ? 1 : 0}`, entry.price);
|
|
253
|
+
}
|
|
254
|
+
return (address, isNative) => { var _a; return (_a = priceByKey.get(`${address}|${isNative ? 1 : 0}`)) !== null && _a !== void 0 ? _a : null; };
|
|
255
|
+
};
|
|
256
|
+
/**
|
|
257
|
+
* Aggregate `credits.aleo / credits` records into the native ALEO
|
|
258
|
+
* `TokenBalance`. Returns `undefined` when the wallet owns no credits
|
|
259
|
+
* records so the caller can omit the row entirely.
|
|
260
|
+
*/
|
|
261
|
+
const buildCreditsBalance = (records, networkId, priceFor) => {
|
|
262
|
+
const creditsRecords = records.filter((r) => (r === null || r === void 0 ? void 0 : r.program_name) === 'credits.aleo' &&
|
|
263
|
+
(r === null || r === void 0 ? void 0 : r.record_name) === 'credits' &&
|
|
264
|
+
typeof (r === null || r === void 0 ? void 0 : r.microcredits) === 'string');
|
|
265
|
+
if (creditsRecords.length === 0)
|
|
266
|
+
return undefined;
|
|
267
|
+
const totalMicrocredits = creditsRecords.reduce((sum, r) => sum + BigInt(r.microcredits), BigInt(0));
|
|
268
|
+
// BigInt → number for the TokenBalance shape. Aleo balances stay well
|
|
269
|
+
// below Number.MAX_SAFE_INTEGER for a single wallet (max u64 supply is
|
|
270
|
+
// 1.5B credits = 1.5e15 microcredits; Number can hold up to ~9e15).
|
|
271
|
+
const rawBalance = Number(totalMicrocredits);
|
|
272
|
+
const balance = rawBalance / MICROCREDITS_PER_CREDIT;
|
|
273
|
+
const price = priceFor('0x0', true);
|
|
274
|
+
return {
|
|
275
|
+
address: '0x0',
|
|
276
|
+
balance,
|
|
277
|
+
decimals: 6,
|
|
278
|
+
isNative: true,
|
|
279
|
+
logoURI: ALEO_CREDITS_LOGO,
|
|
280
|
+
marketValue: price !== null ? balance * price : undefined,
|
|
281
|
+
name: 'Aleo Credits',
|
|
282
|
+
networkId,
|
|
283
|
+
price: price !== null ? price : undefined,
|
|
284
|
+
rawBalance,
|
|
285
|
+
symbol: 'ALEO',
|
|
286
|
+
};
|
|
287
|
+
};
|
|
288
|
+
/**
|
|
289
|
+
* Aggregate stablecoin + ARC-21 `Token` records by `(program, tokenId)`
|
|
290
|
+
* and emit one `TokenBalance` per matched spec. Records that don't
|
|
291
|
+
* match a curated spec, lack an `amount`, or have a malformed amount
|
|
292
|
+
* string are silently skipped.
|
|
293
|
+
*/
|
|
294
|
+
const buildTokenBalances = (records, networkId, priceFor) => {
|
|
295
|
+
var _a, _b;
|
|
296
|
+
const sumsByContract = new Map();
|
|
297
|
+
const specsByContract = new Map();
|
|
298
|
+
for (const r of records) {
|
|
299
|
+
const spec = findTokenSpec(r);
|
|
300
|
+
if (!spec || typeof r.amount !== 'string')
|
|
301
|
+
continue;
|
|
302
|
+
try {
|
|
303
|
+
const prev = (_a = sumsByContract.get(spec.contractAddress)) !== null && _a !== void 0 ? _a : BigInt(0);
|
|
304
|
+
sumsByContract.set(spec.contractAddress, prev + BigInt(r.amount));
|
|
305
|
+
specsByContract.set(spec.contractAddress, spec);
|
|
306
|
+
}
|
|
307
|
+
catch (_c) {
|
|
308
|
+
/* ignore — malformed amount string */
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
const out = [];
|
|
312
|
+
for (const [contractAddress, total] of sumsByContract.entries()) {
|
|
313
|
+
const spec = specsByContract.get(contractAddress);
|
|
314
|
+
if (!spec)
|
|
315
|
+
continue;
|
|
316
|
+
const rawBalance = Number(total);
|
|
317
|
+
const balance = rawBalance / Math.pow(10, spec.decimals);
|
|
318
|
+
const price = priceFor(spec.contractAddress, false);
|
|
319
|
+
out.push({
|
|
320
|
+
address: spec.contractAddress,
|
|
321
|
+
balance,
|
|
322
|
+
decimals: spec.decimals,
|
|
323
|
+
// Use redcoast's `DEFAULT_TOKEN_LOGO_URI` for stablecoins + ARC-21
|
|
324
|
+
// so they render the same dark "?" icon the Unshielded tab shows
|
|
325
|
+
// for these tokens (the multichain endpoint applies that fallback
|
|
326
|
+
// itself; we mirror it here for visual parity).
|
|
327
|
+
logoURI: (_b = spec.logoURI) !== null && _b !== void 0 ? _b : UNKNOWN_TOKEN_LOGO,
|
|
328
|
+
marketValue: price !== null ? balance * price : undefined,
|
|
329
|
+
name: spec.name,
|
|
330
|
+
networkId,
|
|
331
|
+
price: price !== null ? price : undefined,
|
|
332
|
+
rawBalance,
|
|
333
|
+
symbol: spec.symbol,
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
return out;
|
|
337
|
+
};
|
|
226
338
|
/**
|
|
227
339
|
* Hook that returns the active wallet's shielded (private) Aleo token
|
|
228
340
|
* balances as a `TokenBalance[]` so the widget can render them through the
|
|
@@ -258,7 +370,7 @@ const useAleoShieldedBalances = () => {
|
|
|
258
370
|
const connectorKey = connector === null || connector === void 0 ? void 0 : connector.key;
|
|
259
371
|
const networkKey = network !== undefined && network !== null ? String(network) : undefined;
|
|
260
372
|
const fetchShielded = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
261
|
-
var _a
|
|
373
|
+
var _a;
|
|
262
374
|
const liveConnector = connectorRef.current;
|
|
263
375
|
if (!supportsShielded || !liveConnector) {
|
|
264
376
|
setTokenBalances((prev) => (prev.length === 0 ? prev : []));
|
|
@@ -267,74 +379,33 @@ const useAleoShieldedBalances = () => {
|
|
|
267
379
|
setIsLoading(true);
|
|
268
380
|
setError(undefined);
|
|
269
381
|
try {
|
|
270
|
-
|
|
382
|
+
// Fetch records and the curated-token price list in parallel. The
|
|
383
|
+
// price list comes from the Aleo-only `/waas/aleo/prices` endpoint
|
|
384
|
+
// (independent of balance) so the join works even when the user
|
|
385
|
+
// holds a shielded token with zero unshielded balance — the
|
|
386
|
+
// multichain `/accountBalances` endpoint would have stripped that
|
|
387
|
+
// token row, leaving the widget with no price source. Prices are
|
|
388
|
+
// best-effort: a failure leaves balances unpriced rather than
|
|
389
|
+
// dropping the shielded list entirely.
|
|
390
|
+
const { safeNetworkId, aleoNetworkParam } = resolveAleoNetwork(networkKey);
|
|
391
|
+
const environmentId = getEnvironmentId();
|
|
392
|
+
const shouldFetchPrices = Boolean(aleoNetworkParam && environmentId);
|
|
393
|
+
const [result, priceList] = yield Promise.all([
|
|
394
|
+
liveConnector.listOwnedRecords(),
|
|
395
|
+
shouldFetchPrices && aleoNetworkParam
|
|
396
|
+
? getAleoCuratedPrices({
|
|
397
|
+
environmentId,
|
|
398
|
+
network: aleoNetworkParam,
|
|
399
|
+
}).catch(() => [])
|
|
400
|
+
: Promise.resolve([]),
|
|
401
|
+
]);
|
|
271
402
|
const records = (_a = result === null || result === void 0 ? void 0 : result.records) !== null && _a !== void 0 ? _a : [];
|
|
272
|
-
const
|
|
273
|
-
const safeNetworkId = Number.isFinite(networkIdNumeric)
|
|
274
|
-
? networkIdNumeric
|
|
275
|
-
: undefined;
|
|
403
|
+
const priceFor = buildPriceLookup(priceList);
|
|
276
404
|
const balances = [];
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
(
|
|
280
|
-
|
|
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
|
-
}
|
|
405
|
+
const credits = buildCreditsBalance(records, safeNetworkId, priceFor);
|
|
406
|
+
if (credits)
|
|
407
|
+
balances.push(credits);
|
|
408
|
+
balances.push(...buildTokenBalances(records, safeNetworkId, priceFor));
|
|
338
409
|
setTokenBalances(balances);
|
|
339
410
|
}
|
|
340
411
|
catch (err) {
|
|
@@ -132,8 +132,19 @@ const BackupUnsuccessfulView = () => {
|
|
|
132
132
|
const refreshPage = () => {
|
|
133
133
|
window.location.reload();
|
|
134
134
|
};
|
|
135
|
+
const onTryAgainClick = () => {
|
|
136
|
+
logger.logger.instrument('Wallet creation retry modal try again clicked', {
|
|
137
|
+
key: 'wallet_creation_retry_modal_try_again_clicked',
|
|
138
|
+
time: 0,
|
|
139
|
+
});
|
|
140
|
+
refreshPage();
|
|
141
|
+
};
|
|
135
142
|
// force refresh on component unmount
|
|
136
143
|
React.useEffect(() => {
|
|
144
|
+
logger.logger.instrument('Wallet creation retry modal shown', {
|
|
145
|
+
key: 'wallet_creation_retry_modal_shown',
|
|
146
|
+
time: 0,
|
|
147
|
+
});
|
|
137
148
|
const timer = setTimeout(() => {
|
|
138
149
|
isProperlyMounted.current = true;
|
|
139
150
|
}, 100);
|
|
@@ -154,7 +165,7 @@ const BackupUnsuccessfulView = () => {
|
|
|
154
165
|
transform: 'translate(-50%, -50%)',
|
|
155
166
|
} })] })] }), jsxRuntime.jsx(Typography.Typography, { variant: 'body_normal', className: 'backup-message', color: 'primary', copykey: 'dyn_waas.backup_unsuccessful.description', children: t('dyn_waas.backup_unsuccessful.description') }), jsxRuntime.jsx("div", { className: classNames.classNames('button-group', {
|
|
156
167
|
'button-group--with-help-section': hasContactInfo,
|
|
157
|
-
}), children: jsxRuntime.jsx(TypographyButton.TypographyButton, { buttonClassName: 'retry-button', buttonVariant: 'brand-primary', type: 'submit', onClick:
|
|
168
|
+
}), children: jsxRuntime.jsx(TypographyButton.TypographyButton, { buttonClassName: 'retry-button', buttonVariant: 'brand-primary', type: 'submit', onClick: onTryAgainClick, copykey: 'dyn_waas.backup_unsuccessful.try_again', typographyProps: {
|
|
158
169
|
color: 'inherit',
|
|
159
170
|
}, children: t('dyn_waas.backup_unsuccessful.try_again') }) }), jsxRuntime.jsx("div", { className: classNames.classNames('button-group', 'logout-group', {
|
|
160
171
|
'button-group--with-help-section': hasContactInfo,
|
|
@@ -128,8 +128,19 @@ const BackupUnsuccessfulView = () => {
|
|
|
128
128
|
const refreshPage = () => {
|
|
129
129
|
window.location.reload();
|
|
130
130
|
};
|
|
131
|
+
const onTryAgainClick = () => {
|
|
132
|
+
logger.instrument('Wallet creation retry modal try again clicked', {
|
|
133
|
+
key: 'wallet_creation_retry_modal_try_again_clicked',
|
|
134
|
+
time: 0,
|
|
135
|
+
});
|
|
136
|
+
refreshPage();
|
|
137
|
+
};
|
|
131
138
|
// force refresh on component unmount
|
|
132
139
|
useEffect(() => {
|
|
140
|
+
logger.instrument('Wallet creation retry modal shown', {
|
|
141
|
+
key: 'wallet_creation_retry_modal_shown',
|
|
142
|
+
time: 0,
|
|
143
|
+
});
|
|
133
144
|
const timer = setTimeout(() => {
|
|
134
145
|
isProperlyMounted.current = true;
|
|
135
146
|
}, 100);
|
|
@@ -150,7 +161,7 @@ const BackupUnsuccessfulView = () => {
|
|
|
150
161
|
transform: 'translate(-50%, -50%)',
|
|
151
162
|
} })] })] }), jsx(Typography, { variant: 'body_normal', className: 'backup-message', color: 'primary', copykey: 'dyn_waas.backup_unsuccessful.description', children: t('dyn_waas.backup_unsuccessful.description') }), jsx("div", { className: classNames('button-group', {
|
|
152
163
|
'button-group--with-help-section': hasContactInfo,
|
|
153
|
-
}), children: jsx(TypographyButton, { buttonClassName: 'retry-button', buttonVariant: 'brand-primary', type: 'submit', onClick:
|
|
164
|
+
}), children: jsx(TypographyButton, { buttonClassName: 'retry-button', buttonVariant: 'brand-primary', type: 'submit', onClick: onTryAgainClick, copykey: 'dyn_waas.backup_unsuccessful.try_again', typographyProps: {
|
|
154
165
|
color: 'inherit',
|
|
155
166
|
}, children: t('dyn_waas.backup_unsuccessful.try_again') }) }), jsx("div", { className: classNames('button-group', 'logout-group', {
|
|
156
167
|
'button-group--with-help-section': hasContactInfo,
|