Skip to content

Commit

Permalink
chore: fix balance and address recovery retry (#504)
Browse files Browse the repository at this point in the history
  • Loading branch information
SGiaccobasso authored Feb 12, 2025
1 parent 361dae4 commit f3e94de
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,7 @@ export function useDeployAndRegisterRemoteCanonicalTokenMutation(
return {
destinationChainNames,
};
}, [
combinedComputed.indexedById,
input?.destinationChainIds,
]);
}, [combinedComputed.indexedById, input?.destinationChainIds]);

const multicallArgs = useMemo(() => {
if (!input || !tokenId) {
Expand All @@ -100,7 +97,6 @@ export function useDeployAndRegisterRemoteCanonicalTokenMutation(
const gasValue = input.remoteDeploymentGasFees[i] ?? 0n;

const args = {
originalChain: "",
originalTokenAddress: input.tokenAddress as `0x{string}`,
destinationChain,
gasValue,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ export default function useRegisterRemoteCanonicalTokens(

return INTERCHAIN_TOKEN_FACTORY_ENCODERS.deployRemoteCanonicalInterchainToken.data(
{
originalChain: "",
originalTokenAddress: tokenDetails.tokenAddress as `0x{string}`,
destinationChain: axelarChainId,
gasValue,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,21 @@ export const getERC20TokenBalanceForOwner = publicProcedure
})
)
.query(async ({ input, ctx }) => {
// If the token address and owner address are not the same length, the balance is 0
// This is because a sui address can't have evm balances and vice versa
if (input.tokenAddress?.length !== input.owner?.length) {
return {
isTokenOwner: false,
isTokenMinter: false,
tokenBalance: "0",
decimals: 0,
isTokenPendingOwner: false,
hasPendingOwner: false,
hasMinterRole: false,
hasOperatorRole: false,
hasFlowLimiterRole: false,
};
}
// Sui address length is 66
if (input.tokenAddress?.length === 66) {
let isTokenOwner = false;
Expand Down
91 changes: 50 additions & 41 deletions apps/maestro/src/server/routers/sui/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
getFullnodeUrl,
SuiClient,
SuiObjectChange,
type DynamicFieldInfo,
type DynamicFieldPage,
} from "@mysten/sui/client";
import { Transaction } from "@mysten/sui/transactions";
Expand Down Expand Up @@ -86,13 +87,6 @@ export const getTokenOwner = async (tokenAddress: string) => {
export const getCoinAddressAndManagerByTokenId = async (input: {
tokenId: string;
}) => {
let cursor = null;
let filteredResult = [];
let result = {
hasNextPage: true,
nextCursor: null,
data: [],
} as DynamicFieldPage;
try {
const suiClient = new SuiClient({
url: config["sui"].rpc,
Expand All @@ -109,29 +103,20 @@ export const getCoinAddressAndManagerByTokenId = async (input: {
},
});
const registeredCoinsBagId = (registeredCoinsObject.data?.content as any)
?.fields?.value?.fields.registered_coins.fields.id.id;

do {
result = await suiClient.getDynamicFields({
parentId: registeredCoinsBagId,
cursor: cursor,
});
cursor = result.nextCursor;
filteredResult = result.data.filter((item: any) => {
return (
item.name.value.id.toString().toLowerCase() ===
input.tokenId.toLowerCase()
);
});
if (filteredResult.length) {
break;
}
} while (result?.hasNextPage && !filteredResult?.length);
?.fields?.value?.fields.registered_coins.fields.id.id as string;

const filteredResult = await findInPaginatedDynamicFields(
suiClient,
registeredCoinsBagId,
(item: any) =>
item.name.value.id.toString().toLowerCase() ===
input.tokenId.toLowerCase()
);

if (filteredResult.length > 0) {
if (filteredResult) {
return extractTokenDetails(filteredResult);
} else {
console.log("Token ID not found.");
console.log("getCoinAddressAndManagerByTokenId: Token ID not found.");
return null;
}
} catch (error) {
Expand All @@ -142,18 +127,42 @@ export const getCoinAddressAndManagerByTokenId = async (input: {
}
};

function extractTokenDetails(filteredResult: any[]) {
return filteredResult.map((item) => {
// Extract the token manager (objectId)
const tokenManager = item.objectId;

// Extract the address from the objectType
const objectType = item.objectType;
const addressMatch = objectType.match(/CoinData<(0x[^:]+)/);
const address = addressMatch ? addressMatch[1] : null;
return {
tokenManager,
address,
};
})[0];
export async function findInPaginatedDynamicFields(
suiClient: SuiClient,
parentId: string,
filterFn: (item: DynamicFieldInfo) => boolean
): Promise<DynamicFieldInfo | null> {
let cursor: string | null = null;
let result: DynamicFieldPage | null;
let filteredResult: DynamicFieldInfo[] = [];

do {
result = await suiClient
.getDynamicFields({
parentId,
cursor: cursor,
})
.catch((error) => {
console.error("Failed to get dynamic fields:", error);
return null;
});

cursor = result?.nextCursor ?? null;
filteredResult = result?.data?.filter(filterFn) ?? [];
} while (result?.hasNextPage && !filteredResult?.length);
return filteredResult?.length ? filteredResult[0] : null;
}

function extractTokenDetails(filteredResult: DynamicFieldInfo) {
// Extract the token manager (objectId)
const tokenManager = filteredResult.objectId;

// Extract the address from the objectType
const objectType = filteredResult.objectType;
const addressMatch = objectType.match(/CoinData<(0x[^:]+)/);
const address = addressMatch?.[1] as string;
return {
tokenManager,
address,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,9 @@ const ConnectedInterchainTokensPage: FC<ConnectedInterchainTokensPageProps> = (
const { mutateAsync: updateEVMAddresses } =
trpc.interchainToken.updateEVMRemoteTokenAddress.useMutation();

// Update Sui remote token addresses
// the address is wrong on the Sui chain on deployment because it's the EVM address,
// we wait for the tx to be executed then we update the address on the Sui chain
useEffect(() => {
if (
!isAlreadyUpdatingRemoteSui &&
Expand All @@ -257,9 +260,10 @@ const ConnectedInterchainTokensPage: FC<ConnectedInterchainTokensPageProps> = (
setAlreadyUpdatingRemoteSui(false);
refetchPageData();
})
.catch((error) => {
setAlreadyUpdatingRemoteSui(false);
console.error("Failed to update Sui remote token addresses:", error);
.catch(() => {
setTimeout(() => {
setAlreadyUpdatingRemoteSui(false);
}, 5000); // space requests while waiting for the tx to be executed and data to be available on sui chain
});
}
}, [
Expand All @@ -273,6 +277,13 @@ const ConnectedInterchainTokensPage: FC<ConnectedInterchainTokensPageProps> = (

const [isUpdating, setIsUpdating] = useState<Record<string, boolean>>({});

const setChainUpdateStatus = useCallback(
(chainId: string | undefined, status: boolean) => {
setIsUpdating((prev) => ({ ...prev, [chainId ?? ""]: status }));
},
[]
);

useEffect(() => {
interchainToken?.matchingTokens?.forEach((x) => {
// check if the EVM token address is the same as sui, which is wrong
Expand All @@ -282,22 +293,19 @@ const ConnectedInterchainTokensPage: FC<ConnectedInterchainTokensPageProps> = (
x.tokenAddress === props.tokenAddress &&
!isUpdating[x.chain?.id ?? ""]
) {
setIsUpdating((prev) => ({ ...prev, [x.chain?.id ?? ""]: true }));
setChainUpdateStatus(x.chain?.id, true);
updateEVMAddresses({
tokenId: props?.tokenId as `0x${string}`,
axelarChainId: x.chain?.id,
})
.then(() => {
setChainUpdateStatus(x.chain?.id, false);
refetchPageData();
})
.catch((error) => {
console.error(
"Failed to update EVM remote token addresses:",
error
);
})
.finally(() => {
setIsUpdating((prev) => ({ ...prev, [x.chain?.id ?? ""]: false }));
.catch(() => {
setTimeout(() => {
setChainUpdateStatus(x.chain?.id, false);
}, 5000);
});
}
});
Expand All @@ -309,6 +317,7 @@ const ConnectedInterchainTokensPage: FC<ConnectedInterchainTokensPageProps> = (
updateEVMAddresses,
isUpdating,
refetchPageData,
setChainUpdateStatus,
]);

const remoteChainsExecuted = useMemo(
Expand Down

0 comments on commit f3e94de

Please sign in to comment.