@sherwoodagent/cli 0.72.0 → 0.73.1

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.
Files changed (61) hide show
  1. package/dist/{addresses-HJDYFLWZ.js → addresses-YDPUPGWQ.js} +3 -3
  2. package/dist/{agent-6OJKQVEG.js → agent-6IRZUPFT.js} +6 -6
  3. package/dist/{chat-2DKD3QPA.js → chat-ONGVCWAP.js} +9 -9
  4. package/dist/{chunk-6SRIVGAV.js → chunk-3NMJ4LUL.js} +4 -4
  5. package/dist/{chunk-OZLX666C.js → chunk-52U76TRE.js} +2 -2
  6. package/dist/{chunk-SVSJNZ5D.js → chunk-D4SPHYXA.js} +4 -4
  7. package/dist/{chunk-ASF2WTSW.js → chunk-FOAX5PGR.js} +4 -4
  8. package/dist/{chunk-GT3KCKF6.js → chunk-FOS47623.js} +9 -6
  9. package/dist/chunk-FOS47623.js.map +1 -0
  10. package/dist/{chunk-RNASYOQT.js → chunk-HYUUR6SC.js} +2 -2
  11. package/dist/chunk-HYUUR6SC.js.map +1 -0
  12. package/dist/{chunk-ITZT5HD4.js → chunk-NWY2U753.js} +2 -2
  13. package/dist/{chunk-YLYANZMC.js → chunk-RAITRCM7.js} +2 -2
  14. package/dist/{chunk-PDUGL4EY.js → chunk-S6XA7PK4.js} +22 -4
  15. package/dist/chunk-S6XA7PK4.js.map +1 -0
  16. package/dist/{chunk-3YUMQGJD.js → chunk-UUHWD7Y3.js} +4 -4
  17. package/dist/{chunk-UC5RMCB3.js → chunk-WECQ6NVS.js} +2 -2
  18. package/dist/{chunk-ZYXFKVYF.js → chunk-XDGCHURW.js} +17 -1
  19. package/dist/chunk-XDGCHURW.js.map +1 -0
  20. package/dist/{client-K4JCNPVV.js → client-QN6SA76M.js} +3 -3
  21. package/dist/{eas-ZXGUNYC5.js → eas-HM2AUOEY.js} +5 -5
  22. package/dist/{governor-CV5PITE3.js → governor-RRBTDGDX.js} +9 -5
  23. package/dist/index.js +132 -61
  24. package/dist/index.js.map +1 -1
  25. package/dist/{ipfs-VGWTUORE.js → ipfs-RWSTXTZM.js} +4 -2
  26. package/dist/{network-DHWEYXP2.js → network-L6JKNYOJ.js} +2 -2
  27. package/dist/{price-GOX6P4NT.js → price-AJ4JMHCT.js} +4 -4
  28. package/dist/{research-6D7NNJX4.js → research-2AFNVV7X.js} +8 -8
  29. package/dist/{research-EFNVHU7G.js → research-7Z6SFPPX.js} +4 -4
  30. package/dist/{session-LDLW66K3.js → session-6FMZMPCE.js} +10 -10
  31. package/dist/{trade-7NNZXP5B.js → trade-YTGLGCRQ.js} +14 -14
  32. package/dist/{vault-SIL4QL5U.js → vault-NIPA5JV4.js} +5 -5
  33. package/dist/{xmtp-QNOVDLXX.js → xmtp-M32JSE4I.js} +6 -6
  34. package/package.json +1 -1
  35. package/dist/chunk-GT3KCKF6.js.map +0 -1
  36. package/dist/chunk-PDUGL4EY.js.map +0 -1
  37. package/dist/chunk-RNASYOQT.js.map +0 -1
  38. package/dist/chunk-ZYXFKVYF.js.map +0 -1
  39. /package/dist/{addresses-HJDYFLWZ.js.map → addresses-YDPUPGWQ.js.map} +0 -0
  40. /package/dist/{agent-6OJKQVEG.js.map → agent-6IRZUPFT.js.map} +0 -0
  41. /package/dist/{chat-2DKD3QPA.js.map → chat-ONGVCWAP.js.map} +0 -0
  42. /package/dist/{chunk-6SRIVGAV.js.map → chunk-3NMJ4LUL.js.map} +0 -0
  43. /package/dist/{chunk-OZLX666C.js.map → chunk-52U76TRE.js.map} +0 -0
  44. /package/dist/{chunk-SVSJNZ5D.js.map → chunk-D4SPHYXA.js.map} +0 -0
  45. /package/dist/{chunk-ASF2WTSW.js.map → chunk-FOAX5PGR.js.map} +0 -0
  46. /package/dist/{chunk-ITZT5HD4.js.map → chunk-NWY2U753.js.map} +0 -0
  47. /package/dist/{chunk-YLYANZMC.js.map → chunk-RAITRCM7.js.map} +0 -0
  48. /package/dist/{chunk-3YUMQGJD.js.map → chunk-UUHWD7Y3.js.map} +0 -0
  49. /package/dist/{chunk-UC5RMCB3.js.map → chunk-WECQ6NVS.js.map} +0 -0
  50. /package/dist/{client-K4JCNPVV.js.map → client-QN6SA76M.js.map} +0 -0
  51. /package/dist/{eas-ZXGUNYC5.js.map → eas-HM2AUOEY.js.map} +0 -0
  52. /package/dist/{governor-CV5PITE3.js.map → governor-RRBTDGDX.js.map} +0 -0
  53. /package/dist/{ipfs-VGWTUORE.js.map → ipfs-RWSTXTZM.js.map} +0 -0
  54. /package/dist/{network-DHWEYXP2.js.map → network-L6JKNYOJ.js.map} +0 -0
  55. /package/dist/{price-GOX6P4NT.js.map → price-AJ4JMHCT.js.map} +0 -0
  56. /package/dist/{research-6D7NNJX4.js.map → research-2AFNVV7X.js.map} +0 -0
  57. /package/dist/{research-EFNVHU7G.js.map → research-7Z6SFPPX.js.map} +0 -0
  58. /package/dist/{session-LDLW66K3.js.map → session-6FMZMPCE.js.map} +0 -0
  59. /package/dist/{trade-7NNZXP5B.js.map → trade-YTGLGCRQ.js.map} +0 -0
  60. /package/dist/{vault-SIL4QL5U.js.map → vault-NIPA5JV4.js.map} +0 -0
  61. /package/dist/{xmtp-QNOVDLXX.js.map → xmtp-M32JSE4I.js.map} +0 -0
@@ -18,8 +18,8 @@ import {
18
18
  isRobinhoodEquityFeed,
19
19
  robinhoodEquityMaxAge,
20
20
  symbolForTokenAddress
21
- } from "./chunk-YLYANZMC.js";
22
- import "./chunk-RNASYOQT.js";
21
+ } from "./chunk-RAITRCM7.js";
22
+ import "./chunk-HYUUR6SC.js";
23
23
  import "./chunk-GSC7PVEO.js";
