signer-test-sdk-react 0.0.23 → 0.0.24
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 -0
- package/README.md +4 -0
- package/dist/src/OnboardingUI.d.ts +1 -1
- package/dist/src/chains.d.ts +1 -1
- package/dist/src/components/AbstraxnProvider/AbstraxnProvider.js.map +1 -1
- package/dist/src/components/AbstraxnProvider/AbstraxnProviderInner.js +1 -1
- package/dist/src/components/AbstraxnProvider/AbstraxnProviderInner.js.map +1 -1
- package/dist/src/components/AbstraxnProvider/useAbstraxnProviderBase.d.ts +2 -2
- package/dist/src/components/AbstraxnProvider/useOAuthCallbacks.d.ts +1 -1
- package/dist/src/components/AbstraxnProvider/useWalletInitialization.d.ts +1 -1
- package/dist/src/components/AbstraxnProvider/useWalletInitialization.js +1 -1
- package/dist/src/components/AbstraxnProvider/useWalletInitialization.js.map +1 -1
- package/dist/src/components/OnboardingUI/OnboardingUIReact.d.ts +1 -1
- package/dist/src/components/OnboardingUI/OnboardingUIWeb.d.ts +1 -1
- package/dist/src/components/OnboardingUI/OnboardingUIWeb.js +1 -1
- package/dist/src/components/OnboardingUI/OnboardingUIWeb.js.map +1 -1
- package/dist/src/components/OnboardingUI/components/EmailForm.d.ts +1 -1
- package/dist/src/components/OnboardingUI/components/EmailForm.js +1 -1
- package/dist/src/components/OnboardingUI/components/EmailForm.js.map +1 -1
- package/dist/src/components/OnboardingUI/components/OtpForm.d.ts +1 -1
- package/dist/src/components/OnboardingUI/components/PasskeyButton.d.ts +1 -1
- package/dist/src/components/OnboardingUI/components/SocialButtons.d.ts +1 -1
- package/dist/src/components/OnboardingUI/hooks/useAuthMethods.d.ts +1 -1
- package/dist/src/components/OnboardingUI/hooks/useOnboarding.d.ts +1 -1
- package/dist/src/components/OnboardingUI/index.d.ts +1 -1
- package/dist/src/components/WalletModal/components/UserAvatar.d.ts +1 -1
- package/dist/src/components/WalletModal/hooks/useSendTransaction.d.ts +1 -1
- package/dist/src/hooks.d.ts +104 -36
- package/dist/src/hooks.js +334 -121
- package/dist/src/hooks.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/types.d.ts +6 -6
- package/dist/src/wagmiConfig.d.ts +1 -1
- package/dist/src/wagmiConfig.js +1 -1
- package/dist/src/wagmiConfig.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -4
package/dist/src/hooks.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { useState, useCallback, useEffect, useMemo } from 'react';
|
|
5
5
|
import { useAbstraxnWallet } from './AbstraxnProvider';
|
|
6
|
-
import { createPublicClient, createWalletClient, http, getContract, serializeTransaction,
|
|
6
|
+
import { createPublicClient, createWalletClient, http, getContract, serializeTransaction, encodeFunctionData } from 'viem';
|
|
7
7
|
import { useWalletClient as useWagmiWalletClient, useAccount, useConfig, useChainId as useWagmiChainId, useSwitchChain as useWagmiSwitchChain, useSignMessage as useWagmiSignMessage } from 'wagmi';
|
|
8
8
|
import { getWalletClient, switchChain } from '@wagmi/core';
|
|
9
9
|
import { getConnectorMeta } from './connectors';
|
|
@@ -307,7 +307,7 @@ export function useExternalWalletInfo() {
|
|
|
307
307
|
*
|
|
308
308
|
* @example
|
|
309
309
|
* ```tsx
|
|
310
|
-
* import { usePublicClient } from 'signer-
|
|
310
|
+
* import { usePublicClient } from '@abstraxn/signer-react';
|
|
311
311
|
* import { polygonAmoy } from 'viem/chains';
|
|
312
312
|
*
|
|
313
313
|
* function MyComponent() {
|
|
@@ -350,7 +350,7 @@ export function usePublicClient(chain, rpcUrl) {
|
|
|
350
350
|
*
|
|
351
351
|
* @example
|
|
352
352
|
* ```tsx
|
|
353
|
-
* import { useWalletClient } from 'signer-
|
|
353
|
+
* import { useWalletClient } from '@abstraxn/signer-react';
|
|
354
354
|
* import { polygonAmoy } from 'viem/chains';
|
|
355
355
|
*
|
|
356
356
|
* function MyComponent() {
|
|
@@ -406,7 +406,7 @@ export function useWalletClient(chain, rpcUrl) {
|
|
|
406
406
|
*
|
|
407
407
|
* @example
|
|
408
408
|
* ```tsx
|
|
409
|
-
* import { useContract, usePublicClient } from 'signer-
|
|
409
|
+
* import { useContract, usePublicClient } from '@abstraxn/signer-react';
|
|
410
410
|
* import { polygonAmoy } from 'viem/chains';
|
|
411
411
|
* import erc20Abi from './erc20Abi.json';
|
|
412
412
|
*
|
|
@@ -510,21 +510,11 @@ export function usePrepareRawTxn(provider) {
|
|
|
510
510
|
// Determine if this is a native transfer
|
|
511
511
|
const isNativeTransfer = !needsEncoding && !hasPreEncodedData;
|
|
512
512
|
if (isNativeTransfer) {
|
|
513
|
-
// Native transfer:
|
|
514
|
-
if (
|
|
513
|
+
// Native transfer: pass value through as-is (no hex conversion)
|
|
514
|
+
if (value === undefined || value === null || value === '' || value === '0' || value === 0) {
|
|
515
515
|
throw new Error('Value is required for native transfer');
|
|
516
516
|
}
|
|
517
|
-
|
|
518
|
-
const valueStr = typeof value === 'string' ? value.trim() : String(value);
|
|
519
|
-
let valueInWei;
|
|
520
|
-
try {
|
|
521
|
-
valueInWei = parseEther(valueStr);
|
|
522
|
-
}
|
|
523
|
-
catch (error) {
|
|
524
|
-
throw new Error(`Invalid value format: "${valueStr}". Value must be a valid number string (e.g., "0.001").`);
|
|
525
|
-
}
|
|
526
|
-
// Convert to hex string
|
|
527
|
-
finalValue = `0x${valueInWei.toString(16)}`;
|
|
517
|
+
finalValue = typeof value === 'bigint' ? value : (typeof value === 'string' ? value.trim() : String(value));
|
|
528
518
|
finalData = '0x';
|
|
529
519
|
}
|
|
530
520
|
else {
|
|
@@ -537,36 +527,8 @@ export function usePrepareRawTxn(provider) {
|
|
|
537
527
|
if (!functionName) {
|
|
538
528
|
throw new Error('Function name is required for encoding function data');
|
|
539
529
|
}
|
|
540
|
-
//
|
|
541
|
-
const processedArgs =
|
|
542
|
-
// Check if this is likely an amount parameter for transfer/transferFrom functions
|
|
543
|
-
const isAmountParam = (functionName === 'transfer' || functionName === 'transferFrom') && index === 1;
|
|
544
|
-
if (isAmountParam) {
|
|
545
|
-
// If arg is a string or number that looks like ETH (has decimal point)
|
|
546
|
-
if (typeof arg === 'string' && arg.includes('.')) {
|
|
547
|
-
try {
|
|
548
|
-
// Convert ETH to wei
|
|
549
|
-
const weiAmount = parseEther(arg);
|
|
550
|
-
return weiAmount.toString();
|
|
551
|
-
}
|
|
552
|
-
catch (error) {
|
|
553
|
-
throw new Error(`Failed to convert amount "${arg}" to wei. Make sure it's a valid number string (e.g., "0.001").`);
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
else if (typeof arg === 'number' && arg % 1 !== 0) {
|
|
557
|
-
// Number with decimal places - convert to wei
|
|
558
|
-
try {
|
|
559
|
-
const weiAmount = parseEther(arg.toString());
|
|
560
|
-
return weiAmount.toString();
|
|
561
|
-
}
|
|
562
|
-
catch (error) {
|
|
563
|
-
throw new Error(`Failed to convert amount ${arg} to wei. Make sure it's a valid number.`);
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
// For other args, just return as-is
|
|
568
|
-
return arg;
|
|
569
|
-
});
|
|
530
|
+
// Pass args through as-is (no conversion); caller must pass amounts in wei / correct format
|
|
531
|
+
const processedArgs = args ?? [];
|
|
570
532
|
try {
|
|
571
533
|
finalData = encodeFunctionData({
|
|
572
534
|
abi: abi,
|
|
@@ -588,18 +550,9 @@ export function usePrepareRawTxn(provider) {
|
|
|
588
550
|
else {
|
|
589
551
|
throw new Error('Either provide encoded data, or provide abi/functionName/args for encoding.');
|
|
590
552
|
}
|
|
591
|
-
// Handle value for contract calls
|
|
553
|
+
// Handle value for contract calls: pass through as-is (no hex conversion)
|
|
592
554
|
if (value && value !== '0' && value !== 0) {
|
|
593
|
-
|
|
594
|
-
const valueStr = typeof value === 'string' ? value.trim() : String(value);
|
|
595
|
-
let valueInWei;
|
|
596
|
-
try {
|
|
597
|
-
valueInWei = parseEther(valueStr);
|
|
598
|
-
}
|
|
599
|
-
catch (error) {
|
|
600
|
-
throw new Error(`Invalid value format: "${valueStr}". Value must be a valid number string (e.g., "0.001").`);
|
|
601
|
-
}
|
|
602
|
-
finalValue = `0x${valueInWei.toString(16)}`;
|
|
555
|
+
finalValue = typeof value === 'bigint' ? value : (typeof value === 'string' ? value.trim() : String(value));
|
|
603
556
|
}
|
|
604
557
|
else {
|
|
605
558
|
finalValue = '0x0';
|
|
@@ -626,22 +579,108 @@ export function usePrepareRawTxn(provider) {
|
|
|
626
579
|
* const { signTxn } = useSignTxn(publicClient);
|
|
627
580
|
*
|
|
628
581
|
* // Prepare transaction
|
|
629
|
-
* const rawTx = await prepareRawTxn({
|
|
630
|
-
*
|
|
631
|
-
*
|
|
632
|
-
*
|
|
633
|
-
*
|
|
634
|
-
*
|
|
635
|
-
* // Sign transaction
|
|
582
|
+
* const rawTx = await prepareRawTxn({ from: address!, to: '0x...', value: '0.001' });
|
|
583
|
+
* const { estimateGas } = useEstimateGas(publicClient);
|
|
584
|
+
* const { getGasPrice } = useGetGasPrice(publicClient);
|
|
585
|
+
* const { gasLimit } = await estimateGas({ account: address!, to: rawTx.to, data: rawTx.data, value: rawTx.value });
|
|
586
|
+
* const fees = await getGasPrice();
|
|
636
587
|
* const signedTx = await signTxn({
|
|
637
588
|
* from: address!,
|
|
638
|
-
* ...rawTx,
|
|
589
|
+
* ...rawTx,
|
|
590
|
+
* gas: { gasLimit, maxFeePerGas: fees.maxFeePerGas!, maxPriorityFeePerGas: fees.maxPriorityFeePerGas! },
|
|
639
591
|
* });
|
|
640
592
|
* ```
|
|
641
593
|
*/
|
|
594
|
+
// export function useSignTxn(provider: PublicClient) {
|
|
595
|
+
// const { wallet, isConnected, address, signTransactionViaAPI } = useAbstraxnWallet();
|
|
596
|
+
// const signTxn = useCallback(async ({
|
|
597
|
+
// from,
|
|
598
|
+
// to,
|
|
599
|
+
// value,
|
|
600
|
+
// data,
|
|
601
|
+
// chainId,
|
|
602
|
+
// gas,
|
|
603
|
+
// }: {
|
|
604
|
+
// from: Address;
|
|
605
|
+
// to: Address;
|
|
606
|
+
// value: string | bigint;
|
|
607
|
+
// data: `0x${string}`;
|
|
608
|
+
// chainId?: number;
|
|
609
|
+
// /** Gas: pass gasLimit + (maxFeePerGas & maxPriorityFeePerGas for EIP-1559) or (gasPrice for legacy). Use useEstimateGas and useGetGasPrice. */
|
|
610
|
+
// gas: {
|
|
611
|
+
// gasLimit: bigint;
|
|
612
|
+
// gasPrice?: bigint;
|
|
613
|
+
// maxFeePerGas?: bigint;
|
|
614
|
+
// maxPriorityFeePerGas?: bigint;
|
|
615
|
+
// };
|
|
616
|
+
// }) => {
|
|
617
|
+
// if (!isConnected || !wallet) {
|
|
618
|
+
// throw new Error('Wallet is not connected');
|
|
619
|
+
// }
|
|
620
|
+
// if (!provider) {
|
|
621
|
+
// throw new Error('Provider (publicClient) is required');
|
|
622
|
+
// }
|
|
623
|
+
// if (!from) {
|
|
624
|
+
// throw new Error('From address is required');
|
|
625
|
+
// }
|
|
626
|
+
// if (!to) {
|
|
627
|
+
// throw new Error('To address is required');
|
|
628
|
+
// }
|
|
629
|
+
// if (gas.gasLimit === undefined) {
|
|
630
|
+
// throw new Error('gas.gasLimit is required. Use useEstimateGas to get values.');
|
|
631
|
+
// }
|
|
632
|
+
// const isLegacy = gas.gasPrice !== undefined;
|
|
633
|
+
// if (!isLegacy) {
|
|
634
|
+
// if (gas.maxFeePerGas === undefined || gas.maxPriorityFeePerGas === undefined) {
|
|
635
|
+
// throw new Error('gas.maxFeePerGas and gas.maxPriorityFeePerGas are required for EIP-1559, or pass gas.gasPrice for legacy.');
|
|
636
|
+
// }
|
|
637
|
+
// }
|
|
638
|
+
// // Get chain ID from provider or use provided one
|
|
639
|
+
// const targetChainId = chainId || provider.chain?.id;
|
|
640
|
+
// if (!targetChainId) {
|
|
641
|
+
// throw new Error('Chain ID is required. Either provide it or ensure provider has a chain configured.');
|
|
642
|
+
// }
|
|
643
|
+
// // Get nonce
|
|
644
|
+
// const nonce = await provider.getTransactionCount({ address: from });
|
|
645
|
+
// // Value in wei (pass-through from prepareRawTxn, no hex conversion)
|
|
646
|
+
// const valueInWei = typeof value === 'bigint' ? value : BigInt(value === '0x' || value === '' ? '0' : value);
|
|
647
|
+
// // Build unsigned tx from user gas (no estimation in hook)
|
|
648
|
+
// const unsignedTx = isLegacy
|
|
649
|
+
// ? {
|
|
650
|
+
// chainId: targetChainId,
|
|
651
|
+
// from,
|
|
652
|
+
// to,
|
|
653
|
+
// data,
|
|
654
|
+
// value: valueInWei,
|
|
655
|
+
// nonce,
|
|
656
|
+
// gas: gas.gasLimit,
|
|
657
|
+
// gasPrice: gas.gasPrice,
|
|
658
|
+
// }
|
|
659
|
+
// : {
|
|
660
|
+
// chainId: targetChainId,
|
|
661
|
+
// from,
|
|
662
|
+
// to,
|
|
663
|
+
// data,
|
|
664
|
+
// value: valueInWei,
|
|
665
|
+
// nonce,
|
|
666
|
+
// gas: gas.gasLimit,
|
|
667
|
+
// maxFeePerGas: gas.maxFeePerGas!,
|
|
668
|
+
// maxPriorityFeePerGas: gas.maxPriorityFeePerGas!,
|
|
669
|
+
// };
|
|
670
|
+
// // Serialize transaction
|
|
671
|
+
// const serializedTx = serializeTransaction(unsignedTx);
|
|
672
|
+
// // Sign transaction via Turnkey API
|
|
673
|
+
// const signResult = await signTransactionViaAPI(serializedTx, from);
|
|
674
|
+
// return {
|
|
675
|
+
// unsignedTransaction: serializedTx,
|
|
676
|
+
// signedTransaction: signResult.signedTransaction,
|
|
677
|
+
// };
|
|
678
|
+
// }, [provider, isConnected, wallet, address, signTransactionViaAPI]);
|
|
679
|
+
// return { signTxn, isConnected, address };
|
|
680
|
+
// }
|
|
642
681
|
export function useSignTxn(provider) {
|
|
643
682
|
const { wallet, isConnected, address, signTransactionViaAPI } = useAbstraxnWallet();
|
|
644
|
-
const signTxn = useCallback(async ({ from, to, value, data, chainId, }) => {
|
|
683
|
+
const signTxn = useCallback(async ({ from, to, value, data, chainId, gas, }) => {
|
|
645
684
|
if (!isConnected || !wallet) {
|
|
646
685
|
throw new Error('Wallet is not connected');
|
|
647
686
|
}
|
|
@@ -661,32 +700,31 @@ export function useSignTxn(provider) {
|
|
|
661
700
|
}
|
|
662
701
|
// Get nonce
|
|
663
702
|
const nonce = await provider.getTransactionCount({ address: from });
|
|
664
|
-
//
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
const
|
|
668
|
-
// Estimate gas
|
|
669
|
-
const gas = await provider.estimateGas({
|
|
670
|
-
account: from,
|
|
671
|
-
to,
|
|
672
|
-
data,
|
|
673
|
-
value: valueInWei,
|
|
674
|
-
});
|
|
675
|
-
// Estimate fees
|
|
676
|
-
const fee = await provider.estimateFeesPerGas();
|
|
677
|
-
// Create unsigned transaction
|
|
678
|
-
const unsignedTx = {
|
|
703
|
+
// Value in wei (pass-through from prepareRawTxn, no hex conversion)
|
|
704
|
+
const valueInWei = typeof value === 'bigint' ? value : BigInt(value === '0x' || value === '' ? '0' : value);
|
|
705
|
+
// Build base transaction object
|
|
706
|
+
const baseTx = {
|
|
679
707
|
chainId: targetChainId,
|
|
680
708
|
from,
|
|
681
709
|
to,
|
|
682
710
|
data,
|
|
683
711
|
value: valueInWei,
|
|
684
712
|
nonce,
|
|
685
|
-
gas,
|
|
686
|
-
maxFeePerGas: fee.maxFeePerGas,
|
|
687
|
-
maxPriorityFeePerGas: fee.maxPriorityFeePerGas,
|
|
688
|
-
type: 'eip1559',
|
|
689
713
|
};
|
|
714
|
+
// Add gas properties if they exist
|
|
715
|
+
const unsignedTx = { ...baseTx };
|
|
716
|
+
if (gas?.gasLimit !== undefined) {
|
|
717
|
+
unsignedTx.gas = gas.gasLimit;
|
|
718
|
+
}
|
|
719
|
+
if (gas?.gasPrice !== undefined) {
|
|
720
|
+
unsignedTx.gasPrice = gas.gasPrice;
|
|
721
|
+
}
|
|
722
|
+
if (gas?.maxFeePerGas !== undefined) {
|
|
723
|
+
unsignedTx.maxFeePerGas = gas.maxFeePerGas;
|
|
724
|
+
}
|
|
725
|
+
if (gas?.maxPriorityFeePerGas !== undefined) {
|
|
726
|
+
unsignedTx.maxPriorityFeePerGas = gas.maxPriorityFeePerGas;
|
|
727
|
+
}
|
|
690
728
|
// Serialize transaction
|
|
691
729
|
const serializedTx = serializeTransaction(unsignedTx);
|
|
692
730
|
// Sign transaction via Turnkey API
|
|
@@ -711,24 +749,114 @@ export function useSignTxn(provider) {
|
|
|
711
749
|
* const { signAndSendTxn } = useSignAndSendTxn(publicClient);
|
|
712
750
|
*
|
|
713
751
|
* // Prepare transaction
|
|
714
|
-
* const rawTx = await prepareRawTxn({
|
|
715
|
-
*
|
|
716
|
-
*
|
|
717
|
-
*
|
|
718
|
-
*
|
|
719
|
-
*
|
|
720
|
-
* // Sign and send transaction
|
|
752
|
+
* const rawTx = await prepareRawTxn({ from: address!, to: '0x...', value: '0.001' });
|
|
753
|
+
* const { estimateGas } = useEstimateGas(publicClient);
|
|
754
|
+
* const { getGasPrice } = useGetGasPrice(publicClient);
|
|
755
|
+
* const { gasLimit } = await estimateGas({ account: address!, to: rawTx.to, data: rawTx.data, value: rawTx.value });
|
|
756
|
+
* const fees = await getGasPrice();
|
|
721
757
|
* const result = await signAndSendTxn({
|
|
722
758
|
* from: address!,
|
|
723
|
-
* ...rawTx,
|
|
759
|
+
* ...rawTx,
|
|
760
|
+
* gas: { gasLimit, maxFeePerGas: fees.maxFeePerGas!, maxPriorityFeePerGas: fees.maxPriorityFeePerGas! },
|
|
724
761
|
* });
|
|
725
|
-
*
|
|
726
762
|
* console.log('Transaction hash:', result.hash);
|
|
727
763
|
* ```
|
|
728
764
|
*/
|
|
765
|
+
// export function useSignAndSendTxn(provider: PublicClient) {
|
|
766
|
+
// const { wallet, isConnected, address, signTransactionViaAPI } = useAbstraxnWallet();
|
|
767
|
+
// const signAndSendTxn = useCallback(async ({
|
|
768
|
+
// from,
|
|
769
|
+
// to,
|
|
770
|
+
// value,
|
|
771
|
+
// data,
|
|
772
|
+
// chainId,
|
|
773
|
+
// gas,
|
|
774
|
+
// }: {
|
|
775
|
+
// from: Address;
|
|
776
|
+
// to: Address;
|
|
777
|
+
// value: string | bigint;
|
|
778
|
+
// data: `0x${string}`;
|
|
779
|
+
// chainId?: number;
|
|
780
|
+
// /** Gas: pass gasLimit + (maxFeePerGas & maxPriorityFeePerGas for EIP-1559) or (gasPrice for legacy). Use useEstimateGas and useGetGasPrice. */
|
|
781
|
+
// gas: {
|
|
782
|
+
// gasLimit: bigint;
|
|
783
|
+
// gasPrice?: bigint;
|
|
784
|
+
// maxFeePerGas?: bigint;
|
|
785
|
+
// maxPriorityFeePerGas?: bigint;
|
|
786
|
+
// };
|
|
787
|
+
// }) => {
|
|
788
|
+
// if (!isConnected || !wallet) {
|
|
789
|
+
// throw new Error('Wallet is not connected');
|
|
790
|
+
// }
|
|
791
|
+
// if (!provider) {
|
|
792
|
+
// throw new Error('Provider (publicClient) is required');
|
|
793
|
+
// }
|
|
794
|
+
// if (!from) {
|
|
795
|
+
// throw new Error('From address is required');
|
|
796
|
+
// }
|
|
797
|
+
// if (!to) {
|
|
798
|
+
// throw new Error('To address is required');
|
|
799
|
+
// }
|
|
800
|
+
// if (gas.gasLimit === undefined) {
|
|
801
|
+
// throw new Error('gas.gasLimit is required. Use useEstimateGas to get values.');
|
|
802
|
+
// }
|
|
803
|
+
// const isLegacy = gas.gasPrice !== undefined;
|
|
804
|
+
// if (!isLegacy) {
|
|
805
|
+
// if (gas.maxFeePerGas === undefined || gas.maxPriorityFeePerGas === undefined) {
|
|
806
|
+
// throw new Error('gas.maxFeePerGas and gas.maxPriorityFeePerGas are required for EIP-1559, or pass gas.gasPrice for legacy.');
|
|
807
|
+
// }
|
|
808
|
+
// }
|
|
809
|
+
// // Get chain ID from provider or use provided one
|
|
810
|
+
// const targetChainId = chainId || provider.chain?.id;
|
|
811
|
+
// if (!targetChainId) {
|
|
812
|
+
// throw new Error('Chain ID is required. Either provide it or ensure provider has a chain configured.');
|
|
813
|
+
// }
|
|
814
|
+
// // Get nonce
|
|
815
|
+
// const nonce = await provider.getTransactionCount({ address: from });
|
|
816
|
+
// // Value in wei (pass-through from prepareRawTxn, no hex conversion)
|
|
817
|
+
// const valueInWei = typeof value === 'bigint' ? value : BigInt(value === '0x' || value === '' ? '0' : value);
|
|
818
|
+
// // Build unsigned tx from user gas (no estimation in hook)
|
|
819
|
+
// const unsignedTx = isLegacy
|
|
820
|
+
// ? {
|
|
821
|
+
// chainId: targetChainId,
|
|
822
|
+
// from,
|
|
823
|
+
// to,
|
|
824
|
+
// data,
|
|
825
|
+
// value: valueInWei,
|
|
826
|
+
// nonce,
|
|
827
|
+
// gas: gas.gasLimit,
|
|
828
|
+
// gasPrice: gas.gasPrice,
|
|
829
|
+
// }
|
|
830
|
+
// : {
|
|
831
|
+
// chainId: targetChainId,
|
|
832
|
+
// from,
|
|
833
|
+
// to,
|
|
834
|
+
// data,
|
|
835
|
+
// value: valueInWei,
|
|
836
|
+
// nonce,
|
|
837
|
+
// gas: gas.gasLimit,
|
|
838
|
+
// maxFeePerGas: gas.maxFeePerGas!,
|
|
839
|
+
// maxPriorityFeePerGas: gas.maxPriorityFeePerGas!,
|
|
840
|
+
// };
|
|
841
|
+
// // Serialize transaction
|
|
842
|
+
// const serializedTx = serializeTransaction(unsignedTx);
|
|
843
|
+
// // Sign transaction via Turnkey API
|
|
844
|
+
// const signResult = await signTransactionViaAPI(serializedTx, from);
|
|
845
|
+
// // Send the signed transaction
|
|
846
|
+
// const hash = await provider.sendRawTransaction({
|
|
847
|
+
// serializedTransaction: signResult.signedTransaction as `0x${string}`,
|
|
848
|
+
// });
|
|
849
|
+
// return {
|
|
850
|
+
// hash,
|
|
851
|
+
// unsignedTransaction: serializedTx,
|
|
852
|
+
// signedTransaction: signResult.signedTransaction,
|
|
853
|
+
// };
|
|
854
|
+
// }, [provider, isConnected, wallet, address, signTransactionViaAPI]);
|
|
855
|
+
// return { signAndSendTxn, isConnected, address };
|
|
856
|
+
// }
|
|
729
857
|
export function useSignAndSendTxn(provider) {
|
|
730
858
|
const { wallet, isConnected, address, signTransactionViaAPI } = useAbstraxnWallet();
|
|
731
|
-
const signAndSendTxn = useCallback(async ({ from, to, value, data, chainId, }) => {
|
|
859
|
+
const signAndSendTxn = useCallback(async ({ from, to, value, data, chainId, gas, }) => {
|
|
732
860
|
if (!isConnected || !wallet) {
|
|
733
861
|
throw new Error('Wallet is not connected');
|
|
734
862
|
}
|
|
@@ -748,32 +876,31 @@ export function useSignAndSendTxn(provider) {
|
|
|
748
876
|
}
|
|
749
877
|
// Get nonce
|
|
750
878
|
const nonce = await provider.getTransactionCount({ address: from });
|
|
751
|
-
//
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
const
|
|
755
|
-
// Estimate gas
|
|
756
|
-
const gas = await provider.estimateGas({
|
|
757
|
-
account: from,
|
|
758
|
-
to,
|
|
759
|
-
data,
|
|
760
|
-
value: valueInWei,
|
|
761
|
-
});
|
|
762
|
-
// Estimate fees
|
|
763
|
-
const fee = await provider.estimateFeesPerGas();
|
|
764
|
-
// Create unsigned transaction
|
|
765
|
-
const unsignedTx = {
|
|
879
|
+
// Value in wei (pass-through from prepareRawTxn, no hex conversion)
|
|
880
|
+
const valueInWei = typeof value === 'bigint' ? value : BigInt(value === '0x' || value === '' ? '0' : value);
|
|
881
|
+
// Build base transaction object
|
|
882
|
+
const baseTx = {
|
|
766
883
|
chainId: targetChainId,
|
|
767
884
|
from,
|
|
768
885
|
to,
|
|
769
886
|
data,
|
|
770
887
|
value: valueInWei,
|
|
771
888
|
nonce,
|
|
772
|
-
gas,
|
|
773
|
-
maxFeePerGas: fee.maxFeePerGas,
|
|
774
|
-
maxPriorityFeePerGas: fee.maxPriorityFeePerGas,
|
|
775
|
-
type: 'eip1559',
|
|
776
889
|
};
|
|
890
|
+
// Add gas properties if they exist
|
|
891
|
+
const unsignedTx = { ...baseTx };
|
|
892
|
+
if (gas?.gasLimit !== undefined) {
|
|
893
|
+
unsignedTx.gas = gas.gasLimit;
|
|
894
|
+
}
|
|
895
|
+
if (gas?.gasPrice !== undefined) {
|
|
896
|
+
unsignedTx.gasPrice = gas.gasPrice;
|
|
897
|
+
}
|
|
898
|
+
if (gas?.maxFeePerGas !== undefined) {
|
|
899
|
+
unsignedTx.maxFeePerGas = gas.maxFeePerGas;
|
|
900
|
+
}
|
|
901
|
+
if (gas?.maxPriorityFeePerGas !== undefined) {
|
|
902
|
+
unsignedTx.maxPriorityFeePerGas = gas.maxPriorityFeePerGas;
|
|
903
|
+
}
|
|
777
904
|
// Serialize transaction
|
|
778
905
|
const serializedTx = serializeTransaction(unsignedTx);
|
|
779
906
|
// Sign transaction via Turnkey API
|
|
@@ -843,6 +970,87 @@ export function useWaitForTxnReceipt(provider) {
|
|
|
843
970
|
}, [provider]);
|
|
844
971
|
return { waitForTxnReceipt };
|
|
845
972
|
}
|
|
973
|
+
/**
|
|
974
|
+
* Hook to estimate gas for a transaction
|
|
975
|
+
* Returns gasLimit to pass as gas.gasLimit to useSignTxn / useSignAndSendTxn (use useGetGasPrice for fees; no estimation inside those hooks).
|
|
976
|
+
*
|
|
977
|
+
* @param provider - PublicClient instance (can be created using usePublicClient hook)
|
|
978
|
+
* @returns Object with estimateGas function
|
|
979
|
+
*
|
|
980
|
+
* @example
|
|
981
|
+
* ```tsx
|
|
982
|
+
* const { estimateGas } = useEstimateGas(publicClient);
|
|
983
|
+
* const result = await estimateGas({
|
|
984
|
+
* account: address!,
|
|
985
|
+
* to: rawTx.to,
|
|
986
|
+
* data: rawTx.data,
|
|
987
|
+
* value: rawTx.value,
|
|
988
|
+
* });
|
|
989
|
+
* // gas: { gasLimit: result.gasLimit }
|
|
990
|
+
* ```
|
|
991
|
+
*/
|
|
992
|
+
export function useEstimateGas(provider) {
|
|
993
|
+
const estimateGas = useCallback(async ({ account, to, data = '0x', value = 0n, }) => {
|
|
994
|
+
if (!provider) {
|
|
995
|
+
throw new Error('Provider (publicClient) is required');
|
|
996
|
+
}
|
|
997
|
+
if (!account) {
|
|
998
|
+
throw new Error('Account (from) is required');
|
|
999
|
+
}
|
|
1000
|
+
if (!to) {
|
|
1001
|
+
throw new Error('To address is required');
|
|
1002
|
+
}
|
|
1003
|
+
const valueInWei = typeof value === 'bigint' ? value : (value === undefined || value === '' || value === '0x' ? 0n : BigInt(value));
|
|
1004
|
+
const gasLimit = await provider.estimateGas({
|
|
1005
|
+
account,
|
|
1006
|
+
to,
|
|
1007
|
+
data: data ?? '0x',
|
|
1008
|
+
value: valueInWei,
|
|
1009
|
+
});
|
|
1010
|
+
return { gasLimit };
|
|
1011
|
+
}, [provider]);
|
|
1012
|
+
return { estimateGas };
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* Hook to get current gas price / EIP-1559 fees from the chain.
|
|
1016
|
+
* Use with useEstimateGas when you need gas limit and gas price for the gas param in useSignTxn / useSignAndSendTxn.
|
|
1017
|
+
*
|
|
1018
|
+
* @param provider - PublicClient instance (can be created using usePublicClient hook)
|
|
1019
|
+
* @returns Object with getGasPrice function returning maxFeePerGas, maxPriorityFeePerGas, and/or gasPrice
|
|
1020
|
+
*
|
|
1021
|
+
* @example
|
|
1022
|
+
* ```tsx
|
|
1023
|
+
* const { publicClient } = usePublicClient(...);
|
|
1024
|
+
* const { getGasPrice } = useGetGasPrice(publicClient);
|
|
1025
|
+
* const fees = await getGasPrice();
|
|
1026
|
+
* // EIP-1559: gas: { gasLimit, maxFeePerGas: fees.maxFeePerGas!, maxPriorityFeePerGas: fees.maxPriorityFeePerGas! }
|
|
1027
|
+
* // Legacy: gas: { gasLimit, gasPrice: fees.gasPrice! }
|
|
1028
|
+
* ```
|
|
1029
|
+
*/
|
|
1030
|
+
export function useGetGasPrice(provider) {
|
|
1031
|
+
const getGasPrice = useCallback(async () => {
|
|
1032
|
+
if (!provider) {
|
|
1033
|
+
throw new Error('Provider (publicClient) is required');
|
|
1034
|
+
}
|
|
1035
|
+
const result = {};
|
|
1036
|
+
try {
|
|
1037
|
+
const fees = await provider.estimateFeesPerGas();
|
|
1038
|
+
result.maxFeePerGas = fees.maxFeePerGas;
|
|
1039
|
+
}
|
|
1040
|
+
catch {
|
|
1041
|
+
// EIP-1559 not supported, will try legacy below
|
|
1042
|
+
}
|
|
1043
|
+
try {
|
|
1044
|
+
result.gasPrice = await provider.getGasPrice();
|
|
1045
|
+
result.maxPriorityFeePerGas = await provider.estimateMaxPriorityFeePerGas();
|
|
1046
|
+
}
|
|
1047
|
+
catch {
|
|
1048
|
+
// Optional: gasPrice not available
|
|
1049
|
+
}
|
|
1050
|
+
return result;
|
|
1051
|
+
}, [provider]);
|
|
1052
|
+
return { getGasPrice };
|
|
1053
|
+
}
|
|
846
1054
|
/**
|
|
847
1055
|
* Hook to read from contract
|
|
848
1056
|
* Reads contract data using publicClient.readContract
|
|
@@ -912,7 +1120,7 @@ export function useReadContract(provider) {
|
|
|
912
1120
|
*
|
|
913
1121
|
* @example
|
|
914
1122
|
* ```tsx
|
|
915
|
-
* import { useExternalWalletClient } from 'signer-
|
|
1123
|
+
* import { useExternalWalletClient } from '@abstraxn/signer-react';
|
|
916
1124
|
*
|
|
917
1125
|
* function MyComponent() {
|
|
918
1126
|
* const { walletClient, isConnected } = useExternalWalletClient();
|
|
@@ -960,7 +1168,7 @@ export function useExternalWalletClient() {
|
|
|
960
1168
|
*
|
|
961
1169
|
* @example
|
|
962
1170
|
* ```tsx
|
|
963
|
-
* import { useWriteContract } from 'signer-
|
|
1171
|
+
* import { useWriteContract } from '@abstraxn/signer-react';
|
|
964
1172
|
* import erc20Abi from './erc20Abi.json';
|
|
965
1173
|
*
|
|
966
1174
|
* function MyComponent() {
|
|
@@ -1002,7 +1210,7 @@ export function useWriteContract() {
|
|
|
1002
1210
|
const { walletClient: hookClient, isPending, isError, error, isConnected } = useExternalWalletClient();
|
|
1003
1211
|
const config = useConfig();
|
|
1004
1212
|
const currentChainId = useWagmiChainId();
|
|
1005
|
-
const writeContract = useCallback(({ address, abi, functionName, args, value, account, gas, gasPrice, maxFeePerGas, maxPriorityFeePerGas, nonce, }) => {
|
|
1213
|
+
const writeContract = useCallback(({ address, abi, functionName, args, value, account, gas, gasLimit, gasPrice, maxFeePerGas, maxPriorityFeePerGas, nonce, }) => {
|
|
1006
1214
|
return (async () => {
|
|
1007
1215
|
let activeClient = hookClient;
|
|
1008
1216
|
// If hook client is missing or in error, try to recover
|
|
@@ -1090,7 +1298,7 @@ export function useWriteContract() {
|
|
|
1090
1298
|
'Make sure the function exists in the ABI and is a state-changing function.');
|
|
1091
1299
|
}
|
|
1092
1300
|
// Prepare the call options (viem contract write methods accept options as the last parameter)
|
|
1093
|
-
const hasOptions = value !== undefined || account !== undefined || gas !== undefined ||
|
|
1301
|
+
const hasOptions = value !== undefined || account !== undefined || gas !== undefined || gasLimit !== undefined ||
|
|
1094
1302
|
gasPrice !== undefined || maxFeePerGas !== undefined ||
|
|
1095
1303
|
maxPriorityFeePerGas !== undefined || nonce !== undefined;
|
|
1096
1304
|
// Viem contract write methods expect args as an array, not spread
|
|
@@ -1101,8 +1309,13 @@ export function useWriteContract() {
|
|
|
1101
1309
|
callOptions.value = value;
|
|
1102
1310
|
if (account !== undefined)
|
|
1103
1311
|
callOptions.account = account;
|
|
1104
|
-
|
|
1312
|
+
// `gas` in viem is the gas *limit*. Allow either `gas` or `gasLimit` from the hook caller.
|
|
1313
|
+
if (gas !== undefined) {
|
|
1105
1314
|
callOptions.gas = gas;
|
|
1315
|
+
}
|
|
1316
|
+
else if (gasLimit !== undefined) {
|
|
1317
|
+
callOptions.gas = gasLimit;
|
|
1318
|
+
}
|
|
1106
1319
|
if (gasPrice !== undefined)
|
|
1107
1320
|
callOptions.gasPrice = gasPrice;
|
|
1108
1321
|
if (maxFeePerGas !== undefined)
|
|
@@ -1131,7 +1344,7 @@ export function useWriteContract() {
|
|
|
1131
1344
|
*
|
|
1132
1345
|
* @example
|
|
1133
1346
|
* ```tsx
|
|
1134
|
-
* import { useConnectionType } from 'signer-
|
|
1347
|
+
* import { useConnectionType } from '@abstraxn/signer-react';
|
|
1135
1348
|
*
|
|
1136
1349
|
* function MyComponent() {
|
|
1137
1350
|
* const { connectionType, connectorMeta } = useConnectionType();
|