Skip to content

Commit

Permalink
feat: added handler for receiving packets
Browse files Browse the repository at this point in the history
  • Loading branch information
frazarshad committed May 2, 2024
1 parent eae1f21 commit f31cbd3
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 5 deletions.
10 changes: 10 additions & 0 deletions project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,11 @@ type IBCChannel @entity {
escrowAddress: String!
}

enum TransferType {
SEND
RECEIVE
}

type IBCTransfer @entity {
id: ID!
blockTime: Date!
Expand All @@ -279,4 +284,5 @@ type IBCTransfer @entity {
destAddress: String!
denomination: String!
amount: String!
transferType: TransferType!
}
7 changes: 7 additions & 0 deletions src/mappings/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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';

116 changes: 111 additions & 5 deletions src/mappings/mappingHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
ReserveAllocationMetricsDaily,
IBCChannel,
IBCTransfer,
TransferType,
} from "../types";
import { CosmosEvent } from "@subql/types-cosmos";
import {
Expand Down Expand Up @@ -47,6 +48,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";
Expand All @@ -66,6 +72,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");
Expand Down Expand Up @@ -127,16 +138,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<void> {
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<void> {
const { event, block } = cosmosEvent;

Expand Down

0 comments on commit f31cbd3

Please sign in to comment.