24
24
  export {
25
25
  AERODROME,
@@ -42,4 +42,4 @@ export {
42
42
  robinhoodEquityMaxAge,
43
43
  symbolForTokenAddress
44
44
  };
45
- //# sourceMappingURL=addresses-HJDYFLWZ.js.map
45
+ //# sourceMappingURL=addresses-YDPUPGWQ.js.map
@@ -12,7 +12,7 @@ import {
12
12
  import {
13
13
  getResearchProvider,
14
14
  isX402WalletFunded
15
- } from "./chunk-ITZT5HD4.js";
15
+ } from "./chunk-NWY2U753.js";
16
16
  import {
17
17
  HyperliquidProvider,
18
18
  calculateATR,
@@ -29,9 +29,9 @@ import {
29
29
  } from "./chunk-DBOINZYU.js";
30
30
  import {
31
31
  chatCompletion
32
- } from "./chunk-OZLX666C.js";
33
- import "./chunk-UC5RMCB3.js";
34
- import "./chunk-RNASYOQT.js";
32
+ } from "./chunk-52U76TRE.js";
33
+ import "./chunk-WECQ6NVS.js";
34
+ import "./chunk-HYUUR6SC.js";
35
35
  import {
36
36
  getVeniceApiKey
37
37
  } from "./chunk-GSC7PVEO.js";
@@ -5573,7 +5573,7 @@ var PortfolioTracker = class {
5573
5573
  }
5574
5574
  try {
5575
5575
  const { createPublicClient, http } = await import("viem");
5576
- const { getChain } = await import("./network-DHWEYXP2.js");
5576
+ const { getChain } = await import("./network-L6JKNYOJ.js");
5577
5577
  const { BASE_STRATEGY_ABI, SYNDICATE_VAULT_ABI } = await import("./abis-KP7M4IPM.js");
5578
5578
  void chain;
5579
5579
  const client = createPublicClient({
@@ -9550,4 +9550,4 @@ function formatFearGreed(value) {
9550
9550
  export {
9551
9551
  registerAgentCommands
9552
9552
  };
9553
- //# sourceMappingURL=agent-6OJKQVEG.js.map
9553
+ //# sourceMappingURL=agent-6IRZUPFT.js.map
@@ -1,21 +1,21 @@
1
1
  import {
2
2
  getFund,
3
3
  updateMetadata
4
- } from "./chunk-6SRIVGAV.js";
4
+ } from "./chunk-3NMJ4LUL.js";
5
5
  import {
6
6
  getTextRecord,
7
7
  resolveFund,
8
8
  setTextRecord
9
- } from "./chunk-GT3KCKF6.js";
10
- import "./chunk-3YUMQGJD.js";
9
+ } from "./chunk-FOS47623.js";
10
+ import "./chunk-UUHWD7Y3.js";
11
11
  import {
12
12
  ENS
13
- } from "./chunk-YLYANZMC.js";
13
+ } from "./chunk-RAITRCM7.js";
14
14
  import {
15
15
  formatContractError,
16
16
  getAccount
17
- } from "./chunk-UC5RMCB3.js";
18
- import "./chunk-RNASYOQT.js";
17
+ } from "./chunk-WECQ6NVS.js";
18
+ import "./chunk-HYUUR6SC.js";
19
19
  import {
20
20
  cacheGroupId,
21
21
  getCachedGroupId
@@ -24,13 +24,13 @@ import "./chunk-BQMOE4FJ.js";
24
24
  import {
25
25
  fetchMetadata,
26
26
  uploadMetadata
27
- } from "./chunk-ZYXFKVYF.js";
27
+ } from "./chunk-XDGCHURW.js";
28
28
 
29
29
  // src/commands/chat.ts
30
30
  import chalk from "chalk";
31
31
  import ora from "ora";
32
32
  async function loadXmtp() {
33
- return import("./xmtp-QNOVDLXX.js");
33
+ return import("./xmtp-M32JSE4I.js");
34
34
  }
35
35
  function formatTimestamp(date) {
36
36
  return `${date.getHours().toString().padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}`;
@@ -564,4 +564,4 @@ function registerChatCommands(program) {
564
564
  export {
565
565
  registerChatCommands
566
566
  };
567
- //# sourceMappingURL=chat-2DKD3QPA.js.map
567
+ //# sourceMappingURL=chat-ONGVCWAP.js.map
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  SHERWOOD
3
- } from "./chunk-YLYANZMC.js";
3
+ } from "./chunk-RAITRCM7.js";
4
4
  import {
5
5
  getAccount,
6
6
  getPublicClient,
7
7
  waitForReceipt,
8
8
  writeContractWithRetry
9
- } from "./chunk-UC5RMCB3.js";
9
+ } from "./chunk-WECQ6NVS.js";
10
10
  import {
11
11
  getChain
12
- } from "./chunk-RNASYOQT.js";
12
+ } from "./chunk-HYUUR6SC.js";
13
13
  import {
14
14
  SYNDICATE_FACTORY_ABI
15
15
  } from "./chunk-BQMOE4FJ.js";
@@ -144,4 +144,4 @@ export {
144
144
  getActiveFunds,
145
145
  updateMetadata
146
146
  };
147
- //# sourceMappingURL=chunk-6SRIVGAV.js.map
147
+ //# sourceMappingURL=chunk-3NMJ4LUL.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getAccount
3
- } from "./chunk-UC5RMCB3.js";
3
+ } from "./chunk-WECQ6NVS.js";
4
4
  import {
5
5
  getVeniceApiKey,
6
6
  setVeniceApiKey
@@ -186,4 +186,4 @@ export {
186
186
  chatCompletion,
187
187
  listModels
188
188
  };
189
- //# sourceMappingURL=chunk-OZLX666C.js.map
189
+ //# sourceMappingURL=chunk-52U76TRE.js.map
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  UNISWAP
3
- } from "./chunk-YLYANZMC.js";
3
+ } from "./chunk-RAITRCM7.js";
4
4
  import {
5
5
  getAccount,
6
6
  getPublicClient,
7
7
  sendTxWithRetry,
8
8
  waitForReceipt
9
- } from "./chunk-UC5RMCB3.js";
9
+ } from "./chunk-WECQ6NVS.js";
10
10
  import {
11
11
  getChain
12
- } from "./chunk-RNASYOQT.js";
12
+ } from "./chunk-HYUUR6SC.js";
13
13
  import {
14
14
  getUniswapApiKey
15
15
  } from "./chunk-GSC7PVEO.js";
@@ -322,4 +322,4 @@ export {
322
322
  encodeSwapPath,
323
323
  getMultiHopQuote
324
324
  };
325
- //# sourceMappingURL=chunk-SVSJNZ5D.js.map
325
+ //# sourceMappingURL=chunk-D4SPHYXA.js.map
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  EAS_CONTRACTS,
3
3
  EAS_SCHEMAS
4
- } from "./chunk-YLYANZMC.js";
4
+ } from "./chunk-RAITRCM7.js";
5
5
  import {
6
6
  getAccount,
7
7
  getPublicClient,
8
8
  waitForReceipt,
9
9
  writeContractWithRetry
10
- } from "./chunk-UC5RMCB3.js";
10
+ } from "./chunk-WECQ6NVS.js";
11
11
  import {
12
12
  CHAIN_REGISTRY,
13
13
  getChain,
@@ -15,7 +15,7 @@ import {
15
15
  getNetwork,
16
16
  isTestnet,
17
17
  withNetwork
18
- } from "./chunk-RNASYOQT.js";
18
+ } from "./chunk-HYUUR6SC.js";
19
19
  import {
20
20
  EAS_ABI
21
21
  } from "./chunk-BQMOE4FJ.js";
@@ -453,4 +453,4 @@ export {
453
453
  queryApprovals,
454
454
  queryJoinRequests
455
455
  };
