Plasma RPC Guide: USDT0 Deposits and Testnet

Connect to Plasma mainnet and testnet, detect USDT0 deposits with eth_getLogs and finalized blocks and see what zero-fee transfers mean for your backend.

Plasma RPC Guide: USDT0 Deposits and Testnet

Plasma mainnet is chain ID 9745 and Plasma testnet is chain ID 9746. Both speak standard Ethereum JSON-RPC, so ethers.js, viem, Foundry and Hardhat work unchanged once you point them at a Plasma endpoint. On BoltRPC the mainnet endpoint is https://endpoints.boltrpc.io/rpc/YOUR_API_KEY/plasma.

What makes Plasma different is not the RPC interface. It is the workload. Plasma is a Layer 1 built for stablecoin payments, so most of what developers build on it is payment backend code: watching deposit addresses, confirming USDT0 transfers and reconciling balances. This guide covers the network parameters, a tested deposit scanner, how finality works on Plasma, what the “zero-fee USDT” feature does and does not change for your backend and the production limits you will hit on public endpoints.

For endpoint setup and MetaMask settings, see the Plasma network page.

Plasma at a glance

MainnetTestnet
Chain ID9745 (0x2611)9746 (0x2612)
Network name in the official docsPlasma Mainnet BetaPlasma Testnet
Public RPC (rate limited)https://rpc.plasma.tohttps://testnet-rpc.plasma.to
Explorerhttps://plasmascan.tohttps://testnet.plasmascan.to
Gas tokenXPL (18 decimals)testnet XPL
Block timeabout 1 secondabout 1 second

Under the hood Plasma pairs two components. PlasmaBFT, a pipelined implementation of the Fast HotStuff consensus protocol, orders and finalizes blocks. A Reth-based execution client runs the EVM. The two talk over the Engine API, the same split Ethereum uses between its consensus and execution clients. You can see the execution side yourself: web3_clientVersion on the public endpoint returns a reth/... version string.

The block time is easy to check too. On 13 October 2026, 1,000 consecutive mainnet blocks spanned exactly 1,000 seconds. That number matters for everything below: Plasma produces 3,600 blocks an hour, twelve times as many as Ethereum.

Connect to Plasma

viem does not need a Plasma preset. Define the chain once and reuse it:

import { createPublicClient, http, defineChain } from "viem";

export const plasma = defineChain({
  id: 9745,
  name: "Plasma",
  nativeCurrency: { name: "XPL", symbol: "XPL", decimals: 18 },
  rpcUrls: {
    default: { http: ["https://endpoints.boltrpc.io/rpc/YOUR_API_KEY/plasma"] },
  },
  blockExplorers: {
    default: { name: "Plasmascan", url: "https://plasmascan.to" },
  },
  contracts: {
    multicall3: { address: "0xcA11bde05977b3631167028862bE2a173976CA11" },
  },
});

export const client = createPublicClient({ chain: plasma, transport: http() });

With ethers.js it is one line:

import { ethers } from "ethers";

const provider = new ethers.JsonRpcProvider(
  "https://endpoints.boltrpc.io/rpc/YOUR_API_KEY/plasma"
);

And a quick check from the shell:

curl https://endpoints.boltrpc.io/rpc/YOUR_API_KEY/plasma \
  -X POST \
  -H "Content-Type: application/json" \
  --data '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}'
# {"jsonrpc":"2.0","id":1,"result":"0x2611"}

Testnet

BoltRPC serves Plasma mainnet. For testnet work, use the public testnet RPC at https://testnet-rpc.plasma.to (chain ID 9746) and get test XPL from one of the faucets Plasma lists in its docs, such as openfaucet.org. The RPC methods, the Multicall3 address and the eth_getLogs range limit are the same on testnet. USDT0 is the exception: Plasma’s own testnet page lists testnet USD₮0 as still in development.

USDT0: the token your backend actually watches

On Plasma, USDT is the USDT0 token at 0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb. Two details catch teams coming from Ethereum:

  • It has 6 decimals, not 18. A transfer of 4990000 base units is 4.99 USDT0. Format with formatUnits(value, 6), never with formatEther.
  • Fees are paid in XPL. The token you are moving is not the token that pays gas, so a hot wallet that sends payouts needs an XPL balance as well as a USDT0 balance.

You can confirm both without trusting any document: call symbol() and decimals() on the contract and you get USDT0 and 6.

Detect USDT0 deposits with eth_getLogs

The standard way to credit deposits on any EVM chain is to read Transfer events where the to topic is one of your deposit addresses. On Plasma the pattern is the same, with two adjustments: read only finalized blocks, and size your block ranges for one-second blocks.

import { parseAbiItem, formatUnits } from "viem";
import { client } from "./plasma";

