Skip to content

Public EVM JSON-RPC endpoints for BitBadges, supported methods, ethers.js, Hardhat and Foundry config, and running your own JSON-RPC node.

BitBadges exposes Ethereum-compatible JSON-RPC endpoints, so MetaMask, ethers.js, web3.js, Hardhat, and Foundry work unchanged. This page lists the URLs and the node settings behind them.

typescript
import { ethers } from "ethers";

// Connect to BitBadges mainnet EVM RPC
const provider = new ethers.JsonRpcProvider("https://evm-rpc.bitbadges.io");

// Get the current block number
const blockNumber = await provider.getBlockNumber();
console.log("Current block:", blockNumber);

// Get balance of an address
const balance = await provider.getBalance("0x0bc63cfe31d5218eb414b142c799e20964a54a1a");
console.log("Balance:", ethers.formatEther(balance), "BADGE");

Endpoints

NetworkTypeURLUse for
MainnetEVM JSON-RPChttps://evm-rpc.bitbadges.ioMetaMask, Hardhat, ethers.js (chain ID 50024)
MainnetCosmos RPChttps://rpc.bitbadges.ioCosmos SDK queries and broadcasts
MainnetCosmos REST/LCDhttps://lcd.bitbadges.ioREST queries
TestnetEVM JSON-RPChttps://evm-rpc-testnet.bitbadges.ioChain ID 50025. Offline as of September 2026
TestnetCosmos RPChttps://rpc-testnet.bitbadges.ioOffline
TestnetCosmos REST/LCDhttps://lcd-testnet.bitbadges.ioOffline

EVM tools use the evm-rpc*.bitbadges.io URLs. Cosmos tools (cosmjs, LCD queries, bb) use rpc*.bitbadges.io or lcd*.bitbadges.io. Mixing them up is the most common connection failure. Testnet status: Testnet.

web3.js works the same way:

javascript
// Using web3.js
const Web3 = require('web3');
const web3 = new Web3('https://evm-rpc.bitbadges.io');

// Get the current block number
const blockNumber = await web3.eth.getBlockNumber();
console.log("Current block:", blockNumber);

MetaMask

Settings > Networks > Add Network:

FieldMainnetTestnet
Network nameBitBadges MainnetBitBadges Testnet
RPC URLhttps://evm-rpc.bitbadges.iohttps://evm-rpc-testnet.bitbadges.io
Chain ID5002450025
Currency symbolBADGEBADGE
Block explorer URLhttps://explorer.bitbadges.io (optional)none

Supported JSON-RPC Methods

The endpoints serve the standard eth, net, and web3 namespaces, including:

GroupMethods
Accounteth_accounts, eth_getBalance, eth_getTransactionCount
Blocketh_blockNumber, eth_getBlockByNumber, eth_getBlockByHash
Transactioneth_sendTransaction, eth_sendRawTransaction, eth_getTransactionByHash, eth_getTransactionReceipt
Contracteth_call, eth_estimateGas
Eventeth_getLogs, eth_newFilter, eth_newBlockFilter, eth_newPendingTransactionFilter
Stateeth_getCode, eth_getStorageAt
Networketh_chainId, net_version, net_listening
Web3web3_clientVersion, web3_sha3

Deploy a Contract

typescript
import { ethers } from "ethers";
import * as fs from "fs";

async function deploy() {
  // Connect to BitBadges mainnet EVM RPC
  const provider = new ethers.JsonRpcProvider("https://evm-rpc.bitbadges.io");

  // Get deployer wallet
  const privateKey = process.env.PRIVATE_KEY || "";
  if (!privateKey) {
    throw new Error("PRIVATE_KEY environment variable required");
  }

  const wallet = new ethers.Wallet(privateKey, provider);
  console.log("Deployer address:", wallet.address);

  // Check balance
  const balance = await provider.getBalance(wallet.address);
  console.log("Balance:", ethers.formatEther(balance), "BADGE");

  // Deploy the Counter contract from the Hardhat artifact (no constructor args)
  const artifact = JSON.parse(
    fs.readFileSync("artifacts/contracts/Counter.sol/Counter.json", "utf8")
  );
  const contractFactory = new ethers.ContractFactory(
    artifact.abi,
    artifact.bytecode,
    wallet
  );

  const contract = await contractFactory.deploy();
  await contract.waitForDeployment();

  const address = await contract.getAddress();
  console.log("Contract deployed at:", address);
}