456
- //# sourceMappingURL=chunk-ASF2WTSW.js.map
456
+ //# sourceMappingURL=chunk-FOAX5PGR.js.map
@@ -1,18 +1,18 @@
1
1
  import {
2
2
  executeBatch,
3
3
  setVaultAddress
4
- } from "./chunk-3YUMQGJD.js";
4
+ } from "./chunk-UUHWD7Y3.js";
5
5
  import {
6
6
  ENS,
7
7
  SHERWOOD
8
- } from "./chunk-YLYANZMC.js";
8
+ } from "./chunk-RAITRCM7.js";
9
9
  import {
10
10
  getPublicClient
11
- } from "./chunk-UC5RMCB3.js";
11
+ } from "./chunk-WECQ6NVS.js";
12
12
  import {
13
13
  VALID_NETWORKS,
14
14
  withNetwork
15
- } from "./chunk-RNASYOQT.js";
15
+ } from "./chunk-HYUUR6SC.js";
16
16
  import {
17
17
  L2_REGISTRY_ABI,
18
18
  SYNDICATE_FACTORY_ABI
@@ -22,6 +22,7 @@ import {
22
22
  import { encodeFunctionData } from "viem";
23
23
  import { namehash } from "viem/ens";
24
24
  var ENS_DOMAIN = "sherwoodagent.eth";
25
+ var ZERO = "0x0000000000000000000000000000000000000000";
25
26
  function getFactoryAddress() {
26
27
  return SHERWOOD().FACTORY;
27
28
  }
@@ -104,10 +105,12 @@ async function setTextRecord(subdomain, key, value, vaultAddress) {
104
105
  );
105
106
  }
106
107
  async function getTextRecord(subdomain, key) {
108
+ const registry = ENS().L2_REGISTRY;
109
+ if (registry.toLowerCase() === ZERO.toLowerCase()) return "";
107
110
  const client = getPublicClient();
108
111
  const node = getSubdomainNode(subdomain);
109
112
  return client.readContract({
110
- address: ENS().L2_REGISTRY,
113
+ address: registry,
111
114
  abi: L2_REGISTRY_ABI,
112
115
  functionName: "text",
113
116
  args: [node, key]
@@ -121,4 +124,4 @@ export {
121
124
  setTextRecord,
122
125
  getTextRecord
123
126
  };
124
- //# sourceMappingURL=chunk-GT3KCKF6.js.map
127
+ //# sourceMappingURL=chunk-FOS47623.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/ens.ts"],"sourcesContent":["/**\n * ENS resolution + text records via Durin L2Registry on Base.\n *\n * Two responsibilities:\n * 1. Resolve fund subdomain → on-chain fund data (via factory)\n * 2. Read/write ENS text records (via L2Registry, routed through vault's executeBatch)\n *\n * The vault owns the ENS subdomain node (registered in the factory via\n * `ensRegistrar.register(subdomain, vault)`). Only the vault can write text\n * records. We route writes through vault.executeBatch → L2Registry.setText,\n * which executes as the vault via delegatecall to the shared executor lib.\n */\n\nimport { encodeFunctionData } from \"viem\";\nimport type { Address, Hex } from \"viem\";\nimport { namehash } from \"viem/ens\";\nimport { getPublicClient, getWalletClient, getAccount, waitForReceipt } from \"./client.js\";\nimport {\n getChain,\n getNetwork,\n withNetwork,\n VALID_NETWORKS,\n type Network,\n} from \"./network.js\";\nimport { SYNDICATE_FACTORY_ABI, L2_REGISTRY_ABI } from \"./abis.js\";\nimport { ENS, SHERWOOD } from \"./addresses.js\";\nimport * as vaultLib from \"./vault.js\";\n\n/**\n * Wait for a transaction to be mined before proceeding.\n */\nasync function waitForTx(hash: Hex): Promise<void> {\n await waitForReceipt(hash);\n}\n\nconst ENS_DOMAIN = \"sherwoodagent.eth\";\n\n/** Sentinel for \"no ENS registry deployed on this chain\" (e.g. Robinhood testnet). */\nconst ZERO: Address = \"0x0000000000000000000000000000000000000000\";\n\nfunction getFactoryAddress(): Address {\n return SHERWOOD().FACTORY;\n}\n\n// ── Fund Resolution (via factory) ──\n\nexport interface FundResolution {\n id: bigint;\n vault: Address;\n creator: Address;\n subdomain: string;\n}\n\n/**\n * Resolve a fund subdomain to its on-chain data.\n * Uses factory.subdomainToSyndicate() → factory.syndicates().\n */\nexport async function resolveFund(subdomain: string): Promise<FundResolution> {\n const client = getPublicClient();\n const factory = getFactoryAddress();\n\n // Get fund ID from subdomain\n const fundId = (await client.readContract({\n address: factory,\n abi: SYNDICATE_FACTORY_ABI,\n functionName: \"subdomainToSyndicate\",\n args: [subdomain],\n })) as bigint;\n\n if (fundId === 0n) {\n throw new Error(`Fund \"${subdomain}\" not found`);\n }\n\n // Get full fund record\n const result = (await client.readContract({\n address: factory,\n abi: SYNDICATE_FACTORY_ABI,\n functionName: \"syndicates\",\n args: [fundId],\n })) as [bigint, Address, Address, string, bigint, boolean, string];\n\n return {\n id: result[0],\n vault: result[1],\n creator: result[2],\n subdomain: result[6],\n };\n}\n\n/**\n * Probe every supported chain for a subdomain registration. Returns every hit —\n * most queries find zero or one, but post-CREATE3 the same subdomain may exist\n * on multiple chains and the caller needs to disambiguate. RPC errors on\n * individual chains are swallowed so a flaky chain doesn't fail the whole\n * search. The current deployment target is a single (ungated) chain, so this\n * iterates VALID_NETWORKS directly.\n */\nexport async function searchFundAcrossChains(\n subdomain: string,\n): Promise<{ network: Network; result: FundResolution }[]> {\n const candidates = VALID_NETWORKS;\n\n const hits: { network: Network; result: FundResolution }[] = [];\n for (const net of candidates) {\n try {\n const result = await withNetwork(net, () => resolveFund(subdomain));\n hits.push({ network: net, result });\n } catch {\n // Not registered on this chain, or RPC failed — keep searching.\n }\n }\n return hits;\n}\n\n/**\n * Reverse lookup: vault address → fund info.\n * Uses factory.vaultToSyndicate() → factory.syndicates().\n */\nexport async function resolveVaultFund(\n vaultAddress: Address,\n): Promise<FundResolution> {\n const client = getPublicClient();\n const factory = getFactoryAddress();\n\n const fundId = (await client.readContract({\n address: factory,\n abi: SYNDICATE_FACTORY_ABI,\n functionName: \"vaultToSyndicate\",\n args: [vaultAddress],\n })) as bigint;\n\n if (fundId === 0n) {\n throw new Error(`No fund found for vault ${vaultAddress}`);\n }\n\n const result = (await client.readContract({\n address: factory,\n abi: SYNDICATE_FACTORY_ABI,\n functionName: \"syndicates\",\n args: [fundId],\n })) as [bigint, Address, Address, string, bigint, boolean, string];\n\n return {\n id: result[0],\n vault: result[1],\n creator: result[2],\n subdomain: result[6],\n };\n}\n\n// ── ENS Text Records (via L2Registry) ──\n\n/**\n * Compute the ENS node hash for a subdomain under sherwoodagent.eth.\n */\nfunction getSubdomainNode(subdomain: string): Hex {\n return namehash(`${subdomain}.${ENS_DOMAIN}`);\n}\n\n/**\n * Write a text record to the L2Registry via the vault's executeBatch.\n *\n * The vault owns the ENS node, so only the vault can call setText.\n * We route the call through vault.executeBatch (delegatecall → executor lib → L2Registry),\n * which means L2Registry sees msg.sender = vault address.\n *\n * Requires the caller to be a registered agent on the vault (creator is auto-registered).\n */\nexport async function setTextRecord(\n subdomain: string,\n key: string,\n value: string,\n vaultAddress: Address,\n): Promise<Hex> {\n const l2Registry = ENS().L2_REGISTRY;\n const node = getSubdomainNode(subdomain);\n\n vaultLib.setVaultAddress(vaultAddress);\n\n // Encode the L2Registry.setText call\n const setTextData = encodeFunctionData({\n abi: L2_REGISTRY_ABI,\n functionName: \"setText\",\n args: [node, key, value],\n });\n\n // Route through vault.executeBatch (owner only)\n return vaultLib.executeBatch(\n [{ target: l2Registry, data: setTextData, value: 0n }],\n );\n}\n\n/**\n * Read a text record from the L2Registry.\n * Used to look up xmtpGroupId when not cached locally.\n *\n * Chains without a deployed ENS registry (e.g. Robinhood testnet, where\n * `L2_REGISTRY == address(0)`) have no text records — reading `text()` from\n * the zero address makes viem throw `ContractFunctionZeroDataError`. Return\n * \"\" instead so callers (chat init idempotency probe, getGroup ENS fallback)\n * degrade to the cache / name-search paths rather than hard-failing. Every\n * caller already treats \"\" as \"not set\".\n */\nexport async function getTextRecord(\n subdomain: string,\n key: string,\n): Promise<string> {\n const registry = ENS().L2_REGISTRY;\n if (registry.toLowerCase() === ZERO.toLowerCase()) return \"\";\n\n const client = getPublicClient();\n const node = getSubdomainNode(subdomain);\n\n return client.readContract({\n address: registry,\n abi: L2_REGISTRY_ABI,\n functionName: \"text\",\n args: [node, key],\n }) as Promise<string>;\n}\n"],"mappings":"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","names":[]}
@@ -27,7 +27,7 @@ var CHAIN_REGISTRY = {
27
27
  explorerHost: "explorer.testnet.chain.robinhood.com",
28
28
  easGraphqlUrl: null,
29
29
  easScanHost: null,
30
- xmtpEnv: "dev",
30
+ xmtpEnv: "production",
31
31
  isTestnet: true
32
32
  }
33
33
  };
@@ -108,4 +108,4 @@ export {
108
108
  getExplorerUrl,
109
109
  isTestnet
110
110
  };
111
- //# sourceMappingURL=chunk-RNASYOQT.js.map
111
+ //# sourceMappingURL=chunk-HYUUR6SC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/network.ts"],"sourcesContent":["/**\n * Network state singleton.\n *\n * Called once at CLI startup via the --chain flag's preAction hook.\n * Every other module reads from here — never hardcodes a chain.\n *\n * Current deployment target: Robinhood L2 testnet (chain 46630) only. Sherwood\n * launches on Robinhood first; other chains may be added back later, at which\n * point they re-enter the Network union + CHAIN_REGISTRY below.\n */\n\nimport { type Chain, defineChain } from \"viem\";\nimport { getConfigRpcUrl } from \"./config.js\";\n\n// ── Robinhood L2 Testnet (Arbitrum Orbit, chain ID 46630) ──\n\nexport const robinhoodTestnet = defineChain({\n id: 46630,\n name: \"Robinhood Chain Testnet\",\n nativeCurrency: { name: \"Ethereum\", symbol: \"ETH\", decimals: 18 },\n rpcUrls: {\n default: { http: [\"https://rpc.testnet.chain.robinhood.com\"] },\n },\n blockExplorers: {\n default: {\n name: \"Blockscout\",\n url: \"https://explorer.testnet.chain.robinhood.com\",\n },\n },\n testnet: true,\n});\n\n// ── Types ──\n\nexport type Network = \"robinhood-testnet\";\n\nexport interface ChainConfig {\n chain: Chain;\n /**\n * Ordered list of public RPC URLs tried in sequence when no user RPC is set.\n * First entry is the primary; the rest are fallbacks used transparently via\n * viem's `fallback` transport on rate-limit / network errors.\n */\n rpcFallbacks: string[];\n /** Legacy env var for backwards compat (optional per chain) */\n rpcEnvVar?: string;\n explorerHost: string;\n /** EAS GraphQL endpoint — null if EAS is not available on this chain */\n easGraphqlUrl: string | null;\n /** EAS scan host — null if unavailable */\n easScanHost: string | null;\n xmtpEnv: \"production\" | \"dev\";\n isTestnet: boolean;\n}\n\n// ── Chain Registry ──\n\nexport const CHAIN_REGISTRY: Record<Network, ChainConfig> = {\n \"robinhood-testnet\": {\n chain: robinhoodTestnet,\n rpcFallbacks: [\"https://rpc.testnet.chain.robinhood.com\"],\n rpcEnvVar: \"ROBINHOOD_TESTNET_RPC_URL\",\n explorerHost: \"explorer.testnet.chain.robinhood.com\",\n easGraphqlUrl: null,\n easScanHost: null,\n xmtpEnv: \"production\",\n isTestnet: true,\n },\n};\n\nexport const VALID_NETWORKS = Object.keys(CHAIN_REGISTRY) as Network[];\n\nexport const DEFAULT_NETWORK: Network = \"robinhood-testnet\";\n\n// ── Singleton state ──\n\nlet _network: Network = DEFAULT_NETWORK;\n\nexport function setNetwork(n: Network) {\n const config = CHAIN_REGISTRY[n];\n if (!config) {\n throw new Error(\n `Unknown network: ${n}. Valid: ${VALID_NETWORKS.join(\", \")}`,\n );\n }\n _network = n;\n}\n\nexport function getNetwork(): Network {\n return _network;\n}\n\n/**\n * Run `fn` with the network singleton temporarily switched to `network`,\n * restoring the previous network in `finally`.\n *\n * The viem clients (`getPublicClient`, `getWalletClient`) auto-invalidate on\n * chain change, so callers get fresh per-chain RPC + chain context inside the\n * block. Used for cross-chain fund resolution.\n */\nexport async function withNetwork<T>(\n network: Network,\n fn: () => Promise<T>,\n): Promise<T> {\n const previous = _network;\n _network = network;\n try {\n return await fn();\n } finally {\n _network = previous;\n }\n}\n\nexport function getChainConfig(): ChainConfig {\n return CHAIN_REGISTRY[_network];\n}\n\n/**\n * Dev/CI-only chain-id override (`SIM_CHAIN_ID`) for custom-chainId vnet forks.\n * viem asserts the node's chainId matches the chain definition on every write,\n * so signing for such a fork requires the id to be swapped at the source.\n *\n * Interlock: honored ONLY while `SIM_ADDRESSES_FILE` is also set (the vnet\n * e2e harness's address override). A bare SIM_CHAIN_ID does nothing, so this\n * can never redirect signing on a real network run.\n */\nexport function applyChainIdOverride(chain: Chain): Chain {\n const raw = process.env.SIM_CHAIN_ID;\n if (!raw || !process.env.SIM_ADDRESSES_FILE) return chain;\n const id = Number(raw);\n if (!Number.isInteger(id) || id <= 0) return chain;\n return { ...chain, id };\n}\n\nexport function getChain(): Chain {\n return applyChainIdOverride(CHAIN_REGISTRY[_network].chain);\n}\n\n/**\n * Ordered list of RPC URLs to try, deduped:\n * 1. User config (~/.sherwood/config.json) — honored first\n * 2. Legacy env var (ROBINHOOD_TESTNET_RPC_URL)\n * 3. Public fallback list from CHAIN_REGISTRY\n *\n * Fed to viem's `fallback()` transport so rate-limited RPCs transparently\n * advance to the next entry. See issue #182.\n */\nexport function getRpcUrls(): string[] {\n const cfg = CHAIN_REGISTRY[_network];\n const urls: string[] = [];\n\n const fromConfig = getConfigRpcUrl(_network);\n if (fromConfig) urls.push(fromConfig);\n\n if (cfg.rpcEnvVar && process.env[cfg.rpcEnvVar]) {\n urls.push(process.env[cfg.rpcEnvVar]!);\n }\n\n // Vnet harness (SIM_CHAIN_ID + SIM_ADDRESSES_FILE interlock): the fork RPC\n // is the ONLY valid endpoint — the public fallbacks point at the real\n // network. viem's fallback() otherwise rotates there on a vnet hiccup and\n // silently estimates gas/fees against MAINNET state (live finding: an\n // approve estimated at 21.9k gas on mainnet — no code at that address —\n // reverted out-of-gas on the vnet where it needs ~46k). A vnet call must\n // fail loudly, never retarget the real chain.\n if (process.env.SIM_CHAIN_ID && process.env.SIM_ADDRESSES_FILE && urls.length > 0) {\n return Array.from(new Set(urls));\n }\n\n urls.push(...cfg.rpcFallbacks);\n\n return Array.from(new Set(urls));\n}\n\nexport function getRpcUrl(): string {\n return getRpcUrls()[0];\n}\n\nexport function getExplorerUrl(txHash: string): string {\n return `https://${CHAIN_REGISTRY[_network].explorerHost}/tx/${txHash}`;\n}\n\nexport function isTestnet(): boolean {\n return CHAIN_REGISTRY[_network].isTestnet;\n}\n"],"mappings":";;;;;AAWA,SAAqB,mBAAmB;AAKjC,IAAM,mBAAmB,YAAY;AAAA,EAC1C,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,gBAAgB,EAAE,MAAM,YAAY,QAAQ,OAAO,UAAU,GAAG;AAAA,EAChE,SAAS;AAAA,IACP,SAAS,EAAE,MAAM,CAAC,yCAAyC,EAAE;AAAA,EAC/D;AAAA,EACA,gBAAgB;AAAA,IACd,SAAS;AAAA,MACP,MAAM;AAAA,MACN,KAAK;AAAA,IACP;AAAA,EACF;AAAA,EACA,SAAS;AACX,CAAC;AA2BM,IAAM,iBAA+C;AAAA,EAC1D,qBAAqB;AAAA,IACnB,OAAO;AAAA,IACP,cAAc,CAAC,yCAAyC;AAAA,IACxD,WAAW;AAAA,IACX,cAAc;AAAA,IACd,eAAe;AAAA,IACf,aAAa;AAAA,IACb,SAAS;AAAA,IACT,WAAW;AAAA,EACb;AACF;AAEO,IAAM,iBAAiB,OAAO,KAAK,cAAc;AAEjD,IAAM,kBAA2B;AAIxC,IAAI,WAAoB;AAEjB,SAAS,WAAW,GAAY;AACrC,QAAM,SAAS,eAAe,CAAC;AAC/B,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;AAAA,MACR,oBAAoB,CAAC,YAAY,eAAe,KAAK,IAAI,CAAC;AAAA,IAC5D;AAAA,EACF;AACA,aAAW;AACb;AAEO,SAAS,aAAsB;AACpC,SAAO;AACT;AAUA,eAAsB,YACpB,SACA,IACY;AACZ,QAAM,WAAW;AACjB,aAAW;AACX,MAAI;AACF,WAAO,MAAM,GAAG;AAAA,EAClB,UAAE;AACA,eAAW;AAAA,EACb;AACF;AAEO,SAAS,iBAA8B;AAC5C,SAAO,eAAe,QAAQ;AAChC;AAWO,SAAS,qBAAqB,OAAqB;AACxD,QAAM,MAAM,QAAQ,IAAI;AACxB,MAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,mBAAoB,QAAO;AACpD,QAAM,KAAK,OAAO,GAAG;AACrB,MAAI,CAAC,OAAO,UAAU,EAAE,KAAK,MAAM,EAAG,QAAO;AAC7C,SAAO,EAAE,GAAG,OAAO,GAAG;AACxB;AAEO,SAAS,WAAkB;AAChC,SAAO,qBAAqB,eAAe,QAAQ,EAAE,KAAK;AAC5D;AAWO,SAAS,aAAuB;AACrC,QAAM,MAAM,eAAe,QAAQ;AACnC,QAAM,OAAiB,CAAC;AAExB,QAAM,aAAa,gBAAgB,QAAQ;AAC3C,MAAI,WAAY,MAAK,KAAK,UAAU;AAEpC,MAAI,IAAI,aAAa,QAAQ,IAAI,IAAI,SAAS,GAAG;AAC/C,SAAK,KAAK,QAAQ,IAAI,IAAI,SAAS,CAAE;AAAA,EACvC;AASA,MAAI,QAAQ,IAAI,gBAAgB,QAAQ,IAAI,sBAAsB,KAAK,SAAS,GAAG;AACjF,WAAO,MAAM,KAAK,IAAI,IAAI,IAAI,CAAC;AAAA,EACjC;AAEA,OAAK,KAAK,GAAG,IAAI,YAAY;AAE7B,SAAO,MAAM,KAAK,IAAI,IAAI,IAAI,CAAC;AACjC;AAEO,SAAS,YAAoB;AAClC,SAAO,WAAW,EAAE,CAAC;AACvB;AAEO,SAAS,eAAe,QAAwB;AACrD,SAAO,WAAW,eAAe,QAAQ,EAAE,YAAY,OAAO,MAAM;AACtE;AAEO,SAAS,YAAqB;AACnC,SAAO,eAAe,QAAQ,EAAE;AAClC;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getAccount
3
- } from "./chunk-UC5RMCB3.js";
3
+ } from "./chunk-WECQ6NVS.js";
4
4
 
5
5
  // src/providers/research/messari.ts
6
6
  import { base, baseSepolia } from "viem/chains";
@@ -635,4 +635,4 @@ export {
635
635
  NansenProvider,
636
636
  getResearchProvider
637
637
  };
638
- //# sourceMappingURL=chunk-ITZT5HD4.js.map
638
+ //# sourceMappingURL=chunk-NWY2U753.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getNetwork
3
- } from "./chunk-RNASYOQT.js";
3
+ } from "./chunk-HYUUR6SC.js";
4
4
 
