Skip to content

Instantly share code, notes, and snippets.

@zengzengzenghuy
Last active September 25, 2024 08:36
Show Gist options
  • Save zengzengzenghuy/0b22c6554dec6a25141c4616e1d39091 to your computer and use it in GitHub Desktop.
Save zengzengzenghuy/0b22c6554dec6a25141c4616e1d39091 to your computer and use it in GitHub Desktop.
Hyperbridge script
require("log-timestamp");
import { HyperClient, MessageStatusWithMeta } from "@polytope-labs/hyperclient";
import { config } from "dotenv";
import {
createPublicClient,
createWalletClient,
decodeFunctionData,
getContract,
http,
parseEventLogs,
} from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { sepolia, gnosisChiado } from "viem/chains";
import { ApiPromise, WsProvider } from "@polkadot/api";
import Reporter_MODULE from "./abis/reporterModule";
import EVM_HOST from "./abis/evmHost";
import HANDLER from "./abis/handler";
// sepolia Reporter
const Reporter_MODULE_ADDRESS = "0xbd21d63ccfd81242db0d84751fa838bf5dba3a36";
// Chiado adapter
const Adapter_MODULE_ADDRESS = "0x59462f59Ab0A5EE90df9a34942FEB67d8a5e615E"
/*
Using a viem client, dispatches an onchain transaction to the Reporter module.
The Reporter module contract, dispatches an ISMP request to Hyperbridge.
Then tracks the resulting ISMP request using Hyperclient.
*/
async function testPostAndGetRequest() {
const {
sepoliaClient,
SEPOLIA,
CHIADO,
gnosisChiadoHandler,
sepoliaReporter,
chiadoClient,
} = await setUp();
const blockNumber = await sepoliaClient.getBlockNumber();
console.log("Latest block number on sepolia: ", blockNumber);
console.log("Setting up hyperclient");
const HyperbridgeConfig = {
// rpc_url: "ws://127.0.0.1:9001",
rpc_url: "wss://hyperbridge-paseo-rpc.blockops.network",
};
const hyperclient = await HyperClient.init({
source: SEPOLIA,
dest: CHIADO,
hyperbridge: HyperbridgeConfig,
indexer: "",
});
console.log("Hyperclient init done")
const wsProvider = new WsProvider(HyperbridgeConfig.rpc_url);
const api = await ApiPromise.create({ provider: wsProvider });
console.log("WS Setup done")
const height = (
await api.query.ismp.latestStateMachineHeight({
stateId: {
Evm: 10200, // chain ID of gnosisChiado
},
consensusStateId: "ETH0",
})
).toJSON() as number;
// This is a post request
const hash = await sepoliaReporter.write.dispatchBlocks([
BigInt(10200),
"0x59462f59Ab0A5EE90df9a34942FEB67d8a5e615E", //adapter contract
[BigInt(blockNumber)-BigInt(1)]
],{}); // put an empty option here, otherwise will cause error in dispatchBlocks "expected 2 arguments, got 1"
const receipt = await sepoliaClient.waitForTransactionReceipt({
hash,
confirmations: 1,
});
console.log(`Transaction reciept: ${sepolia.blockExplorers.default.url}/tx/${hash}`);
console.log("Block: ", receipt.blockNumber);
// parse EvmHost PostRequestEvent emitted in the transcation logs
const event = parseEventLogs({ abi: EVM_HOST.ABI, logs: receipt.logs })[0];
if (event.eventName !== "PostRequestEvent") {
throw new Error("Unexpected Event type");
}
const request = event.args;
console.log({ request });
const postRequest = {
...request,
txHeight: receipt.blockNumber,
};
const status = await hyperclient.query_post_request_status(postRequest);
console.log("Request status: ", status);
const stream = await hyperclient.post_request_status_stream(postRequest);
console.log("Stream ", stream)
for await (const item of stream) {
let status: MessageStatusWithMeta;
if (item instanceof Map) {
status = Object.fromEntries((item as any).entries()) as MessageStatusWithMeta;
} else {
status = item;
}
console.log({ status });
switch (status.kind) {
case "SourceFinalized": {
console.log(
`Status ${status.kind}, Transaction: https://gargantua.statescan.io/#/extrinsics/${status.transaction_hash}`,
);
break;
}
case "HyperbridgeDelivered": {
console.log(
`Status ${status.kind}, Transaction: https://gargantua.statescan.io/#/extrinsics/${status.transaction_hash}`,
);
break;
}
case "HyperbridgeFinalized": {
console.log(
`Status ${status.kind}, Transaction: https://sepolia-CHIADOtimism.etherscan.io/tx/${status.transaction_hash}`,
);
const { args, functionName } = decodeFunctionData({
abi: HANDLER.ABI,
data: status.calldata,
});
try {
const hash = await gnosisChiadoHandler.write.handlePostRequests(args as any);
await chiadoClient.waitForTransactionReceipt({
hash,
confirmations: 1,
});
console.log(`Transaction submitted: https://gnosis-chiado.blockscout.com/tx/${hash}`);
} catch (e) {
console.error("Error self-relaying: ", e);
}
break;
}
case "DestinationDelivered": {
console.log(
`Status ${status.kind}, Transaction: https://gnosis-chiado.blockscout.com/tx/${status.transaction_hash}`,
);
return;
}
}
}
}
async function setUp() {
const account = privateKeyToAccount(process.env.PRIVATE_KEY as any);
const sepoliaWalletClient = createWalletClient({
chain: sepolia,
account,
transport: http(),
});
const chiadoWalletClient = createWalletClient({
chain: gnosisChiado,
account,
transport: http(),
});
const sepoliaClient = createPublicClient({
chain: sepolia,
transport: http(),
});
const chiadoClient = createPublicClient({
chain: gnosisChiado,
transport: http(),
});
const sepoliaReporter = getContract({
address: Reporter_MODULE_ADDRESS,
abi: Reporter_MODULE.ABI,
client: { public: sepoliaClient, wallet: sepoliaWalletClient },
});
const sepoliaIsmpHostAddress = await sepoliaReporter.read.host();
const sepoliaIsmpHost = getContract({
address: sepoliaIsmpHostAddress,
abi: EVM_HOST.ABI,
client: sepoliaClient,
});
const sepoliaHostParams = await sepoliaIsmpHost.read.hostParams();
const sepoliaHandler = getContract({
address: sepoliaHostParams.handler,
abi: HANDLER.ABI,
client: { public: sepoliaClient, wallet: sepoliaWalletClient },
});
const chiadoAdapterContract = getContract({
address: Adapter_MODULE_ADDRESS,
abi: Reporter_MODULE.ABI,
client: chiadoClient,
});
const gnosisChiadoIsmpHostAddress = await chiadoAdapterContract.read.host();
const gnosisChiadoIsmpHost = getContract({
address: gnosisChiadoIsmpHostAddress,
abi: EVM_HOST.ABI,
client: { public: chiadoClient, wallet: chiadoWalletClient },
});
const gnosisChiadoHostParams = await gnosisChiadoIsmpHost.read.hostParams();
const gnosisChiadoHandler = getContract({
address: gnosisChiadoHostParams.handler,
abi: HANDLER.ABI,
client: { public: chiadoClient, wallet: chiadoWalletClient },
});
const SEPOLIA = {
rpc_url: process.env.SEPOLIA_URL!,
consensus_state_id: "ETH0",
host_address: sepoliaIsmpHostAddress,
state_machine: await sepoliaIsmpHost.read.host(),
};
const CHIADO = {
rpc_url: process.env.CHIADO_URL!,
consensus_state_id: "ETH0",
host_address: gnosisChiadoIsmpHostAddress,
state_machine: await gnosisChiadoIsmpHost.read.host(),
};
return {
sepoliaClient,
account,
SEPOLIA,
CHIADO,
gnosisChiadoHandler,
sepoliaHandler,
sepoliaReporter,
chiadoClient,
chiadoWalletClient,
gnosisChiadoIsmpHost,
};
}
config();
testPostAndGetRequest();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment