Working in the Testnet
Available Testnets​
0x Swap API testnets can be accessed from:
- Ethereum (Sepolia): https://sepolia.api.0x.org/
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​
Symbol | Address |
---|---|
WETH | 0xfff9976782d46cc05630d1f6ebab18b2324d6b14 |
UNI | 0x1f9840a85d5af5bf1d1762f925bdaddc4201f984 |
LINK | 0x779877a7b0d9e8603169ddbd7836e478b4624789 |
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.
Getting Testnet Funds​
- List of Sepolia Faucets
- Sepolia Faucet
- Sepolia POW Faucet
- Paradigm MultiFaucet - Funds a wallet with ETH, WETH, DAI, and NFTS across 4 testnets
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 11155111.
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 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