Develop with ITX

The ITX API is implemented as an extension of the standard Ethereum JSON-RPC API - it follows the same design principles and you can use it from your favorite programming language and Web3 framework. Your ITX API traffic is counted towards your Ethereum subscription's daily limits and rate limits described here.
The deposit system is managed by an on-chain contract which is deployed at the same address on all supported Ethereum public networks. The address is referenced by the ENS entry itx.eth.
ITX is not supported on the Polygon Mumbai testnet.
The code snippets in this walkthrough are written in JavaScript using the ethers.js library, but you're not limited to these programming choices.
You can find a full collection of scripts that showcase an end-to-end interaction with ITX in this GitHub repository.

Set up the ITX provider

All ITX-specific JSON-RPC methods can be accessed via the ethers.js built-in InfuraProvider class, using your dedicated Infura URL.
const { ethers } = require('ethers')
const itx = new ethers.providers.InfuraProvider(
'mainnet', // or 'goerli'

Create a signer account

This is as simple as generating an Ethereum-compatible private key you have exclusive control over. You will use the private key for authenticating your ITX transaction requests, and its corresponding public address for identifying your ITX gas tank.
const signer = new ethers.Wallet('YOUR_PRIVATE_KEY', itx)

Check your ITX gas tank

Let's check if your signing account has any gas tank balance registered with ITX. You can do this by calling the relay_getBalance method:
async function getBalance() {
response = await itx.send('relay_getBalance', [signer.address])
console.log(`Your current ITX balance is ${response.balance}`)
Full script to read your ITX balance here.

Make a deposit

You can make a deposit by sending Ether to the ITX contract. This contract is deployed at the same address on all public Ethereum networks.
Your deposit will be registered after 10 block confirmations.
async function deposit(signer) {
const tx = await signer.sendTransaction({
// ITX deposit contract (same address for all public Ethereum networks)
to: '0x015C7C7A7D65bbdb117C573007219107BD7486f9',
// Choose how much ether you want to deposit to your ITX gas tank
value: ethers.utils.parseUnits('0.1', 'ether')
// Waiting for the transaction to be mined
await tx.wait()
Full script to make an ITX deposit here.

Sign a relay request

The format of an ITX relay request is:
"to": "<target contract address>",
"data": "<encoded contract call>",
"gas": "<upper limit for gas spent>",
"schedule": "<'fast' or 'slow'>"
ITX generates a unique identifer for every relay request (called the relay transaction hash), computed by taking the keccak256 hash of the ABI argument encoded list of variables [to, data, gas, chainId, schedule] with types address, bytes, uint, uint, string (in that order)
relayTransactionHash = keccak256(
['address', 'bytes', 'uint', 'uint', 'string'],
[to, data, gas, chainId, schedule]
The relay transaction hash is then signed by using the standard Ethereum message signing process:
signature = EcdsaSignMessage(
"\x19Ethereum Signed Message:\n",
The signature generation logic is already implemented in most web3-compatible libraries, so, for example, if you're using ethers.js, you only need to pass in the relay transaction hash to the signMessage function, as shown in the following example.
async function signRequest(tx) {
const relayTransactionHash = ethers.utils.keccak256(
['address', 'bytes', 'uint', 'uint', 'string'],
[,, tx.gas, 5, tx.schedule] // Goerli chainId is 5
return await signer.signMessage(ethers.utils.arrayify(relayTransactionHash))

Send your first transaction

Now that you're able to generate signatures that authenticate your relay requests, you're ready to call the relay_sendTransaction method and instruct ITX to relay your requests to the Ethereum network.
ITX supports any type of transaction that doesn't directly carry Ether (i.e. whose value field is set to 0). You can use it for deploying your own contracts or calling arbitrary contract methods, and you can also use it for enabling your users to interact with your Dapp, even if they don't hold any Ether. However, you cannot use ITX to send Ether without the intermediation of a wallet contract.
Only send ITX using accounts for which you own the private keys, in order to fund your ITX gas tank. Don't send transactions from hosted wallets (for example, Coinbase).
We'll send a transaction that calls the the echo method of a simple demo contract. This contract is deployed at the same address on all supported Ethereum networks.
relay_sendTransaction requires two parameters:
  • The relay request object
  • Your signature
async function callContract() {
const iface = new ethers.utils.Interface(['function echo(string message)'])
const data = iface.encodeFunctionData('echo', ['Hello world!'])
const tx = {
to: '0x6663184b3521bF1896Ba6e1E776AB94c317204B6',
data: data,
gas: '100000',
schedule: 'fast'
const signature = await signRequest(tx)
const relayTransactionHash = await itx.send('relay_sendTransaction', [tx, signature])
console.log(`ITX relay hash: ${relayTransactionHash}`)
return relayTransactionHash

Check if the relay request is mined

Unlike eth_sendRawTransaction, the relay request returns a relayTransactionHash instead of an Ethereum transaction hash. The ITX service is responsible for taking your relay request, packing it into an Ethereum transaction, and then gradually increasing the fee until the transaction is mined. The Ethereum Transaction hash is changed every time the fee is bumped and the previous hash is no longer reliable for tracking its status.
We provide a new RPC call relay_getTransactionStatus that returns the list of Ethereum Transaction hashes which have been broadcast for the supplied relayTransactionHash. You can then check client-side whether any of the transaction hashes were mined.
const wait = (milliseconds) => {
return new Promise((resolve) => setTimeout(resolve, milliseconds))
async function waitTransaction(relayTransactionHash) {
let mined = false
while (!mined) {
const statusResponse = await itx.send('relay_getTransactionStatus', [relayTransactionHash])
if (statusResponse.broadcasts) {
for (let i = 0; i < statusResponse.broadcasts.length; i++) {
const bc = statusResponse.broadcasts[i]
const receipt = await itx.getTransactionReceipt(bc.ethTxHash)
if (receipt && receipt.confirmations && receipt.confirmations > 1) {
mined = true
return receipt
await wait(1000)
And that's it! You have just sent a relay request via the ITX service. A full code sample is available in our demo repository.