Skip to main content

Working in the Testnet

Available Testnets

0x Swap API testnets can be accessed from:

These testnets offers a subset of DEX sources available on Ethereum mainnet. To view the currently supported sources on each network, you can use the /sources endpoint.

Alternatively, you can also fork Ethereum mainnet into your own testnet.

Available Token Pairs

To view all currently supported sources on each network, you can use the /sources endpoint.

Note the following:

  • Testnet liquidity is more limited than on mainnet
  • Liquidity sources are also different between mainnets and testnets
  • Not all pairs on mainnet are deployed on testnet, so the token pair availability is more limited

Be aware that token you want to use for testing must have liquidity on at least one of the liquidity /sources; otherwise, you will receive an error.

Therefore, we recommend the following ways to find available testnet tokens:

  • See our recommended lists of tokens for Sepolia below
  • Using a blockchain explorer, look through transactions that have gone through the 0x Exchange Proxy contract for your desired network, and check the token pairs that show up in "Tokens Transferred". See examples for how to do this for Sepolia below.

Sepolia

At the time of writing this guide the following liquidity sources are supported on Sepolia: MultiHop and Uniswap_V3.

In addition, only certain pairs are deployed on testnests and available for testing. At the time of writing, the recommended testing pair is WETH <> UNI deployed by Uniswap on Sepolia.

Example tokens available on Sepolia

SymbolAddress
WETH0xfff9976782d46cc05630d1f6ebab18b2324d6b14
UNI0x1f9840a85d5af5bf1d1762f925bdaddc4201f984
LINK0x779877a7b0d9e8603169ddbd7836e478b4624789

To find additional example pairs, you can use Etherscan and look at token pairs for transactions that have gone through the the 0x Exchange Proxy contract on Sepolia, 0xdef1c0ded9bec7f1a1670819833240f027b25eff.

Example: The following is transaction that went through 0x Exchange Proxy on Sepolia. See addresses for the "ERC-20 Tokens Transferred" below. Sepolia tokens example

Getting Testnet Funds

Interacting with Limit Orders on Sepolia

Refer to @0x/contract-addresses to find the addresses of the latest deployment on Sepolia and then follow our limit order related guides below, using the Sepolia contract addresses, and chain id 5.

Forking mainnet Ethereum

If you need to test composability between multiple protocols, or the liquidity source/token that you want to test is not available on Sepolia then using a tool like Ganache or Hardhat to create your own private fork of the Ethereum mainnet can be helpful.

When forking Ethereum mainnet all current Ethereum state as of the block that you fork will also be available in your private fork, all contracts addresses, and balances tokens will be exactly like the Ethereum mainnet. The main advantage with this is that you can test quotes from our hosted Ethereum mainnet 0x API on your private forked network without having to run any additional infrastructure or spend any real funds on test transactions.

Forking Ethereum mainnet with Hardhat

This guide assumes that you already have a working Hardhat project, if not please refer to the official Hardhat Getting Started Guide.

Configuring Hardhat to create a private fork

First, you need to add a hardhat network in your Hardhat config file.

// hardhat.config.ts
// ...
const config = {
solidity: "0.8.4",
networks: {
hardhat: {
forking: {
url: RPC_URL, // This should be your Alchemy/Infura RPC URL
},
},
},
};
// ...

Now, for your tests, you can find an account on Ethereum mainnet with the appropriate balances required for the swaps that you want to test locally, then using the hardhat_impersonateAccount you can act as that account on your private fork. You can then request a valid quote for that account from Ethereum mainnet 0x API and submit the transaction on your private fork. Keep in mind that you may need to set allowances if you are trading with other tokens than Ethereum.

Example test swapping 1 ETH for DAI using an Ethereum mainnet 0x API quote

import { expect } from "chai";
import { ethers, network } from "hardhat";
// node-fetch version 2 needs to be added to your project
import fetch from "node-fetch";

const ONE_ETHER_BASE_UNITS = "1000000000000000000"; // 1 ETH
const MINIMAL_ERC20_ABI = [
"function balanceOf(address account) external view returns (uint256)",
];

describe("0x API integration", function () {
it("it should be able to use a 0x API mainnet quote", async function () {
// Quote parameters
const sellToken = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"; // ETH
const buyToken = "0x6b175474e89094c44da98b954eedeac495271d0f"; // DAI
const sellAmount = ONE_ETHER_BASE_UNITS;
const takerAddress = "0xab5801a7d398351b8be11c439e05c5b3259aec9b"; // An account with sufficient balance on mainnet

const quoteResponse = await fetch(
`https://api.0x.org/swap/v1/quote?buyToken=${buyToken}&sellAmount=${sellAmount}&sellToken=${sellToken}&takerAddress=${takerAddress}`
);
// Check for error from 0x API
if (quoteResponse.status !== 200) {
const body = await quoteResponse.text();
throw new Error(body);
}

const quote = await quoteResponse.json();

// Impersonate the taker account so that we can submit the quote transaction
await network.provider.request({
method: "hardhat_impersonateAccount",
params: [takerAddress],
});

// Get a signer for the account we are impersonating
const signer = await ethers.getSigner(takerAddress);
const dai = new ethers.Contract(buyToken, MINIMAL_ERC20_ABI, signer);

// Get pre-swap balances for comparison
const etherBalanceBefore = await signer.getBalance();
const daiBalalanceBefore = await dai.balanceOf(takerAddress);

// Send the transaction
const txResponse = await signer.sendTransaction({
from: quote.from,
to: quote.to,
data: quote.data,
value: ethers.BigNumber.from(quote.value || 0),
gasPrice: ethers.BigNumber.from(quote.gasPrice),
gasLimit: ethers.BigNumber.from(quote.gas),
});
// Wait for transaction to confirm
const txReceipt = await txResponse.wait();

// Verify that the transaction was successful
expect(txReceipt.status).to.equal(1, "successful swap transaction");

// Get post-swap balances
const etherBalanceAfter = await signer.getBalance();
const daiBalanceAfter = await dai.balanceOf(takerAddress);

console.log(
`ETH: ${etherBalanceBefore.toString()} -> ${etherBalanceAfter.toString()}`
);
console.log(
`DAI: ${daiBalalanceBefore.toString()} -> ${daiBalanceAfter.toString()}`
);
});
});

Hardhat Example Project

For more detailed information please refer to our mainnet fork example project