5
5
  // src/lib/addresses.ts
6
6
  import { isAddress } from "viem";
@@ -305,4 +305,4 @@ export {
305
305
  SYNTHRA,
306
306
  CHAINLINK
307
307
  };
308
- //# sourceMappingURL=chunk-YLYANZMC.js.map
308
+ //# sourceMappingURL=chunk-RAITRCM7.js.map
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  SHERWOOD
3
- } from "./chunk-YLYANZMC.js";
3
+ } from "./chunk-RAITRCM7.js";
4
4
  import {
5
5
  getAccount,
6
6
  getPublicClient,
7
7
  waitForReceipt,
8
8
  writeContractWithRetry
9
- } from "./chunk-UC5RMCB3.js";
9
+ } from "./chunk-WECQ6NVS.js";
10
10
  import {
11
11
  getChain
12
- } from "./chunk-RNASYOQT.js";
12
+ } from "./chunk-HYUUR6SC.js";
13
13
  import {
14
14
  PROTOCOL_CONFIG_ABI,
15
15
  SYNDICATE_FACTORY_ABI,
@@ -45,6 +45,22 @@ var VOTE_TYPE = {
45
45
  Against: 1,
46
46
  Abstain: 2
47
47
  };
48
+ function evaluateExecuteGate(args) {
49
+ const { state, reviewEnd, executeBy, now } = args;
50
+ if (state === PROPOSAL_STATE.Approved) return { kind: "send" };
51
+ if (state === PROPOSAL_STATE.GuardianReview) {
52
+ if (now <= reviewEnd) return { kind: "refuse-review-open" };
53
+ if (now > executeBy) return { kind: "refuse-expired" };
54
+ return { kind: "send-self-resolve" };
55
+ }
56
+ return { kind: "refuse-state" };
57
+ }
58
+ function classifyReview(args) {
59
+ const { opened, resolved, reviewEnd, now } = args;
60
+ const pastWindow = reviewEnd > 0n && now >= reviewEnd;
61
+ if (!pastWindow || resolved) return "none";
62
+ return opened ? "resolvable" : "cold-start";
63
+ }
48
64
  function parseDuration(input) {
49
65
  const match = input.match(/^(\d+)(d|h|m|s)?$/);
50
66
  if (!match) throw new Error(`Invalid duration: ${input}`);
@@ -374,6 +390,8 @@ export {
374
390
  PROPOSAL_STATES,
375
391
  PROPOSAL_STATE,
376
392
  VOTE_TYPE,
393
+ evaluateExecuteGate,
394
+ classifyReview,
377
395
  parseDuration,
378
396
  getGovernorOf,
379
397
  getProtocolConfigAddress,
@@ -407,4 +425,4 @@ export {
407
425
  vetoProposal,
408
426
  setProtocolFeeBps
409
427
  };
410
- //# sourceMappingURL=chunk-PDUGL4EY.js.map
428
+ //# sourceMappingURL=chunk-S6XA7PK4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/governor.ts"],"sourcesContent":["/**\n * Governor contract wrapper — reads/writes to SyndicateGovernor.\n *\n * Per-vault governor design: the factory deploys ONE governor per vault\n * (BeaconProxy). Every helper takes the vault address and resolves its\n * governor via `factory.governorOf(vault)` (memoized per chain+vault —\n * the binding is set once at createSyndicate and never changes).\n *\n * Protocol-wide fee parameters (protocol/guardian fee bps + recipients)\n * live on the separate ProtocolConfig contract, resolved via\n * `factory.protocolConfig()`.\n */\n\nimport type { Address, Hex, Log } from \"viem\";\nimport { parseEventLogs } from \"viem\";\nimport { getPublicClient, getAccount, writeContractWithRetry, waitForReceipt } from \"./client.js\";\nimport { getChain } from \"./network.js\";\nimport { SHERWOOD } from \"./addresses.js\";\nimport { SYNDICATE_GOVERNOR_ABI, SYNDICATE_FACTORY_ABI, PROTOCOL_CONFIG_ABI } from \"./abis.js\";\n\n// ── Types ──\n\nexport interface GovernorParams {\n votingPeriod: bigint;\n executionWindow: bigint;\n vetoThresholdBps: bigint;\n maxPerformanceFeeBps: bigint;\n cooldownPeriod: bigint;\n collaborationWindow: bigint;\n maxCoProposers: bigint;\n minStrategyDuration: bigint;\n maxStrategyDuration: bigint;\n}\n\nexport interface StrategyProposal {\n id: bigint;\n proposer: Address;\n vault: Address;\n /** Strategy contract address whose `positionValue()` the vault polls\n * for live NAV. Set at propose time, immutable thereafter. address(0)\n * for queue-only proposals (no live NAV). */\n strategy: Address;\n metadataURI: string;\n /** Agent fee (bps) snapshotted from the vault's `agentFeeBps` at propose. */\n performanceFeeBps: bigint;\n strategyDuration: bigint;\n votesFor: bigint;\n votesAgainst: bigint;\n votesAbstain: bigint;\n snapshotTimestamp: bigint;\n voteEnd: bigint;\n reviewEnd: bigint;\n executeBy: bigint;\n executedAt: bigint;\n state: number;\n vetoThresholdBps: bigint;\n /** Fee snapshot taken from ProtocolConfig at propose time (PR #421). These\n * four fields sit between `vetoThresholdBps` and `selfManagesFees` in the\n * on-chain `StrategyProposal` struct — omitting them corrupts tuple decode. */\n snapshotProtocolFeeBps: bigint;\n snapshotProtocolFeeRecipient: Address;\n snapshotGuardianFeeBps: bigint;\n snapshotGuardiansFeeRecipient: Address;\n /** `IStrategy.selfManagesFees()` snapshotted at propose (PR #388 #2); read\n * from storage at settle so it can't flip mid-flight or brick settlement. */\n selfManagesFees: boolean;\n}\n\nexport interface CoProposer {\n agent: Address;\n splitBps: bigint;\n}\n\nexport interface BatchCall {\n target: Address;\n data: Hex;\n value: bigint;\n}\n\n// Must match Solidity ISyndicateGovernor.ProposalState ordering. PR #229\n// inserted GuardianReview at index 2, shifting every subsequent state by\n// one. Without this fix, the CLI mislabels Approved (3) as Rejected,\n// Executed (6) as Settled, etc. — and `proposal execute` rejects valid\n// approved proposals.\nexport const PROPOSAL_STATES = [\n \"Draft\",\n \"Pending\",\n \"GuardianReview\",\n \"Approved\",\n \"Rejected\",\n \"Expired\",\n \"Executed\",\n \"Settled\",\n \"Cancelled\",\n] as const;\n\nexport const PROPOSAL_STATE = {\n Draft: 0,\n Pending: 1,\n GuardianReview: 2,\n Approved: 3,\n Rejected: 4,\n Expired: 5,\n Executed: 6,\n Settled: 7,\n Cancelled: 8,\n} as const;\n\nexport const VOTE_TYPE = {\n For: 0,\n Against: 1,\n Abstain: 2,\n} as const;\n\n// ── Client-side action gates (mirror SyndicateGovernor) ──\n//\n// The governor's mutating entrypoints resolve state INLINE and can act on a\n// state the read-only `getProposalState` view is still reporting as\n// GuardianReview. The client gates below reproduce that divergence so the CLI\n// stops refusing txs the contract would accept (issue #452).\n\n/** Result of the `proposal execute` client gate. */\nexport type ExecuteGate =\n | { kind: \"send\" } // state == Approved — straightforward execute.\n | { kind: \"send-self-resolve\" } // GuardianReview, window elapsed, still within\n // the execution window — executeProposal\n // self-resolves the (cold-start) review inline.\n | { kind: \"refuse-review-open\" } // GuardianReview, review window still open — the\n // tx WOULD revert (ProposalNotApproved).\n | { kind: \"refuse-expired\" } // GuardianReview past executeBy — the inline\n // self-resolve maps to Expired, tx WOULD revert.\n | { kind: \"refuse-state\" }; // any other non-executable state.\n\n/**\n * Decide whether `executeProposal(id)` should be broadcast.\n *\n * Mirrors `SyndicateGovernor.executeProposal` (contracts/src/SyndicateGovernor.sol:342)\n * vs. the `getProposalState` view:\n * - The view (`_resolveStateView` @824 / `_resolveAfterVote` @865) keeps\n * reporting `GuardianReview` once the review window elapses but the registry\n * has not cached a resolution — a zero-guardian / never-opened cold-start\n * review NEVER auto-opens, so the view is stuck there indefinitely.\n * - `executeProposal` runs the MUTATING `_resolveState` (@789) which, when the\n * window elapsed (`now > reviewEnd`), calls `registry.resolveReview` inline\n * (cold-start ⇒ blocked=false) and maps to Approved when `now <= executeBy`\n * (else Expired) — then executes in the same tx.\n * Invariant `voteEnd < reviewEnd < executeBy` (@528-530) holds for any past-vote\n * proposal, so `reviewEnd`/`executeBy` are always populated in the GuardianReview\n * branch.\n *\n * `now` MUST be chain time (latest block timestamp), not wall-clock — on a\n * time-warped vnet the two diverge and the contract compares against chain time.\n */\nexport function evaluateExecuteGate(args: {\n state: number;\n reviewEnd: bigint;\n executeBy: bigint;\n now: bigint;\n}): ExecuteGate {\n const { state, reviewEnd, executeBy, now } = args;\n if (state === PROPOSAL_STATE.Approved) return { kind: \"send\" };\n if (state === PROPOSAL_STATE.GuardianReview) {\n if (now <= reviewEnd) return { kind: \"refuse-review-open\" };\n if (now > executeBy) return { kind: \"refuse-expired\" };\n return { kind: \"send-self-resolve\" };\n }\n return { kind: \"refuse-state\" };\n}\n\n/**\n * Classification for the `resolve-reviews` keeper.\n * - `resolvable`: an OPENED, unresolved review past its window — needs a real\n * `resolveReview` tx (computes block quorum, may slash approvers).\n * - `cold-start`: an UNOPENED, unresolved review past its window — the\n * zero-guardian case. `resolveReview` would only mark it resolved/not-blocked\n * (GuardianRegistry.resolveReview @639-643), which `executeProposal`\n * already does inline, so the keeper should report it (pointing at\n * `proposal execute`) rather than spend a redundant tx.\n * - `none`: not past window yet, or already resolved.\n */\nexport type ReviewResolveClass = \"resolvable\" | \"cold-start\" | \"none\";\n\nexport function classifyReview(args: {\n opened: boolean;\n resolved: boolean;\n reviewEnd: bigint;\n now: bigint;\n}): ReviewResolveClass {\n const { opened, resolved, reviewEnd, now } = args;\n const pastWindow = reviewEnd > 0n && now >= reviewEnd;\n if (!pastWindow || resolved) return \"none\";\n return opened ? \"resolvable\" : \"cold-start\";\n}\n\n// ── Duration parser ──\n\nexport function parseDuration(input: string): bigint {\n const match = input.match(/^(\\d+)(d|h|m|s)?$/);\n if (!match) throw new Error(`Invalid duration: ${input}`);\n const value = BigInt(match[1]);\n switch (match[2]) {\n case \"d\":\n return value * 86400n;\n case \"h\":\n return value * 3600n;\n case \"m\":\n return value * 60n;\n case \"s\":\n case undefined:\n return value;\n default:\n throw new Error(`Unknown duration unit: ${match[2]}`);\n }\n}\n\n// ── Address helpers ──\n\n// governorOf(vault) is set once at createSyndicate and never rebinds, so\n// it is safe to memoize per chain+vault for the lifetime of the process.\nconst governorCache = new Map<string, Address>();\n\n/** Resolve the per-vault governor via `factory.governorOf(vault)`. */\nexport async function getGovernorOf(vault: Address): Promise<Address> {\n const key = `${getChain().id}:${vault.toLowerCase()}`;\n const cached = governorCache.get(key);\n if (cached) return cached;\n\n const client = getPublicClient();\n const governor = await client.readContract({\n address: SHERWOOD().FACTORY,\n abi: SYNDICATE_FACTORY_ABI,\n functionName: \"governorOf\",\n args: [vault],\n }) as Address;\n\n if (governor === \"0x0000000000000000000000000000000000000000\") {\n throw new Error(`No governor registered for vault ${vault} — is it a factory-created vault?`);\n }\n\n governorCache.set(key, governor);\n return governor;\n}\n\n// ProtocolConfig is a protocol-wide singleton behind the factory — same\n// set-once semantics as governorOf, memoized per chain.\nconst protocolConfigCache = new Map<number, Address>();\n\n/** Resolve the ProtocolConfig address via `factory.protocolConfig()`. */\nexport async function getProtocolConfigAddress(): Promise<Address> {\n const chainId = getChain().id;\n const cached = protocolConfigCache.get(chainId);\n if (cached) return cached;\n\n const client = getPublicClient();\n const config = await client.readContract({\n address: SHERWOOD().FACTORY,\n abi: SYNDICATE_FACTORY_ABI,\n functionName: \"protocolConfig\",\n }) as Address;\n\n protocolConfigCache.set(chainId, config);\n return config;\n}\n\n// ── Read helpers ──\n\nexport async function getGovernorParams(vault: Address): Promise<GovernorParams> {\n const client = getPublicClient();\n const result = await client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getGovernorParams\",\n }) as {\n votingPeriod: bigint;\n executionWindow: bigint;\n vetoThresholdBps: bigint;\n maxPerformanceFeeBps: bigint;\n cooldownPeriod: bigint;\n collaborationWindow: bigint;\n maxCoProposers: bigint;\n minStrategyDuration: bigint;\n maxStrategyDuration: bigint;\n };\n return result;\n}\n\nexport async function getProposal(vault: Address, id: bigint): Promise<StrategyProposal> {\n const client = getPublicClient();\n const result = await client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getProposal\",\n args: [id],\n }) as StrategyProposal;\n return result;\n}\n\nexport async function getProposalState(vault: Address, id: bigint): Promise<number> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getProposalState\",\n args: [id],\n }) as Promise<number>;\n}\n\nexport async function proposalCount(vault: Address): Promise<bigint> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"proposalCount\",\n }) as Promise<bigint>;\n}\n\nexport async function getVoteWeight(vault: Address, proposalId: bigint, voter: Address): Promise<bigint> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getVoteWeight\",\n args: [proposalId, voter],\n }) as Promise<bigint>;\n}\n\nexport async function hasVoted(vault: Address, proposalId: bigint, voter: Address): Promise<boolean> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"hasVoted\",\n args: [proposalId, voter],\n }) as Promise<boolean>;\n}\n\n// `getProposalCalls` (concat of execute + settle) was dropped in V1.5\n// to reclaim governor bytecode under EIP-170. Use `getExecuteCalls`\n// + `getSettlementCalls` instead — same data, no on-chain copy loop.\n\nexport async function getExecuteCalls(vault: Address, proposalId: bigint): Promise<BatchCall[]> {\n const client = getPublicClient();\n const result = await client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getExecuteCalls\",\n args: [proposalId],\n }) as { target: Address; data: Hex; value: bigint }[];\n return result.map((c) => ({ target: c.target, data: c.data, value: c.value }));\n}\n\nexport async function getSettlementCalls(vault: Address, proposalId: bigint): Promise<BatchCall[]> {\n const client = getPublicClient();\n const result = await client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getSettlementCalls\",\n args: [proposalId],\n }) as { target: Address; data: Hex; value: bigint }[];\n return result.map((c) => ({ target: c.target, data: c.data, value: c.value }));\n}\n\n// Per-vault governor: `getRegisteredVaults` / `isRegisteredVault` were\n// removed on-chain — a governor serves exactly one vault (`governor.vault()`).\n// Enumerate vaults via the factory (`getAllActiveSyndicates`) instead.\n\nexport async function getActiveProposal(vault: Address): Promise<bigint> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getActiveProposal\",\n }) as Promise<bigint>;\n}\n\nexport async function getCooldownEnd(vault: Address): Promise<bigint> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getCooldownEnd\",\n }) as Promise<bigint>;\n}\n\nexport async function openProposalCount(vault: Address): Promise<bigint> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"openProposalCount\",\n }) as Promise<bigint>;\n}\n\nexport async function getCapitalSnapshot(vault: Address, proposalId: bigint): Promise<bigint> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getCapitalSnapshot\",\n args: [proposalId],\n }) as Promise<bigint>;\n}\n\n/**\n * Extract proposalId from ProposalCreated event logs.\n * Returns undefined if the event is not found or parsing fails.\n */\nexport function parseProposalIdFromLogs(logs: Log[]): bigint | undefined {\n try {\n const parsed = parseEventLogs({\n abi: SYNDICATE_GOVERNOR_ABI,\n logs,\n eventName: \"ProposalCreated\",\n });\n return parsed[0]?.args.proposalId;\n } catch {\n return undefined;\n }\n}\n\n// ── Write helpers ──\n\nexport async function propose(\n vault: Address,\n strategy: Address,\n metadataURI: string,\n strategyDuration: bigint,\n executeCalls: BatchCall[],\n settlementCalls: BatchCall[],\n coProposers: CoProposer[] = [],\n): Promise<{ hash: Hex; proposalId: bigint }> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"propose\",\n args: [vault, strategy, metadataURI, strategyDuration, executeCalls, settlementCalls, coProposers],\n });\n\n const receipt = await waitForReceipt(hash);\n\n // Parse proposalId from the ProposalCreated event in the receipt logs.\n // Falls back to proposalCount() if event parsing fails.\n let proposalId = parseProposalIdFromLogs(receipt.logs);\n if (proposalId === undefined) {\n try {\n proposalId = await proposalCount(vault);\n } catch {\n proposalId = 0n;\n }\n }\n\n return { hash: receipt.transactionHash, proposalId };\n}\n\nexport async function vote(vault: Address, proposalId: bigint, support: number): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"vote\",\n args: [proposalId, support],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\nexport async function executeProposal(vault: Address, proposalId: bigint): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"executeProposal\",\n args: [proposalId],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\n/**\n * Walk a proposal's executeCalls and pick the strategy clone — the\n * target of the call whose selector matches `BaseStrategy.execute()`\n * (0x61461954). This is the canonical entry point that every Sherwood\n * strategy template inherits from BaseStrategy, so it's a reliable\n * marker even across template families (Moonwell / Aerodrome /\n * Hyperliquid / Mamo / Venice / Portfolio).\n *\n * Returns null when no execute() call is present (e.g. proposals that\n * only do approves and direct ERC-20 transfers without a strategy).\n */\nexport function detectStrategyAdapter(\n calls: { target: Address; data: Hex; value: bigint }[],\n): Address | null {\n const STRATEGY_EXECUTE_SELECTOR = \"0x61461954\";\n for (const call of calls) {\n if (call.data.slice(0, 10).toLowerCase() === STRATEGY_EXECUTE_SELECTOR) {\n return call.target;\n }\n }\n return null;\n}\n\nexport async function settleProposal(vault: Address, proposalId: bigint): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"settleProposal\",\n args: [proposalId],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\nexport async function emergencySettle(vault: Address, proposalId: bigint, calls: BatchCall[]): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"emergencySettleWithCalls\",\n args: [proposalId, calls],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\nexport async function cancelProposal(vault: Address, proposalId: bigint): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"cancelProposal\",\n args: [proposalId],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\nexport async function emergencyCancel(vault: Address, proposalId: bigint): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"emergencyCancel\",\n args: [proposalId],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\n// ── Parameter setters ──\n//\n// Per-vault governor: governance parameters are per-vault now, set by the\n// VAULT OWNER on that vault's governor. Setters revert with\n// `ParamsFrozenDuringProposal` while any proposal is open on the vault.\n\ntype GovernorParamSetter =\n | \"setVotingPeriod\"\n | \"setExecutionWindow\"\n | \"setVetoThresholdBps\"\n | \"setMaxPerformanceFeeBps\"\n | \"setMaxStrategyDuration\"\n | \"setCooldownPeriod\";\n\nasync function setGovernorParam(\n vault: Address,\n functionName: GovernorParamSetter,\n value: bigint,\n): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName,\n args: [value],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\nexport async function setVotingPeriod(vault: Address, seconds: bigint): Promise<Hex> {\n return setGovernorParam(vault, \"setVotingPeriod\", seconds);\n}\n\nexport async function setExecutionWindow(vault: Address, seconds: bigint): Promise<Hex> {\n return setGovernorParam(vault, \"setExecutionWindow\", seconds);\n}\n\nexport async function setVetoThresholdBps(vault: Address, bps: bigint): Promise<Hex> {\n return setGovernorParam(vault, \"setVetoThresholdBps\", bps);\n}\n\nexport async function setMaxPerformanceFeeBps(vault: Address, bps: bigint): Promise<Hex> {\n return setGovernorParam(vault, \"setMaxPerformanceFeeBps\", bps);\n}\n\nexport async function setMaxStrategyDuration(vault: Address, seconds: bigint): Promise<Hex> {\n return setGovernorParam(vault, \"setMaxStrategyDuration\", seconds);\n}\n\nexport async function setCooldownPeriod(vault: Address, seconds: bigint): Promise<Hex> {\n return setGovernorParam(vault, \"setCooldownPeriod\", seconds);\n}\n\nexport async function vetoProposal(vault: Address, proposalId: bigint): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"vetoProposal\",\n args: [proposalId],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\n// ── ProtocolConfig fee setters (protocol-owner only) ──\n//\n// Fee parameters moved off the governor onto the protocol-wide\n// ProtocolConfig contract (resolved via `factory.protocolConfig()`).\n\nexport async function setProtocolFeeBps(bps: bigint): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getProtocolConfigAddress(),\n abi: PROTOCOL_CONFIG_ABI,\n functionName: \"setProtocolFeeBps\",\n args: [bps],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n"],"mappings":"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","names":[]}
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  TOKENS
3
- } from "./chunk-YLYANZMC.js";
3
+ } from "./chunk-RAITRCM7.js";
4
4
  import {
5
5
  getAccount,
6
6
  getPublicClient,
7
7
  getWalletClient,
8
8
  waitForReceipt,
9
9
  writeContractWithRetry
10
- } from "./chunk-UC5RMCB3.js";
10
+ } from "./chunk-WECQ6NVS.js";
11
11
  import {
12
12
  getChain
13
- } from "./chunk-RNASYOQT.js";
13
+ } from "./chunk-HYUUR6SC.js";
14
14
  import {
15
15
  getChainContracts
16
16
  } from "./chunk-GSC7PVEO.js";
