Docs

eth_sendRawTransaction - Moonbase RPC Method

Submit signed transactions to Moonbase Alpha. Essential for broadcasting transactions for EVM dApp testing, XCM integration validation, and pre-mainnet deployment verification.

Submits a pre-signed transaction for broadcast to Moonbase Alpha.

Why Moonbase? Build on the Moonbeam testnet for risk-free EVM dApp development and deployment testing with free testnet tokens, full EVM compatibility, XCM testing capabilities, and identical feature set to Moonbeam mainnet.

When to Use This Method

The eth_sendRawTransaction method serves these key scenarios for Moonbeam developers, dApp testers, and teams validating cross-chain integrations:

  • Submit pre-signed transactions - Broadcast transactions that were signed offline or in a secure enclave, keeping private keys away from the RPC endpoint
  • Broadcast from offline signers - Air-gapped devices and hardware wallets first sign, then use this method to push the signed payload to Moonbase
  • Resubmit stuck transactions - Replace pending transactions with the same nonce and a higher gas price when the original is not being included in blocks
  • Deploy contracts programmatically - Submit contract creation transactions containing compiled bytecode and constructor arguments

Common Use Cases

1. Sign and Send an ETH Transfer

Build, sign, and broadcast a native ETH transfer with proper nonce management. The nonce must be retrieved from the node immediately before signing to avoid conflicts with pending transactions.

JavaScript
import { JsonRpcProvider, Wallet, parseEther, Transaction } from 'ethers';

const provider = new JsonRpcProvider('https://api-moonbase-alpha.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function sendNativeTransfer(to, amountInEth) {
  const tx = await wallet.sendTransaction({
    to: to,
    value: parseEther(amountInEth)
  });

  console.log('Transaction submitted:', tx.hash);

  const receipt = await tx.wait();
  console.log(`Confirmed in block ${receipt.blockNumber}, gas used: ${receipt.gasUsed}`);
  return receipt;
}

const receipt = await sendNativeTransfer('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', '0.01');

2. Resubmit a Stuck Transaction

If a pending transaction is not being confirmed due to low gas, submit a replacement with the same nonce and a higher gas price. The replacement must use an increased fee to be accepted by the Moonbase mempool.

JavaScript
import { JsonRpcProvider, Wallet, parseEther } from 'ethers';

const provider = new JsonRpcProvider('https://api-moonbase-alpha.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

async function speedUpTransaction(originalTxHash, gasMultiplier = 1.5) {
  const pendingTx = await provider.getTransaction(originalTxHash);
  if (!pendingTx) throw new Error('Transaction not found');

  const feeData = await provider.getFeeData();

  const replacementTx = {
    to: pendingTx.to,
    value: pendingTx.value,
    data: pendingTx.data,
    nonce: pendingTx.nonce,
    maxFeePerGas: feeData.maxFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    maxPriorityFeePerGas: feeData.maxPriorityFeePerGas * BigInt(Math.floor(gasMultiplier * 100)) / 100n,
    gasLimit: pendingTx.gasLimit
  };

  const tx = await wallet.sendTransaction(replacementTx);
  console.log('Replacement transaction:', tx.hash);
  return tx;
}

const newTx = await speedUpTransaction('0x...');

3. Deploy a Compiled Contract

Submit a contract deployment transaction containing the compiled bytecode. The to field is omitted for contract creation transactions; the contract address is deterministically derived from the sender address and nonce.

JavaScript
import { JsonRpcProvider, Wallet, ContractFactory } from 'ethers';

const provider = new JsonRpcProvider('https://api-moonbase-alpha.n.dwellir.com/YOUR_API_KEY');
const wallet = new Wallet('PRIVATE_KEY', provider);

const contractAbi = ['constructor(string memory name, uint256 supply)'];
const contractBytecode = '0x608060...';

async function deployContract(constructorArgs) {
  const factory = new ContractFactory(contractAbi, contractBytecode, wallet);
  const contract = await factory.deploy(...constructorArgs);

  console.log('Deployment tx:', contract.deploymentTransaction().hash);

  await contract.waitForDeployment();
  console.log('Contract deployed at:', await contract.getAddress());
  return contract;
}

const contract = await deployContract(['MyToken', 1000000]);

Best Practices

  • Always sign transactions client-side: never send private keys to any RPC endpoint, including https://api-moonbase-alpha.n.dwellir.com/YOUR_API_KEY
  • Track nonces carefully to avoid gaps or conflicts: retrieve the pending nonce from eth_getTransactionCount with "pending" tag before each signing
  • The return value is a transaction hash: use eth_getTransactionReceipt to poll for confirmation status
  • Handle replacement transactions correctly: the replacement must use the same nonce with a higher gas price
  • Use eth_estimateGas to set an appropriate gas limit before signing and sending

Code Examples

Error Handling

Error CodeMessageDescription
-32000Nonce too lowTransaction nonce already used
-32000Insufficient fundsAccount has insufficient balance
-32000Gas too lowGas limit insufficient
-32000Replacement underpricedGas price too low for replacement