From 3c9bf9c1e23b6049ac39fb19cefb96d7d94c883e Mon Sep 17 00:00:00 2001 From: Inkvi Date: Thu, 21 Mar 2024 15:21:41 -0700 Subject: [PATCH] Refactor: share business logic between proof and sim event handlers --- ponder.schema.ts | 20 +- src/index.ts | 530 +++++++++++++++++++++++++++++++++++++++++++++++ src/proof.ts | 292 -------------------------- src/sim.ts | 417 ------------------------------------- src/stats.ts | 3 + 5 files changed, 543 insertions(+), 719 deletions(-) delete mode 100644 src/proof.ts delete mode 100644 src/sim.ts diff --git a/ponder.schema.ts b/ponder.schema.ts index 5256b36..9c7930e 100644 --- a/ponder.schema.ts +++ b/ponder.schema.ts @@ -3,7 +3,7 @@ import { createSchema } from "@ponder/core"; export default createSchema((p) => ({ Acknowledgement: p.createTable({ id: p.string(), - dispatcherAddress: p.hex(), + dispatcherAddress: p.string(), dispatcherType: p.string(), sourcePortAddress: p.string(), sourceChannelId: p.string(), @@ -19,7 +19,7 @@ export default createSchema((p) => ({ }), CloseIbcChannel: p.createTable({ id: p.string(), - dispatcherAddress: p.hex(), + dispatcherAddress: p.string(), dispatcherType: p.string(), portAddress: p.string(), channelId: p.string(), @@ -34,7 +34,7 @@ export default createSchema((p) => ({ }), ConnectIbcChannel: p.createTable({ id: p.string(), - dispatcherAddress: p.hex(), + dispatcherAddress: p.string(), dispatcherType: p.string(), portAddress: p.string(), channelId: p.string(), @@ -49,7 +49,7 @@ export default createSchema((p) => ({ }), OpenIbcChannel: p.createTable({ id: p.string(), - dispatcherAddress: p.hex(), + dispatcherAddress: p.string(), dispatcherType: p.string(), portAddress: p.string(), version: p.string(), @@ -69,7 +69,7 @@ export default createSchema((p) => ({ }), OwnershipTransferred: p.createTable({ id: p.string(), - dispatcherAddress: p.hex(), + dispatcherAddress: p.string(), dispatcherType: p.string(), previousOwner: p.string(), newOwner: p.string(), @@ -84,7 +84,7 @@ export default createSchema((p) => ({ }), RecvPacket: p.createTable({ id: p.string(), - dispatcherAddress: p.hex(), + dispatcherAddress: p.string(), dispatcherType: p.string(), destPortAddress: p.string(), destChannelId: p.string(), @@ -100,7 +100,7 @@ export default createSchema((p) => ({ }), SendPacket: p.createTable({ id: p.string(), - dispatcherAddress: p.hex(), + dispatcherAddress: p.string(), dispatcherType: p.string(), sourcePortAddress: p.string(), sourceChannelId: p.string(), @@ -118,7 +118,7 @@ export default createSchema((p) => ({ }), Timeout: p.createTable({ id: p.string(), - dispatcherAddress: p.hex(), + dispatcherAddress: p.string(), dispatcherType: p.string(), sourcePortAddress: p.string(), sourceChannelId: p.string(), @@ -134,7 +134,7 @@ export default createSchema((p) => ({ }), WriteAckPacket: p.createTable({ id: p.string(), - dispatcherAddress: p.hex(), + dispatcherAddress: p.string(), dispatcherType: p.string(), writerPortAddress: p.string(), writerChannelId: p.string(), @@ -152,7 +152,7 @@ export default createSchema((p) => ({ }), WriteTimeoutPacket: p.createTable({ id: p.string(), - dispatcherAddress: p.hex(), + dispatcherAddress: p.string(), dispatcherType: p.string(), writerPortAddress: p.string(), writerChannelId: p.string(), diff --git a/src/index.ts b/src/index.ts index e69de29..6b29908 100644 --- a/src/index.ts +++ b/src/index.ts @@ -0,0 +1,530 @@ +import { config, ponder, schema } from "@/generated"; +import { ethers } from "ethers"; +import { DISPATCHER_CLIENT, TmClient } from "./client"; +import logger from './logger'; +import { StatName, updateStats } from "./stats"; +import { Virtual } from "@ponder/core"; + +function getAddressAndDispatcherType>(contractName: "DispatcherSim" | "DispatcherProof", context: Virtual.Context) { + let address: `0x${string}` = "0x"; + let dispatcherType: string; + if (contractName == "DispatcherSim") { + address = context.contracts.DispatcherSim.address!; + dispatcherType = "sim"; + } else { + address = context.contracts.DispatcherProof.address!; + dispatcherType = "proof"; + } + return {address, dispatcherType}; +} + +async function openIbcChannel>(event: Virtual.Event, context: Virtual.Context, contractName: Virtual.ExtractContractName) { + let {address, dispatcherType} = getAddressAndDispatcherType(contractName, context); + const chainId = context.network.chainId as number; + let counterpartyPortId = event.args.counterpartyPortId; + let counterpartyChannelId = ethers.decodeBytes32String(event.args.counterpartyChannelId); + let connectionHops = event.args.connectionHops; + let portAddress = event.args.portAddress; + let version = event.args.version; + + await context.db.OpenIbcChannel.create({ + id: event.log.id, + data: { + dispatcherAddress: address, + dispatcherType: dispatcherType, + portAddress: portAddress, + version: version, + ordering: event.args.ordering, + feeEnabled: event.args.feeEnabled, + // @ts-ignore + connectionHops: connectionHops, + counterpartyPortId: counterpartyPortId, + counterpartyChannelId: counterpartyChannelId, + blockNumber: event.block.number, + blockTimestamp: event.block.timestamp, + transactionHash: event.transaction.hash, + chainId: chainId, + gas: event.transaction.gas, + maxFeePerGas: event.transaction.maxFeePerGas, + maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, + from: event.transaction.from.toString(), + }, + }); + + let channelId = ''; + let client = DISPATCHER_CLIENT[address!]; + let portId = `polyibc.${client}.${portAddress.slice(2)}`; + let state: "INIT" | "TRY" = counterpartyChannelId == "" ? "INIT" : "TRY"; + + if (state == "TRY") { + const tmClient = await TmClient.getInstance(); + let channel; + try { + channel = await tmClient.ibc.channel.channel(counterpartyPortId, counterpartyChannelId); + if (!channel.channel) { + logger.warn('No channel found for write ack: ', counterpartyChannelId, counterpartyPortId); + } else { + channelId = channel.channel.counterparty.channelId; + } + } catch (e) { + logger.warn('Skipping packet for channel: ', counterpartyChannelId); + } + } + + await context.db.Channel.create({ + id: event.log.id, + data: { + channelId: channelId, + portId: portId, + connectionHops: [...connectionHops], + counterpartyPortId: counterpartyPortId, + counterpartyChannelId: counterpartyChannelId, + blockNumber: event.block.number, + blockTimestamp: event.block.timestamp, + transactionHash: event.transaction.hash, + state: state, + } + }) +} + +ponder.on("DispatcherSim:OpenIbcChannel", async ({event, context}) => { + await openIbcChannel(event, context, "DispatcherSim"); +}); + +ponder.on("DispatcherProof:OpenIbcChannel", async ({event, context}) => { + await openIbcChannel(event, context, "DispatcherProof"); +}); + +async function connectIbcChannel>(event: Virtual.Event, context: Virtual.Context, contractName: Virtual.ExtractContractName) { + const {address, dispatcherType} = getAddressAndDispatcherType(contractName, context); + const chainId = context.network.chainId as number; + let channelId = ethers.decodeBytes32String(event.args.channelId); + let portAddress = event.args.portAddress; + + await context.db.ConnectIbcChannel.create({ + id: event.log.id, + data: { + dispatcherAddress: address || "0x", + dispatcherType: dispatcherType, + portAddress: portAddress, + channelId: channelId, + chainId: chainId, + blockNumber: event.block.number, + blockTimestamp: event.block.timestamp, + transactionHash: event.transaction.hash, + gas: event.transaction.gas, + maxFeePerGas: event.transaction.maxFeePerGas, + maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, + from: event.transaction.from.toString(), + }, + }); + + let counterpartyPortId = ''; + let counterpartyChannelId = ''; + let client = DISPATCHER_CLIENT[address!]; + let portId = `polyibc.${client}.${portAddress.slice(2)}`; + + const tmClient = await TmClient.getInstance(); + let channel; + try { + channel = await tmClient.ibc.channel.channel(portId, channelId); + if (!channel.channel) { + logger.warn('No channel found for write ack: ', channelId, portId); + } else { + counterpartyChannelId = channel.channel.counterparty.channelId; + counterpartyPortId = channel.channel.counterparty.portId; + } + } catch (e) { + logger.info('Skipping packet for channel: ', channelId); + } + + // update earliest INIT state record that have incomplete id + let channels = await context.db.Channel.findMany({ + where: {portId: portId, channelId: ""}, + orderBy: {blockTimestamp: "asc"}, + limit: 1 + }); + for (let channel of channels.items) { + await context.db.Channel.update({ + id: channel.id, + data: { + channelId: channelId, + counterpartyChannelId: counterpartyChannelId, + counterpartyPortId: counterpartyPortId, + state: "OPEN", + blockNumber: event.block.number, + blockTimestamp: event.block.timestamp, + transactionHash: event.transaction.hash, + } + }) + } + + channels = await context.db.Channel.findMany({ + where: {portId: portId, channelId: channelId}, + orderBy: {blockTimestamp: "asc"}, + limit: 1 + }); + for (let channel of channels.items) { + await context.db.Channel.update({ + id: channel.id, + data: { + state: "OPEN", + blockNumber: event.block.number, + blockTimestamp: event.block.timestamp, + transactionHash: event.transaction.hash, + } + }) + } +} + +ponder.on("DispatcherSim:ConnectIbcChannel", async ({event, context}) => { + await connectIbcChannel(event, context, "DispatcherSim"); +}); + +ponder.on("DispatcherProof:ConnectIbcChannel", async ({event, context}) => { + await connectIbcChannel(event, context, "DispatcherProof"); +}); + +async function closeIbcChannel>(event: Virtual.Event, context: Virtual.Context, contractName: Virtual.ExtractContractName) { + const {address, dispatcherType} = getAddressAndDispatcherType(contractName, context); + const chainId = context.network.chainId as number; + + await context.db.CloseIbcChannel.create({ + id: event.log.id, + data: { + dispatcherAddress: address || "0x", + dispatcherType: dispatcherType, + portAddress: event.args.portAddress, + channelId: ethers.decodeBytes32String(event.args.channelId), + blockNumber: event.block.number, + blockTimestamp: event.block.timestamp, + transactionHash: event.transaction.hash, + chainId: chainId, + gas: event.transaction.gas, + maxFeePerGas: event.transaction.maxFeePerGas, + maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, + from: event.transaction.from.toString(), + }, + }); +} + +ponder.on("DispatcherSim:CloseIbcChannel", async ({event, context}) => { + await closeIbcChannel(event, context, "DispatcherSim"); +}); + +ponder.on("DispatcherProof:CloseIbcChannel", async ({event, context}) => { + await closeIbcChannel(event, context, "DispatcherProof"); +}); + +async function ownershipTransferred>(event: Virtual.Event, context: Virtual.Context, contractName: Virtual.ExtractContractName) { + const {address, dispatcherType} = getAddressAndDispatcherType(contractName, context); + const chainId = context.network.chainId as number; + + await context.db.OwnershipTransferred.create({ + id: event.log.id, + data: { + dispatcherAddress: address || "0x", + dispatcherType: dispatcherType, + previousOwner: event.args.previousOwner, + newOwner: event.args.newOwner, + blockNumber: event.block.number, + blockTimestamp: event.block.timestamp, + transactionHash: event.transaction.hash, + chainId: chainId, + gas: event.transaction.gas, + maxFeePerGas: event.transaction.maxFeePerGas, + maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, + from: event.transaction.from.toString(), + }, + }); +} + +ponder.on("DispatcherSim:OwnershipTransferred", async ({event, context}) => { + await ownershipTransferred(event, context, "DispatcherSim"); +}); + +ponder.on("DispatcherProof:OwnershipTransferred", async ({event, context}) => { + await ownershipTransferred(event, context, "DispatcherProof"); +}); + +async function sendPacket>(event: Virtual.Event, context: Virtual.Context, contractName: Virtual.ExtractContractName) { + const {address, dispatcherType} = getAddressAndDispatcherType(contractName, context); + const chainId = context.network.chainId as number; + let sourceChannelId = ethers.decodeBytes32String(event.args.sourceChannelId); + let srcPortAddress = event.args.sourcePortAddress; + let sequence = event.args.sequence; + + await context.db.SendPacket.create({ + id: event.log.id, + data: { + dispatcherAddress: address || "0x", + dispatcherType: dispatcherType, + sourcePortAddress: srcPortAddress, + sourceChannelId: sourceChannelId, + packet: event.args.packet, + sequence: sequence, + timeoutTimestamp: event.args.timeoutTimestamp, + blockNumber: event.block.number, + blockTimestamp: event.block.timestamp, + transactionHash: event.transaction.hash, + chainId: chainId, + gas: event.transaction.gas, + maxFeePerGas: event.transaction.maxFeePerGas, + maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, + from: event.transaction.from.toString(), + }, + }); + + let client = DISPATCHER_CLIENT[address!]; + const srcPortId = `polyibc.${client}.${srcPortAddress.slice(2)}`; + const key = `${srcPortId}-${sourceChannelId}-${sequence}`; + + await context.db.Packet.upsert({ + id: key, + create: { + state: "SENT", + sendPacketId: event.log.id, + }, + update: { + sendPacketId: event.log.id, + } + }); + + await updateStats(context.db.Stat, StatName.SendPackets) +} + +ponder.on("DispatcherSim:SendPacket", async ({event, context}) => { + await sendPacket(event, context, "DispatcherSim"); +}); + +ponder.on("DispatcherProof:SendPacket", async ({event, context}) => { + await sendPacket(event, context, "DispatcherProof"); +}); + +async function writeAckPacket>(event: Virtual.Event, context: Virtual.Context, contractName: Virtual.ExtractContractName) { + const {address, dispatcherType} = getAddressAndDispatcherType(contractName, context); + const chainId = context.network.chainId as number; + let writerPortAddress = event.args.writerPortAddress; + let writerChannelId = ethers.decodeBytes32String(event.args.writerChannelId); + let sequence = event.args.sequence; + + await context.db.WriteAckPacket.create({ + id: event.log.id, + data: { + dispatcherAddress: address || "0x", + dispatcherType: dispatcherType, + writerPortAddress: writerPortAddress, + writerChannelId: writerChannelId, + sequence: sequence, + ackPacketSuccess: event.args.ackPacket.success, + ackPacketData: event.args.ackPacket.data, + blockNumber: event.block.number, + blockTimestamp: event.block.timestamp, + transactionHash: event.transaction.hash, + chainId: chainId, + gas: event.transaction.gas, + maxFeePerGas: event.transaction.maxFeePerGas, + maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, + from: event.transaction.from.toString(), + }, + }); + + let client = DISPATCHER_CLIENT[address!]; + const destPortId = `polyibc.${client}.${writerPortAddress.slice(2)}`; + const tmClient = await TmClient.getInstance(); + let channel; + try { + channel = await tmClient.ibc.channel.channel(destPortId, writerChannelId); + } catch (e) { + logger.info('Skipping packet for channel: ', writerChannelId); + return; + } + + if (!channel.channel) { + logger.warn('No channel found for write ack: ', writerChannelId, writerPortAddress); + return; + } + + const key = `${channel.channel.counterparty.portId}-${channel.channel.counterparty.channelId}-${sequence}`; + await context.db.Packet.upsert({ + id: key, + create: { + state: "WRITE_ACK", + writeAckPacketId: event.log.id, + }, + update: ({current}) => { + let state = current.state; + if (current.state == "SENT") { + state = "WRITE_ACK" + } + return { + writeAckPacketId: event.log.id, + state: state, + }; + }, + }); + + await updateStats(context.db.Stat, StatName.WriteAckPacket); +} + +ponder.on("DispatcherSim:WriteAckPacket", async ({event, context}) => { + await writeAckPacket(event, context, "DispatcherSim"); +}); + +ponder.on("DispatcherProof:WriteAckPacket", async ({event, context}) => { + await writeAckPacket(event, context, "DispatcherProof"); +}); + +async function recvPacket>(event: Virtual.Event, context: Virtual.Context, contractName: Virtual.ExtractContractName) { + const {address, dispatcherType} = getAddressAndDispatcherType(contractName, context); + const chainId = context.network.chainId as number; + + await context.db.RecvPacket.create({ + id: event.log.id, + data: { + dispatcherAddress: address || "0x", + dispatcherType: dispatcherType, + destPortAddress: event.args.destPortAddress, + destChannelId: ethers.decodeBytes32String(event.args.destChannelId), + sequence: event.args.sequence, + blockNumber: event.block.number, + blockTimestamp: event.block.timestamp, + transactionHash: event.transaction.hash, + chainId: chainId, + gas: event.transaction.gas, + maxFeePerGas: event.transaction.maxFeePerGas, + maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, + from: event.transaction.from.toString(), + }, + }); + + await updateStats(context.db.Stat, StatName.RecvPackets) +} + +ponder.on("DispatcherSim:RecvPacket", async ({event, context}) => { + await recvPacket(event, context, "DispatcherSim"); +}); + +ponder.on("DispatcherProof:RecvPacket", async ({event, context}) => { + await recvPacket(event, context, "DispatcherProof"); +}); + +async function acknowledgement>(event: Virtual.Event, context: Virtual.Context, contractName: Virtual.ExtractContractName) { + const {address, dispatcherType} = getAddressAndDispatcherType(contractName, context); + const chainId = context.network.chainId as number; + let sourceChannelId = ethers.decodeBytes32String(event.args.sourceChannelId); + let sequence = event.args.sequence; + let srcPortAddress = event.args.sourcePortAddress; + + await context.db.Acknowledgement.create({ + id: event.log.id, + data: { + dispatcherAddress: address || "0x", + dispatcherType: dispatcherType, + sourcePortAddress: srcPortAddress, + sourceChannelId: sourceChannelId, + sequence: sequence, + blockNumber: event.block.number, + blockTimestamp: event.block.timestamp, + transactionHash: event.transaction.hash, + chainId: chainId, + gas: event.transaction.gas, + maxFeePerGas: event.transaction.maxFeePerGas, + maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, + from: event.transaction.from.toString(), + }, + }); + + let client = DISPATCHER_CLIENT[address!]; + const srcPortId = `polyibc.${client}.${srcPortAddress.slice(2)}`; + const key = `${srcPortId}-${sourceChannelId}-${sequence}`; + + await context.db.Packet.upsert({ + id: key, + create: { + state: "ACK", + ackPacketId: event.log.id, + }, + update: { + ackPacketId: event.log.id, + state: "ACK", + } + }); + + await updateStats(context.db.Stat, StatName.AckPackets) +} + +ponder.on("DispatcherSim:Acknowledgement", async ({event, context}) => { + await acknowledgement(event, context, "DispatcherSim"); +}); + +ponder.on("DispatcherProof:Acknowledgement", async ({event, context}) => { + await acknowledgement(event, context, "DispatcherProof"); +}); + +async function timeout>(event: Virtual.Event, context: Virtual.Context, contractName: Virtual.ExtractContractName) { + const {address, dispatcherType} = getAddressAndDispatcherType(contractName, context); + const chainId = context.network.chainId as number; + + await context.db.Timeout.create({ + id: event.log.id, + data: { + dispatcherAddress: address || "0x", + dispatcherType: dispatcherType, + sourcePortAddress: event.args.sourcePortAddress, + sourceChannelId: ethers.decodeBytes32String(event.args.sourceChannelId), + sequence: event.args.sequence, + blockNumber: event.block.number, + blockTimestamp: event.block.timestamp, + transactionHash: event.transaction.hash, + chainId: chainId, + gas: event.transaction.gas, + maxFeePerGas: event.transaction.maxFeePerGas, + maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, + from: event.transaction.from.toString(), + }, + }); +} + +ponder.on("DispatcherSim:Timeout", async ({event, context}) => { + await timeout(event, context, "DispatcherSim"); +}); + +ponder.on("DispatcherProof:Timeout", async ({event, context}) => { + await timeout(event, context, "DispatcherProof"); +}); + +async function writeTimeoutPacket>(event: Virtual.Event, context: Virtual.Context, contractName: Virtual.ExtractContractName) { + const {address, dispatcherType} = getAddressAndDispatcherType(contractName, context); + const chainId = context.network.chainId as number; + + await context.db.WriteTimeoutPacket.create({ + id: event.log.id, + data: { + dispatcherAddress: address || "0x", + dispatcherType: dispatcherType, + writerPortAddress: event.args.writerPortAddress, + writerChannelId: ethers.decodeBytes32String(event.args.writerChannelId), + sequence: event.args.sequence, + timeoutHeightRevisionNumber: event.args.timeoutHeight.revision_number, + timeoutHeightRevisionHeight: event.args.timeoutHeight.revision_height, + timeoutTimestamp: event.args.timeoutTimestamp, + blockNumber: event.block.number, + blockTimestamp: event.block.timestamp, + transactionHash: event.transaction.hash, + chainId: chainId, + gas: event.transaction.gas, + maxFeePerGas: event.transaction.maxFeePerGas, + maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, + from: event.transaction.from.toString(), + }, + }); +} + +ponder.on("DispatcherSim:WriteTimeoutPacket", async ({event, context}) => { + await writeTimeoutPacket(event, context, "DispatcherSim"); +}); + +ponder.on("DispatcherProof:WriteTimeoutPacket", async ({event, context}) => { + await writeTimeoutPacket(event, context, "DispatcherProof"); +}); \ No newline at end of file diff --git a/src/proof.ts b/src/proof.ts deleted file mode 100644 index efffcdf..0000000 --- a/src/proof.ts +++ /dev/null @@ -1,292 +0,0 @@ -import { ponder } from "@/generated"; -import { ethers } from "ethers"; -import { DISPATCHER_CLIENT, TmClient } from "./client"; -import logger from './logger'; -import { StatName, updateStats } from "./stats"; - -ponder.on("DispatcherProof:ConnectIbcChannel", async ({event, context}) => { - const {address} = context.contracts.DispatcherProof; - const chainId = context.network.chainId; - await context.db.ConnectIbcChannel.create({ - id: event.log.id, - data: { - dispatcherAddress: address || "0x", - dispatcherType: "proof", - portAddress: event.args.portAddress, - channelId: ethers.decodeBytes32String(event.args.channelId), - blockNumber: event.block.number, - blockTimestamp: event.block.timestamp, - transactionHash: event.transaction.hash, - chainId: chainId, - gas: event.transaction.gas, - maxFeePerGas: event.transaction.maxFeePerGas, - maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, - from: event.transaction.from.toString(), - }, - }); -}); - -ponder.on("DispatcherProof:CloseIbcChannel", async ({event, context}) => { - const {address} = context.contracts.DispatcherProof; - const chainId = context.network.chainId; - await context.db.CloseIbcChannel.create({ - id: event.log.id, - data: { - dispatcherAddress: address || "0x", - dispatcherType: "proof", - portAddress: event.args.portAddress, - channelId: ethers.decodeBytes32String(event.args.channelId), - blockNumber: event.block.number, - blockTimestamp: event.block.timestamp, - transactionHash: event.transaction.hash, - chainId: chainId, - gas: event.transaction.gas, - maxFeePerGas: event.transaction.maxFeePerGas, - maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, - from: event.transaction.from.toString(), - }, - }); -}); - -ponder.on("DispatcherProof:OwnershipTransferred", async ({event, context}) => { - const {address} = context.contracts.DispatcherProof; - const chainId = context.network.chainId; - await context.db.OwnershipTransferred.create({ - id: event.log.id, - data: { - dispatcherAddress: address || "0x", - dispatcherType: "proof", - previousOwner: event.args.previousOwner, - newOwner: event.args.newOwner, - blockNumber: event.block.number, - blockTimestamp: event.block.timestamp, - transactionHash: event.transaction.hash, - chainId: chainId, - gas: event.transaction.gas, - maxFeePerGas: event.transaction.maxFeePerGas, - maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, - from: event.transaction.from.toString(), - }, - }); -}); - -ponder.on("DispatcherProof:SendPacket", async ({event, context}) => { - const {address} = context.contracts.DispatcherProof; - const chainId = context.network.chainId; - await context.db.SendPacket.create({ - id: event.log.id, - data: { - dispatcherAddress: address || "0x", - dispatcherType: "proof", - sourcePortAddress: event.args.sourcePortAddress, - sourceChannelId: ethers.decodeBytes32String(event.args.sourceChannelId), - packet: event.args.packet, - sequence: event.args.sequence, - timeoutTimestamp: event.args.timeoutTimestamp, - blockNumber: event.block.number, - blockTimestamp: event.block.timestamp, - transactionHash: event.transaction.hash, - chainId: chainId, - gas: event.transaction.gas, - maxFeePerGas: event.transaction.maxFeePerGas, - maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, - from: event.transaction.from.toString(), - }, - }); - await updateStats(context.db.Stat, StatName.SendPackets) -}); - -ponder.on("DispatcherProof:RecvPacket", async ({event, context}) => { - const {address} = context.contracts.DispatcherProof; - const chainId = context.network.chainId; - let destChannelId = ethers.decodeBytes32String(event.args.destChannelId); - let destPortAddress = event.args.destPortAddress; - let sequence = event.args.sequence; - await context.db.RecvPacket.create({ - id: event.log.id, - data: { - dispatcherAddress: address || "0x", - dispatcherType: "proof", - destPortAddress: destPortAddress, - destChannelId: destChannelId, - sequence: sequence, - blockNumber: event.block.number, - blockTimestamp: event.block.timestamp, - transactionHash: event.transaction.hash, - chainId: chainId, - gas: event.transaction.gas, - maxFeePerGas: event.transaction.maxFeePerGas, - maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, - from: event.transaction.from.toString(), - }, - }); - const tmClient = await TmClient.getInstance(); - let client = DISPATCHER_CLIENT[address!]; - let channel; - try { - channel = await tmClient.ibc.channel.channel(`polyibc.${client}.${destPortAddress.slice(2)}`, destChannelId); - } catch (e) { - logger.info('Skipping packet for channel: ', destChannelId); - return; - } - if (!channel.channel) { - logger.warn('No channel found for write ack: ', destChannelId, destPortAddress); - return; - } - const key = `${channel.channel.counterparty.portId}-${channel.channel.counterparty.channelId}-${sequence}`; - await context.db.Packet.upsert({ - id: key, - create: { - state: "RECV", - recvPacketId: event.log.id, - }, - update: ({current}) => { - let state = current.state; - if (["SENT", "WRITE_ACK"].includes(current.state)) { - state = "RECV"; - } - return { - recvPacketId: event.log.id, - state: state, - }; - }, - }); - await updateStats(context.db.Stat, StatName.RecvPackets) -}); - -ponder.on("DispatcherProof:WriteAckPacket", async ({event, context}) => { - const {address} = context.contracts.DispatcherProof; - const chainId = context.network.chainId; - let writerPortAddress = event.args.writerPortAddress; - let writerChannelId = ethers.decodeBytes32String(event.args.writerChannelId); - let sequence = event.args.sequence; - await context.db.WriteAckPacket.create({ - id: event.log.id, - data: { - dispatcherAddress: address || "0x", - dispatcherType: "proof", - writerPortAddress: writerPortAddress, - writerChannelId: writerChannelId, - sequence: sequence, - ackPacketSuccess: event.args.ackPacket.success, - ackPacketData: event.args.ackPacket.data, - blockNumber: event.block.number, - blockTimestamp: event.block.timestamp, - transactionHash: event.transaction.hash, - chainId: chainId, - gas: event.transaction.gas, - maxFeePerGas: event.transaction.maxFeePerGas, - maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, - from: event.transaction.from.toString(), - }, - }); - - let client = DISPATCHER_CLIENT[address!]; - const destPortId = `polyibc.${client}.${writerPortAddress.slice(2)}`; - const tmClient = await TmClient.getInstance(); - let channel; - try { - channel = await tmClient.ibc.channel.channel(destPortId, writerChannelId); - } catch (e) { - logger.info('Skipping packet for channel: ', writerChannelId); - return; - } - if (!channel.channel) { - logger.warn('No channel found for write ack: ', writerChannelId, writerPortAddress); - return; - } - const key = `${channel.channel.counterparty.portId}-${channel.channel.counterparty.channelId}-${sequence}`; - await context.db.Packet.upsert({ - id: key, - create: { - state: "WRITE_ACK", - writeAckPacketId: event.log.id, - }, - update: ({current}) => { - let state = current.state; - if (current.state == "SENT") { - state = "WRITE_ACK" - } - return { - writeAckPacketId: event.log.id, - state: state, - }; - }, - }); - - await updateStats(context.db.Stat, StatName.WriteAckPacket); -}); - - -ponder.on("DispatcherProof:Acknowledgement", async ({event, context}) => { - const {address} = context.contracts.DispatcherProof; - const chainId = context.network.chainId; - await context.db.Acknowledgement.create({ - id: event.log.id, - data: { - dispatcherAddress: address || "0x", - dispatcherType: "proof", - sourcePortAddress: event.args.sourcePortAddress, - sourceChannelId: ethers.decodeBytes32String(event.args.sourceChannelId), - sequence: event.args.sequence, - blockNumber: event.block.number, - blockTimestamp: event.block.timestamp, - transactionHash: event.transaction.hash, - chainId: chainId, - gas: event.transaction.gas, - maxFeePerGas: event.transaction.maxFeePerGas, - maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, - from: event.transaction.from.toString(), - }, - }); - await updateStats(context.db.Stat, StatName.AckPackets) -}); - -ponder.on("DispatcherProof:Timeout", async ({event, context}) => { - const {address} = context.contracts.DispatcherProof; - const chainId = context.network.chainId; - await context.db.Timeout.create({ - id: event.log.id, - data: { - dispatcherAddress: address || "0x", - dispatcherType: "proof", - sourcePortAddress: event.args.sourcePortAddress, - sourceChannelId: ethers.decodeBytes32String(event.args.sourceChannelId), - sequence: event.args.sequence, - blockNumber: event.block.number, - blockTimestamp: event.block.timestamp, - transactionHash: event.transaction.hash, - chainId: chainId, - gas: event.transaction.gas, - maxFeePerGas: event.transaction.maxFeePerGas, - maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, - from: event.transaction.from.toString(), - }, - }); -}); - -ponder.on("DispatcherProof:WriteTimeoutPacket", async ({event, context}) => { - const {address} = context.contracts.DispatcherProof; - const chainId = context.network.chainId; - await context.db.WriteTimeoutPacket.create({ - id: event.log.id, - data: { - chainId: chainId, - dispatcherAddress: address || "0x", - dispatcherType: "proof", - writerPortAddress: event.args.writerPortAddress, - writerChannelId: ethers.decodeBytes32String(event.args.writerChannelId), - sequence: event.args.sequence, - timeoutHeightRevisionNumber: event.args.timeoutHeight.revision_number, - timeoutHeightRevisionHeight: event.args.timeoutHeight.revision_height, - timeoutTimestamp: event.args.timeoutTimestamp, - blockNumber: event.block.number, - blockTimestamp: event.block.timestamp, - transactionHash: event.transaction.hash, - gas: event.transaction.gas, - maxFeePerGas: event.transaction.maxFeePerGas, - maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, - from: event.transaction.from.toString(), - }, - }); -}); \ No newline at end of file diff --git a/src/sim.ts b/src/sim.ts deleted file mode 100644 index 06f1b56..0000000 --- a/src/sim.ts +++ /dev/null @@ -1,417 +0,0 @@ -import { ponder } from "@/generated"; -import { ethers } from "ethers"; -import { DISPATCHER_CLIENT, TmClient } from "./client"; -import logger from './logger'; -import { StatName, updateStats } from "./stats"; - -ponder.on("DispatcherSim:OpenIbcChannel", async ({event, context}) => { - const {address} = context.contracts.DispatcherSim; - const chainId = context.network.chainId; - let counterpartyPortId = event.args.counterpartyPortId; - let counterpartyChannelId = ethers.decodeBytes32String(event.args.counterpartyChannelId); - let connectionHops = event.args.connectionHops; - let portAddress = event.args.portAddress; - let version = event.args.version; - await context.db.OpenIbcChannel.create({ - id: event.log.id, - data: { - dispatcherAddress: address || "0x", - dispatcherType: "sim", - portAddress: portAddress, - version: version, - ordering: event.args.ordering, - feeEnabled: event.args.feeEnabled, - // @ts-ignore - connectionHops: connectionHops, - counterpartyPortId: counterpartyPortId, - counterpartyChannelId: counterpartyChannelId, - blockNumber: event.block.number, - blockTimestamp: event.block.timestamp, - transactionHash: event.transaction.hash, - chainId: chainId, - gas: event.transaction.gas, - maxFeePerGas: event.transaction.maxFeePerGas, - maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, - from: event.transaction.from.toString(), - }, - }); - - let channelId = ''; - let client = DISPATCHER_CLIENT[address!]; - let portId = `polyibc.${client}.${portAddress.slice(2)}`; - let state: "INIT" | "TRY" = counterpartyChannelId == "" ? "INIT" : "TRY"; - - if (state == "TRY") { - const tmClient = await TmClient.getInstance(); - let channel; - try { - channel = await tmClient.ibc.channel.channel(counterpartyPortId, counterpartyChannelId); - if (!channel.channel) { - logger.warn('No channel found for write ack: ', counterpartyChannelId, counterpartyPortId); - } else { - channelId = channel.channel.counterparty.channelId; - } - } catch (e) { - logger.warn('Skipping packet for channel: ', counterpartyChannelId); - } - } - - await context.db.Channel.create({ - id: event.log.id, - data: { - channelId: channelId, - portId: portId, - connectionHops: [...connectionHops], - counterpartyPortId: counterpartyPortId, - counterpartyChannelId: counterpartyChannelId, - blockNumber: event.block.number, - blockTimestamp: event.block.timestamp, - transactionHash: event.transaction.hash, - state: state, - } - }) -}); - -ponder.on("DispatcherSim:ConnectIbcChannel", async ({event, context}) => { - const {address} = context.contracts.DispatcherSim; - const chainId = context.network.chainId; - let channelId = ethers.decodeBytes32String(event.args.channelId); - let portAddress = event.args.portAddress; - await context.db.ConnectIbcChannel.create({ - id: event.log.id, - data: { - dispatcherAddress: address || "0x", - dispatcherType: "sim", - portAddress: portAddress, - channelId: channelId, - chainId: chainId, - blockNumber: event.block.number, - blockTimestamp: event.block.timestamp, - transactionHash: event.transaction.hash, - gas: event.transaction.gas, - maxFeePerGas: event.transaction.maxFeePerGas, - maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, - from: event.transaction.from.toString(), - }, - }); - - let counterpartyPortId = ''; - let counterpartyChannelId = ''; - let client = DISPATCHER_CLIENT[address!]; - let portId = `polyibc.${client}.${portAddress.slice(2)}`; - - const tmClient = await TmClient.getInstance(); - let channel; - try { - channel = await tmClient.ibc.channel.channel(portId, channelId); - if (!channel.channel) { - logger.warn('No channel found for write ack: ', channelId, portId); - } else { - counterpartyChannelId = channel.channel.counterparty.channelId; - counterpartyPortId = channel.channel.counterparty.portId; - } - } catch (e) { - logger.info('Skipping packet for channel: ', channelId); - } - - // update earliest INIT state record that have incomplete id - let channels = await context.db.Channel.findMany({ - where: {portId: portId, channelId: ""}, - orderBy: {blockTimestamp: "asc"}, - limit: 1 - }); - for (let channel of channels.items) { - await context.db.Channel.update({ - id: channel.id, - data: { - channelId: channelId, - counterpartyChannelId: counterpartyChannelId, - counterpartyPortId: counterpartyPortId, - state: "OPEN", - blockNumber: event.block.number, - blockTimestamp: event.block.timestamp, - transactionHash: event.transaction.hash, - } - }) - } - - channels = await context.db.Channel.findMany({ - where: {portId: portId, channelId: channelId}, - orderBy: {blockTimestamp: "asc"}, - limit: 1 - }); - for (let channel of channels.items) { - await context.db.Channel.update({ - id: channel.id, - data: { - state: "OPEN", - blockNumber: event.block.number, - blockTimestamp: event.block.timestamp, - transactionHash: event.transaction.hash, - } - }) - } -}); - -ponder.on("DispatcherSim:CloseIbcChannel", async ({event, context}) => { - const {address} = context.contracts.DispatcherSim; - const chainId = context.network.chainId; - await context.db.CloseIbcChannel.create({ - id: event.log.id, - data: { - dispatcherAddress: address || "0x", - dispatcherType: "sim", - portAddress: event.args.portAddress, - channelId: ethers.decodeBytes32String(event.args.channelId), - blockNumber: event.block.number, - blockTimestamp: event.block.timestamp, - transactionHash: event.transaction.hash, - chainId: chainId, - gas: event.transaction.gas, - maxFeePerGas: event.transaction.maxFeePerGas, - maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, - from: event.transaction.from.toString(), - }, - }); -}); - -ponder.on("DispatcherSim:OwnershipTransferred", async ({event, context}) => { - const {address} = context.contracts.DispatcherSim; - const chainId = context.network.chainId; - await context.db.OwnershipTransferred.create({ - id: event.log.id, - data: { - dispatcherAddress: address || "0x", - dispatcherType: "sim", - previousOwner: event.args.previousOwner, - newOwner: event.args.newOwner, - blockNumber: event.block.number, - blockTimestamp: event.block.timestamp, - transactionHash: event.transaction.hash, - chainId: chainId, - gas: event.transaction.gas, - maxFeePerGas: event.transaction.maxFeePerGas, - maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, - from: event.transaction.from.toString(), - }, - }); -}); - -ponder.on("DispatcherSim:SendPacket", async ({event, context}) => { - const {address} = context.contracts.DispatcherSim; - const chainId = context.network.chainId; - let sourceChannelId = ethers.decodeBytes32String(event.args.sourceChannelId); - let srcPortAddress = event.args.sourcePortAddress; - let sequence = event.args.sequence; - await context.db.SendPacket.create({ - id: event.log.id, - data: { - dispatcherAddress: address || "0x", - dispatcherType: "sim", - sourcePortAddress: srcPortAddress, - sourceChannelId: sourceChannelId, - packet: event.args.packet, - sequence: sequence, - timeoutTimestamp: event.args.timeoutTimestamp, - blockNumber: event.block.number, - blockTimestamp: event.block.timestamp, - transactionHash: event.transaction.hash, - chainId: chainId, - gas: event.transaction.gas, - maxFeePerGas: event.transaction.maxFeePerGas, - maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, - from: event.transaction.from.toString(), - }, - }); - let client = DISPATCHER_CLIENT[address!]; - const srcPortId = `polyibc.${client}.${srcPortAddress.slice(2)}`; - const key = `${srcPortId}-${sourceChannelId}-${sequence}`; - await context.db.Packet.upsert({ - id: key, - create: { - state: "SENT", - sendPacketId: event.log.id, - }, - update: { - sendPacketId: event.log.id, - } - }); - - await updateStats(context.db.Stat, StatName.SendPackets) -}); - -ponder.on("DispatcherSim:WriteAckPacket", async ({event, context}) => { - const {address} = context.contracts.DispatcherSim; - const chainId = context.network.chainId; - let writerPortAddress = event.args.writerPortAddress; - let writerChannelId = ethers.decodeBytes32String(event.args.writerChannelId); - let sequence = event.args.sequence; - await context.db.WriteAckPacket.create({ - id: event.log.id, - data: { - dispatcherAddress: address || "0x", - dispatcherType: "sim", - writerPortAddress: writerPortAddress, - writerChannelId: writerChannelId, - sequence: sequence, - ackPacketSuccess: event.args.ackPacket.success, - ackPacketData: event.args.ackPacket.data, - blockNumber: event.block.number, - blockTimestamp: event.block.timestamp, - transactionHash: event.transaction.hash, - chainId: chainId, - gas: event.transaction.gas, - maxFeePerGas: event.transaction.maxFeePerGas, - maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, - from: event.transaction.from.toString(), - }, - }); - let client = DISPATCHER_CLIENT[address!]; - const destPortId = `polyibc.${client}.${writerPortAddress.slice(2)}`; - const tmClient = await TmClient.getInstance(); - let channel; - try { - channel = await tmClient.ibc.channel.channel(destPortId, writerChannelId); - } catch (e) { - logger.info('Skipping packet for channel: ', writerChannelId); - return; - } - if (!channel.channel) { - logger.warn('No channel found for write ack: ', writerChannelId, writerPortAddress); - return; - } - const key = `${channel.channel.counterparty.portId}-${channel.channel.counterparty.channelId}-${sequence}`; - await context.db.Packet.upsert({ - id: key, - create: { - state: "WRITE_ACK", - writeAckPacketId: event.log.id, - }, - update: ({current}) => { - let state = current.state; - if (current.state == "SENT") { - state = "WRITE_ACK" - } - return { - writeAckPacketId: event.log.id, - state: state, - }; - }, - }); - - await updateStats(context.db.Stat, StatName.WriteAckPacket); -}); - -ponder.on("DispatcherSim:RecvPacket", async ({event, context}) => { - const {address} = context.contracts.DispatcherSim; - const chainId = context.network.chainId; - await context.db.RecvPacket.create({ - id: event.log.id, - data: { - dispatcherAddress: address || "0x", - dispatcherType: "sim", - destPortAddress: event.args.destPortAddress, - destChannelId: ethers.decodeBytes32String(event.args.destChannelId), - sequence: event.args.sequence, - blockNumber: event.block.number, - blockTimestamp: event.block.timestamp, - transactionHash: event.transaction.hash, - chainId: chainId, - gas: event.transaction.gas, - maxFeePerGas: event.transaction.maxFeePerGas, - maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, - from: event.transaction.from.toString(), - }, - }); - await updateStats(context.db.Stat, StatName.RecvPackets) -}); - -ponder.on("DispatcherSim:Acknowledgement", async ({event, context}) => { - const {address} = context.contracts.DispatcherSim; - const chainId = context.network.chainId; - let sourceChannelId = ethers.decodeBytes32String(event.args.sourceChannelId); - let sequence = event.args.sequence; - let srcPortAddress = event.args.sourcePortAddress; - await context.db.Acknowledgement.create({ - id: event.log.id, - data: { - dispatcherAddress: address || "0x", - dispatcherType: "sim", - sourcePortAddress: srcPortAddress, - sourceChannelId: sourceChannelId, - sequence: sequence, - blockNumber: event.block.number, - blockTimestamp: event.block.timestamp, - transactionHash: event.transaction.hash, - chainId: chainId, - gas: event.transaction.gas, - maxFeePerGas: event.transaction.maxFeePerGas, - maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, - from: event.transaction.from.toString(), - }, - }); - let client = DISPATCHER_CLIENT[address!]; - const srcPortId = `polyibc.${client}.${srcPortAddress.slice(2)}`; - const key = `${srcPortId}-${sourceChannelId}-${sequence}`; - await context.db.Packet.upsert({ - id: key, - create: { - state: "ACK", - ackPacketId: event.log.id, - }, - update: { - ackPacketId: event.log.id, - state: "ACK", - } - }); - await updateStats(context.db.Stat, StatName.AckPackets) -}); - -ponder.on("DispatcherSim:Timeout", async ({event, context}) => { - const {address} = context.contracts.DispatcherSim; - const chainId = context.network.chainId; - await context.db.Timeout.create({ - id: event.log.id, - data: { - dispatcherAddress: address || "0x", - dispatcherType: "sim", - sourcePortAddress: event.args.sourcePortAddress, - sourceChannelId: ethers.decodeBytes32String(event.args.sourceChannelId), - sequence: event.args.sequence, - blockNumber: event.block.number, - blockTimestamp: event.block.timestamp, - transactionHash: event.transaction.hash, - chainId: chainId, - gas: event.transaction.gas, - maxFeePerGas: event.transaction.maxFeePerGas, - maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, - from: event.transaction.from.toString(), - }, - }); -}); - -ponder.on("DispatcherSim:WriteTimeoutPacket", async ({event, context}) => { - const {address} = context.contracts.DispatcherSim; - const chainId = context.network.chainId; - await context.db.WriteTimeoutPacket.create({ - id: event.log.id, - data: { - dispatcherAddress: address || "0x", - dispatcherType: "sim", - writerPortAddress: event.args.writerPortAddress, - writerChannelId: ethers.decodeBytes32String(event.args.writerChannelId), - sequence: event.args.sequence, - timeoutHeightRevisionNumber: event.args.timeoutHeight.revision_number, - timeoutHeightRevisionHeight: event.args.timeoutHeight.revision_height, - timeoutTimestamp: event.args.timeoutTimestamp, - blockNumber: event.block.number, - blockTimestamp: event.block.timestamp, - transactionHash: event.transaction.hash, - chainId: chainId, - gas: event.transaction.gas, - maxFeePerGas: event.transaction.maxFeePerGas, - maxPriorityFeePerGas: event.transaction.maxPriorityFeePerGas, - from: event.transaction.from.toString(), - }, - }); -}); \ No newline at end of file diff --git a/src/stats.ts b/src/stats.ts index c4e2a28..aaa660d 100644 --- a/src/stats.ts +++ b/src/stats.ts @@ -7,6 +7,9 @@ export enum StatName { RecvPackets = 'RecvPackets', AckPackets = 'AckPackets', WriteAckPacket = 'WriteAckPacket', + OpenIBCChannel = 'OpenIBCChannel', + CloseIBCChannel = 'CloseIBCChannel', + ConnectIbcChannel = 'ConnectIbcChannel', } export async function updateStats["Stat"]>>(Stat: T, id: StatName) {