@abstraxn/signer-react 3.1.3 → 3.2.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 +29 -5
- package/README.md +72 -0
- package/dist/src/WalletModal.css +46 -0
- package/dist/src/WalletModal.js +23 -4
- package/dist/src/components/AbstraxnProvider/AbstraxnProvider.js +23 -52
- package/dist/src/components/AbstraxnProvider/AbstraxnProviderInner.js +102 -22
- package/dist/src/components/AbstraxnProvider/useWalletInitialization.js +10 -5
- package/dist/src/components/OnboardingUI/OnboardingUIReact.js +4 -1
- package/dist/src/components/OnboardingUI/OnboardingUIWeb.js +10 -4
- package/dist/src/components/OnboardingUI/hooks/useAuthMethods.js +10 -0
- package/dist/src/components/WalletModal/hooks/useSendTransaction.js +1 -1
- package/dist/src/components/WalletModal/utils/formatUtils.d.ts +1 -1
- package/dist/src/components/WalletModal/utils/formatUtils.js +3 -4
- package/dist/src/hooks.d.ts +50 -21
- package/dist/src/hooks.js +342 -4
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.js +1 -1
- package/dist/src/types.d.ts +1 -1
- package/dist/src/wagmiConfig.d.ts +1 -7
- package/dist/src/wagmiConfig.js +15 -31
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,16 +5,40 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [3.
|
|
8
|
+
## [3.2.0] - 2026-04-22
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Account Abstraction owner hook** – Added `useSmartAccountOwner()` to expose a viem-compatible custom local account for AA integrations (e.g. permissionless). The hook returns `{ smartAccountOwner, isReady, address }`, supports optional address override, and is exported from `@abstraxn/signer-react`.
|
|
13
|
+
- **EIP-7702 authorization signing support** – `smartAccountOwner` now implements `signAuthorization(...)` so 7702 flows can sign delegation authorizations through the SDK backend path.
|
|
9
14
|
|
|
10
15
|
### Changed
|
|
11
16
|
|
|
12
|
-
- **
|
|
13
|
-
-
|
|
17
|
+
- **AA signing now uses backend signing APIs** – AA owner signing routes through existing authenticated backend signing methods (`signTransactionViaAPI` / `signTypedTxViaAPI`) instead of requiring app-level Turnkey account creation.
|
|
18
|
+
- **UserOperation message signing compatibility** – `signMessage` in AA owner flow now follows viem EIP-191 semantics (`hashMessage(...)` then sign digest) to match permissionless/simple account UserOperation signature expectations.
|
|
19
|
+
- **7702 payload encoding alignment** – 7702 authorization signing uses Turnkey-specific parameters:
|
|
20
|
+
- `encoding: PAYLOAD_ENCODING_EIP7702_AUTHORIZATION`
|
|
21
|
+
- `hashFunction: HASH_FUNCTION_NOT_APPLICABLE`
|
|
14
22
|
|
|
15
|
-
###
|
|
23
|
+
### Documentation
|
|
24
|
+
|
|
25
|
+
- **AA docs update** – Added `useSmartAccountOwner()` to hook list and expanded AA integration example in README.
|
|
26
|
+
- **Abstraxn infra example** – Updated README AA sample to use Abstraxn bundler/paymaster endpoints and dynamic chain-based URL construction.
|
|
27
|
+
|
|
28
|
+
## [3.1.4] - 2026-04-06
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- **Passkey completion via login code (`@abstraxn/signer-core`)** – Passkey signup and login now expect a `loginCode` (and optional `mfaRequired`) from the backend, then exchange it through `POST /auth/exchange` before tokens and user state are finalized. Passkey responses no longer persist access/refresh tokens directly from those calls.
|
|
33
|
+
- **Auth route prefixes** – OTP init/verify and passkey signup/login client paths use `/auth/otp/...` and `/auth/passkey/...` instead of `/login/otp/...` and `/login/passkey/...`.
|
|
34
|
+
- **Passkey login stamp** – The WebAuthn/Turnkey stamp is serialized and sent as a JSON string in the passkey login request, matching the updated API contract.
|
|
35
|
+
- **Passkey signup payload** – `targetPublicKey` is optional when a device public key is not available; session completion merges profile fields from the passkey API response where the JWT omits them (e.g. `isPolicy`, `publicKey`, `authProvider`).
|
|
36
|
+
- **MFA after passkey** – `AbstraxnWallet.loginWithPasskey` / `signupWithPasskey` and the React provider defer `connect()` when MFA is still required; `AuthManager` tracks `pendingSessionAuthMethod: 'passkey'` so post-MFA session setup uses the correct path.
|
|
37
|
+
|
|
38
|
+
### Added
|
|
16
39
|
|
|
17
|
-
- **`
|
|
40
|
+
- **`PasskeyFlowResult` and onboarding hooks** – `onPasskeySignup` / `onPasskeyLogin` may return `{ mfaRequired: true }`; `onPasskeyPendingMfa` lets UIs jump to the MFA step (`OnboardingUIReact`, `OnboardingUIWeb`, and `useAuthMethods`). `PasskeyFlowResult` is re-exported from `@abstraxn/signer-core`.
|
|
41
|
+
- **Server logout on full disconnect** – When the Abstraxn session disconnect runs, the SDK best-effort calls `POST /auth/logout` with the current access token (external-wallet-only disconnect continues to skip this).
|
|
18
42
|
|
|
19
43
|
## [3.1.2] - 2026-03-27
|
|
20
44
|
|
package/README.md
CHANGED
|
@@ -105,6 +105,78 @@ function HookConnectButton() {
|
|
|
105
105
|
- `useExportWallet()` - Export wallet (EVM or Solana, based on current chain)
|
|
106
106
|
- `usePublicClient()` / `usePrepareRawTxn()` / `useSignTxn()` / `useSignAndSendTxn()` / `useWaitForTxnReceipt()` - EVM transaction flow (prepare → sign → send → confirm)
|
|
107
107
|
- `useSolanaConnection()` / `useSolanaPublicKey()` / `usePrepareSolanaTxn()` / `useSignSolanaTxn()` / `useSignAndSendSolanaTxn()` / `useWaitForSolanaConfirmation()` - Solana transaction flow (prepare → sign → send → confirm)
|
|
108
|
+
- `useSmartAccountOwner()` - Get an AA-compatible owner account for permissionless-style account abstraction flows
|
|
109
|
+
|
|
110
|
+
### Example: Account Abstraction owner (permissionless-compatible)
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
import { useMemo } from 'react';
|
|
114
|
+
import { useSmartAccountOwner } from '@abstraxn/signer-react';
|
|
115
|
+
import { createPublicClient, createWalletClient, http } from 'viem';
|
|
116
|
+
import { sepolia } from 'viem/chains';
|
|
117
|
+
import { toSimpleSmartAccount } from 'permissionless/accounts';
|
|
118
|
+
import {
|
|
119
|
+
createBundlerClient,
|
|
120
|
+
createPaymasterClient,
|
|
121
|
+
entryPoint07Address,
|
|
122
|
+
} from 'viem/account-abstraction';
|
|
123
|
+
|
|
124
|
+
export function useAaClient({
|
|
125
|
+
chain = sepolia,
|
|
126
|
+
rpcUrl = 'https://sepolia.rpc.thirdweb.com',
|
|
127
|
+
abstraxnApiKey,
|
|
128
|
+
}: {
|
|
129
|
+
chain?: Chain;
|
|
130
|
+
rpcUrl?: string;
|
|
131
|
+
abstraxnApiKey: string;
|
|
132
|
+
}) {
|
|
133
|
+
const { smartAccountOwner, isReady } = useSmartAccountOwner();
|
|
134
|
+
|
|
135
|
+
return useMemo(async () => {
|
|
136
|
+
if (!isReady || !smartAccountOwner) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const bundlerUrl = `https://bundler.abstraxn.com/api/v1/${chainId}/?apikey=${abstraxnApiKey}`;
|
|
141
|
+
const paymasterUrl = `https://paymaster.abstraxn.com/api/v2/${chainId}/?apikey=${abstraxnApiKey}`;
|
|
142
|
+
|
|
143
|
+
const publicClient = createPublicClient({
|
|
144
|
+
chain,
|
|
145
|
+
transport: http(rpcUrl),
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// permissionless expects a wallet client owner
|
|
149
|
+
const ownerWalletClient = createWalletClient({
|
|
150
|
+
account: smartAccountOwner,
|
|
151
|
+
chain,
|
|
152
|
+
transport: http(rpcUrl),
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
const paymasterClient = createPaymasterClient({
|
|
156
|
+
transport: http(paymasterUrl),
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const simpleSmartAccount = await toSimpleSmartAccount({
|
|
160
|
+
owner: ownerWalletClient,
|
|
161
|
+
client: publicClient,
|
|
162
|
+
entryPoint: {
|
|
163
|
+
address: entryPoint07Address,
|
|
164
|
+
version: '0.7',
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
return createBundlerClient({
|
|
169
|
+
client: publicClient,
|
|
170
|
+
transport: http(bundlerUrl),
|
|
171
|
+
});
|
|
172
|
+
}, [isReady, smartAccountOwner, chain, rpcUrl, abstraxnApiKey]);
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Notes:
|
|
177
|
+
- `permissionless` and AA provider clients are app-level dependencies (not bundled in `@abstraxn/signer-react`).
|
|
178
|
+
- The owner returned by `useSmartAccountOwner()` is signer-only; you control chain, bundler, paymaster, and entry point in your app.
|
|
179
|
+
- After creating the `bundlerClient`, call `sendUserOperation({ account: simpleSmartAccount, calls: [...], paymaster: paymasterClient })`.
|
|
108
180
|
|
|
109
181
|
### Example: EVM → Solana flow after social/email login
|
|
110
182
|
|
package/dist/src/WalletModal.css
CHANGED
|
@@ -531,6 +531,52 @@
|
|
|
531
531
|
color: #6b7280;
|
|
532
532
|
}
|
|
533
533
|
|
|
534
|
+
.wallet-modal-asset-balance-skeleton {
|
|
535
|
+
display: inline-block;
|
|
536
|
+
width: 140px;
|
|
537
|
+
max-width: 100%;
|
|
538
|
+
height: 14px;
|
|
539
|
+
border-radius: 999px;
|
|
540
|
+
background: linear-gradient(90deg, rgba(156, 163, 175, 0.22), rgba(156, 163, 175, 0.44), rgba(156, 163, 175, 0.22));
|
|
541
|
+
background-size: 200% 100%;
|
|
542
|
+
animation: wallet-modal-balance-shimmer 1.2s ease-in-out infinite;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
.wallet-modal-theme-dark .wallet-modal-asset-balance-skeleton {
|
|
546
|
+
background: linear-gradient(90deg, rgba(75, 85, 99, 0.3), rgba(107, 114, 128, 0.55), rgba(75, 85, 99, 0.3));
|
|
547
|
+
background-size: 200% 100%;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
.wallet-modal-asset-explorer-link {
|
|
551
|
+
display: inline-flex;
|
|
552
|
+
width: fit-content;
|
|
553
|
+
margin-top: 2px;
|
|
554
|
+
font-size: 12px;
|
|
555
|
+
font-weight: 500;
|
|
556
|
+
text-decoration: none;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
.wallet-modal-theme-dark .wallet-modal-asset-explorer-link {
|
|
560
|
+
color: #a855f7;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
.wallet-modal-theme-light .wallet-modal-asset-explorer-link {
|
|
564
|
+
color: #9333ea;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
.wallet-modal-asset-explorer-link:hover {
|
|
568
|
+
text-decoration: underline;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
@keyframes wallet-modal-balance-shimmer {
|
|
572
|
+
0% {
|
|
573
|
+
background-position: 100% 0;
|
|
574
|
+
}
|
|
575
|
+
100% {
|
|
576
|
+
background-position: -100% 0;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
534
580
|
.wallet-modal-asset-status {
|
|
535
581
|
position: absolute;
|
|
536
582
|
bottom: 0;
|
package/dist/src/WalletModal.js
CHANGED
|
@@ -36,6 +36,7 @@ export function WalletModal({ isOpen, onClose, onRampUrl }) {
|
|
|
36
36
|
const [showSendModal, setShowSendModal] = useState(false);
|
|
37
37
|
const [showManageModal, setShowManageModal] = useState(false);
|
|
38
38
|
const [showChainSelector, setShowChainSelector] = useState(false);
|
|
39
|
+
const [isBalanceRefreshing, setIsBalanceRefreshing] = useState(false);
|
|
39
40
|
const [selectedChainType, setSelectedChainType] = useState("evm");
|
|
40
41
|
// Export states
|
|
41
42
|
const [showExportWarning, setShowExportWarning] = useState(false);
|
|
@@ -59,19 +60,30 @@ export function WalletModal({ isOpen, onClose, onRampUrl }) {
|
|
|
59
60
|
// If no chain selected, show default
|
|
60
61
|
if (!balance || balance === 0n)
|
|
61
62
|
return "0";
|
|
62
|
-
return formatBalance(balance, 18, "ETH");
|
|
63
|
+
return formatBalance(balance, 18, "ETH", 4);
|
|
63
64
|
}
|
|
64
65
|
const symbol = currentChain.nativeCurrency?.symbol || "ETH";
|
|
65
66
|
const decimals = currentChain.nativeCurrency?.decimals || 18;
|
|
66
67
|
if (!balance || balance === 0n) {
|
|
67
68
|
return `0 ${symbol}`;
|
|
68
69
|
}
|
|
69
|
-
return formatBalance(balance, decimals, symbol);
|
|
70
|
+
return formatBalance(balance, decimals, symbol, 4);
|
|
70
71
|
}, [currentChain, externalWalletBalance, walletBalance]);
|
|
72
|
+
const chainExplorer = useMemo(() => {
|
|
73
|
+
if (!currentChain)
|
|
74
|
+
return null;
|
|
75
|
+
const url = currentChain.blockExplorer?.url || currentChain.explorerUrl;
|
|
76
|
+
if (!url)
|
|
77
|
+
return null;
|
|
78
|
+
return {
|
|
79
|
+
url,
|
|
80
|
+
label: currentChain.blockExplorer?.name || "Explorer",
|
|
81
|
+
};
|
|
82
|
+
}, [currentChain]);
|
|
71
83
|
// Refetch balance from RPC when UI screen changes (back button, modal open/close, etc.)
|
|
72
84
|
useEffect(() => {
|
|
73
85
|
if (isOpen && refetchBalance) {
|
|
74
|
-
refetchBalance();
|
|
86
|
+
void refetchBalance();
|
|
75
87
|
}
|
|
76
88
|
}, [isOpen, showReceiveModal, showSendModal, showManageModal, showChainSelector, refetchBalance]);
|
|
77
89
|
/** Load MFA status once per session (in-memory) when this wallet modal opens; not persisted. */
|
|
@@ -300,7 +312,7 @@ export function WalletModal({ isOpen, onClose, onRampUrl }) {
|
|
|
300
312
|
return (_jsx(ManageWalletModal, { isOpen: true, onClose: () => setShowManageModal(false), displayAddress: displayAddress, userEmail: user?.email, organizationName: whoami?.organizationName, isExternalWalletConnected: isExternalWalletConnected || false, onExportPrivateKey: handleExportPrivateKey, theme: theme }));
|
|
301
313
|
}
|
|
302
314
|
// Main Modal
|
|
303
|
-
return (_jsxs(_Fragment, { children: [_jsx("div", { "data-abstraxn-sdk-root": true, className: `wallet-modal-overlay wallet-modal-theme-${theme}`, onClick: showChainSelector ? undefined : onClose, style: showChainSelector ? { pointerEvents: "none" } : undefined, children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} ${showChainSelector ? "selector-open" : ""}`, onClick: (e) => e.stopPropagation(), style: showChainSelector ? { pointerEvents: "auto" } : undefined, children: [_jsxs("div", { className: "wallet-modal-header", children: [_jsx("div", { className: "wallet-modal-header-left", children: _jsxs("div", { className: "wallet-modal-user-info", children: [_jsx("div", { className: "wallet-modal-avatar", children: _jsx(UserAvatar, { user: user, isExternalWalletConnected: isExternalWalletConnected || false }) }), _jsxs("div", { className: "wallet-modal-user-details", children: [_jsxs("div", { className: "wallet-modal-address", onClick: handleCopyAddress, children: [formatAddress(displayAddress || address), copied ? (_jsx("span", { className: "wallet-modal-copy-notification", children: "Copied!" })) : (_jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", className: "wallet-modal-copy-icon", children: [_jsx("path", { d: "M5.5 3.5H3.5C2.67157 3.5 2 4.17157 2 5V12.5C2 13.3284 2.67157 14 3.5 14H11C11.8284 14 12.5 13.3284 12.5 12.5V10.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M5.5 3.5C5.5 2.67157 6.17157 2 7 2H12.5C13.3284 2 14 2.67157 14 3.5V9C14 9.82843 13.3284 10.5 12.5 10.5H7C6.17157 10.5 5.5 9.82843 5.5 9V3.5Z", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })] }))] }), user?.email && (_jsx("div", { className: "wallet-modal-email", children: user.email }))] })] }) }), _jsx("div", { className: "wallet-modal-header-right", children: _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M18 6L6 18M6 6L18 18", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }) })] }), !isExternalWalletConnected && (_jsxs("div", { className: "wallet-modal-actions", children: [_jsxs("button", { className: "wallet-modal-action-btn", onClick: handleSend, children: [_jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("line", { x1: "22", y1: "2", x2: "11", y2: "13" }), _jsx("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })] }), _jsx("span", { children: "Send" })] }), _jsxs("button", { className: "wallet-modal-action-btn", onClick: handleReceive, children: [_jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }), _jsx("polyline", { points: "7 10 12 15 17 10" }), _jsx("line", { x1: "12", y1: "15", x2: "12", y2: "3" })] }), _jsx("span", { children: "Receive" })] }), _jsxs("button", { className: "wallet-modal-action-btn", onClick: handleBuy, children: [_jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }), _jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })] }), _jsx("span", { children: "Buy" })] })] })), !isExternalWalletConnected && currentChain && (_jsxs("div", { className: "wallet-modal-asset", onClick: () => setShowChainSelector(true), children: [_jsxs("div", { className: "wallet-modal-asset-info", children: [_jsxs("div", { className: "wallet-modal-asset-icon-wrapper", children: [currentChain.iconUrl ? (_jsx("img", { src: currentChain.iconUrl, alt: currentChain.displayName, className: "wallet-modal-asset-icon-img" })) : (_jsx("div", { className: "wallet-modal-asset-icon", children: _jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("circle", { cx: "12", cy: "12", r: "10" }), _jsx("path", { d: "M12 2v20M2 12h20" })] }) })), _jsx("span", { className: "wallet-modal-asset-status" })] }), _jsxs("div", { className: "wallet-modal-asset-details", children: [_jsx("div", { className: "wallet-modal-asset-name", children: currentChain.displayName }), _jsx("div", { className: "wallet-modal-asset-balance", children: balanceDisplay })] })] }), _jsx("div", { className: "wallet-modal-asset-arrow", children: _jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: _jsx("polyline", { points: "9 18 15 12 9 6" }) }) })] })), _jsxs("div", { className: "wallet-modal-menu", children: [_jsxs("button", { className: "wallet-modal-menu-item", onClick: handleManageWallet, children: [_jsx(LuWallet, { size: 20 }), _jsx("span", { children: "Manage Wallet" })] }), _jsxs("button", { className: "wallet-modal-menu-item wallet-modal-menu-item-disconnect", onClick: handleDisconnect, children: [_jsxs("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: [_jsx("path", { d: "M7 3H4C3.44772 3 3 3.44772 3 4V16C3 16.5523 3.44772 17 4 17H7", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M13 7L17 10L13 13", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M17 10H9", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })] }), _jsx("span", { children: "Disconnect" })] })] })] }) }), showChainSelector && (_jsx("div", { "data-abstraxn-sdk-root": true, className: `wallet-modal-overlay wallet-modal-theme-${theme}`, style: { zIndex: 10006, pointerEvents: "auto" }, onClick: (e) => {
|
|
315
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { "data-abstraxn-sdk-root": true, className: `wallet-modal-overlay wallet-modal-theme-${theme}`, onClick: showChainSelector ? undefined : onClose, style: showChainSelector ? { pointerEvents: "none" } : undefined, children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} ${showChainSelector ? "selector-open" : ""}`, onClick: (e) => e.stopPropagation(), style: showChainSelector ? { pointerEvents: "auto" } : undefined, children: [_jsxs("div", { className: "wallet-modal-header", children: [_jsx("div", { className: "wallet-modal-header-left", children: _jsxs("div", { className: "wallet-modal-user-info", children: [_jsx("div", { className: "wallet-modal-avatar", children: _jsx(UserAvatar, { user: user, isExternalWalletConnected: isExternalWalletConnected || false }) }), _jsxs("div", { className: "wallet-modal-user-details", children: [_jsxs("div", { className: "wallet-modal-address", onClick: handleCopyAddress, children: [formatAddress(displayAddress || address), copied ? (_jsx("span", { className: "wallet-modal-copy-notification", children: "Copied!" })) : (_jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", className: "wallet-modal-copy-icon", children: [_jsx("path", { d: "M5.5 3.5H3.5C2.67157 3.5 2 4.17157 2 5V12.5C2 13.3284 2.67157 14 3.5 14H11C11.8284 14 12.5 13.3284 12.5 12.5V10.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M5.5 3.5C5.5 2.67157 6.17157 2 7 2H12.5C13.3284 2 14 2.67157 14 3.5V9C14 9.82843 13.3284 10.5 12.5 10.5H7C6.17157 10.5 5.5 9.82843 5.5 9V3.5Z", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })] }))] }), user?.email && (_jsx("div", { className: "wallet-modal-email", children: user.email }))] })] }) }), _jsx("div", { className: "wallet-modal-header-right", children: _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M18 6L6 18M6 6L18 18", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }) })] }), !isExternalWalletConnected && (_jsxs("div", { className: "wallet-modal-actions", children: [_jsxs("button", { className: "wallet-modal-action-btn", onClick: handleSend, children: [_jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("line", { x1: "22", y1: "2", x2: "11", y2: "13" }), _jsx("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })] }), _jsx("span", { children: "Send" })] }), _jsxs("button", { className: "wallet-modal-action-btn", onClick: handleReceive, children: [_jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }), _jsx("polyline", { points: "7 10 12 15 17 10" }), _jsx("line", { x1: "12", y1: "15", x2: "12", y2: "3" })] }), _jsx("span", { children: "Receive" })] }), _jsxs("button", { className: "wallet-modal-action-btn", onClick: handleBuy, children: [_jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }), _jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })] }), _jsx("span", { children: "Buy" })] })] })), !isExternalWalletConnected && currentChain && (_jsxs("div", { className: "wallet-modal-asset", onClick: () => setShowChainSelector(true), children: [_jsxs("div", { className: "wallet-modal-asset-info", children: [_jsxs("div", { className: "wallet-modal-asset-icon-wrapper", children: [currentChain.iconUrl ? (_jsx("img", { src: currentChain.iconUrl, alt: currentChain.displayName, className: "wallet-modal-asset-icon-img" })) : (_jsx("div", { className: "wallet-modal-asset-icon", children: _jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("circle", { cx: "12", cy: "12", r: "10" }), _jsx("path", { d: "M12 2v20M2 12h20" })] }) })), _jsx("span", { className: "wallet-modal-asset-status" })] }), _jsxs("div", { className: "wallet-modal-asset-details", children: [_jsx("div", { className: "wallet-modal-asset-name", children: currentChain.displayName }), _jsx("div", { className: "wallet-modal-asset-balance", children: isBalanceRefreshing ? (_jsx("span", { className: "wallet-modal-asset-balance-skeleton", "aria-label": "Loading balance" })) : (balanceDisplay) }), chainExplorer?.url && (_jsx("a", { href: chainExplorer.url, target: "_blank", rel: "noopener noreferrer", className: "wallet-modal-asset-explorer-link", onClick: (e) => e.stopPropagation(), children: chainExplorer.label }))] })] }), _jsx("div", { className: "wallet-modal-asset-arrow", children: _jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: _jsx("polyline", { points: "9 18 15 12 9 6" }) }) })] })), _jsxs("div", { className: "wallet-modal-menu", children: [_jsxs("button", { className: "wallet-modal-menu-item", onClick: handleManageWallet, children: [_jsx(LuWallet, { size: 20 }), _jsx("span", { children: "Manage Wallet" })] }), _jsxs("button", { className: "wallet-modal-menu-item wallet-modal-menu-item-disconnect", onClick: handleDisconnect, children: [_jsxs("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: [_jsx("path", { d: "M7 3H4C3.44772 3 3 3.44772 3 4V16C3 16.5523 3.44772 17 4 17H7", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M13 7L17 10L13 13", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M17 10H9", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })] }), _jsx("span", { children: "Disconnect" })] })] })] }) }), showChainSelector && (_jsx("div", { "data-abstraxn-sdk-root": true, className: `wallet-modal-overlay wallet-modal-theme-${theme}`, style: { zIndex: 10006, pointerEvents: "auto" }, onClick: (e) => {
|
|
304
316
|
e.stopPropagation();
|
|
305
317
|
setShowChainSelector(false);
|
|
306
318
|
}, children: _jsx("div", { className: `wallet-modal-content wallet-modal-theme-${theme}`, onClick: (e) => e.stopPropagation(), children: _jsx(ChainSelector, { isOpen: showChainSelector, onClose: () => setShowChainSelector(false), currentChain: currentChain || null, availableChains: availableChains || [], onChainSelect: async (chainId) => {
|
|
@@ -317,7 +329,11 @@ export function WalletModal({ isOpen, onClose, onRampUrl }) {
|
|
|
317
329
|
// Switch to a different chain
|
|
318
330
|
if (switchChainEnhanced) {
|
|
319
331
|
try {
|
|
332
|
+
setIsBalanceRefreshing(true);
|
|
320
333
|
await switchChainEnhanced(chainId);
|
|
334
|
+
if (refetchBalance) {
|
|
335
|
+
await refetchBalance();
|
|
336
|
+
}
|
|
321
337
|
// Only close if switch was successful
|
|
322
338
|
setShowChainSelector(false);
|
|
323
339
|
}
|
|
@@ -325,6 +341,9 @@ export function WalletModal({ isOpen, onClose, onRampUrl }) {
|
|
|
325
341
|
console.error("Failed to switch chain:", error);
|
|
326
342
|
// Don't close the selector on error so user can try again
|
|
327
343
|
}
|
|
344
|
+
finally {
|
|
345
|
+
setIsBalanceRefreshing(false);
|
|
346
|
+
}
|
|
328
347
|
}
|
|
329
348
|
else {
|
|
330
349
|
console.warn("switchChainEnhanced not available");
|
|
@@ -168,67 +168,38 @@ export function AbstraxnProvider({ config, children }) {
|
|
|
168
168
|
externalSsr,
|
|
169
169
|
config.wagmiConfig,
|
|
170
170
|
]);
|
|
171
|
-
//
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
if (externalWalletsEnabled) {
|
|
176
|
-
return { embedWagmiConfig: null, embedConfigError: null };
|
|
177
|
-
}
|
|
178
|
-
try {
|
|
179
|
-
const cfg = createWagmiConfig(wagmiChains, undefined, undefined, wagmiThemeRef.current, externalSsr, true);
|
|
180
|
-
return { embedWagmiConfig: cfg, embedConfigError: null };
|
|
181
|
-
}
|
|
182
|
-
catch (error) {
|
|
183
|
-
console.error("Failed to create embed-only wagmi config:", error);
|
|
184
|
-
return {
|
|
185
|
-
embedWagmiConfig: null,
|
|
186
|
-
embedConfigError: error instanceof Error
|
|
187
|
-
? error
|
|
188
|
-
: new Error("Failed to create embed-only wagmi config"),
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
}, [externalWalletsEnabled, chainsKey, externalSsr]);
|
|
192
|
-
// Embedded-only mode: still mount WagmiProvider (no connectors) when React Query is available.
|
|
193
|
-
if (!externalWalletsEnabled) {
|
|
171
|
+
// If external wallets are enabled, wrap with QueryClientProvider and WagmiProvider
|
|
172
|
+
if (externalWalletsEnabled) {
|
|
173
|
+
// Check if React Query is available BEFORE doing anything else
|
|
174
|
+
// This prevents errors from happening in the first place
|
|
194
175
|
const queryCheck = canUseReactQuery();
|
|
195
176
|
if (!queryCheck.canUse) {
|
|
196
|
-
console.error("❌
|
|
177
|
+
console.error("❌ External wallets are disabled because React Query is not available.\n" +
|
|
197
178
|
`Reason: ${queryCheck.reason || "Unknown"}\n` +
|
|
198
|
-
"
|
|
179
|
+
"Please install @tanstack/react-query@^5.90.16 and ensure there is only one React instance.\n" +
|
|
180
|
+
"Falling back to Abstraxn wallet only.");
|
|
199
181
|
return (_jsx(AbstraxnProviderWithoutWagmi, { config: config, children: children }));
|
|
200
182
|
}
|
|
201
|
-
if (
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
}
|
|
183
|
+
if (configError) {
|
|
184
|
+
console.error("Failed to create wagmi config:", configError);
|
|
185
|
+
// Fallback to provider without wagmi if config creation fails
|
|
205
186
|
return (_jsx(AbstraxnProviderWithoutWagmi, { config: config, children: children }));
|
|
206
187
|
}
|
|
188
|
+
if (!wagmiConfig) {
|
|
189
|
+
// Show loading state while config is being created
|
|
190
|
+
// Don't render AbstraxnProviderInner until wagmiConfig is ready
|
|
191
|
+
return (_jsx(QueryClientWrapper, { queryClient: queryClient, children: _jsx("div", { style: { display: "none" }, children: "Loading wallet connectors..." }) }));
|
|
192
|
+
}
|
|
193
|
+
// ✅ For SSR mode, wait for hydration before rendering WagmiProvider
|
|
194
|
+
// This ensures injected wallets (Phantom, etc.) are detected properly
|
|
207
195
|
if (externalSsr && !isHydrated) {
|
|
208
|
-
return (_jsx(QueryClientWrapper, { queryClient: queryClient, children: _jsx("div", { style: { display: "none" }, children: "Hydrating..." }) }));
|
|
196
|
+
return (_jsx(QueryClientWrapper, { queryClient: queryClient, children: _jsx("div", { style: { display: "none" }, children: "Hydrating wallet connectors..." }) }));
|
|
209
197
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
// Check if React Query is available BEFORE doing anything else
|
|
214
|
-
const queryCheck = canUseReactQuery();
|
|
215
|
-
if (!queryCheck.canUse) {
|
|
216
|
-
console.error("❌ External wallets are disabled because React Query is not available.\n" +
|
|
217
|
-
`Reason: ${queryCheck.reason || "Unknown"}\n` +
|
|
218
|
-
"Please install @tanstack/react-query@^5.90.16 and ensure there is only one React instance.\n" +
|
|
219
|
-
"Falling back to Abstraxn wallet only.");
|
|
220
|
-
return (_jsx(AbstraxnProviderWithoutWagmi, { config: config, children: children }));
|
|
221
|
-
}
|
|
222
|
-
if (configError) {
|
|
223
|
-
console.error("Failed to create wagmi config:", configError);
|
|
224
|
-
return (_jsx(AbstraxnProviderWithoutWagmi, { config: config, children: children }));
|
|
225
|
-
}
|
|
226
|
-
if (!wagmiConfig) {
|
|
227
|
-
return (_jsx(QueryClientWrapper, { queryClient: queryClient, children: _jsx("div", { style: { display: "none" }, children: "Loading wallet connectors..." }) }));
|
|
228
|
-
}
|
|
229
|
-
if (externalSsr && !isHydrated) {
|
|
230
|
-
return (_jsx(QueryClientWrapper, { queryClient: queryClient, children: _jsx("div", { style: { display: "none" }, children: "Hydrating wallet connectors..." }) }));
|
|
198
|
+
// Do NOT pass key to WagmiProvider. Remounting loses connection state and causes
|
|
199
|
+
// "Connector not connected" in Next.js (e.g. when config loads after hydration).
|
|
200
|
+
return (_jsx(QueryClientWrapper, { queryClient: queryClient, children: _jsx(ConnectionProvider, { endpoint: config.chains?.solanaEndpoint || "https://api.mainnet-beta.solana.com", children: _jsx(WalletProvider, { wallets: solanaWallets, autoConnect: true, children: _jsx(WagmiProvider, { config: wagmiConfig, initialState: config.initialState, children: _jsx(AbstraxnProviderWithWagmi, { config: config, children: children }) }) }) }) }));
|
|
231
201
|
}
|
|
232
|
-
|
|
202
|
+
// If external wallets are disabled, use the provider without wagmi
|
|
203
|
+
return (_jsx(AbstraxnProviderWithoutWagmi, { config: config, children: children }));
|
|
233
204
|
}
|
|
234
205
|
//# sourceMappingURL=AbstraxnProvider.js.map
|
|
@@ -766,10 +766,13 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
|
|
|
766
766
|
}
|
|
767
767
|
const authManager = walletInstance.getAuthManager();
|
|
768
768
|
const user = await authManager.loginWithPasskey();
|
|
769
|
-
// Set user immediately so onLoginSuccess can access it
|
|
770
769
|
setUser(user);
|
|
771
|
-
|
|
770
|
+
const lastAuthState = authManager.getLastAuthState();
|
|
771
|
+
if (lastAuthState?.mfaRequired === true) {
|
|
772
|
+
return { mfaRequired: true };
|
|
773
|
+
}
|
|
772
774
|
await walletInstance.connect();
|
|
775
|
+
return undefined;
|
|
773
776
|
},
|
|
774
777
|
onPasskeySignup: async () => {
|
|
775
778
|
if (!walletInstance)
|
|
@@ -784,11 +787,13 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
|
|
|
784
787
|
}
|
|
785
788
|
const authManager = walletInstance.getAuthManager();
|
|
786
789
|
const user = await authManager.signupWithPasskey();
|
|
787
|
-
// Clear any previous errors on successful verification
|
|
788
|
-
// setError(null);
|
|
789
790
|
setUser(user);
|
|
790
|
-
|
|
791
|
+
const lastAuthState = authManager.getLastAuthState();
|
|
792
|
+
if (lastAuthState?.mfaRequired === true) {
|
|
793
|
+
return { mfaRequired: true };
|
|
794
|
+
}
|
|
791
795
|
await walletInstance.connect();
|
|
796
|
+
return undefined;
|
|
792
797
|
},
|
|
793
798
|
onLoginSuccess: async (_data) => {
|
|
794
799
|
// Clear any previous errors on successful login
|
|
@@ -1605,7 +1610,7 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
|
|
|
1605
1610
|
setLoading(false);
|
|
1606
1611
|
}
|
|
1607
1612
|
}, [showOnboarding]);
|
|
1608
|
-
//
|
|
1613
|
+
// Full disconnect: when Abstraxn is connected, `wallet.disconnect()` runs and signer-core notifies POST /auth/logout; external-wallet-only flows use `disconnectExternalWallet` instead (no core disconnect).
|
|
1609
1614
|
const disconnect = useCallback(async () => {
|
|
1610
1615
|
setLoading(true);
|
|
1611
1616
|
setDisconnecting(true);
|
|
@@ -2972,7 +2977,7 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
|
|
|
2972
2977
|
wagmiDisconnect,
|
|
2973
2978
|
wagmiAccount?.isConnected,
|
|
2974
2979
|
]);
|
|
2975
|
-
//
|
|
2980
|
+
// External wallet only — does not call AbstraxnWallet.disconnect (no server /auth/logout).
|
|
2976
2981
|
const disconnectExternalWallet = useCallback(async () => {
|
|
2977
2982
|
if (!externalWalletsEnabled || !wagmiDisconnect) {
|
|
2978
2983
|
return;
|
|
@@ -3220,6 +3225,60 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
|
|
|
3220
3225
|
const currentChainId = isExternalWalletConnected && externalWalletChainId
|
|
3221
3226
|
? externalWalletChainId
|
|
3222
3227
|
: chainId;
|
|
3228
|
+
// Custom chains passed via `config.chains` (array form) are not part of the static `EVM_CHAINS` map.
|
|
3229
|
+
// Normalize them into `ChainData` so the wallet UI can resolve chain + balance correctly.
|
|
3230
|
+
const customChainsById = useMemo(() => {
|
|
3231
|
+
const chainConfig = config.chains;
|
|
3232
|
+
const map = new Map();
|
|
3233
|
+
if (!Array.isArray(chainConfig) || chainConfig.length === 0)
|
|
3234
|
+
return map;
|
|
3235
|
+
for (const raw of chainConfig) {
|
|
3236
|
+
if (!raw || typeof raw.id !== "number" || !raw.nativeCurrency)
|
|
3237
|
+
continue;
|
|
3238
|
+
// Extract RPC URL (support viem shape + sdk-integrate custom shape)
|
|
3239
|
+
let rpcUrl;
|
|
3240
|
+
if (raw.rpcUrls?.default?.http) {
|
|
3241
|
+
rpcUrl = Array.isArray(raw.rpcUrls.default.http)
|
|
3242
|
+
? raw.rpcUrls.default.http[0]
|
|
3243
|
+
: raw.rpcUrls.default.http;
|
|
3244
|
+
}
|
|
3245
|
+
else if (raw.rpcUrls?.public?.http) {
|
|
3246
|
+
rpcUrl = Array.isArray(raw.rpcUrls.public.http)
|
|
3247
|
+
? raw.rpcUrls.public.http[0]
|
|
3248
|
+
: raw.rpcUrls.public.http;
|
|
3249
|
+
}
|
|
3250
|
+
else if (typeof raw.rpcUrl === "string") {
|
|
3251
|
+
rpcUrl = raw.rpcUrl;
|
|
3252
|
+
}
|
|
3253
|
+
if (!rpcUrl || rpcUrl.trim() === "")
|
|
3254
|
+
continue;
|
|
3255
|
+
const explorerUrl = raw.blockExplorers?.default?.url ||
|
|
3256
|
+
raw.explorerUrl || '';
|
|
3257
|
+
const displayName = raw.displayName || raw.name || `Chain ${raw.id}`;
|
|
3258
|
+
const name = (raw.name ? String(raw.name) : `chain-${raw.id}`)
|
|
3259
|
+
.toLowerCase()
|
|
3260
|
+
.replace(/\s+/g, "-");
|
|
3261
|
+
const isTestnet = raw.testnet === true ||
|
|
3262
|
+
raw.isTestnet === true ||
|
|
3263
|
+
// Heuristic fallback for unknown custom chains
|
|
3264
|
+
(raw.id !== 1 && raw.id !== 10 && raw.id !== 137 && raw.id !== 8453 && raw.id !== 42161 && raw.id !== 2741);
|
|
3265
|
+
const chainData = {
|
|
3266
|
+
id: raw.id,
|
|
3267
|
+
name,
|
|
3268
|
+
displayName,
|
|
3269
|
+
rpcUrl,
|
|
3270
|
+
explorerUrl,
|
|
3271
|
+
iconUrl: raw.iconUrl,
|
|
3272
|
+
icon: raw.icon,
|
|
3273
|
+
nativeCurrency: raw.nativeCurrency,
|
|
3274
|
+
type: "evm",
|
|
3275
|
+
isTestnet,
|
|
3276
|
+
blockExplorer: raw.blockExplorer,
|
|
3277
|
+
};
|
|
3278
|
+
map.set(chainData.id, chainData);
|
|
3279
|
+
}
|
|
3280
|
+
return map;
|
|
3281
|
+
}, [config.chains]);
|
|
3223
3282
|
// Fetch balance for Abstraxn wallet (not external wallet) - reusable for on-demand refetch
|
|
3224
3283
|
const refetchWalletBalance = useCallback(async () => {
|
|
3225
3284
|
if (isExternalWalletConnected || !address || !currentChainId) {
|
|
@@ -3227,7 +3286,7 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
|
|
|
3227
3286
|
return;
|
|
3228
3287
|
}
|
|
3229
3288
|
try {
|
|
3230
|
-
const currentChain = getChainById(currentChainId);
|
|
3289
|
+
const currentChain = getChainById(currentChainId) || customChainsById.get(currentChainId);
|
|
3231
3290
|
if (!currentChain || currentChain.type !== "evm") {
|
|
3232
3291
|
setWalletBalance(null);
|
|
3233
3292
|
return;
|
|
@@ -3254,24 +3313,35 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
|
|
|
3254
3313
|
console.error("Failed to fetch balance:", error);
|
|
3255
3314
|
setWalletBalance(null);
|
|
3256
3315
|
}
|
|
3257
|
-
}, [address, currentChainId, isExternalWalletConnected]);
|
|
3316
|
+
}, [address, currentChainId, isExternalWalletConnected, customChainsById]);
|
|
3258
3317
|
useEffect(() => {
|
|
3259
3318
|
refetchWalletBalance();
|
|
3260
3319
|
}, [refetchWalletBalance]);
|
|
3261
3320
|
// Single refetch for UI: Abstraxn wallet = RPC call, external wallet = wagmi refetch
|
|
3262
|
-
const refetchBalance = useCallback(() => {
|
|
3321
|
+
const refetchBalance = useCallback(async () => {
|
|
3263
3322
|
if (isExternalWalletConnected && wagmiBalance?.refetch) {
|
|
3264
|
-
|
|
3323
|
+
await wagmiBalance.refetch();
|
|
3265
3324
|
return;
|
|
3266
3325
|
}
|
|
3267
|
-
|
|
3326
|
+
await refetchWalletBalance();
|
|
3268
3327
|
}, [isExternalWalletConnected, wagmiBalance, refetchWalletBalance]);
|
|
3269
3328
|
// Compute available chains from config - supports both legacy and new format
|
|
3270
3329
|
const availableChains = useMemo(() => {
|
|
3271
3330
|
const chains = [];
|
|
3272
3331
|
const chainConfig = config.chains;
|
|
3273
|
-
// Priority 1: Check
|
|
3274
|
-
if (chainConfig
|
|
3332
|
+
// Priority 1: Check if chains is an array of viem/custom chain objects
|
|
3333
|
+
if (Array.isArray(chainConfig) && chainConfig.length > 0) {
|
|
3334
|
+
for (const raw of chainConfig) {
|
|
3335
|
+
const normalized = raw && typeof raw.id === "number"
|
|
3336
|
+
? customChainsById.get(raw.id)
|
|
3337
|
+
: undefined;
|
|
3338
|
+
if (normalized)
|
|
3339
|
+
chains.push(normalized);
|
|
3340
|
+
}
|
|
3341
|
+
}
|
|
3342
|
+
// Priority 2: Check new chains config format
|
|
3343
|
+
if (!Array.isArray(chainConfig) &&
|
|
3344
|
+
chainConfig?.supportedEvmChains &&
|
|
3275
3345
|
chainConfig.supportedEvmChains.length > 0) {
|
|
3276
3346
|
// Use configured chains from new format
|
|
3277
3347
|
chainConfig.supportedEvmChains.forEach((chainName) => {
|
|
@@ -3281,8 +3351,10 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
|
|
|
3281
3351
|
}
|
|
3282
3352
|
});
|
|
3283
3353
|
}
|
|
3284
|
-
// Priority
|
|
3285
|
-
else if (
|
|
3354
|
+
// Priority 3: Check legacy supportedChains format
|
|
3355
|
+
else if (!Array.isArray(chainConfig) &&
|
|
3356
|
+
config.supportedChains &&
|
|
3357
|
+
config.supportedChains.length > 0) {
|
|
3286
3358
|
// Convert legacy Chain format to ChainData
|
|
3287
3359
|
config.supportedChains.forEach((legacyChain) => {
|
|
3288
3360
|
// Try to find matching chain by ID
|
|
@@ -3308,7 +3380,7 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
|
|
|
3308
3380
|
}
|
|
3309
3381
|
});
|
|
3310
3382
|
}
|
|
3311
|
-
// Priority
|
|
3383
|
+
// Priority 4: Default chains only if nothing configured at all
|
|
3312
3384
|
// Only show defaults if both config.chains and config.supportedChains are missing
|
|
3313
3385
|
else if (!chainConfig && !config.supportedChains) {
|
|
3314
3386
|
chains.push(EVM_CHAINS.ethereum, EVM_CHAINS.polygon, EVM_CHAINS.base);
|
|
@@ -3325,13 +3397,15 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
|
|
|
3325
3397
|
: !chainConfig && !config.supportedChains
|
|
3326
3398
|
? [EVM_CHAINS.ethereum, EVM_CHAINS.polygon, EVM_CHAINS.base]
|
|
3327
3399
|
: [];
|
|
3328
|
-
}, [config.chains, config.supportedChains]);
|
|
3400
|
+
}, [config.chains, config.supportedChains, customChainsById]);
|
|
3329
3401
|
// Get current chain data
|
|
3330
3402
|
const currentChain = useMemo(() => {
|
|
3331
3403
|
if (!currentChainId)
|
|
3332
3404
|
return null;
|
|
3333
|
-
return getChainById(currentChainId) ||
|
|
3334
|
-
|
|
3405
|
+
return (getChainById(currentChainId) ||
|
|
3406
|
+
customChainsById.get(currentChainId) ||
|
|
3407
|
+
null);
|
|
3408
|
+
}, [currentChainId, customChainsById]);
|
|
3335
3409
|
// Enhanced switchChain that works for both EVM and Solana
|
|
3336
3410
|
const switchChainEnhanced = useCallback(async (targetChainId) => {
|
|
3337
3411
|
if (!walletRef.current) {
|
|
@@ -3342,7 +3416,7 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
|
|
|
3342
3416
|
if (!targetChainInAvailable) {
|
|
3343
3417
|
throw new Error(`Chain with ID ${targetChainId} is not available. Please configure it in your SDK setup.`);
|
|
3344
3418
|
}
|
|
3345
|
-
const targetChain = getChainById(targetChainId);
|
|
3419
|
+
const targetChain = getChainById(targetChainId) || customChainsById.get(targetChainId);
|
|
3346
3420
|
if (!targetChain) {
|
|
3347
3421
|
throw new Error(`Chain with ID ${targetChainId} is not supported`);
|
|
3348
3422
|
}
|
|
@@ -3402,7 +3476,13 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
|
|
|
3402
3476
|
finally {
|
|
3403
3477
|
setLoading(false);
|
|
3404
3478
|
}
|
|
3405
|
-
}, [
|
|
3479
|
+
}, [
|
|
3480
|
+
isExternalWalletConnected,
|
|
3481
|
+
wagmiSwitchChain,
|
|
3482
|
+
switchChain,
|
|
3483
|
+
availableChains,
|
|
3484
|
+
customChainsById,
|
|
3485
|
+
]);
|
|
3406
3486
|
const setEmailForOtp = useCallback((email) => {
|
|
3407
3487
|
setEmailForOtpState(email);
|
|
3408
3488
|
}, []);
|
|
@@ -351,10 +351,13 @@ export function useWalletInitialization({ config, walletRef, onboardingRef, otpI
|
|
|
351
351
|
}
|
|
352
352
|
const authManager = walletInstance.getAuthManager();
|
|
353
353
|
const user = await authManager.loginWithPasskey();
|
|
354
|
-
// Set user immediately so onLoginSuccess can access it
|
|
355
354
|
setUser(user);
|
|
356
|
-
|
|
355
|
+
const lastAuthState = authManager.getLastAuthState();
|
|
356
|
+
if (lastAuthState?.mfaRequired === true) {
|
|
357
|
+
return { mfaRequired: true };
|
|
358
|
+
}
|
|
357
359
|
await walletInstance.connect();
|
|
360
|
+
return undefined;
|
|
358
361
|
},
|
|
359
362
|
onPasskeySignup: async () => {
|
|
360
363
|
if (!walletInstance)
|
|
@@ -369,11 +372,13 @@ export function useWalletInitialization({ config, walletRef, onboardingRef, otpI
|
|
|
369
372
|
}
|
|
370
373
|
const authManager = walletInstance.getAuthManager();
|
|
371
374
|
const user = await authManager.signupWithPasskey();
|
|
372
|
-
// Clear any previous errors on successful verification
|
|
373
|
-
// setError(null);
|
|
374
375
|
setUser(user);
|
|
375
|
-
|
|
376
|
+
const lastAuthState = authManager.getLastAuthState();
|
|
377
|
+
if (lastAuthState?.mfaRequired === true) {
|
|
378
|
+
return { mfaRequired: true };
|
|
379
|
+
}
|
|
376
380
|
await walletInstance.connect();
|
|
381
|
+
return undefined;
|
|
377
382
|
},
|
|
378
383
|
onLoginSuccess: async (_data) => {
|
|
379
384
|
// Clear any previous errors on successful login
|