Introduction
In this comprehensive guide, we'll explore how to use Node.js to create optimized interfaces for Ethereum (ETH) and token transfers. This builds upon previous work with Web3.js balance queries and takes transaction processing to the next level with two key improvements:
- Creating callable Node.js interfaces
- Implementing balance verification before transfers
Part 1: Creating Node.js Interfaces
1.1 ETH Transfer Interface
Endpoint Description
- Function: ETH transfer
- URL:
http://127.0.0.1:8084/eth/transfer - Method: GET
Parameters
| Parameter | Required | Type | Description |
|---|---|---|---|
| currentAccount | Yes | string | Sender wallet address |
| to | Yes | string | Recipient wallet address |
| amount | Yes | string | Transfer amount (in wei) |
| privateKey | Yes | string | Sender's private key |
| gasPrice | No | string | Gas price (in Gwei) |
| gasLimit | No | string | Gas limit (in Wei, default: 26000) |
Response Example
{
"code": 10000,
"hash": "0x3aa7b47d69f38aa2e606c5b355c6c07e68d970cf5d891bbb6881011b5f2a4539",
"message": "ok"
}Implementation Code
router.get('/eth/transfer', async(ctx, next) => {
// Parameter validation
if (!ctx.request.query.currentAccount) {
return errorResponse(ctx, 20005, 'currentAccount must be a string');
}
// Set default gas values
const gasLimit = ctx.request.query.gasLimit || '26000';
let gasPrice = ctx.request.query.gasPrice
? web3.utils.toWei(ctx.request.query.gasPrice, 'gwei')
: await web3.eth.getGasPrice();
// Calculate maximum transaction cost
const fees = await calculateMaxFee(gasLimit, gasPrice);
const balance = await web3.eth.getBalance(ctx.request.query.currentAccount);
// Balance verification
if (parseInt(balance) < (parseInt(ctx.request.query.amount) + parseInt(fees))) {
return insufficientBalanceResponse(ctx, balance, fees, ctx.request.query.amount);
}
// Transaction execution
const txData = {
nonce: web3.utils.toHex(await web3.eth.getTransactionCount(ctx.request.query.currentAccount, 'pending')),
gasLimit: web3.utils.toHex(gasLimit),
gasPrice: web3.utils.toHex(gasPrice),
to: ctx.request.query.to,
value: web3.utils.toHex(ctx.request.query.amount),
data: ''
};
const tx = new Tx(txData);
tx.sign(new Buffer.from(ctx.request.query.privateKey, 'hex'));
const hash = await web3.eth.sendSignedTransaction('0x' + tx.serialize().toString('hex'));
ctx.body = {
code: 10000,
hash: hash.transactionHash,
message: 'ok'
};
});๐ Learn more about Ethereum transaction optimization
1.2 Token Transfer Interface
Endpoint Description
- Function: Token transfer
- URL:
http://127.0.0.1:8084/token/transfer - Method: GET
Parameters
| Parameter | Required | Type | Description |
|---|---|---|---|
| contractAddress | Yes | string | Token contract address |
| currentAccount | Yes | string | Sender wallet address |
| to | Yes | string | Recipient wallet address |
| amount | Yes | string | Transfer amount (adjusted for decimals) |
| privateKey | Yes | string | Sender's private key |
| gasPrice | No | string | Gas price (in Gwei) |
| gasLimit | No | string | Gas limit (in Wei, default: 26000) |
Implementation Code
router.get('/token/transfer', async(ctx, next) => {
// Parameter validation
if (!ctx.request.query.contractAddress) {
return errorResponse(ctx, 20004, 'contractAddress required');
}
// Set default gas values
const gasLimit = ctx.request.query.gasLimit || '26000';
let gasPrice = ctx.request.query.gasPrice
? web3.utils.toWei(ctx.request.query.gasPrice, 'gwei')
: await web3.eth.getGasPrice();
// Balance verification
const fees = await calculateMaxFee(gasLimit, gasPrice);
const balance = await web3.eth.getBalance(ctx.request.query.currentAccount);
if (parseInt(balance) < parseInt(fees)) {
return insufficientBalanceResponse(ctx, balance, fees);
}
// Prepare token transfer data
const txData = {
nonce: web3.utils.toHex(await web3.eth.getTransactionCount(ctx.request.query.currentAccount, 'pending')),
gasLimit: web3.utils.toHex(gasLimit),
gasPrice: web3.utils.toHex(gasPrice),
to: ctx.request.query.contractAddress,
value: '0x00',
data: generateTransferData(ctx.request.query.to, ctx.request.query.amount)
};
// Execute transaction
const tx = new Tx(txData);
tx.sign(new Buffer.from(ctx.request.query.privateKey, 'hex'));
const hash = await web3.eth.sendSignedTransaction('0x' + tx.serialize().toString('hex'));
ctx.body = {
code: 10000,
hash: hash.transactionHash,
message: 'ok'
};
});
function generateTransferData(toAddress, amount) {
return '0x' + 'a9059cbb' + '000000000000000000000000' +
toAddress.substr(2) +
web3.utils.toHex(amount).substr(2).padStart(64, '0');
}๐ Master token transfers with our advanced guide
Part 2: Optimization Strategies
2.1 Gas Price Optimization
Key improvements:
- Made
gasPriceoptional - Defaults to median gas price from recent blocks via
web3.eth.getGasPrice() - Balances between transaction speed and cost
2.2 Gas Limit Optimization
- Reduced default
gasLimitfrom 99000 to 26000 wei - Matches simpler transfer operations' actual requirements
- Prevents "Insufficient funds" errors from overestimated limits
2.3 Balance Verification System
async function calculateMaxFee(gasLimit, gasPrice) {
return gasLimit * gasPrice;
}
function insufficientBalanceResponse(ctx, balance, fees, amount = null) {
let message = `Current balance: ${web3.utils.fromWei(balance, 'ether')} `;
message += `Max fee: ${web3.utils.fromWei(fees.toString(), 'ether')}`;
if (amount) {
message += ` Transfer amount: ${web3.utils.fromWei(amount, 'ether')}`;
}
message += ' - Insufficient balance';
ctx.body = {
code: 20001,
data: {},
message: message
};
}FAQ Section
Q1: Why is my transaction failing with "Insufficient funds"?
A: This occurs when your ETH balance cannot cover both the transfer amount and maximum gas cost. Our system now checks this automatically before attempting transactions.
Q2: What's the optimal gas price for fast confirmation?
A: For urgent transfers, use the current network average (available via web3.eth.getGasPrice()). For non-urgent transfers, you can often use lower prices.
Q3: How is the default gasLimit of 26000 determined?
A: This value represents the typical computational cost for simple transfers. Complex smart contract interactions may require higher limits.
Q4: Can I use these interfaces for production applications?
A: Yes, but consider adding additional security layers like rate limiting and authentication for production use.
Q5: How do token transfers differ from ETH transfers?
A: Token transfers interact with smart contracts and require the token contract address. They also need specially formatted transaction data.
Conclusion
By implementing these Node.js interfaces and optimization strategies, developers can:
- Create reliable transaction services
- Prevent failed transactions from insufficient balances
- Automatically handle gas parameter optimization
- Provide clear error messaging
๐ Explore more blockchain development resources
Remember to always test thoroughly with small amounts before larger transactions, and consider implementing additional security measures for production systems.
Original content, please credit when sharing.