Skip to content

Commit

Permalink
feat: fix tx progress for its hub tx (#489)
Browse files Browse the repository at this point in the history
  • Loading branch information
npty authored Jan 22, 2025
1 parent 1d05d56 commit 5ee1a72
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,15 @@ function useCanonicalTokenDeploymentState(
},
actions: {
reset: () => {
console.log("reset");
setState((draft) => {
Object.assign(draft, initialState);
});
},
setTokenDetails: (detatils: Partial<TokenDetails>) => {
console.log("setTokenDetails", detatils);
setTokenDetails: (details: Partial<TokenDetails>) => {
setState((draft) => {
draft.tokenDetails = {
...draft.tokenDetails,
...detatils,
...details,
};
});
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const SEARCHGMP_SOURCE = {
"confirm",
"executed",
"callback",
"interchain_token_deployment_started.destinationChain",
],
excludes: [
"call.transaction",
Expand Down Expand Up @@ -54,31 +55,52 @@ export const getTransactionStatusOnDestinationChains = publicProcedure
});

if (data.length) {
const result = data.reduce(
(acc, gmpData) => {
const { call, status } = gmpData;
const destinationChain = gmpData.callback?.returnValues.destinationChain.toLowerCase() || call.returnValues.destinationChain.toLowerCase();
const pendingResult = data.reduce(
async (acc, gmpData) => {
const {
call,
status: firstHopStatus,
interchain_token_deployment_started: tokenDeployment,
} = gmpData;

const chainType = gmpData.call.chain_type;
let secondHopStatus = "pending"

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;
}

const destinationChain =
tokenDeployment?.destinationChain?.toLowerCase() ||
call.returnValues.destinationChain.toLowerCase();

return {
...acc,
[destinationChain]: {
status,
status: chainType === "evm" ? firstHopStatus : secondHopStatus,
txHash: call.transactionHash,
logIndex: call.logIndex ?? call._logIndex ?? 0,
txId: call.id,
txId: gmpData.message_id,
},
};
},
{} as {
{} as Promise<{
[chainId: string]: {
status: GMPTxStatus;
txHash: `0x${string}`;
txId: string;
logIndex: number;
};
}
}>
);

return result;
return await pendingResult;
}

// If we don't find the transaction, we throw a 404 error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const getTransactionStatusesOnDestinationChains = publicProcedure
.input(INPUT_SCHEMA)
.query(async ({ ctx, input }) => {
try {
// Fetch all first hop transactions
const results = await Promise.all(
input.txHashes.map((txHash) =>
ctx.services.gmp.searchGMP({
Expand All @@ -27,15 +28,52 @@ export const getTransactionStatusesOnDestinationChains = publicProcedure
)
);

return results.flat().reduce(
(acc, { call, status }) => ({
// Process all transactions and their second hops
const processedResults = await Promise.all(
results.flat().map(async (gmpData) => {
const {
call,
status: firstHopStatus,
interchain_token_deployment_started: tokenDeployment,
} = gmpData;

const chainType = gmpData.call.chain_type;
let secondHopStatus = "pending" as GMPTxStatus;

// Check for second hop if callback exists
if (gmpData.callback) {
const secondHopMessageId = gmpData.callback.returnValues.messageId;
const secondHopData = await ctx.services.gmp.searchGMP({
txHash: secondHopMessageId,
_source: SEARCHGMP_SOURCE,
});

if (secondHopData.length > 0) {
secondHopStatus = secondHopData[0].status;
}
}

const destinationChain =
tokenDeployment?.destinationChain?.toLowerCase() ||
call.returnValues.destinationChain.toLowerCase();

return {
destinationChain,
data: {
status: chainType === "evm" ? firstHopStatus : secondHopStatus,
txHash: call.transactionHash,
logIndex: call.logIndex ?? call._logIndex ?? 0,
txId: gmpData.message_id,
},
};
})
);

// Combine all results into a single object
return processedResults.reduce(
(acc, { destinationChain, data }) => ({
...acc,
[call.returnValues.destinationChain.toLowerCase()]: {
status,
txHash: call.transactionHash,
logIndex: call.logIndex ?? call._logIndex ?? 0,
txId: call.id,
},
[destinationChain]: data,
}),
{} as {
[chainId: string]: {
Expand Down
30 changes: 21 additions & 9 deletions apps/maestro/src/services/axelarscan/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,16 @@ const EVM_CHAIN_CONFIGS_BY_ID = indexBy(prop("id"), WAGMI_CHAIN_CONFIGS);
const VM_CHAIN_CONFIGS_BY_ID = indexBy(prop("id"), WAGMI_CHAIN_CONFIGS);

export function useAllChainConfigsQuery() {
const { computed: evmComputed, data: evmChains, isLoading: isLoadingEVM } = useEVMChainConfigsQuery();
const { computed: vmComputed, data: vmChains, isLoading: isLoadingVM } = useVMChainConfigsQuery();
const {
computed: evmComputed,
data: evmChains,
...evmChainsQuery
} = useEVMChainConfigsQuery();
const {
computed: vmComputed,
data: vmChains,
...vmChainsQuery
} = useVMChainConfigsQuery();
const combinedComputed = useMemo(
() => ({
indexedById: {
Expand All @@ -26,10 +34,7 @@ export function useAllChainConfigsQuery() {
...vmComputed.indexedByChainId,
...evmComputed.indexedByChainId,
},
wagmiChains: [
...vmComputed.wagmiChains,
...evmComputed.wagmiChains
]
wagmiChains: [...vmComputed.wagmiChains, ...evmComputed.wagmiChains],
}),
[evmComputed, vmComputed]
);
Expand Down Expand Up @@ -60,8 +65,15 @@ export function useAllChainConfigsQuery() {
return Array.from(chainMap.values());
}, [evmChains, vmChains]);


return {combinedComputed, allChains, isLoading: isLoadingEVM || isLoadingVM};
return {
combinedComputed,
allChains,
isLoading: evmChainsQuery.isLoading || vmChainsQuery.isLoading,
isError: evmChainsQuery.isError || vmChainsQuery.isError,
error: evmChainsQuery.error || vmChainsQuery.error,
isFetching: evmChainsQuery.isFetching || vmChainsQuery.isFetching,
isSuccess: evmChainsQuery.isSuccess || vmChainsQuery.isSuccess,
};
}

export function useEVMChainConfigsQuery() {
Expand Down Expand Up @@ -150,7 +162,7 @@ export function useVMChainConfigsQuery() {
computed: {
indexedByChainId: indexBy(prop("chain_id"), configured),
indexedById: indexBy(prop("id"), configured),
wagmiChains
wagmiChains,
},
};
}
Expand Down
25 changes: 6 additions & 19 deletions apps/maestro/src/services/gmp/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,14 @@ import { isAddress } from "viem";

import { trpc } from "~/lib/trpc";
import { hex64 } from "~/lib/utils/validation";
import { useEVMChainConfigsQuery, useVMChainConfigsQuery } from "../axelarscan/hooks";
import { useAllChainConfigsQuery } from "../axelarscan/hooks";

export function useInterchainTokensQuery(input: {
chainId?: number;
tokenAddress?: `0x${string}`;
strict?: boolean;
}) {
const { computed: evmComputed, ...evmChainsQuery } = useEVMChainConfigsQuery();
const { computed: vmComputed, ...vmChainsQuery } = useVMChainConfigsQuery();

const combinedComputed = useMemo(() => ({
indexedById: {
...vmComputed.indexedById,
...evmComputed.indexedById,
},
indexedByChainId: {
...vmComputed.indexedByChainId,
...evmComputed.indexedByChainId,
},
wagmiChains: evmComputed.wagmiChains, // Keep wagmiChains for EVM compatibility
}), [evmComputed, vmComputed]);
const { combinedComputed, isLoading, isError, error, isFetching } = useAllChainConfigsQuery();

const { data, ...queryResult } =
trpc.interchainToken.searchInterchainToken.useQuery(
Expand Down Expand Up @@ -58,10 +45,10 @@ export function useInterchainTokensQuery(input: {
combinedComputed.wagmiChains?.find((x) => x?.id === chainId)
),
},
isLoading: evmChainsQuery.isLoading || vmChainsQuery.isLoading || queryResult.isLoading,
isFetching: evmChainsQuery.isFetching || vmChainsQuery.isFetching || queryResult.isFetching,
isError: evmChainsQuery.isError || vmChainsQuery.isError || queryResult.isError,
error: evmChainsQuery.error || vmChainsQuery.error || queryResult.error,
isLoading,
isFetching,
isError,
error,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,36 +132,31 @@ const TxFinalityProgress: FC<{ txHash: `0x${string}`; chainId: number }> = ({
};

const GMPTxStatusMonitor = ({ txHash, onAllChainsExecuted }: Props) => {
const chainId = useChainId();
const { combinedComputed } = useAllChainConfigsQuery();
const {
data: statuses,
computed: { chains: total, executed },
isLoading,
} = useGetTransactionStatusOnDestinationChainsQuery({ txHash });

const chainId = useChainId();

const { combinedComputed } = useAllChainConfigsQuery();

const statusList = Object.values(statuses ?? {});
const pendingItsHubTx =
Object.keys(statuses).includes("axelarnet") ||
Object.keys(statuses).includes("axelar");

useEffect(() => {
if (
statusList.length &&
!pendingItsHubTx &&
statusList?.every((s) => s.status === "executed")
) {
onAllChainsExecuted?.();
}
}, [pendingItsHubTx, statusList, onAllChainsExecuted]);
}, [statusList, onAllChainsExecuted]);

if (!statuses || Object.keys(statuses).length === 0 || pendingItsHubTx) {
if (!isLoading && !pendingItsHubTx) {
if (!statuses || Object.keys(statuses).length === 0) {
if (!isLoading) {
// nothing to show
return null;
}

return (
<div className="grid place-items-center gap-4">
<div className="flex">Loading transaction status...</div>
Expand Down
24 changes: 23 additions & 1 deletion packages/api/src/gmp/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { Log } from "viem";

type BaseGMPResponse<T> = T & {
time_spent: number;
};
Expand Down Expand Up @@ -69,6 +71,23 @@ export type SearchGMPParams = Omit<BaseGMPParams, "contractMethod"> & {
};
};

export type TransactionReceipt = {
blockHash: `0x${string}`;
blockNumber: number;
contractAddress: string | null;
cumulativeGasUsed: string;
effectiveGasPrice: string;
from: `0x${string}`;
gasUsed: string;
logs: Array<Log>;
status: number;
to: `0x${string}`;
transactionHash: `0x${string}`;
transactionIndex: number;
type: number;
gasLimit: string;
};

export type SearchGMPCall = {
blockNumber: number;
blockHash: `0x${string}`;
Expand All @@ -84,11 +103,13 @@ export type SearchGMPCall = {
event: string;
eventIndex: number;
eventSignature: string;
id: string;
_id: string;
chain: string;
contract_address: `0x${string}`;
chain_type: ChainType;
destination_chain_type: ChainType;
receipt?: TransactionReceipt;
messageIdIndex: number;
returnValues: {
sender: string;
destinationChain: string;
Expand Down Expand Up @@ -296,6 +317,7 @@ export type SearchGMPResponseData = {
status: GMPTxStatus;
executed?: SearchGMPExecuted;
error?: SearchGMPDataError;
message_id: string;
time_spent: SearchGMPTimespent;
gas_paid: SearchGMPGasPaid;
gas_status: SearchGMPGasStatus;
Expand Down

0 comments on commit 5ee1a72

Please sign in to comment.