Skip to content

Commit 88e71b6

Browse files
authored
feat: enhance ibc data (#31)
* feat: enhance ibc data * fix: as comments
1 parent f7604f1 commit 88e71b6

16 files changed

Lines changed: 394 additions & 49 deletions

src/api.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
zCollectionResource,
1212
zMoveViewResponse,
1313
zNftResource,
14+
zNodeInfo,
1415
zObjectCoreResource,
1516
zRegistries,
1617
zValidator,
@@ -59,6 +60,33 @@ export class ApiClient {
5960
return z.string().parse(response);
6061
}
6162

63+
public async findIbcCounterPartyChainId(
64+
chainId: string,
65+
portId: string,
66+
channelId: string
67+
): Promise<string | null> {
68+
await this._getRegistries();
69+
70+
const registry = this.registries.find(
71+
(registry) => registry.chain_id === chainId
72+
);
73+
74+
if (!registry) {
75+
return null;
76+
}
77+
78+
const channel = registry.metadata.ibc_channels.find(
79+
(channel) =>
80+
channel.port_id === portId && channel.channel_id === channelId
81+
);
82+
83+
if (!channel) {
84+
return null;
85+
}
86+
87+
return channel.chain_id;
88+
}
89+
6290
public async findNftFromTokenAddr(
6391
tokenAddr: string
6492
): Promise<NftResource | null> {
@@ -114,6 +142,18 @@ export class ApiClient {
114142
}
115143
}
116144

145+
public async getChainId(): Promise<string> {
146+
try {
147+
const response = await axios.get(
148+
`${this.restUrl}/cosmos/base/tendermint/v1beta1/node_info`
149+
);
150+
return zNodeInfo.parse(response.data).default_node_info.network;
151+
} catch (error) {
152+
console.error("Failed to fetch chain ID:", error);
153+
throw new Error("Unable to retrieve chain ID from node info");
154+
}
155+
}
156+
117157
private async _getAccountResources(
118158
address: string
119159
): Promise<AccountResource[] | null> {

src/decoders/ibc/nft.ts

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,31 @@ export const ibcSendNftDecoder: MessageDecoder = {
4949
);
5050
}
5151

52+
const srcChainId = await apiClient.getChainId();
53+
54+
const dstPort = event.attributes.find(
55+
(attr) => attr.key === "packet_dst_port"
56+
)?.value;
57+
if (!dstPort) {
58+
throw new Error("IBC NFT Send packet dst port attribute not found");
59+
}
60+
61+
const dstChannel = event.attributes.find(
62+
(attr) => attr.key === "packet_dst_channel"
63+
)?.value;
64+
if (!dstChannel) {
65+
throw new Error("IBC NFT Send packet dst channel attribute not found");
66+
}
67+
68+
const dstChainId = await apiClient.findIbcCounterPartyChainId(
69+
srcChainId,
70+
source_port,
71+
source_channel
72+
);
73+
if (!dstChainId) {
74+
throw new Error("IBC NFT Send packet dst chain id not found");
75+
}
76+
5277
return {
5378
action: "ibc_nft_send",
5479
data: {
@@ -59,10 +84,14 @@ export const ibcSendNftDecoder: MessageDecoder = {
5984
uri: collection.data.uri || parsedData.data.classUri,
6085
},
6186
collectionId: toBech32(denomToHex(class_id)),
87+
dstChainId,
88+
dstChannel,
89+
dstPort,
6290
receiver,
6391
sender,
64-
sourceChannel: source_channel,
65-
sourcePort: source_port,
92+
srcChainId,
93+
srcChannel: source_channel,
94+
srcPort: source_port,
6695
tokenIds: parsedData.data.tokenIds,
6796
tokenUris: parsedData.data.tokenUris,
6897
},
@@ -125,6 +154,31 @@ export const ibcReceiveNftDecoder: MessageDecoder = {
125154
);
126155
}
127156

157+
const dstChainId = await apiClient.getChainId();
158+
159+
const srcPort = event.attributes.find(
160+
(attr) => attr.key === "packet_src_port"
161+
)?.value;
162+
if (!srcPort) {
163+
throw new Error("IBC NFT Receive packet src port attribute not found");
164+
}
165+
166+
const srcChannel = event.attributes.find(
167+
(attr) => attr.key === "packet_src_channel"
168+
)?.value;
169+
if (!srcChannel) {
170+
throw new Error("IBC NFT Receive packet src channel attribute not found");
171+
}
172+
173+
const srcChainId = await apiClient.findIbcCounterPartyChainId(
174+
dstChainId,
175+
destination_port,
176+
destination_channel
177+
);
178+
if (!srcChainId) {
179+
throw new Error("IBC NFT Receive packet src chain id not found");
180+
}
181+
128182
return {
129183
action: "ibc_nft_receive",
130184
data: {
@@ -135,10 +189,14 @@ export const ibcReceiveNftDecoder: MessageDecoder = {
135189
uri: collection.data.uri || parsedData.data.classUri,
136190
},
137191
collectionId: toBech32(collection_id),
138-
destinationChannel: destination_channel,
139-
destinationPort: destination_port,
192+
dstChainId,
193+
dstChannel: destination_channel,
194+
dstPort: destination_port,
140195
receiver: parsedData.data.receiver,
141196
sender: parsedData.data.sender,
197+
srcChainId,
198+
srcChannel,
199+
srcPort,
142200
tokenIds: parsedData.data.tokenIds,
143201
tokenUris: parsedData.data.tokenUris,
144202
},

src/decoders/ibc/transfer.ts

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,46 @@ export const ibcSendFtDecoder: MessageDecoder = {
1313
const parsed = zMsgIbcTransfer.safeParse(message);
1414
return parsed.success && parsed.data.source_port === "transfer";
1515
},
16-
decode: async (message: Message, log: Log, _apiClient: ApiClient) => {
16+
decode: async (message: Message, log: Log, apiClient: ApiClient) => {
1717
const parsed = zMsgIbcTransfer.parse(message);
1818
const { receiver, sender, source_channel, source_port, token } = parsed;
1919

2020
const event = log.events.find((event) => event.type === "send_packet");
2121

2222
if (!event) throw new Error("IBC Transfer send packet event not found");
2323

24+
const dstChannel = event.attributes.find(
25+
(attr) => attr.key === "packet_dst_channel"
26+
)?.value;
27+
if (!dstChannel) throw new Error(`IBC Transfer dst channel not found`);
28+
29+
const dstPort = event.attributes.find(
30+
(attr) => attr.key === "packet_dst_port"
31+
)?.value;
32+
if (!dstPort) throw new Error(`IBC Transfer dst port not found`);
33+
34+
const srcChainId = await apiClient.getChainId();
35+
36+
const dstChainId = await apiClient.findIbcCounterPartyChainId(
37+
srcChainId,
38+
source_port,
39+
source_channel
40+
);
41+
if (!dstChainId) throw new Error(`IBC Transfer dst chain id not found`);
42+
2443
return {
2544
action: "ibc_ft_send",
2645
data: {
2746
amount: token.amount,
2847
denom: token.denom,
29-
destinationChannel:
30-
event.attributes.find((attr) => attr.key === "packet_dst_channel")
31-
?.value ?? "",
32-
destinationPort:
33-
event.attributes.find((attr) => attr.key === "packet_dst_port")
34-
?.value ?? "",
48+
dstChainId,
49+
dstChannel,
50+
dstPort,
3551
receiver,
3652
sender,
37-
sourceChannel: source_channel,
38-
sourcePort: source_port,
53+
srcChainId,
54+
srcChannel: source_channel,
55+
srcPort: source_port,
3956
},
4057
isIbc: true,
4158
isOp: false,
@@ -48,7 +65,7 @@ export const ibcReceiveFtDecoder: MessageDecoder = {
4865
const parsed = zMsgIbcRecvPacket.safeParse(message);
4966
return parsed.success && parsed.data.packet.source_port === "transfer";
5067
},
51-
decode: async (message: Message, _log: Log, _apiClient: ApiClient) => {
68+
decode: async (message: Message, _log: Log, apiClient: ApiClient) => {
5269
const parsed = zMsgIbcRecvPacket.parse(message);
5370
const {
5471
packet: {
@@ -64,17 +81,28 @@ export const ibcReceiveFtDecoder: MessageDecoder = {
6481
Buffer.from(data, "base64").toString()
6582
);
6683

84+
const dstChainId = await apiClient.getChainId();
85+
86+
const srcChainId = await apiClient.findIbcCounterPartyChainId(
87+
dstChainId,
88+
destination_port,
89+
destination_channel
90+
);
91+
if (!srcChainId) throw new Error(`IBC Transfer src chain id not found`);
92+
6793
return {
6894
action: "ibc_ft_receive",
6995
data: {
7096
amount: parsedPacket.amount,
7197
denom: parsedPacket.denom,
72-
destinationChannel: destination_channel,
73-
destinationPort: destination_port,
98+
dstChainId,
99+
dstChannel: destination_channel,
100+
dstPort: destination_port,
74101
receiver: parsedPacket.receiver,
75102
sender: parsedPacket.sender,
76-
sourceChannel: source_channel,
77-
sourcePort: source_port,
103+
srcChainId,
104+
srcChannel: source_channel,
105+
srcPort: source_port,
78106
},
79107
isIbc: true,
80108
isOp: false,

src/interfaces/decoded-messages.ts

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,14 @@ interface DecodedIbcFtSendMessage extends DecodedMessageBase {
4040
data: {
4141
amount: string;
4242
denom: string;
43-
destinationChannel: string;
44-
destinationPort: string;
43+
dstChainId: string;
44+
dstChannel: string;
45+
dstPort: string;
4546
receiver: string;
4647
sender: string;
47-
sourceChannel: string;
48-
sourcePort: string;
48+
srcChainId: string;
49+
srcChannel: string;
50+
srcPort: string;
4951
};
5052
}
5153

@@ -54,12 +56,14 @@ interface DecodedIbcFtReceiveMessage extends DecodedMessageBase {
5456
data: {
5557
amount: string;
5658
denom: string;
57-
destinationChannel: string;
58-
destinationPort: string;
59+
dstChainId: string;
60+
dstChannel: string;
61+
dstPort: string;
5962
receiver: string;
6063
sender: string;
61-
sourceChannel: string;
62-
sourcePort: string;
64+
srcChainId: string;
65+
srcChannel: string;
66+
srcPort: string;
6367
};
6468
}
6569

@@ -190,10 +194,14 @@ interface DecodedIbcNftSendMessage extends DecodedMessageBase {
190194
uri: string | null;
191195
};
192196
collectionId: string;
197+
dstChainId: string;
198+
dstChannel: string;
199+
dstPort: string;
193200
receiver: string;
194201
sender: string;
195-
sourceChannel: string;
196-
sourcePort: string;
202+
srcChainId: string;
203+
srcChannel: string;
204+
srcPort: string;
197205
tokenIds: string[];
198206
tokenUris: string[];
199207
};
@@ -209,10 +217,14 @@ interface DecodedIbcNftReceiveMessage extends DecodedMessageBase {
209217
uri: string | null;
210218
};
211219
collectionId: string;
212-
destinationChannel: string;
213-
destinationPort: string;
220+
dstChainId: string;
221+
dstChannel: string;
222+
dstPort: string;
214223
receiver: string;
215224
sender: string;
225+
srcChainId: string;
226+
srcChannel: string;
227+
srcPort: string;
216228
tokenIds: string[];
217229
tokenUris: string[];
218230
};

src/schema/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export * from "./messages";
44
export * from "./packet";
55
export * from "./registry";
66
export * from "./resources";
7+
export * from "./rest";
78
export * from "./transaction";
89
export * from "./validators";
910
export * from "./view";

src/schema/registry.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
11
import { z } from "zod";
22

3+
const zIbcChannel = z.object({
4+
chain_id: z.string(),
5+
channel_id: z.string(),
6+
port_id: z.string(),
7+
version: z.string(),
8+
});
9+
310
const zMetadata = z.object({
11+
ibc_channels: z.array(zIbcChannel),
412
op_bridge_id: z.string().optional(),
513
op_denoms: z.array(z.string()).optional(),
614
});
715

816
export const zRegistry = z.object({
917
chain_id: z.string(),
1018
chain_name: z.string(),
19+
1120
metadata: zMetadata,
1221
});
1322
export type Registry = z.infer<typeof zRegistry>;

src/schema/rest.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { z } from "zod";
2+
3+
export const zNodeInfo = z.object({
4+
default_node_info: z.object({
5+
network: z.string(),
6+
}),
7+
});

0 commit comments

Comments
 (0)