Docs

eth_sendRawTransaction - Bittensor RPC Method

Submit signed transactions to Bittensor. Essential for broadcasting transactions for decentralized AI inference, subnet-specific AI models, TAO staking, and cross-subnet AI collaboration.

Submits a pre-signed transaction for broadcast to Bittensor.

Why Bittensor? Build on the decentralized machine intelligence network built around subnets, TAO staking, and validator-miner coordination with Yuma Consensus, subnet-based specialization, dual Substrate and EVM surfaces, and onchain incentive coordination.

When to Use This Method

The eth_sendRawTransaction method serves these key scenarios for AI/ML developers, subnet operators, and teams building decentralized machine learning applications:

  • 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 Bittensor
  • 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-bittensor-mainnet.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('0x156e431cc96e0e3b70c97214d869c9bc4b5bbd21', '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 Bittensor mempool.

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

const provider = new JsonRpcProvider('https://api-bittensor-mainnet.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-bittensor-mainnet.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-bittensor-mainnet.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