n8n is the best tool in 2026 for gluing internal workflows together. It handles the nine boring parts of an automation — schedules, credentials, branching, retries, notifications — so you can focus on the one interesting part. Everything except one thing: reading live data from a smart contract.
Until recently, anyone who needed that had to fall back on the HTTP Request node, hand-encode an eth_call, remember to hex-prefix the function selector, parse a raw bytes response, and then — if they were lucky — pipe the result into a Code node for decoding. Fifteen minutes per recipe. Multiply by every chain. Multiply by every contract.
The evmquery community node collapses that into a single node: pick a chain, paste a contract address, write one expression, click execute.
TL;DR
Install the n8n-nodes-evmquery community node, drop an evmquery node into any workflow, and read from any contract on Ethereum, Base, or BNB Smart Chain. Works in n8n Cloud and self-hosted. Free tier gives you 2,000 credits/month.
Why read contracts in an automation?
The obvious stuff first. If you already run n8n for internal tooling, any of these pay for themselves within a day:
- Treasury alerts. Ping Slack when your ops wallet drops below a threshold on any chain.
- Position monitors. Watch your Aave / Morpho / Euler health factor and alert before you get liquidated.
- DAO tracking. Notify the team when a Governor proposal moves from
ActivetoSucceeded. - Market triggers. React when a token’s price or an AMM pool’s reserves cross a boundary.
- Compliance snapshots. Capture vault totals at end-of-day for reporting.
None of these need Solidity. They need reads, on a schedule, with conditional branching. That’s n8n’s entire job — plus one extra node.
Installing the community node
n8n supports community nodes natively since v0.187. Two paths:
n8n Cloud / Desktop: Settings → Community Nodes → Install → paste n8n-nodes-evmquery → Install. The node appears in the node picker under “evmquery.”
Self-hosted: npm install n8n-nodes-evmquery inside your .n8n/custom directory, or add it to your package.json and rebuild the container. Restart n8n. Same picker entry.
You’ll also need credentials. In n8n: Credentials → New → evmquery API → paste your key. Grab one from the dashboard — the free tier covers the three recipes below with room to spare.
Recipe 1: ERC-20 balance alert
Goal: Post to Slack when your ops wallet drops below 10,000 USDC on Base.
The workflow is four nodes:
- Schedule Trigger — every 5 minutes.
- evmquery — Operation: Execute Query, read the USDC balance.
- IF — compare result to threshold.
- Slack — send message on the “true” branch.
The evmquery node config:
Operation: Execute Query
Chain: Base
Contracts:
Token = 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
Context:
ops : sol_address = 0xYourOpsWalletHere
Expression:
formatUnits(Token.balanceOf(ops), Token.decimals())
The node returns the decoded value plus block metadata:
{ "value": 9832.11, "type": "double", "block": 21034992 }
Wire {{ $json.value }} into the IF node, compare to 10000, and you have a working treasury alarm. Total build time: 4 minutes.
The same shape works for any view function: name the contract, declare your inputs as typed context, and write a single Smart Expression Language line — Token.balanceOf(ops) for raw integers, formatUnits(Token.balanceOf(ops), Token.decimals()) for a human number, or solAddress("0x…").balance() for native ETH.
Recipe 2: DAO proposal state watcher
Goal: Notify a Discord channel when a Governor proposal transitions from Active to Succeeded, Defeated, or Queued.
This one needs a tiny bit of state. We’ll store the last-seen state in n8n’s built-in data store (n8n-nodes-base.set) or in a Postgres row if you have one handy.
Workflow:
- Schedule Trigger — every minute.
- evmquery — Operation: Execute Query, read current proposal state.
- Get Previous State — from your data store.
- IF — compare.
- Discord + Update Store — notify on change and update the stored value.
The Governor state(uint256) function returns an enum (0..7). The evmquery node returns the numeric value; we map it client-side:
Operation: Execute Query
Chain: Ethereum
Contracts:
Governor = 0xYourGovernorHere
Context:
proposalId : sol_int = 123
Expression:
Governor.state(proposalId)
In a Code node (or a Set node with an expression):
const STATES = [
"Pending",
"Active",
"Canceled",
"Defeated",
"Succeeded",
"Queued",
"Expired",
"Executed",
];
return { state: STATES[$json.value] ?? "Unknown" };
The IF node compares state to the stored lastState. The Discord message only fires on actual transitions.
The trick here — and the reason doing this on raw RPC is painful — is that the evmquery node handles the proxy unwinding for Governors that use OpenZeppelin’s upgradeable pattern. You don’t have to know it’s a proxy; you just call state(uint256).
Recipe 3: NFT floor monitor
Goal: Slack alert when the OpenSea floor for a collection drops below a target, correlated with onchain totalSupply (so you know the collection hasn’t been rug-burned).
This one uses one batched contract read, then a market call.
Workflow:
- Schedule Trigger — every 15 minutes.
- evmquery —
totalSupply()andownerOf(1)on the NFT contract, returned as one map. - HTTP Request — OpenSea floor endpoint.
- Merge — join the two results.
- IF — floor below threshold AND supply unchanged.
- Slack — alert.
The reason totalSupply() is in the loop: if the collection was migrated, rugged, or had a major mint, the floor price means something different. Your alarm should care.
Operation: Execute Query
Chain: Ethereum
Contracts:
Collection = 0xBd3531dA5CF5857e7CfAA92426877b022e612cf8
Expression:
{
"supply": Collection.totalSupply(),
"tokenOneOwner": Collection.ownerOf(solInt(1))
}
(Substitute the contract for the collection you actually care about. The two reads are independent, so the engine batches them into one Multicall3 round and returns a typed map.)
Batching is automatic
The evmquery node batches reads to the same chain into a single Multicall3 call under the hood. Two reads or two hundred, it’s one request on the wire. You don’t have to structure your workflow differently to get the efficiency — it just happens.
Comparing to the HTTP Request approach
The HTTP Request node can do all of this. We’ve built the exact same recipes both ways, and the line count in the JSON export tells the story: the raw-RPC version of Recipe 1 is 4 nodes including a Code node with 30 lines of ABI encoding. The evmquery version is 4 nodes with no Code node at all.
The bigger cost is the next time you want to add a contract. With the HTTP Request approach, you copy the Code node and adjust the selector, the ABI, the decoding. With the evmquery node, you change one field.
If you’re running three automations, either approach is fine. If you’re running thirty, the abstraction pays for itself in about a week.
Mistakes that trip people up
- Chain names. The dropdown lists Ethereum, Base, and BNB Smart Chain — those are the three networks the engine currently serves. The corresponding ids (if you ever set the node via an expression) are
evm_ethereum,evm_base, andevm_bnb_mainnet. More chains land progressively; check the dashboard for the latest list. - Decimals. ERC-20 decimals vary (USDC is 6, WETH is 18). Use
formatUnits(Token.balanceOf(holder), Token.decimals())to scale to a human number; if you see a result that’s ~12 orders of magnitude off, you forgot theformatUnitswrap. - Token IDs. Bare integer literals are 64-bit
intin SEL; ERC-721 token ids areuint256. Wrap them withsolInt(...)—Collection.ownerOf(solInt(7890)), notCollection.ownerOf(7890). - Rate limits on the free tier. 2,000 credits per month is generous for one or two recipes on 5-minute schedules, but a 10-second-interval scanner will burn through it. A single contract read typically costs 1–2 credits, so budget accordingly and watch the dashboard.
Next steps
- The automation landing page has a deeper reference for the node, including the full expression language.
- Reading the same contracts from code? The Multicall3 guide shows the primitive that the n8n node is using under the hood.
- Automating with AI agents instead of n8n? The MCP server post is the Claude/Cursor equivalent.