The useSendTransaction hook from MoonKey’s React SDK provides a simple interface for sending transactions from embedded wallets. It handles transaction preparation, signing, and broadcasting to the network.
MoonKey automatically handles transaction population (gas estimation, nonce management, etc.) and prompts users for confirmation before broadcasting.
A successful return indicates the transaction was broadcasted to the network. It may still fail during confirmation. Always verify transaction status onchain or listen for confirmation events.
Hiding the confirmation modal removes the user’s ability to review transaction details before signing. Only use this for trusted operations or after obtaining explicit user consent.
Let MoonKey handle gas estimation, but allow overrides when needed:
Copy
// MoonKey handles gas estimation automaticallyawait sendTransaction({ to: '0x...', value: '0x38d7ea4c68000' // gasLimit is optional - only provide if you need a specific value});// Or provide custom gas parameters for advanced use casesawait sendTransaction({ to: '0x...', value: '0x38d7ea4c68000', gasLimit: '0x5208', maxFeePerGas: '0x59682f00', maxPriorityFeePerGas: '0x3b9aca00'});
Handle transaction confirmations
Wait for transaction confirmations before considering it final:
Copy
import { createPublicClient, http } from 'viem';import { mainnet } from 'viem/chains';const publicClient = createPublicClient({ chain: mainnet, transport: http()});const handleSend = async () => { const result = await sendTransaction({ to: '0x...', value: '0x38d7ea4c68000' }); console.log('Transaction broadcasted:', result.transactionHash); // Wait for confirmation const receipt = await publicClient.waitForTransactionReceipt({ hash: result.transactionHash as `0x${string}` }); console.log('Transaction confirmed:', receipt.status);};
Display transaction links
Help users track their transactions on block explorers:
Check that the user’s wallet has sufficient balance
Verify the recipient address is valid
Ensure the contract address is correct for contract interactions
Check that the encoded data is properly formatted
Try on a testnet first to debug
Copy
// Add detailed loggingtry { console.log('Sending transaction:', { to, value, data }); const result = await sendTransaction({ to, value, data }); console.log('Transaction sent:', result);} catch (error) { console.error('Full error:', error); console.error('Error details:', JSON.stringify(error, null, 2));}
User rejected transaction
Handle user cancellations gracefully:
Copy
catch (error: any) { if (error.code === 'USER_REJECTED' || error.message.includes('User rejected')) { console.log('User cancelled the transaction'); // Don't show error - this is expected behavior return; } // Handle other errors alert('Transaction failed: ' + error.message);}
Insufficient gas
If transactions fail due to gas issues:
MoonKey usually handles gas estimation automatically
For complex transactions, consider providing a custom gas limit
Ensure the wallet has enough ETH for both value + gas
Copy
// Check if error is gas-relatedif (error.message.includes('gas') || error.message.includes('insufficient funds')) { alert('Insufficient ETH for gas. Please add more ETH to your wallet.');}
Transaction stuck or pending
If a transaction appears stuck:
Check the network status (congestion, downtime)
Verify the transaction on a block explorer
Consider the gas price used - low gas prices can cause delays
Wait for network confirmation (can take minutes during congestion)
Copy
// Implement a timeoutconst TIMEOUT = 60000; // 60 secondsconst sendWithTimeout = async () => { const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('Transaction timeout')), TIMEOUT) ); try { const result = await Promise.race([ sendTransaction({ to: '0x...', value: '0x38d7ea4c68000' }), timeoutPromise ]); console.log('Transaction sent:', result); } catch (error: any) { if (error.message === 'Transaction timeout') { alert('Transaction is taking longer than expected. Check your wallet or explorer.'); } }};
Wrong network
Ensure transactions are sent on the correct network:
Copy
import { useWalletChain } from '@moon-key/react-auth/ethereum';const { chainId, switchChain } = useWalletChain();const handleSend = async () => { const targetChainId = 8453; // Base if (chainId !== targetChainId) { try { await switchChain(targetChainId); } catch (error) { alert('Please switch to Base network'); return; } } await sendTransaction({ to: '0x...', value: '0x38d7ea4c68000' });};