All pages
Powered by GitBook
1 of 4

Loading...

Loading...

Loading...

Loading...

Verifying foreign event

This example demonstrates the validation of a Transfer Event from an ERC-20 contract on the Sepolia network using an event proof on the Chiado network. The proof is retrieved via an API call and provided to a custom contract to be deployed on Chiado. The contract utilizes the HashiProver helper library to verify the proof against the latest block header recorded in Hashi.

Validating your statements

Once the proof has been fetched, we can verify it using a custom contract on Chiado. The contract will use the HashiProver helper library to check the proof against the block header stored on Chiado.

Deploying the Custom Verification Contract on Chiado

Here is a custom contract that deployed on Chiado can be used to read and verify the Transfer event on Sepolia:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { HashiProver } from "./HashiProver.sol";

contract MockERC20Prover {

    event TransferEventVerified(uint256 indexed chainID, bytes rlpEncodedEvent);

    HashiProver public hashiProver;
    address public erc20Contract;
    uint256 public chainID;

    constructor(address shoyuBashi_, address erc20Contract_, uint256 chainID_) {
        hashiProver = HashiProver(shoyuBashi_);
        erc20Contract = erc20Contract_;
        chainID = chainID_;
    }

    function verifyTransferEvent(HashiProver.ReceiptProof calldata proof, bytes memory expectedRlpEncodedEvent) external {
        require(proof.chainId == chainID, "Invalid chain id"); 

        bytes memory rlpEncodedEvent = hashiProver.verifyForeignEvent(proof);

        require(keccak256(rlpEncodedEvent) == keccak256(expectedRlpEncodedEvent), "invalid event");
        emit TransferEventVerified(proof.chainId , rlpEncodedEvent);

        // TODO: Define custom logic here

    }
}

Deployment:

  • HashiProver & ShoyuBashi are already deployed on a list of networks that can be called from the custom verification contract (this contract). In order to configure a custom oracle set for it is possible to deploy a new ShoyuBashi contract, inherit HashiProver contract and configure your oracle set in the ShoyuBashi contract.

  • In this example, pass to the custom verification contract constructor <ShoyuBashi contract address on Chiado, the ERC20 contract address on Sepolia, from which the Transfer event is emitted, chain ID of the ERC20Contract (Sepolia: 11155111)>

verifyForeignEvent explanation:

Inputs:

  • expectedRlpEncodedEvent : an bytes encoded format with the Event information: check out the helper script from Hashi-template in order to generate it starting from the Event topics and data.

  • proof: the HashiAPI retreived proof

Logic:

  • check that the proof chainID matches the origin chain chainId (Sepolia in this case).

  • The verifyForeignEvent function validates the event proof against the block header stored on Chiado, which was relayed from Sepolia.

  • check that rlpEncodedEvent returned from HashiProver.verifyForeignEvent matches the expectedRlpEncodedEvent that we passed as the function argument. This is useful to check that the Event infos encoded in the proof just verified actually match the Event we expect.

  • If the proof is valid, the contract emits the TransferEventVerified event. You may define your own logic after the proof has been verified.

Check verifyForeignEvent implementation here.

Submitting the Proof

Once the contract is deployed on Chiado, you can submit the proof fetched from the API using the following command:

// Example of submitting the proof in Solidity (or via web3 call)
HashiProver.ReceiptProof memory proof = { /* fetched proof from curl command */ };
MockERC20Prover.verifyTransferEvent(proof, expectedRlpEncodedEvent);

This will trigger the contract to verify the proof using the block header stored in Hashi from Sepolia. If the proof is valid, the rplEncodedEvent will be emitted.

References

  1. RLP encode event helper script

  2. MockERC20Prover contract

  3. HashiProver contract

  4. ShoyuBashi contract

  5. MockERC20Prover contract address on Chiado

  6. HashiProver & ShoyuBashi addresses

Setting the scene

What we have:

  • A ERC20 Transfer Event emitted in Sepolia USDC contract.

What we need:

  • The verification on Chiado chain of the actual Sepolia Transfer event.

How Hashi enables the Event verification:

  • With HashiAPI: a offchain component used to retrieve the Event Proof for the specific Sepolia Event emitted.

  • With HashiProver: a onchain contract provided by Hashi which can verify the block proof provided by HashiAPI. HashiProver must be deployed on the target chain (Chiado in this case) and can be used in a custom contract which can use the Event proof verification provided by HashiProver itself.

Steps followed in this example:

  • Fetch the event proof for Transfer event from Sepolia.

  • Deploy a custom contract on Chiado that will verify the event proof using HashiProver.

  • Submitting the proof to the custom contract.

Getting the Event Proof

The first step is to fetch the Event Proof from Sepolia. An important parameter is the block number which ensures that Hashi can verify the proof against the block header stored on Chiado. This is possible if the block header related the emitted event on the origin chain (Sepolia in this case) has already been propagated to the target chain (Chiado in this case). To check the block propagation status is possible to use the Hashi Explorer.

Fetching the Proof

Use the following curl command to fetch the account and storage proof for the following ERC20 Transaction : tx-example.

curl --location --request POST 'https://jsonrpc.hashi-explorer.xyz/v1' \
--header 'Content-Type: application/json' \
--data-raw '{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "hashi_getReceiptProof",
  "params": {
    "logIndex": 397,
    "blockNumber": 7016999,
    "chainId": 11155111,
    "transactionHash": "0x25a6a5c138f3b5a434a3a2b5d6bf7bdf97cb700bd7515f801ecfb71f1d965e7b"
  }
}'
import axios from "axios";

const main = async () => {
  // fetch event proof from Hashi Prover
  console.log("Fetching event proof from Hashi prover...");
  const result = await axios.post(
    `http://jsonrpc.hashi-explorer.xyz:3000/v1`,
    {
      jsonrpc: "2.0",
      method: "hashi_getReceiptProof",
      params: {
        logIndex: 397,
        blockNumber: 7016999,
        chainId: 11155111,
        transactionHash: "0x25a6a5c138f3b5a434a3a2b5d6bf7bdf97cb700bd7515f801ecfb71f1d965e7b",
      },
      id: 1,
    },
    {
      headers: {
        "Content-Type": "application/json",
      },
    }
  );
  console.log("Event proof result", result.data.result.proof);
};

main();

  • chainId: 11155111 (Sepolia).

  • txHash: The tx-hash that emitted the Transfer Event on Sepolia: tx-example.

  • logIndex: The log index for the event.

  • blockNumber: The block number on Sepolia, 7016999, which must have already been propagated to Chiado via Hashi for the proof to be valid. The block number must reference a block that appears after the block containing the event. In this case 7016999 > 7016956

This curl command / script returns the Event Proof for the Transfer Event on Sepolia, which will be used for verification on Chiado.

References

  1. Receipt proof request script