Transaction Troubleshooting
This guide helps developers and users resolve common transaction issues on Circle Layer blockchain, including pending transactions, gas problems, and meta transaction errors.
Common Transaction Issuesβ
1. Inappropriate Nonceβ
Problem: Transaction fails due to incorrect nonce value.
Symptoms:
- "Nonce too low" error
- "Nonce too high" error
- Transactions stuck in pending state
Solutions:
Reset Account Nonceβ
# MetaMask Solution
1. MetaMask β Settings β Advanced β Reset Account
2. This clears pending transaction history and resets nonce
Customize Transaction Nonceβ
# MetaMask Advanced Settings
1. MetaMask β Settings β Advanced β Customize transaction nonce
2. Enable this setting
3. Manually set appropriate nonce when sending transactions
Check Current Nonceβ
// Web3.js
const nonce = await web3.eth.getTransactionCount(address, 'pending');
// Ethers.js
const nonce = await provider.getTransactionCount(address, 'pending');
Handle Multiple Pending Transactionsβ
- Wait for earlier transactions to confirm before sending new ones
- Cancel pending transactions by sending 0 ETH to yourself with higher gas price
- Use sequential nonces when sending multiple transactions
2. Low Gas Priceβ
Problem: Transaction remains pending due to insufficient gas price.
Symptoms:
- Transaction stays in mempool for extended periods
- "Gas price too low" warnings
- Transaction never gets mined
Solutions:
Increase Gas Priceβ
// Set higher gas price
const transaction = {
to: recipient,
value: amount,
gasLimit: 21000,
gasPrice: ethers.utils.parseUnits('20', 'gwei') // Increase from default
};
Use Dynamic Gas Pricingβ
// Get current gas price recommendations
async function getOptimalGasPrice() {
const gasPrice = await provider.getGasPrice();
// Add 20% buffer
return gasPrice.mul(120).div(100);
}
Speed Up Transactionsβ
# MetaMask Speed Up
1. Go to Activity tab
2. Click on pending transaction
3. Click "Speed Up"
4. Confirm with higher gas price
3. Meta Transaction Issuesβ
Meta transactions have specific error patterns and solutions:
Invalid Fee Percentageβ
Error:
invalid meta transaction FeePercent need 0-10000. Found:100001
Cause: Fee percentage exceeds valid range (0-100%).
Solution:
// Ensure fee percentage is within valid range
const feePercent = 2500; // 25% (valid range: 0-10000)
if (feePercent < 0 || feePercent > 10000) {
throw new Error('Fee percentage must be between 0-10000');
}
Expired Meta Transactionβ
Error:
err: expired meta transaction. current:2083222, need execute before 2075609
Cause: Meta transaction expired (valid for 28,800 blocks β 1 day).
Solutions:
- Create New Meta Transaction:
// Check if meta transaction is still valid
function isMetaTransactionValid(expiryBlock, currentBlock) {
return currentBlock < expiryBlock;
}
// Create new meta transaction if expired
if (!isMetaTransactionValid(expiryBlock, currentBlock)) {
const newMetaTx = await createMetaTransaction(txParams);
}
- Resend with Regular Transaction:
# MetaMask - Send regular transaction instead
1. MetaMask β Settings β Advanced β Customize transaction nonce
2. Send transaction with same nonce but higher gas price
3. This replaces the expired meta transaction
Advanced Troubleshootingβ
Gas Estimation Failuresβ
Problem: "Gas estimation failed" error when sending transactions.
Debugging Steps:
- Check Contract State:
// Verify contract exists and function is callable
const code = await provider.getCode(contractAddress);
if (code === '0x') {
console.error('Contract not found at address');
}
- Simulate Transaction:
// Use callStatic to simulate without sending
try {
const result = await contract.callStatic.functionName(params);
console.log('Simulation successful:', result);
} catch (error) {
console.error('Simulation failed:', error.message);
}
- Manual Gas Limit:
// Set manual gas limit if estimation fails
const transaction = await contract.functionName(params, {
gasLimit: 200000 // Set manually
});
Network Congestion Issuesβ
Symptoms:
- High gas prices required
- Long confirmation times
- Frequent timeout errors
Solutions:
- Monitor Network Status:
// Check current network conditions
async function getNetworkStatus() {
const block = await provider.getBlock('latest');
const gasPrice = await provider.getGasPrice();
return {
blockNumber: block.number,
gasUsed: block.gasUsed,
gasLimit: block.gasLimit,
utilization: (block.gasUsed / block.gasLimit) * 100,
gasPrice: ethers.utils.formatUnits(gasPrice, 'gwei')
};
}
- Implement Retry Logic:
async function sendTransactionWithRetry(txParams, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const tx = await signer.sendTransaction(txParams);
return await tx.wait();
} catch (error) {
if (i === maxRetries - 1) throw error;
// Increase gas price for retry
txParams.gasPrice = txParams.gasPrice.mul(110).div(100);
await new Promise(resolve => setTimeout(resolve, 5000));
}
}
}
RPC Connection Issuesβ
Common Problems:
- Connection timeouts
- Rate limiting
- Provider errors
Solutions:
- Use Multiple RPC Endpoints:
const providers = [
'https://testnet-rpc.circlelayer.com'
];
class FallbackProvider {
constructor(urls) {
this.providers = urls.map(url => new ethers.providers.JsonRpcProvider(url));
this.currentIndex = 0;
}
async sendRequest(method, params) {
for (let i = 0; i < this.providers.length; i++) {
try {
return await this.providers[this.currentIndex].send(method, params);
} catch (error) {
this.currentIndex = (this.currentIndex + 1) % this.providers.length;
if (i === this.providers.length - 1) throw error;
}
}
}
}
- Implement Request Batching:
// Batch multiple requests to reduce RPC calls
async function batchRequests(requests) {
const batch = requests.map((req, index) => ({
jsonrpc: '2.0',
id: index,
method: req.method,
params: req.params
}));
const response = await fetch(rpcUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(batch)
});
return response.json();
}
MetaMask-Specific Issuesβ
Reset Accountβ
When experiencing persistent nonce issues:
1. MetaMask β Settings β Advanced β Reset Account
2. This clears transaction history and resets nonce counter
3. Does NOT affect your funds or private keys
Custom RPC Configurationβ
// MetaMask Custom Network Settings
Network Name: Circle Layer Testnet
RPC URL: https://testnet-rpc.circlelayer.com
Chain ID: 28525
Currency Symbol: CLAYER
Block Explorer: https://explorer-testnet.circlelayer.com
Enable Advanced Featuresβ
# Enable advanced MetaMask features
1. Settings β Advanced β Show hex data (ON)
2. Settings β Advanced β Customize transaction nonce (ON)
3. Settings β Advanced β Advanced gas controls (ON)
Monitoring Toolsβ
Transaction Status Checkingβ
// Monitor transaction status
async function monitorTransaction(txHash) {
console.log('Monitoring transaction:', txHash);
const checkStatus = async () => {
const tx = await provider.getTransaction(txHash);
if (!tx) {
console.log('Transaction not found in mempool');
return;
}
const receipt = await provider.getTransactionReceipt(txHash);
if (receipt) {
console.log('Transaction confirmed in block:', receipt.blockNumber);
console.log('Gas used:', receipt.gasUsed.toString());
console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed');
} else {
console.log('Transaction pending...');
setTimeout(checkStatus, 10000); // Check again in 10 seconds
}
};
checkStatus();
}
Gas Price Monitoringβ
// Track gas price trends
async function monitorGasPrices() {
const history = [];
setInterval(async () => {
const gasPrice = await provider.getGasPrice();
const gwei = ethers.utils.formatUnits(gasPrice, 'gwei');
history.push({
timestamp: Date.now(),
gasPrice: parseFloat(gwei)
});
// Keep last 24 hours of data
const oneDayAgo = Date.now() - 24 * 60 * 60 * 1000;
history.splice(0, history.findIndex(h => h.timestamp > oneDayAgo));
console.log('Current gas price:', gwei, 'gwei');
}, 60000); // Check every minute
}
Emergency Recoveryβ
Stuck Transaction Recoveryβ
// Cancel stuck transaction by replacing with higher gas
async function cancelTransaction(originalTx) {
const cancelTx = {
to: originalTx.from, // Send to yourself
value: 0,
gasPrice: originalTx.gasPrice.mul(110).div(100), // 10% higher
gasLimit: 21000,
nonce: originalTx.nonce // Same nonce to replace
};
return await signer.sendTransaction(cancelTx);
}
Account Recoveryβ
// Drain account if private key compromised
async function emergencyDrain(toAddress) {
const balance = await provider.getBalance(compromisedAddress);
const gasPrice = await provider.getGasPrice();
const gasLimit = 21000;
const gasCost = gasPrice.mul(gasLimit);
if (balance.gt(gasCost)) {
const amount = balance.sub(gasCost);
return await signer.sendTransaction({
to: toAddress,
value: amount,
gasPrice,
gasLimit
});
}
}
Best Practicesβ
Preventionβ
- Always check gas prices before sending transactions
- Use appropriate gas limits for complex contracts
- Monitor network congestion during high-traffic periods
- Keep backup RPC endpoints configured
- Test on testnet first before mainnet deployment
Transaction Managementβ
- Track nonces carefully when sending multiple transactions
- Implement proper error handling in your applications
- Use event monitoring for important transactions
- Set reasonable timeouts for transaction confirmation
- Have fallback strategies for failed transactions
This troubleshooting guide should help resolve most common transaction issues on Circle Layer. For complex problems, consider reaching out to the Circle Layer development community or support channels.