125 lines
5.0 KiB
JavaScript
125 lines
5.0 KiB
JavaScript
|
|
#!/usr/bin/env node
|
|||
|
|
/**
|
|||
|
|
* Example: How to Send Signed Transactions to Besu RPC Nodes
|
|||
|
|
*
|
|||
|
|
* This script demonstrates the correct way to send transactions to Besu,
|
|||
|
|
* which requires eth_sendRawTransaction instead of eth_sendTransaction.
|
|||
|
|
*
|
|||
|
|
* Usage:
|
|||
|
|
* node example-send-signed-transaction.js <rpc_url> <private_key> <to_address> <amount_eth>
|
|||
|
|
*
|
|||
|
|
* Example:
|
|||
|
|
* node example-send-signed-transaction.js http://192.168.11.250:8545 0x<private_key> 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb 0.01
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
const https = require('https');
|
|||
|
|
const http = require('http');
|
|||
|
|
const { ethers } = require('ethers');
|
|||
|
|
|
|||
|
|
// Parse command line arguments
|
|||
|
|
const args = process.argv.slice(2);
|
|||
|
|
if (args.length < 4) {
|
|||
|
|
console.error('Usage: node example-send-signed-transaction.js <rpc_url> <private_key> <to_address> <amount_eth>');
|
|||
|
|
console.error('');
|
|||
|
|
console.error('Example:');
|
|||
|
|
console.error(' node example-send-signed-transaction.js http://192.168.11.250:8545 0x<private_key> 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb 0.01');
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const [rpcUrl, privateKey, toAddress, amountEth] = args;
|
|||
|
|
|
|||
|
|
async function sendSignedTransaction() {
|
|||
|
|
try {
|
|||
|
|
console.log('=== Besu Signed Transaction Example ===\n');
|
|||
|
|
|
|||
|
|
// 1. Create wallet from private key
|
|||
|
|
console.log('1. Creating wallet from private key...');
|
|||
|
|
const wallet = new ethers.Wallet(privateKey);
|
|||
|
|
console.log(` Address: ${wallet.address}\n`);
|
|||
|
|
|
|||
|
|
// 2. Connect to RPC provider
|
|||
|
|
console.log('2. Connecting to RPC node...');
|
|||
|
|
const provider = new ethers.providers.JsonRpcProvider(rpcUrl);
|
|||
|
|
|
|||
|
|
// Verify connection
|
|||
|
|
const network = await provider.getNetwork();
|
|||
|
|
console.log(` Chain ID: ${network.chainId}`);
|
|||
|
|
const balance = await provider.getBalance(wallet.address);
|
|||
|
|
console.log(` Balance: ${ethers.utils.formatEther(balance)} ETH\n`);
|
|||
|
|
|
|||
|
|
if (balance.lt(ethers.utils.parseEther(amountEth))) {
|
|||
|
|
console.error(`❌ Insufficient balance. Need ${amountEth} ETH, have ${ethers.utils.formatEther(balance)} ETH`);
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 3. Get current gas price
|
|||
|
|
console.log('3. Getting gas price...');
|
|||
|
|
const gasPrice = await provider.getGasPrice();
|
|||
|
|
console.log(` Gas Price: ${ethers.utils.formatUnits(gasPrice, 'gwei')} gwei\n`);
|
|||
|
|
|
|||
|
|
// 4. Get nonce
|
|||
|
|
console.log('4. Getting transaction count (nonce)...');
|
|||
|
|
const nonce = await provider.getTransactionCount(wallet.address, 'pending');
|
|||
|
|
console.log(` Nonce: ${nonce}\n`);
|
|||
|
|
|
|||
|
|
// 5. Create transaction
|
|||
|
|
console.log('5. Creating transaction...');
|
|||
|
|
const tx = {
|
|||
|
|
to: toAddress,
|
|||
|
|
value: ethers.utils.parseEther(amountEth),
|
|||
|
|
gasLimit: 21000, // Standard transfer
|
|||
|
|
gasPrice: gasPrice,
|
|||
|
|
nonce: nonce,
|
|||
|
|
chainId: network.chainId
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
console.log(` To: ${tx.to}`);
|
|||
|
|
console.log(` Value: ${amountEth} ETH`);
|
|||
|
|
console.log(` Gas Limit: ${tx.gasLimit}`);
|
|||
|
|
console.log(` Gas Price: ${ethers.utils.formatUnits(tx.gasPrice, 'gwei')} gwei`);
|
|||
|
|
console.log(` Nonce: ${tx.nonce}`);
|
|||
|
|
console.log(` Chain ID: ${tx.chainId}\n`);
|
|||
|
|
|
|||
|
|
// 6. Sign transaction
|
|||
|
|
console.log('6. Signing transaction...');
|
|||
|
|
const signedTx = await wallet.signTransaction(tx);
|
|||
|
|
console.log(` Signed transaction length: ${signedTx.length} characters\n`);
|
|||
|
|
|
|||
|
|
// 7. Send signed transaction via eth_sendRawTransaction
|
|||
|
|
console.log('7. Sending signed transaction via eth_sendRawTransaction...');
|
|||
|
|
const txResponse = await provider.sendTransaction(signedTx);
|
|||
|
|
console.log(` ✅ Transaction hash: ${txResponse.hash}\n`);
|
|||
|
|
|
|||
|
|
// 8. Wait for transaction to be mined
|
|||
|
|
console.log('8. Waiting for transaction to be mined...');
|
|||
|
|
const receipt = await txResponse.wait();
|
|||
|
|
|
|||
|
|
if (receipt.status === 1) {
|
|||
|
|
console.log(` ✅ Transaction successful!`);
|
|||
|
|
console.log(` Block: ${receipt.blockNumber}`);
|
|||
|
|
console.log(` Gas Used: ${receipt.gasUsed.toString()}`);
|
|||
|
|
} else {
|
|||
|
|
console.log(` ❌ Transaction failed (status: ${receipt.status})`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
console.log('\n=== Transaction Complete ===');
|
|||
|
|
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('\n❌ Error:', error.message);
|
|||
|
|
|
|||
|
|
if (error.message.includes('eth_sendTransaction')) {
|
|||
|
|
console.error('\n⚠️ This error occurs if you try to use eth_sendTransaction.');
|
|||
|
|
console.error(' Besu requires eth_sendRawTransaction with signed transactions.');
|
|||
|
|
} else if (error.message.includes('insufficient funds')) {
|
|||
|
|
console.error('\n⚠️ Insufficient balance for this transaction.');
|
|||
|
|
} else if (error.message.includes('nonce')) {
|
|||
|
|
console.error('\n⚠️ Nonce error - transaction may already be pending.');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Run the example
|
|||
|
|
sendSignedTransaction();
|