0x Documentation
Working in the Testnet
0x API and 0x Protocol can be accessed on the Ropsten testnet, or by forking Ethereum mainnet into your own testnet.

Using Ropsten

Swapping tokens with 0x API

A hosted 0x API for the Ropsten testnet is available at https://ropsten.api.0x.org which offers a subset of DEX sources available on Ethereum mainnet.
To view the currently supported sources on Ropsten refer to /swap/v1/sources, at the time of writing this guide 0x, Curve, Kyber, Mooniswap, SushiSwap, Uniswap V1, Uniswap V2 and Uniswap V3 are supported. The token you want to use for testing must have liquidity on at least one of these sources.

Example tokens available on Ropsten

Performing a swap on Ropsten

For general information about the /swap endpoints see 0x API Swap​
Example code for swapping 0.1 ETH for DAI on Ropsten using Metamask

Interacting with Limit Orders on Ropsten

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

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 Ropsten 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(
// 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);
`ETH: ${etherBalanceBefore.toString()} -> ${etherBalanceAfter.toString()}`
`DAI: ${daiBalalanceBefore.toString()} -> ${daiBalanceAfter.toString()}`
For more detailed information please refer to our mainnet fork example project​
Copy link
On this page
Using Ropsten
Forking mainnet Ethereum