@oydual31/more-vaults-sdk 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as _tanstack_react_query from '@tanstack/react-query';
2
- import { h as VaultStatus, f as VaultMetadata, e as UserPosition, a as AsyncRequestStatusInfo, j as VaultTopology, V as VaultDistribution, c as InboundRouteWithBalance } from '../spokeRoutes-BFI1m_zk.cjs';
2
+ import { h as VaultStatus, f as VaultMetadata, e as UserPosition, a as AsyncRequestStatusInfo, j as VaultTopology, V as VaultDistribution, c as InboundRouteWithBalance } from '../spokeRoutes-CK5NSOOF.cjs';
3
3
  import * as _tanstack_query_core from '@tanstack/query-core';
4
4
  import { Address } from 'viem';
5
5
 
@@ -250,14 +250,14 @@ interface UseVaultTopologyReturn {
250
250
  allChainIds: number[];
251
251
  }
252
252
  /**
253
- * Resolve the cross-chain topology of a vault from the current wallet chain.
253
+ * Resolve the cross-chain topology of a vault with automatic multi-chain discovery.
254
254
  *
255
- * Returns the hub chain, all spoke chains, and whether the user needs to
256
- * switch networks to interact with the hub.
257
- *
258
- * Since MoreVaults uses CREATE3, the vault address is the same on all chains.
255
+ * Uses `discoverVaultTopology` internally: if the wallet's current chain doesn't
256
+ * know the vault, it iterates all supported chains via public RPCs until the hub
257
+ * is found. Works even without a connected wallet.
259
258
  *
260
259
  * @example
260
+ * // Works regardless of which chain the wallet is on (or if disconnected)
261
261
  * const { topology, needsNetworkSwitch, allChainIds } = useVaultTopology('0xVAULT')
262
262
  *
263
263
  * if (needsNetworkSwitch) {
@@ -376,9 +376,9 @@ interface UseVaultDistributionReturn {
376
376
  /**
377
377
  * Read the full cross-chain capital distribution of a vault.
378
378
  *
379
- * Uses the connected wallet's chain as the hub client (via wagmi),
380
- * discovers spoke chains via topology, and creates ephemeral public
381
- * clients with fallback RPCs for spoke reads (all supported chains covered).
379
+ * Discovers the vault topology automatically via `discoverVaultTopology`
380
+ * (works without a connected wallet), then creates hub and spoke clients
381
+ * via public RPCs.
382
382
  *
383
383
  * Spoke reads that fail (bad RPC, timeout) degrade gracefully —
384
384
  * those spokes will appear with `isReachable: false`.
@@ -1,5 +1,5 @@
1
1
  import * as _tanstack_react_query from '@tanstack/react-query';
2
- import { h as VaultStatus, f as VaultMetadata, e as UserPosition, a as AsyncRequestStatusInfo, j as VaultTopology, V as VaultDistribution, c as InboundRouteWithBalance } from '../spokeRoutes-BFI1m_zk.js';
2
+ import { h as VaultStatus, f as VaultMetadata, e as UserPosition, a as AsyncRequestStatusInfo, j as VaultTopology, V as VaultDistribution, c as InboundRouteWithBalance } from '../spokeRoutes-CK5NSOOF.js';
3
3
  import * as _tanstack_query_core from '@tanstack/query-core';
4
4
  import { Address } from 'viem';
5
5
 
@@ -250,14 +250,14 @@ interface UseVaultTopologyReturn {
250
250
  allChainIds: number[];
251
251
  }
252
252
  /**
253
- * Resolve the cross-chain topology of a vault from the current wallet chain.
253
+ * Resolve the cross-chain topology of a vault with automatic multi-chain discovery.
254
254
  *
255
- * Returns the hub chain, all spoke chains, and whether the user needs to
256
- * switch networks to interact with the hub.
257
- *
258
- * Since MoreVaults uses CREATE3, the vault address is the same on all chains.
255
+ * Uses `discoverVaultTopology` internally: if the wallet's current chain doesn't
256
+ * know the vault, it iterates all supported chains via public RPCs until the hub
257
+ * is found. Works even without a connected wallet.
259
258
  *
260
259
  * @example
260
+ * // Works regardless of which chain the wallet is on (or if disconnected)
261
261
  * const { topology, needsNetworkSwitch, allChainIds } = useVaultTopology('0xVAULT')
262
262
  *
263
263
  * if (needsNetworkSwitch) {
@@ -376,9 +376,9 @@ interface UseVaultDistributionReturn {
376
376
  /**
377
377
  * Read the full cross-chain capital distribution of a vault.
378
378
  *
379
- * Uses the connected wallet's chain as the hub client (via wagmi),
380
- * discovers spoke chains via topology, and creates ephemeral public
381
- * clients with fallback RPCs for spoke reads (all supported chains covered).
379
+ * Discovers the vault topology automatically via `discoverVaultTopology`
380
+ * (works without a connected wallet), then creates hub and spoke clients
381
+ * via public RPCs.
382
382
  *
383
383
  * Spoke reads that fail (bad RPC, timeout) degrade gracefully —
384
384
  * those spokes will appear with `isReachable: false`.
@@ -1029,84 +1029,6 @@ async function isAsyncMode(publicClient, vault) {
1029
1029
  });
1030
1030
  return !oraclesEnabled;
1031
1031
  }
1032
- var OMNI_FACTORY_ADDRESS = "0x7bDB8B17604b03125eFAED33cA0c55FBf856BB0C";
1033
- var FACTORY_ABI = [
1034
- {
1035
- name: "localEid",
1036
- type: "function",
1037
- inputs: [],
1038
- outputs: [{ type: "uint32" }],
1039
- stateMutability: "view"
1040
- },
1041
- {
1042
- name: "isCrossChainVault",
1043
- type: "function",
1044
- inputs: [{ name: "__eid", type: "uint32" }, { name: "_vault", type: "address" }],
1045
- outputs: [{ type: "bool" }],
1046
- stateMutability: "view"
1047
- },
1048
- {
1049
- name: "hubToSpokes",
1050
- type: "function",
1051
- inputs: [{ name: "__eid", type: "uint32" }, { name: "_hubVault", type: "address" }],
1052
- outputs: [{ name: "eids", type: "uint32[]" }, { name: "vaults", type: "address[]" }],
1053
- stateMutability: "view"
1054
- },
1055
- {
1056
- name: "spokeToHub",
1057
- type: "function",
1058
- inputs: [{ name: "__eid", type: "uint32" }, { name: "_spokeVault", type: "address" }],
1059
- outputs: [{ name: "eid", type: "uint32" }, { name: "vault", type: "address" }],
1060
- stateMutability: "view"
1061
- }
1062
- ];
1063
- async function getVaultTopology(publicClient, vault, factoryAddress = OMNI_FACTORY_ADDRESS) {
1064
- const v = getAddress(vault);
1065
- const f = getAddress(factoryAddress);
1066
- const localEid = await publicClient.readContract({
1067
- address: f,
1068
- abi: FACTORY_ABI,
1069
- functionName: "localEid"
1070
- });
1071
- const isHub = await publicClient.readContract({
1072
- address: f,
1073
- abi: FACTORY_ABI,
1074
- functionName: "isCrossChainVault",
1075
- args: [localEid, v]
1076
- });
1077
- if (isHub) {
1078
- const [spokeEids] = await publicClient.readContract({
1079
- address: f,
1080
- abi: FACTORY_ABI,
1081
- functionName: "hubToSpokes",
1082
- args: [localEid, v]
1083
- });
1084
- const localChainId2 = EID_TO_CHAIN_ID[localEid] ?? Number(publicClient.chain?.id ?? 0);
1085
- const spokeChainIds = spokeEids.map((eid) => EID_TO_CHAIN_ID[eid]).filter((id) => id !== void 0);
1086
- return { role: "hub", hubChainId: localChainId2, spokeChainIds };
1087
- }
1088
- const [hubEid, hubVault] = await publicClient.readContract({
1089
- address: f,
1090
- abi: FACTORY_ABI,
1091
- functionName: "spokeToHub",
1092
- args: [localEid, v]
1093
- });
1094
- if (hubEid !== 0 && hubVault !== "0x0000000000000000000000000000000000000000") {
1095
- const hubChainId = EID_TO_CHAIN_ID[hubEid] ?? 0;
1096
- const spokeChainIds = [];
1097
- const localChainId2 = EID_TO_CHAIN_ID[localEid];
1098
- if (localChainId2 !== void 0) spokeChainIds.push(localChainId2);
1099
- return { role: "spoke", hubChainId, spokeChainIds };
1100
- }
1101
- const localChainId = EID_TO_CHAIN_ID[localEid] ?? Number(publicClient.chain?.id ?? 0);
1102
- return { role: "local", hubChainId: localChainId, spokeChainIds: [] };
1103
- }
1104
- function isOnHubChain(currentChainId, topology) {
1105
- return currentChainId === topology.hubChainId;
1106
- }
1107
- function getAllVaultChainIds(topology) {
1108
- return [topology.hubChainId, ...topology.spokeChainIds];
1109
- }
1110
1032
  var PUBLIC_RPCS = {
1111
1033
  1: [
1112
1034
  "https://ethereum-rpc.publicnode.com",
@@ -1297,6 +1219,144 @@ async function getUserBalancesForRoutes(routes, userAddress) {
1297
1219
  );
1298
1220
  }
1299
1221
 
1222
+ // src/viem/topology.ts
1223
+ var OMNI_FACTORY_ADDRESS = "0x7bDB8B17604b03125eFAED33cA0c55FBf856BB0C";
1224
+ var FACTORY_ABI = [
1225
+ {
1226
+ name: "localEid",
1227
+ type: "function",
1228
+ inputs: [],
1229
+ outputs: [{ type: "uint32" }],
1230
+ stateMutability: "view"
1231
+ },
1232
+ {
1233
+ name: "isCrossChainVault",
1234
+ type: "function",
1235
+ inputs: [{ name: "__eid", type: "uint32" }, { name: "_vault", type: "address" }],
1236
+ outputs: [{ type: "bool" }],
1237
+ stateMutability: "view"
1238
+ },
1239
+ {
1240
+ name: "hubToSpokes",
1241
+ type: "function",
1242
+ inputs: [{ name: "__eid", type: "uint32" }, { name: "_hubVault", type: "address" }],
1243
+ outputs: [{ name: "eids", type: "uint32[]" }, { name: "vaults", type: "address[]" }],
1244
+ stateMutability: "view"
1245
+ },
1246
+ {
1247
+ name: "spokeToHub",
1248
+ type: "function",
1249
+ inputs: [{ name: "__eid", type: "uint32" }, { name: "_spokeVault", type: "address" }],
1250
+ outputs: [{ name: "eid", type: "uint32" }, { name: "vault", type: "address" }],
1251
+ stateMutability: "view"
1252
+ }
1253
+ ];
1254
+ async function getVaultTopology(publicClient, vault, factoryAddress = OMNI_FACTORY_ADDRESS) {
1255
+ const v = getAddress(vault);
1256
+ const f = getAddress(factoryAddress);
1257
+ const localEid = await publicClient.readContract({
1258
+ address: f,
1259
+ abi: FACTORY_ABI,
1260
+ functionName: "localEid"
1261
+ });
1262
+ const isHub = await publicClient.readContract({
1263
+ address: f,
1264
+ abi: FACTORY_ABI,
1265
+ functionName: "isCrossChainVault",
1266
+ args: [localEid, v]
1267
+ });
1268
+ if (isHub) {
1269
+ const [spokeEids] = await publicClient.readContract({
1270
+ address: f,
1271
+ abi: FACTORY_ABI,
1272
+ functionName: "hubToSpokes",
1273
+ args: [localEid, v]
1274
+ });
1275
+ const localChainId2 = EID_TO_CHAIN_ID[localEid] ?? Number(publicClient.chain?.id ?? 0);
1276
+ const spokeChainIds = spokeEids.map((eid) => EID_TO_CHAIN_ID[eid]).filter((id) => id !== void 0);
1277
+ return { role: "hub", hubChainId: localChainId2, spokeChainIds };
1278
+ }
1279
+ const [hubEid, hubVault] = await publicClient.readContract({
1280
+ address: f,
1281
+ abi: FACTORY_ABI,
1282
+ functionName: "spokeToHub",
1283
+ args: [localEid, v]
1284
+ });
1285
+ if (hubEid !== 0 && hubVault !== "0x0000000000000000000000000000000000000000") {
1286
+ const hubChainId = EID_TO_CHAIN_ID[hubEid] ?? 0;
1287
+ const spokeChainIds = [];
1288
+ const localChainId2 = EID_TO_CHAIN_ID[localEid];
1289
+ if (localChainId2 !== void 0) spokeChainIds.push(localChainId2);
1290
+ return { role: "spoke", hubChainId, spokeChainIds };
1291
+ }
1292
+ const localChainId = EID_TO_CHAIN_ID[localEid] ?? Number(publicClient.chain?.id ?? 0);
1293
+ return { role: "local", hubChainId: localChainId, spokeChainIds: [] };
1294
+ }
1295
+ async function getFullVaultTopology(hubChainClient, vault, factoryAddress = OMNI_FACTORY_ADDRESS) {
1296
+ const topo = await getVaultTopology(hubChainClient, vault, factoryAddress);
1297
+ if (topo.role !== "hub") {
1298
+ throw new Error(
1299
+ `getFullVaultTopology: client must be connected to the hub chain (${topo.hubChainId}), but got role="${topo.role}". Connect to chainId ${topo.hubChainId} instead.`
1300
+ );
1301
+ }
1302
+ return topo;
1303
+ }
1304
+ var DISCOVERY_CHAIN_IDS = Object.values(CHAIN_IDS).filter(
1305
+ (id) => id !== 545
1306
+ // exclude testnet
1307
+ );
1308
+ async function discoverVaultTopology(vault, publicClient, factoryAddress = OMNI_FACTORY_ADDRESS) {
1309
+ const v = getAddress(vault);
1310
+ let triedChainId;
1311
+ if (publicClient) {
1312
+ try {
1313
+ const topo = await getVaultTopology(publicClient, v, factoryAddress);
1314
+ if (topo.role !== "local") {
1315
+ if (topo.role === "spoke") {
1316
+ const hubClient = createChainClient(topo.hubChainId);
1317
+ if (hubClient) {
1318
+ try {
1319
+ return await getFullVaultTopology(hubClient, v, factoryAddress);
1320
+ } catch {
1321
+ }
1322
+ }
1323
+ }
1324
+ return topo;
1325
+ }
1326
+ triedChainId = publicClient.chain?.id;
1327
+ } catch {
1328
+ }
1329
+ }
1330
+ for (const chainId of DISCOVERY_CHAIN_IDS) {
1331
+ if (chainId === triedChainId) continue;
1332
+ const client = createChainClient(chainId);
1333
+ if (!client) continue;
1334
+ try {
1335
+ const topo = await getVaultTopology(client, v, factoryAddress);
1336
+ if (topo.role === "hub") return topo;
1337
+ if (topo.role === "spoke") {
1338
+ const hubClient = createChainClient(topo.hubChainId);
1339
+ if (hubClient) {
1340
+ try {
1341
+ return await getFullVaultTopology(hubClient, v, factoryAddress);
1342
+ } catch {
1343
+ return topo;
1344
+ }
1345
+ }
1346
+ return topo;
1347
+ }
1348
+ } catch {
1349
+ }
1350
+ }
1351
+ return { role: "local", hubChainId: 0, spokeChainIds: [] };
1352
+ }
1353
+ function isOnHubChain(currentChainId, topology) {
1354
+ return currentChainId === topology.hubChainId;
1355
+ }
1356
+ function getAllVaultChainIds(topology) {
1357
+ return [topology.hubChainId, ...topology.spokeChainIds];
1358
+ }
1359
+
1300
1360
  // src/viem/preflight.ts
1301
1361
  async function preflightAsync(publicClient, vault, escrow) {
1302
1362
  const v = getAddress(vault);
@@ -1785,9 +1845,14 @@ function useVaultTopology(vault, factoryAddress = OMNI_FACTORY_ADDRESS) {
1785
1845
  const currentChainId = useChainId();
1786
1846
  const publicClient = usePublicClient();
1787
1847
  const { data: topology, isLoading } = useQuery({
1788
- queryKey: ["vaultTopology", vault, currentChainId, factoryAddress],
1789
- queryFn: () => getVaultTopology(asSdkClient(publicClient), vault, factoryAddress),
1790
- enabled: !!vault && !!publicClient,
1848
+ // Key does NOT include currentChainId — topology is chain-independent
1849
+ queryKey: ["vaultTopology", vault, factoryAddress],
1850
+ queryFn: () => discoverVaultTopology(
1851
+ vault,
1852
+ publicClient ? asSdkClient(publicClient) : null,
1853
+ factoryAddress
1854
+ ),
1855
+ enabled: !!vault,
1791
1856
  staleTime: 5 * 60 * 1e3
1792
1857
  // topology rarely changes — 5 min cache
1793
1858
  });
@@ -1972,9 +2037,12 @@ function useRedeemShares(vault, chainId) {
1972
2037
  };
1973
2038
  }
1974
2039
  function useVaultDistribution(vault) {
1975
- const chainId = useChainId();
1976
- const publicClient = usePublicClient();
1977
- const { topology } = useVaultTopology(vault);
2040
+ const { data: topology } = useQuery({
2041
+ queryKey: ["vaultTopology", vault],
2042
+ queryFn: () => discoverVaultTopology(vault),
2043
+ enabled: !!vault,
2044
+ staleTime: 5 * 60 * 1e3
2045
+ });
1978
2046
  const spokeClients = useMemo(() => {
1979
2047
  if (!topology) return {};
1980
2048
  const clients = {};
@@ -1985,13 +2053,13 @@ function useVaultDistribution(vault) {
1985
2053
  return clients;
1986
2054
  }, [topology]);
1987
2055
  const { data: distribution, isLoading } = useQuery({
1988
- queryKey: ["vaultDistribution", vault, chainId],
1989
- queryFn: () => getVaultDistribution(
1990
- asSdkClient(publicClient),
1991
- vault,
1992
- spokeClients
1993
- ),
1994
- enabled: !!vault && !!publicClient,
2056
+ queryKey: ["vaultDistribution", vault, topology?.hubChainId],
2057
+ queryFn: () => {
2058
+ const hubClient = createChainClient(topology.hubChainId);
2059
+ if (!hubClient) throw new Error(`No public RPC for hub chainId ${topology.hubChainId}`);
2060
+ return getVaultDistribution(hubClient, vault, spokeClients);
2061
+ },
2062
+ enabled: !!vault && !!topology && topology.role !== "local",
1995
2063
  staleTime: 3e4
1996
2064
  });
1997
2065
  return { distribution, isLoading };