@@ -523,4 +523,4 @@ export {
523
523
  registerAgent,
524
524
  getVaultInfo
525
525
  };
526
- //# sourceMappingURL=chunk-3YUMQGJD.js.map
526
+ //# sourceMappingURL=chunk-UUHWD7Y3.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getChain,
3
3
  getRpcUrls
4
- } from "./chunk-RNASYOQT.js";
4
+ } from "./chunk-HYUUR6SC.js";
5
5
  import {
6
6
  loadConfig
7
7
  } from "./chunk-GSC7PVEO.js";
@@ -509,4 +509,4 @@ export {
509
509
  writeContractWithRetry,
510
510
  waitForReceipt
511
511
  };
512
- //# sourceMappingURL=chunk-UC5RMCB3.js.map
512
+ //# sourceMappingURL=chunk-WECQ6NVS.js.map
@@ -58,6 +58,21 @@ async function fetchMetadata(ipfsURI) {
58
58
  }
59
59
  return await response.json();
60
60
  }
61
+ function mergeFundMetadata(current, overrides) {
62
+ const base = { ...current ?? {} };
63
+ const name = overrides.name || base.name || overrides.subdomain;
64
+ const description = overrides.description || base.description || `${name} \u2014 a Sherwood fund on ${overrides.subdomain}.sherwoodagent.eth`;
65
+ return {
66
+ ...base,
67
+ schema: base.schema || "sherwood/fund/v1",
68
+ name,
69
+ description,
70
+ chain: base.chain || overrides.defaultChain,
71
+ strategies: base.strategies ?? [],
72
+ terms: base.terms ?? {},
73
+ links: base.links ?? {}
74
+ };
75
+ }
61
76
  async function resolveMetadataSummary(uri) {
62
77
  try {
63
78
  if (uri.startsWith("data:application/json;base64,")) {
@@ -76,6 +91,7 @@ export {
76
91
  pinJSON,
77
92
  uploadMetadata,
78
93
  fetchMetadata,
94
+ mergeFundMetadata,
79
95
  resolveMetadataSummary
80
96
  };
81
- //# sourceMappingURL=chunk-ZYXFKVYF.js.map
97
+ //# sourceMappingURL=chunk-XDGCHURW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/ipfs.ts"],"sourcesContent":["/**\n * IPFS metadata upload/fetch via Sherwood API.\n *\n * Uploads go through the server-side API at sherwood.sh/api/ipfs/upload\n * which holds the Pinata JWT. CLI and app only need the gateway URL for reads.\n */\n\nexport interface FundMetadata {\n schema: string;\n name: string;\n description: string;\n logo?: string;\n chain: string;\n xmtpGroupId?: string;\n strategies: {\n id: string;\n name: string;\n description: string;\n protocols: string[];\n riskLevel: string;\n }[];\n terms: {\n minDeposit?: string;\n minDepositFormatted?: string;\n feeModel?: string;\n lockPeriod?: number;\n };\n links: {\n moltbook?: string;\n dashboard?: string;\n github?: string;\n };\n}\n\nconst DEFAULT_PINATA_GATEWAY = \"https://sherwood.mypinata.cloud\";\n// www is canonical — the apex 307-redirects to it (an extra hop that has been\n// observed slow/flaky on cold starts; vnet e2e finding).\nconst DEFAULT_UPLOAD_API = \"https://www.sherwood.sh/api/ipfs/upload\";\n\nfunction getUploadApiUrl(): string {\n return process.env.SHERWOOD_API_URL\n ? `${process.env.SHERWOOD_API_URL}/api/ipfs/upload`\n : DEFAULT_UPLOAD_API;\n}\n\nfunction getPinataGateway(): string {\n return process.env.PINATA_GATEWAY || DEFAULT_PINATA_GATEWAY;\n}\n\n/**\n * Upload JSON to IPFS via the Sherwood API (server-side Pinata).\n * Returns the IPFS URI (ipfs://Qm...).\n */\nasync function uploadToIPFS(content: Record<string, unknown>, name: string): Promise<string> {\n const url = getUploadApiUrl();\n\n // Transient \"fetch failed\" / cold-start 5xx from the pin API shouldn't kill\n // a propose flow — retry briefly before surfacing (vnet e2e finding).\n const attempts = 3;\n let lastErr: unknown;\n for (let i = 0; i < attempts; i++) {\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ content, name }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n // 4xx won't improve on retry; 5xx might.\n if (response.status < 500) throw new Error(`IPFS upload failed (${response.status}): ${text}`);\n lastErr = new Error(`IPFS upload failed (${response.status}): ${text}`);\n } else {\n const result = (await response.json()) as { ipfsHash: string };\n return `ipfs://${result.ipfsHash}`;\n }\n } catch (err) {\n if (err instanceof Error && err.message.startsWith(\"IPFS upload failed (4\")) throw err;\n lastErr = err;\n }\n if (i < attempts - 1) await new Promise((r) => setTimeout(r, 2000 * (i + 1)));\n }\n throw lastErr instanceof Error ? lastErr : new Error(`IPFS upload failed: ${String(lastErr)}`);\n}\n\n/**\n * Pin arbitrary JSON to IPFS.\n * Used for research results and other generic JSON payloads.\n * Returns the IPFS URI (ipfs://Qm...).\n */\nexport async function pinJSON(content: Record<string, unknown>, name: string): Promise<string> {\n return uploadToIPFS(content, name);\n}\n\n/**\n * Upload fund metadata to IPFS.\n * Returns the IPFS URI (ipfs://Qm...).\n */\nexport async function uploadMetadata(metadata: FundMetadata): Promise<string> {\n const name = `sherwood-fund-${metadata.name.toLowerCase().replace(/\\s+/g, \"-\")}`;\n return uploadToIPFS(metadata as unknown as Record<string, unknown>, name);\n}\n\n/**\n * Fetch and parse metadata from an IPFS URI.\n * Supports ipfs:// protocol URIs and raw CIDs.\n */\nexport async function fetchMetadata(ipfsURI: string): Promise<FundMetadata> {\n const gateway = getPinataGateway();\n let cid: string;\n\n if (ipfsURI.startsWith(\"ipfs://\")) {\n cid = ipfsURI.slice(7);\n } else if (ipfsURI.startsWith(\"Qm\") || ipfsURI.startsWith(\"bafy\")) {\n cid = ipfsURI;\n } else {\n throw new Error(`Invalid IPFS URI: ${ipfsURI}`);\n }\n\n const url = `${gateway}/ipfs/${cid}`;\n const response = await fetch(url);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch metadata from ${url} (${response.status})`);\n }\n\n return (await response.json()) as FundMetadata;\n}\n\n/**\n * Merge flag-driven overrides onto the fund's CURRENT metadata.\n *\n * `update-metadata` used to rebuild the JSON from scratch, silently dropping\n * any field not re-supplied by a flag — notably `xmtpGroupId`, which is the\n * ONLY group-discovery path for the dashboard on ENS-less chains (issue #458).\n *\n * Semantics: flags (`name`/`description`) win; everything else on `current`\n * (`xmtpGroupId`, `terms`, `links`, `strategies`, and any unknown keys) is\n * preserved. Unknown keys survive because the spread of `current` is a runtime\n * copy of every own-enumerable property, not just the ones in `FundMetadata`.\n * Pass `current = null` (e.g. when the fetch failed) to fall back to the old\n * build-from-scratch behavior.\n */\nexport function mergeFundMetadata(\n current: Partial<FundMetadata> | null | undefined,\n overrides: {\n name?: string;\n description?: string;\n subdomain: string;\n defaultChain: string;\n },\n): FundMetadata {\n const base = { ...(current ?? {}) } as Partial<FundMetadata> & Record<string, unknown>;\n const name = overrides.name || base.name || overrides.subdomain;\n const description =\n overrides.description ||\n base.description ||\n `${name} — a Sherwood fund on ${overrides.subdomain}.sherwoodagent.eth`;\n return {\n ...base,\n schema: base.schema || \"sherwood/fund/v1\",\n name,\n description,\n chain: base.chain || overrides.defaultChain,\n strategies: base.strategies ?? [],\n terms: base.terms ?? {},\n links: base.links ?? {},\n };\n}\n\n/**\n * Resolve a metadata URI (ipfs:// or data: base64) to name + description.\n * Returns null on any error — callers should treat enrichment as best-effort.\n */\nexport async function resolveMetadataSummary(\n uri: string,\n): Promise<{ name: string; description: string } | null> {\n try {\n if (uri.startsWith(\"data:application/json;base64,\")) {\n const b64 = uri.slice(\"data:application/json;base64,\".length);\n const json = JSON.parse(Buffer.from(b64, \"base64\").toString(\"utf-8\"));\n return { name: json.name || \"\", description: json.description || \"\" };\n }\n const meta = await fetchMetadata(uri);\n return { name: meta.name, description: meta.description };\n } catch {\n return null;\n }\n}\n"],"mappings":"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","names":[]}
@@ -10,8 +10,8 @@ import {
10
10
  unstickWallet,
11
11
  waitForReceipt,
12
12
  writeContractWithRetry
13
- } from "./chunk-UC5RMCB3.js";
14
- import "./chunk-RNASYOQT.js";
13
+ } from "./chunk-WECQ6NVS.js";
14
+ import "./chunk-HYUUR6SC.js";
15
15
  import "./chunk-GSC7PVEO.js";
16
16
  export {
17
17
  detectStuckNonce,
@@ -26,4 +26,4 @@ export {
26
26
  waitForReceipt,
27
27
  writeContractWithRetry
28
28
  };
29
- //# sourceMappingURL=client-K4JCNPVV.js.map
29
+ //# sourceMappingURL=client-QN6SA76M.js.map
@@ -17,10 +17,10 @@ import {
17
17
  revokeAttestation,
18
18
  revokeJoinRequest,
19
19
  stripReferrerPrefix
20
- } from "./chunk-ASF2WTSW.js";
21
- import "./chunk-YLYANZMC.js";
22
- import "./chunk-UC5RMCB3.js";
23
- import "./chunk-RNASYOQT.js";
20
+ } from "./chunk-FOAX5PGR.js";
21
+ import "./chunk-RAITRCM7.js";
22
+ import "./chunk-WECQ6NVS.js";
23
+ import "./chunk-HYUUR6SC.js";
24
24
  import "./chunk-GSC7PVEO.js";
25
25
  import "./chunk-BQMOE4FJ.js";
26
26
  export {
@@ -43,4 +43,4 @@ export {
43
43
  revokeJoinRequest,
44
44
  stripReferrerPrefix
45
45
  };
46
- //# sourceMappingURL=eas-ZXGUNYC5.js.map
46
+ //# sourceMappingURL=eas-HM2AUOEY.js.map