@sage-protocol/sdk 0.1.18 → 0.1.21

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.
package/dist/index.mjs CHANGED
@@ -20,7 +20,7 @@ var require_package = __commonJS({
20
20
  "package.json"(exports2, module2) {
21
21
  module2.exports = {
22
22
  name: "@sage-protocol/sdk",
23
- version: "0.1.18",
23
+ version: "0.1.21",
24
24
  description: "Backend-agnostic SDK for interacting with the Sage Protocol (governance, SubDAOs, tokens).",
25
25
  main: "dist/index.cjs",
26
26
  module: "dist/index.mjs",
@@ -136,7 +136,6 @@ var require_abi = __commonJS({
136
136
  "function stableCreationFee() view returns (uint256)",
137
137
  "function stableFeeReceiver() view returns (address)",
138
138
  "function stableCreationEnabled() view returns (bool)",
139
- "function stablePromptForkFee() view returns (uint256)",
140
139
  "function stableForkFee() view returns (uint256)",
141
140
  // Core factory reads
142
141
  "function timelockMinDelay() view returns (uint256)",
@@ -178,13 +177,18 @@ var require_abi = __commonJS({
178
177
  "function maxCreationBurn() view returns (uint256)"
179
178
  ];
180
179
  var LibraryRegistry = [
181
- "function libraryByDAO(address) view returns (string manifestCID, address lastUpdater, uint256 lastUpdated, string version)",
180
+ "function libraryByDAO(address) view returns (string manifestCID, address lastUpdater, uint256 lastUpdated, string version, address forkedFromDAO, uint256 sxxxForkFee)",
182
181
  "function daoTimelock(address) view returns (address)",
183
- "function getLibrary(address) view returns (tuple(string manifestCID, address lastUpdater, uint256 lastUpdated, string version))",
182
+ "function getLibrary(address) view returns (tuple(string manifestCID, address lastUpdater, uint256 lastUpdated, string version, address forkedFromDAO, uint256 sxxxForkFee))",
183
+ "function getLibraryForkFee(address dao) view returns (uint256)",
184
+ "function setLibraryForkFee(address dao, uint256 fee)",
184
185
  "function updateLibrary(address dao, string manifestCID, string version)",
185
186
  "function registerDAO(address dao, address timelock)",
187
+ "function registerForkedDAO(address childDAO, address childTimelock, address parentDAO, string manifestCID, string version)",
186
188
  "event LibraryUpdated(address indexed dao, string manifestCID, address indexed timelock, string version)",
187
- "event DAORegistered(address indexed dao, address indexed timelock)"
189
+ "event DAORegistered(address indexed dao, address indexed timelock)",
190
+ "event LibraryForked(address indexed parentDAO, address indexed childDAO)",
191
+ "event LibraryForkFeeUpdated(address indexed dao, uint256 fee)"
188
192
  ];
189
193
  var PromptRegistry = [
190
194
  "function prompts(string key) view returns (string cid, uint256 version, uint256 timestamp, address author, string forkedFromCID, address originalAuthor, bool isFork, uint256 forkDepth)",
@@ -1756,7 +1760,6 @@ var require_ipfs = __commonJS({
1756
1760
  headers["X-Wallet-Address"] = auth.address;
1757
1761
  headers["X-Wallet-Signature"] = auth.signature;
1758
1762
  headers["X-Wallet-Nonce"] = auth.nonce;
1759
- headers["X-Wallet-Message"] = auth.message;
1760
1763
  }
1761
1764
  return { headers, auth };
1762
1765
  }
@@ -1777,8 +1780,7 @@ var require_ipfs = __commonJS({
1777
1780
  ...extraHeaders,
1778
1781
  "X-Wallet-Address": auth.address,
1779
1782
  "X-Wallet-Signature": auth.signature,
1780
- "X-Wallet-Nonce": auth.nonce,
1781
- "X-Wallet-Message": auth.message
1783
+ "X-Wallet-Nonce": auth.nonce
1782
1784
  };
1783
1785
  return { headers, auth };
1784
1786
  }
@@ -1799,6 +1801,13 @@ var require_ipfs = __commonJS({
1799
1801
  order.push(name);
1800
1802
  };
1801
1803
  const normalizedPreference = Array.isArray(preference) ? preference.map((p) => toLowerSafe(p)).filter(Boolean) : preference ? [toLowerSafe(preference)].filter(Boolean) : [];
1804
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
1805
+ console.log("[SDK DEBUG] resolveProviderOrder preference:", preference);
1806
+ console.log("[SDK DEBUG] normalizedPreference:", normalizedPreference);
1807
+ console.log("[SDK DEBUG] config.provider:", config.provider);
1808
+ console.log("[SDK DEBUG] shouldUseWorker():", shouldUseWorker());
1809
+ console.log("[SDK DEBUG] hasPinataCreds():", hasPinataCreds());
1810
+ }
1802
1811
  normalizedPreference.forEach(append);
1803
1812
  if (shouldUseWorker()) append("worker");
1804
1813
  if (hasPinataCreds()) append("pinata");
@@ -1806,17 +1815,90 @@ var require_ipfs = __commonJS({
1806
1815
  if (config.simulate) append("simulate");
1807
1816
  return order;
1808
1817
  }
1809
- async function uploadViaWorker(payload, { warm, gateways } = {}) {
1818
+ async function uploadViaWorker(payload, { warm, gateways, pin: pin2 } = {}) {
1819
+ const uploadUrl = workerUrl("upload");
1820
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
1821
+ console.log("[SDK DEBUG] uploadViaWorker called");
1822
+ console.log("[SDK DEBUG] workerBaseUrl:", workerBaseUrl());
1823
+ console.log("[SDK DEBUG] uploadUrl:", uploadUrl);
1824
+ console.log("[SDK DEBUG] workerHasAuth:", workerHasAuth());
1825
+ }
1810
1826
  const { headers, auth } = await buildWorkerAuthHeaders({ "Content-Type": "application/json" });
1811
1827
  const body = { ...payload };
1812
1828
  if (auth) body.auth = auth;
1813
- const response = await axiosInstance.post(workerUrl("upload"), body, { headers, timeout: config.timeoutMs });
1814
- const cid = response?.data?.cid || response?.data?.IpfsHash;
1829
+ if (pin2) {
1830
+ body.pin = typeof pin2 === "string" ? { duration: pin2 } : pin2;
1831
+ }
1832
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
1833
+ console.log("[SDK DEBUG] headers:", Object.keys(headers));
1834
+ console.log("[SDK DEBUG] hasAuth:", !!auth);
1835
+ if (pin2) console.log("[SDK DEBUG] pin:", JSON.stringify(body.pin));
1836
+ }
1837
+ let response;
1838
+ try {
1839
+ response = await axiosInstance.post(uploadUrl, body, { headers, timeout: config.timeoutMs });
1840
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
1841
+ console.log("[SDK DEBUG] Upload response status:", response?.status);
1842
+ console.log("[SDK DEBUG] Upload response data:", JSON.stringify(response?.data || {}));
1843
+ }
1844
+ } catch (uploadErr) {
1845
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
1846
+ console.log("[SDK DEBUG] Upload error:", uploadErr.message);
1847
+ console.log("[SDK DEBUG] Response status:", uploadErr.response?.status);
1848
+ console.log("[SDK DEBUG] Response data:", JSON.stringify(uploadErr.response?.data || {}));
1849
+ }
1850
+ const status = uploadErr.response?.status;
1851
+ const data2 = uploadErr.response?.data;
1852
+ if (status === 400 && data2?.error === "content_blocked") {
1853
+ const error = new Error("content_blocked");
1854
+ error.code = "CONTENT_BLOCKED";
1855
+ error.categories = data2.categories || [];
1856
+ error.reason = data2.reason;
1857
+ error.response = data2;
1858
+ throw error;
1859
+ }
1860
+ if (status === 402) {
1861
+ const error = new Error("payment_required");
1862
+ error.code = "PAYMENT_REQUIRED";
1863
+ error.creditsNeeded = data2?.creditsNeeded;
1864
+ error.balance = data2?.balance;
1865
+ error.duration = data2?.duration;
1866
+ error.accepts = data2?.accepts;
1867
+ error.response = data2;
1868
+ throw error;
1869
+ }
1870
+ throw uploadErr;
1871
+ }
1872
+ const data = response?.data || {};
1873
+ const cid = data.cid || data.IpfsHash;
1874
+ if (response?.status === 202 || data.status === "pending_review") {
1875
+ return {
1876
+ cid: cid || null,
1877
+ provider: "worker",
1878
+ status: "pending_review",
1879
+ categories: data.categories || [],
1880
+ response: data
1881
+ };
1882
+ }
1815
1883
  if (!cid) {
1816
1884
  throw new Error("Worker response missing cid");
1817
1885
  }
1818
1886
  if (warm || config.shouldWarm) await warmGateways(cid, { gateways });
1819
- return { cid, provider: "worker", response: response?.data || null };
1887
+ const result = {
1888
+ cid,
1889
+ provider: "worker",
1890
+ response: data
1891
+ };
1892
+ if (data.moderation) {
1893
+ result.moderation = data.moderation;
1894
+ }
1895
+ if (data.pinned !== void 0) {
1896
+ result.pinned = data.pinned;
1897
+ result.expiresAt = data.expiresAt;
1898
+ result.creditsPaid = data.creditsPaid;
1899
+ result.urls = data.urls;
1900
+ }
1901
+ return result;
1820
1902
  }
1821
1903
  async function uploadToPinata(payload, { filename = "payload.json", metadata, warm, gateways } = {}) {
1822
1904
  if (!hasPinataCreds()) {
@@ -1894,7 +1976,7 @@ var require_ipfs = __commonJS({
1894
1976
  return { cid, provider: "simulate" };
1895
1977
  }
1896
1978
  async function uploadPayload(payload, options2 = {}) {
1897
- const { providers, provider, warm, gateways, filename, metadata } = options2;
1979
+ const { providers, provider, warm, gateways, filename, metadata, pin: pin2 } = options2;
1898
1980
  const order = resolveProviderOrder(providers || provider);
1899
1981
  if (!order.length) {
1900
1982
  throw new Error("No IPFS providers configured. Set Pinata credentials, worker upload, or enable test mode");
@@ -1903,7 +1985,7 @@ var require_ipfs = __commonJS({
1903
1985
  for (const candidate of order) {
1904
1986
  try {
1905
1987
  if (candidate === "worker") {
1906
- return await uploadViaWorker(payload, { warm, gateways });
1988
+ return await uploadViaWorker(payload, { warm, gateways, pin: pin2 });
1907
1989
  }
1908
1990
  if (candidate === "pinata") {
1909
1991
  return await uploadToPinata(payload, { filename, metadata, warm, gateways });
@@ -1915,6 +1997,9 @@ var require_ipfs = __commonJS({
1915
1997
  return await uploadSimulated(payload, { warm, gateways });
1916
1998
  }
1917
1999
  } catch (error2) {
2000
+ if (error2.code === "CONTENT_BLOCKED" || error2.code === "PAYMENT_REQUIRED") {
2001
+ throw error2;
2002
+ }
1918
2003
  errors.push({ provider: candidate, error: error2 });
1919
2004
  }
1920
2005
  }
@@ -1923,7 +2008,7 @@ var require_ipfs = __commonJS({
1923
2008
  throw error;
1924
2009
  }
1925
2010
  async function uploadPrompt(options2 = {}) {
1926
- const { prompt, providers, provider, warm, gateways } = options2;
2011
+ const { prompt, providers, provider, warm, gateways, pin: pin2 } = options2;
1927
2012
  if (!prompt || typeof prompt !== "object") {
1928
2013
  throw new Error("prompt payload required");
1929
2014
  }
@@ -1949,6 +2034,7 @@ var require_ipfs = __commonJS({
1949
2034
  provider,
1950
2035
  warm,
1951
2036
  gateways,
2037
+ pin: pin2,
1952
2038
  filename: `${prompt.name || "prompt"}.json`,
1953
2039
  metadata
1954
2040
  });
@@ -2183,8 +2269,7 @@ var require_ipfs = __commonJS({
2183
2269
  "Content-Type": "application/json",
2184
2270
  "X-Wallet-Address": address,
2185
2271
  "X-Wallet-Signature": signature,
2186
- "X-Wallet-Nonce": nonce,
2187
- "X-Wallet-Message": message
2272
+ "X-Wallet-Nonce": nonce
2188
2273
  };
2189
2274
  let verified = false;
2190
2275
  try {
@@ -3042,13 +3127,10 @@ var require_governance = __commonJS({
3042
3127
  } else {
3043
3128
  const govAddr = normaliseGovernor(governor);
3044
3129
  try {
3045
- const iface = new Interface(["function sxxxToken() view returns (address)"]);
3046
- const data = iface.encodeFunctionData("sxxxToken", []);
3047
- const ret = await provider.call({ to: govAddr, data });
3048
- const [tok] = AbiCoder.defaultAbiCoder().decode(["address"], ret);
3049
- addr = getAddress(tok);
3130
+ const chain = await resolveVotesTokenChain({ provider, governor: govAddr });
3131
+ addr = getAddress(chain.votingToken);
3050
3132
  } catch (err) {
3051
- throw new SageSDKError(CODES.NOT_FOUND, "failed to resolve governance token from governor", { cause: err });
3133
+ throw new SageSDKError(CODES.NOT_FOUND, "failed to resolve votes token from governor", { cause: err });
3052
3134
  }
3053
3135
  }
3054
3136
  const user = getAddress(account);
@@ -3129,6 +3211,210 @@ var require_governance = __commonJS({
3129
3211
  const token = await g.sxxxToken();
3130
3212
  return buildDelegateTx({ token, delegatee: account });
3131
3213
  }
3214
+ async function resolveVotesTokenChain({ provider, subdao, governor }) {
3215
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3216
+ if (!subdao && !governor) throw new SageSDKError(CODES.INVALID_ARGS, "subdao or governor required");
3217
+ let votingToken = null;
3218
+ if (governor) {
3219
+ const govAddr = normaliseGovernor(governor);
3220
+ try {
3221
+ const iTok = new Interface(["function token() view returns (address)"]);
3222
+ const data = iTok.encodeFunctionData("token", []);
3223
+ const ret = await provider.call({ to: govAddr, data });
3224
+ if (ret && ret !== "0x") {
3225
+ const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], ret);
3226
+ votingToken = addr;
3227
+ }
3228
+ } catch (_) {
3229
+ }
3230
+ if (!votingToken) {
3231
+ try {
3232
+ const iGov = new Interface(["function sxxxToken() view returns (address)"]);
3233
+ const d2 = iGov.encodeFunctionData("sxxxToken", []);
3234
+ const r2 = await provider.call({ to: govAddr, data: d2 });
3235
+ if (r2 && r2 !== "0x") {
3236
+ const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], r2);
3237
+ votingToken = addr;
3238
+ }
3239
+ } catch (_) {
3240
+ }
3241
+ }
3242
+ }
3243
+ if (!votingToken && subdao) {
3244
+ try {
3245
+ const subAddr = getAddress(subdao);
3246
+ const iSub = new Interface(["function stakeToken() view returns (address)"]);
3247
+ const d3 = iSub.encodeFunctionData("stakeToken", []);
3248
+ const r3 = await provider.call({ to: subAddr, data: d3 });
3249
+ if (r3 && r3 !== "0x") {
3250
+ const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], r3);
3251
+ votingToken = addr;
3252
+ }
3253
+ } catch (_) {
3254
+ }
3255
+ }
3256
+ if (!votingToken) {
3257
+ throw new SageSDKError(CODES.NOT_FOUND, "failed to resolve votes token");
3258
+ }
3259
+ const votingTokenNorm = getAddress(votingToken);
3260
+ let baseToken = votingTokenNorm;
3261
+ let isWrapper = false;
3262
+ try {
3263
+ const wrapperIface = new Interface([
3264
+ "function baseToken() view returns (address)",
3265
+ "function dao() view returns (address)"
3266
+ ]);
3267
+ const [rawBase, rawDao] = await Promise.all([
3268
+ provider.call({ to: votingTokenNorm, data: wrapperIface.encodeFunctionData("baseToken", []) }),
3269
+ provider.call({ to: votingTokenNorm, data: wrapperIface.encodeFunctionData("dao", []) })
3270
+ ]);
3271
+ if (rawBase && rawBase !== "0x" && rawDao && rawDao !== "0x") {
3272
+ const [decodedBase] = AbiCoder.defaultAbiCoder().decode(["address"], rawBase);
3273
+ const [decodedDao] = AbiCoder.defaultAbiCoder().decode(["address"], rawDao);
3274
+ const baseNorm = getAddress(decodedBase);
3275
+ const daoNorm = getAddress(decodedDao);
3276
+ if (!subdao || daoNorm === getAddress(subdao)) {
3277
+ baseToken = baseNorm;
3278
+ isWrapper = true;
3279
+ }
3280
+ }
3281
+ } catch (_) {
3282
+ }
3283
+ return { votingToken: votingTokenNorm, baseToken, isWrapper };
3284
+ }
3285
+ async function describeVotesToken({ provider, subdao, governor }) {
3286
+ const { votingToken, baseToken, isWrapper } = await resolveVotesTokenChain({ provider, subdao, governor });
3287
+ let multiplierNFT = null;
3288
+ let basis = null;
3289
+ if (isWrapper) {
3290
+ try {
3291
+ const wrapper = new Contract(votingToken, ABI.MultipliedVotes, provider);
3292
+ multiplierNFT = await wrapper.multiplierNFT().catch(() => null);
3293
+ basis = await wrapper.BASIS().catch(() => null);
3294
+ } catch (_) {
3295
+ }
3296
+ }
3297
+ const votingNorm = getAddress(votingToken);
3298
+ const baseNorm = getAddress(baseToken);
3299
+ const multiplierNorm = multiplierNFT && /^0x[0-9a-fA-F]{40}$/.test(String(multiplierNFT)) ? getAddress(multiplierNFT) : null;
3300
+ const basisBig = basis != null ? BigInt(String(basis)) : null;
3301
+ let description;
3302
+ if (!isWrapper) {
3303
+ description = `Voting token = ERC20Votes at ${votingNorm}`;
3304
+ } else {
3305
+ const basisStr = basisBig != null ? basisBig.toString() : "10000";
3306
+ description = `Voting token = MultipliedVotes(base=${baseNorm}, multiplierNFT=${multiplierNorm || "unknown"}, BASIS=${basisStr})`;
3307
+ if (subdao) {
3308
+ description += ` for DAO ${getAddress(subdao)}`;
3309
+ }
3310
+ }
3311
+ return {
3312
+ votingToken: votingNorm,
3313
+ baseToken: baseNorm,
3314
+ isWrapper,
3315
+ multiplierNFT: multiplierNorm,
3316
+ basis: basisBig,
3317
+ description
3318
+ };
3319
+ }
3320
+ async function getVotingStatus({ provider, subdao, governor, account }) {
3321
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3322
+ if (!governor && !subdao) throw new SageSDKError(CODES.INVALID_ARGS, "governor or subdao required");
3323
+ if (!account) throw new SageSDKError(CODES.INVALID_ARGS, "account required");
3324
+ const acct = getAddress(account);
3325
+ let govAddr = null;
3326
+ let subdaoAddr = null;
3327
+ if (governor) {
3328
+ govAddr = normaliseGovernor(governor);
3329
+ }
3330
+ if (subdao) {
3331
+ subdaoAddr = getAddress(subdao);
3332
+ if (!govAddr) {
3333
+ try {
3334
+ const sub = new Contract(subdaoAddr, ["function governor() view returns (address)"], provider);
3335
+ govAddr = getAddress(await sub.governor());
3336
+ } catch (_) {
3337
+ }
3338
+ }
3339
+ }
3340
+ if (!govAddr) throw new SageSDKError(CODES.INVALID_ARGS, "could not resolve governor address");
3341
+ let threshold = null;
3342
+ try {
3343
+ const g = new Contract(govAddr, ABI.Governor, provider);
3344
+ const t = await g.proposalThreshold();
3345
+ threshold = BigInt(t.toString());
3346
+ } catch (_) {
3347
+ }
3348
+ const desc = await describeVotesToken({ provider, subdao: subdaoAddr || void 0, governor: govAddr });
3349
+ let stakeToken = null;
3350
+ if (subdaoAddr) {
3351
+ try {
3352
+ const sub = new Contract(subdaoAddr, ["function stakeToken() view returns (address)"], provider);
3353
+ const st = await sub.stakeToken();
3354
+ if (st && /^0x[0-9a-fA-F]{40}$/.test(String(st))) {
3355
+ stakeToken = getAddress(st);
3356
+ }
3357
+ } catch (_) {
3358
+ }
3359
+ }
3360
+ const VotesABI = [
3361
+ "function getVotes(address) view returns (uint256)",
3362
+ "function delegates(address) view returns (address)",
3363
+ "function balanceOf(address) view returns (uint256)"
3364
+ ];
3365
+ let votingPower = null;
3366
+ let delegate = null;
3367
+ let tokenBalance = null;
3368
+ try {
3369
+ const votingC = new Contract(desc.votingToken, VotesABI, provider);
3370
+ const vp = await votingC.getVotes(acct).catch(() => null);
3371
+ if (vp != null) votingPower = BigInt(vp.toString());
3372
+ const del = await votingC.delegates(acct).catch(() => null);
3373
+ if (del && /^0x[0-9a-fA-F]{40}$/.test(String(del))) delegate = getAddress(del);
3374
+ const bal = await votingC.balanceOf(acct).catch(() => null);
3375
+ if (bal != null) tokenBalance = BigInt(bal.toString());
3376
+ } catch (_) {
3377
+ }
3378
+ const canPropose = threshold != null && votingPower != null ? votingPower >= threshold : null;
3379
+ let stakeTokenVotes = null;
3380
+ let stakeTokenDelegate = null;
3381
+ let stakeTokenBalance = null;
3382
+ const tokenMismatch = !!stakeToken && stakeToken.toLowerCase() !== desc.votingToken.toLowerCase();
3383
+ if (stakeToken && tokenMismatch) {
3384
+ try {
3385
+ const stakeC = new Contract(stakeToken, VotesABI, provider);
3386
+ const sv = await stakeC.getVotes(acct).catch(() => null);
3387
+ if (sv != null) stakeTokenVotes = BigInt(sv.toString());
3388
+ const sd = await stakeC.delegates(acct).catch(() => null);
3389
+ if (sd && /^0x[0-9a-fA-F]{40}$/.test(String(sd))) {
3390
+ stakeTokenDelegate = getAddress(sd);
3391
+ }
3392
+ const sb = await stakeC.balanceOf(acct).catch(() => null);
3393
+ if (sb != null) stakeTokenBalance = BigInt(sb.toString());
3394
+ } catch (_) {
3395
+ }
3396
+ }
3397
+ return {
3398
+ subdao: subdaoAddr,
3399
+ governor: govAddr,
3400
+ stakeToken,
3401
+ votingToken: desc.votingToken,
3402
+ baseToken: desc.baseToken,
3403
+ isWrapper: desc.isWrapper,
3404
+ multiplierNFT: desc.multiplierNFT,
3405
+ basis: desc.basis,
3406
+ threshold,
3407
+ votingPower,
3408
+ tokenBalance,
3409
+ delegate,
3410
+ canPropose,
3411
+ tokenMismatch,
3412
+ stakeTokenVotes,
3413
+ stakeTokenDelegate,
3414
+ stakeTokenBalance,
3415
+ description: desc.description
3416
+ };
3417
+ }
3132
3418
  module2.exports = {
3133
3419
  getGovernorInfo,
3134
3420
  getProposal,
@@ -3160,52 +3446,28 @@ var require_governance = __commonJS({
3160
3446
  * - SubDAO.stakeToken() (when subdao provided)
3161
3447
  */
3162
3448
  resolveVotesToken: async function resolveVotesToken({ provider, subdao, governor }) {
3163
- if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3164
- if (!subdao && !governor) throw new SageSDKError(CODES.INVALID_ARGS, "subdao or governor required");
3165
- if (governor) {
3166
- const govAddr = normaliseGovernor(governor);
3167
- try {
3168
- const iTok = new Interface(["function token() view returns (address)"]);
3169
- const data = iTok.encodeFunctionData("token", []);
3170
- const ret = await provider.call({ to: govAddr, data });
3171
- if (ret && ret !== "0x") {
3172
- const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], ret);
3173
- return getAddress(addr);
3174
- }
3175
- } catch (_) {
3176
- }
3177
- try {
3178
- const iGov = new Interface(["function sxxxToken() view returns (address)"]);
3179
- const d2 = iGov.encodeFunctionData("sxxxToken", []);
3180
- const r2 = await provider.call({ to: govAddr, data: d2 });
3181
- if (r2 && r2 !== "0x") {
3182
- const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], r2);
3183
- return getAddress(addr);
3184
- }
3185
- } catch (_) {
3186
- }
3187
- }
3188
- if (subdao) {
3189
- try {
3190
- const subAddr = getAddress(subdao);
3191
- const iSub = new Interface(["function stakeToken() view returns (address)"]);
3192
- const d3 = iSub.encodeFunctionData("stakeToken", []);
3193
- const r3 = await provider.call({ to: subAddr, data: d3 });
3194
- if (r3 && r3 !== "0x") {
3195
- const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], r3);
3196
- return getAddress(addr);
3197
- }
3198
- } catch (_) {
3199
- }
3200
- }
3201
- throw new SageSDKError(CODES.NOT_FOUND, "failed to resolve votes token");
3449
+ const { votingToken } = await resolveVotesTokenChain({ provider, subdao, governor });
3450
+ return votingToken;
3202
3451
  },
3452
+ /**
3453
+ * Resolve the IVotes token chain used for voting (wrapper + base token).
3454
+ * See resolveVotesTokenChain() for details.
3455
+ */
3456
+ resolveVotesTokenChain,
3457
+ /**
3458
+ * Human-friendly description of the voting token wiring for a Governor/SubDAO.
3459
+ */
3460
+ describeVotesToken,
3461
+ /**
3462
+ * Get voting status for an account relative to a Governor/SubDAO.
3463
+ */
3464
+ getVotingStatus,
3203
3465
  /** Build a delegate(self) tx using the preferred votes token resolution path. */
3204
3466
  buildDelegateSelfPreferred: async function buildDelegateSelfPreferred({ provider, subdao, governor, account }) {
3205
3467
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3206
3468
  if (!account) throw new SageSDKError(CODES.INVALID_ARGS, "account required");
3207
- const token = await this.resolveVotesToken({ provider, subdao, governor });
3208
- return buildDelegateTx({ token, delegatee: account });
3469
+ const { baseToken } = await resolveVotesTokenChain({ provider, subdao, governor });
3470
+ return buildDelegateTx({ token: baseToken, delegatee: account });
3209
3471
  },
3210
3472
  /**
3211
3473
  * Send a delegate(self) and verify votes at latest-1.
@@ -3214,15 +3476,15 @@ var require_governance = __commonJS({
3214
3476
  delegateSelfAndVerify: async function delegateSelfAndVerify({ provider, subdao, governor, account, signer = null, minVotes = null }) {
3215
3477
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3216
3478
  if (!account) throw new SageSDKError(CODES.INVALID_ARGS, "account required");
3217
- const token = await this.resolveVotesToken({ provider, subdao, governor });
3218
- const payload = buildDelegateTx({ token, delegatee: account });
3479
+ const { votingToken, baseToken } = await resolveVotesTokenChain({ provider, subdao, governor });
3480
+ const payload = buildDelegateTx({ token: baseToken, delegatee: account });
3219
3481
  let txHash = null;
3220
3482
  if (signer && typeof signer.sendTransaction === "function") {
3221
3483
  const tx = await signer.sendTransaction({ to: payload.to, data: payload.data, value: payload.value });
3222
3484
  txHash = tx?.hash || null;
3223
3485
  if (tx?.wait) await tx.wait();
3224
3486
  }
3225
- const votes = await getVotesLatestMinusOne({ provider, token, account });
3487
+ const votes = await getVotesLatestMinusOne({ provider, token: votingToken, account });
3226
3488
  const ok = minVotes != null ? votes >= BigInt(minVotes) : votes > 0n;
3227
3489
  return { txHash, ok, votes, payload };
3228
3490
  },
@@ -3276,8 +3538,8 @@ var require_governance = __commonJS({
3276
3538
  }
3277
3539
  let votesOk = null;
3278
3540
  try {
3279
- const token = sxxx || await this.resolveVotesToken({ provider, governor });
3280
- const votes = await getVotesLatestMinusOne({ provider, token, account: user });
3541
+ const { votingToken } = await resolveVotesTokenChain({ provider, governor });
3542
+ const votes = await getVotesLatestMinusOne({ provider, token: votingToken, account: user });
3281
3543
  const th = threshold != null ? BigInt(threshold) : 0n;
3282
3544
  votesOk = votes >= th;
3283
3545
  } catch (_) {
@@ -3801,12 +4063,608 @@ var require_templates = __commonJS({
3801
4063
  if (depositOnly) {
3802
4064
  actions.push(() => governorContract.setDepositOnlyMode(true));
3803
4065
  }
3804
- const receipts = await executeSequence(actions);
3805
- return { governor, timelock, receipts };
3806
- }
3807
- module2.exports = {
3808
- communityDraftsBoardExec,
3809
- tokenDemocracy
4066
+ const receipts = await executeSequence(actions);
4067
+ return { governor, timelock, receipts };
4068
+ }
4069
+ module2.exports = {
4070
+ communityDraftsBoardExec,
4071
+ tokenDemocracy
4072
+ };
4073
+ }
4074
+ });
4075
+
4076
+ // src/browser/utils.js
4077
+ var require_utils = __commonJS({
4078
+ "src/browser/utils.js"(exports2, module2) {
4079
+ function getAddress(address) {
4080
+ if (!address) return address;
4081
+ const addr = String(address).trim();
4082
+ const normalized = addr.startsWith("0x") ? addr.slice(2).toLowerCase() : addr.toLowerCase();
4083
+ return `0x${normalized}`;
4084
+ }
4085
+ async function keccak256Async(data) {
4086
+ const encoder = new TextEncoder();
4087
+ const dataBuffer = typeof data === "string" ? encoder.encode(data) : data;
4088
+ const hashBuffer = await crypto.subtle.digest("SHA-256", dataBuffer);
4089
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
4090
+ const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
4091
+ return `0x${hashHex}`;
4092
+ }
4093
+ function keccak256Sync(data) {
4094
+ const str = typeof data === "string" ? data : JSON.stringify(data);
4095
+ let hash = 0;
4096
+ for (let i = 0; i < str.length; i++) {
4097
+ const char = str.charCodeAt(i);
4098
+ hash = (hash << 5) - hash + char;
4099
+ hash = hash & hash;
4100
+ }
4101
+ const hex = Math.abs(hash).toString(16).padStart(8, "0");
4102
+ return `0x${hex.repeat(8)}`.slice(0, 66);
4103
+ }
4104
+ module2.exports = {
4105
+ getAddress,
4106
+ keccak256Async,
4107
+ keccak256Sync
4108
+ };
4109
+ }
4110
+ });
4111
+
4112
+ // src/browser/subgraph.js
4113
+ var require_subgraph2 = __commonJS({
4114
+ "src/browser/subgraph.js"(exports2, module2) {
4115
+ var { getAddress } = require_utils();
4116
+ function sanitizeOrderBy(orderBy, allowed, fallback) {
4117
+ const value = (orderBy || "").toString();
4118
+ return allowed.includes(value) ? value : fallback;
4119
+ }
4120
+ function sanitizeOrderDirection(direction, fallback = "desc") {
4121
+ const v = (direction || "").toString().toLowerCase();
4122
+ return v === "asc" ? "asc" : "desc";
4123
+ }
4124
+ function safeGetAddress(value) {
4125
+ try {
4126
+ return getAddress(value);
4127
+ } catch {
4128
+ return null;
4129
+ }
4130
+ }
4131
+ function mapSafe(list, mapper) {
4132
+ const out = [];
4133
+ for (const item of list || []) {
4134
+ try {
4135
+ const v = mapper(item);
4136
+ if (v != null) out.push(v);
4137
+ } catch {
4138
+ }
4139
+ }
4140
+ return out;
4141
+ }
4142
+ async function query(url, document, variables) {
4143
+ if (!url) throw new Error("subgraph url required");
4144
+ const controller = new AbortController();
4145
+ const timeoutId = setTimeout(() => controller.abort(), 1e4);
4146
+ try {
4147
+ const resp = await fetch(url, {
4148
+ method: "POST",
4149
+ headers: { "Content-Type": "application/json" },
4150
+ body: JSON.stringify({ query: document, variables }),
4151
+ signal: controller.signal
4152
+ });
4153
+ clearTimeout(timeoutId);
4154
+ if (!resp.ok) {
4155
+ throw new Error(`HTTP ${resp.status}: ${resp.statusText}`);
4156
+ }
4157
+ const data = await resp.json();
4158
+ if (data && data.errors) {
4159
+ throw new Error(data.errors.map((e) => e.message).join("; "));
4160
+ }
4161
+ return data.data;
4162
+ } catch (error) {
4163
+ clearTimeout(timeoutId);
4164
+ throw error;
4165
+ }
4166
+ }
4167
+ async function listProposals({ url, governor, first = 20, skip = 0 }) {
4168
+ const data = await query(url, `
4169
+ query($governor: Bytes!, $first: Int!, $skip: Int!) {
4170
+ proposals(where: { governor: $governor }, first: $first, skip: $skip, orderBy: createdAt, orderDirection: desc) {
4171
+ id
4172
+ proposer
4173
+ description
4174
+ createdAt
4175
+ targets
4176
+ values
4177
+ calldatas
4178
+ }
4179
+ }
4180
+ `, { governor: String(governor).toLowerCase(), first, skip });
4181
+ return mapSafe(data?.proposals, (p) => {
4182
+ const proposer = safeGetAddress(p.proposer);
4183
+ if (!proposer) return null;
4184
+ const targets = (p.targets || []).map((t) => safeGetAddress(t)).filter(Boolean);
4185
+ if (!targets.length && (p.targets || []).length) return null;
4186
+ return {
4187
+ id: BigInt(p.id),
4188
+ proposer,
4189
+ description: p.description,
4190
+ createdAt: Number(p.createdAt || 0),
4191
+ targets,
4192
+ values: (p.values || []).map((value) => BigInt(String(value))),
4193
+ calldatas: p.calldatas || []
4194
+ };
4195
+ });
4196
+ }
4197
+ var STATE_STRING_TO_NUMBER = {
4198
+ PENDING: 0,
4199
+ ACTIVE: 1,
4200
+ CANCELED: 2,
4201
+ CANCELLED: 2,
4202
+ // some indexes may use British spelling
4203
+ DEFEATED: 3,
4204
+ SUCCEEDED: 4,
4205
+ QUEUED: 5,
4206
+ EXPIRED: 6,
4207
+ EXECUTED: 7
4208
+ };
4209
+ async function listProposalsFiltered({ url, governor, states, fromTimestamp, toTimestamp, first = 20, skip = 0, orderBy = "createdAt", orderDirection = "desc" }) {
4210
+ const govLower = governor ? String(governor).toLowerCase() : null;
4211
+ const statesUpper = Array.isArray(states) && states.length ? states.map((s) => String(s).toUpperCase()) : null;
4212
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["createdAt", "updatedAt", "eta"], "createdAt");
4213
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
4214
+ const doc = `
4215
+ query($first: Int!, $skip: Int!, $governor: Bytes, $states: [String!], $from: Int, $to: Int) {
4216
+ proposals(
4217
+ where: {
4218
+ ${governor ? "governor: $governor," : ""}
4219
+ ${statesUpper ? "state_in: $states," : ""}
4220
+ ${fromTimestamp !== void 0 ? "createdAt_gte: $from," : ""}
4221
+ ${toTimestamp !== void 0 ? "createdAt_lte: $to," : ""}
4222
+ }
4223
+ first: $first
4224
+ skip: $skip
4225
+ orderBy: ${safeOrderBy}
4226
+ orderDirection: ${safeOrderDirection}
4227
+ ) {
4228
+ id
4229
+ proposer
4230
+ description
4231
+ createdAt
4232
+ updatedAt
4233
+ state
4234
+ eta
4235
+ targets
4236
+ values
4237
+ calldatas
4238
+ }
4239
+ }
4240
+ `;
4241
+ const variables = { first, skip };
4242
+ if (govLower) variables.governor = govLower;
4243
+ if (statesUpper) variables.states = statesUpper;
4244
+ if (fromTimestamp !== void 0) variables.from = Number(fromTimestamp);
4245
+ if (toTimestamp !== void 0) variables.to = Number(toTimestamp);
4246
+ const data = await query(url, doc, variables);
4247
+ return mapSafe(data?.proposals, (p) => {
4248
+ const stateStr = String(p.state || "").toUpperCase();
4249
+ const stateNum = STATE_STRING_TO_NUMBER[stateStr] != null ? STATE_STRING_TO_NUMBER[stateStr] : null;
4250
+ const proposer = safeGetAddress(p.proposer);
4251
+ if (!proposer) return null;
4252
+ const targets = (p.targets || []).map((t) => safeGetAddress(t)).filter(Boolean);
4253
+ if (!targets.length && (p.targets || []).length) return null;
4254
+ return {
4255
+ id: BigInt(p.id),
4256
+ proposer,
4257
+ description: p.description || "",
4258
+ createdAt: Number(p.createdAt || 0),
4259
+ updatedAt: Number(p.updatedAt || 0),
4260
+ state: stateStr,
4261
+ stateNum,
4262
+ eta: p.eta ? BigInt(String(p.eta)) : null,
4263
+ targets,
4264
+ values: (p.values || []).map((value) => BigInt(String(value))),
4265
+ calldatas: p.calldatas || []
4266
+ };
4267
+ });
4268
+ }
4269
+ async function listLibraries({ url, subdao, first = 50, skip = 0 }) {
4270
+ const where = subdao ? `where: { subDAO: "${String(subdao).toLowerCase()}" }` : "";
4271
+ const data = await query(url, `
4272
+ query($first: Int!, $skip: Int!) {
4273
+ libraries(${where} first: $first, skip: $skip, orderBy: createdAt, orderDirection: desc) {
4274
+ id
4275
+ manifestCID
4276
+ subDAO
4277
+ proposer
4278
+ createdAt
4279
+ }
4280
+ }
4281
+ `, { first, skip });
4282
+ return mapSafe(data?.libraries, (lib) => {
4283
+ const sub = safeGetAddress(lib.subDAO);
4284
+ const proposer = safeGetAddress(lib.proposer);
4285
+ if (!sub || !proposer) return null;
4286
+ return {
4287
+ id: lib.id,
4288
+ manifestCID: lib.manifestCID,
4289
+ subdao: sub,
4290
+ proposer,
4291
+ createdAt: Number(lib.createdAt || 0)
4292
+ };
4293
+ });
4294
+ }
4295
+ async function getSubdaoLibraries({ url, subdao, first = 20, skip = 0 }) {
4296
+ if (!url) throw new Error("subgraph url required");
4297
+ const hasFilter = !!subdao;
4298
+ const whereClause = hasFilter ? "where:{ subdao:$subdao }" : "";
4299
+ const doc = `
4300
+ query($subdao:Bytes,$first:Int!,$skip:Int!){
4301
+ subDAOLibraryPointers(
4302
+ ${whereClause}
4303
+ first:$first,
4304
+ skip:$skip,
4305
+ orderBy: updatedAt,
4306
+ orderDirection: desc
4307
+ ){
4308
+ id
4309
+ subdao
4310
+ libraryId
4311
+ manifestCID
4312
+ previousCID
4313
+ promptCount
4314
+ updatedAt
4315
+ }
4316
+ }
4317
+ `;
4318
+ const variables = {
4319
+ first: Math.min(Math.max(1, Number(first || 20)), 100),
4320
+ skip
4321
+ };
4322
+ if (hasFilter) {
4323
+ const addr = safeGetAddress(subdao);
4324
+ if (!addr) throw new Error("invalid subdao address");
4325
+ variables.subdao = addr.toLowerCase();
4326
+ }
4327
+ const data = await query(url, doc, variables);
4328
+ return mapSafe(data?.subDAOLibraryPointers, (row) => {
4329
+ const id2 = row?.id;
4330
+ const manifestCID = row?.manifestCID;
4331
+ const sub = safeGetAddress(row?.subdao);
4332
+ if (!id2 || !manifestCID || !sub) return null;
4333
+ return {
4334
+ id: String(id2),
4335
+ subdao: sub,
4336
+ libraryId: String(row.libraryId || "main"),
4337
+ manifestCID: String(manifestCID),
4338
+ previousCID: row.previousCID || null,
4339
+ promptCount: row.promptCount != null ? Number(row.promptCount) : null,
4340
+ updatedAt: row.updatedAt != null ? Number(row.updatedAt) : null
4341
+ };
4342
+ });
4343
+ }
4344
+ async function getSubdaoPrompts({ url, registry, first = 50, skip = 0, orderBy = "updatedAt", orderDirection = "desc" }) {
4345
+ if (!url) throw new Error("subgraph url required");
4346
+ const reg = safeGetAddress(registry);
4347
+ if (!reg) throw new Error("invalid registry address");
4348
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["updatedAt"], "updatedAt");
4349
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
4350
+ const doc = `
4351
+ query($registry:Bytes!,$first:Int!,$skip:Int!){
4352
+ prompts(
4353
+ where:{ registry:$registry },
4354
+ first:$first,
4355
+ skip:$skip,
4356
+ orderBy: ${safeOrderBy},
4357
+ orderDirection: ${safeOrderDirection}
4358
+ ){
4359
+ id
4360
+ key
4361
+ cid
4362
+ version
4363
+ author
4364
+ registry
4365
+ updatedAt
4366
+ }
4367
+ }
4368
+ `;
4369
+ const data = await query(url, doc, {
4370
+ registry: reg.toLowerCase(),
4371
+ first: Math.min(Math.max(1, Number(first || 50)), 100),
4372
+ skip
4373
+ });
4374
+ return mapSafe(data?.prompts, (p) => {
4375
+ const author = safeGetAddress(p.author);
4376
+ const regAddr = safeGetAddress(p.registry);
4377
+ if (!author || !regAddr) return null;
4378
+ return {
4379
+ id: String(p.id),
4380
+ key: String(p.key),
4381
+ cid: String(p.cid),
4382
+ version: BigInt(p.version || "0"),
4383
+ author,
4384
+ registry: regAddr,
4385
+ updatedAt: Number(p.updatedAt || 0)
4386
+ };
4387
+ });
4388
+ }
4389
+ module2.exports = {
4390
+ query,
4391
+ listProposals,
4392
+ listProposalsFiltered,
4393
+ listLibraries,
4394
+ getSubdaoLibraries,
4395
+ getSubdaoPrompts,
4396
+ /**
4397
+ * Canonical proposal timeline. Tries common fields first, then event-style fallbacks.
4398
+ * Returns { id, createdAt, queuedAt, executedAt, canceledAt, eta, state } (numbers/strings may be null when unavailable).
4399
+ */
4400
+ async getProposalTimeline({ url, id: id2 }) {
4401
+ if (!url) throw new Error("subgraph url required");
4402
+ const pid = typeof id2 === "bigint" ? id2.toString() : String(id2);
4403
+ try {
4404
+ const data = await query(url, `
4405
+ query($id: ID!) {
4406
+ proposal(id: $id) {
4407
+ id
4408
+ createdAt
4409
+ updatedAt
4410
+ state
4411
+ eta
4412
+ queuedAt
4413
+ executedAt
4414
+ canceledAt
4415
+ }
4416
+ }
4417
+ `, { id: pid });
4418
+ if (data && data.proposal) {
4419
+ const p = data.proposal;
4420
+ return {
4421
+ id: p.id,
4422
+ createdAt: Number(p.createdAt || 0),
4423
+ queuedAt: p.queuedAt != null ? Number(p.queuedAt) : null,
4424
+ executedAt: p.executedAt != null ? Number(p.executedAt) : null,
4425
+ canceledAt: p.canceledAt != null ? Number(p.canceledAt) : null,
4426
+ eta: p.eta != null ? BigInt(String(p.eta)) : null,
4427
+ state: String(p.state || "")
4428
+ };
4429
+ }
4430
+ } catch (_) {
4431
+ }
4432
+ try {
4433
+ const data = await query(url, `
4434
+ query($id: String!) {
4435
+ proposalEvents(where: { proposal: $id }, orderBy: timestamp, orderDirection: asc) {
4436
+ type
4437
+ timestamp
4438
+ }
4439
+ proposals(where: { id: $id }, first:1) { id createdAt state eta }
4440
+ }
4441
+ `, { id: pid });
4442
+ const events = (data?.proposalEvents || []).map((e) => ({ type: String(e.type || ""), timestamp: Number(e.timestamp || 0) }));
4443
+ const base = data?.proposals?.[0] || {};
4444
+ const find = (t) => events.find((e) => e.type.toLowerCase() === t)?.timestamp || null;
4445
+ return {
4446
+ id: base.id || pid,
4447
+ createdAt: Number(base.createdAt || 0),
4448
+ queuedAt: find("queued"),
4449
+ executedAt: find("executed"),
4450
+ canceledAt: find("canceled") || find("cancelled") || null,
4451
+ eta: base.eta != null ? BigInt(String(base.eta)) : null,
4452
+ state: String(base.state || "")
4453
+ };
4454
+ } catch (_) {
4455
+ }
4456
+ return { id: pid, createdAt: 0, queuedAt: null, executedAt: null, canceledAt: null, eta: null, state: "" };
4457
+ },
4458
+ async listLiquidityAddPlans({ url, subdao = null, first = 50, skip = 0, orderBy = "blockTimestamp", orderDirection = "desc" }) {
4459
+ if (!url) throw new Error("subgraph url required");
4460
+ const filters = [];
4461
+ if (subdao) {
4462
+ const addr = safeGetAddress(subdao);
4463
+ if (!addr) throw new Error("invalid subdao address");
4464
+ filters.push(`subdao: "${addr.toLowerCase()}"`);
4465
+ }
4466
+ const where = filters.length ? `where: { ${filters.join(", ")} }` : "";
4467
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["blockTimestamp", "blockNumber"], "blockTimestamp");
4468
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
4469
+ const doc = `
4470
+ query($first:Int!,$skip:Int!){
4471
+ liquidityAddPlans(${where} first:$first, skip:$skip, orderBy: ${safeOrderBy}, orderDirection: ${safeOrderDirection}){
4472
+ id subdao pool sxxxToken stableToken sxxxAmount stableAmount lpRecipient blockNumber blockTimestamp transactionHash
4473
+ }
4474
+ }
4475
+ `;
4476
+ const data = await query(url, doc, { first, skip });
4477
+ return mapSafe(data?.liquidityAddPlans, (e) => {
4478
+ const sub = safeGetAddress(e.subdao);
4479
+ const pool = safeGetAddress(e.pool);
4480
+ const sxxxToken = safeGetAddress(e.sxxxToken);
4481
+ const stableToken = safeGetAddress(e.stableToken);
4482
+ const lpRecipient = safeGetAddress(e.lpRecipient);
4483
+ if (!sub || !pool || !sxxxToken || !stableToken || !lpRecipient) return null;
4484
+ return {
4485
+ id: String(e.id),
4486
+ subdao: sub,
4487
+ pool,
4488
+ sxxxToken,
4489
+ stableToken,
4490
+ sxxxAmount: BigInt(String(e.sxxxAmount)),
4491
+ stableAmount: BigInt(String(e.stableAmount)),
4492
+ lpRecipient,
4493
+ blockNumber: Number(e.blockNumber || 0),
4494
+ blockTimestamp: Number(e.blockTimestamp || 0),
4495
+ transactionHash: e.transactionHash
4496
+ };
4497
+ });
4498
+ },
4499
+ async listLiquidityRemovePlans({ url, subdao = null, first = 50, skip = 0, orderBy = "blockTimestamp", orderDirection = "desc" }) {
4500
+ if (!url) throw new Error("subgraph url required");
4501
+ const filters = [];
4502
+ if (subdao) {
4503
+ const addr = safeGetAddress(subdao);
4504
+ if (!addr) throw new Error("invalid subdao address");
4505
+ filters.push(`subdao: "${addr.toLowerCase()}"`);
4506
+ }
4507
+ const where = filters.length ? `where: { ${filters.join(", ")} }` : "";
4508
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["blockTimestamp", "blockNumber"], "blockTimestamp");
4509
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
4510
+ const doc = `
4511
+ query($first:Int!,$skip:Int!){
4512
+ liquidityRemovePlans(${where} first:$first, skip:$skip, orderBy: ${safeOrderBy}, orderDirection: ${safeOrderDirection}){
4513
+ id subdao pool lpToken lpAmount recipient blockNumber blockTimestamp transactionHash
4514
+ }
4515
+ }
4516
+ `;
4517
+ const data = await query(url, doc, { first, skip });
4518
+ return mapSafe(data?.liquidityRemovePlans, (e) => {
4519
+ const sub = safeGetAddress(e.subdao);
4520
+ const pool = safeGetAddress(e.pool);
4521
+ const lpToken = safeGetAddress(e.lpToken);
4522
+ const recipient = safeGetAddress(e.recipient);
4523
+ if (!sub || !pool || !lpToken || !recipient) return null;
4524
+ return {
4525
+ id: String(e.id),
4526
+ subdao: sub,
4527
+ pool,
4528
+ lpToken,
4529
+ lpAmount: BigInt(String(e.lpAmount)),
4530
+ recipient,
4531
+ blockNumber: Number(e.blockNumber || 0),
4532
+ blockTimestamp: Number(e.blockTimestamp || 0),
4533
+ transactionHash: e.transactionHash
4534
+ };
4535
+ });
4536
+ },
4537
+ async listPromptsByTag({ url, tagsHash, registry = null, first = 50, skip = 0, orderBy = "updatedAt", orderDirection = "desc" }) {
4538
+ if (!url) throw new Error("subgraph url required");
4539
+ const clauses = [`tagsHash: "${String(tagsHash)}"`];
4540
+ if (registry) {
4541
+ const addr = safeGetAddress(registry);
4542
+ if (!addr) throw new Error("invalid registry address");
4543
+ clauses.push(`registry: "${addr.toLowerCase()}"`);
4544
+ }
4545
+ const where = `where: { ${clauses.join(", ")} }`;
4546
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["updatedAt"], "updatedAt");
4547
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
4548
+ const doc = `
4549
+ query($first:Int!,$skip:Int!) {
4550
+ prompts(${where} first:$first, skip:$skip, orderBy: ${safeOrderBy}, orderDirection: ${safeOrderDirection}) {
4551
+ id key cid version author registry updatedAt tagsHash
4552
+ }
4553
+ }
4554
+ `;
4555
+ const data = await query(url, doc, { first, skip });
4556
+ return mapSafe(data?.prompts, (p) => {
4557
+ const author = safeGetAddress(p.author);
4558
+ const regAddr = safeGetAddress(p.registry);
4559
+ if (!author || !regAddr) return null;
4560
+ return {
4561
+ id: String(p.id),
4562
+ key: String(p.key),
4563
+ cid: String(p.cid),
4564
+ version: BigInt(p.version || "0"),
4565
+ author,
4566
+ registry: regAddr,
4567
+ updatedAt: Number(p.updatedAt || 0),
4568
+ tagsHash: String(p.tagsHash || "")
4569
+ };
4570
+ });
4571
+ },
4572
+ // Prompt helpers (registry scoped)
4573
+ async listRegistryPrompts({ url, registry, first = 50, skip = 0, orderBy = "updatedAt", orderDirection = "desc" }) {
4574
+ if (!url) throw new Error("subgraph url required");
4575
+ const reg = safeGetAddress(registry);
4576
+ if (!reg) throw new Error("invalid registry address");
4577
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["updatedAt"], "updatedAt");
4578
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
4579
+ const doc = `
4580
+ query($first:Int!,$skip:Int!,$registry:Bytes!) {
4581
+ prompts(where:{ registry: $registry }, first:$first, skip:$skip, orderBy: ${safeOrderBy}, orderDirection: ${safeOrderDirection}) {
4582
+ id
4583
+ key
4584
+ cid
4585
+ version
4586
+ author
4587
+ registry
4588
+ updatedAt
4589
+ }
4590
+ }
4591
+ `;
4592
+ const data = await query(url, doc, { first, skip, registry: reg.toLowerCase() });
4593
+ return mapSafe(data?.prompts, (p) => {
4594
+ const author = safeGetAddress(p.author);
4595
+ const regAddr = safeGetAddress(p.registry);
4596
+ if (!author || !regAddr) return null;
4597
+ return {
4598
+ id: String(p.id),
4599
+ key: String(p.key),
4600
+ cid: String(p.cid),
4601
+ version: BigInt(p.version || "0"),
4602
+ author,
4603
+ registry: regAddr,
4604
+ updatedAt: Number(p.updatedAt || 0)
4605
+ };
4606
+ });
4607
+ },
4608
+ async getPromptByKey({ url, registry, key }) {
4609
+ if (!url) throw new Error("subgraph url required");
4610
+ const reg = safeGetAddress(registry);
4611
+ if (!reg) throw new Error("invalid registry address");
4612
+ const doc = `
4613
+ query($registry:Bytes!,$key:String!) {
4614
+ prompts(where:{ registry: $registry, key: $key }, first:1) {
4615
+ id
4616
+ key
4617
+ cid
4618
+ version
4619
+ author
4620
+ registry
4621
+ updatedAt
4622
+ }
4623
+ }
4624
+ `;
4625
+ const data = await query(url, doc, { registry: reg.toLowerCase(), key: String(key) });
4626
+ const p = (data?.prompts || [])[0];
4627
+ if (!p) return null;
4628
+ const author = safeGetAddress(p.author);
4629
+ const regAddr = safeGetAddress(p.registry);
4630
+ if (!author || !regAddr) return null;
4631
+ return {
4632
+ id: String(p.id),
4633
+ key: String(p.key),
4634
+ cid: String(p.cid),
4635
+ version: BigInt(p.version || "0"),
4636
+ author,
4637
+ registry: regAddr,
4638
+ updatedAt: Number(p.updatedAt || 0)
4639
+ };
4640
+ },
4641
+ async getProposalById({ url, id: id2 }) {
4642
+ if (!url) throw new Error("subgraph url required");
4643
+ const doc = `query($id: ID!){ proposal(id:$id){ id proposer description createdAt updatedAt state eta targets values calldatas } }`;
4644
+ const data = await query(url, doc, { id: String(id2) });
4645
+ const p = data?.proposal;
4646
+ if (!p) return null;
4647
+ try {
4648
+ const proposer = safeGetAddress(p.proposer);
4649
+ if (!proposer) return null;
4650
+ const targets = (p.targets || []).map((t) => safeGetAddress(t)).filter(Boolean);
4651
+ if (!targets.length && (p.targets || []).length) return null;
4652
+ return {
4653
+ id: BigInt(p.id),
4654
+ proposer,
4655
+ description: p.description || "",
4656
+ createdAt: Number(p.createdAt || 0),
4657
+ updatedAt: Number(p.updatedAt || 0),
4658
+ state: String(p.state || ""),
4659
+ eta: p.eta ? BigInt(String(p.eta)) : null,
4660
+ targets,
4661
+ values: (p.values || []).map((v) => BigInt(String(v))),
4662
+ calldatas: p.calldatas || []
4663
+ };
4664
+ } catch {
4665
+ return null;
4666
+ }
4667
+ }
3810
4668
  };
3811
4669
  }
3812
4670
  });
@@ -4165,6 +5023,7 @@ var require_operations = __commonJS({
4165
5023
  cache = null,
4166
5024
  fromBlock = 0,
4167
5025
  helperAddress = null,
5026
+ subgraphUrl = null,
4168
5027
  hints = {},
4169
5028
  chunkSizeBlocks = 1e4,
4170
5029
  lookBackBlocks = 2e3,
@@ -4178,6 +5037,27 @@ var require_operations = __commonJS({
4178
5037
  const cached = await cacheAdapter.load(govAddr, id2);
4179
5038
  if (cached) return cached;
4180
5039
  }
5040
+ if (subgraphUrl) {
5041
+ try {
5042
+ const subgraph = require_subgraph2();
5043
+ const sgProposal = await subgraph.getProposalById({ url: subgraphUrl, id: String(id2) });
5044
+ if (sgProposal && sgProposal.targets && sgProposal.targets.length > 0) {
5045
+ const tuple2 = {
5046
+ id: id2,
5047
+ governor: govAddr,
5048
+ targets: sgProposal.targets,
5049
+ values: sgProposal.values || [],
5050
+ calldatas: sgProposal.calldatas || [],
5051
+ description: sgProposal.description || "",
5052
+ descriptionHash: sgProposal.description ? keccak256(toUtf8Bytes(sgProposal.description)) : null,
5053
+ createdBlock: sgProposal.createdAt || null
5054
+ };
5055
+ if (cacheAdapter) await cacheAdapter.save(govAddr, id2, tuple2);
5056
+ return tuple2;
5057
+ }
5058
+ } catch (_) {
5059
+ }
5060
+ }
4181
5061
  if (helperAddress) {
4182
5062
  try {
4183
5063
  const helperAbi = [
@@ -4391,8 +5271,14 @@ var require_operations = __commonJS({
4391
5271
  ]);
4392
5272
  let resolvedSubDAO = subdao;
4393
5273
  if (!resolvedSubDAO) {
4394
- resolvedSubDAO = await governorContract.subDAO().catch(() => null);
4395
- if (resolvedSubDAO === ZeroAddress) resolvedSubDAO = null;
5274
+ try {
5275
+ const subDAOInterface = new Interface(["function subDAO() view returns (address)"]);
5276
+ const subdaoContract = new Contract(govAddr, subDAOInterface, provider);
5277
+ resolvedSubDAO = await subdaoContract.subDAO().catch(() => null);
5278
+ if (resolvedSubDAO === ZeroAddress) resolvedSubDAO = null;
5279
+ } catch {
5280
+ resolvedSubDAO = null;
5281
+ }
4396
5282
  }
4397
5283
  let mode = null;
4398
5284
  let eligible = null;
@@ -4467,10 +5353,11 @@ var require_operations = __commonJS({
4467
5353
  refresh = false,
4468
5354
  cache = null,
4469
5355
  includeTimeline = false,
4470
- helperAddress = null
5356
+ helperAddress = null,
5357
+ subgraphUrl = null
4471
5358
  }) {
4472
5359
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
4473
- const tuple = await resolveProposalTuple({ provider, governor, proposalId, refresh, cache, helperAddress });
5360
+ const tuple = await resolveProposalTuple({ provider, governor, proposalId, refresh, cache, helperAddress, subgraphUrl });
4474
5361
  let proposal = null;
4475
5362
  try {
4476
5363
  proposal = await governance.getProposal({ provider, governor: tuple.governor, id: tuple.id });
@@ -4808,8 +5695,6 @@ var require_factory = __commonJS({
4808
5695
  stableCreationFee,
4809
5696
  feeReceiver,
4810
5697
  allowStableFee,
4811
- stablePromptForkFee,
4812
- allowStablePromptForkFee,
4813
5698
  stableForkFee,
4814
5699
  allowStableForkFee,
4815
5700
  timelockMinDelay,
@@ -4833,8 +5718,6 @@ var require_factory = __commonJS({
4833
5718
  }
4834
5719
  })(),
4835
5720
  contract.allowStableFee().catch(() => null),
4836
- contract.stablePromptForkFee().catch(() => null),
4837
- contract.allowStablePromptForkFee().catch(() => null),
4838
5721
  contract.stableForkFee().catch(() => null),
4839
5722
  contract.allowStableForkFee().catch(() => null),
4840
5723
  contract.timelockMinDelay().catch(() => null),
@@ -4850,8 +5733,6 @@ var require_factory = __commonJS({
4850
5733
  stableCreationFee,
4851
5734
  feeReceiver: feeReceiver && feeReceiver !== "0x0000000000000000000000000000000000000000" ? getAddress(feeReceiver) : null,
4852
5735
  allowStableFee,
4853
- stablePromptForkFee,
4854
- allowStablePromptForkFee,
4855
5736
  stableForkFee,
4856
5737
  allowStableForkFee,
4857
5738
  timelockMinDelay,
@@ -5183,6 +6064,113 @@ var require_factory = __commonJS({
5183
6064
  }
5184
6065
  });
5185
6066
 
6067
+ // src/lineage/index.js
6068
+ var require_lineage = __commonJS({
6069
+ "src/lineage/index.js"(exports2, module2) {
6070
+ var { Contract, getAddress } = __require("ethers");
6071
+ var { SageSDKError, CODES } = require_errors();
6072
+ var LINEAGE_ABI = [
6073
+ "function libraryByDAO(address) view returns (string manifestCID, address lastUpdater, uint256 lastUpdated, string version, address forkedFromDAO, uint256 sxxxForkFee)",
6074
+ "function getLibraryForkFee(address) view returns (uint256)"
6075
+ ];
6076
+ var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
6077
+ function normalise(address, label) {
6078
+ if (!address) throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
6079
+ try {
6080
+ return getAddress(address);
6081
+ } catch (err) {
6082
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
6083
+ }
6084
+ }
6085
+ async function getParentLibrary({ provider, registry, subdao }) {
6086
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6087
+ if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
6088
+ if (!subdao) throw new SageSDKError(CODES.INVALID_ARGS, "subdao required");
6089
+ try {
6090
+ const contract = new Contract(normalise(registry, "registry"), LINEAGE_ABI, provider);
6091
+ const info = await contract.libraryByDAO(normalise(subdao, "subdao"));
6092
+ const parent = info.forkedFromDAO;
6093
+ if (!parent || parent === ZERO_ADDRESS) {
6094
+ return null;
6095
+ }
6096
+ return getAddress(parent).toLowerCase();
6097
+ } catch (err) {
6098
+ throw new SageSDKError(CODES.CONTRACT_ERROR, "Failed to fetch parent library", { cause: err });
6099
+ }
6100
+ }
6101
+ async function getLineageChain({ provider, registry, subdao }) {
6102
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6103
+ if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
6104
+ if (!subdao) throw new SageSDKError(CODES.INVALID_ARGS, "subdao required");
6105
+ try {
6106
+ const contract = new Contract(normalise(registry, "registry"), LINEAGE_ABI, provider);
6107
+ const chain = [];
6108
+ let current = normalise(subdao, "subdao");
6109
+ const MAX_DEPTH = 100;
6110
+ let iterations = 0;
6111
+ while (current && iterations < MAX_DEPTH) {
6112
+ chain.unshift(getAddress(current).toLowerCase());
6113
+ const info = await contract.libraryByDAO(current);
6114
+ const parent = info.forkedFromDAO;
6115
+ if (!parent || parent === ZERO_ADDRESS) {
6116
+ break;
6117
+ }
6118
+ current = parent;
6119
+ iterations++;
6120
+ }
6121
+ return {
6122
+ chain,
6123
+ depth: chain.length - 1,
6124
+ root: chain[0]
6125
+ };
6126
+ } catch (err) {
6127
+ throw new SageSDKError(CODES.CONTRACT_ERROR, "Failed to fetch lineage chain", { cause: err });
6128
+ }
6129
+ }
6130
+ async function isFork({ provider, registry, subdao }) {
6131
+ const parent = await getParentLibrary({ provider, registry, subdao });
6132
+ return parent !== null;
6133
+ }
6134
+ async function getLibraryForkFee({ provider, registry, subdao }) {
6135
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6136
+ if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
6137
+ if (!subdao) throw new SageSDKError(CODES.INVALID_ARGS, "subdao required");
6138
+ try {
6139
+ const contract = new Contract(normalise(registry, "registry"), LINEAGE_ABI, provider);
6140
+ const fee = await contract.getLibraryForkFee(normalise(subdao, "subdao"));
6141
+ return BigInt(fee.toString());
6142
+ } catch (err) {
6143
+ throw new SageSDKError(CODES.CONTRACT_ERROR, "Failed to fetch library fork fee", { cause: err });
6144
+ }
6145
+ }
6146
+ async function getLibraryInfo({ provider, registry, subdao }) {
6147
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6148
+ if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
6149
+ if (!subdao) throw new SageSDKError(CODES.INVALID_ARGS, "subdao required");
6150
+ try {
6151
+ const contract = new Contract(normalise(registry, "registry"), LINEAGE_ABI, provider);
6152
+ const info = await contract.libraryByDAO(normalise(subdao, "subdao"));
6153
+ const parent = info.forkedFromDAO;
6154
+ return {
6155
+ parentDAO: !parent || parent === ZERO_ADDRESS ? null : getAddress(parent).toLowerCase(),
6156
+ forkFee: BigInt(info.sxxxForkFee.toString()),
6157
+ manifestCID: info.manifestCID,
6158
+ version: info.version
6159
+ };
6160
+ } catch (err) {
6161
+ throw new SageSDKError(CODES.CONTRACT_ERROR, "Failed to fetch library info", { cause: err });
6162
+ }
6163
+ }
6164
+ module2.exports = {
6165
+ getParentLibrary,
6166
+ getLineageChain,
6167
+ isFork,
6168
+ getLibraryForkFee,
6169
+ getLibraryInfo
6170
+ };
6171
+ }
6172
+ });
6173
+
5186
6174
  // src/prompt/execute.js
5187
6175
  var require_execute = __commonJS({
5188
6176
  "src/prompt/execute.js"(exports2, module2) {
@@ -5855,7 +6843,6 @@ var require_ipns = __commonJS({
5855
6843
  headers["X-Wallet-Address"] = auth.address;
5856
6844
  headers["X-Wallet-Signature"] = auth.signature;
5857
6845
  headers["X-Wallet-Nonce"] = auth.nonce;
5858
- headers["X-Wallet-Message"] = auth.message;
5859
6846
  }
5860
6847
  return { headers, auth };
5861
6848
  }
@@ -5877,8 +6864,7 @@ var require_ipns = __commonJS({
5877
6864
  ...extraHeaders,
5878
6865
  "X-Wallet-Address": auth.address,
5879
6866
  "X-Wallet-Signature": auth.signature,
5880
- "X-Wallet-Nonce": auth.nonce,
5881
- "X-Wallet-Message": auth.message
6867
+ "X-Wallet-Nonce": auth.nonce
5882
6868
  };
5883
6869
  return { headers, auth };
5884
6870
  }
@@ -6515,8 +7501,34 @@ var require_time = __commonJS({
6515
7501
  var require_treasury = __commonJS({
6516
7502
  "src/treasury/index.js"(exports2, module2) {
6517
7503
  var { Contract, Interface, getAddress } = __require("ethers");
6518
- var ABI = require_abi();
6519
7504
  var { SageSDKError, CODES } = require_errors();
7505
+ var SAGE_TREASURY_ABI = [
7506
+ // Aggregated views
7507
+ "function totalReserves() view returns (uint256)",
7508
+ "function totalPOL() view returns (uint256)",
7509
+ "function totalDebt() view returns (uint256)",
7510
+ // Canonical liquidity config
7511
+ "function canonicalPool() view returns (address)",
7512
+ "function routerOrVault() view returns (address)",
7513
+ // Withdrawal rate limits
7514
+ "function maxWithdrawalRate() view returns (uint256)",
7515
+ "function emergencyWithdrawalLimit() view returns (uint256)",
7516
+ // Reserve tokens
7517
+ "function getReserveTokens() view returns (address[])",
7518
+ "function getReserve(address token) view returns (tuple(uint256 amount, uint256 value, bool isLP, bool isActive))",
7519
+ // Withdrawal queue
7520
+ "function nextWithdrawalId() view returns (uint256)",
7521
+ "function pendingWithdrawals(uint256 id) view returns (tuple(bool exists, address token, address recipient, uint256 amount, uint256 value, address requester, uint256 balanceBefore, uint256 recipientBalanceBefore, uint256 depositSnapshot, bool isLP, bool isEmergency))",
7522
+ "function withdraw(address token, uint256 amount, address recipient)",
7523
+ "function confirmWithdrawal(uint256 id)",
7524
+ "function cancelWithdrawal(uint256 id)",
7525
+ // Manual price overrides
7526
+ "function manualPrices(address token) view returns (tuple(uint256 price, uint256 expiresAt, bool active))",
7527
+ "function setPriceOverride(address token, uint256 price, uint256 ttlSeconds)",
7528
+ "function clearPriceOverride(address token)",
7529
+ // Events
7530
+ "event WithdrawalScheduled(uint256 indexed id, address indexed token, address indexed recipient, uint256 amount)"
7531
+ ];
6520
7532
  var LiquidityEvents = new Interface([
6521
7533
  "event CanonicalLiquidityUpdated(address indexed pool, address indexed routerOrVault)",
6522
7534
  "event LiquidityAddPlanned(address indexed subdao, address indexed pool, address sxxxToken, address stableToken, uint256 sxxxAmount, uint256 stableAmount, address lpRecipient)",
@@ -6561,7 +7573,7 @@ var require_treasury = __commonJS({
6561
7573
  async function getTreasuryInfo({ provider, treasury }) {
6562
7574
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6563
7575
  const addr = normalise(treasury, "treasury");
6564
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7576
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6565
7577
  const [totalReserves, totalPOL, totalDebt, canonicalPool, routerOrVault, maxWithdrawalRate, emergencyWithdrawalLimit] = await Promise.all([
6566
7578
  contract.totalReserves().catch(() => 0n),
6567
7579
  contract.totalPOL().catch(() => 0n),
@@ -6585,7 +7597,7 @@ var require_treasury = __commonJS({
6585
7597
  async function getPendingWithdrawals({ provider, treasury, ids, limit = 50 }) {
6586
7598
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6587
7599
  const addr = normalise(treasury, "treasury");
6588
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7600
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6589
7601
  let idList = ids;
6590
7602
  if (!Array.isArray(idList)) {
6591
7603
  const nextId = await contract.nextWithdrawalId().catch(() => 0n);
@@ -6617,14 +7629,14 @@ var require_treasury = __commonJS({
6617
7629
  async function getReserveTokens({ provider, treasury }) {
6618
7630
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6619
7631
  const addr = normalise(treasury, "treasury");
6620
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7632
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6621
7633
  const tokens = await contract.getReserveTokens().catch(() => []);
6622
7634
  return tokens.map((token) => getAddress(token));
6623
7635
  }
6624
7636
  async function getReserves({ provider, treasury, tokens, fetchMetadata = true }) {
6625
7637
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6626
7638
  const addr = normalise(treasury, "treasury");
6627
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7639
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6628
7640
  const tokenList = Array.isArray(tokens) && tokens.length ? tokens.map((token) => getAddress(token)) : await contract.getReserveTokens().catch(() => []);
6629
7641
  const reserves = [];
6630
7642
  for (const token of tokenList) {
@@ -6654,7 +7666,7 @@ var require_treasury = __commonJS({
6654
7666
  async function getManualPriceOverrides({ provider, treasury, tokens }) {
6655
7667
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6656
7668
  const addr = normalise(treasury, "treasury");
6657
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7669
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6658
7670
  const tokenList = Array.isArray(tokens) && tokens.length ? tokens.map((token) => getAddress(token)) : await contract.getReserveTokens().catch(() => []);
6659
7671
  const overrides = [];
6660
7672
  for (const token of tokenList) {
@@ -6759,7 +7771,7 @@ var require_treasury = __commonJS({
6759
7771
  async function getLPContribution({ provider, treasury, subdao, token }) {
6760
7772
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6761
7773
  const addr = normalise(treasury, "treasury");
6762
- const c = new Contract(addr, ABI.SageTreasury, provider);
7774
+ const c = new Contract(addr, SAGE_TREASURY_ABI, provider);
6763
7775
  const amount = await c.lpContributions(normalise(subdao, "subdao"), normalise(token, "token")).catch(() => 0n);
6764
7776
  return amount;
6765
7777
  }
@@ -6801,7 +7813,7 @@ var require_treasury = __commonJS({
6801
7813
  function createWriteContract({ signer, treasury }) {
6802
7814
  if (!signer) throw new SageSDKError(CODES.INVALID_ARGS, "signer required");
6803
7815
  const addr = normalise(treasury, "treasury");
6804
- return new Contract(addr, ABI.SageTreasury, signer);
7816
+ return new Contract(addr, SAGE_TREASURY_ABI, signer);
6805
7817
  }
6806
7818
  async function waitForReceipt({ signer, tx, waitMs }) {
6807
7819
  const provider = signer.provider;
@@ -7105,6 +8117,350 @@ var require_bounty = __commonJS({
7105
8117
  }
7106
8118
  });
7107
8119
 
8120
+ // src/votingMultiplier/index.js
8121
+ var require_votingMultiplier = __commonJS({
8122
+ "src/votingMultiplier/index.js"(exports2, module2) {
8123
+ var { Contract, Interface, getAddress } = __require("ethers");
8124
+ var ABI = require_abi();
8125
+ var { SageSDKError, CODES } = require_errors();
8126
+ function normaliseAddress(address, label) {
8127
+ if (!address) throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
8128
+ try {
8129
+ return getAddress(address);
8130
+ } catch (err) {
8131
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
8132
+ }
8133
+ }
8134
+ function toBigInt(value, label) {
8135
+ if (value === void 0 || value === null) {
8136
+ throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
8137
+ }
8138
+ try {
8139
+ return BigInt(value.toString());
8140
+ } catch (err) {
8141
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
8142
+ }
8143
+ }
8144
+ function getNftContract(provider, nft) {
8145
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
8146
+ const addr = normaliseAddress(nft, "nft");
8147
+ return new Contract(addr, ABI.VotingMultiplierNFT, provider);
8148
+ }
8149
+ function getWrapperContract(provider, wrapper) {
8150
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
8151
+ const addr = normaliseAddress(wrapper, "wrapper");
8152
+ return new Contract(addr, ABI.MultipliedVotes, provider);
8153
+ }
8154
+ async function getTier({ provider, nft, tierId }) {
8155
+ const c = getNftContract(provider, nft);
8156
+ const id2 = toBigInt(tierId, "tierId");
8157
+ let tier;
8158
+ if (typeof c.getTier === "function") {
8159
+ tier = await c.getTier(id2);
8160
+ } else {
8161
+ tier = await c.tiers(id2);
8162
+ }
8163
+ const name = String(tier.name ?? tier[0]);
8164
+ const multiplier = BigInt((tier.multiplier ?? tier[1]).toString());
8165
+ const maxSupply = BigInt((tier.maxSupply ?? tier[2]).toString());
8166
+ const minted = BigInt((tier.minted ?? tier[3]).toString());
8167
+ const price = BigInt((tier.price ?? tier[4]).toString());
8168
+ const dao = getAddress(tier.dao ?? tier[5]);
8169
+ return { name, multiplier, maxSupply, minted, price, dao };
8170
+ }
8171
+ async function getTierCount({ provider, nft }) {
8172
+ const c = getNftContract(provider, nft);
8173
+ const count = await c.tierCount();
8174
+ return BigInt(count.toString());
8175
+ }
8176
+ function buildCreateTierTx({ nft, dao, name, multiplier, maxSupply, price }) {
8177
+ const addr = normaliseAddress(nft, "nft");
8178
+ const iface = new Interface(ABI.VotingMultiplierNFT);
8179
+ const data = iface.encodeFunctionData("createTier", [
8180
+ normaliseAddress(dao, "dao"),
8181
+ String(name ?? ""),
8182
+ toBigInt(multiplier, "multiplier"),
8183
+ toBigInt(maxSupply, "maxSupply"),
8184
+ toBigInt(price, "price")
8185
+ ]);
8186
+ return { to: addr, data, value: 0n };
8187
+ }
8188
+ function buildMintTx({ nft, to, tierId, uri }) {
8189
+ const addr = normaliseAddress(nft, "nft");
8190
+ const iface = new Interface(ABI.VotingMultiplierNFT);
8191
+ const data = iface.encodeFunctionData("mint", [
8192
+ normaliseAddress(to, "to"),
8193
+ toBigInt(tierId, "tierId"),
8194
+ String(uri ?? "")
8195
+ ]);
8196
+ return { to: addr, data, value: 0n };
8197
+ }
8198
+ function buildPublicMintTx({ nft, tierId, uri, value }) {
8199
+ const addr = normaliseAddress(nft, "nft");
8200
+ const iface = new Interface(ABI.VotingMultiplierNFT);
8201
+ const data = iface.encodeFunctionData("publicMint", [
8202
+ toBigInt(tierId, "tierId"),
8203
+ String(uri ?? "")
8204
+ ]);
8205
+ return { to: addr, data, value: toBigInt(value ?? 0n, "value") };
8206
+ }
8207
+ async function getMultiplier({ provider, nft, account, dao }) {
8208
+ const c = getNftContract(provider, nft);
8209
+ const res = await c.getMultiplier(normaliseAddress(account, "account"), normaliseAddress(dao, "dao"));
8210
+ return BigInt(res.toString());
8211
+ }
8212
+ async function getPastMultiplier({ provider, nft, account, dao, timepoint }) {
8213
+ const c = getNftContract(provider, nft);
8214
+ const res = await c.getPastMultiplier(
8215
+ normaliseAddress(account, "account"),
8216
+ normaliseAddress(dao, "dao"),
8217
+ toBigInt(timepoint, "timepoint")
8218
+ );
8219
+ return BigInt(res.toString());
8220
+ }
8221
+ async function getTokenMultiplier({ provider, nft, tokenId }) {
8222
+ const c = getNftContract(provider, nft);
8223
+ const res = await c.getTokenMultiplier(toBigInt(tokenId, "tokenId"));
8224
+ return BigInt(res.toString());
8225
+ }
8226
+ async function getTokenDAO({ provider, nft, tokenId }) {
8227
+ const c = getNftContract(provider, nft);
8228
+ const res = await c.getTokenDAO(toBigInt(tokenId, "tokenId"));
8229
+ return getAddress(res);
8230
+ }
8231
+ async function getTokenInfo({ provider, nft, tokenId }) {
8232
+ const c = getNftContract(provider, nft);
8233
+ const id2 = toBigInt(tokenId, "tokenId");
8234
+ const info = await c.getTokenInfo(id2);
8235
+ const owner = getAddress(info.owner ?? info[0]);
8236
+ const tierId = BigInt((info.tierId ?? info[1]).toString());
8237
+ const multiplier = BigInt((info.multiplier ?? info[2]).toString());
8238
+ const uri = String(info.uri ?? info[3]);
8239
+ return { owner, tierId, multiplier, uri };
8240
+ }
8241
+ async function getVotes({ provider, wrapper, account }) {
8242
+ const c = getWrapperContract(provider, wrapper);
8243
+ const res = await c.getVotes(normaliseAddress(account, "account"));
8244
+ return BigInt(res.toString());
8245
+ }
8246
+ async function getPastVotes({ provider, wrapper, account, timepoint }) {
8247
+ const c = getWrapperContract(provider, wrapper);
8248
+ const res = await c.getPastVotes(
8249
+ normaliseAddress(account, "account"),
8250
+ toBigInt(timepoint, "timepoint")
8251
+ );
8252
+ return BigInt(res.toString());
8253
+ }
8254
+ async function getVotingBreakdown({ provider, wrapper, account }) {
8255
+ const c = getWrapperContract(provider, wrapper);
8256
+ const [baseVotes, multiplier, effectiveVotes] = await c.getVotingBreakdown(normaliseAddress(account, "account"));
8257
+ return {
8258
+ baseVotes: BigInt(baseVotes.toString()),
8259
+ multiplier: BigInt(multiplier.toString()),
8260
+ effectiveVotes: BigInt(effectiveVotes.toString())
8261
+ };
8262
+ }
8263
+ async function getPastVotingBreakdown({ provider, wrapper, account, timepoint }) {
8264
+ const c = getWrapperContract(provider, wrapper);
8265
+ const [baseVotes, multiplier, effectiveVotes] = await c.getPastVotingBreakdown(
8266
+ normaliseAddress(account, "account"),
8267
+ toBigInt(timepoint, "timepoint")
8268
+ );
8269
+ return {
8270
+ baseVotes: BigInt(baseVotes.toString()),
8271
+ multiplier: BigInt(multiplier.toString()),
8272
+ effectiveVotes: BigInt(effectiveVotes.toString())
8273
+ };
8274
+ }
8275
+ async function hasMultiplierBonus({ provider, wrapper, account }) {
8276
+ const c = getWrapperContract(provider, wrapper);
8277
+ const res = await c.hasMultiplierBonus(normaliseAddress(account, "account"));
8278
+ return !!res;
8279
+ }
8280
+ module2.exports = {
8281
+ // Tier management
8282
+ getTier,
8283
+ getTierCount,
8284
+ buildCreateTierTx,
8285
+ // Minting
8286
+ buildMintTx,
8287
+ buildPublicMintTx,
8288
+ // Multiplier queries
8289
+ getMultiplier,
8290
+ getPastMultiplier,
8291
+ getTokenMultiplier,
8292
+ getTokenDAO,
8293
+ getTokenInfo,
8294
+ // Wrapper queries
8295
+ getVotes,
8296
+ getPastVotes,
8297
+ getVotingBreakdown,
8298
+ getPastVotingBreakdown,
8299
+ hasMultiplierBonus
8300
+ };
8301
+ }
8302
+ });
8303
+
8304
+ // src/auction/index.js
8305
+ var require_auction = __commonJS({
8306
+ "src/auction/index.js"(exports2, module2) {
8307
+ var { Contract, Interface, getAddress } = __require("ethers");
8308
+ var ABI = require_abi();
8309
+ var { SageSDKError, CODES } = require_errors();
8310
+ function normaliseAddress(address, label) {
8311
+ if (!address) throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
8312
+ try {
8313
+ return getAddress(address);
8314
+ } catch (err) {
8315
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
8316
+ }
8317
+ }
8318
+ function toBigInt(value, label) {
8319
+ if (value === void 0 || value === null) {
8320
+ throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
8321
+ }
8322
+ try {
8323
+ return BigInt(value.toString());
8324
+ } catch (err) {
8325
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
8326
+ }
8327
+ }
8328
+ function getAuctionContract(provider, auctionHouse) {
8329
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
8330
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8331
+ return new Contract(addr, ABI.SageAuctionHouse, provider);
8332
+ }
8333
+ async function getAuction({ provider, auctionHouse }) {
8334
+ const c = getAuctionContract(provider, auctionHouse);
8335
+ const res = await c.auction();
8336
+ const nftId = BigInt(res.nftId.toString());
8337
+ const amount = BigInt(res.amount.toString());
8338
+ const startTime = BigInt(res.startTime.toString());
8339
+ const endTime = BigInt(res.endTime.toString());
8340
+ const bidder = getAddress(res.bidder);
8341
+ const settled = !!res.settled;
8342
+ return { nftId, amount, startTime, endTime, bidder, settled };
8343
+ }
8344
+ async function getConfig({ provider, auctionHouse }) {
8345
+ const c = getAuctionContract(provider, auctionHouse);
8346
+ const [nft, treasury, weth, timeBuffer, reservePrice, minBidIncrementPercentage, duration, mintTierId, defaultTokenURI, paused, owner] = await Promise.all([
8347
+ c.nft(),
8348
+ c.treasury(),
8349
+ c.weth(),
8350
+ c.timeBuffer(),
8351
+ c.reservePrice(),
8352
+ c.minBidIncrementPercentage(),
8353
+ c.duration(),
8354
+ c.mintTierId(),
8355
+ c.defaultTokenURI(),
8356
+ c.paused(),
8357
+ c.owner()
8358
+ ]);
8359
+ return {
8360
+ nft: getAddress(nft),
8361
+ treasury: getAddress(treasury),
8362
+ weth: getAddress(weth),
8363
+ timeBuffer: BigInt(timeBuffer.toString()),
8364
+ reservePrice: BigInt(reservePrice.toString()),
8365
+ minBidIncrementPercentage: BigInt(minBidIncrementPercentage.toString()),
8366
+ duration: BigInt(duration.toString()),
8367
+ mintTierId: BigInt(mintTierId.toString()),
8368
+ defaultTokenURI: String(defaultTokenURI),
8369
+ paused: !!paused,
8370
+ owner: getAddress(owner)
8371
+ };
8372
+ }
8373
+ function buildCreateBidTx({ auctionHouse, nftId, value }) {
8374
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8375
+ const iface = new Interface(ABI.SageAuctionHouse);
8376
+ const data = iface.encodeFunctionData("createBid", [toBigInt(nftId, "nftId")]);
8377
+ return { to: addr, data, value: toBigInt(value, "value") };
8378
+ }
8379
+ function buildSettleAndCreateTx({ auctionHouse }) {
8380
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8381
+ const iface = new Interface(ABI.SageAuctionHouse);
8382
+ const data = iface.encodeFunctionData("settleCurrentAndCreateNewAuction", []);
8383
+ return { to: addr, data, value: 0n };
8384
+ }
8385
+ function buildSettleTx({ auctionHouse }) {
8386
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8387
+ const iface = new Interface(ABI.SageAuctionHouse);
8388
+ const data = iface.encodeFunctionData("settleAuction", []);
8389
+ return { to: addr, data, value: 0n };
8390
+ }
8391
+ function buildCreateAuctionTx({ auctionHouse }) {
8392
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8393
+ const iface = new Interface(ABI.SageAuctionHouse);
8394
+ const data = iface.encodeFunctionData("createAuction", []);
8395
+ return { to: addr, data, value: 0n };
8396
+ }
8397
+ function buildPauseTx({ auctionHouse }) {
8398
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8399
+ const iface = new Interface(ABI.SageAuctionHouse);
8400
+ const data = iface.encodeFunctionData("pause", []);
8401
+ return { to: addr, data, value: 0n };
8402
+ }
8403
+ function buildUnpauseTx({ auctionHouse }) {
8404
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8405
+ const iface = new Interface(ABI.SageAuctionHouse);
8406
+ const data = iface.encodeFunctionData("unpause", []);
8407
+ return { to: addr, data, value: 0n };
8408
+ }
8409
+ function buildSetTimeBufferTx({ auctionHouse, timeBuffer }) {
8410
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8411
+ const iface = new Interface(ABI.SageAuctionHouse);
8412
+ const data = iface.encodeFunctionData("setTimeBuffer", [toBigInt(timeBuffer, "timeBuffer")]);
8413
+ return { to: addr, data, value: 0n };
8414
+ }
8415
+ function buildSetReservePriceTx({ auctionHouse, reservePrice }) {
8416
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8417
+ const iface = new Interface(ABI.SageAuctionHouse);
8418
+ const data = iface.encodeFunctionData("setReservePrice", [toBigInt(reservePrice, "reservePrice")]);
8419
+ return { to: addr, data, value: 0n };
8420
+ }
8421
+ function buildSetMinBidIncrementTx({ auctionHouse, percentage }) {
8422
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8423
+ const iface = new Interface(ABI.SageAuctionHouse);
8424
+ const data = iface.encodeFunctionData("setMinBidIncrementPercentage", [toBigInt(percentage, "percentage")]);
8425
+ return { to: addr, data, value: 0n };
8426
+ }
8427
+ function buildSetDurationTx({ auctionHouse, duration }) {
8428
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8429
+ const iface = new Interface(ABI.SageAuctionHouse);
8430
+ const data = iface.encodeFunctionData("setDuration", [toBigInt(duration, "duration")]);
8431
+ return { to: addr, data, value: 0n };
8432
+ }
8433
+ function buildSetMintTierIdTx({ auctionHouse, tierId }) {
8434
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8435
+ const iface = new Interface(ABI.SageAuctionHouse);
8436
+ const data = iface.encodeFunctionData("setMintTierId", [toBigInt(tierId, "tierId")]);
8437
+ return { to: addr, data, value: 0n };
8438
+ }
8439
+ function buildSetDefaultTokenURITx({ auctionHouse, uri }) {
8440
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8441
+ const iface = new Interface(ABI.SageAuctionHouse);
8442
+ const data = iface.encodeFunctionData("setDefaultTokenURI", [String(uri ?? "")]);
8443
+ return { to: addr, data, value: 0n };
8444
+ }
8445
+ module2.exports = {
8446
+ getAuction,
8447
+ getConfig,
8448
+ buildCreateBidTx,
8449
+ buildSettleAndCreateTx,
8450
+ buildSettleTx,
8451
+ buildCreateAuctionTx,
8452
+ buildPauseTx,
8453
+ buildUnpauseTx,
8454
+ buildSetTimeBufferTx,
8455
+ buildSetReservePriceTx,
8456
+ buildSetMinBidIncrementTx,
8457
+ buildSetDurationTx,
8458
+ buildSetMintTierIdTx,
8459
+ buildSetDefaultTokenURITx
8460
+ };
8461
+ }
8462
+ });
8463
+
7108
8464
  // src/utils/provider.js
7109
8465
  var require_provider = __commonJS({
7110
8466
  "src/utils/provider.js"(exports2, module2) {
@@ -9910,6 +11266,273 @@ var require_client2 = __commonJS({
9910
11266
  }
9911
11267
  });
9912
11268
 
11269
+ // src/clients/discovery-client.js
11270
+ var require_discovery_client = __commonJS({
11271
+ "src/clients/discovery-client.js"(exports2, module2) {
11272
+ var DiscoveryClient = class {
11273
+ /**
11274
+ * @param {string} baseUrl - Base URL of the discovery API
11275
+ * @param {object} [options] - Client options
11276
+ * @param {number} [options.timeout=10000] - Request timeout in milliseconds
11277
+ * @param {Record<string, string>} [options.headers] - Custom headers
11278
+ */
11279
+ constructor(baseUrl, options = {}) {
11280
+ this.baseUrl = baseUrl.replace(/\/$/, "");
11281
+ this.timeout = options.timeout || 1e4;
11282
+ this.headers = options.headers || {};
11283
+ }
11284
+ /**
11285
+ * Search prompts with keyword matching and trend ranking
11286
+ * @param {string} query - Search query
11287
+ * @param {object} [options] - Search options
11288
+ * @param {string} [options.category] - Filter by category
11289
+ * @param {string[]} [options.tags] - Filter by tags
11290
+ * @param {string} [options.author] - Filter by author
11291
+ * @param {number} [options.limit] - Max results to return
11292
+ * @param {number} [options.offset] - Number of results to skip
11293
+ * @param {boolean} [options.useVector] - Use vector search
11294
+ * @returns {Promise<{results: Array, total: number}>}
11295
+ */
11296
+ async search(query, options = {}) {
11297
+ const params = new URLSearchParams();
11298
+ if (query) params.set("q", query);
11299
+ if (options.category) params.set("category", options.category);
11300
+ if (options.author) params.set("author", options.author);
11301
+ if (options.tags) {
11302
+ options.tags.forEach((tag) => params.append("tags", tag));
11303
+ }
11304
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11305
+ if (options.offset !== void 0) params.set("offset", String(options.offset));
11306
+ if (options.useVector !== void 0) params.set("useVector", String(options.useVector));
11307
+ return this._get(`/discover/search?${params}`);
11308
+ }
11309
+ /**
11310
+ * Get trending prompts by time window
11311
+ * @param {object} [options] - Trending options
11312
+ * @param {'1h'|'24h'|'7d'|'30d'|'all'} [options.window] - Time window
11313
+ * @param {string} [options.category] - Filter by category
11314
+ * @param {number} [options.limit] - Max results to return
11315
+ * @param {number} [options.offset] - Number of results to skip
11316
+ * @returns {Promise<{results: Array}>}
11317
+ */
11318
+ async trending(options = {}) {
11319
+ const params = new URLSearchParams();
11320
+ if (options.window) params.set("window", options.window);
11321
+ if (options.category) params.set("category", options.category);
11322
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11323
+ if (options.offset !== void 0) params.set("offset", String(options.offset));
11324
+ return this._get(`/discover/trending?${params}`);
11325
+ }
11326
+ /**
11327
+ * Get trending prompts (alias for /trends/top endpoint)
11328
+ * @param {object} [options] - Trending options
11329
+ * @param {'1h'|'24h'|'7d'|'30d'|'all'} [options.window] - Time window
11330
+ * @param {number} [options.limit] - Max results to return
11331
+ * @param {number} [options.offset] - Number of results to skip
11332
+ * @returns {Promise<{results: Array}>}
11333
+ */
11334
+ async trendingTop(options = {}) {
11335
+ const params = new URLSearchParams();
11336
+ if (options.window) params.set("window", options.window);
11337
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11338
+ if (options.offset !== void 0) params.set("offset", String(options.offset));
11339
+ return this._get(`/trends/top?${params}`);
11340
+ }
11341
+ /**
11342
+ * Find prompts matching user preferences
11343
+ *
11344
+ * Note: This endpoint is not yet implemented in the backend.
11345
+ * This is a placeholder for future implementation.
11346
+ * @param {object} preferences - User preferences
11347
+ * @param {string[]} [preferences.recentPrompts] - Recent prompt CIDs
11348
+ * @param {string[]} [preferences.preferredTags] - Preferred tags
11349
+ * @param {string[]} [preferences.preferredCategories] - Preferred categories
11350
+ * @param {string[]} [preferences.excludeAuthors] - Authors to exclude
11351
+ * @param {number} [preferences.limit] - Max results
11352
+ * @param {boolean} [preferences.diversify] - Diversify results
11353
+ * @returns {Promise<{results: Array, total: number}>}
11354
+ */
11355
+ async match(preferences) {
11356
+ return this._post("/discover/match", preferences);
11357
+ }
11358
+ /**
11359
+ * Find prompts similar to a given prompt
11360
+ * @param {string} cid - Prompt CID to find similar prompts for
11361
+ * @param {object} [options] - Similar options
11362
+ * @param {number} [options.limit] - Max results to return
11363
+ * @param {'vector'|'keyword'|'hybrid'} [options.method] - Similarity method
11364
+ * @returns {Promise<{similar: Array}>}
11365
+ */
11366
+ async similar(cid, options = {}) {
11367
+ const params = new URLSearchParams();
11368
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11369
+ if (options.method) params.set("method", options.method);
11370
+ return this._get(`/discover/similar/${cid}?${params}`);
11371
+ }
11372
+ /**
11373
+ * Get popular tags with optional clustering
11374
+ * @param {object} [options] - Tags options
11375
+ * @param {number} [options.limit] - Max tags to return
11376
+ * @param {string} [options.category] - Filter by category
11377
+ * @param {boolean} [options.clusters] - Enable tag clustering
11378
+ * @returns {Promise<{tags: Array}>}
11379
+ */
11380
+ async tags(options = {}) {
11381
+ const params = new URLSearchParams();
11382
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11383
+ if (options.category) params.set("category", options.category);
11384
+ if (options.clusters !== void 0) params.set("clusters", String(options.clusters));
11385
+ return this._get(`/discover/tags?${params}`);
11386
+ }
11387
+ /**
11388
+ * Get category statistics
11389
+ *
11390
+ * Note: This endpoint is not yet implemented in the backend.
11391
+ * This is a placeholder for future implementation.
11392
+ * @returns {Promise<{categories: Array}>}
11393
+ */
11394
+ async categories() {
11395
+ return this._get("/discover/categories");
11396
+ }
11397
+ /**
11398
+ * Get prompts by tag
11399
+ * @param {string} tag - Tag to search for
11400
+ * @param {number} [limit] - Max results to return
11401
+ * @returns {Promise<{results: Array}>}
11402
+ */
11403
+ async promptsByTag(tag, limit) {
11404
+ const params = new URLSearchParams();
11405
+ if (limit !== void 0) params.set("limit", String(limit));
11406
+ const encodedTag = encodeURIComponent(tag);
11407
+ return this._get(`/discover/by-tag/${encodedTag}?${params}`);
11408
+ }
11409
+ /**
11410
+ * Get index statistics
11411
+ * @returns {Promise<{totalPrompts: number, totalTags: number, avgTrendScore: number}>}
11412
+ */
11413
+ async stats() {
11414
+ return this._get("/discover/stats");
11415
+ }
11416
+ /**
11417
+ * Get trend signals for a specific CID
11418
+ * @param {string} cid - Prompt CID
11419
+ * @returns {Promise<{usageCount: number, forkCount: number, purchaseCount: number, uniqueBuyers: number, governanceVotes: number, lastActivityAt: number}>}
11420
+ */
11421
+ async trendSignals(cid) {
11422
+ return this._get(`/trends/signals/${cid}`);
11423
+ }
11424
+ /**
11425
+ * Get trend history for a specific CID
11426
+ * @param {string} cid - Prompt CID
11427
+ * @param {object} [options] - History options
11428
+ * @param {number} [options.limit] - Max history entries
11429
+ * @param {number} [options.since] - Timestamp to start from
11430
+ * @returns {Promise<{history: Array}>}
11431
+ */
11432
+ async trendHistory(cid, options = {}) {
11433
+ const params = new URLSearchParams();
11434
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11435
+ if (options.since !== void 0) params.set("since", String(options.since));
11436
+ return this._get(`/trends/history/${cid}?${params}`);
11437
+ }
11438
+ /**
11439
+ * Get trend statistics
11440
+ * @returns {Promise<{totalTracked: number, avgScore: number, maxScore: number, recentlyActive: number}>}
11441
+ */
11442
+ async trendStats() {
11443
+ return this._get("/trends/stats");
11444
+ }
11445
+ /**
11446
+ * Record a usage event for a prompt (requires authentication)
11447
+ * @param {string} cid - Prompt CID
11448
+ * @returns {Promise<{ok: boolean}>}
11449
+ */
11450
+ async recordUsage(cid) {
11451
+ return this._post("/trends/usage", { cid });
11452
+ }
11453
+ // Private fetch helpers
11454
+ /**
11455
+ * Perform a GET request
11456
+ * @private
11457
+ * @param {string} path - API path
11458
+ * @returns {Promise<any>}
11459
+ */
11460
+ async _get(path2) {
11461
+ const controller = new AbortController();
11462
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
11463
+ try {
11464
+ const response = await fetch(`${this.baseUrl}${path2}`, {
11465
+ method: "GET",
11466
+ headers: {
11467
+ "Accept": "application/json",
11468
+ ...this.headers
11469
+ },
11470
+ signal: controller.signal
11471
+ });
11472
+ clearTimeout(timeoutId);
11473
+ if (!response.ok) {
11474
+ const errorBody = await response.text().catch(() => "Unknown error");
11475
+ throw new Error(`HTTP ${response.status}: ${errorBody}`);
11476
+ }
11477
+ return await response.json();
11478
+ } catch (error) {
11479
+ clearTimeout(timeoutId);
11480
+ if (error.name === "AbortError") {
11481
+ throw new Error(`Request timeout after ${this.timeout}ms`);
11482
+ }
11483
+ throw error;
11484
+ }
11485
+ }
11486
+ /**
11487
+ * Perform a POST request
11488
+ * @private
11489
+ * @param {string} path - API path
11490
+ * @param {any} body - Request body
11491
+ * @returns {Promise<any>}
11492
+ */
11493
+ async _post(path2, body) {
11494
+ const controller = new AbortController();
11495
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
11496
+ try {
11497
+ const response = await fetch(`${this.baseUrl}${path2}`, {
11498
+ method: "POST",
11499
+ headers: {
11500
+ "Accept": "application/json",
11501
+ "Content-Type": "application/json",
11502
+ ...this.headers
11503
+ },
11504
+ body: JSON.stringify(body),
11505
+ signal: controller.signal
11506
+ });
11507
+ clearTimeout(timeoutId);
11508
+ if (!response.ok) {
11509
+ const errorBody = await response.text().catch(() => "Unknown error");
11510
+ throw new Error(`HTTP ${response.status}: ${errorBody}`);
11511
+ }
11512
+ return await response.json();
11513
+ } catch (error) {
11514
+ clearTimeout(timeoutId);
11515
+ if (error.name === "AbortError") {
11516
+ throw new Error(`Request timeout after ${this.timeout}ms`);
11517
+ }
11518
+ throw error;
11519
+ }
11520
+ }
11521
+ };
11522
+ module2.exports = { DiscoveryClient };
11523
+ }
11524
+ });
11525
+
11526
+ // src/clients/index.js
11527
+ var require_clients = __commonJS({
11528
+ "src/clients/index.js"(exports2, module2) {
11529
+ var { DiscoveryClient } = require_discovery_client();
11530
+ module2.exports = {
11531
+ DiscoveryClient
11532
+ };
11533
+ }
11534
+ });
11535
+
9913
11536
  // src/hooks/useSubDAOs.js
9914
11537
  var require_useSubDAOs = __commonJS({
9915
11538
  "src/hooks/useSubDAOs.js"(exports2, module2) {
@@ -10120,6 +11743,7 @@ var require_src = __commonJS({
10120
11743
  var timelock = require_timelock();
10121
11744
  var factory = require_factory();
10122
11745
  var library = require_library();
11746
+ var lineage = require_lineage();
10123
11747
  var prompt = require_prompt();
10124
11748
  var { SageEchoExecutor } = require_execute();
10125
11749
  var ipfs = require_ipfs();
@@ -10133,6 +11757,8 @@ var require_src = __commonJS({
10133
11757
  var treasury = require_treasury();
10134
11758
  var boost = require_boost();
10135
11759
  var bounty = require_bounty();
11760
+ var votingMultiplier = require_votingMultiplier();
11761
+ var auction = require_auction();
10136
11762
  var wallet = require_wallet();
10137
11763
  wallet.session = require_session();
10138
11764
  var walletCastManager = require_cast_manager();
@@ -10153,6 +11779,7 @@ var require_src = __commonJS({
10153
11779
  var serviceErrors = require_errors2();
10154
11780
  var { SimpleCache } = require_cache();
10155
11781
  var { retryWithBackoff } = require_retry();
11782
+ var { DiscoveryClient } = require_clients();
10156
11783
  var hooks = null;
10157
11784
  try {
10158
11785
  hooks = require_hooks();
@@ -10168,6 +11795,7 @@ var require_src = __commonJS({
10168
11795
  timelock,
10169
11796
  factory,
10170
11797
  library,
11798
+ lineage,
10171
11799
  prompt,
10172
11800
  ipfs,
10173
11801
  ipns,
@@ -10180,6 +11808,8 @@ var require_src = __commonJS({
10180
11808
  subgraph,
10181
11809
  utils: { ...utils, privateTx, safe, time },
10182
11810
  bounty,
11811
+ votingMultiplier,
11812
+ auction,
10183
11813
  wallet: Object.assign(wallet, {
10184
11814
  cast: walletCastManager,
10185
11815
  cdp: walletCdpManager
@@ -10200,6 +11830,11 @@ var require_src = __commonJS({
10200
11830
  SimpleCache,
10201
11831
  retryWithBackoff
10202
11832
  },
11833
+ // Client exports
11834
+ clients: {
11835
+ DiscoveryClient
11836
+ },
11837
+ DiscoveryClient,
10203
11838
  // React hooks (optional - requires react + swr peer dependencies)
10204
11839
  hooks,
10205
11840
  // Legacy exports (deprecated): maintain compatibility while consumers migrate