142 lines
4.3 KiB
TypeScript
142 lines
4.3 KiB
TypeScript
import * as wh from "@certusone/wormhole-sdk"
|
|
import { Implementation__factory } from "@certusone/wormhole-sdk/lib/cjs/ethers-contracts"
|
|
import { LogMessagePublishedEvent } from "../../../sdk/src"
|
|
import {
|
|
ChainInfo,
|
|
getCoreRelayer,
|
|
getMockIntegration,
|
|
getMockIntegrationAddress,
|
|
} from "../helpers/env"
|
|
import * as grpcWebNodeHttpTransport from "@improbable-eng/grpc-web-node-http-transport"
|
|
import { ethers } from "ethers"
|
|
|
|
export async function sendMessage(
|
|
sourceChain: ChainInfo,
|
|
targetChain: ChainInfo,
|
|
fetchSignedVaa: boolean = false,
|
|
queryMessageOnTargetFlag: boolean = true
|
|
): Promise<boolean | undefined> {
|
|
console.log(
|
|
`Sending message from chain ${sourceChain.chainId} to ${targetChain.chainId}...`
|
|
)
|
|
|
|
const sourceRelayer = getCoreRelayer(sourceChain)
|
|
|
|
const relayQuote = await (
|
|
await sourceRelayer.quoteGas(
|
|
targetChain.chainId,
|
|
2000000,
|
|
await sourceRelayer.getDefaultRelayProvider()
|
|
)
|
|
).add(10000000000)
|
|
console.log("relay quote: " + relayQuote)
|
|
|
|
const mockIntegration = getMockIntegration(sourceChain)
|
|
const targetAddress = getMockIntegrationAddress(targetChain)
|
|
|
|
const sentMessage = "ID: " + String(Math.ceil(Math.random() * 10000))
|
|
console.log(`Sent message: ${sentMessage}`)
|
|
const tx = await mockIntegration.sendMessage(
|
|
Buffer.from(sentMessage),
|
|
targetChain.chainId,
|
|
targetAddress,
|
|
{
|
|
gasLimit: 1000000,
|
|
value: relayQuote,
|
|
}
|
|
)
|
|
const rx = await tx.wait()
|
|
const sequences = wh.parseSequencesFromLogEth(rx, sourceChain.wormholeAddress)
|
|
console.log("Tx hash: ", rx.transactionHash)
|
|
console.log(`Sequences: ${sequences}`)
|
|
if (fetchSignedVaa) {
|
|
for (let i = 0; i < 120; i++) {
|
|
try {
|
|
const vaa1 = await fetchVaaFromLog(rx.logs[0], sourceChain.chainId)
|
|
console.log(vaa1)
|
|
const vaa2 = await fetchVaaFromLog(rx.logs[1], sourceChain.chainId)
|
|
console.log(vaa2)
|
|
break
|
|
} catch (e) {
|
|
console.error(`${i} seconds`)
|
|
if (i === 0) {
|
|
console.error(e)
|
|
}
|
|
}
|
|
await new Promise((resolve) => setTimeout(resolve, 1_000))
|
|
}
|
|
}
|
|
|
|
if (queryMessageOnTargetFlag) {
|
|
return await queryMessageOnTarget(sentMessage, targetChain)
|
|
}
|
|
console.log("")
|
|
}
|
|
|
|
async function queryMessageOnTarget(
|
|
sentMessage: string,
|
|
targetChain: ChainInfo
|
|
): Promise<boolean> {
|
|
let messageHistory: string[][] = []
|
|
const targetIntegration = getMockIntegration(targetChain)
|
|
|
|
let notFound = true
|
|
for (let i = 0; i < 20 && notFound; i++) {
|
|
await new Promise<void>((resolve) => setTimeout(() => resolve(), 2000))
|
|
const messageHistoryResp = await targetIntegration.getMessageHistory()
|
|
messageHistory = messageHistoryResp.map((messages) =>
|
|
messages.map((message) => ethers.utils.toUtf8String(message))
|
|
)
|
|
notFound = !messageHistory
|
|
.slice(messageHistory.length - 20)
|
|
.find((msgs) => msgs.find((m) => m === sentMessage))
|
|
process.stdout.write("..")
|
|
}
|
|
console.log("")
|
|
|
|
if (notFound) {
|
|
console.log(`ERROR: Did not receive message!`)
|
|
return false
|
|
}
|
|
|
|
console.log(`Received message: ${messageHistory[messageHistory.length - 1][0]}`)
|
|
console.log(`Received messageHistory: ${messageHistory.join(", ")}`)
|
|
return true
|
|
}
|
|
|
|
export async function encodeEmitterAddress(
|
|
myChainId: wh.ChainId,
|
|
emitterAddressStr: string
|
|
): Promise<string> {
|
|
if (myChainId === wh.CHAIN_ID_SOLANA || myChainId === wh.CHAIN_ID_PYTHNET) {
|
|
return wh.getEmitterAddressSolana(emitterAddressStr)
|
|
}
|
|
if (wh.isTerraChain(myChainId)) {
|
|
return wh.getEmitterAddressTerra(emitterAddressStr)
|
|
}
|
|
if (wh.isEVMChain(myChainId)) {
|
|
return wh.getEmitterAddressEth(emitterAddressStr)
|
|
}
|
|
throw new Error(`Unrecognized wormhole chainId ${myChainId}`)
|
|
}
|
|
|
|
function fetchVaaFromLog(bridgeLog: any, chainId: wh.ChainId): Promise<wh.SignedVaa> {
|
|
const iface = Implementation__factory.createInterface()
|
|
const log = iface.parseLog(bridgeLog) as unknown as LogMessagePublishedEvent
|
|
const sequence = log.args.sequence.toString()
|
|
const emitter = wh.tryNativeToHexString(log.args.sender, "ethereum")
|
|
return wh
|
|
.getSignedVAA(
|
|
"https://wormhole-v2-testnet-api.certus.one",
|
|
chainId,
|
|
emitter,
|
|
sequence,
|
|
{ transport: grpcWebNodeHttpTransport.NodeHttpTransport() }
|
|
)
|
|
.then((r) => r.vaaBytes)
|
|
}
|
|
|
|
export async function sleep(ms: number) {
|
|
return new Promise((r) => setTimeout(r, ms))
|
|
}
|