Skip to content

Typed smart contract query API for EVM

Stop wiring ABIs, proxies and Multicall3 by hand. Send one expression and get decoded, typed values back from Ethereum, Base, BNB Chain and Polygon.

cel.bind(d, token.decimals(), {
  "name":        token.name(),
  "symbol":      token.symbol(),
  "decimals":    string(formatUnits(d, 0)),
  "totalSupply": string(formatUnits(token.totalSupply(), d))
})

Free tier: 120 units/min, no credit card

It starts with one contract read.

Then the contract turns out to be a proxy, or the script that worked yesterday starts answering with 429. Every read you write by hand runs into the same four walls.

  • The proxy returns nothing

    You call the address everyone knows and get 0x back, because your ABI belongs to the implementation. Now you are reading EIP-1967 storage slots to work out which ABI goes with which address.

  • Batching still hits 429s

    Ten reads in a loop are ten RPC requests. Multicall3 fixes that until viem's default chunking splits the batch again and your provider rate limits eth_call anyway.

  • Setup for every project

    Each new project needs an RPC key, an ABI source and decoding code, repeated for every chain you read from.

  • Raw hex back

    eth_call returns hex. You decode it against the ABI, juggle BigInt and scale by decimals before the number means anything.

One expression. The wiring happens on our side.

Name the contract and the method. evmquery resolves the ABI, follows the proxy, batches the reads and returns typed JSON.

  1. The proxy returns nothing

    Proxies are followed for you

    EIP-1967, transparent and beacon proxies resolve to the implementation before the call runs, so you call the address users know.

    pool.getUserAccountData(user)
  2. Batching still hits 429s

    One round trip per chain

    Every independent read in an expression goes out as one Multicall3 call. Each response reports totalCalls and totalRounds, so you can check it.

    { "name": token.name(), "supply": token.totalSupply() }
  3. Setup for every project

    No RPC key, no ABI files

    Verified contracts on Ethereum, Base, BNB Smart Chain and Polygon work by address. One API key covers all four chains.

  4. Raw hex back

    Typed values back

    Results arrive decoded with their type, and structs as fields you dot into. formatUnits handles decimals inside the expression.

    formatUnits(usdc.balanceOf(owner), usdc.decimals())

What it does not do. evmquery only reads. It does not send transactions, it cannot batch two chains into one round trip, it does not index event history, and it does not resolve ENS names inside expressions. Keep viem or ethers for writes and logs.

Call it from curl or TypeScript.

One POST to /api/v1/query with your key in the x-api-key header. No SDK to install.

  1. curl

    Send the chain, the contracts and the expression. Context values are typed, so the owner address is declared as sol_address.

    curl -s -X POST https://api.evmquery.com/api/v1/query \
      -H "Content-Type: application/json" \
      -H "x-api-key: YOUR_API_KEY" \
      -d '{
        "chain": "evm_ethereum",
        "schema": {
          "contracts": { "usdc": { "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" } },
          "context": { "owner": "sol_address" }
        },
        "context": { "owner": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" },
        "expression": "formatUnits(usdc.balanceOf(owner), usdc.decimals())"
      }'
  2. TypeScript

    Plain fetch, so it runs anywhere fetch does. The response carries the value, its type and the block it was read at.

    const res = await fetch("https://api.evmquery.com/api/v1/query", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "x-api-key": process.env.EVMQUERY_API_KEY!,
      },
      body: JSON.stringify({
        chain: "evm_ethereum",
        schema: {
          contracts: { usdc: { address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" } },
          context: { owner: "sol_address" },
        },
        context: { owner: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" },
        expression: "formatUnits(usdc.balanceOf(owner), usdc.decimals())",
      }),
    });
    
    // result: { value, type }, meta: { blockNumber, totalCalls, totalRounds }
    const { result, meta } = await res.json();

Frequently asked questions

viem is a client library: you bring the RPC key, the ABI and the batching setup, and it runs in your process. evmquery is a hosted API: you send an expression and it resolves the ABI, follows proxies and batches the reads with Multicall3 on the server. You can keep viem for writes and signing and move only the reads.

Yes. Every independent read in one expression is grouped into a single Multicall3 call per chain. The response meta reports totalCalls and totalRounds, so you can see the batching on every request. Reads on different chains are separate requests.

There is no SDK. It is one HTTPS endpoint you call with fetch, so nothing new lands in your lockfile and nothing needs upgrading.

A query is one HTTPS request to evmquery plus one batched round trip to the chain. Actual time depends on the chain and the contract. The live console at the top of this page shows the server-measured time of a real query.

Values are decoded against the ABI of the verified implementation contract, and every response carries the block number it was read at, so you can check any value against your own node at that block.

Every query is a documented REST call with a plain JSON response. There is no proprietary SDK and no custom response format, so moving back to viem or ethers means re-implementing the same calls, not unwinding a framework.

The data is the same public chain state you can read with a free RPC key. What evmquery removes is the work around it: ABI lookup, proxy resolution, batching and decoding. The free tier needs no credit card, so you can measure that trade on real code first.

Ethereum, Base, BNB Smart Chain and Polygon today, with more chains on the roadmap.

Stop writing ABI resolution and proxy detection by hand.

Free tier: 120 units/min, no credit card.

No credit card · 120 units/min free · REST, MCP or n8n