From 50b4c332c4e61186e96bb6ba1f67f199cb3c192c Mon Sep 17 00:00:00 2001 From: Fraz Arshad Date: Tue, 30 Apr 2024 18:11:09 +0500 Subject: [PATCH 1/8] feat: added event handler for send-packet --- project.ts | 10 +++++++++ schema.graphql | 11 ++++++++++ src/mappings/constants.ts | 8 +++++-- src/mappings/mappingHandlers.ts | 37 +++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 2 deletions(-) diff --git a/project.ts b/project.ts index 39aaf9dce..a0c551e2c 100644 --- a/project.ts +++ b/project.ts @@ -80,6 +80,16 @@ const project: CosmosProject = { // }, // }, // }, + { + handler: "handleIbcSendPacketEvent", + kind: CosmosHandlerKind.Event, + filter: { + type: "send_packet", + messageFilter: { + type: "/ibc.applications.transfer.v1.MsgTransfer", + }, + }, + }, { handler: "handleStateChangeEvent", kind: CosmosHandlerKind.Event, diff --git a/schema.graphql b/schema.graphql index a563d0482..c219c72be 100644 --- a/schema.graphql +++ b/schema.graphql @@ -241,3 +241,14 @@ type ReserveMetrics @entity { totalFeeMinted: BigInt! allocations: [ReserveAllocationMetrics] @derivedFrom(field: "reserveMetrics") } + +type IBCChannel @entity { + id: ID! + blockTime: Date! + blockHeight: BigInt! + channelName: String! + srcAddress: String! + destAddress: String! + denomination: String! + amount: String! +} diff --git a/src/mappings/constants.ts b/src/mappings/constants.ts index 465b93021..514247f75 100644 --- a/src/mappings/constants.ts +++ b/src/mappings/constants.ts @@ -17,12 +17,14 @@ export const EVENT_TYPES = { STORAGE: "storage", SUBMIT_PROPOSAL: "submit_proposal", TRANSFER: "transfer", + SEND_PACKET: "send_packet", + RECEIVE_PACKET: "recv_packet", }; export const VAULT_STATES = { LIQUIDATING: "liquidating", - LIQUIDATED: "liquidated" -} + LIQUIDATED: "liquidated", +}; export const VALUE_KEY = b64encode("value"); export const STORE_KEY = b64encode("store"); @@ -31,3 +33,5 @@ export const KEY_KEY = b64encode("key"); export const STORE_NAME_KEY = b64encode("store_name"); export const SUBKEY_KEY = b64encode("store_subkey"); export const UNPROVED_VALUE_KEY = b64encode("unproved_value"); +export const PACKET_DATA_KEY = "packet_data"; +export const PACKET_SRC_CHANNEL_KEY = "packet_src_channel"; diff --git a/src/mappings/mappingHandlers.ts b/src/mappings/mappingHandlers.ts index 0c1efba6a..91f0d101c 100644 --- a/src/mappings/mappingHandlers.ts +++ b/src/mappings/mappingHandlers.ts @@ -1,5 +1,6 @@ import { StateChangeEvent, + IBCChannel, } from "../types"; import { CosmosEvent } from "@subql/types-cosmos"; import { @@ -18,6 +19,8 @@ import { STORE_NAME_KEY, SUBKEY_KEY, UNPROVED_VALUE_KEY, + PACKET_DATA_KEY, + PACKET_SRC_CHANNEL_KEY, } from "./constants"; import { psmEventKit } from "./events/psm"; import { boardAuxEventKit } from "./events/boardAux"; @@ -30,6 +33,40 @@ BigInt.prototype.toJSON = function () { return this.toString(); }; +export async function handleIbcSendPacketEvent(cosmosEvent: CosmosEvent): Promise { + const { event, block } = cosmosEvent; + if (event.type != EVENT_TYPES.SEND_PACKET) { + logger.warn("Not valid send_packet event."); + return; + } + + const packetDataAttr = event.attributes.find((a) => a.key === PACKET_DATA_KEY); + if (!packetDataAttr) { + logger.warn("No packet data attribute found"); + return; + } + + const packetSrcChannelAttr = event.attributes.find((a) => a.key === PACKET_SRC_CHANNEL_KEY); + if (!packetSrcChannelAttr) { + logger.warn("No packet source channel found"); + return; + } + + const { amount, denom, receiver, sender } = JSON.parse(packetDataAttr.value); + + const record = new IBCChannel( + packetSrcChannelAttr.value, + block.header.time as any, + BigInt(block.header.height), + packetSrcChannelAttr.value, + sender, + receiver, + denom, + amount, + ); + record.save(); +} + export async function handleStateChangeEvent(cosmosEvent: CosmosEvent): Promise { const { event, block } = cosmosEvent; From ef95c41a58bc13ef7b09ef10a61948229521e4b4 Mon Sep 17 00:00:00 2001 From: Fraz Arshad Date: Wed, 1 May 2024 15:37:00 +0500 Subject: [PATCH 2/8] feat: save escrow address as well --- schema.graphql | 1 + src/mappings/constants.ts | 7 +++++ src/mappings/mappingHandlers.ts | 45 +++++++++++++++++++++++++++++++-- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/schema.graphql b/schema.graphql index c219c72be..7c6fecf89 100644 --- a/schema.graphql +++ b/schema.graphql @@ -249,6 +249,7 @@ type IBCChannel @entity { channelName: String! srcAddress: String! destAddress: String! + escrowAddress: String! denomination: String! amount: String! } diff --git a/src/mappings/constants.ts b/src/mappings/constants.ts index 514247f75..e9067d62c 100644 --- a/src/mappings/constants.ts +++ b/src/mappings/constants.ts @@ -19,6 +19,7 @@ export const EVENT_TYPES = { TRANSFER: "transfer", SEND_PACKET: "send_packet", RECEIVE_PACKET: "recv_packet", + IBC_TRANSFER: "ibc_transfer", }; export const VAULT_STATES = { @@ -35,3 +36,9 @@ export const SUBKEY_KEY = b64encode("store_subkey"); export const UNPROVED_VALUE_KEY = b64encode("unproved_value"); export const PACKET_DATA_KEY = "packet_data"; export const PACKET_SRC_CHANNEL_KEY = "packet_src_channel"; +export const ACTION_KEY = b64encode("action"); +export const IBC_MESSAGE_TRANSFER_VALUE = b64encode("/ibc.applications.transfer.v1.MsgTransfer"); +export const RECEPIENT_KEY = b64encode("recipient"); +export const SENDER_KEY = b64encode("sender"); +export const RECEIVER_KEY = b64encode("receiver"); +export const AMOUNT_KEY = b64encode("amount"); diff --git a/src/mappings/mappingHandlers.ts b/src/mappings/mappingHandlers.ts index 91f0d101c..c8fee0f8f 100644 --- a/src/mappings/mappingHandlers.ts +++ b/src/mappings/mappingHandlers.ts @@ -21,6 +21,12 @@ import { UNPROVED_VALUE_KEY, PACKET_DATA_KEY, PACKET_SRC_CHANNEL_KEY, + ACTION_KEY, + IBC_MESSAGE_TRANSFER_VALUE, + RECEPIENT_KEY, + RECEIVER_KEY, + SENDER_KEY, + AMOUNT_KEY, } from "./constants"; import { psmEventKit } from "./events/psm"; import { boardAuxEventKit } from "./events/boardAux"; @@ -51,16 +57,51 @@ export async function handleIbcSendPacketEvent(cosmosEvent: CosmosEvent): Promis logger.warn("No packet source channel found"); return; } - const { amount, denom, receiver, sender } = JSON.parse(packetDataAttr.value); + const txns = block.txs; + const ibcTransaction = txns.find( + (txn) => + txn.events.find( + (event) => + event.type === EVENT_TYPES.MESSAGE && + event.attributes.find( + (attribute) => attribute.key === ACTION_KEY && attribute.value === IBC_MESSAGE_TRANSFER_VALUE, + ), + ) && + txn.events.find( + (event) => + event.type === EVENT_TYPES.IBC_TRANSFER && + event.attributes.find((attribute) => attribute.key === SENDER_KEY)?.value === b64encode(sender) && + event.attributes.find((attribute) => attribute.key === RECEIVER_KEY)?.value === b64encode(receiver), + ), + ); + const transferEvents = ibcTransaction?.events.filter((event) => event.type === EVENT_TYPES.TRANSFER); + const escrowTransaction = transferEvents + ?.reverse() + .find( + (event) => + event.attributes.find((attribute) => attribute.key === SENDER_KEY)?.value === b64encode(sender) && + event.attributes.find((attribute) => attribute.key === AMOUNT_KEY)?.value === b64encode(amount + denom), + ); + const encodedEscrowAddress = escrowTransaction?.attributes.find( + (attribute) => attribute.key === RECEPIENT_KEY, + )?.value; + const escrowAddress = encodedEscrowAddress ? b64decode(encodedEscrowAddress) : null; + + if (!escrowAddress) { + logger.error(`No escrow address found for ${packetSrcChannelAttr.value} at block height ${block.header.height}`); + return; + } + const record = new IBCChannel( - packetSrcChannelAttr.value, + `${block.block.id}-${packetSrcChannelAttr.value}`, block.header.time as any, BigInt(block.header.height), packetSrcChannelAttr.value, sender, receiver, + escrowAddress, denom, amount, ); From d8cfb55a903242956392043d4cdbbb413f7edd42 Mon Sep 17 00:00:00 2001 From: Fraz Arshad Date: Thu, 2 May 2024 10:57:02 +0500 Subject: [PATCH 3/8] feat: split the model into two --- schema.graphql | 7 ++++++- src/mappings/mappingHandlers.ts | 16 +++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/schema.graphql b/schema.graphql index 7c6fecf89..c33c9e502 100644 --- a/schema.graphql +++ b/schema.graphql @@ -243,13 +243,18 @@ type ReserveMetrics @entity { } type IBCChannel @entity { + id: ID! + channelName: String! + escrowAddress: String! +} + +type IBCTransfer @entity { id: ID! blockTime: Date! blockHeight: BigInt! channelName: String! srcAddress: String! destAddress: String! - escrowAddress: String! denomination: String! amount: String! } diff --git a/src/mappings/mappingHandlers.ts b/src/mappings/mappingHandlers.ts index c8fee0f8f..46628f05b 100644 --- a/src/mappings/mappingHandlers.ts +++ b/src/mappings/mappingHandlers.ts @@ -1,6 +1,7 @@ import { StateChangeEvent, IBCChannel, + IBCTransfer, } from "../types"; import { CosmosEvent } from "@subql/types-cosmos"; import { @@ -93,19 +94,28 @@ export async function handleIbcSendPacketEvent(cosmosEvent: CosmosEvent): Promis logger.error(`No escrow address found for ${packetSrcChannelAttr.value} at block height ${block.header.height}`); return; } + const ibcChannel = await IBCChannel.get(packetSrcChannelAttr.value); + if (ibcChannel && ibcChannel.escrowAddress !== escrowAddress) { + throw new Error(`Escrow address does not match that of ${packetSrcChannelAttr.value}`); + } - const record = new IBCChannel( + const transferRecord = new IBCTransfer( `${block.block.id}-${packetSrcChannelAttr.value}`, block.header.time as any, BigInt(block.header.height), packetSrcChannelAttr.value, sender, receiver, - escrowAddress, denom, amount, ); - record.save(); + const channelRecord = new IBCChannel( + packetSrcChannelAttr.value, + packetSrcChannelAttr.value, + escrowAddress, + ); + transferRecord.save(); + channelRecord.save(); } export async function handleStateChangeEvent(cosmosEvent: CosmosEvent): Promise { From 6945faed71803e46a880896e456e2e9533b00416 Mon Sep 17 00:00:00 2001 From: Fraz Arshad Date: Thu, 2 May 2024 16:01:13 +0500 Subject: [PATCH 4/8] feat: added handler for receiving packets --- project.ts | 10 +++ schema.graphql | 6 ++ src/mappings/constants.ts | 7 ++ src/mappings/mappingHandlers.ts | 116 ++++++++++++++++++++++++++++++-- 4 files changed, 134 insertions(+), 5 deletions(-) diff --git a/project.ts b/project.ts index a0c551e2c..36fa24303 100644 --- a/project.ts +++ b/project.ts @@ -90,6 +90,16 @@ const project: CosmosProject = { }, }, }, + { + handler: "handleIbcReceivePacketEvent", + kind: CosmosHandlerKind.Event, + filter: { + type: "recv_packet", + messageFilter: { + type: "/ibc.core.channel.v1.MsgRecvPacket", + }, + }, + }, { handler: "handleStateChangeEvent", kind: CosmosHandlerKind.Event, diff --git a/schema.graphql b/schema.graphql index c33c9e502..d9373f2fb 100644 --- a/schema.graphql +++ b/schema.graphql @@ -248,6 +248,11 @@ type IBCChannel @entity { escrowAddress: String! } +enum TransferType { + SEND + RECEIVE +} + type IBCTransfer @entity { id: ID! blockTime: Date! @@ -257,4 +262,5 @@ type IBCTransfer @entity { destAddress: String! denomination: String! amount: String! + transferType: TransferType! } diff --git a/src/mappings/constants.ts b/src/mappings/constants.ts index e9067d62c..924bfa560 100644 --- a/src/mappings/constants.ts +++ b/src/mappings/constants.ts @@ -20,6 +20,7 @@ export const EVENT_TYPES = { SEND_PACKET: "send_packet", RECEIVE_PACKET: "recv_packet", IBC_TRANSFER: "ibc_transfer", + FUNGIBLE_TOKEN_PACKET: "fungible_token_packet", }; export const VAULT_STATES = { @@ -36,9 +37,15 @@ export const SUBKEY_KEY = b64encode("store_subkey"); export const UNPROVED_VALUE_KEY = b64encode("unproved_value"); export const PACKET_DATA_KEY = "packet_data"; export const PACKET_SRC_CHANNEL_KEY = "packet_src_channel"; +export const PACKET_DST_CHANNEL_KEY = "packet_dst_channel"; +export const PACKET_SRC_PORT_KEY = "packet_src_port"; +export const PACKET_DST_PORT_KEY = "packet_dst_port"; export const ACTION_KEY = b64encode("action"); export const IBC_MESSAGE_TRANSFER_VALUE = b64encode("/ibc.applications.transfer.v1.MsgTransfer"); +export const IBC_MESSAGE_RECEIVE_PACKET_VALUE = b64encode("/ibc.core.channel.v1.MsgRecvPacket"); export const RECEPIENT_KEY = b64encode("recipient"); export const SENDER_KEY = b64encode("sender"); export const RECEIVER_KEY = b64encode("receiver"); export const AMOUNT_KEY = b64encode("amount"); +export const TRANSFER_PORT_VALUE = 'transfer'; + diff --git a/src/mappings/mappingHandlers.ts b/src/mappings/mappingHandlers.ts index 46628f05b..59f8859ed 100644 --- a/src/mappings/mappingHandlers.ts +++ b/src/mappings/mappingHandlers.ts @@ -2,6 +2,7 @@ import { StateChangeEvent, IBCChannel, IBCTransfer, + TransferType, } from "../types"; import { CosmosEvent } from "@subql/types-cosmos"; import { @@ -28,6 +29,11 @@ import { RECEIVER_KEY, SENDER_KEY, AMOUNT_KEY, + IBC_MESSAGE_RECEIVE_PACKET_VALUE, + PACKET_DST_CHANNEL_KEY, + PACKET_DST_PORT_KEY, + PACKET_SRC_PORT_KEY, + TRANSFER_PORT_VALUE, } from "./constants"; import { psmEventKit } from "./events/psm"; import { boardAuxEventKit } from "./events/boardAux"; @@ -47,6 +53,11 @@ export async function handleIbcSendPacketEvent(cosmosEvent: CosmosEvent): Promis return; } + const packetSrcPortAttr = event.attributes.find((a) => a.key === PACKET_SRC_PORT_KEY); + if (!packetSrcPortAttr || packetSrcPortAttr.value !== TRANSFER_PORT_VALUE) { + logger.warn("packet_src_port is not transfer"); + return; + } const packetDataAttr = event.attributes.find((a) => a.key === PACKET_DATA_KEY); if (!packetDataAttr) { logger.warn("No packet data attribute found"); @@ -108,16 +119,111 @@ export async function handleIbcSendPacketEvent(cosmosEvent: CosmosEvent): Promis receiver, denom, amount, + TransferType.SEND, ); - const channelRecord = new IBCChannel( - packetSrcChannelAttr.value, - packetSrcChannelAttr.value, - escrowAddress, + transferRecord.save(); + + if (!ibcChannel) { + const channelRecord = new IBCChannel( + packetSrcChannelAttr.value, + packetSrcChannelAttr.value, + escrowAddress, + ); + channelRecord.save(); + } +} + +export async function handleIbcReceivePacketEvent(cosmosEvent: CosmosEvent): Promise { + const { event, block } = cosmosEvent; + if (event.type != EVENT_TYPES.RECEIVE_PACKET) { + logger.warn("Not valid recv_packet event."); + return; + } + + const packetDataAttr = event.attributes.find((a) => a.key === PACKET_DATA_KEY); + if (!packetDataAttr) { + logger.warn("No packet data attribute found"); + return; + } + + const packetDestPortAttr = event.attributes.find((a) => a.key === PACKET_DST_PORT_KEY); + if (!packetDestPortAttr || packetDestPortAttr.value !== TRANSFER_PORT_VALUE) { + logger.warn("packet_dest_port is not transfer"); + return; + } + + const packetDstChannelAttr = event.attributes.find((a) => a.key === PACKET_DST_CHANNEL_KEY); + if (!packetDstChannelAttr) { + logger.warn("No packet destination channel found"); + return; + } + const { amount, denom, receiver, sender } = JSON.parse(packetDataAttr.value); + + const txns = block.txs; + const ibcTransaction = txns.find( + (txn) => + txn.events.find( + (event) => + event.type === EVENT_TYPES.MESSAGE && + event.attributes.find( + (attribute) => attribute.key === ACTION_KEY && attribute.value === IBC_MESSAGE_RECEIVE_PACKET_VALUE, + ), + ) && + txn.events.find( + (event) => + event.type === EVENT_TYPES.FUNGIBLE_TOKEN_PACKET && + event.attributes.find((attribute) => attribute.key === SENDER_KEY)?.value === b64encode(sender) && + event.attributes.find((attribute) => attribute.key === RECEIVER_KEY)?.value === b64encode(receiver), + ), + ); + const transferEvents = ibcTransaction?.events.filter((event) => event.type === EVENT_TYPES.TRANSFER); + const [, , denomUnit] = denom.split('/') + const escrowTransaction = transferEvents + ?.reverse() + .find( + (event) => + event.attributes.find((attribute) => attribute.key === RECEPIENT_KEY)?.value === b64encode(receiver) && + event.attributes.find((attribute) => attribute.key === AMOUNT_KEY)?.value === b64encode(amount + denomUnit), + ); + const encodedEscrowAddress = escrowTransaction?.attributes.find( + (attribute) => attribute.key === SENDER_KEY, + )?.value; + const escrowAddress = encodedEscrowAddress ? b64decode(encodedEscrowAddress) : null; + + if (!escrowAddress) { + logger.error(`No escrow address found for ${packetDstChannelAttr.value} at block height ${block.header.height}`); + return; + } + + const ibcChannel = await IBCChannel.get(packetDstChannelAttr.value); + if (ibcChannel && ibcChannel.escrowAddress !== escrowAddress) { + throw new Error(`Escrow address does not match that of ${packetDstChannelAttr.value}`); + } + + const transferRecord = new IBCTransfer( + `${block.block.id}-${packetDstChannelAttr.value}`, + block.header.time as any, + BigInt(block.header.height), + packetDstChannelAttr.value, + sender, + receiver, + denom, + amount, + TransferType.RECEIVE, ); transferRecord.save(); - channelRecord.save(); + + if (!ibcChannel) { + const channelRecord = new IBCChannel( + packetDstChannelAttr.value, + packetDstChannelAttr.value, + escrowAddress, + ); + channelRecord.save(); + } } + export async function handleStateChangeEvent(cosmosEvent: CosmosEvent): Promise { const { event, block } = cosmosEvent; From c4be4b67e9d4204c801b85e29511542ceb2042c2 Mon Sep 17 00:00:00 2001 From: Fraz Arshad Date: Sat, 4 May 2024 10:56:08 +0500 Subject: [PATCH 5/8] feat: updated method to get escrow addresses --- package.json | 2 + src/mappings/constants.ts | 3 +- src/mappings/mappingHandlers.ts | 119 +++++--------------------------- src/mappings/utils.ts | 13 ++++ 4 files changed, 33 insertions(+), 104 deletions(-) diff --git a/package.json b/package.json index 7a5bd33e8..4bf154b51 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,8 @@ "dependencies": { "@subql/types-cosmos": "^3.2.3", "@types/node": "^17.0.21", + "bech32": "^2.0.0", + "js-sha256": "^0.11.0", "pino": "^7.8.0", "ts-proto": "^1.112.1", "tslib": "^2.3.1" diff --git a/src/mappings/constants.ts b/src/mappings/constants.ts index 924bfa560..d9b27544c 100644 --- a/src/mappings/constants.ts +++ b/src/mappings/constants.ts @@ -47,5 +47,4 @@ export const RECEPIENT_KEY = b64encode("recipient"); export const SENDER_KEY = b64encode("sender"); export const RECEIVER_KEY = b64encode("receiver"); export const AMOUNT_KEY = b64encode("amount"); -export const TRANSFER_PORT_VALUE = 'transfer'; - +export const TRANSFER_PORT_VALUE = "transfer"; diff --git a/src/mappings/mappingHandlers.ts b/src/mappings/mappingHandlers.ts index 59f8859ed..908615ce2 100644 --- a/src/mappings/mappingHandlers.ts +++ b/src/mappings/mappingHandlers.ts @@ -10,6 +10,7 @@ import { extractStoragePath, getStateChangeModule, resolveBrandNamesAndValues, + getEscrowAddress, } from "./utils"; import { @@ -46,8 +47,15 @@ BigInt.prototype.toJSON = function () { return this.toString(); }; +async function saveIbcChannel(channelName: string) { + const generatedEscrowAddress = getEscrowAddress(TRANSFER_PORT_VALUE, channelName); + + const channelRecord = new IBCChannel(channelName, channelName, generatedEscrowAddress); + channelRecord.save(); +} + export async function handleIbcSendPacketEvent(cosmosEvent: CosmosEvent): Promise { - const { event, block } = cosmosEvent; + const { event, block, tx } = cosmosEvent; if (event.type != EVENT_TYPES.SEND_PACKET) { logger.warn("Not valid send_packet event."); return; @@ -70,48 +78,12 @@ export async function handleIbcSendPacketEvent(cosmosEvent: CosmosEvent): Promis return; } const { amount, denom, receiver, sender } = JSON.parse(packetDataAttr.value); + const sourceChannel = packetSrcChannelAttr.value; - const txns = block.txs; - const ibcTransaction = txns.find( - (txn) => - txn.events.find( - (event) => - event.type === EVENT_TYPES.MESSAGE && - event.attributes.find( - (attribute) => attribute.key === ACTION_KEY && attribute.value === IBC_MESSAGE_TRANSFER_VALUE, - ), - ) && - txn.events.find( - (event) => - event.type === EVENT_TYPES.IBC_TRANSFER && - event.attributes.find((attribute) => attribute.key === SENDER_KEY)?.value === b64encode(sender) && - event.attributes.find((attribute) => attribute.key === RECEIVER_KEY)?.value === b64encode(receiver), - ), - ); - const transferEvents = ibcTransaction?.events.filter((event) => event.type === EVENT_TYPES.TRANSFER); - const escrowTransaction = transferEvents - ?.reverse() - .find( - (event) => - event.attributes.find((attribute) => attribute.key === SENDER_KEY)?.value === b64encode(sender) && - event.attributes.find((attribute) => attribute.key === AMOUNT_KEY)?.value === b64encode(amount + denom), - ); - const encodedEscrowAddress = escrowTransaction?.attributes.find( - (attribute) => attribute.key === RECEPIENT_KEY, - )?.value; - const escrowAddress = encodedEscrowAddress ? b64decode(encodedEscrowAddress) : null; - - if (!escrowAddress) { - logger.error(`No escrow address found for ${packetSrcChannelAttr.value} at block height ${block.header.height}`); - return; - } - const ibcChannel = await IBCChannel.get(packetSrcChannelAttr.value); - if (ibcChannel && ibcChannel.escrowAddress !== escrowAddress) { - throw new Error(`Escrow address does not match that of ${packetSrcChannelAttr.value}`); - } + saveIbcChannel(sourceChannel); const transferRecord = new IBCTransfer( - `${block.block.id}-${packetSrcChannelAttr.value}`, + tx.hash, block.header.time as any, BigInt(block.header.height), packetSrcChannelAttr.value, @@ -122,19 +94,10 @@ export async function handleIbcSendPacketEvent(cosmosEvent: CosmosEvent): Promis TransferType.SEND, ); transferRecord.save(); - - if (!ibcChannel) { - const channelRecord = new IBCChannel( - packetSrcChannelAttr.value, - packetSrcChannelAttr.value, - escrowAddress, - ); - channelRecord.save(); - } } export async function handleIbcReceivePacketEvent(cosmosEvent: CosmosEvent): Promise { - const { event, block } = cosmosEvent; + const { event, block, tx } = cosmosEvent; if (event.type != EVENT_TYPES.RECEIVE_PACKET) { logger.warn("Not valid recv_packet event."); return; @@ -158,53 +121,15 @@ export async function handleIbcReceivePacketEvent(cosmosEvent: CosmosEvent): Pro return; } const { amount, denom, receiver, sender } = JSON.parse(packetDataAttr.value); + const destinationChannel = packetDstChannelAttr.value; - const txns = block.txs; - const ibcTransaction = txns.find( - (txn) => - txn.events.find( - (event) => - event.type === EVENT_TYPES.MESSAGE && - event.attributes.find( - (attribute) => attribute.key === ACTION_KEY && attribute.value === IBC_MESSAGE_RECEIVE_PACKET_VALUE, - ), - ) && - txn.events.find( - (event) => - event.type === EVENT_TYPES.FUNGIBLE_TOKEN_PACKET && - event.attributes.find((attribute) => attribute.key === SENDER_KEY)?.value === b64encode(sender) && - event.attributes.find((attribute) => attribute.key === RECEIVER_KEY)?.value === b64encode(receiver), - ), - ); - const transferEvents = ibcTransaction?.events.filter((event) => event.type === EVENT_TYPES.TRANSFER); - const [, , denomUnit] = denom.split('/') - const escrowTransaction = transferEvents - ?.reverse() - .find( - (event) => - event.attributes.find((attribute) => attribute.key === RECEPIENT_KEY)?.value === b64encode(receiver) && - event.attributes.find((attribute) => attribute.key === AMOUNT_KEY)?.value === b64encode(amount + denomUnit), - ); - const encodedEscrowAddress = escrowTransaction?.attributes.find( - (attribute) => attribute.key === SENDER_KEY, - )?.value; - const escrowAddress = encodedEscrowAddress ? b64decode(encodedEscrowAddress) : null; - - if (!escrowAddress) { - logger.error(`No escrow address found for ${packetDstChannelAttr.value} at block height ${block.header.height}`); - return; - } - - const ibcChannel = await IBCChannel.get(packetDstChannelAttr.value); - if (ibcChannel && ibcChannel.escrowAddress !== escrowAddress) { - throw new Error(`Escrow address does not match that of ${packetDstChannelAttr.value}`); - } + saveIbcChannel(destinationChannel); const transferRecord = new IBCTransfer( - `${block.block.id}-${packetDstChannelAttr.value}`, + tx.hash, block.header.time as any, BigInt(block.header.height), - packetDstChannelAttr.value, + destinationChannel, sender, receiver, denom, @@ -212,18 +137,8 @@ export async function handleIbcReceivePacketEvent(cosmosEvent: CosmosEvent): Pro TransferType.RECEIVE, ); transferRecord.save(); - - if (!ibcChannel) { - const channelRecord = new IBCChannel( - packetDstChannelAttr.value, - packetDstChannelAttr.value, - escrowAddress, - ); - channelRecord.save(); - } } - export async function handleStateChangeEvent(cosmosEvent: CosmosEvent): Promise { const { event, block } = cosmosEvent; diff --git a/src/mappings/utils.ts b/src/mappings/utils.ts index 07c1d8c63..53b62faf1 100644 --- a/src/mappings/utils.ts +++ b/src/mappings/utils.ts @@ -1,3 +1,6 @@ +import { bech32 } from "bech32"; +import sha256 from "js-sha256"; + export function extractBrand(str: string): string { return str.replace("Alleged: ", "").replace(" brand", ""); } @@ -95,3 +98,13 @@ export function dateToDayKey(timestamp: any): number { const day = date.getUTCDate().toString().padStart(2, "0"); return parseInt(`${year}${month}${day}`); } + +export const getEscrowAddress = (port: string, channel: string) => { + const version = "ics20-1"; + const chainPrefix = "agoric"; + const stringtoSha = Buffer.from([...Buffer.from(version), 0, ...Buffer.from(`${port}/${channel}`)]); + const shaHash = sha256.sha256.array(stringtoSha.toString()); + const bechWords = bech32.toWords(shaHash.slice(0, 20)); + const address = bech32.encode(chainPrefix, bechWords); + return address; +}; From c35cc07407089d1d5423f51b31391abde82886d7 Mon Sep 17 00:00:00 2001 From: Touseef Liaqat Date: Sat, 4 May 2024 20:13:38 -0700 Subject: [PATCH 6/8] Add Account and link with IBCChannel --- schema.graphql | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/schema.graphql b/schema.graphql index d9373f2fb..da431d9ed 100644 --- a/schema.graphql +++ b/schema.graphql @@ -242,10 +242,14 @@ type ReserveMetrics @entity { allocations: [ReserveAllocationMetrics] @derivedFrom(field: "reserveMetrics") } +type Account @entity { + id: ID! +} + type IBCChannel @entity { id: ID! channelName: String! - escrowAddress: String! + escrowAccount: Account! } enum TransferType { @@ -257,9 +261,9 @@ type IBCTransfer @entity { id: ID! blockTime: Date! blockHeight: BigInt! - channelName: String! - srcAddress: String! - destAddress: String! + channel: IBCChannel! + srcAccount: Account! + destAccount: Account! denomination: String! amount: String! transferType: TransferType! From 6888367e60e54a0439b2eab21c3ef2d3a45dbe6e Mon Sep 17 00:00:00 2001 From: Fraz Arshad Date: Mon, 6 May 2024 10:12:00 +0500 Subject: [PATCH 7/8] chore: async/await fixes --- schema.graphql | 2 +- src/mappings/mappingHandlers.ts | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/schema.graphql b/schema.graphql index da431d9ed..62fedbba6 100644 --- a/schema.graphql +++ b/schema.graphql @@ -264,7 +264,7 @@ type IBCTransfer @entity { channel: IBCChannel! srcAccount: Account! destAccount: Account! - denomination: String! + denom: String! amount: String! transferType: TransferType! } diff --git a/src/mappings/mappingHandlers.ts b/src/mappings/mappingHandlers.ts index 908615ce2..e218554d8 100644 --- a/src/mappings/mappingHandlers.ts +++ b/src/mappings/mappingHandlers.ts @@ -51,7 +51,7 @@ async function saveIbcChannel(channelName: string) { const generatedEscrowAddress = getEscrowAddress(TRANSFER_PORT_VALUE, channelName); const channelRecord = new IBCChannel(channelName, channelName, generatedEscrowAddress); - channelRecord.save(); + await channelRecord.save(); } export async function handleIbcSendPacketEvent(cosmosEvent: CosmosEvent): Promise { @@ -80,7 +80,7 @@ export async function handleIbcSendPacketEvent(cosmosEvent: CosmosEvent): Promis const { amount, denom, receiver, sender } = JSON.parse(packetDataAttr.value); const sourceChannel = packetSrcChannelAttr.value; - saveIbcChannel(sourceChannel); + await saveIbcChannel(sourceChannel); const transferRecord = new IBCTransfer( tx.hash, @@ -93,7 +93,7 @@ export async function handleIbcSendPacketEvent(cosmosEvent: CosmosEvent): Promis amount, TransferType.SEND, ); - transferRecord.save(); + await transferRecord.save(); } export async function handleIbcReceivePacketEvent(cosmosEvent: CosmosEvent): Promise { @@ -123,7 +123,7 @@ export async function handleIbcReceivePacketEvent(cosmosEvent: CosmosEvent): Pro const { amount, denom, receiver, sender } = JSON.parse(packetDataAttr.value); const destinationChannel = packetDstChannelAttr.value; - saveIbcChannel(destinationChannel); + await saveIbcChannel(destinationChannel); const transferRecord = new IBCTransfer( tx.hash, @@ -136,7 +136,7 @@ export async function handleIbcReceivePacketEvent(cosmosEvent: CosmosEvent): Pro amount, TransferType.RECEIVE, ); - transferRecord.save(); + await transferRecord.save(); } export async function handleStateChangeEvent(cosmosEvent: CosmosEvent): Promise { From 61f86a49ab4551e2a516b75652b3f420ab237faa Mon Sep 17 00:00:00 2001 From: Fraz Arshad Date: Mon, 6 May 2024 10:21:01 +0500 Subject: [PATCH 8/8] chore: remove unused constants --- src/mappings/mappingHandlers.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/mappings/mappingHandlers.ts b/src/mappings/mappingHandlers.ts index e218554d8..d383490d7 100644 --- a/src/mappings/mappingHandlers.ts +++ b/src/mappings/mappingHandlers.ts @@ -24,13 +24,6 @@ import { UNPROVED_VALUE_KEY, PACKET_DATA_KEY, PACKET_SRC_CHANNEL_KEY, - ACTION_KEY, - IBC_MESSAGE_TRANSFER_VALUE, - RECEPIENT_KEY, - RECEIVER_KEY, - SENDER_KEY, - AMOUNT_KEY, - IBC_MESSAGE_RECEIVE_PACKET_VALUE, PACKET_DST_CHANNEL_KEY, PACKET_DST_PORT_KEY, PACKET_SRC_PORT_KEY,