Skip to content

Commit

Permalink
feat: improve GMP transaction status retrieval
Browse files Browse the repository at this point in the history
  • Loading branch information
npty committed Feb 13, 2025
1 parent 964dd5b commit 7172708
Showing 1 changed file with 61 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ import { z } from "zod";

import { publicProcedure } from "~/server/trpc";

export type ChainStatus = {
status: GMPTxStatus;
txHash: string;
txId: string;
logIndex: number;
};

export const SEARCHGMP_SOURCE = {
includes: [
"call.returnValues.destinationChain",
Expand All @@ -20,26 +27,52 @@ export const SEARCHGMP_SOURCE = {
"gas",
"gas_price_rate",
"gas_paid",
"approved.receipt",
"confirm.receipt",
"executed.receipt",
"approved.topics",
"approved.returnValues",
"confirm.returnValues",
"executed.returnValues",
"approved.transaction",
"confirm.transaction",
"executed.transaction",
"approved.created_at",
"confirm.created_at",
"executed.created_at",
...["approved", "confirm", "executed"].flatMap((prefix) => [
`${prefix}.receipt`,
`${prefix}.topics`,
`${prefix}.returnValues`,
`${prefix}.transaction`,
`${prefix}.created_at`,
]),
],
};

const INPUT_SCHEMA = z.object({
txHash: z.string(),
});

async function processGMPData(
gmpData: any,
ctx: any
): Promise<[string, ChainStatus]> {
const { call, callback, status: firstHopStatus } = gmpData;
const destinationChain = (
callback?.returnValues.destinationChain ??
call.returnValues.destinationChain
).toLowerCase();

let status = firstHopStatus;

// Handle second hop for non-EVM chains
if (call.chain_type !== "evm" && callback) {
const secondHopData = await ctx.services.gmp.searchGMP({
txHash: callback.returnValues.messageId,
_source: SEARCHGMP_SOURCE,
});
status = secondHopData[0].status;
}

return [
destinationChain,
{
status,
txHash: call.transactionHash,
logIndex: call.logIndex ?? call._logIndex ?? 0,
txId: gmpData.message_id,
},
];
}

/**
* Get the status of an GMP transaction on destination chains
*/
Expand All @@ -52,71 +85,25 @@ export const getTransactionStatusOnDestinationChains = publicProcedure
_source: SEARCHGMP_SOURCE,
});

if (data.length) {
const pendingResult = data.reduce(
async (acc, gmpData) => {
const { call, callback, status: firstHopStatus } = gmpData;

const chainType = gmpData.call.chain_type;
let secondHopStatus: GMPTxStatus = "confirming";

if (gmpData.callback) {
const secondHopMessageId =
gmpData.callback.returnValues.messageId;

const secondHopData = await ctx.services.gmp.searchGMP({
txHash: secondHopMessageId,
_source: SEARCHGMP_SOURCE,
});

secondHopStatus = secondHopData[0].status;
}

// For 2-hops transaction, the destination chain in callback is the final destination chain, which only exist after the transaction is already executed at the Axelar chain.
const destinationChain =
callback?.returnValues.destinationChain?.toLowerCase() ||
call.returnValues.destinationChain.toLowerCase();

const awaitedAcc = await acc;

return {
...awaitedAcc,
[destinationChain]: {
status: chainType === "evm" ? firstHopStatus : secondHopStatus,
txHash: call.transactionHash,
logIndex: call.logIndex ?? call._logIndex ?? 0,
txId: gmpData.message_id,
},
};
},
Promise.resolve(
{} as {
[chainId: string]: {
status: GMPTxStatus;
txHash: string;
txId: string;
logIndex: number;
};
}
)
);
if (!data.length) {
throw new TRPCError({
code: "NOT_FOUND",
message: "Transaction not found",
});
}

const result = await pendingResult;
// Process all GMP data entries in parallel
const processedEntries = await Promise.all(
data.map((gmpData) => processGMPData(gmpData, ctx))
);

return result;
}
// Convert the processed entries into a ChainStatusMap
const result = Object.fromEntries(processedEntries);

// If we don't find the transaction, we throw a 404 error
throw new TRPCError({
code: "NOT_FOUND",
message: "Transaction not found",
});
return result;
} catch (error) {
// If we get a TRPC error, we throw it
if (error instanceof TRPCError) {
throw error;
}
// otherwise, we throw an internal server error
if (error instanceof TRPCError) throw error;

throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Failed to get transaction status",
Expand Down

0 comments on commit 7172708

Please sign in to comment.