@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/dist/src/hooks.js
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
import { useState, useCallback, useEffect, useMemo } from 'react';
|
|
5
5
|
import { useAbstraxnWallet } from './AbstraxnProvider';
|
|
6
6
|
import { InvalidDeviceIdError, SignMfaRequiredError } from '@abstraxn/signer-core';
|
|
7
|
-
import { createPublicClient, createWalletClient, http, getContract, serializeTransaction, encodeFunctionData, hashTypedData } from 'viem';
|
|
7
|
+
import { createPublicClient, createWalletClient, http, getContract, serializeTransaction, encodeFunctionData, hashTypedData, hashMessage, parseSignature } from 'viem';
|
|
8
|
+
import { toAccount } from 'viem/accounts';
|
|
8
9
|
import { Connection as SolanaConnection, Transaction as SolanaTransaction, SystemProgram, PublicKey, LAMPORTS_PER_SOL, TransactionInstruction, } from '@solana/web3.js';
|
|
9
10
|
import { useWalletClient as useWagmiWalletClient, useAccount, useConfig, useChainId as useWagmiChainId, useSwitchChain as useWagmiSwitchChain, useSignMessage as useWagmiSignMessage, useReconnect as useWagmiReconnect } from 'wagmi';
|
|
10
11
|
import { getWalletClient, switchChain } from '@wagmi/core';
|
|
@@ -72,6 +73,67 @@ export function useWallet() {
|
|
|
72
73
|
const { wallet } = useAbstraxnWallet();
|
|
73
74
|
return wallet;
|
|
74
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Hook to get an AA-compatible owner account for permissionless-compatible SDKs.
|
|
78
|
+
* This does not include bundler/paymaster integration; apps can plug in any provider.
|
|
79
|
+
*/
|
|
80
|
+
export function useSmartAccountOwner(options = {}) {
|
|
81
|
+
const { isConnected, address: connectedAddress, signTransactionViaAPI, signTypedTxViaAPI, verifySignMfa, } = useAbstraxnWallet();
|
|
82
|
+
const ownerAddress = (options.address ?? connectedAddress ?? null);
|
|
83
|
+
const smartAccountOwner = useMemo(() => {
|
|
84
|
+
if (!isConnected || !ownerAddress)
|
|
85
|
+
return null;
|
|
86
|
+
return toAccount({
|
|
87
|
+
address: ownerAddress,
|
|
88
|
+
/**
|
|
89
|
+
* ERC-4337 SimpleAccount (permissionless) signs UserOperations via viem `signMessage` with
|
|
90
|
+
* `message: { raw: userOpHash }`. That requires the same digest as viem local accounts:
|
|
91
|
+
* EIP-191 `hashMessage(message)`, then ECDSA sign that 32-byte digest — not UTF-8 text hashing.
|
|
92
|
+
*/
|
|
93
|
+
async signMessage({ message }) {
|
|
94
|
+
const digest = hashMessage(message);
|
|
95
|
+
const signature = await runWithSignStepUpRetry(() => signTypedTxViaAPI(ownerAddress, digest, 'PAYLOAD_ENCODING_HEXADECIMAL', 'HASH_FUNCTION_NO_OP').then((res) => res.signature), verifySignMfa);
|
|
96
|
+
return (signature.startsWith('0x') ? signature : `0x${signature}`);
|
|
97
|
+
},
|
|
98
|
+
async signTransaction(transaction) {
|
|
99
|
+
const unsignedTransaction = serializeTransaction(transaction);
|
|
100
|
+
const result = await runWithSignStepUpRetry(() => signTransactionViaAPI(unsignedTransaction, ownerAddress), verifySignMfa);
|
|
101
|
+
return result.signedTransaction;
|
|
102
|
+
},
|
|
103
|
+
async signTypedData(typedData) {
|
|
104
|
+
const digest = hashTypedData(typedData);
|
|
105
|
+
const result = await runWithSignStepUpRetry(() => signTypedTxViaAPI(ownerAddress, digest, 'PAYLOAD_ENCODING_EIP712', 'HASH_FUNCTION_NO_OP'), verifySignMfa);
|
|
106
|
+
const signature = result.signature;
|
|
107
|
+
return (signature.startsWith('0x') ? signature : `0x${signature}`);
|
|
108
|
+
},
|
|
109
|
+
/** EIP-7702: sign delegation authorization (`keccak256(0x05 || rlp(...))`) via backend, same as raw ECDSA over digest. */
|
|
110
|
+
async signAuthorization(parameters) {
|
|
111
|
+
const authorizationAddress = parameters.contractAddress ?? parameters.address;
|
|
112
|
+
const authorizationPayload = JSON.stringify({
|
|
113
|
+
chainId: parameters.chainId,
|
|
114
|
+
address: authorizationAddress,
|
|
115
|
+
nonce: parameters.nonce,
|
|
116
|
+
});
|
|
117
|
+
const sig = await runWithSignStepUpRetry(() => signTypedTxViaAPI(ownerAddress, authorizationPayload, 'PAYLOAD_ENCODING_EIP7702_AUTHORIZATION', 'HASH_FUNCTION_NOT_APPLICABLE').then((res) => res.signature), verifySignMfa);
|
|
118
|
+
const hex = (sig.startsWith('0x') ? sig : `0x${sig}`);
|
|
119
|
+
const { r, s, yParity } = parseSignature(hex);
|
|
120
|
+
return {
|
|
121
|
+
address: authorizationAddress,
|
|
122
|
+
chainId: parameters.chainId,
|
|
123
|
+
nonce: parameters.nonce,
|
|
124
|
+
r,
|
|
125
|
+
s,
|
|
126
|
+
yParity,
|
|
127
|
+
};
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
}, [isConnected, ownerAddress, signTransactionViaAPI, signTypedTxViaAPI, verifySignMfa]);
|
|
131
|
+
return {
|
|
132
|
+
smartAccountOwner,
|
|
133
|
+
isReady: !!smartAccountOwner,
|
|
134
|
+
address: ownerAddress,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
75
137
|
/**
|
|
76
138
|
* Hook to export wallet private key
|
|
77
139
|
* Returns the export bundle containing the private key
|
|
@@ -414,6 +476,282 @@ export function useDisableMfa() {
|
|
|
414
476
|
reset,
|
|
415
477
|
};
|
|
416
478
|
}
|
|
479
|
+
const AUTH_METHOD_LINK_PROVIDER_ALLOWLIST = new Set([
|
|
480
|
+
'google',
|
|
481
|
+
'discord',
|
|
482
|
+
'x',
|
|
483
|
+
'passkey',
|
|
484
|
+
]);
|
|
485
|
+
const AUTH_METHOD_UNLINK_PROVIDER_ALLOWLIST = new Set([
|
|
486
|
+
'google',
|
|
487
|
+
'discord',
|
|
488
|
+
'x',
|
|
489
|
+
'email',
|
|
490
|
+
'passkey',
|
|
491
|
+
]);
|
|
492
|
+
function normalizeAuthMethodProviderForApi(provider) {
|
|
493
|
+
const normalized = provider.trim().toLowerCase();
|
|
494
|
+
if (normalized === 'otp')
|
|
495
|
+
return 'email';
|
|
496
|
+
return normalized;
|
|
497
|
+
}
|
|
498
|
+
function normalizeAuthMethodProviderForMatch(provider) {
|
|
499
|
+
const normalized = normalizeAuthMethodProviderForApi(provider);
|
|
500
|
+
if (normalized === 'twitter' || normalized === 'x')
|
|
501
|
+
return 'x';
|
|
502
|
+
return normalized;
|
|
503
|
+
}
|
|
504
|
+
function normalizeAuthMethodErrorMessage(message) {
|
|
505
|
+
return message.replace(/^network error:\s*/i, '').trim();
|
|
506
|
+
}
|
|
507
|
+
function toAuthMethodError(error, fallbackMessage) {
|
|
508
|
+
if (error instanceof Error) {
|
|
509
|
+
return new Error(normalizeAuthMethodErrorMessage(error.message || fallbackMessage));
|
|
510
|
+
}
|
|
511
|
+
if (typeof error === 'string' && error.trim() !== '') {
|
|
512
|
+
return new Error(normalizeAuthMethodErrorMessage(error));
|
|
513
|
+
}
|
|
514
|
+
return new Error(fallbackMessage);
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Hook for linking/unlinking auth methods without any UI concerns.
|
|
518
|
+
* It exposes state and actions only; consumers own rendering and messaging.
|
|
519
|
+
*/
|
|
520
|
+
export function useAuthMethodLinking() {
|
|
521
|
+
const { wallet, whoami, getSupportedAuthMethods, getLinkedAuthMethods, requestOtpForEmailLink, loginWithOTP, } = useAbstraxnWallet();
|
|
522
|
+
const [supportedMethods, setSupportedMethods] = useState([]);
|
|
523
|
+
const [linkedMethods, setLinkedMethods] = useState([]);
|
|
524
|
+
const [queryLoading, setQueryLoading] = useState(false);
|
|
525
|
+
const [actionProvider, setActionProvider] = useState(null);
|
|
526
|
+
const [error, setError] = useState(null);
|
|
527
|
+
const requireConnectedWallet = useCallback(() => {
|
|
528
|
+
if (!wallet?.isConnected) {
|
|
529
|
+
throw new Error('Wallet not connected');
|
|
530
|
+
}
|
|
531
|
+
return wallet;
|
|
532
|
+
}, [wallet]);
|
|
533
|
+
const refreshAuthMethods = useCallback(async (_options) => {
|
|
534
|
+
const activeWallet = requireConnectedWallet();
|
|
535
|
+
setQueryLoading(true);
|
|
536
|
+
setError(null);
|
|
537
|
+
try {
|
|
538
|
+
const supportedRequest = getSupportedAuthMethods != null
|
|
539
|
+
? getSupportedAuthMethods()
|
|
540
|
+
: activeWallet.getSupportedAuthMethods();
|
|
541
|
+
const linkedRequest = getLinkedAuthMethods != null
|
|
542
|
+
? getLinkedAuthMethods()
|
|
543
|
+
: activeWallet.getLinkedAuthMethods();
|
|
544
|
+
const [supportedResponse, linkedResponse] = await Promise.all([
|
|
545
|
+
supportedRequest,
|
|
546
|
+
linkedRequest,
|
|
547
|
+
]);
|
|
548
|
+
const loginProvider = normalizeAuthMethodProviderForMatch(String(whoami?.loginProvider ?? ''));
|
|
549
|
+
const allSupportedMethods = supportedResponse.supportedMethods ?? [];
|
|
550
|
+
const filteredMethods = loginProvider !== ''
|
|
551
|
+
? allSupportedMethods.filter((method) => normalizeAuthMethodProviderForMatch(method.provider) !== loginProvider)
|
|
552
|
+
: allSupportedMethods;
|
|
553
|
+
setSupportedMethods(filteredMethods);
|
|
554
|
+
setLinkedMethods(linkedResponse.linkedMethods ?? []);
|
|
555
|
+
}
|
|
556
|
+
catch (err) {
|
|
557
|
+
const nextError = toAuthMethodError(err, 'Failed to load auth methods');
|
|
558
|
+
setSupportedMethods([]);
|
|
559
|
+
setLinkedMethods([]);
|
|
560
|
+
setError(nextError.message);
|
|
561
|
+
throw nextError;
|
|
562
|
+
}
|
|
563
|
+
finally {
|
|
564
|
+
setQueryLoading(false);
|
|
565
|
+
}
|
|
566
|
+
}, [getLinkedAuthMethods, getSupportedAuthMethods, requireConnectedWallet, whoami]);
|
|
567
|
+
const isLinked = useCallback((provider) => {
|
|
568
|
+
const normalizedProvider = normalizeAuthMethodProviderForMatch(provider);
|
|
569
|
+
return linkedMethods.some((method) => normalizeAuthMethodProviderForMatch(method.authProvider) === normalizedProvider);
|
|
570
|
+
}, [linkedMethods]);
|
|
571
|
+
const runOAuthPopupLink = useCallback(async (activeWallet, provider) => {
|
|
572
|
+
if (typeof window === 'undefined') {
|
|
573
|
+
throw new Error('OAuth linking requires a browser environment');
|
|
574
|
+
}
|
|
575
|
+
const { authUrl } = await activeWallet.initiateLinkAuth(provider);
|
|
576
|
+
const width = 500;
|
|
577
|
+
const height = 600;
|
|
578
|
+
const left = Math.round((window.screen.width - width) / 2);
|
|
579
|
+
const top = Math.round((window.screen.height - height) / 2);
|
|
580
|
+
const popup = window.open(authUrl, 'abstraxn-auth-link', `width=${width},height=${height},left=${left},top=${top},scrollbars=yes,resizable=yes`);
|
|
581
|
+
if (!popup) {
|
|
582
|
+
throw new Error('Popup blocked. Please allow popups for this site.');
|
|
583
|
+
}
|
|
584
|
+
const timeoutMs = 120000;
|
|
585
|
+
await new Promise((resolve, reject) => {
|
|
586
|
+
let settled = false;
|
|
587
|
+
let closeCheckId = null;
|
|
588
|
+
let timeoutId = null;
|
|
589
|
+
const finalizeReject = (reason) => {
|
|
590
|
+
if (settled)
|
|
591
|
+
return;
|
|
592
|
+
settled = true;
|
|
593
|
+
cleanup();
|
|
594
|
+
reject(new Error(reason));
|
|
595
|
+
};
|
|
596
|
+
const cleanup = () => {
|
|
597
|
+
window.removeEventListener('message', onMessage);
|
|
598
|
+
if (closeCheckId != null)
|
|
599
|
+
clearInterval(closeCheckId);
|
|
600
|
+
if (timeoutId != null)
|
|
601
|
+
clearTimeout(timeoutId);
|
|
602
|
+
};
|
|
603
|
+
const onMessage = (event) => {
|
|
604
|
+
if (event.origin !== window.location.origin)
|
|
605
|
+
return;
|
|
606
|
+
if (event.source !== popup)
|
|
607
|
+
return;
|
|
608
|
+
const data = event.data;
|
|
609
|
+
if (!data?.type)
|
|
610
|
+
return;
|
|
611
|
+
const eventProvider = normalizeAuthMethodProviderForMatch(String(data.provider ?? ''));
|
|
612
|
+
const targetProvider = normalizeAuthMethodProviderForMatch(provider);
|
|
613
|
+
if (eventProvider !== targetProvider)
|
|
614
|
+
return;
|
|
615
|
+
if (data.type === 'abstraxn-auth-link-error') {
|
|
616
|
+
finalizeReject(normalizeAuthMethodErrorMessage(String(data.error ?? 'Failed to link auth method')));
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
if (data.type === 'abstraxn-auth-link-done') {
|
|
620
|
+
if (!data.activityBody || data.activityBody.trim() === '') {
|
|
621
|
+
finalizeReject('Invalid linking response');
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
settled = true;
|
|
625
|
+
cleanup();
|
|
626
|
+
activeWallet
|
|
627
|
+
.submitLinkAuthStamped(provider, data.activityBody)
|
|
628
|
+
.then(resolve)
|
|
629
|
+
.catch((submitError) => {
|
|
630
|
+
reject(toAuthMethodError(submitError, 'Failed to finalize auth method link'));
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
window.addEventListener('message', onMessage);
|
|
635
|
+
closeCheckId = setInterval(() => {
|
|
636
|
+
if (popup.closed) {
|
|
637
|
+
finalizeReject('Linking was cancelled');
|
|
638
|
+
}
|
|
639
|
+
}, 200);
|
|
640
|
+
timeoutId = setTimeout(() => {
|
|
641
|
+
finalizeReject('Linking timed out. Please try again.');
|
|
642
|
+
}, timeoutMs);
|
|
643
|
+
});
|
|
644
|
+
}, [wallet]);
|
|
645
|
+
const linkProvider = useCallback(async (provider) => {
|
|
646
|
+
const activeWallet = requireConnectedWallet();
|
|
647
|
+
const normalizedProvider = provider.toLowerCase();
|
|
648
|
+
if (!AUTH_METHOD_LINK_PROVIDER_ALLOWLIST.has(normalizedProvider)) {
|
|
649
|
+
throw new Error(`Unsupported provider for linking: ${provider}`);
|
|
650
|
+
}
|
|
651
|
+
setActionProvider(normalizedProvider);
|
|
652
|
+
setError(null);
|
|
653
|
+
try {
|
|
654
|
+
if (normalizedProvider === 'passkey') {
|
|
655
|
+
await activeWallet.linkPasskey();
|
|
656
|
+
}
|
|
657
|
+
else {
|
|
658
|
+
await runOAuthPopupLink(activeWallet, normalizedProvider);
|
|
659
|
+
}
|
|
660
|
+
await refreshAuthMethods({ force: true });
|
|
661
|
+
}
|
|
662
|
+
catch (err) {
|
|
663
|
+
const nextError = toAuthMethodError(err, 'Failed to link auth method');
|
|
664
|
+
setError(nextError.message);
|
|
665
|
+
throw nextError;
|
|
666
|
+
}
|
|
667
|
+
finally {
|
|
668
|
+
setActionProvider(null);
|
|
669
|
+
}
|
|
670
|
+
}, [refreshAuthMethods, requireConnectedWallet, runOAuthPopupLink]);
|
|
671
|
+
const requestEmailLinkOtp = useCallback(async (email) => {
|
|
672
|
+
const activeWallet = requireConnectedWallet();
|
|
673
|
+
const trimmedEmail = email.trim();
|
|
674
|
+
if (!trimmedEmail) {
|
|
675
|
+
throw new Error('Email is required');
|
|
676
|
+
}
|
|
677
|
+
setActionProvider('email');
|
|
678
|
+
setError(null);
|
|
679
|
+
try {
|
|
680
|
+
if (requestOtpForEmailLink) {
|
|
681
|
+
return await requestOtpForEmailLink(trimmedEmail);
|
|
682
|
+
}
|
|
683
|
+
if (loginWithOTP) {
|
|
684
|
+
return await loginWithOTP(trimmedEmail);
|
|
685
|
+
}
|
|
686
|
+
// Fallback to core method directly if context methods are unavailable.
|
|
687
|
+
return await activeWallet.requestOtpForEmailLink(trimmedEmail);
|
|
688
|
+
}
|
|
689
|
+
catch (err) {
|
|
690
|
+
const nextError = toAuthMethodError(err, 'Failed to send email verification code');
|
|
691
|
+
setError(nextError.message);
|
|
692
|
+
throw nextError;
|
|
693
|
+
}
|
|
694
|
+
finally {
|
|
695
|
+
setActionProvider(null);
|
|
696
|
+
}
|
|
697
|
+
}, [loginWithOTP, requestOtpForEmailLink, requireConnectedWallet]);
|
|
698
|
+
const confirmEmailLink = useCallback(async (otpId, otpCode) => {
|
|
699
|
+
const activeWallet = requireConnectedWallet();
|
|
700
|
+
const trimmedOtpId = otpId.trim();
|
|
701
|
+
const trimmedOtpCode = otpCode.trim();
|
|
702
|
+
if (!trimmedOtpId || !trimmedOtpCode) {
|
|
703
|
+
throw new Error('otpId and otpCode are required');
|
|
704
|
+
}
|
|
705
|
+
setActionProvider('email');
|
|
706
|
+
setError(null);
|
|
707
|
+
try {
|
|
708
|
+
await activeWallet.linkEmail(trimmedOtpId, trimmedOtpCode);
|
|
709
|
+
await refreshAuthMethods({ force: true });
|
|
710
|
+
}
|
|
711
|
+
catch (err) {
|
|
712
|
+
const nextError = toAuthMethodError(err, 'Failed to link email');
|
|
713
|
+
setError(nextError.message);
|
|
714
|
+
throw nextError;
|
|
715
|
+
}
|
|
716
|
+
finally {
|
|
717
|
+
setActionProvider(null);
|
|
718
|
+
}
|
|
719
|
+
}, [refreshAuthMethods, requireConnectedWallet]);
|
|
720
|
+
const unlinkProvider = useCallback(async (provider) => {
|
|
721
|
+
const activeWallet = requireConnectedWallet();
|
|
722
|
+
const normalizedProvider = normalizeAuthMethodProviderForApi(provider);
|
|
723
|
+
if (!AUTH_METHOD_UNLINK_PROVIDER_ALLOWLIST.has(normalizedProvider)) {
|
|
724
|
+
throw new Error(`Unsupported provider for unlinking: ${provider}`);
|
|
725
|
+
}
|
|
726
|
+
setActionProvider(normalizedProvider);
|
|
727
|
+
setError(null);
|
|
728
|
+
try {
|
|
729
|
+
await activeWallet.unlinkAuthMethod(normalizedProvider);
|
|
730
|
+
await refreshAuthMethods({ force: true });
|
|
731
|
+
}
|
|
732
|
+
catch (err) {
|
|
733
|
+
const nextError = toAuthMethodError(err, 'Failed to unlink auth method');
|
|
734
|
+
setError(nextError.message);
|
|
735
|
+
throw nextError;
|
|
736
|
+
}
|
|
737
|
+
finally {
|
|
738
|
+
setActionProvider(null);
|
|
739
|
+
}
|
|
740
|
+
}, [refreshAuthMethods, requireConnectedWallet]);
|
|
741
|
+
return {
|
|
742
|
+
supportedMethods,
|
|
743
|
+
linkedMethods,
|
|
744
|
+
loading: queryLoading || actionProvider !== null,
|
|
745
|
+
actionProvider,
|
|
746
|
+
error,
|
|
747
|
+
refreshAuthMethods,
|
|
748
|
+
isLinked,
|
|
749
|
+
linkProvider,
|
|
750
|
+
requestEmailLinkOtp,
|
|
751
|
+
confirmEmailLink,
|
|
752
|
+
unlinkProvider,
|
|
753
|
+
};
|
|
754
|
+
}
|
|
417
755
|
/**
|
|
418
756
|
* Hook to access external wallet functionality
|
|
419
757
|
* Returns external wallet connection state and methods
|
|
@@ -504,7 +842,7 @@ export function useExternalWalletChain() {
|
|
|
504
842
|
* ```
|
|
505
843
|
*/
|
|
506
844
|
export function useExternalWalletInfo() {
|
|
507
|
-
const { externalWalletChainId, externalWalletNetwork, isExternalWalletConnected, externalWalletAddress, externalWalletBalance, } = useExternalWallet();
|
|
845
|
+
const { externalWalletChainId, externalWalletNetwork, switchExternalWalletChain, isExternalWalletConnected, externalWalletAddress, externalWalletBalance, } = useExternalWallet();
|
|
508
846
|
const { sendTransaction, signMessage, signTransaction, switchChain, } = useAbstraxnWallet();
|
|
509
847
|
const [formattedBalance, setFormattedBalance] = useState('0');
|
|
510
848
|
useEffect(() => {
|
|
@@ -571,8 +909,8 @@ export function useExternalWalletInfo() {
|
|
|
571
909
|
// Balance information
|
|
572
910
|
balance: externalWalletBalance, // BigInt in wei
|
|
573
911
|
formattedBalance, // String formatted as ETH (e.g., "0.123456")
|
|
574
|
-
//
|
|
575
|
-
switchChain,
|
|
912
|
+
// Chain switching
|
|
913
|
+
switchChain: switchExternalWalletChain,
|
|
576
914
|
// Connection status
|
|
577
915
|
isConnected: isExternalWalletConnected,
|
|
578
916
|
address: externalWalletAddress,
|
package/dist/src/index.d.ts
CHANGED
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
* when used in a React project
|
|
5
5
|
*/
|
|
6
6
|
export { AbstraxnProvider, useAbstraxnWallet } from './AbstraxnProvider';
|
|
7
|
-
export { useIsConnected, useAddress, useAuthContext, useChainId, useError, useEnableMfa, useDisableMfa, useEmailForOtp, useWallet, useExportWallet, useWhoami, useExternalWallet, useExternalWalletBalance, useExternalWalletChain, useExternalWalletInfo, usePublicClient, useWalletClient, useContract, usePrepareRawTxn, useSignTxn, useSignTypedTx, useSignAndSendTxn, useWaitForTxnReceipt, useReadContract, useExternalWalletClient, useWriteContract, useConnectionType, useSwitchChain, useSignMessage, useEstimateGas, useGetGasPrice, useSolanaConnection, useSolanaPublicKey, useSolanaBalance, usePrepareSolanaTxn, useSolanaExternalWallet, usePrepareSolanaProgramTxn, useSolanaProgramTransaction, useSignSolanaTxn, useSignAndSendSolanaTxn, useWaitForSolanaConfirmation, } from './hooks';
|
|
7
|
+
export { useIsConnected, useAddress, useAuthContext, useChainId, useError, useEnableMfa, useDisableMfa, useAuthMethodLinking, useEmailForOtp, useWallet, useSmartAccountOwner, useExportWallet, useWhoami, useExternalWallet, useExternalWalletBalance, useExternalWalletChain, useExternalWalletInfo, usePublicClient, useWalletClient, useContract, usePrepareRawTxn, useSignTxn, useSignTypedTx, useSignAndSendTxn, useWaitForTxnReceipt, useReadContract, useExternalWalletClient, useWriteContract, useConnectionType, useSwitchChain, useSignMessage, useEstimateGas, useGetGasPrice, useSolanaConnection, useSolanaPublicKey, useSolanaBalance, usePrepareSolanaTxn, useSolanaExternalWallet, usePrepareSolanaProgramTxn, useSolanaProgramTransaction, useSignSolanaTxn, useSignAndSendSolanaTxn, useWaitForSolanaConfirmation, } from './hooks';
|
|
8
8
|
export { ConnectButton } from './ConnectButton';
|
|
9
9
|
export type { ConnectButtonProps, ConnectButtonVariant, ConnectButtonSize } from './ConnectButton';
|
|
10
10
|
export { WalletModal } from './WalletModal';
|
|
11
11
|
export type { WalletModalProps } from './WalletModal';
|
|
12
12
|
export { OnboardingUIComponent as OnboardingUI } from './OnboardingUI';
|
|
13
13
|
export type { AbstraxnProviderConfig, AbstraxnUIConfig, AbstraxnContextValue, ChainConfig, } from './types';
|
|
14
|
-
export type { PayloadEncoding, HashFunction, SignTypedTxParams, SolanaAccountMetaInput, SolanaInstructionDataInput, } from './hooks';
|
|
14
|
+
export type { PayloadEncoding, HashFunction, SignTypedTxParams, SmartAccountOwnerOptions, SmartAccountOwnerResult, SolanaAccountMetaInput, SolanaInstructionDataInput, } from './hooks';
|
|
15
15
|
export type { OnboardingUIComponentProps, OnboardingUIComponentRef } from './OnboardingUI';
|
|
16
16
|
export { ALL_CHAINS, EVM_CHAINS, SOLANA_CHAINS, getChainById, getChainsByType, getDefaultChains, toCoreChain, type ChainData, } from './chains';
|
|
17
17
|
export { CONNECTORS, getConnectorMeta, isOAuthConnector, isWalletConnector, isAuthConnector, type ConnectorType, type ConnectorMeta, } from './connectors';
|
package/dist/src/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* when used in a React project
|
|
5
5
|
*/
|
|
6
6
|
export { AbstraxnProvider, useAbstraxnWallet } from './AbstraxnProvider';
|
|
7
|
-
export { useIsConnected, useAddress, useAuthContext, useChainId, useError, useEnableMfa, useDisableMfa, useEmailForOtp, useWallet, useExportWallet, useWhoami, useExternalWallet, useExternalWalletBalance, useExternalWalletChain, useExternalWalletInfo, usePublicClient, useWalletClient, useContract, usePrepareRawTxn, useSignTxn, useSignTypedTx, useSignAndSendTxn, useWaitForTxnReceipt, useReadContract, useExternalWalletClient, useWriteContract, useConnectionType, useSwitchChain, useSignMessage, useEstimateGas, useGetGasPrice, useSolanaConnection, useSolanaPublicKey, useSolanaBalance, usePrepareSolanaTxn, useSolanaExternalWallet, usePrepareSolanaProgramTxn, useSolanaProgramTransaction, useSignSolanaTxn, useSignAndSendSolanaTxn, useWaitForSolanaConfirmation, } from './hooks';
|
|
7
|
+
export { useIsConnected, useAddress, useAuthContext, useChainId, useError, useEnableMfa, useDisableMfa, useAuthMethodLinking, useEmailForOtp, useWallet, useSmartAccountOwner, useExportWallet, useWhoami, useExternalWallet, useExternalWalletBalance, useExternalWalletChain, useExternalWalletInfo, usePublicClient, useWalletClient, useContract, usePrepareRawTxn, useSignTxn, useSignTypedTx, useSignAndSendTxn, useWaitForTxnReceipt, useReadContract, useExternalWalletClient, useWriteContract, useConnectionType, useSwitchChain, useSignMessage, useEstimateGas, useGetGasPrice, useSolanaConnection, useSolanaPublicKey, useSolanaBalance, usePrepareSolanaTxn, useSolanaExternalWallet, usePrepareSolanaProgramTxn, useSolanaProgramTransaction, useSignSolanaTxn, useSignAndSendSolanaTxn, useWaitForSolanaConfirmation, } from './hooks';
|
|
8
8
|
export { ConnectButton } from './ConnectButton';
|
|
9
9
|
export { WalletModal } from './WalletModal';
|
|
10
10
|
export { OnboardingUIComponent as OnboardingUI } from './OnboardingUI';
|
package/dist/src/types.d.ts
CHANGED
|
@@ -273,7 +273,7 @@ export interface AbstraxnContextValue {
|
|
|
273
273
|
availableChains?: import("./chains").ChainData[];
|
|
274
274
|
walletBalance?: bigint | null;
|
|
275
275
|
/** Refetch wallet balance from RPC (Abstraxn or external). Call when UI screen changes (e.g. back button, modal open/close). */
|
|
276
|
-
refetchBalance?: () => void
|
|
276
|
+
refetchBalance?: () => Promise<void>;
|
|
277
277
|
connectionType?: string | null;
|
|
278
278
|
emailForOtp?: string;
|
|
279
279
|
setEmailForOtp?: (email: string) => void;
|
|
@@ -9,13 +9,7 @@ import { type Chain as CoreChain } from "@abstraxn/signer-core";
|
|
|
9
9
|
* Note: Uses 'injected' connector which automatically detects MetaMask and other wallets
|
|
10
10
|
* without requiring @metamask/sdk
|
|
11
11
|
*/
|
|
12
|
-
export declare function createWagmiConfig(chains?: CoreChain[] | Chain[], walletConnectProjectId?: string, enabledConnectors?: ("injected" | "metaMask" | "walletConnect")[], theme?: "light" | "dark", ssr?: boolean
|
|
13
|
-
/**
|
|
14
|
-
* When true, builds a wagmi config with **no** wallet connectors. Used when
|
|
15
|
-
* `externalWallets.enabled` is false so hooks like `useConfig` / `useAccount`
|
|
16
|
-
* still work for embedded flows without exposing MetaMask / WalletConnect.
|
|
17
|
-
*/
|
|
18
|
-
embedOnly?: boolean): Config;
|
|
12
|
+
export declare function createWagmiConfig(chains?: CoreChain[] | Chain[], walletConnectProjectId?: string, enabledConnectors?: ("injected" | "metaMask" | "walletConnect")[], theme?: "light" | "dark", ssr?: boolean): Config;
|
|
19
13
|
/**
|
|
20
14
|
* External wallet connector types
|
|
21
15
|
*/
|
package/dist/src/wagmiConfig.js
CHANGED
|
@@ -35,13 +35,7 @@ function convertToViemChain(chain) {
|
|
|
35
35
|
* Note: Uses 'injected' connector which automatically detects MetaMask and other wallets
|
|
36
36
|
* without requiring @metamask/sdk
|
|
37
37
|
*/
|
|
38
|
-
export function createWagmiConfig(chains, walletConnectProjectId, enabledConnectors, theme, ssr
|
|
39
|
-
/**
|
|
40
|
-
* When true, builds a wagmi config with **no** wallet connectors. Used when
|
|
41
|
-
* `externalWallets.enabled` is false so hooks like `useConfig` / `useAccount`
|
|
42
|
-
* still work for embedded flows without exposing MetaMask / WalletConnect.
|
|
43
|
-
*/
|
|
44
|
-
embedOnly) {
|
|
38
|
+
export function createWagmiConfig(chains, walletConnectProjectId, enabledConnectors, theme, ssr) {
|
|
45
39
|
// Normalize chains to ensure they are all valid viem Chain objects
|
|
46
40
|
// This handles mixed arrays of viem Chains and CoreChains (e.g. custom chains)
|
|
47
41
|
const viemChains = chains && chains.length > 0
|
|
@@ -54,28 +48,6 @@ embedOnly) {
|
|
|
54
48
|
return convertToViemChain(chain);
|
|
55
49
|
})
|
|
56
50
|
: SUPPORTED_CHAINS.map(convertToViemChain);
|
|
57
|
-
// Ensure we have at least one chain (shared by embed + full config)
|
|
58
|
-
if (viemChains.length === 0) {
|
|
59
|
-
throw new Error("At least one chain is required");
|
|
60
|
-
}
|
|
61
|
-
const transports = viemChains.reduce((acc, chain) => {
|
|
62
|
-
acc[chain.id] = http();
|
|
63
|
-
return acc;
|
|
64
|
-
}, {});
|
|
65
|
-
const storage = ssr
|
|
66
|
-
? createStorage({ storage: cookieStorage })
|
|
67
|
-
: typeof window !== "undefined"
|
|
68
|
-
? createStorage({ storage: window.localStorage })
|
|
69
|
-
: undefined;
|
|
70
|
-
if (embedOnly) {
|
|
71
|
-
return createConfig({
|
|
72
|
-
chains: viemChains,
|
|
73
|
-
connectors: [],
|
|
74
|
-
transports,
|
|
75
|
-
storage,
|
|
76
|
-
ssr: !!ssr,
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
51
|
const connectors = [];
|
|
80
52
|
// Add connectors based on enabled list
|
|
81
53
|
// Note: 'injected' connector will automatically detect MetaMask and other injected wallets
|
|
@@ -123,11 +95,23 @@ embedOnly) {
|
|
|
123
95
|
}));
|
|
124
96
|
}
|
|
125
97
|
}
|
|
98
|
+
// Ensure we have at least one chain
|
|
99
|
+
if (viemChains.length === 0) {
|
|
100
|
+
throw new Error("At least one chain is required");
|
|
101
|
+
}
|
|
126
102
|
return createConfig({
|
|
127
103
|
chains: viemChains,
|
|
128
104
|
connectors,
|
|
129
|
-
transports,
|
|
130
|
-
|
|
105
|
+
transports: viemChains.reduce((acc, chain) => {
|
|
106
|
+
acc[chain.id] = http();
|
|
107
|
+
return acc;
|
|
108
|
+
}, {}),
|
|
109
|
+
// Configure storage based on SSR setting
|
|
110
|
+
storage: ssr
|
|
111
|
+
? createStorage({ storage: cookieStorage })
|
|
112
|
+
: typeof window !== "undefined"
|
|
113
|
+
? createStorage({ storage: window.localStorage })
|
|
114
|
+
: undefined,
|
|
131
115
|
ssr: !!ssr,
|
|
132
116
|
});
|
|
133
117
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abstraxn/signer-react",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "React SDK for Abstraxn Wallet - React components, hooks, and providers for seamless Web3 wallet integration",
|
|
5
5
|
"main": "./dist/src/index.js",
|
|
6
6
|
"module": "./dist/src/index.js",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"access": "public"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@abstraxn/signer-core": "
|
|
43
|
+
"@abstraxn/signer-core": "2.1.2",
|
|
44
44
|
"@solana/wallet-adapter-base": "^0.9.27",
|
|
45
45
|
"@solana/wallet-adapter-react": "^0.15.39",
|
|
46
46
|
"@solana/wallet-adapter-react-ui": "^0.9.39",
|