⚠️Blast API (blastapi.io) ends Oct 31. Migrate to Dwellir and skip Alchemy's expensive compute units.
Switch Today →
Skip to main content

eth_sendRawTransaction

Sends a signed raw transaction to the Avalanche C-Chain network for execution.

When to Use This Method

eth_sendRawTransaction is essential for:

  • Hardware Wallet Integration - Submit transactions signed by hardware wallets
  • Offline Signing - Send transactions signed in secure offline environments
  • Custom Signing Logic - Implement custom transaction signing workflows
  • Batch Transactions - Submit multiple pre-signed transactions efficiently

Parameters

  1. Signed Transaction Data - DATA
    • The signed raw transaction data in RLP-encoded format
    • Format: 0x prefixed hexadecimal string
{
"jsonrpc": "2.0",
"method": "eth_sendRawTransaction",
"params": [
"0xf86c808504a817c800825208943535353535353535353535353535353535353535880de0b6b3a764000080258080"
],
"id": 1
}

Returns

DATA - 32-byte transaction hash, or error if transaction is invalid.

Implementation Examples

curl -X POST https://api-avalanche-mainnet-archive.n.dwellir.com/YOUR_API_KEY/ext/bc/C/rpc \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_sendRawTransaction",
"params": [
"0xf86c808504a817c800825208943535353535353535353535353535353535353535880de0b6b3a764000080258080"
],
"id": 1
}'

Response Example

Successful Response

{
"jsonrpc": "2.0",
"id": 1,
"result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}

Error Response

{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32000,
"message": "insufficient funds for gas * price + value"
}
}

Common Use Cases

1. Hardware Wallet Integration

Send transactions signed by hardware wallets:

// Simulate hardware wallet signing
async function sendHardwareWalletTransaction(hardwareSignedTx) {
try {
// Broadcast the pre-signed transaction
const txResponse = await provider.broadcastTransaction(hardwareSignedTx);

console.log('Hardware wallet transaction sent:', txResponse.hash);

// Monitor confirmation
const receipt = await txResponse.wait(1); // 1 confirmation

return {
success: true,
hash: txResponse.hash,
blockNumber: receipt.blockNumber,
gasUsed: receipt.gasUsed.toString()
};
} catch (error) {
return {
success: false,
error: error.message
};
}
}

2. Multi-Sig Wallet Operations

Handle multi-signature wallet transactions:

async function sendMultiSigTransaction(multiSigData, signatures) {
// Assume multi-sig contract interaction
const multiSigContract = new Contract(multiSigData.contractAddress, MULTISIG_ABI, provider);

// Encode the transaction data
const txData = multiSigContract.interface.encodeFunctionData('executeTransaction', [
multiSigData.to,
multiSigData.value,
multiSigData.data,
signatures
]);

// Create raw transaction
const tx = {
to: multiSigData.contractAddress,
data: txData,
gasLimit: 500000n,
gasPrice: await provider.getGasPrice()
};

// Sign with one of the owners
const wallet = new Wallet(multiSigData.ownerPrivateKey, provider);
const signedTx = await wallet.signTransaction(tx);

// Send raw transaction
const txResponse = await provider.broadcastTransaction(signedTx);
return txResponse.hash;
}

3. Gas Optimization Strategies

Implement dynamic gas pricing for optimal transaction fees:

async function sendOptimizedTransaction(privateKey, to, value) {
const wallet = new Wallet(privateKey, provider);

// Get current network conditions
const feeData = await provider.getFeeData();
const latestBlock = await provider.getBlock('latest');

// Calculate optimal gas price based on network congestion
const baseFee = latestBlock.baseFeePerGas || 0n;
const gasUsage = Number(latestBlock.gasUsed) / Number(latestBlock.gasLimit);

let priorityFee = feeData.maxPriorityFeePerGas || parseUnits('2', 'gwei');

// Adjust priority fee based on network congestion
if (gasUsage > 0.7) {
priorityFee = priorityFee * 150n / 100n; // +50% during congestion
} else if (gasUsage < 0.3) {
priorityFee = priorityFee * 80n / 100n; // -20% during low usage
}

const maxFeePerGas = baseFee * 2n + priorityFee;

const tx = {
to: to,
value: parseEther(value),
gasLimit: 21000n,
maxFeePerGas: maxFeePerGas,
maxPriorityFeePerGas: priorityFee,
type: 2
};

const signedTx = await wallet.signTransaction(tx);
const txResponse = await provider.broadcastTransaction(signedTx);

console.log('Optimized transaction sent with fees:', {
maxFeePerGas: formatUnits(maxFeePerGas, 'gwei') + ' gwei',
priorityFee: formatUnits(priorityFee, 'gwei') + ' gwei'
});

return txResponse;
}

