Skip to main content

Using Hashi πŸŒ‰

Crosschain Request of a Chainlink VRF with Gnosis's Hashi πŸŒ‰

This article demonstrates how to use the Yaho and Yaru contracts, part of the Gnosis's Hashi protocol, to send a crosschain message(from Chiado to Goerli) to a Chainlink VRF contract(deployed on Goerli) and listen for the response event.

First off, what is the Hashi Protocol πŸŒ‰?​

Hashi is an EVM Header Oracle Aggregator, designed to facilitate a principled approach to cross-chain bridge security. It allows users to build custom oracle adapter contracts for any hash oracle mechanism they would like to use. Yaho and Yaru are contracts within the Hashi protocol that facilitate crosschain communication.

  • Yaho allows users to dispatch arbitrary messages, store the arbitrary message in storage, and relay previously stored messages to any number of message adapters.
  • Yaru allows the execution of arbitrary messages passed from Yaho.

Step-by-Step Process πŸšΆβ€β™‚οΈβ€‹

Step 1: Dispatch the Message​

// Initialize Yaho contract with the signer that can interact with it
const yahoContract = new ethers.Contract(yahoAddress, yahoAbi.abi, chiadoWallet);

// Define the message structure
const message = {
toChainId: ethers.utils.hexValue(5), // Chain ID for Goerli
to: vrfConsumerAddress, // Address of the VRF consumer contract on Goerli
data: vrfConsumerContract.interface.encodeFunctionData("requestRandomWords"), // Encoded function call
};

// Dispatch the message to the AMB on the Goerli network
const dispatchTx = await yahoContract.dispatchMessagesToAdapters(
[message],
[chiadoAmbAdapterAddress],
[goerliAmbAddress],
);
await dispatchTx.wait();

In this step, we're sending our message to the Yaho contract to be relayed to Goerli. The dispatchMessagesToAdapters function is called with the message and the addresses of the AMB adapter contracts.

Step 2: Get the Signature​

// Encode the data for the AMB Helper contract
const encodedData = new ethers.utils.AbiCoder().encode(
["address", "bytes"],
[vrfConsumerAddress, message.data]
);

// Obtain the signature from the AMB Helper contract
const signature = await ambHelperContract.getSignature(encodedData);

The encodedData is constructed with the address of the VRF consumer and the encoded function call data. The getSignature function of the AMB Helper contract is then called to retrieve the signature.

Step 3: Execute the Signature​

// Interact with the AMB contract on Goerli to execute the signature
const ambContractOnGoerli = new ethers.Contract(goerliAmbAddress, ambAbi, goerliProvider);
const executeSignatureTx = await ambContractOnGoerli.executeSignature(encodedData, signature);
const executeSignatureReceipt = await executeSignatureTx.wait();

Here, we send the encodedData and signature to the AMB contract on Goerli using the executeSignature function. This triggers the AMB to process our message.

Step 4: Extract Message ID​

// Extract the messageId from the transaction receipt
const messageId = executeSignatureReceipt.events.find(event => event.event === "MessageDispatched").args.messageId;

Once the executeSignature transaction is confirmed, we extract the messageId from the emitted MessageDispatched event.

Step 5: Execute the Message​

// Execute the message on Goerli through the Yaru contract
const executeTx = await yaruContract.executeMessages(
[message],
[messageId],
[chiadoWallet.address],
[goerliAmbAddress],
);
await executeTx.wait();

The executeMessages function of the Yaru contract on Goerli is called with the message, messageId, and the address of our wallet.

Step 6: Listen for the VRF Response​

// Listen for the VRF response
listenForVRFResponse(messageId);

Finally, we invoke a listener function that waits for the VRF response to be emitted by the Chainlink VRF contract.

Use Cases πŸŽ―β€‹

Being able to request VRF crosschain opens up a lot of possibilities for decentralized applications. For example, a dApp on one chain could use a random number generated by a Chainlink VRF on another chain. This could be useful for dApps that need secure, verifiable randomness but are running on a chain where Chainlink VRF is not available or too expensive to use.

Running Locally

Add your private key to the .env file and run the following commands: yarn install yarn dev

To see where the real action is happening skip directly to the packages/nextjs/pages/getvrf.tsx directory.