const USDT0 = "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb";
const transfer = parseAbiItem(
  "event Transfer(address indexed from, address indexed to, uint256 value)"
);

// Scan finalized blocks for USDT0 sent to any of your deposit addresses.
export async function scanDeposits(depositAddresses, fromBlock) {
  const { number: finalized } = await client.getBlock({ blockTag: "finalized" });
  const CHUNK = 1_000n; // about 17 minutes of Plasma blocks
  const deposits = [];

  for (let start = fromBlock; start <= finalized; start += CHUNK) {
    const end = start + CHUNK - 1n < finalized ? start + CHUNK - 1n : finalized;
    const logs = await client.getLogs({
      address: USDT0,
      event: transfer,
      args: { to: depositAddresses },
      fromBlock: start,
      toBlock: end,
    });
    for (const log of logs) {
      deposits.push({
        txHash: log.transactionHash,
        logIndex: log.logIndex,
        block: log.blockNumber,
        from: log.args.from,
        amount: formatUnits(log.args.value, 6), // USDT0 has 6 decimals
      });
    }
  }
  return { deposits, nextFromBlock: finalized + 1n };
}

Passing an array to args.to makes the node match any of the addresses in one request, so a few hundred deposit addresses cost one call per chunk, not one call per address. Store nextFromBlock and start the next run from it. Deduplicate on txHash plus logIndex before you credit anything, because a retried chunk returns the same logs again.

We ran this exact function against Plasma mainnet on 13 October 2026. It found a live USDT0 deposit and returned it with the right amount.

Credit from finalized blocks

On Ethereum, a deposit system usually waits a number of confirmations because a recent block can still be reorganized. Plasma’s documentation describes PlasmaBFT as finalizing blocks within seconds, without slot-based finality. The RPC exposes a standard finalized block tag, and when we compared latest and finalized on mainnet, the finalized block trailed the head by two blocks, about two seconds, in every sample.

That suggests a simple rule: credit deposits from the finalized tag instead of counting confirmations yourself. You rely on the chain’s own finality signal, and the wait is only a couple of seconds. Reading latest is fine for showing “payment detected” in a UI, as long as the balance is only credited once the block is finalized.

Block ranges and WebSocket

At 3,600 blocks an hour, a range that looks small on Ethereum covers very little time on Plasma. A 1,000-block window is about 17 minutes. Plasma’s public RPC rejects anything above 10,000 blocks per eth_getLogs call (eth_getLogs is limited to a 10,000 range), so a backfill of one day is at least nine requests, and more if a busy token returns large responses. Keep chunks small enough that a single response stays manageable, and retry a failed chunk rather than the whole range. Our guide to building an eth_getLogs pipeline covers checkpointing and retries in depth.

For live detection, subscribe instead of polling. A WebSocket subscription to logs filtered on the USDT0 address delivers each transfer as its block arrives, which matters when blocks land every second. BoltRPC serves Plasma over WebSocket at wss://endpoints.boltrpc.io/ws/YOUR_API_KEY/plasma. Keep the eth_getLogs scan running as the source of truth anyway, because a subscription misses whatever happens while it is reconnecting. The event monitoring guide shows how to combine the two.

Zero-fee USDT transfers: what changes for your backend

Plasma’s headline feature is free USDT transfers. It is worth being precise about what that means, because the official documentation describes it at different stages:

  • Plasma’s payments concepts page presents free USD₮ transfers and USD₮ as a whitelisted gas token as part of the network’s design.
  • Plasma’s network connection pages list XPL as the only live fee token, and its network fees page describes custom gas tokens, paid through a protocol-maintained paymaster, as being built.
  • Plasma’s testnet page says zero-fee USD₮0 transfers are in development on testnet.

In practice, assume your own transactions pay gas in XPL until Plasma confirms otherwise for your use case. If you want users to move USDT0 without holding XPL, look at the account abstraction providers Plasma lists for its mainnet, including Gelato Relay, thirdweb, ZeroDev and Safe, and check each one’s gas sponsorship options for your case.

The feature leans on a standard you can check today. USDT0 on Plasma implements EIP-3009 (transferWithAuthorization): a user signs an authorization off-chain and someone else submits it and pays the gas. Each authorization carries a nonce, and the contract records which nonces are used:

import { parseAbi } from "viem";
import { client } from "./plasma";

const usdt0Abi = parseAbi([
  "function authorizationState(address authorizer, bytes32 nonce) view returns (bool)",
]);

const used = await client.readContract({
  address: "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
  abi: usdt0Abi,
  functionName: "authorizationState",
  args: ["0xPayerAddress", "0xAuthorizationNonce"],
});
// true once the authorization has been executed or cancelled

