A simple-to-use EVM chain indexing made for Web3 applications.
- Synchronize contract logs
- Serve the logs via GraphQL, including realtime subscriptions
To run Offchain Café: EVM, you'll need the following:
- A PostgreSQL database (
DATABASE_URL) - A Redis instance (
REDIS_URL) - An Ethereum RPC endpoint (
ETH_CHAIN_ID,ETH_HTTP_RPC_URLandETH_WS_RPC_URL(optional, but recommended)) - Addresses and deploy block numbers of the contracts you want to index
- Prepare
contracts.json(seecontracts.example.jsonfor an example) - Prepare environment (see
env.examplefor an example) - Run
pnpm install && pnpm build - Run
pnpm db:migrateto create the database schema - Run
pnpm start
You should now have the GraphQL API endpoint running at /graphql.
Enjoy! ☕️
This example uses @urql/core in NodeJS environment.
offchainCafe.ts
import{createClient,defaultExchanges}from"@urql/core";import{yogaExchange}from"@graphql-yoga/urql-exchange";constclient=createClient({url: "http://<OFFCHAIN_SERVER_HOST>:<OFFCHAIN_SERVER_PORT>/graphql",exchanges: [...defaultExchanges,yogaExchange()],});exportdefaultclient;queryLogs.ts
import{gql}from"@urql/core";importoffchainCafefrom"./offchainCafe";importreceiverAbifrom"~/abi/receiver.json" assert {type: "json"};constreceiverAddress="0x...";constiface=newethers.utils.Interface(receiverAbi);constreceiveEventTopic=iface.getEventTopic("Receive");constfromBlock=0;// 0 means contract creation blockconsttoBlock=-1;// -1 means the latest chain blockconstlogs=(awaitoffchainCafe.query(gql` query ContractLogs( $fromBlock: Int!, $toBlock: Int! ) { contract(address: "${receiverAddress}") { logs( topics: [["${receiveEventTopic}"]], limit: 10, fromBlock: $fromBlock, toBlock: $toBlock ) { block { number timestamp } logIndex transaction { hash } data topics } } }`,{ fromBlock, toBlock }).toPromise()).data.contract.logs;subscribeToLogs.ts
import{pipe,subscribe}from"wonka";import{gql}from"@urql/core";importoffchainCafefrom"./offchainCafe";importreceiverAbifrom"~/abi/receiver.json" assert {type: "json"};constreceiverAddress="0x...";constiface=newethers.utils.Interface(receiverAbi);constreceiveEventTopic=iface.getEventTopic("Receive");const{ unsubscribe }=pipe(offchainCafe.subscription(gql` subscription { log( contractAddress: "${receiverAddress}", topics: [["${receiveEventTopic}"]] ) { block { number timestamp } logIndex transaction { hash } data topics } }`,{}),subscribe(async(result)=>{constlog=result.data!.log;}));