4. Transaction Queue Management

Manage pending transactions with nonce handling:

class TransactionQueue {
constructor(provider, privateKey) {
this.provider = provider;
this.wallet = new Wallet(privateKey, provider);
this.pendingTxs = new Map();
this.currentNonce = null;
}

async initialize() {
this.currentNonce = await this.provider.getTransactionCount(this.wallet.address);
}

async queueTransaction(to, value, data = '0x') {
if (this.currentNonce === null) {
await this.initialize();
}

const tx = {
to: to,
value: value,
data: data,
gasLimit: 100000n,
gasPrice: await this.provider.getGasPrice(),
nonce: this.currentNonce
};

const signedTx = await this.wallet.signTransaction(tx);

try {
const txResponse = await this.provider.broadcastTransaction(signedTx);

this.pendingTxs.set(this.currentNonce, {
hash: txResponse.hash,
timestamp: Date.now()
});

this.currentNonce++;

return txResponse.hash;
} catch (error) {
throw new Error(`Failed to queue transaction: ${error.message}`);
}
}

async checkPendingTransactions() {
const confirmedNonce = await this.provider.getTransactionCount(this.wallet.address);

// Remove confirmed transactions
for (const [nonce, txData] of this.pendingTxs) {
if (nonce < confirmedNonce) {
console.log(`Transaction ${txData.hash} confirmed`);
this.pendingTxs.delete(nonce);
}
}

return {
confirmedNonce,
pendingCount: this.pendingTxs.size
};
}
}

Error Handling

Common errors and solutions:

Error CodeDescriptionSolution
-32000Insufficient fundsCheck account balance
-32000Nonce too lowUse correct nonce value
-32000Gas price too lowIncrease gas price
-32602Invalid transaction dataVerify RLP encoding
async function safeSubmitRawTransaction(signedTx, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const txResponse = await provider.broadcastTransaction(signedTx);
return { success: true, hash: txResponse.hash };

} catch (error) {
console.error(`Attempt ${i + 1} failed:`, error.message);

if (error.message.includes('nonce too low')) {
return { success: false, error: 'Transaction nonce is too low. Transaction may already be processed.' };
}

if (error.message.includes('insufficient funds')) {
return { success: false, error: 'Insufficient AVAX balance for transaction.' };
}

if (error.message.includes('gas price too low')) {
// Could implement gas price increase logic here
return { success: false, error: 'Gas price too low. Please increase gas price.' };
}

// Retry for other errors
if (i === maxRetries - 1) {
return { success: false, error: error.message };
}

await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1))); // Exponential backoff
}
}
}

Security Best Practices

1. Private Key Management

// Never expose private keys in client-side code
// Use environment variables or secure key management
const privateKey = process.env.PRIVATE_KEY;

// Validate private key format
function validatePrivateKey(key) {
if (!key || key.length !== 66 || !key.startsWith('0x')) {
throw new Error('Invalid private key format');
}
return key;
}

2. Transaction Validation

async function validateTransaction(signedTx) {
try {
// Parse the signed transaction
const parsedTx = Transaction.from(signedTx);

// Validate transaction parameters
if (!parsedTx.to || !parsedTx.value || !parsedTx.gasLimit) {
throw new Error('Invalid transaction parameters');
}

// Check if sender has sufficient balance
const senderBalance = await provider.getBalance(parsedTx.from);
const totalCost = parsedTx.value + (parsedTx.gasLimit * parsedTx.gasPrice);

if (senderBalance < totalCost) {
throw new Error('Insufficient balance');
}

return { valid: true };
} catch (error) {
return { valid: false, error: error.message };
}
}

Need help? Contact our support team or check the Avalanche documentation.