None of this changes how you detect a deposit. Under EIP-3009, a transfer submitted by a relayer still makes the token emit the same Transfer(from, to, value) event, so the scanner above credits it like any other transfer. What changes is who sent the transaction: the event’s from is the payer, while the transaction’s from is the relayer. Credit on the event, never on the transaction sender.

Archive data and traces

Payment systems eventually need history: a balance at the end of a month, or proof of exactly what a contract did in a disputed payout. Both are archive reads. On BoltRPC, Plasma includes full archive state and the debug_* trace methods on the standard endpoint, so a historical eth_call and a transaction trace work without a second provider.

curl https://endpoints.boltrpc.io/rpc/YOUR_API_KEY/plasma \
  -X POST \
  -H "Content-Type: application/json" \
  --data '{"jsonrpc":"2.0","method":"debug_traceTransaction","params":["0xYourTxHash",{"tracer":"callTracer"}],"id":1}'

The callTracer result shows every internal call. For a relayed USDT0 transfer, that is how you see which contract actually moved the funds.

For bulk reads, Plasma has the standard Multicall3 contract at 0xcA11bde05977b3631167028862bE2a173976CA11, so viem’s multicall batches many balanceOf calls into one eth_call. viem only uses it when the chain definition names the contract, which is why the plasma definition above includes contracts.multicall3; without it, multicall throws. That is the cheapest way to reconcile many deposit addresses in one go.

Production checklist

  • Credit from finalized, show from latest.
  • Format USDT0 with 6 decimals everywhere: API responses, database columns and admin tools.
  • Keep XPL in every hot wallet that sends transactions, and alert on a low XPL balance, not only a low USDT0 balance.
  • Size log ranges for one-second blocks and checkpoint each chunk.
  • Pair a WebSocket subscription with a log scan, so a dropped connection never means a missed deposit.
  • Do not build on public RPC. Plasma’s own docs label rpc.plasma.to as rate limited and not for production systems. A deposit scanner that gets throttled shows up as payments that look stuck. Our explainer on RPC rate limits covers how to budget for this.

FAQ

What is the Plasma chain ID?

Plasma mainnet is chain ID 9745 (0x2611) and Plasma testnet is chain ID 9746 (0x2612). Both values come back from eth_chainId on the respective endpoint.

What is the Plasma RPC URL?

The public mainnet RPC is https://rpc.plasma.to, which Plasma rate limits and does not recommend for production. The BoltRPC mainnet endpoint is https://endpoints.boltrpc.io/rpc/YOUR_API_KEY/plasma, with WebSocket at wss://endpoints.boltrpc.io/ws/YOUR_API_KEY/plasma.

What is the USDT0 contract address on Plasma?

USDT0 on Plasma mainnet is 0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb. It has 6 decimals, so divide raw amounts by 1,000,000.

How many confirmations does a Plasma deposit need?

Credit deposits from the standard finalized block tag instead of counting confirmations. Plasma’s BFT consensus finalizes blocks within seconds, and in our mainnet measurements the finalized block trailed the head by two blocks, about two seconds.

Are USDT transfers on Plasma free?

Plasma is designed for free USD₮ transfers, but its connection pages list XPL as the only live fee token, its testnet page says zero-fee USD₮0 transfers are in development and custom gas tokens are described as being built. Assume your own transactions pay gas in XPL, and confirm the current status with Plasma before you design around free transfers.

Is there a Plasma testnet faucet?

Yes. Plasma’s docs list faucets for testnet XPL, including openfaucet.org. Testnet XPL pays for gas when you deploy contracts and send test transactions on chain ID 9746.

Start building on Plasma

BoltRPC serves Plasma with archive data, debug traces and WebSocket on the same key. Start with the Plasma endpoint, check request-unit costs on pricing or compare it with the other stablecoin rail we cover in the Tron USDT deposit guide.

Questions we get about this.

Content is for informational purposes only and does not constitute financial, legal or technical advice. Code examples and configurations are provided as-is. Verify against official documentation and test in your own environment before deploying to production.

More from the blog.

All articles →
Tron

Tron USDT Deposits: TRC-20 Scanning Guide

Detect USDT deposits on Tron: scan solidified blocks in one call each, decode TRC-20 logs to base58 addresses and budget energy for withdrawals.

Oct 13, 2026 · 9 min read
RPC

Sui gRPC Migration Guide: JSON-RPC to gRPC (2026)

Move a Sui app from deprecated JSON-RPC to gRPC: method mapping, SDK code, streams instead of polling and what each call costs, measured on a live endpoint.

Oct 11, 2026 · 17 min read
RPC

WebSocket vs Polling: Block Data Costs, Measured

A newHeads WebSocket stream against 1-second polling for 24 hours on one key: what each costs in request units, how much earlier the stream knows and how to pick the right feed per chain.

Sep 19, 2026 · 14 min read