Skip to content

ABI Lookup & Decoding

Decode raw transaction calldata, function selectors, and event topic hashes against an ever-growing registry backed by 4byte.directory and Sourcify.

The ABI registry exists so that block-explorer-style decoders can answer "what does 0xa9059cbb... mean?" without each consumer maintaining their own selector table. Internally, CryptaChain runs nightly 4byte sync (selectors + event topics) and weekly Sourcify sync (verified-contract full ABIs per chain).

Endpoint map

EndpointReturnsUse
GET /v1/abi/function/{selector}Function signature for a 4-byte selectorDecode tx.input[:10]
GET /v1/abi/event/{topicHash}Event signature for a 32-byte topic-0Decode receipt logs
GET /v1/abi/contract/{chainId}/{address}Full verified ABI (Sourcify)Static analysis, codegen
POST /v1/abi/decodeOne-shot decode of {chainId, calldata}Tx-row enrichment

Selectors are 4 bytes / 10 hex chars including 0x (e.g. 0xa9059cbb). Topic hashes are 32 bytes / 66 hex chars including 0x. Both are case-insensitive in the request; addresses on contract lookups are lower-cased before the database key is built.

Example 1 — resolve a function selector

The first four bytes of a contract call's input are the function selector. Look it up:

bash
curl 'https://api.cryptachain.com/v1/abi/function/0xa9059cbb' \
  -H "X-API-Key: $CRYPTACHAIN_API_KEY"
python
import os, requests
r = requests.get(
    "https://api.cryptachain.com/v1/abi/function/0xa9059cbb",
    headers={"X-API-Key": os.environ["CRYPTACHAIN_API_KEY"]},
)
print(r.json())
typescript
const r = await fetch('https://api.cryptachain.com/v1/abi/function/0xa9059cbb', {
  headers: { 'X-API-Key': process.env.CRYPTACHAIN_API_KEY! },
});
console.log(await r.json());

Response:

json
{
  "selector":  "0xa9059cbb",
  "signature": "transfer(address,uint256)",
  "name":      "transfer",
  "source":    "4BYTE"
}

Unknown selector returns 404. The source is 4BYTE (community-submitted), SOURCIFY (verified-contract ABI), MANUAL (curated override), or OTHER.

Example 2 — resolve an event topic

Receipts come back with topics as an array; the first one (topic-0) is the event signature's keccak256 hash. Look it up:

bash
curl 'https://api.cryptachain.com/v1/abi/event/0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' \
  -H "X-API-Key: $CRYPTACHAIN_API_KEY"

Response:

json
{
  "topic_hash": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
  "signature":  "Transfer(address,address,uint256)",
  "name":       "Transfer",
  "source":     "4BYTE"
}

That hash is the canonical ERC-20 Transfer event. Every wallet integration ends up calling this thousands of times — cache aggressively on your end; CryptaChain also serves this from cache, but a local LRU of the top ~1000 hashes is essentially zero cost and saves a round-trip.

Example 3 — full contract ABI from Sourcify

For verified contracts, the full ABI is mirrored from Sourcify by chain ID + address:

bash
curl 'https://api.cryptachain.com/v1/abi/contract/1/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' \
  -H "X-API-Key: $CRYPTACHAIN_API_KEY"

Response (truncated):

json
{
  "chain_id": 1,
  "address":  "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
  "source":   "SOURCIFY",
  "abi": [
    { "type": "function", "name": "transfer",
      "inputs":  [{ "name": "to", "type": "address" }, { "name": "amount", "type": "uint256" }],
      "outputs": [{ "type": "bool" }],
      "stateMutability": "nonpayable" },
    { "type": "event", "name": "Transfer", "anonymous": false,
      "inputs": [
        { "indexed": true,  "name": "from",  "type": "address" },
        { "indexed": true,  "name": "to",    "type": "address" },
        { "indexed": false, "name": "value", "type": "uint256" }
      ] }
  ]
}

If the contract is not verified on Sourcify, the endpoint returns 404. Sourcify coverage is best on Ethereum / Polygon / Arbitrum / Optimism / Base; coverage on smaller L2s is patchy. For unverified contracts the function-selector endpoint is your fallback — even if no full ABI exists, the 4byte registry usually has the top-level call.

Example 4 — one-shot decode (selector + raw args)

If you have raw calldata from a transaction and want the function name plus args without picking it apart yourself, use the decode endpoint:

bash
curl -X POST 'https://api.cryptachain.com/v1/abi/decode' \
  -H "X-API-Key: $CRYPTACHAIN_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "chainId":  1,
    "calldata": "0xa9059cbb000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa9604500000000000000000000000000000000000000000000000000000000000003e8"
  }'

Response:

json
{
  "selector":  "0xa9059cbb",
  "signature": "transfer(address,uint256)",
  "name":      "transfer",
  "argsHex":   "000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa9604500000000000000000000000000000000000000000000000000000000000003e8",
  "status":    "OK"
}

Status values: OK (decoded), UNKNOWN_SELECTOR (no selector match — name and signature are null but argsHex is still extracted), MALFORMED (calldata is null / non-hex / shorter than 4 bytes).

MVP scope

The decode endpoint currently returns argsHex as a single 32-byte-aligned hex string — it does not yet pre-split args by ABI parameter type. Per-type unpacking (decoded address, uint256, etc.) is on the roadmap. If you need that today, hand off argsHex to your local ethers / web3.py decoder using the returned signature.

Common pitfalls

Selector collisions

4-byte selectors are not unique — keccak256(signature)[:4] can collide. The 4byte registry stores all known collisions, but the endpoint returns the most-popular one by usage count. If you care about disambiguation (audit / forensic work), fetch the verified contract's ABI via /v1/abi/contract/{chainId}/{address} first; the contract ABI is unambiguous.

Cache locally

The top 100 selectors account for >80% of mainnet traffic. Stash them in an in-memory LRU on your side — every cache hit saves a request and a credit.

Try it live

The /playground lets you call any ABI endpoint with your API key. Filter operations by tag ABI.

Next steps

  • Blockchain data endpoints — fetching transactions and receipts that produce calldata to decode
  • Wallet swaps — pre-decoded DEX swap events with token / amount fields already extracted

CryptaChain API — built by CryptaCount Luxembourg S.a r.l.