@abstraxn/signer-react 1.0.1 → 1.0.2
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 +11 -0
- package/README.md +4 -0
- package/dist/src/hooks.d.ts +55 -42
- package/dist/src/hooks.js +125 -153
- package/dist/src/hooks.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.0.1] - 2026-01-28
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Added `useEstimateGas` hook for estimating gas costs for transactions
|
package/README.md
CHANGED
|
@@ -109,6 +109,10 @@ function HookConnectButton() {
|
|
|
109
109
|
- **@abstraxn/signer-core** - Core SDK (dependency)
|
|
110
110
|
- **@abstraxn/signer** - Backward compatible wrapper (deprecated)
|
|
111
111
|
|
|
112
|
+
## 📋 Changelog
|
|
113
|
+
|
|
114
|
+
See [CHANGELOG.md](./CHANGELOG.md) for a list of changes and version history.
|
|
115
|
+
|
|
112
116
|
## 📝 License
|
|
113
117
|
|
|
114
118
|
MIT
|
package/dist/src/hooks.d.ts
CHANGED
|
@@ -8366,14 +8366,14 @@ export declare function usePrepareRawTxn(provider: PublicClient): {
|
|
|
8366
8366
|
prepareRawTxn: ({ from, to, value, data, abi, functionName, args, }: {
|
|
8367
8367
|
from: Address;
|
|
8368
8368
|
to: Address;
|
|
8369
|
-
value?: string | number;
|
|
8369
|
+
value?: string | number | bigint;
|
|
8370
8370
|
data?: `0x${string}`;
|
|
8371
8371
|
abi?: Abi;
|
|
8372
8372
|
functionName?: string;
|
|
8373
8373
|
args?: any[];
|
|
8374
8374
|
}) => Promise<{
|
|
8375
8375
|
to: Address;
|
|
8376
|
-
value:
|
|
8376
|
+
value: string | bigint;
|
|
8377
8377
|
data: `0x${string}`;
|
|
8378
8378
|
}>;
|
|
8379
8379
|
};
|
|
@@ -8390,28 +8390,35 @@ export declare function usePrepareRawTxn(provider: PublicClient): {
|
|
|
8390
8390
|
* const { signTxn } = useSignTxn(publicClient);
|
|
8391
8391
|
*
|
|
8392
8392
|
* // Prepare transaction
|
|
8393
|
-
* const rawTx = await prepareRawTxn({
|
|
8394
|
-
*
|
|
8395
|
-
*
|
|
8396
|
-
*
|
|
8397
|
-
* });
|
|
8398
|
-
*
|
|
8399
|
-
* // Sign transaction
|
|
8393
|
+
* const rawTx = await prepareRawTxn({ from: address!, to: '0x...', value: '0.001' });
|
|
8394
|
+
* const { estimateGas } = useEstimateGas(publicClient);
|
|
8395
|
+
* const gasEstimate = await estimateGas({ account: address!, to: rawTx.to, data: rawTx.data, value: rawTx.value });
|
|
8396
|
+
* // Sign (override required; no estimation in hook)
|
|
8400
8397
|
* const signedTx = await signTxn({
|
|
8401
8398
|
* from: address!,
|
|
8402
|
-
* ...rawTx,
|
|
8399
|
+
* ...rawTx,
|
|
8400
|
+
* override: { gasLimit: gasEstimate.gasLimit, maxFeePerGas: gasEstimate.maxFeePerGas!, maxPriorityFeePerGas: gasEstimate.maxPriorityFeePerGas! },
|
|
8403
8401
|
* });
|
|
8404
8402
|
* ```
|
|
8405
8403
|
*/
|
|
8406
8404
|
export declare function useSignTxn(provider: PublicClient): {
|
|
8407
|
-
signTxn: ({ from, to, value, data, chainId, }: {
|
|
8405
|
+
signTxn: ({ from, to, value, data, chainId, override, }: {
|
|
8408
8406
|
from: Address;
|
|
8409
8407
|
to: Address;
|
|
8410
|
-
value:
|
|
8408
|
+
value: string | bigint;
|
|
8411
8409
|
data: `0x${string}`;
|
|
8412
8410
|
chainId?: number;
|
|
8411
|
+
/** Gas and fees (user must pass; no estimation in hook). EIP-1559 or legacy. Use useEstimateGas to get values. */
|
|
8412
|
+
override: {
|
|
8413
|
+
gasLimit: bigint;
|
|
8414
|
+
maxFeePerGas: bigint;
|
|
8415
|
+
maxPriorityFeePerGas: bigint;
|
|
8416
|
+
} | {
|
|
8417
|
+
gasLimit: bigint;
|
|
8418
|
+
gasPrice: bigint;
|
|
8419
|
+
};
|
|
8413
8420
|
}) => Promise<{
|
|
8414
|
-
unsignedTransaction: `0x02${string}
|
|
8421
|
+
unsignedTransaction: `0x02${string}` | import("viem").TransactionSerializedLegacy;
|
|
8415
8422
|
signedTransaction: string;
|
|
8416
8423
|
}>;
|
|
8417
8424
|
isConnected: boolean;
|
|
@@ -8430,31 +8437,37 @@ export declare function useSignTxn(provider: PublicClient): {
|
|
|
8430
8437
|
* const { signAndSendTxn } = useSignAndSendTxn(publicClient);
|
|
8431
8438
|
*
|
|
8432
8439
|
* // Prepare transaction
|
|
8433
|
-
* const rawTx = await prepareRawTxn({
|
|
8434
|
-
*
|
|
8435
|
-
*
|
|
8436
|
-
*
|
|
8437
|
-
* });
|
|
8438
|
-
*
|
|
8439
|
-
* // Sign and send transaction
|
|
8440
|
+
* const rawTx = await prepareRawTxn({ from: address!, to: '0x...', value: '0.001' });
|
|
8441
|
+
* const { estimateGas } = useEstimateGas(publicClient);
|
|
8442
|
+
* const gasEstimate = await estimateGas({ account: address!, to: rawTx.to, data: rawTx.data, value: rawTx.value });
|
|
8443
|
+
* // Sign and send (override required; no estimation in hook)
|
|
8440
8444
|
* const result = await signAndSendTxn({
|
|
8441
8445
|
* from: address!,
|
|
8442
|
-
* ...rawTx,
|
|
8446
|
+
* ...rawTx,
|
|
8447
|
+
* override: { gasLimit: gasEstimate.gasLimit, maxFeePerGas: gasEstimate.maxFeePerGas!, maxPriorityFeePerGas: gasEstimate.maxPriorityFeePerGas! },
|
|
8443
8448
|
* });
|
|
8444
|
-
*
|
|
8445
8449
|
* console.log('Transaction hash:', result.hash);
|
|
8446
8450
|
* ```
|
|
8447
8451
|
*/
|
|
8448
8452
|
export declare function useSignAndSendTxn(provider: PublicClient): {
|
|
8449
|
-
signAndSendTxn: ({ from, to, value, data, chainId, }: {
|
|
8453
|
+
signAndSendTxn: ({ from, to, value, data, chainId, override, }: {
|
|
8450
8454
|
from: Address;
|
|
8451
8455
|
to: Address;
|
|
8452
|
-
value:
|
|
8456
|
+
value: string | bigint;
|
|
8453
8457
|
data: `0x${string}`;
|
|
8454
8458
|
chainId?: number;
|
|
8459
|
+
/** Gas and fees (user must pass; no estimation in hook). EIP-1559 or legacy. Use useEstimateGas to get values. */
|
|
8460
|
+
override: {
|
|
8461
|
+
gasLimit: bigint;
|
|
8462
|
+
maxFeePerGas: bigint;
|
|
8463
|
+
maxPriorityFeePerGas: bigint;
|
|
8464
|
+
} | {
|
|
8465
|
+
gasLimit: bigint;
|
|
8466
|
+
gasPrice: bigint;
|
|
8467
|
+
};
|
|
8455
8468
|
}) => Promise<{
|
|
8456
8469
|
hash: `0x${string}`;
|
|
8457
|
-
unsignedTransaction: `0x02${string}
|
|
8470
|
+
unsignedTransaction: `0x02${string}` | import("viem").TransactionSerializedLegacy;
|
|
8458
8471
|
signedTransaction: string;
|
|
8459
8472
|
}>;
|
|
8460
8473
|
isConnected: boolean;
|
|
@@ -8495,33 +8508,33 @@ export declare function useWaitForTxnReceipt(provider: PublicClient): {
|
|
|
8495
8508
|
}) => Promise<TransactionReceipt>;
|
|
8496
8509
|
};
|
|
8497
8510
|
/**
|
|
8498
|
-
* Hook to estimate gas
|
|
8499
|
-
*
|
|
8511
|
+
* Hook to estimate gas for a transaction
|
|
8512
|
+
* Returns gasLimit and fees to pass as override to useSignTxn / useSignAndSendTxn (no estimation inside those hooks).
|
|
8500
8513
|
*
|
|
8501
8514
|
* @param provider - PublicClient instance (can be created using usePublicClient hook)
|
|
8502
8515
|
* @returns Object with estimateGas function
|
|
8503
8516
|
*
|
|
8504
8517
|
* @example
|
|
8505
8518
|
* ```tsx
|
|
8506
|
-
* const { publicClient } = usePublicClient(
|
|
8507
|
-
* polygonAmoy,
|
|
8508
|
-
* 'https://rpc-amoy.polygon.technology'
|
|
8509
|
-
* );
|
|
8510
8519
|
* const { estimateGas } = useEstimateGas(publicClient);
|
|
8511
|
-
*
|
|
8512
|
-
*
|
|
8513
|
-
*
|
|
8514
|
-
*
|
|
8515
|
-
*
|
|
8516
|
-
*
|
|
8517
|
-
* //
|
|
8518
|
-
* //
|
|
8519
|
-
* // maxPriorityFeePerGas?: bigint // EIP-1559 max priority fee per gas
|
|
8520
|
-
* // }
|
|
8520
|
+
* const result = await estimateGas({
|
|
8521
|
+
* account: address!,
|
|
8522
|
+
* to: rawTx.to,
|
|
8523
|
+
* data: rawTx.data,
|
|
8524
|
+
* value: rawTx.value,
|
|
8525
|
+
* });
|
|
8526
|
+
* // EIP-1559: override: { gasLimit: result.gasLimit, maxFeePerGas: result.maxFeePerGas!, maxPriorityFeePerGas: result.maxPriorityFeePerGas! }
|
|
8527
|
+
* // Legacy: override: { gasLimit: result.gasLimit, gasPrice: result.gasPrice! }
|
|
8521
8528
|
* ```
|
|
8522
8529
|
*/
|
|
8523
8530
|
export declare function useEstimateGas(provider: PublicClient): {
|
|
8524
|
-
estimateGas: (
|
|
8531
|
+
estimateGas: ({ account, to, data, value, }: {
|
|
8532
|
+
account: Address;
|
|
8533
|
+
to: Address;
|
|
8534
|
+
data?: `0x${string}`;
|
|
8535
|
+
value?: string | bigint;
|
|
8536
|
+
}) => Promise<{
|
|
8537
|
+
gasLimit: bigint;
|
|
8525
8538
|
gasPrice?: bigint;
|
|
8526
8539
|
maxFeePerGas?: bigint;
|
|
8527
8540
|
maxPriorityFeePerGas?: bigint;
|
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';
|
|
@@ -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,20 @@ 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 gasEstimate = await estimateGas({ account: address!, to: rawTx.to, data: rawTx.data, value: rawTx.value });
|
|
585
|
+
* // Sign (override required; no estimation in hook)
|
|
636
586
|
* const signedTx = await signTxn({
|
|
637
587
|
* from: address!,
|
|
638
|
-
* ...rawTx,
|
|
588
|
+
* ...rawTx,
|
|
589
|
+
* override: { gasLimit: gasEstimate.gasLimit, maxFeePerGas: gasEstimate.maxFeePerGas!, maxPriorityFeePerGas: gasEstimate.maxPriorityFeePerGas! },
|
|
639
590
|
* });
|
|
640
591
|
* ```
|
|
641
592
|
*/
|
|
642
593
|
export function useSignTxn(provider) {
|
|
643
594
|
const { wallet, isConnected, address, signTransactionViaAPI } = useAbstraxnWallet();
|
|
644
|
-
const signTxn = useCallback(async ({ from, to, value, data, chainId, }) => {
|
|
595
|
+
const signTxn = useCallback(async ({ from, to, value, data, chainId, override, }) => {
|
|
645
596
|
if (!isConnected || !wallet) {
|
|
646
597
|
throw new Error('Wallet is not connected');
|
|
647
598
|
}
|
|
@@ -654,6 +605,16 @@ export function useSignTxn(provider) {
|
|
|
654
605
|
if (!to) {
|
|
655
606
|
throw new Error('To address is required');
|
|
656
607
|
}
|
|
608
|
+
if (override.gasLimit === undefined) {
|
|
609
|
+
throw new Error('override.gasLimit is required. Use useEstimateGas to get values.');
|
|
610
|
+
}
|
|
611
|
+
const isLegacy = 'gasPrice' in override && override.gasPrice !== undefined;
|
|
612
|
+
if (!isLegacy) {
|
|
613
|
+
const o = override;
|
|
614
|
+
if (o.maxFeePerGas === undefined || o.maxPriorityFeePerGas === undefined) {
|
|
615
|
+
throw new Error('override.maxFeePerGas and maxPriorityFeePerGas are required for EIP-1559, or pass gasPrice for legacy.');
|
|
616
|
+
}
|
|
617
|
+
}
|
|
657
618
|
// Get chain ID from provider or use provided one
|
|
658
619
|
const targetChainId = chainId || provider.chain?.id;
|
|
659
620
|
if (!targetChainId) {
|
|
@@ -661,32 +622,34 @@ export function useSignTxn(provider) {
|
|
|
661
622
|
}
|
|
662
623
|
// Get nonce
|
|
663
624
|
const nonce = await provider.getTransactionCount({ address: from });
|
|
664
|
-
//
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
const
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
625
|
+
// Value in wei (pass-through from prepareRawTxn, no hex conversion)
|
|
626
|
+
const valueInWei = typeof value === 'bigint' ? value : BigInt(value === '0x' || value === '' ? '0' : value);
|
|
627
|
+
// Build unsigned tx from user override only (no estimateGas/estimateFeesPerGas)
|
|
628
|
+
const unsignedTx = isLegacy
|
|
629
|
+
? {
|
|
630
|
+
chainId: targetChainId,
|
|
631
|
+
from,
|
|
632
|
+
to,
|
|
633
|
+
data,
|
|
634
|
+
value: valueInWei,
|
|
635
|
+
nonce,
|
|
636
|
+
gas: override.gasLimit,
|
|
637
|
+
gasPrice: override.gasPrice,
|
|
638
|
+
}
|
|
639
|
+
: (() => {
|
|
640
|
+
const o = override;
|
|
641
|
+
return {
|
|
642
|
+
chainId: targetChainId,
|
|
643
|
+
from,
|
|
644
|
+
to,
|
|
645
|
+
data,
|
|
646
|
+
value: valueInWei,
|
|
647
|
+
nonce,
|
|
648
|
+
gas: o.gasLimit,
|
|
649
|
+
maxFeePerGas: o.maxFeePerGas,
|
|
650
|
+
maxPriorityFeePerGas: o.maxPriorityFeePerGas,
|
|
651
|
+
};
|
|
652
|
+
})();
|
|
690
653
|
// Serialize transaction
|
|
691
654
|
const serializedTx = serializeTransaction(unsignedTx);
|
|
692
655
|
// Sign transaction via Turnkey API
|
|
@@ -711,24 +674,21 @@ export function useSignTxn(provider) {
|
|
|
711
674
|
* const { signAndSendTxn } = useSignAndSendTxn(publicClient);
|
|
712
675
|
*
|
|
713
676
|
* // Prepare transaction
|
|
714
|
-
* const rawTx = await prepareRawTxn({
|
|
715
|
-
*
|
|
716
|
-
*
|
|
717
|
-
*
|
|
718
|
-
* });
|
|
719
|
-
*
|
|
720
|
-
* // Sign and send transaction
|
|
677
|
+
* const rawTx = await prepareRawTxn({ from: address!, to: '0x...', value: '0.001' });
|
|
678
|
+
* const { estimateGas } = useEstimateGas(publicClient);
|
|
679
|
+
* const gasEstimate = await estimateGas({ account: address!, to: rawTx.to, data: rawTx.data, value: rawTx.value });
|
|
680
|
+
* // Sign and send (override required; no estimation in hook)
|
|
721
681
|
* const result = await signAndSendTxn({
|
|
722
682
|
* from: address!,
|
|
723
|
-
* ...rawTx,
|
|
683
|
+
* ...rawTx,
|
|
684
|
+
* override: { gasLimit: gasEstimate.gasLimit, maxFeePerGas: gasEstimate.maxFeePerGas!, maxPriorityFeePerGas: gasEstimate.maxPriorityFeePerGas! },
|
|
724
685
|
* });
|
|
725
|
-
*
|
|
726
686
|
* console.log('Transaction hash:', result.hash);
|
|
727
687
|
* ```
|
|
728
688
|
*/
|
|
729
689
|
export function useSignAndSendTxn(provider) {
|
|
730
690
|
const { wallet, isConnected, address, signTransactionViaAPI } = useAbstraxnWallet();
|
|
731
|
-
const signAndSendTxn = useCallback(async ({ from, to, value, data, chainId, }) => {
|
|
691
|
+
const signAndSendTxn = useCallback(async ({ from, to, value, data, chainId, override, }) => {
|
|
732
692
|
if (!isConnected || !wallet) {
|
|
733
693
|
throw new Error('Wallet is not connected');
|
|
734
694
|
}
|
|
@@ -741,6 +701,16 @@ export function useSignAndSendTxn(provider) {
|
|
|
741
701
|
if (!to) {
|
|
742
702
|
throw new Error('To address is required');
|
|
743
703
|
}
|
|
704
|
+
if (override.gasLimit === undefined) {
|
|
705
|
+
throw new Error('override.gasLimit is required. Use useEstimateGas to get values.');
|
|
706
|
+
}
|
|
707
|
+
const isLegacy = 'gasPrice' in override && override.gasPrice !== undefined;
|
|
708
|
+
if (!isLegacy) {
|
|
709
|
+
const o = override;
|
|
710
|
+
if (o.maxFeePerGas === undefined || o.maxPriorityFeePerGas === undefined) {
|
|
711
|
+
throw new Error('override.maxFeePerGas and maxPriorityFeePerGas are required for EIP-1559, or pass gasPrice for legacy.');
|
|
712
|
+
}
|
|
713
|
+
}
|
|
744
714
|
// Get chain ID from provider or use provided one
|
|
745
715
|
const targetChainId = chainId || provider.chain?.id;
|
|
746
716
|
if (!targetChainId) {
|
|
@@ -748,32 +718,34 @@ export function useSignAndSendTxn(provider) {
|
|
|
748
718
|
}
|
|
749
719
|
// Get nonce
|
|
750
720
|
const nonce = await provider.getTransactionCount({ address: from });
|
|
751
|
-
//
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
const
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
721
|
+
// Value in wei (pass-through from prepareRawTxn, no hex conversion)
|
|
722
|
+
const valueInWei = typeof value === 'bigint' ? value : BigInt(value === '0x' || value === '' ? '0' : value);
|
|
723
|
+
// Build unsigned tx from user override only (no estimateGas/estimateFeesPerGas)
|
|
724
|
+
const unsignedTx = isLegacy
|
|
725
|
+
? {
|
|
726
|
+
chainId: targetChainId,
|
|
727
|
+
from,
|
|
728
|
+
to,
|
|
729
|
+
data,
|
|
730
|
+
value: valueInWei,
|
|
731
|
+
nonce,
|
|
732
|
+
gas: override.gasLimit,
|
|
733
|
+
gasPrice: override.gasPrice,
|
|
734
|
+
}
|
|
735
|
+
: (() => {
|
|
736
|
+
const o = override;
|
|
737
|
+
return {
|
|
738
|
+
chainId: targetChainId,
|
|
739
|
+
from,
|
|
740
|
+
to,
|
|
741
|
+
data,
|
|
742
|
+
value: valueInWei,
|
|
743
|
+
nonce,
|
|
744
|
+
gas: o.gasLimit,
|
|
745
|
+
maxFeePerGas: o.maxFeePerGas,
|
|
746
|
+
maxPriorityFeePerGas: o.maxPriorityFeePerGas,
|
|
747
|
+
};
|
|
748
|
+
})();
|
|
777
749
|
// Serialize transaction
|
|
778
750
|
const serializedTx = serializeTransaction(unsignedTx);
|
|
779
751
|
// Sign transaction via Turnkey API
|
|
@@ -844,59 +816,59 @@ export function useWaitForTxnReceipt(provider) {
|
|
|
844
816
|
return { waitForTxnReceipt };
|
|
845
817
|
}
|
|
846
818
|
/**
|
|
847
|
-
* Hook to estimate gas
|
|
848
|
-
*
|
|
819
|
+
* Hook to estimate gas for a transaction
|
|
820
|
+
* Returns gasLimit and fees to pass as override to useSignTxn / useSignAndSendTxn (no estimation inside those hooks).
|
|
849
821
|
*
|
|
850
822
|
* @param provider - PublicClient instance (can be created using usePublicClient hook)
|
|
851
823
|
* @returns Object with estimateGas function
|
|
852
824
|
*
|
|
853
825
|
* @example
|
|
854
826
|
* ```tsx
|
|
855
|
-
* const { publicClient } = usePublicClient(
|
|
856
|
-
* polygonAmoy,
|
|
857
|
-
* 'https://rpc-amoy.polygon.technology'
|
|
858
|
-
* );
|
|
859
827
|
* const { estimateGas } = useEstimateGas(publicClient);
|
|
860
|
-
*
|
|
861
|
-
*
|
|
862
|
-
*
|
|
863
|
-
*
|
|
864
|
-
*
|
|
865
|
-
*
|
|
866
|
-
* //
|
|
867
|
-
* //
|
|
868
|
-
* // maxPriorityFeePerGas?: bigint // EIP-1559 max priority fee per gas
|
|
869
|
-
* // }
|
|
828
|
+
* const result = await estimateGas({
|
|
829
|
+
* account: address!,
|
|
830
|
+
* to: rawTx.to,
|
|
831
|
+
* data: rawTx.data,
|
|
832
|
+
* value: rawTx.value,
|
|
833
|
+
* });
|
|
834
|
+
* // EIP-1559: override: { gasLimit: result.gasLimit, maxFeePerGas: result.maxFeePerGas!, maxPriorityFeePerGas: result.maxPriorityFeePerGas! }
|
|
835
|
+
* // Legacy: override: { gasLimit: result.gasLimit, gasPrice: result.gasPrice! }
|
|
870
836
|
* ```
|
|
871
837
|
*/
|
|
872
838
|
export function useEstimateGas(provider) {
|
|
873
|
-
const estimateGas = useCallback(async () => {
|
|
839
|
+
const estimateGas = useCallback(async ({ account, to, data = '0x', value = 0n, }) => {
|
|
874
840
|
if (!provider) {
|
|
875
841
|
throw new Error('Provider (publicClient) is required');
|
|
876
842
|
}
|
|
843
|
+
if (!account) {
|
|
844
|
+
throw new Error('Account (from) is required');
|
|
845
|
+
}
|
|
846
|
+
if (!to) {
|
|
847
|
+
throw new Error('To address is required');
|
|
848
|
+
}
|
|
849
|
+
const valueInWei = typeof value === 'bigint' ? value : (value === undefined || value === '' || value === '0x' ? 0n : BigInt(value));
|
|
850
|
+
const gasLimit = await provider.estimateGas({
|
|
851
|
+
account,
|
|
852
|
+
to,
|
|
853
|
+
data: data ?? '0x',
|
|
854
|
+
value: valueInWei,
|
|
855
|
+
});
|
|
877
856
|
try {
|
|
878
|
-
// Try to get EIP-1559 fees first (for modern chains)
|
|
879
857
|
const fees = await provider.estimateFeesPerGas();
|
|
880
858
|
return {
|
|
859
|
+
gasLimit,
|
|
881
860
|
maxFeePerGas: fees.maxFeePerGas,
|
|
882
861
|
maxPriorityFeePerGas: fees.maxPriorityFeePerGas,
|
|
883
|
-
// Also get legacy gas price as fallback
|
|
884
862
|
gasPrice: fees.gasPrice,
|
|
885
863
|
};
|
|
886
864
|
}
|
|
887
865
|
catch (error) {
|
|
888
|
-
// If EIP-1559 fails, try legacy gas price
|
|
889
866
|
try {
|
|
890
867
|
const gasPrice = await provider.getGasPrice();
|
|
891
|
-
return {
|
|
892
|
-
gasPrice,
|
|
893
|
-
};
|
|
868
|
+
return { gasLimit, gasPrice };
|
|
894
869
|
}
|
|
895
870
|
catch (legacyError) {
|
|
896
|
-
|
|
897
|
-
throw new Error(`Failed to estimate gas price: ${error.message}`);
|
|
898
|
-
}
|
|
899
|
-
throw error;
|
|
871
|
+
return { gasLimit };
|
|
900
872
|
}
|
|
901
873
|
}
|
|
902
874
|
}, [provider]);
|