Web: fix vaa parsing (#31)
* web: fix broken response objects & update parseVaa method * Removed _parseVAAAlgorand * onchain-data: replaced serum rpc and added more try/catch in case of failure * update axios * web: set proxy and fixed unique key in TokenDetails.tsx Co-authored-by: Evan Gray <battledingo@gmail.com>
This commit is contained in:
parent
ff4f7f4ee7
commit
e7c81723ca
|
@ -242,7 +242,12 @@ export async function getAlgoCustody(chainInfo, useAllowList = true) {
|
|||
|
||||
export async function grabAlgoCustodyData(chain, useAllowList) {
|
||||
const chainInfo = CHAIN_INFO_MAP[chain];
|
||||
const balances = await getAlgoCustody(chainInfo, useAllowList);
|
||||
var balances = [];
|
||||
try {
|
||||
balances = await getAlgoCustody(chainInfo, useAllowList);
|
||||
} catch (e) {
|
||||
console.log(`could not grab ${chainInfo.name} data`);
|
||||
}
|
||||
// await updateTable(chainInfo, balances);
|
||||
const chainInfo_ = {
|
||||
...chainInfo,
|
||||
|
|
|
@ -206,7 +206,12 @@ export async function getAptosCustody(chainInfo, useAllowList = true) {
|
|||
|
||||
export async function grabAptosCustodyData(chain, useAllowList) {
|
||||
const chainInfo = CHAIN_INFO_MAP[chain];
|
||||
const balances = await getAptosCustody(chainInfo, useAllowList);
|
||||
var balances = [];
|
||||
try {
|
||||
balances = await getAptosCustody(chainInfo, useAllowList);
|
||||
} catch (e) {
|
||||
console.log(`could not grab ${chainInfo.name} data`);
|
||||
}
|
||||
// await updateTable(chainInfo, balances);
|
||||
const chainInfo_ = {
|
||||
...chainInfo,
|
||||
|
|
|
@ -348,7 +348,12 @@ export async function getEvmCustody(chainInfo, useAllowList = true) {
|
|||
|
||||
export async function grabEvmCustodyData(chain, useAllowList) {
|
||||
const chainInfo = CHAIN_INFO_MAP[chain];
|
||||
const balances = await getEvmCustody(chainInfo, useAllowList);
|
||||
var balances = [];
|
||||
try {
|
||||
balances = await getEvmCustody(chainInfo, useAllowList);
|
||||
} catch (e) {
|
||||
console.log(`could not grab ${chainInfo.name} data`);
|
||||
}
|
||||
// await updateTable(chainInfo, balances);
|
||||
const chainInfo_ = {
|
||||
...chainInfo,
|
||||
|
|
|
@ -214,7 +214,12 @@ export async function getNearCustody(chainInfo, useAllowList = true) {
|
|||
|
||||
export async function grabNearCustodyData(chain, useAllowList) {
|
||||
const chainInfo = CHAIN_INFO_MAP[chain];
|
||||
const balances = await getNearCustody(chainInfo, useAllowList);
|
||||
var balances = [];
|
||||
try {
|
||||
balances = await getNearCustody(chainInfo, useAllowList);
|
||||
} catch (e) {
|
||||
console.log("could not grab Near data");
|
||||
}
|
||||
// await updateTable(chainInfo, balances);
|
||||
const chainInfo_ = {
|
||||
...chainInfo,
|
||||
|
|
|
@ -310,7 +310,12 @@ export async function getSolanaCustody(chainInfo, useAllowList = true) {
|
|||
|
||||
export async function grabSolanaCustodyData(chain, useAllowList) {
|
||||
const chainInfo = CHAIN_INFO_MAP[chain];
|
||||
const balances = await getSolanaCustody(chainInfo, useAllowList);
|
||||
var balances = [];
|
||||
try {
|
||||
balances = await getSolanaCustody(chainInfo, useAllowList);
|
||||
} catch (e) {
|
||||
console.log("could not grab Solana data");
|
||||
}
|
||||
if (balances.length === 0) {
|
||||
console.log(`could not get ${chainInfo.name} custody data`);
|
||||
}
|
||||
|
|
|
@ -312,7 +312,12 @@ export async function getTerraCustody(chainInfo, useAllowList) {
|
|||
|
||||
export async function grabTerraCustodyData(chain, useAllowList) {
|
||||
const chainInfo = CHAIN_INFO_MAP[chain];
|
||||
const balances = await getTerraCustody(chainInfo, useAllowList);
|
||||
var balances = [];
|
||||
try {
|
||||
balances = await getTerraCustody(chainInfo, useAllowList);
|
||||
} catch (e) {
|
||||
console.log("could not grab Solana data");
|
||||
}
|
||||
if (balances === undefined) {
|
||||
console.log("could not pull terra balances");
|
||||
return { balances: [] };
|
||||
|
|
|
@ -177,8 +177,7 @@ export var CHAIN_INFO_MAP = {
|
|||
name: "solana",
|
||||
evm: false,
|
||||
chain_id: CHAIN_ID_SOLANA,
|
||||
endpoint_url:
|
||||
process.env.SOLANA_RPC || "https://solana-api.projectserum.com",
|
||||
endpoint_url: process.env.SOLANA_RPC || "https://rpc.ankr.com/solana",
|
||||
core_bridge: "worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth",
|
||||
token_bridge_address: "wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb",
|
||||
custody_address: "GugU1tP7doLeTw9hQP51xRJyS8Da1fWxuiy2rVrnMD2m",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,7 +5,7 @@
|
|||
"license": "Apache-2.0",
|
||||
"proxy": "http://server:4000",
|
||||
"dependencies": {
|
||||
"@certusone/wormhole-sdk": "^0.7.6",
|
||||
"@certusone/wormhole-sdk": "^0.9.2",
|
||||
"@certusone/wormhole-sdk-proto-web": "^0.0.4",
|
||||
"@emotion/react": "^11.10.0",
|
||||
"@emotion/styled": "^11.10.0",
|
||||
|
@ -23,7 +23,7 @@
|
|||
"@types/react-dom": "^18.0.6",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"assert": "^2.0.0",
|
||||
"axios": "^0.27.2",
|
||||
"axios": "^1.1.3",
|
||||
"binary-parser": "^2.2.1",
|
||||
"coingecko-api": "^1.0.10",
|
||||
"dotenv": "^16.0.2",
|
||||
|
|
|
@ -12,26 +12,7 @@ import useEnqueuedVaaDetails, {
|
|||
} from "../hooks/useEnqueuedVaaDetails";
|
||||
import Table from "./Table";
|
||||
import numeral from "numeral";
|
||||
|
||||
// async function VaaExists(row: EnqueuedVaaDetailsResponse) {
|
||||
// try {
|
||||
// const chainId: ChainId = findChainId(row.chainId.toString());
|
||||
// const vaa = await getSignedVAAWithRetry(
|
||||
// WORMHOLE_RPC_HOSTS,
|
||||
// chainId,
|
||||
// row.emitterAddress,
|
||||
// row.sequence.toString(),
|
||||
// { transport: NodeHttpTransport() },
|
||||
// 1000,
|
||||
// 4
|
||||
// );
|
||||
// if (vaa != undefined) {
|
||||
// return true;
|
||||
// }
|
||||
// } catch (e) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
import EnqueuedVaaExists from "./EnqueuedVaaExists";
|
||||
|
||||
const columnHelper = createColumnHelper<EnqueuedVaaDetailsResponse>();
|
||||
|
||||
|
@ -73,14 +54,11 @@ const columns = [
|
|||
? new Date(info.getValue() * 1000).toLocaleString()
|
||||
: null,
|
||||
}),
|
||||
// columnHelper.display({
|
||||
// id: "hasQuorum",
|
||||
// header: () => "Has Quorum?",
|
||||
// cell: (info) => {
|
||||
// const value = VaaExists(info.row.original);
|
||||
// return value;
|
||||
// },
|
||||
// }),
|
||||
columnHelper.display({
|
||||
id: "hasQuorum",
|
||||
header: () => "Has Quorum?",
|
||||
cell: (info) => EnqueuedVaaExists(info.row.original),
|
||||
}),
|
||||
columnHelper.accessor("txHash", {
|
||||
header: () => "Transaction",
|
||||
cell: (info) => (
|
||||
|
@ -100,7 +78,8 @@ function EnqueuedVaaDetails(id: string) {
|
|||
state: {
|
||||
sorting,
|
||||
},
|
||||
getRowId: (chain) => chain.chainId,
|
||||
getRowId: (vaa) =>
|
||||
`${vaa.chainId}/${vaa.emitterAddress.slice(2)}/${vaa.sequence}`,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
onSortingChange: setSorting,
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
import axios from "axios";
|
||||
import { useEffect, useState } from "react";
|
||||
import { EnqueuedVaaDetailsResponse } from "../hooks/useEnqueuedVaaDetails";
|
||||
|
||||
const VAA_CHECK_TIMEOUT = 60000;
|
||||
|
||||
function EnqueuedVaaExists(row: EnqueuedVaaDetailsResponse) {
|
||||
const [vaaHasQuorum, setVaaHasQuorum] = useState<boolean | null>(null);
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
(async () => {
|
||||
while (!cancelled) {
|
||||
setVaaHasQuorum(null);
|
||||
let result = false;
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`/api/vaas/${row.chainId}/${row.emitterAddress.slice(2)}/${
|
||||
row.sequence
|
||||
}`
|
||||
);
|
||||
if (response.data) result = true;
|
||||
} catch (e) {}
|
||||
if (!cancelled) {
|
||||
setVaaHasQuorum(result);
|
||||
if (result) {
|
||||
cancelled = true;
|
||||
return;
|
||||
}
|
||||
await new Promise((resolve) =>
|
||||
setTimeout(resolve, VAA_CHECK_TIMEOUT)
|
||||
);
|
||||
}
|
||||
}
|
||||
})();
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [row]);
|
||||
return (
|
||||
<span role="img">
|
||||
{vaaHasQuorum === null ? "⏳" : vaaHasQuorum ? "✅" : "❌"}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
export default EnqueuedVaaExists;
|
|
@ -46,34 +46,34 @@ const columns = [
|
|||
header: () => "Sequence",
|
||||
cell: (info) => info.getValue().split("/")[2],
|
||||
}),
|
||||
columnHelper.accessor("vaa", {
|
||||
columnHelper.accessor("vaas", {
|
||||
id: "type",
|
||||
header: () => "Type",
|
||||
cell: (info) =>
|
||||
vaa.parse(Buffer.from(info.getValue(), "base64")).payload.type,
|
||||
}),
|
||||
columnHelper.accessor("vaa", {
|
||||
columnHelper.accessor("vaas", {
|
||||
id: "chain",
|
||||
header: () => "Chain",
|
||||
cell: (info) =>
|
||||
(vaa.parse(Buffer.from(info.getValue(), "base64")).payload as any)
|
||||
.chain || "",
|
||||
}),
|
||||
columnHelper.accessor("vaa", {
|
||||
columnHelper.accessor("vaas", {
|
||||
id: "address",
|
||||
header: () => "Address",
|
||||
cell: (info) =>
|
||||
(vaa.parse(Buffer.from(info.getValue(), "base64")).payload as any)
|
||||
.address || "",
|
||||
}),
|
||||
columnHelper.accessor("vaa", {
|
||||
columnHelper.accessor("vaas", {
|
||||
id: "module",
|
||||
header: () => "Module",
|
||||
cell: (info) =>
|
||||
(vaa.parse(Buffer.from(info.getValue(), "base64")).payload as any)
|
||||
.module || "",
|
||||
}),
|
||||
columnHelper.accessor("createdAt", {
|
||||
columnHelper.accessor("updatedAt", {
|
||||
header: () => "Observed At",
|
||||
cell: (info) => new Date(info.getValue()).toLocaleString(),
|
||||
}),
|
||||
|
@ -95,7 +95,7 @@ const obsColumns = [
|
|||
function VAADetails({ row }: { row: Row<VAAsResponse> }): ReactElement {
|
||||
return (
|
||||
<Typography variant="body2" sx={{ wordBreak: "break-all" }}>
|
||||
{Buffer.from(row.original.vaa, "base64").toString("hex")}
|
||||
{Buffer.from(row.original.vaas, "base64").toString("hex")}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
@ -118,10 +118,10 @@ function Governance() {
|
|||
// NOTE: this ignores differing digests
|
||||
Object.entries(
|
||||
obs.reduce((obvsById, o) => {
|
||||
if (!obvsById[o.messageid]) {
|
||||
obvsById[o.messageid] = [];
|
||||
if (!obvsById[o.messageId]) {
|
||||
obvsById[o.messageId] = [];
|
||||
}
|
||||
obvsById[o.messageid].push(o);
|
||||
obvsById[o.messageId].push(o);
|
||||
return obvsById;
|
||||
}, {} as any)
|
||||
).map(([key, val]: [string, any]) => ({
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { ChainId, tryHexToNativeString } from "@certusone/wormhole-sdk";
|
||||
import { _parseVAAAlgorand } from "@certusone/wormhole-sdk/lib/esm/algorand/Algorand";
|
||||
import { parseVaa } from "@certusone/wormhole-sdk/lib/cjs/vaa";
|
||||
import { parseTransferPayload } from "@certusone/wormhole-sdk/lib/cjs/utils";
|
||||
import { ChevronRight } from "@mui/icons-material";
|
||||
import { Card, IconButton, Typography } from "@mui/material";
|
||||
import { Box } from "@mui/system";
|
||||
|
@ -61,16 +62,18 @@ const columns = [
|
|||
];
|
||||
|
||||
function VAADetails({ row }: { row: Row<VAAsResponse> }): ReactElement {
|
||||
const parsedVaa = _parseVAAAlgorand(
|
||||
new Uint8Array(Buffer.from(row.original.vaa, "base64"))
|
||||
const parsedVaa = parseVaa(
|
||||
new Uint8Array(Buffer.from(row.original.vaas, "base64"))
|
||||
);
|
||||
let token = parsedVaa.Contract;
|
||||
const payload = parsedVaa.payload;
|
||||
const parsedPayload = parseTransferPayload(payload);
|
||||
let token = parsedPayload.originAddress;
|
||||
// FromChain is a misnomer - actually OriginChain
|
||||
if (parsedVaa.Contract && parsedVaa.FromChain)
|
||||
if (parsedPayload.originAddress && parsedPayload.originChain)
|
||||
try {
|
||||
token = tryHexToNativeString(
|
||||
parsedVaa.Contract,
|
||||
parsedVaa.FromChain as ChainId
|
||||
parsedPayload.originAddress,
|
||||
parsedPayload.originChain as ChainId
|
||||
);
|
||||
} catch (e) {}
|
||||
return (
|
||||
|
@ -79,15 +82,15 @@ function VAADetails({ row }: { row: Row<VAAsResponse> }): ReactElement {
|
|||
<br />
|
||||
Timestamp: {new Date(parsedVaa.timestamp * 1000).toLocaleString()}
|
||||
<br />
|
||||
Consistency: {parsedVaa.consistency}
|
||||
Consistency: {parsedVaa.consistencyLevel}
|
||||
<br />
|
||||
Nonce: {parsedVaa.nonce}
|
||||
<br />
|
||||
Origin: {parsedVaa.FromChain}
|
||||
Origin: {parsedPayload.originChain}
|
||||
<br />
|
||||
Token: {token}
|
||||
<br />
|
||||
Amount: {BigNumber.from(parsedVaa.Amount).toString()}
|
||||
Amount: {BigNumber.from(parsedPayload.amount).toString()}
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -67,7 +67,7 @@ function TokenDetails(id: string) {
|
|||
state: {
|
||||
sorting,
|
||||
},
|
||||
getRowId: (token) => token.name,
|
||||
getRowId: (token) => token.tokenAddress,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
onSortingChange: setSorting,
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import { ChainId, tryHexToNativeString } from "@certusone/wormhole-sdk";
|
||||
import { _parseVAAAlgorand } from "@certusone/wormhole-sdk/lib/esm/algorand/Algorand";
|
||||
import {
|
||||
ChainId,
|
||||
parseTransferPayload,
|
||||
parseVaa,
|
||||
tryHexToNativeString,
|
||||
} from "@certusone/wormhole-sdk";
|
||||
import { ChevronRight } from "@mui/icons-material";
|
||||
import { Card, IconButton, Typography } from "@mui/material";
|
||||
import { Box } from "@mui/system";
|
||||
|
@ -63,16 +67,18 @@ const columns = [
|
|||
];
|
||||
|
||||
function VAADetails({ row }: { row: Row<VAAsResponse> }): ReactElement {
|
||||
const parsedVaa = _parseVAAAlgorand(
|
||||
new Uint8Array(Buffer.from(row.original.vaa, "base64"))
|
||||
const parsedVaa = parseVaa(
|
||||
new Uint8Array(Buffer.from(row.original.vaas, "base64"))
|
||||
);
|
||||
let token = parsedVaa.Contract;
|
||||
const payload = parsedVaa.payload;
|
||||
const parsedPayload = parseTransferPayload(payload);
|
||||
let token = parsedPayload.originAddress;
|
||||
// FromChain is a misnomer - actually OriginChain
|
||||
if (parsedVaa.Contract && parsedVaa.FromChain)
|
||||
if (parsedPayload.originAddress && parsedPayload.originChain)
|
||||
try {
|
||||
token = tryHexToNativeString(
|
||||
parsedVaa.Contract,
|
||||
parsedVaa.FromChain as ChainId
|
||||
parsedPayload.originAddress,
|
||||
parsedPayload.originChain as ChainId
|
||||
);
|
||||
} catch (e) {}
|
||||
return (
|
||||
|
@ -81,15 +87,15 @@ function VAADetails({ row }: { row: Row<VAAsResponse> }): ReactElement {
|
|||
<br />
|
||||
Timestamp: {new Date(parsedVaa.timestamp * 1000).toLocaleString()}
|
||||
<br />
|
||||
Consistency: {parsedVaa.consistency}
|
||||
Consistency: {parsedVaa.consistencyLevel}
|
||||
<br />
|
||||
Nonce: {parsedVaa.nonce}
|
||||
<br />
|
||||
Origin: {parsedVaa.FromChain}
|
||||
Origin: {parsedPayload.originChain}
|
||||
<br />
|
||||
Token: {token}
|
||||
<br />
|
||||
Amount: {BigNumber.from(parsedVaa.Amount).toString()}
|
||||
Amount: {BigNumber.from(parsedPayload.amount).toString()}
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -5,7 +5,7 @@ import { POLL_TIME } from "../utils/consts";
|
|||
|
||||
export type EnqueuedVaa = {
|
||||
chainId: number;
|
||||
emitterAddres: string;
|
||||
emitterAddress: string;
|
||||
sequence: number;
|
||||
notionalValue: number;
|
||||
txHash: string;
|
||||
|
|
|
@ -14,7 +14,7 @@ export type HeartbeatNetwork = {
|
|||
export type HeartbeatResponse = {
|
||||
boottimestamp: NumberLong;
|
||||
counter: number;
|
||||
createdAt: string;
|
||||
indexedAt: string;
|
||||
features: string[] | null;
|
||||
guardianaddr: string;
|
||||
networks: HeartbeatNetwork[];
|
||||
|
|
|
@ -4,11 +4,11 @@ import { useNetworkContext } from "../contexts/NetworkContext";
|
|||
import { POLL_TIME } from "../utils/consts";
|
||||
|
||||
export type ObservationsResponse = {
|
||||
createdAt: string;
|
||||
indexedAt: string;
|
||||
updatedAt: string;
|
||||
addr: string;
|
||||
hash: string;
|
||||
messageid: string;
|
||||
messageId: string;
|
||||
signature: string;
|
||||
txhash: string;
|
||||
_id: string;
|
||||
|
|
|
@ -4,9 +4,15 @@ import { useNetworkContext } from "../contexts/NetworkContext";
|
|||
import { POLL_TIME } from "../utils/consts";
|
||||
|
||||
export type VAAsResponse = {
|
||||
createdAt: string;
|
||||
indexedAt: string;
|
||||
updatedAt: string;
|
||||
vaa: string;
|
||||
emitterAddr: string;
|
||||
emitterChain: number;
|
||||
guardianSetIndex: number;
|
||||
sequence: number;
|
||||
timestamp: string;
|
||||
version: number;
|
||||
vaas: string;
|
||||
_id: string;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue