Testing
The Qiguard API runs on mainnets only; there are no testnets. Test in three steps: unit tests against recorded answers, a local fork for the full flow, then small trades on Base.
1. Recorded answers
Record real answers once (price, quote, errors) and replay them in your unit tests. Every answer is plain JSON with a zid; the API reference lists every field. The SDK takes a fetch option, so a test can pass its own:
import { QiguardClient } from './qiguard-sdk.mjs'; // https://docs.qiguard.com/sdk/qiguard-sdk.mjs
const recorded = { '/swap/chains': { chains: [{ chainId: 8453, chainName: 'Base' }], zid: '0x5f1c9a7e2b44d0c3a1e8f6b2' } };
const qg = new QiguardClient({
apiKey: 'qg_sk_test',
fetch: async (url) => new Response(JSON.stringify(recorded[new URL(url).pathname]), { status: 200 }),
});
2. Local fork
Run the full swap flow on a fork of Base, with a wallet you control on the fork. The example uses Foundry (anvil, cast).
# 1. fork Base at the latest block
anvil --fork-url https://mainnet.base.org --port 8545
# 2. act as a wallet that holds USDC on Base
export TAKER=0xYourTestWallet
cast rpc anvil_impersonateAccount $TAKER --rpc-url http://127.0.0.1:8545
# 3. quote with taker=$TAKER against the live API (quotes are read from mainnet)
curl -s "https://api.qiguard.com/swap/allowance-holder/quote?chainId=8453&sellToken=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913&buyToken=0x4200000000000000000000000000000000000006&sellAmount=25000000&taker=$TAKER" \
-H "qg-api-key: $QG_API_KEY" -H "qg-version: v1" > quote.json
# 4. approve the settlement contract for the exact amount on the fork
cast send 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 "approve(address,uint256)" 0x67433187Db1e57f66E88880b6Be833f6759362b1 25000000 \
--from $TAKER --unlocked --rpc-url http://127.0.0.1:8545
# 5. quote again (step 3), then send transaction.data to transaction.to on the fork
cast send $(jq -r .transaction.to quote.json) $(jq -r .transaction.data quote.json) \
--from $TAKER --unlocked --gas-limit $(jq -r .transaction.gas quote.json) --rpc-url http://127.0.0.1:8545
Fork again shortly before each run: the quote is priced at the current mainnet block and carries a 120-second deadline by default (deadlineSeconds).
3. Small trades on Base
Base has low gas costs. A trade of a few dollars of USDC to WETH tests the real path end to end, with the approval, the transaction and the dashboard usage graph. Gasless trades need at least 10 USD.
Gasless before it is switched on
Until gasless is switched on for a chain, POST /gasless/submit answers 503 GASLESS_NOT_ENABLED (data.reason gasless_not_enabled). Everything before the submit works: the gasless price and quote, the Permit2 approval and the signature. Handle the 503 in your flow, and read GET /gasless/chains to see when enabled turns true.
Checks worth automating
- Pairs: every pair has an anchor on one side (
GET /tokens). issues.allowanceandissues.balanceare handled before sending.- The quote is refreshed after an approval (
expiresAt). 429answers wait forRetry-After.warnings[]is logged.
This page as Markdown: testing.md. All pages for tools: llms.txt.