DEV Community

BlazePhoenix
BlazePhoenix

Posted on

Stop Calling Quote APIs. Make an eth_call

Look at your swap integration and find the line that fetches a quote.

There is a good chance it is an HTTPS request to someone else's server, with an API key in a header and a rate limit you discovered in production.

That line is the least decentralised thing in your stack.

What that dependency really costs

A quote API gives you three problems you did not ask for:

  1. Availability. Their outage is your outage. Their rate limit is your ceiling.
  2. Identity. An API key ties every request to an account. For a bot, a backend or an agent, that is a credential to store, rotate and leak.
  3. Verifiability. The response is a JSON number. Your code cannot tell a correct quote from a wrong one. It can only trust it.

The third one is the expensive one. You built on a chain so you would not have to trust a server, and then you put a server in front of your most important number.

The alternative: the quote is a view

If the quote is computed by a contract, fetching it is a read call. No account, no key, no vendor. Your RPC, your block, your result.

That is how BlazePhoenix works. (Disclosure: I am on the team.) Quotes are computed on-chain by the Quoter contract, and you can read them three ways:

  • a plain eth_call on your own RPC;
  • the SDK: npm i @blazephoenix/sdk;
  • the MCP server at https://blazephoenix.xyz/mcp, if the caller is an AI agent.

None of them needs an API key or a signup.

The shape of the call

Here is the pattern with viem. Treat the names in capitals as placeholders: the addresses and ABI for each chain come from the project docs, starting at llms.txt, or from the SDK.

import { createPublicClient, http, encodeFunctionData, decodeFunctionResult } from "viem";
import { base } from "viem/chains";

const client = createPublicClient({ chain: base, transport: http(MY_RPC_URL) });

const data = encodeFunctionData({
  abi: QUOTER_ABI,
  functionName: QUOTE_FUNCTION,
  args: QUOTE_ARGS, // tokenIn, tokenOut, amountIn, ...
});

// Pin the block so the result is reproducible.
const { data: raw } = await client.call({ to: QUOTER_ADDRESS, data, blockNumber: BLOCK });

const quote = decodeFunctionResult({ abi: QUOTER_ABI, functionName: QUOTE_FUNCTION, data: raw! });
Enter fullscreen mode Exit fullscreen mode

Three things changed compared to the REST version:

  • the request went to your node;
  • the result is deterministic for a given block: anyone running the same call gets the same answer;
  • there is nothing to authenticate.

What the call does not solve

A quote is still a snapshot. State can move before your swap lands. The difference here is what happens next: on BlazePhoenix the route is computed inside the transaction that executes it, and the swap reverts unless the recipient gets at least the minimum signed. Surplus from a better fill goes to the user. The protocol fee is 0.28 % per swap, a constant in the core contract.

And honestly: the protocol is pre-launch. The contracts are not yet audited by an external firm; an independent external audit is scheduled. If you integrate early, integrate the way you would integrate anything unaudited.

Try it

Swap one REST call for one eth_call in a test branch. Start from the guide at blazephoenix.xyz/llms.txt. Then delete an API key from your secrets manager, which is a nice feeling.

Top comments (0)