parent
ac6d09ab1b
commit
a799605ec2
|
@ -6,4 +6,3 @@ export type { IWormhole, LogMessagePublishedEvent } from "./ethers-contracts/IWo
|
|||
export { IWormhole__factory } from "./ethers-contracts/factories/IWormhole__factory"
|
||||
export type { RelayProvider } from "./ethers-contracts/RelayProvider"
|
||||
export { RelayProvider__factory } from "./ethers-contracts/factories/RelayProvider__factory"
|
||||
export * from './structs'
|
|
@ -1,166 +0,0 @@
|
|||
import { BigNumber, ethers} from "ethers"
|
||||
import { arrayify } from "ethers/lib/utils"
|
||||
|
||||
export enum RelayerPayloadId {
|
||||
Delivery = 1,
|
||||
Redelivery = 2,
|
||||
// DeliveryStatus = 3,
|
||||
}
|
||||
|
||||
export interface DeliveryInstructionsContainer {
|
||||
payloadId: number // 1
|
||||
sufficientlyFunded: boolean
|
||||
instructions: DeliveryInstruction[]
|
||||
}
|
||||
|
||||
export interface DeliveryInstruction {
|
||||
targetChain: number
|
||||
targetAddress: Buffer
|
||||
refundAddress: Buffer
|
||||
maximumRefundTarget: BigNumber
|
||||
applicationBudgetTarget: BigNumber
|
||||
executionParameters: ExecutionParameters
|
||||
}
|
||||
|
||||
export interface ExecutionParameters {
|
||||
version: number
|
||||
gasLimit: number
|
||||
providerDeliveryAddress: Buffer
|
||||
}
|
||||
|
||||
export interface RedeliveryByTxHashInstruction {
|
||||
payloadId: number //2
|
||||
sourceChain: number
|
||||
sourceTxHash: Buffer
|
||||
sourceNonce: BigNumber
|
||||
targetChain: number
|
||||
newMaximumRefundTarget: BigNumber
|
||||
newApplicationBudgetTarget: BigNumber
|
||||
executionParameters: ExecutionParameters
|
||||
}
|
||||
|
||||
export function parsePayloadType(
|
||||
stringPayload: string | Buffer | Uint8Array
|
||||
): RelayerPayloadId {
|
||||
const payload =
|
||||
typeof stringPayload === "string" ? arrayify(stringPayload) : stringPayload
|
||||
if (payload[0] == 0 || payload[0] >= 3) {
|
||||
throw new Error("Unrecogned payload type " + payload[0])
|
||||
}
|
||||
return payload[0]
|
||||
}
|
||||
|
||||
export function parseDeliveryInstructionsContainer(
|
||||
bytes: Buffer
|
||||
): DeliveryInstructionsContainer {
|
||||
let idx = 0
|
||||
const payloadId = bytes.readUInt8(idx)
|
||||
if (payloadId !== RelayerPayloadId.Delivery) {
|
||||
throw new Error(
|
||||
`Expected Delivery payload type (${RelayerPayloadId.Delivery}), found: ${payloadId}`
|
||||
)
|
||||
}
|
||||
idx += 1
|
||||
|
||||
const sufficientlyFunded = Boolean(bytes.readUInt8(idx))
|
||||
idx += 1
|
||||
|
||||
const numInstructions = bytes.readUInt8(idx)
|
||||
idx += 1
|
||||
let instructions = [] as DeliveryInstruction[]
|
||||
for (let i = 0; i < numInstructions; ++i) {
|
||||
const targetChain = bytes.readUInt16BE(idx)
|
||||
idx += 2
|
||||
const targetAddress = bytes.slice(idx, idx + 32)
|
||||
idx += 32
|
||||
const refundAddress = bytes.slice(idx, idx + 32)
|
||||
idx += 32
|
||||
const maximumRefundTarget = ethers.BigNumber.from(
|
||||
Uint8Array.prototype.subarray.call(bytes, idx, idx + 32)
|
||||
)
|
||||
idx += 32
|
||||
const applicationBudgetTarget = ethers.BigNumber.from(
|
||||
Uint8Array.prototype.subarray.call(bytes, idx, idx + 32)
|
||||
)
|
||||
idx += 32
|
||||
const executionParameters = parseExecutionParameters(bytes, idx)
|
||||
instructions.push(
|
||||
// dumb typechain format
|
||||
{
|
||||
targetChain,
|
||||
targetAddress,
|
||||
refundAddress,
|
||||
maximumRefundTarget,
|
||||
applicationBudgetTarget,
|
||||
executionParameters,
|
||||
}
|
||||
)
|
||||
}
|
||||
return {
|
||||
payloadId,
|
||||
sufficientlyFunded,
|
||||
instructions,
|
||||
}
|
||||
}
|
||||
|
||||
export function parseRedeliveryByTxHashInstruction(
|
||||
bytes: Buffer
|
||||
): RedeliveryByTxHashInstruction {
|
||||
let idx = 0
|
||||
const payloadId = bytes.readUInt8(idx)
|
||||
if (payloadId !== RelayerPayloadId.Redelivery) {
|
||||
throw new Error(
|
||||
`Expected Delivery payload type (${RelayerPayloadId.Redelivery}), found: ${payloadId}`
|
||||
)
|
||||
}
|
||||
idx += 1
|
||||
|
||||
const sourceChain = bytes.readUInt16BE(idx)
|
||||
idx += 2
|
||||
|
||||
const sourceTxHash = bytes.slice(idx, idx + 32)
|
||||
idx += 32
|
||||
|
||||
const sourceNonce = BigNumber.from(bytes.slice(idx, idx + 32))
|
||||
idx += 32
|
||||
const targetChain = bytes.readUInt16BE(idx)
|
||||
idx += 2
|
||||
// note: confirmed that BigNumber.from(<Buffer>) assumes big endian
|
||||
const newMaximumRefundTarget = BigNumber.from(bytes.slice(idx, idx + 32))
|
||||
idx += 32
|
||||
const newApplicationBudgetTarget = BigNumber.from(bytes.slice(idx, idx + 32))
|
||||
idx += 32
|
||||
const executionParameters = parseExecutionParameters(bytes, idx)
|
||||
return {
|
||||
payloadId,
|
||||
sourceChain,
|
||||
sourceTxHash,
|
||||
sourceNonce,
|
||||
targetChain,
|
||||
newMaximumRefundTarget,
|
||||
newApplicationBudgetTarget,
|
||||
executionParameters,
|
||||
}
|
||||
}
|
||||
|
||||
function parseExecutionParameters(bytes: Buffer, idx: number = 0): ExecutionParameters {
|
||||
const version = bytes.readUInt8(idx)
|
||||
idx += 1
|
||||
const gasLimit = bytes.readUint32BE(idx)
|
||||
idx += 4
|
||||
const providerDeliveryAddress = bytes.slice(idx, idx + 32)
|
||||
idx += 32
|
||||
return { version, gasLimit, providerDeliveryAddress }
|
||||
}
|
||||
|
||||
/*
|
||||
* Helpers
|
||||
*/
|
||||
|
||||
export function dbg<T>(x: T, msg?: string): T {
|
||||
if (msg) {
|
||||
console.log("[DEBUG] " + msg)
|
||||
}
|
||||
console.log(x)
|
||||
return x
|
||||
}
|
|
@ -25,16 +25,10 @@ import {
|
|||
RelayProvider__factory,
|
||||
LogMessagePublishedEvent,
|
||||
CoreRelayerStructs,
|
||||
DeliveryInstructionsContainer,
|
||||
parseDeliveryInstructionsContainer,
|
||||
parseRedeliveryByTxHashInstruction,
|
||||
parsePayloadType,
|
||||
RelayerPayloadId,
|
||||
} from "../../../pkgs/sdk/src"
|
||||
import * as ethers from "ethers"
|
||||
import { Implementation__factory } from "@certusone/wormhole-sdk/lib/cjs/ethers-contracts"
|
||||
import * as grpcWebNodeHttpTransport from "@improbable-eng/grpc-web-node-http-transport"
|
||||
import { retryAsyncUntilDefined } from "ts-retry/lib/cjs/retry"
|
||||
|
||||
const wormholeRpc = "https://wormhole-v2-testnet-api.certus.one"
|
||||
|
||||
|
@ -55,19 +49,14 @@ export interface GenericRelayerPluginConfig {
|
|||
}
|
||||
|
||||
interface WorkflowPayload {
|
||||
payloadId: RelayerPayloadId
|
||||
coreRelayerDeliveryVaaIndex: number
|
||||
coreRelayerVaaIndex: number
|
||||
vaas: string[] // base64
|
||||
// only present when payload type is Redelivery
|
||||
coreRelayerRedeliveryVaa?: string // base64
|
||||
}
|
||||
|
||||
interface WorkflowPayloadParsed {
|
||||
payloadId: RelayerPayloadId
|
||||
deliveryInstructionsContainer: DeliveryInstructionsContainer
|
||||
coreRelayerDeliveryVaaIndex: number
|
||||
coreRelayerDeliveryVaa: ParsedVaaWithBytes
|
||||
coreRelayerRedeliveryVaa?: ParsedVaaWithBytes
|
||||
coreRelayerVaaIndex: number
|
||||
coreRelayerVaa: ParsedVaaWithBytes
|
||||
vaas: Buffer[]
|
||||
}
|
||||
|
||||
|
@ -93,8 +82,6 @@ interface Entry {
|
|||
deliveryVaaIdx: number
|
||||
vaas: { emitter: string; sequence: string; bytes: string }[]
|
||||
allFetched: boolean
|
||||
// only present for Redeliveries
|
||||
redeliveryVaa?: string
|
||||
}
|
||||
|
||||
export class GenericRelayerPlugin implements Plugin<WorkflowPayload> {
|
||||
|
@ -151,7 +138,7 @@ export class GenericRelayerPlugin implements Plugin<WorkflowPayload> {
|
|||
await sleep(3_000) // todo: make configurable
|
||||
|
||||
// track which delivery vaa hashes have all vaas ready this iteration
|
||||
let newlyResolved = new Map<string, Entry>()
|
||||
let newlyResolved = new Map<string, SignedVaa>()
|
||||
await db.withKey(
|
||||
[PENDING, RESOLVED],
|
||||
async (kv: { [RESOLVED]?: Resolved[]; [PENDING]?: Pending[] }) => {
|
||||
|
@ -187,7 +174,10 @@ export class GenericRelayerPlugin implements Plugin<WorkflowPayload> {
|
|||
}
|
||||
const newEntry: Entry = await this.fetchEntry(hash, entry, logger)
|
||||
if (newEntry.allFetched) {
|
||||
newlyResolved.set(hash, newEntry)
|
||||
newlyResolved.set(
|
||||
hash,
|
||||
Buffer.from(newEntry.vaas[newEntry.deliveryVaaIdx].bytes, "base64")
|
||||
)
|
||||
}
|
||||
return [hash, newEntry]
|
||||
})
|
||||
|
@ -211,13 +201,9 @@ export class GenericRelayerPlugin implements Plugin<WorkflowPayload> {
|
|||
}
|
||||
)
|
||||
// kick off an engine listener event for each resolved delivery vaa
|
||||
for (const entry of newlyResolved.values()) {
|
||||
this.logger.info("Kicking off engine listener event for resolved entry")
|
||||
if (entry.redeliveryVaa) {
|
||||
eventSource(Buffer.from(entry.redeliveryVaa, "base64"))
|
||||
} else {
|
||||
eventSource(Buffer.from(entry.vaas[entry.deliveryVaaIdx].bytes, "base64"))
|
||||
}
|
||||
for (const deliveryVAA of newlyResolved.values()) {
|
||||
this.logger.info("Kicking off engine listener event for resolved deliveryVAA")
|
||||
eventSource(deliveryVAA)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -275,27 +261,15 @@ export class GenericRelayerPlugin implements Plugin<WorkflowPayload> {
|
|||
coreRelayerVaa.hash
|
||||
).toString("base64")}`
|
||||
)
|
||||
const payloadId = parsePayloadType(coreRelayerVaa.payload)
|
||||
if (payloadId !== RelayerPayloadId.Delivery) {
|
||||
const payloadType = parsePayloadType(coreRelayerVaa.payload)
|
||||
if (payloadType !== RelayerPayloadType.Delivery) {
|
||||
// todo: support redelivery
|
||||
this.logger.warn(
|
||||
"Only delivery payloads currently implemented, found type: " + payloadType
|
||||
)
|
||||
return {}
|
||||
}
|
||||
switch (payloadId) {
|
||||
case RelayerPayloadId.Delivery:
|
||||
return this.consumeDeliveryEvent(coreRelayerVaa, db)
|
||||
case RelayerPayloadId.Redelivery:
|
||||
return this.consumeRedeliveryEvent(coreRelayerVaa, db)
|
||||
}
|
||||
}
|
||||
|
||||
async consumeRedeliveryEvent(
|
||||
coreRelayerVaa: ParsedVaaWithBytes,
|
||||
db: StagingAreaKeyLock
|
||||
): Promise<{ workflowData?: WorkflowPayload }> {}
|
||||
|
||||
async consumeDeliveryEvent(
|
||||
coreRelayerVaa: ParsedVaaWithBytes,
|
||||
db: StagingAreaKeyLock
|
||||
): Promise<{ workflowData?: WorkflowPayload }> {
|
||||
const hash = coreRelayerVaa.hash.toString("base64")
|
||||
const { [hash]: fetched } = await db.getKeys<Record<typeof hash, Entry>>([hash])
|
||||
|
||||
|
@ -305,8 +279,7 @@ export class GenericRelayerPlugin implements Plugin<WorkflowPayload> {
|
|||
return dbg(
|
||||
{
|
||||
workflowData: {
|
||||
payloadId: RelayerPayloadId.Delivery,
|
||||
coreRelayerDeliveryVaaIndex: fetched.deliveryVaaIdx,
|
||||
coreRelayerVaaIndex: fetched.deliveryVaaIdx,
|
||||
vaas: fetched.vaas.map((v) => v.bytes),
|
||||
},
|
||||
},
|
||||
|
@ -320,7 +293,40 @@ export class GenericRelayerPlugin implements Plugin<WorkflowPayload> {
|
|||
const rx = await this.fetchReceipt(coreRelayerVaa.sequence, chainId)
|
||||
// parse rx for seqs and emitters
|
||||
|
||||
const { vaas, deliveryVaaIdx } = this.filterLogs(rx, chainId, coreRelayerVaa)
|
||||
const onlyVAALogs = rx.logs.filter(
|
||||
(log) =>
|
||||
log.address ===
|
||||
this.pluginConfig.supportedChains.get(chainId)?.coreContract?.address
|
||||
)
|
||||
const vaas = onlyVAALogs.flatMap((bridgeLog: ethers.providers.Log) => {
|
||||
const iface = Implementation__factory.createInterface()
|
||||
const log = iface.parseLog(bridgeLog) as unknown as LogMessagePublishedEvent
|
||||
// filter down to just synthetic batch
|
||||
if (log.args.nonce !== coreRelayerVaa.nonce) {
|
||||
return []
|
||||
}
|
||||
return [
|
||||
{
|
||||
sequence: log.args.sequence.toString(),
|
||||
emitter: wh.tryNativeToHexString(log.args.sender, "ethereum"),
|
||||
bytes: "",
|
||||
},
|
||||
]
|
||||
})
|
||||
this.logger.debug(vaas)
|
||||
const deliveryVaaIdx = vaas.findIndex(
|
||||
(vaa) =>
|
||||
vaa.emitter ===
|
||||
wh.tryNativeToHexString(
|
||||
wh.tryUint8ArrayToNative(coreRelayerVaa.emitterAddress, "ethereum"),
|
||||
"ethereum"
|
||||
)
|
||||
)
|
||||
if (deliveryVaaIdx === -1) {
|
||||
throw new PluginError("CoreRelayerVaa not found in fetched vaas", {
|
||||
vaas,
|
||||
})
|
||||
}
|
||||
vaas[deliveryVaaIdx].bytes = coreRelayerVaa.bytes.toString("base64")
|
||||
|
||||
// create entry and pending in db
|
||||
|
@ -336,8 +342,7 @@ export class GenericRelayerPlugin implements Plugin<WorkflowPayload> {
|
|||
this.logger.info("Resolved entry immediately")
|
||||
return {
|
||||
workflowData: {
|
||||
payloadId: RelayerPayloadId.Delivery,
|
||||
coreRelayerDeliveryVaaIndex: maybeResolvedEntry.deliveryVaaIdx,
|
||||
coreRelayerVaaIndex: maybeResolvedEntry.deliveryVaaIdx,
|
||||
vaas: maybeResolvedEntry.vaas.map((v) => v.bytes),
|
||||
},
|
||||
}
|
||||
|
@ -419,74 +424,14 @@ export class GenericRelayerPlugin implements Plugin<WorkflowPayload> {
|
|||
}
|
||||
}
|
||||
|
||||
filterLogs(
|
||||
rx: ethers.ContractReceipt,
|
||||
chainId: wh.EVMChainId,
|
||||
coreRelayerVaa: ParsedVaaWithBytes
|
||||
): {
|
||||
vaas: {
|
||||
sequence: string
|
||||
emitter: string
|
||||
bytes: string
|
||||
}[]
|
||||
deliveryVaaIdx: number
|
||||
} {
|
||||
const onlyVAALogs = rx.logs.filter(
|
||||
(log) =>
|
||||
log.address ===
|
||||
this.pluginConfig.supportedChains.get(chainId)?.coreContract?.address
|
||||
)
|
||||
const vaas = onlyVAALogs.flatMap((bridgeLog: ethers.providers.Log) => {
|
||||
const iface = Implementation__factory.createInterface()
|
||||
const log = iface.parseLog(bridgeLog) as unknown as LogMessagePublishedEvent
|
||||
// filter down to just synthetic batch
|
||||
if (log.args.nonce !== coreRelayerVaa.nonce) {
|
||||
return []
|
||||
}
|
||||
return [
|
||||
{
|
||||
sequence: log.args.sequence.toString(),
|
||||
emitter: wh.tryNativeToHexString(log.args.sender, "ethereum"),
|
||||
bytes: "",
|
||||
},
|
||||
]
|
||||
})
|
||||
this.logger.debug(vaas)
|
||||
const deliveryVaaIdx = vaas.findIndex(
|
||||
(vaa) =>
|
||||
vaa.emitter ===
|
||||
wh.tryNativeToHexString(
|
||||
wh.tryUint8ArrayToNative(coreRelayerVaa.emitterAddress, "ethereum"),
|
||||
"ethereum"
|
||||
)
|
||||
)
|
||||
if (deliveryVaaIdx === -1) {
|
||||
throw new PluginError("CoreRelayerVaa not found in fetched vaas", {
|
||||
vaas,
|
||||
})
|
||||
}
|
||||
return { vaas, deliveryVaaIdx }
|
||||
}
|
||||
|
||||
async handleWorkflow(
|
||||
workflow: Workflow<WorkflowPayload>,
|
||||
_providers: Providers,
|
||||
execute: ActionExecutor
|
||||
): Promise<void> {
|
||||
const payload = this.parseWorkflowPayload(workflow)
|
||||
switch (payload.payloadId) {
|
||||
case RelayerPayloadId.Delivery:
|
||||
}
|
||||
}
|
||||
|
||||
async handleDeliveryWorkflow(
|
||||
workflow: Workflow<WorkflowPayload>,
|
||||
_providers: Providers,
|
||||
execute: ActionExecutor
|
||||
): Promise<void> {
|
||||
this.logger.info("Got workflow")
|
||||
this.logger.info(JSON.stringify(workflow, undefined, 2))
|
||||
this.logger.info(workflow.data.coreRelayerDeliveryVaaIndex)
|
||||
this.logger.info(workflow.data.coreRelayerVaaIndex)
|
||||
this.logger.info(workflow.data.vaas)
|
||||
console.log("sanity console log")
|
||||
|
||||
|
@ -562,22 +507,11 @@ export class GenericRelayerPlugin implements Plugin<WorkflowPayload> {
|
|||
|
||||
parseWorkflowPayload(workflow: Workflow<WorkflowPayload>): WorkflowPayloadParsed {
|
||||
this.logger.info("Parse workflow")
|
||||
const payloadId = workflow.data.payloadId
|
||||
const vaas = workflow.data.vaas.map((s) => Buffer.from(s, "base64"))
|
||||
const coreRelayerRedeliveryVaa =
|
||||
(workflow.data.coreRelayerRedeliveryVaa &&
|
||||
parseVaaWithBytes(
|
||||
Buffer.from(workflow.data.coreRelayerRedeliveryVaa, "base64")
|
||||
)) ||
|
||||
undefined
|
||||
const coreRelayerVaa = parseVaaWithBytes(
|
||||
vaas[workflow.data.coreRelayerDeliveryVaaIndex]
|
||||
)
|
||||
const coreRelayerVaa = parseVaaWithBytes(vaas[workflow.data.coreRelayerVaaIndex])
|
||||
return {
|
||||
payloadId,
|
||||
coreRelayerDeliveryVaa: coreRelayerVaa,
|
||||
coreRelayerDeliveryVaaIndex: workflow.data.coreRelayerDeliveryVaaIndex,
|
||||
coreRelayerRedeliveryVaa,
|
||||
coreRelayerVaa,
|
||||
coreRelayerVaaIndex: workflow.data.coreRelayerVaaIndex,
|
||||
vaas,
|
||||
deliveryInstructionsContainer: parseDeliveryInstructionsContainer(
|
||||
coreRelayerVaa.payload
|
||||
|
@ -604,3 +538,115 @@ class Definition implements PluginDefinition<GenericRelayerPluginConfig, Plugin>
|
|||
|
||||
// todo: move to sdk
|
||||
export default new Definition()
|
||||
|
||||
import { arrayify } from "ethers/lib/utils"
|
||||
import { retryAsyncUntilDefined } from "ts-retry/lib/cjs/retry"
|
||||
|
||||
export enum RelayerPayloadType {
|
||||
Delivery = 1,
|
||||
Redelivery = 2,
|
||||
// DeliveryStatus = 3,
|
||||
}
|
||||
|
||||
export interface DeliveryInstructionsContainer {
|
||||
payloadId: number
|
||||
sufficientlyFunded: boolean
|
||||
instructions: DeliveryInstruction[]
|
||||
}
|
||||
|
||||
export interface DeliveryInstruction {
|
||||
targetChain: number
|
||||
targetAddress: Buffer
|
||||
refundAddress: Buffer
|
||||
maximumRefundTarget: ethers.BigNumber
|
||||
applicationBudgetTarget: ethers.BigNumber
|
||||
executionParameters: ExecutionParameters
|
||||
}
|
||||
|
||||
export interface ExecutionParameters {
|
||||
version: number
|
||||
gasLimit: number
|
||||
providerDeliveryAddress: Buffer
|
||||
}
|
||||
|
||||
export function parsePayloadType(
|
||||
stringPayload: string | Buffer | Uint8Array
|
||||
): RelayerPayloadType {
|
||||
const payload =
|
||||
typeof stringPayload === "string" ? arrayify(stringPayload) : stringPayload
|
||||
if (payload[0] == 0 || payload[0] >= 3) {
|
||||
throw new Error("Unrecogned payload type " + payload[0])
|
||||
}
|
||||
return payload[0]
|
||||
}
|
||||
|
||||
export function parseDeliveryInstructionsContainer(
|
||||
bytes: Buffer
|
||||
): DeliveryInstructionsContainer {
|
||||
dbg(bytes.length, "payload length")
|
||||
let idx = 0
|
||||
const payloadId = bytes.readUInt8(idx)
|
||||
if (payloadId !== RelayerPayloadType.Delivery) {
|
||||
throw new Error(
|
||||
`Expected Delivery payload type (${RelayerPayloadType.Delivery}), found: ${payloadId}`
|
||||
)
|
||||
}
|
||||
idx += 1
|
||||
|
||||
const sufficientlyFunded = Boolean(bytes.readUInt8(idx))
|
||||
idx += 1
|
||||
dbg(sufficientlyFunded)
|
||||
|
||||
const numInstructions = bytes.readUInt8(idx)
|
||||
dbg(numInstructions)
|
||||
idx += 1
|
||||
let instructions = [] as DeliveryInstruction[]
|
||||
for (let i = 0; i < numInstructions; ++i) {
|
||||
const targetChain = bytes.readUInt16BE(idx)
|
||||
dbg(targetChain)
|
||||
idx += 2
|
||||
const targetAddress = bytes.slice(idx, idx + 32)
|
||||
dbg(targetAddress)
|
||||
idx += 32
|
||||
const refundAddress = bytes.slice(idx, idx + 32)
|
||||
dbg(refundAddress)
|
||||
idx += 32
|
||||
const maximumRefundTarget = ethers.BigNumber.from(
|
||||
Uint8Array.prototype.subarray.call(bytes, idx, idx + 32)
|
||||
)
|
||||
dbg(maximumRefundTarget)
|
||||
idx += 32
|
||||
const applicationBudgetTarget = ethers.BigNumber.from(
|
||||
Uint8Array.prototype.subarray.call(bytes, idx, idx + 32)
|
||||
)
|
||||
dbg(applicationBudgetTarget)
|
||||
idx += 32
|
||||
const version = bytes.readUInt8(idx)
|
||||
dbg(version)
|
||||
idx += 1
|
||||
const gasLimit = bytes.readUint32BE(idx)
|
||||
dbg(gasLimit)
|
||||
idx += 4
|
||||
const providerDeliveryAddress = bytes.slice(idx, idx + 32)
|
||||
dbg(providerDeliveryAddress)
|
||||
idx += 32
|
||||
const executionParameters = { version, gasLimit, providerDeliveryAddress }
|
||||
instructions.push(
|
||||
// dumb typechain format
|
||||
{
|
||||
targetChain,
|
||||
targetAddress,
|
||||
refundAddress,
|
||||
maximumRefundTarget,
|
||||
applicationBudgetTarget,
|
||||
executionParameters,
|
||||
}
|
||||
)
|
||||
}
|
||||
console.log("here")
|
||||
return {
|
||||
payloadId,
|
||||
sufficientlyFunded,
|
||||
instructions,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,4 +6,3 @@ export type { IWormhole, LogMessagePublishedEvent } from "./ethers-contracts/IWo
|
|||
export { IWormhole__factory } from "./ethers-contracts/factories/IWormhole__factory"
|
||||
export type { RelayProvider } from "./ethers-contracts/RelayProvider"
|
||||
export { RelayProvider__factory } from "./ethers-contracts/factories/RelayProvider__factory"
|
||||
export * from './structs'
|
|
@ -1,166 +0,0 @@
|
|||
import { BigNumber, ethers} from "ethers"
|
||||
import { arrayify } from "ethers/lib/utils"
|
||||
|
||||
export enum RelayerPayloadId {
|
||||
Delivery = 1,
|
||||
Redelivery = 2,
|
||||
// DeliveryStatus = 3,
|
||||
}
|
||||
|
||||
export interface DeliveryInstructionsContainer {
|
||||
payloadId: number // 1
|
||||
sufficientlyFunded: boolean
|
||||
instructions: DeliveryInstruction[]
|
||||
}
|
||||
|
||||
export interface DeliveryInstruction {
|
||||
targetChain: number
|
||||
targetAddress: Buffer
|
||||
refundAddress: Buffer
|
||||
maximumRefundTarget: BigNumber
|
||||
applicationBudgetTarget: BigNumber
|
||||
executionParameters: ExecutionParameters
|
||||
}
|
||||
|
||||
export interface ExecutionParameters {
|
||||
version: number
|
||||
gasLimit: number
|
||||
providerDeliveryAddress: Buffer
|
||||
}
|
||||
|
||||
export interface RedeliveryByTxHashInstruction {
|
||||
payloadId: number //2
|
||||
sourceChain: number
|
||||
sourceTxHash: Buffer
|
||||
sourceNonce: BigNumber
|
||||
targetChain: number
|
||||
newMaximumRefundTarget: BigNumber
|
||||
newApplicationBudgetTarget: BigNumber
|
||||
executionParameters: ExecutionParameters
|
||||
}
|
||||
|
||||
export function parsePayloadType(
|
||||
stringPayload: string | Buffer | Uint8Array
|
||||
): RelayerPayloadId {
|
||||
const payload =
|
||||
typeof stringPayload === "string" ? arrayify(stringPayload) : stringPayload
|
||||
if (payload[0] == 0 || payload[0] >= 3) {
|
||||
throw new Error("Unrecogned payload type " + payload[0])
|
||||
}
|
||||
return payload[0]
|
||||
}
|
||||
|
||||
export function parseDeliveryInstructionsContainer(
|
||||
bytes: Buffer
|
||||
): DeliveryInstructionsContainer {
|
||||
let idx = 0
|
||||
const payloadId = bytes.readUInt8(idx)
|
||||
if (payloadId !== RelayerPayloadId.Delivery) {
|
||||
throw new Error(
|
||||
`Expected Delivery payload type (${RelayerPayloadId.Delivery}), found: ${payloadId}`
|
||||
)
|
||||
}
|
||||
idx += 1
|
||||
|
||||
const sufficientlyFunded = Boolean(bytes.readUInt8(idx))
|
||||
idx += 1
|
||||
|
||||
const numInstructions = bytes.readUInt8(idx)
|
||||
idx += 1
|
||||
let instructions = [] as DeliveryInstruction[]
|
||||
for (let i = 0; i < numInstructions; ++i) {
|
||||
const targetChain = bytes.readUInt16BE(idx)
|
||||
idx += 2
|
||||
const targetAddress = bytes.slice(idx, idx + 32)
|
||||
idx += 32
|
||||
const refundAddress = bytes.slice(idx, idx + 32)
|
||||
idx += 32
|
||||
const maximumRefundTarget = ethers.BigNumber.from(
|
||||
Uint8Array.prototype.subarray.call(bytes, idx, idx + 32)
|
||||
)
|
||||
idx += 32
|
||||
const applicationBudgetTarget = ethers.BigNumber.from(
|
||||
Uint8Array.prototype.subarray.call(bytes, idx, idx + 32)
|
||||
)
|
||||
idx += 32
|
||||
const executionParameters = parseExecutionParameters(bytes, idx)
|
||||
instructions.push(
|
||||
// dumb typechain format
|
||||
{
|
||||
targetChain,
|
||||
targetAddress,
|
||||
refundAddress,
|
||||
maximumRefundTarget,
|
||||
applicationBudgetTarget,
|
||||
executionParameters,
|
||||
}
|
||||
)
|
||||
}
|
||||
return {
|
||||
payloadId,
|
||||
sufficientlyFunded,
|
||||
instructions,
|
||||
}
|
||||
}
|
||||
|
||||
export function parseRedeliveryByTxHashInstruction(
|
||||
bytes: Buffer
|
||||
): RedeliveryByTxHashInstruction {
|
||||
let idx = 0
|
||||
const payloadId = bytes.readUInt8(idx)
|
||||
if (payloadId !== RelayerPayloadId.Redelivery) {
|
||||
throw new Error(
|
||||
`Expected Delivery payload type (${RelayerPayloadId.Redelivery}), found: ${payloadId}`
|
||||
)
|
||||
}
|
||||
idx += 1
|
||||
|
||||
const sourceChain = bytes.readUInt16BE(idx)
|
||||
idx += 2
|
||||
|
||||
const sourceTxHash = bytes.slice(idx, idx + 32)
|
||||
idx += 32
|
||||
|
||||
const sourceNonce = BigNumber.from(bytes.slice(idx, idx + 32))
|
||||
idx += 32
|
||||
const targetChain = bytes.readUInt16BE(idx)
|
||||
idx += 2
|
||||
// note: confirmed that BigNumber.from(<Buffer>) assumes big endian
|
||||
const newMaximumRefundTarget = BigNumber.from(bytes.slice(idx, idx + 32))
|
||||
idx += 32
|
||||
const newApplicationBudgetTarget = BigNumber.from(bytes.slice(idx, idx + 32))
|
||||
idx += 32
|
||||
const executionParameters = parseExecutionParameters(bytes, idx)
|
||||
return {
|
||||
payloadId,
|
||||
sourceChain,
|
||||
sourceTxHash,
|
||||
sourceNonce,
|
||||
targetChain,
|
||||
newMaximumRefundTarget,
|
||||
newApplicationBudgetTarget,
|
||||
executionParameters,
|
||||
}
|
||||
}
|
||||
|
||||
function parseExecutionParameters(bytes: Buffer, idx: number = 0): ExecutionParameters {
|
||||
const version = bytes.readUInt8(idx)
|
||||
idx += 1
|
||||
const gasLimit = bytes.readUint32BE(idx)
|
||||
idx += 4
|
||||
const providerDeliveryAddress = bytes.slice(idx, idx + 32)
|
||||
idx += 32
|
||||
return { version, gasLimit, providerDeliveryAddress }
|
||||
}
|
||||
|
||||
/*
|
||||
* Helpers
|
||||
*/
|
||||
|
||||
export function dbg<T>(x: T, msg?: string): T {
|
||||
if (msg) {
|
||||
console.log("[DEBUG] " + msg)
|
||||
}
|
||||
console.log(x)
|
||||
return x
|
||||
}
|
Loading…
Reference in New Issue