diff --git a/dashboard/src/components/Contracts.tsx b/dashboard/src/components/Contracts.tsx index 3cb0cfa0..a5bcac8e 100644 --- a/dashboard/src/components/Contracts.tsx +++ b/dashboard/src/components/Contracts.tsx @@ -36,7 +36,13 @@ function useGetGuardianSet(chain: Chain, address: string | undefined) { setGuardianSet([null, null]); if (!address) return; const rpcUrl = - chain === 'Wormchain' ? WORMCHAIN_URL : rpc.rpcAddress(network.currentNetwork.env, chain); + chain === 'Klaytn' + ? 'https://klaytn-mainnet-rpc.allthatnode.com:8551' + : chain === 'Near' + ? 'https://rpc.mainnet.near.org' + : chain === 'Wormchain' + ? WORMCHAIN_URL + : rpc.rpcAddress(network.currentNetwork.env, chain); if (!rpcUrl) return; let cancelled = false; const platform = chainToPlatform(chain); @@ -114,6 +120,83 @@ function useGetGuardianSet(chain: Chain, address: string | undefined) { setGuardianSet([BigInt(currentGuardianSetIndexState.value.uint), null]); } catch (e) {} })(); + } else if (platform === 'Near') { + // https://docs.near.org/api/rpc/contracts#view-contract-state + (async () => { + try { + const response = await axios.post(rpcUrl, { + jsonrpc: '2.0', + id: 'dontcare', + method: 'query', + params: { + request_type: 'view_state', + finality: 'final', + account_id: address, + prefix_base64: 'U1RBVEU=', // STATE + }, + }); + const state = Buffer.from( + response.data.result.values.find( + (s: any) => Buffer.from(s.key, 'base64').toString('ascii') === 'STATE' + ).value, + 'base64' + ).toString('hex'); + // a tiny hack - instead of parsing the whole state, just find the expiry, which comes before the guardian set index + // https://github.com/wormhole-foundation/wormhole/blob/main/near/contracts/wormhole/src/lib.rs#L109 + const expiry = `00004f91944e0000`; // = 24 * 60 * 60 * 1_000_000_000, // 24 hours in nanoseconds + const expiryIndex = state.indexOf(expiry); + const gsiIndex = expiryIndex + 16; // u64 len in hex + const gsi = BigInt( + `0x${state + .substring(gsiIndex, gsiIndex + 8) + .match(/../g) + ?.reverse() + .join('')}` + ); + if (cancelled) return; + setGuardianSet([gsi, null]); + } catch (e) {} + })(); + } else if (platform === 'Aptos') { + // https://aptos.dev/nodes/aptos-api-spec/#/ + (async () => { + try { + const response = await axios.get( + `${rpcUrl}/accounts/${address}/resource/${address}::state::WormholeState` + ); + const gsi = BigInt(response.data.data.guardian_set_index.number); + // const gsHandle = response.data.data.guardian_sets + if (cancelled) return; + setGuardianSet([gsi, null]); + } catch (e) {} + })(); + } else if (platform === 'Sui') { + // https://docs.sui.io/sui-api-ref#sui_getobject + (async () => { + try { + const response = await axios.post(rpcUrl, { + jsonrpc: '2.0', + id: 1, + method: 'sui_getObject', + params: [ + address, + { + showType: false, + showOwner: false, + showPreviousTransaction: false, + showDisplay: false, + showContent: true, + showBcs: false, + showStorageRebate: false, + }, + ], + }); + const gsi = BigInt(response.data.result.data.content.fields.guardian_set_index); + // const gsTable = response.data.result.data.content.fields.guardian_sets); + if (cancelled) return; + setGuardianSet([gsi, null]); + } catch (e) {} + })(); } return () => { cancelled = true;