@dynamic-labs/sdk-react-core 4.83.2-alpha.0 → 4.84.1
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 +36 -1
- package/package.cjs +1 -1
- package/package.js +1 -1
- package/package.json +12 -12
- package/src/index.cjs +4 -0
- package/src/index.d.ts +2 -2
- package/src/index.js +2 -0
- package/src/lib/components/SendBalanceForm/SendBalanceForm.cjs +26 -1
- package/src/lib/components/SendBalanceForm/SendBalanceForm.js +26 -1
- package/src/lib/components/SendBalancePageLayout/SendBalancePageLayout.cjs +6 -1
- package/src/lib/components/SendBalancePageLayout/SendBalancePageLayout.js +6 -1
- package/src/lib/main.global.cjs +1 -1
- package/src/lib/main.global.js +1 -1
- package/src/lib/utils/hooks/index.d.ts +2 -0
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/pollOnShielded.cjs +24 -4
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/pollOnShielded.d.ts +10 -2
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/pollOnShielded.js +24 -4
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/useAleoAutoShieldSponsoredTokens.cjs +14 -3
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/useAleoAutoShieldSponsoredTokens.d.ts +5 -1
- package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/useAleoAutoShieldSponsoredTokens.js +14 -3
- package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.cjs +14 -0
- package/src/lib/utils/hooks/useAleoShieldedBalances/useAleoShieldedBalances.js +14 -0
- package/src/lib/utils/hooks/usePrivateTokenBalances/index.d.ts +2 -0
- package/src/lib/utils/hooks/usePrivateTokenBalances/usePrivateTokenBalances.cjs +19 -0
- package/src/lib/utils/hooks/usePrivateTokenBalances/usePrivateTokenBalances.d.ts +9 -0
- package/src/lib/utils/hooks/usePrivateTokenBalances/usePrivateTokenBalances.js +15 -0
- package/src/lib/utils/hooks/useSyncDeviceRegistrationFlow/useSyncDeviceRegistrationFlow.cjs +8 -0
- package/src/lib/utils/hooks/useSyncDeviceRegistrationFlow/useSyncDeviceRegistrationFlow.js +9 -1
- package/src/lib/utils/hooks/useWalletDelegation/useWalletDelegation.cjs +19 -16
- package/src/lib/utils/hooks/useWalletDelegation/useWalletDelegation.d.ts +8 -0
- package/src/lib/utils/hooks/useWalletDelegation/useWalletDelegation.js +19 -17
- package/src/lib/utils/hooks/useWalletPassword/useWalletPassword.d.ts +4 -4
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/ActiveWalletBalance.cjs +138 -21
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/ActiveWalletBalance.js +139 -22
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/optimisticShield.cjs +134 -0
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/optimisticShield.d.ts +69 -0
- package/src/lib/widgets/DynamicWidget/components/ActiveWalletBalance/optimisticShield.js +127 -0
- package/src/lib/widgets/DynamicWidget/views/ManageTrustedDevicesView/ManageTrustedDevicesView.cjs +12 -8
- package/src/lib/widgets/DynamicWidget/views/ManageTrustedDevicesView/ManageTrustedDevicesView.js +8 -4
|
@@ -9,7 +9,7 @@ var _tslib = require('../../../../../_virtual/_tslib.cjs');
|
|
|
9
9
|
// when the relay accepts the broadcast, not when the public→private
|
|
10
10
|
// transition confirms on-chain. Aleo block time + RecordScanner indexer
|
|
11
11
|
// lag means the immediate post-broadcast fetch usually returns the
|
|
12
|
-
// pre-confirmation balance, so we re-poll
|
|
12
|
+
// pre-confirmation balance, so we re-poll on a backoff schedule.
|
|
13
13
|
//
|
|
14
14
|
// Shared between the auto-shield hook (background) and the widget's
|
|
15
15
|
// manual Shield Manually CTA (foreground), so both flows update the
|
|
@@ -17,23 +17,41 @@ var _tslib = require('../../../../../_virtual/_tslib.cjs');
|
|
|
17
17
|
// the manual flow refreshed exactly once and the unshielded row
|
|
18
18
|
// stayed at its pre-broadcast value for the full RecordScanner lag,
|
|
19
19
|
// making a successful shield look like a no-op.
|
|
20
|
+
//
|
|
21
|
+
// Total window ≈106s. Provable's mapping endpoint typically reflects
|
|
22
|
+
// a `transfer_public_to_private` within ~30s of broadcast, but the
|
|
23
|
+
// RecordScanner index lag for the new private record can stretch to
|
|
24
|
+
// ~90s in the worst case. The tail entries (25s, 35s) keep the poll
|
|
25
|
+
// alive across the upper end of that range without spamming requests
|
|
26
|
+
// during the common case (most balances converge inside the first
|
|
27
|
+
// three iterations and the convergence predicate exits the loop).
|
|
20
28
|
const REFRESH_DELAYS_MS = [
|
|
21
|
-
3000, 5000, 8000, 12000, 18000,
|
|
29
|
+
3000, 5000, 8000, 12000, 18000, 25000, 35000,
|
|
22
30
|
];
|
|
23
31
|
/**
|
|
24
32
|
* After a successful shield broadcast, poll `onShielded` on a backoff
|
|
25
33
|
* schedule so the consumer sees both the shielded and unshielded balances
|
|
26
|
-
* update without a manual refresh click. Stops early on cancel
|
|
34
|
+
* update without a manual refresh click. Stops early on cancel or when
|
|
35
|
+
* the optional `hasConverged` predicate returns true; swallows
|
|
27
36
|
* per-iteration errors (refresh is best-effort).
|
|
28
37
|
*
|
|
29
38
|
* `isCancelled` is a thunk so callers can hook it up to whatever liveness
|
|
30
39
|
* signal they have (effect cleanup `cancelled` flag, abort signal, mount
|
|
31
40
|
* ref, etc.) without this module having to know about React lifecycle.
|
|
41
|
+
*
|
|
42
|
+
* `hasConverged` is optional and lets callers exit early once the
|
|
43
|
+
* post-shield state has actually materialized (e.g. the just-shielded
|
|
44
|
+
* token's unshielded balance has dropped). When omitted, the schedule
|
|
45
|
+
* runs to completion. Checked both before each delay and after each
|
|
46
|
+
* refresh so a refresh that produces the converged state ends the loop
|
|
47
|
+
* immediately.
|
|
32
48
|
*/
|
|
33
|
-
const pollOnShielded = (onShielded, isCancelled) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
|
|
49
|
+
const pollOnShielded = (onShielded, isCancelled, hasConverged) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
|
|
34
50
|
for (const delay of REFRESH_DELAYS_MS) {
|
|
35
51
|
if (isCancelled())
|
|
36
52
|
return;
|
|
53
|
+
if (hasConverged === null || hasConverged === void 0 ? void 0 : hasConverged())
|
|
54
|
+
return;
|
|
37
55
|
yield new Promise((resolve) => setTimeout(resolve, delay));
|
|
38
56
|
if (isCancelled())
|
|
39
57
|
return;
|
|
@@ -43,6 +61,8 @@ const pollOnShielded = (onShielded, isCancelled) => _tslib.__awaiter(void 0, voi
|
|
|
43
61
|
catch (_a) {
|
|
44
62
|
/* swallow — refresh is best-effort */
|
|
45
63
|
}
|
|
64
|
+
if (hasConverged === null || hasConverged === void 0 ? void 0 : hasConverged())
|
|
65
|
+
return;
|
|
46
66
|
}
|
|
47
67
|
});
|
|
48
68
|
|
|
@@ -2,11 +2,19 @@ export declare const REFRESH_DELAYS_MS: ReadonlyArray<number>;
|
|
|
2
2
|
/**
|
|
3
3
|
* After a successful shield broadcast, poll `onShielded` on a backoff
|
|
4
4
|
* schedule so the consumer sees both the shielded and unshielded balances
|
|
5
|
-
* update without a manual refresh click. Stops early on cancel
|
|
5
|
+
* update without a manual refresh click. Stops early on cancel or when
|
|
6
|
+
* the optional `hasConverged` predicate returns true; swallows
|
|
6
7
|
* per-iteration errors (refresh is best-effort).
|
|
7
8
|
*
|
|
8
9
|
* `isCancelled` is a thunk so callers can hook it up to whatever liveness
|
|
9
10
|
* signal they have (effect cleanup `cancelled` flag, abort signal, mount
|
|
10
11
|
* ref, etc.) without this module having to know about React lifecycle.
|
|
12
|
+
*
|
|
13
|
+
* `hasConverged` is optional and lets callers exit early once the
|
|
14
|
+
* post-shield state has actually materialized (e.g. the just-shielded
|
|
15
|
+
* token's unshielded balance has dropped). When omitted, the schedule
|
|
16
|
+
* runs to completion. Checked both before each delay and after each
|
|
17
|
+
* refresh so a refresh that produces the converged state ends the loop
|
|
18
|
+
* immediately.
|
|
11
19
|
*/
|
|
12
|
-
export declare const pollOnShielded: (onShielded: () => Promise<void> | void, isCancelled: () => boolean) => Promise<void>;
|
|
20
|
+
export declare const pollOnShielded: (onShielded: () => Promise<void> | void, isCancelled: () => boolean, hasConverged?: () => boolean) => Promise<void>;
|
|
@@ -5,7 +5,7 @@ import { __awaiter } from '../../../../../_virtual/_tslib.js';
|
|
|
5
5
|
// when the relay accepts the broadcast, not when the public→private
|
|
6
6
|
// transition confirms on-chain. Aleo block time + RecordScanner indexer
|
|
7
7
|
// lag means the immediate post-broadcast fetch usually returns the
|
|
8
|
-
// pre-confirmation balance, so we re-poll
|
|
8
|
+
// pre-confirmation balance, so we re-poll on a backoff schedule.
|
|
9
9
|
//
|
|
10
10
|
// Shared between the auto-shield hook (background) and the widget's
|
|
11
11
|
// manual Shield Manually CTA (foreground), so both flows update the
|
|
@@ -13,23 +13,41 @@ import { __awaiter } from '../../../../../_virtual/_tslib.js';
|
|
|
13
13
|
// the manual flow refreshed exactly once and the unshielded row
|
|
14
14
|
// stayed at its pre-broadcast value for the full RecordScanner lag,
|
|
15
15
|
// making a successful shield look like a no-op.
|
|
16
|
+
//
|
|
17
|
+
// Total window ≈106s. Provable's mapping endpoint typically reflects
|
|
18
|
+
// a `transfer_public_to_private` within ~30s of broadcast, but the
|
|
19
|
+
// RecordScanner index lag for the new private record can stretch to
|
|
20
|
+
// ~90s in the worst case. The tail entries (25s, 35s) keep the poll
|
|
21
|
+
// alive across the upper end of that range without spamming requests
|
|
22
|
+
// during the common case (most balances converge inside the first
|
|
23
|
+
// three iterations and the convergence predicate exits the loop).
|
|
16
24
|
const REFRESH_DELAYS_MS = [
|
|
17
|
-
3000, 5000, 8000, 12000, 18000,
|
|
25
|
+
3000, 5000, 8000, 12000, 18000, 25000, 35000,
|
|
18
26
|
];
|
|
19
27
|
/**
|
|
20
28
|
* After a successful shield broadcast, poll `onShielded` on a backoff
|
|
21
29
|
* schedule so the consumer sees both the shielded and unshielded balances
|
|
22
|
-
* update without a manual refresh click. Stops early on cancel
|
|
30
|
+
* update without a manual refresh click. Stops early on cancel or when
|
|
31
|
+
* the optional `hasConverged` predicate returns true; swallows
|
|
23
32
|
* per-iteration errors (refresh is best-effort).
|
|
24
33
|
*
|
|
25
34
|
* `isCancelled` is a thunk so callers can hook it up to whatever liveness
|
|
26
35
|
* signal they have (effect cleanup `cancelled` flag, abort signal, mount
|
|
27
36
|
* ref, etc.) without this module having to know about React lifecycle.
|
|
37
|
+
*
|
|
38
|
+
* `hasConverged` is optional and lets callers exit early once the
|
|
39
|
+
* post-shield state has actually materialized (e.g. the just-shielded
|
|
40
|
+
* token's unshielded balance has dropped). When omitted, the schedule
|
|
41
|
+
* runs to completion. Checked both before each delay and after each
|
|
42
|
+
* refresh so a refresh that produces the converged state ends the loop
|
|
43
|
+
* immediately.
|
|
28
44
|
*/
|
|
29
|
-
const pollOnShielded = (onShielded, isCancelled) => __awaiter(void 0, void 0, void 0, function* () {
|
|
45
|
+
const pollOnShielded = (onShielded, isCancelled, hasConverged) => __awaiter(void 0, void 0, void 0, function* () {
|
|
30
46
|
for (const delay of REFRESH_DELAYS_MS) {
|
|
31
47
|
if (isCancelled())
|
|
32
48
|
return;
|
|
49
|
+
if (hasConverged === null || hasConverged === void 0 ? void 0 : hasConverged())
|
|
50
|
+
return;
|
|
33
51
|
yield new Promise((resolve) => setTimeout(resolve, delay));
|
|
34
52
|
if (isCancelled())
|
|
35
53
|
return;
|
|
@@ -39,6 +57,8 @@ const pollOnShielded = (onShielded, isCancelled) => __awaiter(void 0, void 0, vo
|
|
|
39
57
|
catch (_a) {
|
|
40
58
|
/* swallow — refresh is best-effort */
|
|
41
59
|
}
|
|
60
|
+
if (hasConverged === null || hasConverged === void 0 ? void 0 : hasConverged())
|
|
61
|
+
return;
|
|
42
62
|
}
|
|
43
63
|
});
|
|
44
64
|
|
package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/useAleoAutoShieldSponsoredTokens.cjs
CHANGED
|
@@ -47,7 +47,7 @@ const buildShieldCandidates = (args) => {
|
|
|
47
47
|
*/
|
|
48
48
|
const tryShieldOneToken = (token, deps) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
|
|
49
49
|
var _a, _b, _c;
|
|
50
|
-
const { accountAddress, shieldHandle, seenKeys, isCancelled, inFlightTokenKeys, } = deps;
|
|
50
|
+
const { accountAddress, shieldHandle, seenKeys, isCancelled, inFlightTokenKeys, onShieldDispatched, } = deps;
|
|
51
51
|
const tokenKey = buildTokenKey.buildTokenKey(token) || nativeTokenKey.nativeTokenKey;
|
|
52
52
|
const key = `${accountAddress}:${tokenKey}`;
|
|
53
53
|
seenKeys.add(key);
|
|
@@ -80,9 +80,19 @@ const tryShieldOneToken = (token, deps) => _tslib.__awaiter(void 0, void 0, void
|
|
|
80
80
|
isNative: token.isNative,
|
|
81
81
|
tokenAddress: token.address,
|
|
82
82
|
});
|
|
83
|
+
// Optimistic-UI hand-off: notify the consumer the broadcast was
|
|
84
|
+
// accepted so it can deduct the unshielded balance locally and
|
|
85
|
+
// prepend a synthesised shielded row. Synchronous and best-effort;
|
|
86
|
+
// failures inside the callback don't roll back the shield.
|
|
87
|
+
try {
|
|
88
|
+
onShieldDispatched === null || onShieldDispatched === void 0 ? void 0 : onShieldDispatched({ amount: atomic, token });
|
|
89
|
+
}
|
|
90
|
+
catch (_e) {
|
|
91
|
+
/* swallow — optimistic hand-off is best-effort */
|
|
92
|
+
}
|
|
83
93
|
return true;
|
|
84
94
|
}
|
|
85
|
-
catch (
|
|
95
|
+
catch (_f) {
|
|
86
96
|
seenKeys.delete(key);
|
|
87
97
|
return false;
|
|
88
98
|
}
|
|
@@ -90,7 +100,7 @@ const tryShieldOneToken = (token, deps) => _tslib.__awaiter(void 0, void 0, void
|
|
|
90
100
|
inFlightTokenKeys === null || inFlightTokenKeys === void 0 ? void 0 : inFlightTokenKeys.delete(tokenKey);
|
|
91
101
|
}
|
|
92
102
|
});
|
|
93
|
-
const useAleoAutoShieldSponsoredTokens = ({ accountAddress, unshieldedTokenBalances, shieldHandle, onShielded, }) => {
|
|
103
|
+
const useAleoAutoShieldSponsoredTokens = ({ accountAddress, unshieldedTokenBalances, shieldHandle, onShielded, onShieldDispatched, }) => {
|
|
94
104
|
// Tracks `(accountAddress:tokenAddress)` we've already attempted in this
|
|
95
105
|
// session. Cleared implicitly on a full page reload.
|
|
96
106
|
const seenKeysRef = React.useRef(new Set());
|
|
@@ -218,6 +228,7 @@ const useAleoAutoShieldSponsoredTokens = ({ accountAddress, unshieldedTokenBalan
|
|
|
218
228
|
accountAddress,
|
|
219
229
|
inFlightTokenKeys: inFlightKeysAdapter,
|
|
220
230
|
isCancelled,
|
|
231
|
+
onShieldDispatched,
|
|
221
232
|
seenKeys: seenKeysRef.current,
|
|
222
233
|
shieldHandle,
|
|
223
234
|
});
|
package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/useAleoAutoShieldSponsoredTokens.d.ts
CHANGED
|
@@ -25,6 +25,10 @@ type UseAleoAutoShieldSponsoredTokensArgs = {
|
|
|
25
25
|
unshieldedTokenBalances: TokenBalance[];
|
|
26
26
|
shieldHandle: AleoShieldHandle | undefined;
|
|
27
27
|
onShielded?: () => Promise<void> | void;
|
|
28
|
+
onShieldDispatched?: (info: {
|
|
29
|
+
token: TokenBalance;
|
|
30
|
+
amount: bigint;
|
|
31
|
+
}) => void;
|
|
28
32
|
};
|
|
29
33
|
/**
|
|
30
34
|
* On Aleo wallet load (and on each subsequent unshielded-balance refresh),
|
|
@@ -66,5 +70,5 @@ export type UseAleoAutoShieldSponsoredTokensResult = {
|
|
|
66
70
|
*/
|
|
67
71
|
currentlyShieldingTokenKeys: ReadonlySet<string>;
|
|
68
72
|
};
|
|
69
|
-
export declare const useAleoAutoShieldSponsoredTokens: ({ accountAddress, unshieldedTokenBalances, shieldHandle, onShielded, }: UseAleoAutoShieldSponsoredTokensArgs) => UseAleoAutoShieldSponsoredTokensResult;
|
|
73
|
+
export declare const useAleoAutoShieldSponsoredTokens: ({ accountAddress, unshieldedTokenBalances, shieldHandle, onShielded, onShieldDispatched, }: UseAleoAutoShieldSponsoredTokensArgs) => UseAleoAutoShieldSponsoredTokensResult;
|
|
70
74
|
export {};
|
package/src/lib/utils/hooks/useAleoAutoShieldSponsoredTokens/useAleoAutoShieldSponsoredTokens.js
CHANGED
|
@@ -43,7 +43,7 @@ const buildShieldCandidates = (args) => {
|
|
|
43
43
|
*/
|
|
44
44
|
const tryShieldOneToken = (token, deps) => __awaiter(void 0, void 0, void 0, function* () {
|
|
45
45
|
var _a, _b, _c;
|
|
46
|
-
const { accountAddress, shieldHandle, seenKeys, isCancelled, inFlightTokenKeys, } = deps;
|
|
46
|
+
const { accountAddress, shieldHandle, seenKeys, isCancelled, inFlightTokenKeys, onShieldDispatched, } = deps;
|
|
47
47
|
const tokenKey = buildTokenKey(token) || nativeTokenKey;
|
|
48
48
|
const key = `${accountAddress}:${tokenKey}`;
|
|
49
49
|
seenKeys.add(key);
|
|
@@ -76,9 +76,19 @@ const tryShieldOneToken = (token, deps) => __awaiter(void 0, void 0, void 0, fun
|
|
|
76
76
|
isNative: token.isNative,
|
|
77
77
|
tokenAddress: token.address,
|
|
78
78
|
});
|
|
79
|
+
// Optimistic-UI hand-off: notify the consumer the broadcast was
|
|
80
|
+
// accepted so it can deduct the unshielded balance locally and
|
|
81
|
+
// prepend a synthesised shielded row. Synchronous and best-effort;
|
|
82
|
+
// failures inside the callback don't roll back the shield.
|
|
83
|
+
try {
|
|
84
|
+
onShieldDispatched === null || onShieldDispatched === void 0 ? void 0 : onShieldDispatched({ amount: atomic, token });
|
|
85
|
+
}
|
|
86
|
+
catch (_e) {
|
|
87
|
+
/* swallow — optimistic hand-off is best-effort */
|
|
88
|
+
}
|
|
79
89
|
return true;
|
|
80
90
|
}
|
|
81
|
-
catch (
|
|
91
|
+
catch (_f) {
|
|
82
92
|
seenKeys.delete(key);
|
|
83
93
|
return false;
|
|
84
94
|
}
|
|
@@ -86,7 +96,7 @@ const tryShieldOneToken = (token, deps) => __awaiter(void 0, void 0, void 0, fun
|
|
|
86
96
|
inFlightTokenKeys === null || inFlightTokenKeys === void 0 ? void 0 : inFlightTokenKeys.delete(tokenKey);
|
|
87
97
|
}
|
|
88
98
|
});
|
|
89
|
-
const useAleoAutoShieldSponsoredTokens = ({ accountAddress, unshieldedTokenBalances, shieldHandle, onShielded, }) => {
|
|
99
|
+
const useAleoAutoShieldSponsoredTokens = ({ accountAddress, unshieldedTokenBalances, shieldHandle, onShielded, onShieldDispatched, }) => {
|
|
90
100
|
// Tracks `(accountAddress:tokenAddress)` we've already attempted in this
|
|
91
101
|
// session. Cleared implicitly on a full page reload.
|
|
92
102
|
const seenKeysRef = useRef(new Set());
|
|
@@ -214,6 +224,7 @@ const useAleoAutoShieldSponsoredTokens = ({ accountAddress, unshieldedTokenBalan
|
|
|
214
224
|
accountAddress,
|
|
215
225
|
inFlightTokenKeys: inFlightKeysAdapter,
|
|
216
226
|
isCancelled,
|
|
227
|
+
onShieldDispatched,
|
|
217
228
|
seenKeys: seenKeysRef.current,
|
|
218
229
|
shieldHandle,
|
|
219
230
|
});
|
|
@@ -173,6 +173,12 @@ const buildCreditsBalance = (records, networkId, lookupCurated) => {
|
|
|
173
173
|
if (creditsRecords.length === 0)
|
|
174
174
|
return undefined;
|
|
175
175
|
const totalMicrocredits = creditsRecords.reduce((sum, r) => sum + BigInt(r.microcredits), BigInt(0));
|
|
176
|
+
// Skip the row entirely when every credits record summed to zero
|
|
177
|
+
// (typically partially-spent change records the indexer hasn't
|
|
178
|
+
// pruned yet). A "0 ALEO" entry in the Shielded tab is just noise
|
|
179
|
+
// the user can't act on.
|
|
180
|
+
if (totalMicrocredits === BigInt(0))
|
|
181
|
+
return undefined;
|
|
176
182
|
// BigInt → number for the TokenBalance shape. Aleo balances stay well
|
|
177
183
|
// below Number.MAX_SAFE_INTEGER for a single wallet (max u64 supply is
|
|
178
184
|
// 1.5B credits = 1.5e15 microcredits; Number can hold up to ~9e15).
|
|
@@ -227,6 +233,14 @@ const buildTokenBalances = (records, networkId, lookupCurated) => {
|
|
|
227
233
|
const spec = specsByContract.get(contractAddress);
|
|
228
234
|
if (!spec)
|
|
229
235
|
continue;
|
|
236
|
+
// Skip tokens whose every matched record summed to zero. Provable
|
|
237
|
+
// occasionally surfaces serialized records with `amount: 0u128`
|
|
238
|
+
// (e.g. partially-spent change records that haven't been pruned by
|
|
239
|
+
// the indexer yet); without this filter the Shielded tab shows a
|
|
240
|
+
// row with "0 USAD" / "0 USDCx" that the user can't act on, which
|
|
241
|
+
// is just noise.
|
|
242
|
+
if (total === BigInt(0))
|
|
243
|
+
continue;
|
|
230
244
|
const rawBalance = Number(total);
|
|
231
245
|
const rawBalanceString = total.toString();
|
|
232
246
|
const balance = rawBalance / Math.pow(10, spec.decimals);
|
|
@@ -169,6 +169,12 @@ const buildCreditsBalance = (records, networkId, lookupCurated) => {
|
|
|
169
169
|
if (creditsRecords.length === 0)
|
|
170
170
|
return undefined;
|
|
171
171
|
const totalMicrocredits = creditsRecords.reduce((sum, r) => sum + BigInt(r.microcredits), BigInt(0));
|
|
172
|
+
// Skip the row entirely when every credits record summed to zero
|
|
173
|
+
// (typically partially-spent change records the indexer hasn't
|
|
174
|
+
// pruned yet). A "0 ALEO" entry in the Shielded tab is just noise
|
|
175
|
+
// the user can't act on.
|
|
176
|
+
if (totalMicrocredits === BigInt(0))
|
|
177
|
+
return undefined;
|
|
172
178
|
// BigInt → number for the TokenBalance shape. Aleo balances stay well
|
|
173
179
|
// below Number.MAX_SAFE_INTEGER for a single wallet (max u64 supply is
|
|
174
180
|
// 1.5B credits = 1.5e15 microcredits; Number can hold up to ~9e15).
|
|
@@ -223,6 +229,14 @@ const buildTokenBalances = (records, networkId, lookupCurated) => {
|
|
|
223
229
|
const spec = specsByContract.get(contractAddress);
|
|
224
230
|
if (!spec)
|
|
225
231
|
continue;
|
|
232
|
+
// Skip tokens whose every matched record summed to zero. Provable
|
|
233
|
+
// occasionally surfaces serialized records with `amount: 0u128`
|
|
234
|
+
// (e.g. partially-spent change records that haven't been pruned by
|
|
235
|
+
// the indexer yet); without this filter the Shielded tab shows a
|
|
236
|
+
// row with "0 USAD" / "0 USDCx" that the user can't act on, which
|
|
237
|
+
// is just noise.
|
|
238
|
+
if (total === BigInt(0))
|
|
239
|
+
continue;
|
|
226
240
|
const rawBalance = Number(total);
|
|
227
241
|
const rawBalanceString = total.toString();
|
|
228
242
|
const balance = rawBalance / Math.pow(10, spec.decimals);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
5
|
+
|
|
6
|
+
var useAleoShieldedBalances = require('../useAleoShieldedBalances/useAleoShieldedBalances.cjs');
|
|
7
|
+
|
|
8
|
+
const usePrivateTokenBalances = () => {
|
|
9
|
+
const { tokenBalances, isLoading, error, refetch, supportsShielded } = useAleoShieldedBalances.useAleoShieldedBalances();
|
|
10
|
+
return {
|
|
11
|
+
error,
|
|
12
|
+
isLoading,
|
|
13
|
+
refetch,
|
|
14
|
+
supportsPrivateBalances: supportsShielded,
|
|
15
|
+
tokenBalances,
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
exports.usePrivateTokenBalances = usePrivateTokenBalances;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { TokenBalance } from '@dynamic-labs/sdk-api-core';
|
|
2
|
+
export type UsePrivateTokenBalancesReturn = {
|
|
3
|
+
tokenBalances: TokenBalance[];
|
|
4
|
+
isLoading: boolean;
|
|
5
|
+
error: string | undefined;
|
|
6
|
+
refetch: () => Promise<void>;
|
|
7
|
+
supportsPrivateBalances: boolean;
|
|
8
|
+
};
|
|
9
|
+
export declare const usePrivateTokenBalances: () => UsePrivateTokenBalancesReturn;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import { useAleoShieldedBalances } from '../useAleoShieldedBalances/useAleoShieldedBalances.js';
|
|
3
|
+
|
|
4
|
+
const usePrivateTokenBalances = () => {
|
|
5
|
+
const { tokenBalances, isLoading, error, refetch, supportsShielded } = useAleoShieldedBalances();
|
|
6
|
+
return {
|
|
7
|
+
error,
|
|
8
|
+
isLoading,
|
|
9
|
+
refetch,
|
|
10
|
+
supportsPrivateBalances: supportsShielded,
|
|
11
|
+
tokenBalances,
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export { usePrivateTokenBalances };
|
|
@@ -22,6 +22,10 @@ var hasPendingDeviceRegistration = require('../../../shared/utils/functions/hasP
|
|
|
22
22
|
const useSyncDeviceRegistrationFlow = () => {
|
|
23
23
|
const { setShowAuthFlow, sdkHasLoaded, userWithMissingInfo } = useInternalDynamicContext.useInternalDynamicContext();
|
|
24
24
|
const { clearStackAndPush } = ViewContext.useViewContext();
|
|
25
|
+
// Device registration tokens are single-use. Track tokens we've already
|
|
26
|
+
// attempted to prevent re-firing if the effect re-runs (e.g. when
|
|
27
|
+
// userWithMissingInfo identity flips after the first call's auth update).
|
|
28
|
+
const attemptedDeviceTokenRef = React.useRef(null);
|
|
25
29
|
React.useEffect(() => {
|
|
26
30
|
let cancelled = false;
|
|
27
31
|
const syncDeviceRegistration = () => _tslib.__awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -37,6 +41,10 @@ const useSyncDeviceRegistrationFlow = () => {
|
|
|
37
41
|
// complete registration directly without showing the modal
|
|
38
42
|
if (client.detectDeviceRegistrationRedirect({ url })) {
|
|
39
43
|
const deviceToken = client.getDeviceRegistrationTokenFromUrl({ url });
|
|
44
|
+
if (attemptedDeviceTokenRef.current === deviceToken) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
attemptedDeviceTokenRef.current = deviceToken;
|
|
40
48
|
try {
|
|
41
49
|
yield client.completeDeviceRegistration({ deviceToken });
|
|
42
50
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
import { __awaiter } from '../../../../../_virtual/_tslib.js';
|
|
3
|
-
import { useEffect } from 'react';
|
|
3
|
+
import { useRef, useEffect } from 'react';
|
|
4
4
|
import { detectDeviceRegistrationRedirect, getDeviceRegistrationTokenFromUrl, completeDeviceRegistration } from '@dynamic-labs-sdk/client';
|
|
5
5
|
import '../../../context/DynamicContext/useDynamicContext/useDynamicContext.js';
|
|
6
6
|
import { useInternalDynamicContext } from '../../../context/DynamicContext/useDynamicContext/useInternalDynamicContext/useInternalDynamicContext.js';
|
|
@@ -18,6 +18,10 @@ import { hasPendingDeviceRegistration } from '../../../shared/utils/functions/ha
|
|
|
18
18
|
const useSyncDeviceRegistrationFlow = () => {
|
|
19
19
|
const { setShowAuthFlow, sdkHasLoaded, userWithMissingInfo } = useInternalDynamicContext();
|
|
20
20
|
const { clearStackAndPush } = useViewContext();
|
|
21
|
+
// Device registration tokens are single-use. Track tokens we've already
|
|
22
|
+
// attempted to prevent re-firing if the effect re-runs (e.g. when
|
|
23
|
+
// userWithMissingInfo identity flips after the first call's auth update).
|
|
24
|
+
const attemptedDeviceTokenRef = useRef(null);
|
|
21
25
|
useEffect(() => {
|
|
22
26
|
let cancelled = false;
|
|
23
27
|
const syncDeviceRegistration = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -33,6 +37,10 @@ const useSyncDeviceRegistrationFlow = () => {
|
|
|
33
37
|
// complete registration directly without showing the modal
|
|
34
38
|
if (detectDeviceRegistrationRedirect({ url })) {
|
|
35
39
|
const deviceToken = getDeviceRegistrationTokenFromUrl({ url });
|
|
40
|
+
if (attemptedDeviceTokenRef.current === deviceToken) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
attemptedDeviceTokenRef.current = deviceToken;
|
|
36
44
|
try {
|
|
37
45
|
yield completeDeviceRegistration({ deviceToken });
|
|
38
46
|
/**
|
|
@@ -41,6 +41,14 @@ var useDynamicWaas = require('../useDynamicWaas/useDynamicWaas.cjs');
|
|
|
41
41
|
var useRefreshAuth = require('../useRefreshAuth/useRefreshAuth.cjs');
|
|
42
42
|
var DelegationError = require('./DelegationError.cjs');
|
|
43
43
|
|
|
44
|
+
// Pre-share-set backends mark delegation via keyShares[].backupLocation='delegated';
|
|
45
|
+
// share-set backends use otherShareSets[].shareSetType='delegated' instead.
|
|
46
|
+
const isWalletDelegated = (walletProperties) => {
|
|
47
|
+
var _a, _b;
|
|
48
|
+
const hasDelegatedKeyShare = (_a = walletProperties === null || walletProperties === void 0 ? void 0 : walletProperties.keyShares) === null || _a === void 0 ? void 0 : _a.some((keyShare) => keyShare.backupLocation === 'delegated');
|
|
49
|
+
const hasDelegatedShareSet = (_b = walletProperties === null || walletProperties === void 0 ? void 0 : walletProperties.otherShareSets) === null || _b === void 0 ? void 0 : _b.some((shareSet) => shareSet.shareSetType === 'delegated');
|
|
50
|
+
return Boolean(hasDelegatedKeyShare || hasDelegatedShareSet);
|
|
51
|
+
};
|
|
44
52
|
/**
|
|
45
53
|
* Gets pending wallets that are eligible for delegation.
|
|
46
54
|
* If wallets are provided and not empty, converts them to WalletWithStatus[] with pending status.
|
|
@@ -87,15 +95,11 @@ const useWalletDelegation = () => {
|
|
|
87
95
|
const waasCredentials = user.verifiedCredentials.filter((vc) => vc.walletName === 'dynamicwaas' &&
|
|
88
96
|
vc.format === sdkApiCore.JwtVerifiedCredentialFormatEnum.Blockchain);
|
|
89
97
|
const hasWalletNeedingDelegation = waasCredentials.some((vc) => {
|
|
90
|
-
var _a, _b, _c
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
// Check if dismissed this session
|
|
96
|
-
const isDismissedThisSession = (_e = sessionState === null || sessionState === void 0 ? void 0 : sessionState.dismissedWallets) === null || _e === void 0 ? void 0 : _e.includes(vc.id);
|
|
97
|
-
// Needs delegation if: not delegated, not denied, and not dismissed this session
|
|
98
|
-
return (!hasDelegatedKeyShare && !hasDeniedAccess && !isDismissedThisSession);
|
|
98
|
+
var _a, _b, _c;
|
|
99
|
+
const isDelegated = isWalletDelegated(vc.walletProperties);
|
|
100
|
+
const hasDeniedAccess = ((_b = (_a = vc.walletProperties) === null || _a === void 0 ? void 0 : _a.settings) === null || _b === void 0 ? void 0 : _b.hasDeniedDelegatedAccess) === true;
|
|
101
|
+
const isDismissedThisSession = (_c = sessionState === null || sessionState === void 0 ? void 0 : sessionState.dismissedWallets) === null || _c === void 0 ? void 0 : _c.includes(vc.id);
|
|
102
|
+
return !isDelegated && !hasDeniedAccess && !isDismissedThisSession;
|
|
99
103
|
});
|
|
100
104
|
return hasWalletNeedingDelegation;
|
|
101
105
|
}, [user === null || user === void 0 ? void 0 : user.verifiedCredentials, delegatedAccessEnabled, promptUsersOnSignIn]);
|
|
@@ -129,20 +133,18 @@ const useWalletDelegation = () => {
|
|
|
129
133
|
// Map credentials to wallets with status
|
|
130
134
|
return waasCredentials
|
|
131
135
|
.map((vc) => {
|
|
132
|
-
var _a, _b, _c
|
|
136
|
+
var _a, _b, _c;
|
|
133
137
|
let status = 'pending';
|
|
134
|
-
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
const hasDeniedAccess = ((_d = (_c = vc.walletProperties) === null || _c === void 0 ? void 0 : _c.settings) === null || _d === void 0 ? void 0 : _d.hasDeniedDelegatedAccess) === true;
|
|
138
|
-
if (hasDelegatedKeyShare) {
|
|
138
|
+
const isDelegated = isWalletDelegated(vc.walletProperties);
|
|
139
|
+
const hasDeniedAccess = ((_b = (_a = vc.walletProperties) === null || _a === void 0 ? void 0 : _a.settings) === null || _b === void 0 ? void 0 : _b.hasDeniedDelegatedAccess) === true;
|
|
140
|
+
if (isDelegated) {
|
|
139
141
|
status = 'delegated';
|
|
140
142
|
}
|
|
141
143
|
else if (hasDeniedAccess) {
|
|
142
144
|
status = 'denied';
|
|
143
145
|
}
|
|
144
146
|
// Check if dismissed this session (UI state only)
|
|
145
|
-
const isDismissedThisSession = (
|
|
147
|
+
const isDismissedThisSession = (_c = sessionState === null || sessionState === void 0 ? void 0 : sessionState.dismissedWallets) === null || _c === void 0 ? void 0 : _c.includes(vc.id);
|
|
146
148
|
// Find corresponding wallet from userWallets
|
|
147
149
|
const wallet = userWallets.find((w) => w.address === vc.address);
|
|
148
150
|
if (!wallet) {
|
|
@@ -309,4 +311,5 @@ const useWalletDelegation = () => {
|
|
|
309
311
|
};
|
|
310
312
|
|
|
311
313
|
exports.getWalletsToDelegate = getWalletsToDelegate;
|
|
314
|
+
exports.isWalletDelegated = isWalletDelegated;
|
|
312
315
|
exports.useWalletDelegation = useWalletDelegation;
|
|
@@ -5,6 +5,14 @@ export type WalletWithStatus = Wallet & {
|
|
|
5
5
|
status: WalletDelegationStatus;
|
|
6
6
|
isDismissedThisSession?: boolean;
|
|
7
7
|
};
|
|
8
|
+
export declare const isWalletDelegated: (walletProperties: {
|
|
9
|
+
keyShares?: Array<{
|
|
10
|
+
backupLocation?: string;
|
|
11
|
+
}>;
|
|
12
|
+
otherShareSets?: Array<{
|
|
13
|
+
shareSetType?: string;
|
|
14
|
+
}>;
|
|
15
|
+
} | null | undefined) => boolean;
|
|
8
16
|
/**
|
|
9
17
|
* Gets pending wallets that are eligible for delegation.
|
|
10
18
|
* If wallets are provided and not empty, converts them to WalletWithStatus[] with pending status.
|
|
@@ -37,6 +37,14 @@ import { useDynamicWaas } from '../useDynamicWaas/useDynamicWaas.js';
|
|
|
37
37
|
import { useRefreshAuth } from '../useRefreshAuth/useRefreshAuth.js';
|
|
38
38
|
import { DelegationError } from './DelegationError.js';
|
|
39
39
|
|
|
40
|
+
// Pre-share-set backends mark delegation via keyShares[].backupLocation='delegated';
|
|
41
|
+
// share-set backends use otherShareSets[].shareSetType='delegated' instead.
|
|
42
|
+
const isWalletDelegated = (walletProperties) => {
|
|
43
|
+
var _a, _b;
|
|
44
|
+
const hasDelegatedKeyShare = (_a = walletProperties === null || walletProperties === void 0 ? void 0 : walletProperties.keyShares) === null || _a === void 0 ? void 0 : _a.some((keyShare) => keyShare.backupLocation === 'delegated');
|
|
45
|
+
const hasDelegatedShareSet = (_b = walletProperties === null || walletProperties === void 0 ? void 0 : walletProperties.otherShareSets) === null || _b === void 0 ? void 0 : _b.some((shareSet) => shareSet.shareSetType === 'delegated');
|
|
46
|
+
return Boolean(hasDelegatedKeyShare || hasDelegatedShareSet);
|
|
47
|
+
};
|
|
40
48
|
/**
|
|
41
49
|
* Gets pending wallets that are eligible for delegation.
|
|
42
50
|
* If wallets are provided and not empty, converts them to WalletWithStatus[] with pending status.
|
|
@@ -83,15 +91,11 @@ const useWalletDelegation = () => {
|
|
|
83
91
|
const waasCredentials = user.verifiedCredentials.filter((vc) => vc.walletName === 'dynamicwaas' &&
|
|
84
92
|
vc.format === JwtVerifiedCredentialFormatEnum.Blockchain);
|
|
85
93
|
const hasWalletNeedingDelegation = waasCredentials.some((vc) => {
|
|
86
|
-
var _a, _b, _c
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
// Check if dismissed this session
|
|
92
|
-
const isDismissedThisSession = (_e = sessionState === null || sessionState === void 0 ? void 0 : sessionState.dismissedWallets) === null || _e === void 0 ? void 0 : _e.includes(vc.id);
|
|
93
|
-
// Needs delegation if: not delegated, not denied, and not dismissed this session
|
|
94
|
-
return (!hasDelegatedKeyShare && !hasDeniedAccess && !isDismissedThisSession);
|
|
94
|
+
var _a, _b, _c;
|
|
95
|
+
const isDelegated = isWalletDelegated(vc.walletProperties);
|
|
96
|
+
const hasDeniedAccess = ((_b = (_a = vc.walletProperties) === null || _a === void 0 ? void 0 : _a.settings) === null || _b === void 0 ? void 0 : _b.hasDeniedDelegatedAccess) === true;
|
|
97
|
+
const isDismissedThisSession = (_c = sessionState === null || sessionState === void 0 ? void 0 : sessionState.dismissedWallets) === null || _c === void 0 ? void 0 : _c.includes(vc.id);
|
|
98
|
+
return !isDelegated && !hasDeniedAccess && !isDismissedThisSession;
|
|
95
99
|
});
|
|
96
100
|
return hasWalletNeedingDelegation;
|
|
97
101
|
}, [user === null || user === void 0 ? void 0 : user.verifiedCredentials, delegatedAccessEnabled, promptUsersOnSignIn]);
|
|
@@ -125,20 +129,18 @@ const useWalletDelegation = () => {
|
|
|
125
129
|
// Map credentials to wallets with status
|
|
126
130
|
return waasCredentials
|
|
127
131
|
.map((vc) => {
|
|
128
|
-
var _a, _b, _c
|
|
132
|
+
var _a, _b, _c;
|
|
129
133
|
let status = 'pending';
|
|
130
|
-
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
const hasDeniedAccess = ((_d = (_c = vc.walletProperties) === null || _c === void 0 ? void 0 : _c.settings) === null || _d === void 0 ? void 0 : _d.hasDeniedDelegatedAccess) === true;
|
|
134
|
-
if (hasDelegatedKeyShare) {
|
|
134
|
+
const isDelegated = isWalletDelegated(vc.walletProperties);
|
|
135
|
+
const hasDeniedAccess = ((_b = (_a = vc.walletProperties) === null || _a === void 0 ? void 0 : _a.settings) === null || _b === void 0 ? void 0 : _b.hasDeniedDelegatedAccess) === true;
|
|
136
|
+
if (isDelegated) {
|
|
135
137
|
status = 'delegated';
|
|
136
138
|
}
|
|
137
139
|
else if (hasDeniedAccess) {
|
|
138
140
|
status = 'denied';
|
|
139
141
|
}
|
|
140
142
|
// Check if dismissed this session (UI state only)
|
|
141
|
-
const isDismissedThisSession = (
|
|
143
|
+
const isDismissedThisSession = (_c = sessionState === null || sessionState === void 0 ? void 0 : sessionState.dismissedWallets) === null || _c === void 0 ? void 0 : _c.includes(vc.id);
|
|
142
144
|
// Find corresponding wallet from userWallets
|
|
143
145
|
const wallet = userWallets.find((w) => w.address === vc.address);
|
|
144
146
|
if (!wallet) {
|
|
@@ -304,4 +306,4 @@ const useWalletDelegation = () => {
|
|
|
304
306
|
};
|
|
305
307
|
};
|
|
306
308
|
|
|
307
|
-
export { getWalletsToDelegate, useWalletDelegation };
|
|
309
|
+
export { getWalletsToDelegate, isWalletDelegated, useWalletDelegation };
|
|
@@ -2,23 +2,23 @@ import { WalletRecoveryState } from '@dynamic-labs-wallet/browser-wallet-client'
|
|
|
2
2
|
import { ChainEnum } from '@dynamic-labs/sdk-api-core';
|
|
3
3
|
export type SetPasswordParams = {
|
|
4
4
|
accountAddress: string;
|
|
5
|
-
chainName: ChainEnum;
|
|
5
|
+
chainName: ChainEnum | string;
|
|
6
6
|
newPassword: string;
|
|
7
7
|
};
|
|
8
8
|
export type UpdatePasswordParams = {
|
|
9
9
|
accountAddress: string;
|
|
10
|
-
chainName: ChainEnum;
|
|
10
|
+
chainName: ChainEnum | string;
|
|
11
11
|
newPassword: string;
|
|
12
12
|
existingPassword?: string;
|
|
13
13
|
};
|
|
14
14
|
export type UnlockWalletParams = {
|
|
15
15
|
accountAddress: string;
|
|
16
|
-
chainName: ChainEnum;
|
|
16
|
+
chainName: ChainEnum | string;
|
|
17
17
|
password: string;
|
|
18
18
|
};
|
|
19
19
|
export type CheckWalletLockStateParams = {
|
|
20
20
|
accountAddress: string;
|
|
21
|
-
chainName: ChainEnum;
|
|
21
|
+
chainName: ChainEnum | string;
|
|
22
22
|
};
|
|
23
23
|
export type WalletPasswordState = {
|
|
24
24
|
isLoading: boolean;
|