@dynamic-labs/sdk-react-core 4.83.1 → 4.83.2-alpha.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 +18 -0
- package/package.cjs +4 -4
- package/package.js +4 -4
- package/package.json +15 -15
- package/src/lib/client/extension/deprecated/mfa/verifyTotpMfaDevice/verifyTotpMfaDevice.d.ts +1 -1
- package/src/lib/components/SendBalancePageLayout/SendBalancePageLayout.cjs +2 -0
- package/src/lib/components/SendBalancePageLayout/SendBalancePageLayout.js +2 -0
- package/src/lib/components/SendBalancePageLayout/components/TokensBalanceDropdown/TokensBalanceDropdown.cjs +1 -0
- package/src/lib/components/SendBalancePageLayout/components/TokensBalanceDropdown/TokensBalanceDropdown.js +1 -0
- package/src/lib/data/api/aleo/getAleoCuratedPrices.d.ts +9 -0
- package/src/lib/styles/index.shadow.cjs +1 -1
- package/src/lib/styles/index.shadow.js +1 -1
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/buildTokenKey.cjs +18 -0
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/buildTokenKey.d.ts +18 -0
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/buildTokenKey.js +14 -0
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/index.d.ts +2 -0
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/nativeTokenKey.cjs +15 -0
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/nativeTokenKey.d.ts +8 -0
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/nativeTokenKey.js +11 -0
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/pollOnShielded.cjs +50 -0
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/pollOnShielded.d.ts +12 -0
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/pollOnShielded.js +45 -0
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/useAleoAutoShieldSponsoredTokens.cjs +48 -41
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/useAleoAutoShieldSponsoredTokens.d.ts +11 -0
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/useAleoAutoShieldSponsoredTokens.js +47 -40
- package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.cjs +43 -29
- package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.js +43 -29
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/ActiveWalletBalance.cjs +45 -2
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/ActiveWalletBalance.js +46 -3
|
@@ -144,25 +144,29 @@ const resolveAleoNetwork = (networkKey) => {
|
|
|
144
144
|
return { aleoNetworkParam: 'testnet', safeNetworkId };
|
|
145
145
|
return { aleoNetworkParam: undefined, safeNetworkId };
|
|
146
146
|
};
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
* endpoint response. The key shape matches the multichain balance feed
|
|
150
|
-
* (native ALEO at `'0x0' + isNative=true`, every other token at its
|
|
151
|
-
* program id + `isNative=false`) so the join is a straight read.
|
|
152
|
-
*/
|
|
153
|
-
const buildPriceLookup = (priceList) => {
|
|
154
|
-
const priceByKey = new Map();
|
|
147
|
+
const buildCuratedTokenLookup = (priceList) => {
|
|
148
|
+
const byKey = new Map();
|
|
155
149
|
for (const entry of priceList) {
|
|
156
|
-
|
|
150
|
+
byKey.set(`${entry.address}|${entry.isNative ? 1 : 0}`, {
|
|
151
|
+
logoURI: entry.logoURI,
|
|
152
|
+
price: entry.price,
|
|
153
|
+
});
|
|
157
154
|
}
|
|
158
|
-
return (address, isNative) => {
|
|
155
|
+
return (address, isNative) => {
|
|
156
|
+
var _a;
|
|
157
|
+
return (_a = byKey.get(`${address}|${isNative ? 1 : 0}`)) !== null && _a !== void 0 ? _a : {
|
|
158
|
+
logoURI: undefined,
|
|
159
|
+
price: null,
|
|
160
|
+
};
|
|
161
|
+
};
|
|
159
162
|
};
|
|
160
163
|
/**
|
|
161
164
|
* Aggregate `credits.aleo / credits` records into the native ALEO
|
|
162
165
|
* `TokenBalance`. Returns `undefined` when the wallet owns no credits
|
|
163
166
|
* records so the caller can omit the row entirely.
|
|
164
167
|
*/
|
|
165
|
-
const buildCreditsBalance = (records, networkId,
|
|
168
|
+
const buildCreditsBalance = (records, networkId, lookupCurated) => {
|
|
169
|
+
var _a;
|
|
166
170
|
const creditsRecords = records.filter((r) => (r === null || r === void 0 ? void 0 : r.program_name) === 'credits.aleo' &&
|
|
167
171
|
(r === null || r === void 0 ? void 0 : r.record_name) === 'credits' &&
|
|
168
172
|
typeof (r === null || r === void 0 ? void 0 : r.microcredits) === 'string');
|
|
@@ -173,19 +177,25 @@ const buildCreditsBalance = (records, networkId, priceFor) => {
|
|
|
173
177
|
// below Number.MAX_SAFE_INTEGER for a single wallet (max u64 supply is
|
|
174
178
|
// 1.5B credits = 1.5e15 microcredits; Number can hold up to ~9e15).
|
|
175
179
|
const rawBalance = Number(totalMicrocredits);
|
|
180
|
+
const rawBalanceString = totalMicrocredits.toString();
|
|
176
181
|
const balance = rawBalance / MICROCREDITS_PER_CREDIT;
|
|
177
|
-
const
|
|
182
|
+
const curated = lookupCurated('0x0', true);
|
|
178
183
|
return {
|
|
179
184
|
address: '0x0',
|
|
180
185
|
balance,
|
|
181
186
|
decimals: 6,
|
|
182
187
|
isNative: true,
|
|
183
|
-
|
|
184
|
-
|
|
188
|
+
// Prefer the server-curated logo (single source of truth for both
|
|
189
|
+
// the unshielded multichain feed and the shielded tab); fall back
|
|
190
|
+
// to the bundled ALEO glyph for older redcoast deployments that
|
|
191
|
+
// don't yet send `logoURI` on the prices response.
|
|
192
|
+
logoURI: (_a = curated.logoURI) !== null && _a !== void 0 ? _a : ALEO_CREDITS_LOGO,
|
|
193
|
+
marketValue: curated.price !== null ? balance * curated.price : undefined,
|
|
185
194
|
name: 'Aleo Credits',
|
|
186
195
|
networkId,
|
|
187
|
-
price: price !== null ? price : undefined,
|
|
196
|
+
price: curated.price !== null ? curated.price : undefined,
|
|
188
197
|
rawBalance,
|
|
198
|
+
rawBalanceString,
|
|
189
199
|
symbol: 'ALEO',
|
|
190
200
|
};
|
|
191
201
|
};
|
|
@@ -195,8 +205,8 @@ const buildCreditsBalance = (records, networkId, priceFor) => {
|
|
|
195
205
|
* match a curated spec, lack an `amount`, or have a malformed amount
|
|
196
206
|
* string are silently skipped.
|
|
197
207
|
*/
|
|
198
|
-
const buildTokenBalances = (records, networkId,
|
|
199
|
-
var _a, _b;
|
|
208
|
+
const buildTokenBalances = (records, networkId, lookupCurated) => {
|
|
209
|
+
var _a, _b, _c;
|
|
200
210
|
const sumsByContract = new Map();
|
|
201
211
|
const specsByContract = new Map();
|
|
202
212
|
for (const r of records) {
|
|
@@ -208,7 +218,7 @@ const buildTokenBalances = (records, networkId, priceFor) => {
|
|
|
208
218
|
sumsByContract.set(spec.contractAddress, prev + BigInt(r.amount));
|
|
209
219
|
specsByContract.set(spec.contractAddress, spec);
|
|
210
220
|
}
|
|
211
|
-
catch (
|
|
221
|
+
catch (_d) {
|
|
212
222
|
/* ignore — malformed amount string */
|
|
213
223
|
}
|
|
214
224
|
}
|
|
@@ -218,22 +228,26 @@ const buildTokenBalances = (records, networkId, priceFor) => {
|
|
|
218
228
|
if (!spec)
|
|
219
229
|
continue;
|
|
220
230
|
const rawBalance = Number(total);
|
|
231
|
+
const rawBalanceString = total.toString();
|
|
221
232
|
const balance = rawBalance / Math.pow(10, spec.decimals);
|
|
222
|
-
const
|
|
233
|
+
const curated = lookupCurated(spec.contractAddress, false);
|
|
223
234
|
out.push({
|
|
224
235
|
address: spec.contractAddress,
|
|
225
236
|
balance,
|
|
226
237
|
decimals: spec.decimals,
|
|
227
|
-
//
|
|
228
|
-
//
|
|
229
|
-
//
|
|
230
|
-
//
|
|
231
|
-
|
|
232
|
-
|
|
238
|
+
// Prefer the server-curated logo so the Shielded tab renders the
|
|
239
|
+
// same brand glyph the Unshielded tab gets from the multichain
|
|
240
|
+
// feed. Fall back to the local spec override (kept for tests +
|
|
241
|
+
// any future curated-but-not-yet-on-server tokens), then to the
|
|
242
|
+
// generic dark `?` placeholder for older redcoast deployments
|
|
243
|
+
// that haven't rolled out the logo response field yet.
|
|
244
|
+
logoURI: (_c = (_b = curated.logoURI) !== null && _b !== void 0 ? _b : spec.logoURI) !== null && _c !== void 0 ? _c : UNKNOWN_TOKEN_LOGO,
|
|
245
|
+
marketValue: curated.price !== null ? balance * curated.price : undefined,
|
|
233
246
|
name: spec.name,
|
|
234
247
|
networkId,
|
|
235
|
-
price: price !== null ? price : undefined,
|
|
248
|
+
price: curated.price !== null ? curated.price : undefined,
|
|
236
249
|
rawBalance,
|
|
250
|
+
rawBalanceString,
|
|
237
251
|
symbol: spec.symbol,
|
|
238
252
|
});
|
|
239
253
|
}
|
|
@@ -304,12 +318,12 @@ const useAleoShieldedBalances = () => {
|
|
|
304
318
|
: Promise.resolve([]),
|
|
305
319
|
]);
|
|
306
320
|
const records = (_a = result === null || result === void 0 ? void 0 : result.records) !== null && _a !== void 0 ? _a : [];
|
|
307
|
-
const
|
|
321
|
+
const lookupCurated = buildCuratedTokenLookup(priceList);
|
|
308
322
|
const balances = [];
|
|
309
|
-
const credits = buildCreditsBalance(records, safeNetworkId,
|
|
323
|
+
const credits = buildCreditsBalance(records, safeNetworkId, lookupCurated);
|
|
310
324
|
if (credits)
|
|
311
325
|
balances.push(credits);
|
|
312
|
-
balances.push(...buildTokenBalances(records, safeNetworkId,
|
|
326
|
+
balances.push(...buildTokenBalances(records, safeNetworkId, lookupCurated));
|
|
313
327
|
setTokenBalances(balances);
|
|
314
328
|
}
|
|
315
329
|
catch (err) {
|
|
@@ -140,25 +140,29 @@ const resolveAleoNetwork = (networkKey) => {
|
|
|
140
140
|
return { aleoNetworkParam: 'testnet', safeNetworkId };
|
|
141
141
|
return { aleoNetworkParam: undefined, safeNetworkId };
|
|
142
142
|
};
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
* endpoint response. The key shape matches the multichain balance feed
|
|
146
|
-
* (native ALEO at `'0x0' + isNative=true`, every other token at its
|
|
147
|
-
* program id + `isNative=false`) so the join is a straight read.
|
|
148
|
-
*/
|
|
149
|
-
const buildPriceLookup = (priceList) => {
|
|
150
|
-
const priceByKey = new Map();
|
|
143
|
+
const buildCuratedTokenLookup = (priceList) => {
|
|
144
|
+
const byKey = new Map();
|
|
151
145
|
for (const entry of priceList) {
|
|
152
|
-
|
|
146
|
+
byKey.set(`${entry.address}|${entry.isNative ? 1 : 0}`, {
|
|
147
|
+
logoURI: entry.logoURI,
|
|
148
|
+
price: entry.price,
|
|
149
|
+
});
|
|
153
150
|
}
|
|
154
|
-
return (address, isNative) => {
|
|
151
|
+
return (address, isNative) => {
|
|
152
|
+
var _a;
|
|
153
|
+
return (_a = byKey.get(`${address}|${isNative ? 1 : 0}`)) !== null && _a !== void 0 ? _a : {
|
|
154
|
+
logoURI: undefined,
|
|
155
|
+
price: null,
|
|
156
|
+
};
|
|
157
|
+
};
|
|
155
158
|
};
|
|
156
159
|
/**
|
|
157
160
|
* Aggregate `credits.aleo / credits` records into the native ALEO
|
|
158
161
|
* `TokenBalance`. Returns `undefined` when the wallet owns no credits
|
|
159
162
|
* records so the caller can omit the row entirely.
|
|
160
163
|
*/
|
|
161
|
-
const buildCreditsBalance = (records, networkId,
|
|
164
|
+
const buildCreditsBalance = (records, networkId, lookupCurated) => {
|
|
165
|
+
var _a;
|
|
162
166
|
const creditsRecords = records.filter((r) => (r === null || r === void 0 ? void 0 : r.program_name) === 'credits.aleo' &&
|
|
163
167
|
(r === null || r === void 0 ? void 0 : r.record_name) === 'credits' &&
|
|
164
168
|
typeof (r === null || r === void 0 ? void 0 : r.microcredits) === 'string');
|
|
@@ -169,19 +173,25 @@ const buildCreditsBalance = (records, networkId, priceFor) => {
|
|
|
169
173
|
// below Number.MAX_SAFE_INTEGER for a single wallet (max u64 supply is
|
|
170
174
|
// 1.5B credits = 1.5e15 microcredits; Number can hold up to ~9e15).
|
|
171
175
|
const rawBalance = Number(totalMicrocredits);
|
|
176
|
+
const rawBalanceString = totalMicrocredits.toString();
|
|
172
177
|
const balance = rawBalance / MICROCREDITS_PER_CREDIT;
|
|
173
|
-
const
|
|
178
|
+
const curated = lookupCurated('0x0', true);
|
|
174
179
|
return {
|
|
175
180
|
address: '0x0',
|
|
176
181
|
balance,
|
|
177
182
|
decimals: 6,
|
|
178
183
|
isNative: true,
|
|
179
|
-
|
|
180
|
-
|
|
184
|
+
// Prefer the server-curated logo (single source of truth for both
|
|
185
|
+
// the unshielded multichain feed and the shielded tab); fall back
|
|
186
|
+
// to the bundled ALEO glyph for older redcoast deployments that
|
|
187
|
+
// don't yet send `logoURI` on the prices response.
|
|
188
|
+
logoURI: (_a = curated.logoURI) !== null && _a !== void 0 ? _a : ALEO_CREDITS_LOGO,
|
|
189
|
+
marketValue: curated.price !== null ? balance * curated.price : undefined,
|
|
181
190
|
name: 'Aleo Credits',
|
|
182
191
|
networkId,
|
|
183
|
-
price: price !== null ? price : undefined,
|
|
192
|
+
price: curated.price !== null ? curated.price : undefined,
|
|
184
193
|
rawBalance,
|
|
194
|
+
rawBalanceString,
|
|
185
195
|
symbol: 'ALEO',
|
|
186
196
|
};
|
|
187
197
|
};
|
|
@@ -191,8 +201,8 @@ const buildCreditsBalance = (records, networkId, priceFor) => {
|
|
|
191
201
|
* match a curated spec, lack an `amount`, or have a malformed amount
|
|
192
202
|
* string are silently skipped.
|
|
193
203
|
*/
|
|
194
|
-
const buildTokenBalances = (records, networkId,
|
|
195
|
-
var _a, _b;
|
|
204
|
+
const buildTokenBalances = (records, networkId, lookupCurated) => {
|
|
205
|
+
var _a, _b, _c;
|
|
196
206
|
const sumsByContract = new Map();
|
|
197
207
|
const specsByContract = new Map();
|
|
198
208
|
for (const r of records) {
|
|
@@ -204,7 +214,7 @@ const buildTokenBalances = (records, networkId, priceFor) => {
|
|
|
204
214
|
sumsByContract.set(spec.contractAddress, prev + BigInt(r.amount));
|
|
205
215
|
specsByContract.set(spec.contractAddress, spec);
|
|
206
216
|
}
|
|
207
|
-
catch (
|
|
217
|
+
catch (_d) {
|
|
208
218
|
/* ignore — malformed amount string */
|
|
209
219
|
}
|
|
210
220
|
}
|
|
@@ -214,22 +224,26 @@ const buildTokenBalances = (records, networkId, priceFor) => {
|
|
|
214
224
|
if (!spec)
|
|
215
225
|
continue;
|
|
216
226
|
const rawBalance = Number(total);
|
|
227
|
+
const rawBalanceString = total.toString();
|
|
217
228
|
const balance = rawBalance / Math.pow(10, spec.decimals);
|
|
218
|
-
const
|
|
229
|
+
const curated = lookupCurated(spec.contractAddress, false);
|
|
219
230
|
out.push({
|
|
220
231
|
address: spec.contractAddress,
|
|
221
232
|
balance,
|
|
222
233
|
decimals: spec.decimals,
|
|
223
|
-
//
|
|
224
|
-
//
|
|
225
|
-
//
|
|
226
|
-
//
|
|
227
|
-
|
|
228
|
-
|
|
234
|
+
// Prefer the server-curated logo so the Shielded tab renders the
|
|
235
|
+
// same brand glyph the Unshielded tab gets from the multichain
|
|
236
|
+
// feed. Fall back to the local spec override (kept for tests +
|
|
237
|
+
// any future curated-but-not-yet-on-server tokens), then to the
|
|
238
|
+
// generic dark `?` placeholder for older redcoast deployments
|
|
239
|
+
// that haven't rolled out the logo response field yet.
|
|
240
|
+
logoURI: (_c = (_b = curated.logoURI) !== null && _b !== void 0 ? _b : spec.logoURI) !== null && _c !== void 0 ? _c : UNKNOWN_TOKEN_LOGO,
|
|
241
|
+
marketValue: curated.price !== null ? balance * curated.price : undefined,
|
|
229
242
|
name: spec.name,
|
|
230
243
|
networkId,
|
|
231
|
-
price: price !== null ? price : undefined,
|
|
244
|
+
price: curated.price !== null ? curated.price : undefined,
|
|
232
245
|
rawBalance,
|
|
246
|
+
rawBalanceString,
|
|
233
247
|
symbol: spec.symbol,
|
|
234
248
|
});
|
|
235
249
|
}
|
|
@@ -300,12 +314,12 @@ const useAleoShieldedBalances = () => {
|
|
|
300
314
|
: Promise.resolve([]),
|
|
301
315
|
]);
|
|
302
316
|
const records = (_a = result === null || result === void 0 ? void 0 : result.records) !== null && _a !== void 0 ? _a : [];
|
|
303
|
-
const
|
|
317
|
+
const lookupCurated = buildCuratedTokenLookup(priceList);
|
|
304
318
|
const balances = [];
|
|
305
|
-
const credits = buildCreditsBalance(records, safeNetworkId,
|
|
319
|
+
const credits = buildCreditsBalance(records, safeNetworkId, lookupCurated);
|
|
306
320
|
if (credits)
|
|
307
321
|
balances.push(credits);
|
|
308
|
-
balances.push(...buildTokenBalances(records, safeNetworkId,
|
|
322
|
+
balances.push(...buildTokenBalances(records, safeNetworkId, lookupCurated));
|
|
309
323
|
setTokenBalances(balances);
|
|
310
324
|
}
|
|
311
325
|
catch (err) {
|
package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/ActiveWalletBalance.cjs
CHANGED
|
@@ -12,7 +12,9 @@ var useInternalDynamicContext = require('../../../../context/DynamicContext/useD
|
|
|
12
12
|
var useTokenBalances = require('../../../../utils/hooks/useTokenBalances/useTokenBalances.cjs');
|
|
13
13
|
var useAleoShieldedBalances = require('../../../../utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.cjs');
|
|
14
14
|
var useAleoAutoMergeRecords = require('../../../../utils/hooks/useAleoAutoMergeRecords/useAleoAutoMergeRecords.cjs');
|
|
15
|
+
var buildTokenKey = require('../../../../utils/hooks/useAleoAutoShieldSponsoredTokens/buildTokenKey.cjs');
|
|
15
16
|
var useAleoAutoShieldSponsoredTokens = require('../../../../utils/hooks/useAleoAutoShieldSponsoredTokens/useAleoAutoShieldSponsoredTokens.cjs');
|
|
17
|
+
var pollOnShielded = require('../../../../utils/hooks/useAleoAutoShieldSponsoredTokens/pollOnShielded.cjs');
|
|
16
18
|
var AccordionItem = require('../../../../components/Accordion/components/AccordionItem/AccordionItem.cjs');
|
|
17
19
|
require('@dynamic-labs/iconic');
|
|
18
20
|
require('@dynamic-labs/wallet-connector-core');
|
|
@@ -193,7 +195,7 @@ const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
|
193
195
|
// `shieldToken` for tokens whose `transfer_public_to_private` is
|
|
194
196
|
// Feemaster-sponsored. Unsponsored tokens stay on the manual Shield
|
|
195
197
|
// Manually CTA, which prompts the user-paid confirmation modal.
|
|
196
|
-
const { isShielding: isAutoShielding } = useAleoAutoShieldSponsoredTokens.useAleoAutoShieldSponsoredTokens({
|
|
198
|
+
const { isShielding: isAutoShielding, currentlyShieldingTokenKeys: autoShieldingTokenKeys, } = useAleoAutoShieldSponsoredTokens.useAleoAutoShieldSponsoredTokens({
|
|
197
199
|
accountAddress: primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.address,
|
|
198
200
|
onShielded: React.useCallback(() => _tslib.__awaiter(void 0, void 0, void 0, function* () {
|
|
199
201
|
yield fetchAccountBalances(true);
|
|
@@ -202,6 +204,16 @@ const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
|
202
204
|
shieldHandle: aleoShieldHandle,
|
|
203
205
|
unshieldedTokenBalances: unshieldedTokenBalances,
|
|
204
206
|
});
|
|
207
|
+
// Liveness handle for the manual post-shield poll — set to true when
|
|
208
|
+
// the component unmounts so `pollOnShielded` exits its backoff loop
|
|
209
|
+
// instead of firing `fetchAccountBalances` on a torn-down tree.
|
|
210
|
+
const isUnmountedRef = React.useRef(false);
|
|
211
|
+
React.useEffect(() => {
|
|
212
|
+
isUnmountedRef.current = false;
|
|
213
|
+
return () => {
|
|
214
|
+
isUnmountedRef.current = true;
|
|
215
|
+
};
|
|
216
|
+
}, []);
|
|
205
217
|
// Token currently awaiting user-paid fee confirmation. Set when
|
|
206
218
|
// Shield Manually is clicked on a token Feemaster doesn't sponsor;
|
|
207
219
|
// cleared on Cancel or after the modal's Shield button dispatches.
|
|
@@ -218,12 +230,14 @@ const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
|
218
230
|
if (atomic <= BigInt(0))
|
|
219
231
|
return;
|
|
220
232
|
setShieldingAddress(token.address);
|
|
233
|
+
let didBroadcast = false;
|
|
221
234
|
try {
|
|
222
235
|
yield aleoShieldHandle.shieldToken({
|
|
223
236
|
amount: atomic,
|
|
224
237
|
isNative: token.isNative,
|
|
225
238
|
tokenAddress: token.address,
|
|
226
239
|
});
|
|
240
|
+
didBroadcast = true;
|
|
227
241
|
// Refresh the unshielded list so the just-shielded balance drops to
|
|
228
242
|
// 0 in the redcoast feed. The shielded side will pick the new
|
|
229
243
|
// record up on its own polling once the RecordScanner indexes.
|
|
@@ -236,6 +250,20 @@ const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
|
236
250
|
finally {
|
|
237
251
|
setShieldingAddress(undefined);
|
|
238
252
|
}
|
|
253
|
+
// The relay-accepted broadcast resolves *before* the
|
|
254
|
+
// public→private transition finalizes on-chain, so the immediate
|
|
255
|
+
// refresh above sees the pre-confirmation balance. Re-poll on the
|
|
256
|
+
// shared backoff so the Unshielded row visibly drops to 0 and the
|
|
257
|
+
// Shielded row picks the new record up without a manual reload.
|
|
258
|
+
// Polling is best-effort — errors are swallowed inside
|
|
259
|
+
// `pollOnShielded`. Skip when the broadcast itself failed; there's
|
|
260
|
+
// nothing new to converge on.
|
|
261
|
+
if (!didBroadcast)
|
|
262
|
+
return;
|
|
263
|
+
yield pollOnShielded.pollOnShielded(() => _tslib.__awaiter(void 0, void 0, void 0, function* () {
|
|
264
|
+
yield fetchAccountBalances(true);
|
|
265
|
+
yield refetchShielded();
|
|
266
|
+
}), () => isUnmountedRef.current);
|
|
239
267
|
}), [aleoShieldHandle, fetchAccountBalances, refetchShielded, shieldingAddress]);
|
|
240
268
|
const getSecondaryAction = React.useCallback((token) => {
|
|
241
269
|
// Only on the Unshielded tab, only when the connector exposes shield
|
|
@@ -252,6 +280,15 @@ const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
|
252
280
|
return undefined;
|
|
253
281
|
if (!token.rawBalance || token.rawBalance <= 0)
|
|
254
282
|
return undefined;
|
|
283
|
+
// Hide the CTA while auto-shield is mid-broadcast for this token.
|
|
284
|
+
// The connector dedupes regardless, but suppressing the button
|
|
285
|
+
// prevents two click-then-spinner cycles for a single underlying
|
|
286
|
+
// shield. Once auto-shield resolves, the row re-renders with the
|
|
287
|
+
// freshly-zero balance, the `rawBalance <= 0` guard above kicks in,
|
|
288
|
+
// and the CTA stays hidden until a new unshielded balance arrives.
|
|
289
|
+
const tokenKey = buildTokenKey.buildTokenKey(token);
|
|
290
|
+
if (tokenKey && autoShieldingTokenKeys.has(tokenKey))
|
|
291
|
+
return undefined;
|
|
255
292
|
return {
|
|
256
293
|
dataTestId: `shield-manually-${token.symbol}`,
|
|
257
294
|
isLoading: shieldingAddress === token.address,
|
|
@@ -282,7 +319,13 @@ const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
|
282
319
|
});
|
|
283
320
|
},
|
|
284
321
|
};
|
|
285
|
-
}, [
|
|
322
|
+
}, [
|
|
323
|
+
activeShieldTab,
|
|
324
|
+
aleoShieldHandle,
|
|
325
|
+
autoShieldingTokenKeys,
|
|
326
|
+
handleShieldToken,
|
|
327
|
+
shieldingAddress,
|
|
328
|
+
]);
|
|
286
329
|
const tokenBalances = React.useMemo(() => supportsShielded && activeShieldTab === 'shielded'
|
|
287
330
|
? shieldedTokenBalances
|
|
288
331
|
: unshieldedTokenBalances, [
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
import { __awaiter } from '../../../../../../_virtual/_tslib.js';
|
|
3
3
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
4
|
-
import { useState, useRef, useMemo, useCallback } from 'react';
|
|
4
|
+
import { useState, useRef, useMemo, useCallback, useEffect } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
import '../../../../context/DynamicContext/useDynamicContext/useDynamicContext.js';
|
|
7
7
|
import { useInternalDynamicContext } from '../../../../context/DynamicContext/useDynamicContext/useInternalDynamicContext/useInternalDynamicContext.js';
|
|
8
8
|
import { useTokenBalances } from '../../../../utils/hooks/useTokenBalances/useTokenBalances.js';
|
|
9
9
|
import { useAleoShieldedBalances } from '../../../../utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.js';
|
|
10
10
|
import { useAleoAutoMergeRecords } from '../../../../utils/hooks/useAleoAutoMergeRecords/useAleoAutoMergeRecords.js';
|
|
11
|
+
import { buildTokenKey } from '../../../../utils/hooks/useAleoAutoShieldSponsoredTokens/buildTokenKey.js';
|
|
11
12
|
import { useAleoAutoShieldSponsoredTokens } from '../../../../utils/hooks/useAleoAutoShieldSponsoredTokens/useAleoAutoShieldSponsoredTokens.js';
|
|
13
|
+
import { pollOnShielded } from '../../../../utils/hooks/useAleoAutoShieldSponsoredTokens/pollOnShielded.js';
|
|
12
14
|
import { AccordionItem } from '../../../../components/Accordion/components/AccordionItem/AccordionItem.js';
|
|
13
15
|
import '@dynamic-labs/iconic';
|
|
14
16
|
import '@dynamic-labs/wallet-connector-core';
|
|
@@ -189,7 +191,7 @@ const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
|
189
191
|
// `shieldToken` for tokens whose `transfer_public_to_private` is
|
|
190
192
|
// Feemaster-sponsored. Unsponsored tokens stay on the manual Shield
|
|
191
193
|
// Manually CTA, which prompts the user-paid confirmation modal.
|
|
192
|
-
const { isShielding: isAutoShielding } = useAleoAutoShieldSponsoredTokens({
|
|
194
|
+
const { isShielding: isAutoShielding, currentlyShieldingTokenKeys: autoShieldingTokenKeys, } = useAleoAutoShieldSponsoredTokens({
|
|
193
195
|
accountAddress: primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.address,
|
|
194
196
|
onShielded: useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
195
197
|
yield fetchAccountBalances(true);
|
|
@@ -198,6 +200,16 @@ const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
|
198
200
|
shieldHandle: aleoShieldHandle,
|
|
199
201
|
unshieldedTokenBalances: unshieldedTokenBalances,
|
|
200
202
|
});
|
|
203
|
+
// Liveness handle for the manual post-shield poll — set to true when
|
|
204
|
+
// the component unmounts so `pollOnShielded` exits its backoff loop
|
|
205
|
+
// instead of firing `fetchAccountBalances` on a torn-down tree.
|
|
206
|
+
const isUnmountedRef = useRef(false);
|
|
207
|
+
useEffect(() => {
|
|
208
|
+
isUnmountedRef.current = false;
|
|
209
|
+
return () => {
|
|
210
|
+
isUnmountedRef.current = true;
|
|
211
|
+
};
|
|
212
|
+
}, []);
|
|
201
213
|
// Token currently awaiting user-paid fee confirmation. Set when
|
|
202
214
|
// Shield Manually is clicked on a token Feemaster doesn't sponsor;
|
|
203
215
|
// cleared on Cancel or after the modal's Shield button dispatches.
|
|
@@ -214,12 +226,14 @@ const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
|
214
226
|
if (atomic <= BigInt(0))
|
|
215
227
|
return;
|
|
216
228
|
setShieldingAddress(token.address);
|
|
229
|
+
let didBroadcast = false;
|
|
217
230
|
try {
|
|
218
231
|
yield aleoShieldHandle.shieldToken({
|
|
219
232
|
amount: atomic,
|
|
220
233
|
isNative: token.isNative,
|
|
221
234
|
tokenAddress: token.address,
|
|
222
235
|
});
|
|
236
|
+
didBroadcast = true;
|
|
223
237
|
// Refresh the unshielded list so the just-shielded balance drops to
|
|
224
238
|
// 0 in the redcoast feed. The shielded side will pick the new
|
|
225
239
|
// record up on its own polling once the RecordScanner indexes.
|
|
@@ -232,6 +246,20 @@ const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
|
232
246
|
finally {
|
|
233
247
|
setShieldingAddress(undefined);
|
|
234
248
|
}
|
|
249
|
+
// The relay-accepted broadcast resolves *before* the
|
|
250
|
+
// public→private transition finalizes on-chain, so the immediate
|
|
251
|
+
// refresh above sees the pre-confirmation balance. Re-poll on the
|
|
252
|
+
// shared backoff so the Unshielded row visibly drops to 0 and the
|
|
253
|
+
// Shielded row picks the new record up without a manual reload.
|
|
254
|
+
// Polling is best-effort — errors are swallowed inside
|
|
255
|
+
// `pollOnShielded`. Skip when the broadcast itself failed; there's
|
|
256
|
+
// nothing new to converge on.
|
|
257
|
+
if (!didBroadcast)
|
|
258
|
+
return;
|
|
259
|
+
yield pollOnShielded(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
260
|
+
yield fetchAccountBalances(true);
|
|
261
|
+
yield refetchShielded();
|
|
262
|
+
}), () => isUnmountedRef.current);
|
|
235
263
|
}), [aleoShieldHandle, fetchAccountBalances, refetchShielded, shieldingAddress]);
|
|
236
264
|
const getSecondaryAction = useCallback((token) => {
|
|
237
265
|
// Only on the Unshielded tab, only when the connector exposes shield
|
|
@@ -248,6 +276,15 @@ const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
|
248
276
|
return undefined;
|
|
249
277
|
if (!token.rawBalance || token.rawBalance <= 0)
|
|
250
278
|
return undefined;
|
|
279
|
+
// Hide the CTA while auto-shield is mid-broadcast for this token.
|
|
280
|
+
// The connector dedupes regardless, but suppressing the button
|
|
281
|
+
// prevents two click-then-spinner cycles for a single underlying
|
|
282
|
+
// shield. Once auto-shield resolves, the row re-renders with the
|
|
283
|
+
// freshly-zero balance, the `rawBalance <= 0` guard above kicks in,
|
|
284
|
+
// and the CTA stays hidden until a new unshielded balance arrives.
|
|
285
|
+
const tokenKey = buildTokenKey(token);
|
|
286
|
+
if (tokenKey && autoShieldingTokenKeys.has(tokenKey))
|
|
287
|
+
return undefined;
|
|
251
288
|
return {
|
|
252
289
|
dataTestId: `shield-manually-${token.symbol}`,
|
|
253
290
|
isLoading: shieldingAddress === token.address,
|
|
@@ -278,7 +315,13 @@ const ActiveWalletBalance = ({ isLoading = false, }) => {
|
|
|
278
315
|
});
|
|
279
316
|
},
|
|
280
317
|
};
|
|
281
|
-
}, [
|
|
318
|
+
}, [
|
|
319
|
+
activeShieldTab,
|
|
320
|
+
aleoShieldHandle,
|
|
321
|
+
autoShieldingTokenKeys,
|
|
322
|
+
handleShieldToken,
|
|
323
|
+
shieldingAddress,
|
|
324
|
+
]);
|
|
282
325
|
const tokenBalances = useMemo(() => supportsShielded && activeShieldTab === 'shielded'
|
|
283
326
|
? shieldedTokenBalances
|
|
284
327
|
: unshieldedTokenBalances, [
|