Interact with a Contract

typescript
import { ethers } from "ethers";

async function interactWithContract() {
  // Connect to BitBadges mainnet EVM RPC
  const provider = new ethers.JsonRpcProvider("https://evm-rpc.bitbadges.io");

  // Load contract
  const contractAddress = "0x5FbDB2315678afecb367f032d93F642f64180aa3"; // Counter deployed above
  const counterAbi = [
    "function count() view returns (uint256)",
    "function increment()"
  ];
  const contract = new ethers.Contract(contractAddress, counterAbi, provider);

  // Read from contract
  const value = await contract.count();
  console.log("Value:", value);

  // Write to contract (requires signer)
  const signer = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
  const contractWithSigner = contract.connect(signer);

  const tx = await contractWithSigner.increment();
  await tx.wait();
  console.log("Transaction confirmed:", tx.hash);
}

Hardhat

javascript
require("@nomicfoundation/hardhat-toolbox");

module.exports = {
  solidity: "0.8.20",
  networks: {
    bitbadges: {
      url: "https://evm-rpc.bitbadges.io",
      chainId: 50024,
      accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [],
    },
    bitbadgesTestnet: {
      url: "https://evm-rpc-testnet.bitbadges.io",
      chainId: 50025,
      accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [],
    },
  },
};

Foundry

toml
[rpc_endpoints]
bitbadges = "https://evm-rpc.bitbadges.io"
bitbadgesTestnet = "https://evm-rpc-testnet.bitbadges.io"

[profile.default]
rpc_endpoints = ["bitbadges", "bitbadgesTestnet"]

Rate Limits

The public endpoints may rate-limit to keep usage fair. For production traffic, run your own node, use a dedicated RPC provider, or cache and batch requests.

Run Your Own JSON-RPC Node

Follow Run a Node for the full node setup. The EVM-specific settings are in app.toml.

Set the EVM Chain ID

The default evm-chain-id (90123) is the local-dev value. On mainnet or testnet it makes every MetaMask transaction fail. Set it before starting the node.

toml
[evm]
# Set this to match your network's EVM chain ID
# Mainnet: 50024
# Testnet: 50025
# The default (90123) is the local-dev chain ID and causes MetaMask transaction failures on mainnet/testnet
evm-chain-id = 50024

net_version reports this value and EIP-155 signature verification uses it. If it does not match eth_chainId, wallets fail with an error like incorrect chain-id; expected 90123, got 50024. The "expected" value is whatever evm-chain-id is set to; 90123 is the local-dev default written by bb init.

Enable JSON-RPC

toml
[json-rpc]
enable = true
address = "0.0.0.0:8545"  # Use 127.0.0.1 for local only
ws-address = "0.0.0.0:8546"
api = ["eth", "net", "web3"]
enable-indexer = true

Configuration Reference

OptionDefaultDescription
enablefalseEnable JSON-RPC server
address127.0.0.1:8545HTTP listen address
ws-address127.0.0.1:8546WebSocket address
apieth,net,web3Enabled namespaces
enable-indexerfalseCustom tx indexer
evm-timeout5seth_call timeout
gas-cap25000000Gas limit for calls
txfee-cap1.0Max tx fee (BADGE)
filter-cap200Max active filters
block-range-cap10000Max block range for logs
logs-cap10000Max log results
batch-request-limit1000Max batch size
batch-response-max-size25000000Max response bytes
http-timeout30sHTTP timeout
http-idle-timeout2m0sHTTP idle timeout
max-open-connections0Max connections (0 = unlimited)
allow-unprotected-txsfalseAllow non-EIP155 txs
ws-origins127.0.0.1,localhostWebSocket allowed origins

Edit this page on GitHub