# Demo Stack components: * `ipld-eth-db` database for statediffed data * Local geth + lighthouse blockchain "fixturenet" running in statediffing mode * `ipld-eth-server-2` which runs an ETH RPC API and a GQL server; they both serve data from `ipld-eth-db` * A go-nitro deployment acting as the remote Nitro node for `ipld-eth-server-2` * Example ERC20 Ponder apps * `ponder-app-indexer-1` that pays the `ipld-eth-server-2` for ETH RPC requests * `ponder-app-indexer-2` that pays `ponder-app-indexer-1` for GQL queries * `ponder-app-watcher` that pays `ponder-app-indexer-2` for GQL queries ## Setup * In a terminal, check `ipld-eth-server-2`'s logs to keep track of incoming RPC requests from the `ponder-app-indexer-1`: ```bash docker logs -f $(docker ps -aq --filter name="ipld-eth-server-2") ``` ## Run ### ERC20 Ponder App * Run the first indexer Ponder app: ```bash docker exec -it payments-ponder-app-indexer-1-1 bash -c "DEBUG=laconic:payments pnpm start" # Expected output: # 12:57:03.751 INFO payment Nitro node setup with address 0x67D5b55604d1aF90074FcB69b8C51838FFF84f8d # laconic:payments Starting voucher subscription... +0ms # ... # 09:58:54.288 INFO payment Creating ledger channel with nitro node 0x660a4bEF3fbC863Fcd8D3CDB39242aE513d7D92e ... # 09:59:14.230 INFO payment Creating payment channel with nitro node 0x660a4bEF3fbC863Fcd8D3CDB39242aE513d7D92e ... # 09:59:14.329 INFO payment Using payment channel 0x1ff59db391b7a55bed723b930ab53c80e7ce857487c1e58771aa5a0737d71625 ``` * Export the payment channel id to a variable: ```bash export PONDER_UPSTREAM_PAYMENT_CHANNEL= ``` * On starting the Ponder app in indexer mode, it creates a payment channel with the `ipld-eth-server-2`'s (external) Nitro node and then starts the historical sync service * The sync service makes several ETH RPC requests to the `ipld-eth-server-2` to fetch required data; check the `ipld-eth-server-2` logs for charged RPC requests (`eth_getBlockByNumber`, `eth_getLogs`): ```bash # Expected output: # ... # 2023/10/18 05:29:38 INFO Serving a paid RPC request method=eth_getBlockByNumber cost=50 sender=0x67D5b55604d1aF90074FcB69b8C51838FFF84f8d # time="2023-10-18T05:29:38Z" level=debug msg=START api_method=eth_getBlockByNumber api_params="[latest true]" api_reqid=0 conn="172.26.0.19:42306" user_id= uuid=54992dc3-6d77-11ee-9ede-0242ac1a000f # WARN [10-18|05:29:38.292] Attempting GerRPCCalls, but default PluginLoader has not been initialized # time="2023-10-18T05:29:38Z" level=debug msg=END api_method=eth_getBlockByNumber api_params="[latest true]" api_reqid=0 conn="172.26.0.19:42306" duration=22 user_id= uuid=54992dc3-6d77-11ee-9ede-0242ac1a000f # ... # 2023/10/18 05:29:40 INFO Serving a paid RPC request method=eth_getLogs cost=50 sender=0x67D5b55604d1aF90074FcB69b8C51838FFF84f8d # WARN [10-18|05:29:40.340] Attempting GerRPCCalls, but default PluginLoader has not been initialized # time="2023-10-18T05:29:40Z" level=debug msg="retrieving log cids for receipt ids" # ... ``` * Check the Ponder - ipld-eth-server-2 payment channel status: ```bash docker exec payments-nitro-rpc-client-1 npm exec -c "nitro-rpc-client get-payment-channel $PONDER_UPSTREAM_PAYMENT_CHANNEL -s false -h go-nitro -p 4006" # Expected output ('PaidSoFar' is non zero): # { # ID: '0x1ff59db391b7a55bed723b930ab53c80e7ce857487c1e58771aa5a0737d71625', # Status: 'Open', # Balance: { # AssetAddress: '0x0000000000000000000000000000000000000000', # Payee: '0x660a4bef3fbc863fcd8d3cdb39242ae513d7d92e', # Payer: '0x67d5b55604d1af90074fcb69b8c51838fff84f8d', # PaidSoFar: 7200n, # RemainingFunds: 999992800n # } # } ``` * In another terminal run the second indexer Ponder app: ```bash docker exec -it payments-ponder-app-indexer-2-1 bash -c "DEBUG=laconic:payments pnpm start" # Expected output: # 08:00:28.701 INFO payment Nitro node setup with address 0xB2B22ec3889d11f2ddb1A1Db11e80D20EF367c01 # laconic:payments Starting voucher subscription... +0ms # ... # 09:58:54.288 INFO payment Creating ledger channel with nitro node 0x67D5b55604d1aF90074FcB69b8C51838FFF84f8d ... # 09:59:14.230 INFO payment Creating payment channel with nitro node 0x67D5b55604d1aF90074FcB69b8C51838FFF84f8d ... # 09:59:14.329 INFO payment Using payment channel 0xfbf9d7eb7c18446883c7f57f4c94db5607f414a224b3e921c787db07371d2a70 ``` * On starting indexer Ponder app, it creates a payment channel with first indexer and then starts the sync services * Check logs in `ponder-indexer-1` to see payments made from `ponder-indexer-2` from GQL queries to fetch network data ```bash # ... # laconic:payments Received a payment voucher of 100 from 0xB2B22ec3889d11f2ddb1A1Db11e80D20EF367c01 +23ms # laconic:payments Serving a paid query for 0xB2B22ec3889d11f2ddb1A1Db11e80D20EF367c01 +0ms # 13:01:05.671 DEBUG payment Verified payment for GQL queries getEthLogs # laconic:payments Received a payment voucher of 100 from 0xB2B22ec3889d11f2ddb1A1Db11e80D20EF367c01 +20ms # laconic:payments Serving a paid query for 0xB2B22ec3889d11f2ddb1A1Db11e80D20EF367c01 +0ms # 13:01:05.691 DEBUG payment Verified payment for GQL queries getEthBlock # 13:01:07.598 INFO realtime Fetched missing blocks [686, 687] (network=fixturenet) # 13:01:07.598 DEBUG realtime Started processing new head block 686 (network=fixturenet) # ... ``` * Following are the example GQL queries (with payment headers) `ponder-indexer-2` makes to `ponder-indexer-1` for fetching data ```graphql { getEthLogs( chainId: 1212, address: "0x6325439389e0797ab35752b4f43a14c004f22a9c", fromBlock: 100, toBlock: 200, ) { address blockHash blockNumber data logIndex removed topics transactionHash transactionIndex } getEthBlock( chainId: 1212, blockNumber: 150, fullTransactions: false ) { baseFeePerGas difficulty extraData gasLimit gasUsed hash logsBloom miner mixHash nonce number parentHash receiptsRoot sha3Uncles size stateRoot timestamp totalDifficulty transactionsRoot txHashes } } ``` * In another terminal run the Ponder app in watcher mode: ```bash docker exec -it payments-ponder-app-watcher-1 bash -c "DEBUG=laconic:payments pnpm start" # Expected output: # 11:23:22.057 DEBUG app Started using config file: ponder.config.ts # 08:02:12.548 INFO payment Nitro node setup with address 0x111A00868581f73AB42FEEF67D235Ca09ca1E8db # laconic:payments Starting voucher subscription... +0ms # 08:02:17.417 INFO payment Creating ledger channel with nitro node 0xB2B22ec3889d11f2ddb1A1Db11e80D20EF367c01 ... # 08:02:37.135 INFO payment Creating payment channel with nitro node 0xB2B22ec3889d11f2ddb1A1Db11e80D20EF367c01 ... # 08:02:37.313 INFO payment Using payment channel 0xc48622577dfa389283beb19ed946274eb034587d72e61445dc997304be671f1a # ... # 11:23:22.436 INFO server Started responding as healthy ``` * Check the terminal of the second indexer Ponder app. Logs of payment for `getLogEvents` queries can be seen: ```bash # ... # 08:02:37.763 DEBUG realtime Finished processing new head block 89 (network=fixturenet) # laconic:payments Received a payment voucher of 50 from 0x111A00868581f73AB42FEEF67D235Ca09ca1E8db +444ms # laconic:payments Serving a paid query for 0x111A00868581f73AB42FEEF67D235Ca09ca1E8db +1ms # 08:02:37.804 DEBUG payment Verified payment for GQL queries getLogEvents # laconic:payments Received a payment voucher of 50 from 0x111A00868581f73AB42FEEF67D235Ca09ca1E8db +45ms # laconic:payments Serving a paid query for 0x111A00868581f73AB42FEEF67D235Ca09ca1E8db +0ms # 08:02:37.849 DEBUG payment Verified payment for GQL queries getLogEvents ``` * Following are the example GQL queries (with payment headers) `ponder-watcher` makes to `ponder-indexer-2` for fetching data ```graphql getLogEvents( fromTimestamp: 1695303079, toTimestamp: 1695304156, filters: [ { name: "AdventureGold" chainId: 1212, address: ["0x6325439389e0797ab35752b4f43a14c004f22a9c"], fromBlock: 100, toBlock: 200, includeEventSelectors: ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"] } ] ) { events { transaction { hash } log { id } block { number } } metadata { pageEndsAtTimestamp isLastPage } } ``` * Open watcher Ponder app endpoint http://localhost:42069 * Try GQL query to see transfer events ```graphql { transferEvents (orderBy: "timestamp", orderDirection: "desc") { id amount from { id } to { id } timestamp } } ``` * Transfer an ERC20 token on chain * Get the deployed ERC20 token address ```bash export TOKEN_ADDRESS=$(docker exec payments-ponder-er20-contracts-1 jq -r '.address' ./deployment/erc20-address.json) ``` * Transfer token ```bash docker exec -it payments-ponder-er20-contracts-1 bash -c "yarn token:transfer:docker --token ${TOKEN_ADDRESS} --to 0xe22AD83A0dE117bA0d03d5E94Eb4E0d80a69C62a --amount 5000" ``` * Wait for a log in watcher Ponder app ```bash 06:40:47.567 INFO handlers Processed 1 event (up to Oct 19, 2023) ``` * Check the GQL query again in http://localhost:42069 to see a new `TransferEvent` entity