@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.
@@ -14,7 +14,7 @@ var require_package = __commonJS({
14
14
  "package.json"(exports2, module2) {
15
15
  module2.exports = {
16
16
  name: "@sage-protocol/sdk",
17
- version: "0.1.18",
17
+ version: "0.1.21",
18
18
  description: "Backend-agnostic SDK for interacting with the Sage Protocol (governance, SubDAOs, tokens).",
19
19
  main: "dist/index.cjs",
20
20
  module: "dist/index.mjs",
@@ -130,7 +130,6 @@ var require_abi = __commonJS({
130
130
  "function stableCreationFee() view returns (uint256)",
131
131
  "function stableFeeReceiver() view returns (address)",
132
132
  "function stableCreationEnabled() view returns (bool)",
133
- "function stablePromptForkFee() view returns (uint256)",
134
133
  "function stableForkFee() view returns (uint256)",
135
134
  // Core factory reads
136
135
  "function timelockMinDelay() view returns (uint256)",
@@ -172,13 +171,18 @@ var require_abi = __commonJS({
172
171
  "function maxCreationBurn() view returns (uint256)"
173
172
  ];
174
173
  var LibraryRegistry = [
175
- "function libraryByDAO(address) view returns (string manifestCID, address lastUpdater, uint256 lastUpdated, string version)",
174
+ "function libraryByDAO(address) view returns (string manifestCID, address lastUpdater, uint256 lastUpdated, string version, address forkedFromDAO, uint256 sxxxForkFee)",
176
175
  "function daoTimelock(address) view returns (address)",
177
- "function getLibrary(address) view returns (tuple(string manifestCID, address lastUpdater, uint256 lastUpdated, string version))",
176
+ "function getLibrary(address) view returns (tuple(string manifestCID, address lastUpdater, uint256 lastUpdated, string version, address forkedFromDAO, uint256 sxxxForkFee))",
177
+ "function getLibraryForkFee(address dao) view returns (uint256)",
178
+ "function setLibraryForkFee(address dao, uint256 fee)",
178
179
  "function updateLibrary(address dao, string manifestCID, string version)",
179
180
  "function registerDAO(address dao, address timelock)",
181
+ "function registerForkedDAO(address childDAO, address childTimelock, address parentDAO, string manifestCID, string version)",
180
182
  "event LibraryUpdated(address indexed dao, string manifestCID, address indexed timelock, string version)",
181
- "event DAORegistered(address indexed dao, address indexed timelock)"
183
+ "event DAORegistered(address indexed dao, address indexed timelock)",
184
+ "event LibraryForked(address indexed parentDAO, address indexed childDAO)",
185
+ "event LibraryForkFeeUpdated(address indexed dao, uint256 fee)"
182
186
  ];
183
187
  var PromptRegistry = [
184
188
  "function prompts(string key) view returns (string cid, uint256 version, uint256 timestamp, address author, string forkedFromCID, address originalAuthor, bool isFork, uint256 forkDepth)",
@@ -1750,7 +1754,6 @@ var require_ipfs = __commonJS({
1750
1754
  headers["X-Wallet-Address"] = auth.address;
1751
1755
  headers["X-Wallet-Signature"] = auth.signature;
1752
1756
  headers["X-Wallet-Nonce"] = auth.nonce;
1753
- headers["X-Wallet-Message"] = auth.message;
1754
1757
  }
1755
1758
  return { headers, auth };
1756
1759
  }
@@ -1771,8 +1774,7 @@ var require_ipfs = __commonJS({
1771
1774
  ...extraHeaders,
1772
1775
  "X-Wallet-Address": auth.address,
1773
1776
  "X-Wallet-Signature": auth.signature,
1774
- "X-Wallet-Nonce": auth.nonce,
1775
- "X-Wallet-Message": auth.message
1777
+ "X-Wallet-Nonce": auth.nonce
1776
1778
  };
1777
1779
  return { headers, auth };
1778
1780
  }
@@ -1793,6 +1795,13 @@ var require_ipfs = __commonJS({
1793
1795
  order.push(name);
1794
1796
  };
1795
1797
  const normalizedPreference = Array.isArray(preference) ? preference.map((p) => toLowerSafe(p)).filter(Boolean) : preference ? [toLowerSafe(preference)].filter(Boolean) : [];
1798
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
1799
+ console.log("[SDK DEBUG] resolveProviderOrder preference:", preference);
1800
+ console.log("[SDK DEBUG] normalizedPreference:", normalizedPreference);
1801
+ console.log("[SDK DEBUG] config.provider:", config.provider);
1802
+ console.log("[SDK DEBUG] shouldUseWorker():", shouldUseWorker());
1803
+ console.log("[SDK DEBUG] hasPinataCreds():", hasPinataCreds());
1804
+ }
1796
1805
  normalizedPreference.forEach(append);
1797
1806
  if (shouldUseWorker()) append("worker");
1798
1807
  if (hasPinataCreds()) append("pinata");
@@ -1800,17 +1809,90 @@ var require_ipfs = __commonJS({
1800
1809
  if (config.simulate) append("simulate");
1801
1810
  return order;
1802
1811
  }
1803
- async function uploadViaWorker(payload, { warm, gateways } = {}) {
1812
+ async function uploadViaWorker(payload, { warm, gateways, pin: pin2 } = {}) {
1813
+ const uploadUrl = workerUrl("upload");
1814
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
1815
+ console.log("[SDK DEBUG] uploadViaWorker called");
1816
+ console.log("[SDK DEBUG] workerBaseUrl:", workerBaseUrl());
1817
+ console.log("[SDK DEBUG] uploadUrl:", uploadUrl);
1818
+ console.log("[SDK DEBUG] workerHasAuth:", workerHasAuth());
1819
+ }
1804
1820
  const { headers, auth } = await buildWorkerAuthHeaders({ "Content-Type": "application/json" });
1805
1821
  const body = { ...payload };
1806
1822
  if (auth) body.auth = auth;
1807
- const response = await axiosInstance.post(workerUrl("upload"), body, { headers, timeout: config.timeoutMs });
1808
- const cid = response?.data?.cid || response?.data?.IpfsHash;
1823
+ if (pin2) {
1824
+ body.pin = typeof pin2 === "string" ? { duration: pin2 } : pin2;
1825
+ }
1826
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
1827
+ console.log("[SDK DEBUG] headers:", Object.keys(headers));
1828
+ console.log("[SDK DEBUG] hasAuth:", !!auth);
1829
+ if (pin2) console.log("[SDK DEBUG] pin:", JSON.stringify(body.pin));
1830
+ }
1831
+ let response;
1832
+ try {
1833
+ response = await axiosInstance.post(uploadUrl, body, { headers, timeout: config.timeoutMs });
1834
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
1835
+ console.log("[SDK DEBUG] Upload response status:", response?.status);
1836
+ console.log("[SDK DEBUG] Upload response data:", JSON.stringify(response?.data || {}));
1837
+ }
1838
+ } catch (uploadErr) {
1839
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
1840
+ console.log("[SDK DEBUG] Upload error:", uploadErr.message);
1841
+ console.log("[SDK DEBUG] Response status:", uploadErr.response?.status);
1842
+ console.log("[SDK DEBUG] Response data:", JSON.stringify(uploadErr.response?.data || {}));
1843
+ }
1844
+ const status = uploadErr.response?.status;
1845
+ const data2 = uploadErr.response?.data;
1846
+ if (status === 400 && data2?.error === "content_blocked") {
1847
+ const error = new Error("content_blocked");
1848
+ error.code = "CONTENT_BLOCKED";
1849
+ error.categories = data2.categories || [];
1850
+ error.reason = data2.reason;
1851
+ error.response = data2;
1852
+ throw error;
1853
+ }
1854
+ if (status === 402) {
1855
+ const error = new Error("payment_required");
1856
+ error.code = "PAYMENT_REQUIRED";
1857
+ error.creditsNeeded = data2?.creditsNeeded;
1858
+ error.balance = data2?.balance;
1859
+ error.duration = data2?.duration;
1860
+ error.accepts = data2?.accepts;
1861
+ error.response = data2;
1862
+ throw error;
1863
+ }
1864
+ throw uploadErr;
1865
+ }
1866
+ const data = response?.data || {};
1867
+ const cid = data.cid || data.IpfsHash;
1868
+ if (response?.status === 202 || data.status === "pending_review") {
1869
+ return {
1870
+ cid: cid || null,
1871
+ provider: "worker",
1872
+ status: "pending_review",
1873
+ categories: data.categories || [],
1874
+ response: data
1875
+ };
1876
+ }
1809
1877
  if (!cid) {
1810
1878
  throw new Error("Worker response missing cid");
1811
1879
  }
1812
1880
  if (warm || config.shouldWarm) await warmGateways(cid, { gateways });
1813
- return { cid, provider: "worker", response: response?.data || null };
1881
+ const result = {
1882
+ cid,
1883
+ provider: "worker",
1884
+ response: data
1885
+ };
1886
+ if (data.moderation) {
1887
+ result.moderation = data.moderation;
1888
+ }
1889
+ if (data.pinned !== void 0) {
1890
+ result.pinned = data.pinned;
1891
+ result.expiresAt = data.expiresAt;
1892
+ result.creditsPaid = data.creditsPaid;
1893
+ result.urls = data.urls;
1894
+ }
1895
+ return result;
1814
1896
  }
1815
1897
  async function uploadToPinata(payload, { filename = "payload.json", metadata, warm, gateways } = {}) {
1816
1898
  if (!hasPinataCreds()) {
@@ -1888,7 +1970,7 @@ var require_ipfs = __commonJS({
1888
1970
  return { cid, provider: "simulate" };
1889
1971
  }
1890
1972
  async function uploadPayload(payload, options2 = {}) {
1891
- const { providers, provider, warm, gateways, filename, metadata } = options2;
1973
+ const { providers, provider, warm, gateways, filename, metadata, pin: pin2 } = options2;
1892
1974
  const order = resolveProviderOrder(providers || provider);
1893
1975
  if (!order.length) {
1894
1976
  throw new Error("No IPFS providers configured. Set Pinata credentials, worker upload, or enable test mode");
@@ -1897,7 +1979,7 @@ var require_ipfs = __commonJS({
1897
1979
  for (const candidate of order) {
1898
1980
  try {
1899
1981
  if (candidate === "worker") {
1900
- return await uploadViaWorker(payload, { warm, gateways });
1982
+ return await uploadViaWorker(payload, { warm, gateways, pin: pin2 });
1901
1983
  }
1902
1984
  if (candidate === "pinata") {
1903
1985
  return await uploadToPinata(payload, { filename, metadata, warm, gateways });
@@ -1909,6 +1991,9 @@ var require_ipfs = __commonJS({
1909
1991
  return await uploadSimulated(payload, { warm, gateways });
1910
1992
  }
1911
1993
  } catch (error2) {
1994
+ if (error2.code === "CONTENT_BLOCKED" || error2.code === "PAYMENT_REQUIRED") {
1995
+ throw error2;
1996
+ }
1912
1997
  errors.push({ provider: candidate, error: error2 });
1913
1998
  }
1914
1999
  }
@@ -1917,7 +2002,7 @@ var require_ipfs = __commonJS({
1917
2002
  throw error;
1918
2003
  }
1919
2004
  async function uploadPrompt(options2 = {}) {
1920
- const { prompt, providers, provider, warm, gateways } = options2;
2005
+ const { prompt, providers, provider, warm, gateways, pin: pin2 } = options2;
1921
2006
  if (!prompt || typeof prompt !== "object") {
1922
2007
  throw new Error("prompt payload required");
1923
2008
  }
@@ -1943,6 +2028,7 @@ var require_ipfs = __commonJS({
1943
2028
  provider,
1944
2029
  warm,
1945
2030
  gateways,
2031
+ pin: pin2,
1946
2032
  filename: `${prompt.name || "prompt"}.json`,
1947
2033
  metadata
1948
2034
  });
@@ -2177,8 +2263,7 @@ var require_ipfs = __commonJS({
2177
2263
  "Content-Type": "application/json",
2178
2264
  "X-Wallet-Address": address,
2179
2265
  "X-Wallet-Signature": signature,
2180
- "X-Wallet-Nonce": nonce,
2181
- "X-Wallet-Message": message
2266
+ "X-Wallet-Nonce": nonce
2182
2267
  };
2183
2268
  let verified = false;
2184
2269
  try {
@@ -3036,13 +3121,10 @@ var require_governance = __commonJS({
3036
3121
  } else {
3037
3122
  const govAddr = normaliseGovernor(governor);
3038
3123
  try {
3039
- const iface = new Interface(["function sxxxToken() view returns (address)"]);
3040
- const data = iface.encodeFunctionData("sxxxToken", []);
3041
- const ret = await provider.call({ to: govAddr, data });
3042
- const [tok] = AbiCoder.defaultAbiCoder().decode(["address"], ret);
3043
- addr = getAddress(tok);
3124
+ const chain = await resolveVotesTokenChain({ provider, governor: govAddr });
3125
+ addr = getAddress(chain.votingToken);
3044
3126
  } catch (err) {
3045
- throw new SageSDKError(CODES.NOT_FOUND, "failed to resolve governance token from governor", { cause: err });
3127
+ throw new SageSDKError(CODES.NOT_FOUND, "failed to resolve votes token from governor", { cause: err });
3046
3128
  }
3047
3129
  }
3048
3130
  const user = getAddress(account);
@@ -3123,6 +3205,210 @@ var require_governance = __commonJS({
3123
3205
  const token = await g.sxxxToken();
3124
3206
  return buildDelegateTx({ token, delegatee: account });
3125
3207
  }
3208
+ async function resolveVotesTokenChain({ provider, subdao, governor }) {
3209
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3210
+ if (!subdao && !governor) throw new SageSDKError(CODES.INVALID_ARGS, "subdao or governor required");
3211
+ let votingToken = null;
3212
+ if (governor) {
3213
+ const govAddr = normaliseGovernor(governor);
3214
+ try {
3215
+ const iTok = new Interface(["function token() view returns (address)"]);
3216
+ const data = iTok.encodeFunctionData("token", []);
3217
+ const ret = await provider.call({ to: govAddr, data });
3218
+ if (ret && ret !== "0x") {
3219
+ const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], ret);
3220
+ votingToken = addr;
3221
+ }
3222
+ } catch (_) {
3223
+ }
3224
+ if (!votingToken) {
3225
+ try {
3226
+ const iGov = new Interface(["function sxxxToken() view returns (address)"]);
3227
+ const d2 = iGov.encodeFunctionData("sxxxToken", []);
3228
+ const r2 = await provider.call({ to: govAddr, data: d2 });
3229
+ if (r2 && r2 !== "0x") {
3230
+ const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], r2);
3231
+ votingToken = addr;
3232
+ }
3233
+ } catch (_) {
3234
+ }
3235
+ }
3236
+ }
3237
+ if (!votingToken && subdao) {
3238
+ try {
3239
+ const subAddr = getAddress(subdao);
3240
+ const iSub = new Interface(["function stakeToken() view returns (address)"]);
3241
+ const d3 = iSub.encodeFunctionData("stakeToken", []);
3242
+ const r3 = await provider.call({ to: subAddr, data: d3 });
3243
+ if (r3 && r3 !== "0x") {
3244
+ const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], r3);
3245
+ votingToken = addr;
3246
+ }
3247
+ } catch (_) {
3248
+ }
3249
+ }
3250
+ if (!votingToken) {
3251
+ throw new SageSDKError(CODES.NOT_FOUND, "failed to resolve votes token");
3252
+ }
3253
+ const votingTokenNorm = getAddress(votingToken);
3254
+ let baseToken = votingTokenNorm;
3255
+ let isWrapper = false;
3256
+ try {
3257
+ const wrapperIface = new Interface([
3258
+ "function baseToken() view returns (address)",
3259
+ "function dao() view returns (address)"
3260
+ ]);
3261
+ const [rawBase, rawDao] = await Promise.all([
3262
+ provider.call({ to: votingTokenNorm, data: wrapperIface.encodeFunctionData("baseToken", []) }),
3263
+ provider.call({ to: votingTokenNorm, data: wrapperIface.encodeFunctionData("dao", []) })
3264
+ ]);
3265
+ if (rawBase && rawBase !== "0x" && rawDao && rawDao !== "0x") {
3266
+ const [decodedBase] = AbiCoder.defaultAbiCoder().decode(["address"], rawBase);
3267
+ const [decodedDao] = AbiCoder.defaultAbiCoder().decode(["address"], rawDao);
3268
+ const baseNorm = getAddress(decodedBase);
3269
+ const daoNorm = getAddress(decodedDao);
3270
+ if (!subdao || daoNorm === getAddress(subdao)) {
3271
+ baseToken = baseNorm;
3272
+ isWrapper = true;
3273
+ }
3274
+ }
3275
+ } catch (_) {
3276
+ }
3277
+ return { votingToken: votingTokenNorm, baseToken, isWrapper };
3278
+ }
3279
+ async function describeVotesToken({ provider, subdao, governor }) {
3280
+ const { votingToken, baseToken, isWrapper } = await resolveVotesTokenChain({ provider, subdao, governor });
3281
+ let multiplierNFT = null;
3282
+ let basis = null;
3283
+ if (isWrapper) {
3284
+ try {
3285
+ const wrapper = new Contract(votingToken, ABI.MultipliedVotes, provider);
3286
+ multiplierNFT = await wrapper.multiplierNFT().catch(() => null);
3287
+ basis = await wrapper.BASIS().catch(() => null);
3288
+ } catch (_) {
3289
+ }
3290
+ }
3291
+ const votingNorm = getAddress(votingToken);
3292
+ const baseNorm = getAddress(baseToken);
3293
+ const multiplierNorm = multiplierNFT && /^0x[0-9a-fA-F]{40}$/.test(String(multiplierNFT)) ? getAddress(multiplierNFT) : null;
3294
+ const basisBig = basis != null ? BigInt(String(basis)) : null;
3295
+ let description;
3296
+ if (!isWrapper) {
3297
+ description = `Voting token = ERC20Votes at ${votingNorm}`;
3298
+ } else {
3299
+ const basisStr = basisBig != null ? basisBig.toString() : "10000";
3300
+ description = `Voting token = MultipliedVotes(base=${baseNorm}, multiplierNFT=${multiplierNorm || "unknown"}, BASIS=${basisStr})`;
3301
+ if (subdao) {
3302
+ description += ` for DAO ${getAddress(subdao)}`;
3303
+ }
3304
+ }
3305
+ return {
3306
+ votingToken: votingNorm,
3307
+ baseToken: baseNorm,
3308
+ isWrapper,
3309
+ multiplierNFT: multiplierNorm,
3310
+ basis: basisBig,
3311
+ description
3312
+ };
3313
+ }
3314
+ async function getVotingStatus({ provider, subdao, governor, account }) {
3315
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3316
+ if (!governor && !subdao) throw new SageSDKError(CODES.INVALID_ARGS, "governor or subdao required");
3317
+ if (!account) throw new SageSDKError(CODES.INVALID_ARGS, "account required");
3318
+ const acct = getAddress(account);
3319
+ let govAddr = null;
3320
+ let subdaoAddr = null;
3321
+ if (governor) {
3322
+ govAddr = normaliseGovernor(governor);
3323
+ }
3324
+ if (subdao) {
3325
+ subdaoAddr = getAddress(subdao);
3326
+ if (!govAddr) {
3327
+ try {
3328
+ const sub = new Contract(subdaoAddr, ["function governor() view returns (address)"], provider);
3329
+ govAddr = getAddress(await sub.governor());
3330
+ } catch (_) {
3331
+ }
3332
+ }
3333
+ }
3334
+ if (!govAddr) throw new SageSDKError(CODES.INVALID_ARGS, "could not resolve governor address");
3335
+ let threshold = null;
3336
+ try {
3337
+ const g = new Contract(govAddr, ABI.Governor, provider);
3338
+ const t = await g.proposalThreshold();
3339
+ threshold = BigInt(t.toString());
3340
+ } catch (_) {
3341
+ }
3342
+ const desc = await describeVotesToken({ provider, subdao: subdaoAddr || void 0, governor: govAddr });
3343
+ let stakeToken = null;
3344
+ if (subdaoAddr) {
3345
+ try {
3346
+ const sub = new Contract(subdaoAddr, ["function stakeToken() view returns (address)"], provider);
3347
+ const st = await sub.stakeToken();
3348
+ if (st && /^0x[0-9a-fA-F]{40}$/.test(String(st))) {
3349
+ stakeToken = getAddress(st);
3350
+ }
3351
+ } catch (_) {
3352
+ }
3353
+ }
3354
+ const VotesABI = [
3355
+ "function getVotes(address) view returns (uint256)",
3356
+ "function delegates(address) view returns (address)",
3357
+ "function balanceOf(address) view returns (uint256)"
3358
+ ];
3359
+ let votingPower = null;
3360
+ let delegate = null;
3361
+ let tokenBalance = null;
3362
+ try {
3363
+ const votingC = new Contract(desc.votingToken, VotesABI, provider);
3364
+ const vp = await votingC.getVotes(acct).catch(() => null);
3365
+ if (vp != null) votingPower = BigInt(vp.toString());
3366
+ const del = await votingC.delegates(acct).catch(() => null);
3367
+ if (del && /^0x[0-9a-fA-F]{40}$/.test(String(del))) delegate = getAddress(del);
3368
+ const bal = await votingC.balanceOf(acct).catch(() => null);
3369
+ if (bal != null) tokenBalance = BigInt(bal.toString());
3370
+ } catch (_) {
3371
+ }
3372
+ const canPropose = threshold != null && votingPower != null ? votingPower >= threshold : null;
3373
+ let stakeTokenVotes = null;
3374
+ let stakeTokenDelegate = null;
3375
+ let stakeTokenBalance = null;
3376
+ const tokenMismatch = !!stakeToken && stakeToken.toLowerCase() !== desc.votingToken.toLowerCase();
3377
+ if (stakeToken && tokenMismatch) {
3378
+ try {
3379
+ const stakeC = new Contract(stakeToken, VotesABI, provider);
3380
+ const sv = await stakeC.getVotes(acct).catch(() => null);
3381
+ if (sv != null) stakeTokenVotes = BigInt(sv.toString());
3382
+ const sd = await stakeC.delegates(acct).catch(() => null);
3383
+ if (sd && /^0x[0-9a-fA-F]{40}$/.test(String(sd))) {
3384
+ stakeTokenDelegate = getAddress(sd);
3385
+ }
3386
+ const sb = await stakeC.balanceOf(acct).catch(() => null);
3387
+ if (sb != null) stakeTokenBalance = BigInt(sb.toString());
3388
+ } catch (_) {
3389
+ }
3390
+ }
3391
+ return {
3392
+ subdao: subdaoAddr,
3393
+ governor: govAddr,
3394
+ stakeToken,
3395
+ votingToken: desc.votingToken,
3396
+ baseToken: desc.baseToken,
3397
+ isWrapper: desc.isWrapper,
3398
+ multiplierNFT: desc.multiplierNFT,
3399
+ basis: desc.basis,
3400
+ threshold,
3401
+ votingPower,
3402
+ tokenBalance,
3403
+ delegate,
3404
+ canPropose,
3405
+ tokenMismatch,
3406
+ stakeTokenVotes,
3407
+ stakeTokenDelegate,
3408
+ stakeTokenBalance,
3409
+ description: desc.description
3410
+ };
3411
+ }
3126
3412
  module2.exports = {
3127
3413
  getGovernorInfo,
3128
3414
  getProposal,
@@ -3154,52 +3440,28 @@ var require_governance = __commonJS({
3154
3440
  * - SubDAO.stakeToken() (when subdao provided)
3155
3441
  */
3156
3442
  resolveVotesToken: async function resolveVotesToken({ provider, subdao, governor }) {
3157
- if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3158
- if (!subdao && !governor) throw new SageSDKError(CODES.INVALID_ARGS, "subdao or governor required");
3159
- if (governor) {
3160
- const govAddr = normaliseGovernor(governor);
3161
- try {
3162
- const iTok = new Interface(["function token() view returns (address)"]);
3163
- const data = iTok.encodeFunctionData("token", []);
3164
- const ret = await provider.call({ to: govAddr, data });
3165
- if (ret && ret !== "0x") {
3166
- const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], ret);
3167
- return getAddress(addr);
3168
- }
3169
- } catch (_) {
3170
- }
3171
- try {
3172
- const iGov = new Interface(["function sxxxToken() view returns (address)"]);
3173
- const d2 = iGov.encodeFunctionData("sxxxToken", []);
3174
- const r2 = await provider.call({ to: govAddr, data: d2 });
3175
- if (r2 && r2 !== "0x") {
3176
- const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], r2);
3177
- return getAddress(addr);
3178
- }
3179
- } catch (_) {
3180
- }
3181
- }
3182
- if (subdao) {
3183
- try {
3184
- const subAddr = getAddress(subdao);
3185
- const iSub = new Interface(["function stakeToken() view returns (address)"]);
3186
- const d3 = iSub.encodeFunctionData("stakeToken", []);
3187
- const r3 = await provider.call({ to: subAddr, data: d3 });
3188
- if (r3 && r3 !== "0x") {
3189
- const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], r3);
3190
- return getAddress(addr);
3191
- }
3192
- } catch (_) {
3193
- }
3194
- }
3195
- throw new SageSDKError(CODES.NOT_FOUND, "failed to resolve votes token");
3443
+ const { votingToken } = await resolveVotesTokenChain({ provider, subdao, governor });
3444
+ return votingToken;
3196
3445
  },
3446
+ /**
3447
+ * Resolve the IVotes token chain used for voting (wrapper + base token).
3448
+ * See resolveVotesTokenChain() for details.
3449
+ */
3450
+ resolveVotesTokenChain,
3451
+ /**
3452
+ * Human-friendly description of the voting token wiring for a Governor/SubDAO.
3453
+ */
3454
+ describeVotesToken,
3455
+ /**
3456
+ * Get voting status for an account relative to a Governor/SubDAO.
3457
+ */
3458
+ getVotingStatus,
3197
3459
  /** Build a delegate(self) tx using the preferred votes token resolution path. */
3198
3460
  buildDelegateSelfPreferred: async function buildDelegateSelfPreferred({ provider, subdao, governor, account }) {
3199
3461
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3200
3462
  if (!account) throw new SageSDKError(CODES.INVALID_ARGS, "account required");
3201
- const token = await this.resolveVotesToken({ provider, subdao, governor });
3202
- return buildDelegateTx({ token, delegatee: account });
3463
+ const { baseToken } = await resolveVotesTokenChain({ provider, subdao, governor });
3464
+ return buildDelegateTx({ token: baseToken, delegatee: account });
3203
3465
  },
3204
3466
  /**
3205
3467
  * Send a delegate(self) and verify votes at latest-1.
@@ -3208,15 +3470,15 @@ var require_governance = __commonJS({
3208
3470
  delegateSelfAndVerify: async function delegateSelfAndVerify({ provider, subdao, governor, account, signer = null, minVotes = null }) {
3209
3471
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3210
3472
  if (!account) throw new SageSDKError(CODES.INVALID_ARGS, "account required");
3211
- const token = await this.resolveVotesToken({ provider, subdao, governor });
3212
- const payload = buildDelegateTx({ token, delegatee: account });
3473
+ const { votingToken, baseToken } = await resolveVotesTokenChain({ provider, subdao, governor });
3474
+ const payload = buildDelegateTx({ token: baseToken, delegatee: account });
3213
3475
  let txHash = null;
3214
3476
  if (signer && typeof signer.sendTransaction === "function") {
3215
3477
  const tx = await signer.sendTransaction({ to: payload.to, data: payload.data, value: payload.value });
3216
3478
  txHash = tx?.hash || null;
3217
3479
  if (tx?.wait) await tx.wait();
3218
3480
  }
3219
- const votes = await getVotesLatestMinusOne({ provider, token, account });
3481
+ const votes = await getVotesLatestMinusOne({ provider, token: votingToken, account });
3220
3482
  const ok = minVotes != null ? votes >= BigInt(minVotes) : votes > 0n;
3221
3483
  return { txHash, ok, votes, payload };
3222
3484
  },
@@ -3270,8 +3532,8 @@ var require_governance = __commonJS({
3270
3532
  }
3271
3533
  let votesOk = null;
3272
3534
  try {
3273
- const token = sxxx || await this.resolveVotesToken({ provider, governor });
3274
- const votes = await getVotesLatestMinusOne({ provider, token, account: user });
3535
+ const { votingToken } = await resolveVotesTokenChain({ provider, governor });
3536
+ const votes = await getVotesLatestMinusOne({ provider, token: votingToken, account: user });
3275
3537
  const th = threshold != null ? BigInt(threshold) : 0n;
3276
3538
  votesOk = votes >= th;
3277
3539
  } catch (_) {
@@ -3795,12 +4057,608 @@ var require_templates = __commonJS({
3795
4057
  if (depositOnly) {
3796
4058
  actions.push(() => governorContract.setDepositOnlyMode(true));
3797
4059
  }
3798
- const receipts = await executeSequence(actions);
3799
- return { governor, timelock, receipts };
3800
- }
3801
- module2.exports = {
3802
- communityDraftsBoardExec,
3803
- tokenDemocracy
4060
+ const receipts = await executeSequence(actions);
4061
+ return { governor, timelock, receipts };
4062
+ }
4063
+ module2.exports = {
4064
+ communityDraftsBoardExec,
4065
+ tokenDemocracy
4066
+ };
4067
+ }
4068
+ });
4069
+
4070
+ // src/browser/utils.js
4071
+ var require_utils = __commonJS({
4072
+ "src/browser/utils.js"(exports2, module2) {
4073
+ function getAddress(address) {
4074
+ if (!address) return address;
4075
+ const addr = String(address).trim();
4076
+ const normalized = addr.startsWith("0x") ? addr.slice(2).toLowerCase() : addr.toLowerCase();
4077
+ return `0x${normalized}`;
4078
+ }
4079
+ async function keccak256Async(data) {
4080
+ const encoder = new TextEncoder();
4081
+ const dataBuffer = typeof data === "string" ? encoder.encode(data) : data;
4082
+ const hashBuffer = await crypto.subtle.digest("SHA-256", dataBuffer);
4083
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
4084
+ const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
4085
+ return `0x${hashHex}`;
4086
+ }
4087
+ function keccak256Sync(data) {
4088
+ const str = typeof data === "string" ? data : JSON.stringify(data);
4089
+ let hash = 0;
4090
+ for (let i = 0; i < str.length; i++) {
4091
+ const char = str.charCodeAt(i);
4092
+ hash = (hash << 5) - hash + char;
4093
+ hash = hash & hash;
4094
+ }
4095
+ const hex = Math.abs(hash).toString(16).padStart(8, "0");
4096
+ return `0x${hex.repeat(8)}`.slice(0, 66);
4097
+ }
4098
+ module2.exports = {
4099
+ getAddress,
4100
+ keccak256Async,
4101
+ keccak256Sync
4102
+ };
4103
+ }
4104
+ });
4105
+
4106
+ // src/browser/subgraph.js
4107
+ var require_subgraph2 = __commonJS({
4108
+ "src/browser/subgraph.js"(exports2, module2) {
4109
+ var { getAddress } = require_utils();
4110
+ function sanitizeOrderBy(orderBy, allowed, fallback) {
4111
+ const value = (orderBy || "").toString();
4112
+ return allowed.includes(value) ? value : fallback;
4113
+ }
4114
+ function sanitizeOrderDirection(direction, fallback = "desc") {
4115
+ const v = (direction || "").toString().toLowerCase();
4116
+ return v === "asc" ? "asc" : "desc";
4117
+ }
4118
+ function safeGetAddress(value) {
4119
+ try {
4120
+ return getAddress(value);
4121
+ } catch {
4122
+ return null;
4123
+ }
4124
+ }
4125
+ function mapSafe(list, mapper) {
4126
+ const out = [];
4127
+ for (const item of list || []) {
4128
+ try {
4129
+ const v = mapper(item);
4130
+ if (v != null) out.push(v);
4131
+ } catch {
4132
+ }
4133
+ }
4134
+ return out;
4135
+ }
4136
+ async function query(url, document, variables) {
4137
+ if (!url) throw new Error("subgraph url required");
4138
+ const controller = new AbortController();
4139
+ const timeoutId = setTimeout(() => controller.abort(), 1e4);
4140
+ try {
4141
+ const resp = await fetch(url, {
4142
+ method: "POST",
4143
+ headers: { "Content-Type": "application/json" },
4144
+ body: JSON.stringify({ query: document, variables }),
4145
+ signal: controller.signal
4146
+ });
4147
+ clearTimeout(timeoutId);
4148
+ if (!resp.ok) {
4149
+ throw new Error(`HTTP ${resp.status}: ${resp.statusText}`);
4150
+ }
4151
+ const data = await resp.json();
4152
+ if (data && data.errors) {
4153
+ throw new Error(data.errors.map((e) => e.message).join("; "));
4154
+ }
4155
+ return data.data;
4156
+ } catch (error) {
4157
+ clearTimeout(timeoutId);
4158
+ throw error;
4159
+ }
4160
+ }
4161
+ async function listProposals({ url, governor, first = 20, skip = 0 }) {
4162
+ const data = await query(url, `
4163
+ query($governor: Bytes!, $first: Int!, $skip: Int!) {
4164
+ proposals(where: { governor: $governor }, first: $first, skip: $skip, orderBy: createdAt, orderDirection: desc) {
4165
+ id
4166
+ proposer
4167
+ description
4168
+ createdAt
4169
+ targets
4170
+ values
4171
+ calldatas
4172
+ }
4173
+ }
4174
+ `, { governor: String(governor).toLowerCase(), first, skip });
4175
+ return mapSafe(data?.proposals, (p) => {
4176
+ const proposer = safeGetAddress(p.proposer);
4177
+ if (!proposer) return null;
4178
+ const targets = (p.targets || []).map((t) => safeGetAddress(t)).filter(Boolean);
4179
+ if (!targets.length && (p.targets || []).length) return null;
4180
+ return {
4181
+ id: BigInt(p.id),
4182
+ proposer,
4183
+ description: p.description,
4184
+ createdAt: Number(p.createdAt || 0),
4185
+ targets,
4186
+ values: (p.values || []).map((value) => BigInt(String(value))),
4187
+ calldatas: p.calldatas || []
4188
+ };
4189
+ });
4190
+ }
4191
+ var STATE_STRING_TO_NUMBER = {
4192
+ PENDING: 0,
4193
+ ACTIVE: 1,
4194
+ CANCELED: 2,
4195
+ CANCELLED: 2,
4196
+ // some indexes may use British spelling
4197
+ DEFEATED: 3,
4198
+ SUCCEEDED: 4,
4199
+ QUEUED: 5,
4200
+ EXPIRED: 6,
4201
+ EXECUTED: 7
4202
+ };
4203
+ async function listProposalsFiltered({ url, governor, states, fromTimestamp, toTimestamp, first = 20, skip = 0, orderBy = "createdAt", orderDirection = "desc" }) {
4204
+ const govLower = governor ? String(governor).toLowerCase() : null;
4205
+ const statesUpper = Array.isArray(states) && states.length ? states.map((s) => String(s).toUpperCase()) : null;
4206
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["createdAt", "updatedAt", "eta"], "createdAt");
4207
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
4208
+ const doc = `
4209
+ query($first: Int!, $skip: Int!, $governor: Bytes, $states: [String!], $from: Int, $to: Int) {
4210
+ proposals(
4211
+ where: {
4212
+ ${governor ? "governor: $governor," : ""}
4213
+ ${statesUpper ? "state_in: $states," : ""}
4214
+ ${fromTimestamp !== void 0 ? "createdAt_gte: $from," : ""}
4215
+ ${toTimestamp !== void 0 ? "createdAt_lte: $to," : ""}
4216
+ }
4217
+ first: $first
4218
+ skip: $skip
4219
+ orderBy: ${safeOrderBy}
4220
+ orderDirection: ${safeOrderDirection}
4221
+ ) {
4222
+ id
4223
+ proposer
4224
+ description
4225
+ createdAt
4226
+ updatedAt
4227
+ state
4228
+ eta
4229
+ targets
4230
+ values
4231
+ calldatas
4232
+ }
4233
+ }
4234
+ `;
4235
+ const variables = { first, skip };
4236
+ if (govLower) variables.governor = govLower;
4237
+ if (statesUpper) variables.states = statesUpper;
4238
+ if (fromTimestamp !== void 0) variables.from = Number(fromTimestamp);
4239
+ if (toTimestamp !== void 0) variables.to = Number(toTimestamp);
4240
+ const data = await query(url, doc, variables);
4241
+ return mapSafe(data?.proposals, (p) => {
4242
+ const stateStr = String(p.state || "").toUpperCase();
4243
+ const stateNum = STATE_STRING_TO_NUMBER[stateStr] != null ? STATE_STRING_TO_NUMBER[stateStr] : null;
4244
+ const proposer = safeGetAddress(p.proposer);
4245
+ if (!proposer) return null;
4246
+ const targets = (p.targets || []).map((t) => safeGetAddress(t)).filter(Boolean);
4247
+ if (!targets.length && (p.targets || []).length) return null;
4248
+ return {
4249
+ id: BigInt(p.id),
4250
+ proposer,
4251
+ description: p.description || "",
4252
+ createdAt: Number(p.createdAt || 0),
4253
+ updatedAt: Number(p.updatedAt || 0),
4254
+ state: stateStr,
4255
+ stateNum,
4256
+ eta: p.eta ? BigInt(String(p.eta)) : null,
4257
+ targets,
4258
+ values: (p.values || []).map((value) => BigInt(String(value))),
4259
+ calldatas: p.calldatas || []
4260
+ };
4261
+ });
4262
+ }
4263
+ async function listLibraries({ url, subdao, first = 50, skip = 0 }) {
4264
+ const where = subdao ? `where: { subDAO: "${String(subdao).toLowerCase()}" }` : "";
4265
+ const data = await query(url, `
4266
+ query($first: Int!, $skip: Int!) {
4267
+ libraries(${where} first: $first, skip: $skip, orderBy: createdAt, orderDirection: desc) {
4268
+ id
4269
+ manifestCID
4270
+ subDAO
4271
+ proposer
4272
+ createdAt
4273
+ }
4274
+ }
4275
+ `, { first, skip });
4276
+ return mapSafe(data?.libraries, (lib) => {
4277
+ const sub = safeGetAddress(lib.subDAO);
4278
+ const proposer = safeGetAddress(lib.proposer);
4279
+ if (!sub || !proposer) return null;
4280
+ return {
4281
+ id: lib.id,
4282
+ manifestCID: lib.manifestCID,
4283
+ subdao: sub,
4284
+ proposer,
4285
+ createdAt: Number(lib.createdAt || 0)
4286
+ };
4287
+ });
4288
+ }
4289
+ async function getSubdaoLibraries({ url, subdao, first = 20, skip = 0 }) {
4290
+ if (!url) throw new Error("subgraph url required");
4291
+ const hasFilter = !!subdao;
4292
+ const whereClause = hasFilter ? "where:{ subdao:$subdao }" : "";
4293
+ const doc = `
4294
+ query($subdao:Bytes,$first:Int!,$skip:Int!){
4295
+ subDAOLibraryPointers(
4296
+ ${whereClause}
4297
+ first:$first,
4298
+ skip:$skip,
4299
+ orderBy: updatedAt,
4300
+ orderDirection: desc
4301
+ ){
4302
+ id
4303
+ subdao
4304
+ libraryId
4305
+ manifestCID
4306
+ previousCID
4307
+ promptCount
4308
+ updatedAt
4309
+ }
4310
+ }
4311
+ `;
4312
+ const variables = {
4313
+ first: Math.min(Math.max(1, Number(first || 20)), 100),
4314
+ skip
4315
+ };
4316
+ if (hasFilter) {
4317
+ const addr = safeGetAddress(subdao);
4318
+ if (!addr) throw new Error("invalid subdao address");
4319
+ variables.subdao = addr.toLowerCase();
4320
+ }
4321
+ const data = await query(url, doc, variables);
4322
+ return mapSafe(data?.subDAOLibraryPointers, (row) => {
4323
+ const id2 = row?.id;
4324
+ const manifestCID = row?.manifestCID;
4325
+ const sub = safeGetAddress(row?.subdao);
4326
+ if (!id2 || !manifestCID || !sub) return null;
4327
+ return {
4328
+ id: String(id2),
4329
+ subdao: sub,
4330
+ libraryId: String(row.libraryId || "main"),
4331
+ manifestCID: String(manifestCID),
4332
+ previousCID: row.previousCID || null,
4333
+ promptCount: row.promptCount != null ? Number(row.promptCount) : null,
4334
+ updatedAt: row.updatedAt != null ? Number(row.updatedAt) : null
4335
+ };
4336
+ });
4337
+ }
4338
+ async function getSubdaoPrompts({ url, registry, first = 50, skip = 0, orderBy = "updatedAt", orderDirection = "desc" }) {
4339
+ if (!url) throw new Error("subgraph url required");
4340
+ const reg = safeGetAddress(registry);
4341
+ if (!reg) throw new Error("invalid registry address");
4342
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["updatedAt"], "updatedAt");
4343
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
4344
+ const doc = `
4345
+ query($registry:Bytes!,$first:Int!,$skip:Int!){
4346
+ prompts(
4347
+ where:{ registry:$registry },
4348
+ first:$first,
4349
+ skip:$skip,
4350
+ orderBy: ${safeOrderBy},
4351
+ orderDirection: ${safeOrderDirection}
4352
+ ){
4353
+ id
4354
+ key
4355
+ cid
4356
+ version
4357
+ author
4358
+ registry
4359
+ updatedAt
4360
+ }
4361
+ }
4362
+ `;
4363
+ const data = await query(url, doc, {
4364
+ registry: reg.toLowerCase(),
4365
+ first: Math.min(Math.max(1, Number(first || 50)), 100),
4366
+ skip
4367
+ });
4368
+ return mapSafe(data?.prompts, (p) => {
4369
+ const author = safeGetAddress(p.author);
4370
+ const regAddr = safeGetAddress(p.registry);
4371
+ if (!author || !regAddr) return null;
4372
+ return {
4373
+ id: String(p.id),
4374
+ key: String(p.key),
4375
+ cid: String(p.cid),
4376
+ version: BigInt(p.version || "0"),
4377
+ author,
4378
+ registry: regAddr,
4379
+ updatedAt: Number(p.updatedAt || 0)
4380
+ };
4381
+ });
4382
+ }
4383
+ module2.exports = {
4384
+ query,
4385
+ listProposals,
4386
+ listProposalsFiltered,
4387
+ listLibraries,
4388
+ getSubdaoLibraries,
4389
+ getSubdaoPrompts,
4390
+ /**
4391
+ * Canonical proposal timeline. Tries common fields first, then event-style fallbacks.
4392
+ * Returns { id, createdAt, queuedAt, executedAt, canceledAt, eta, state } (numbers/strings may be null when unavailable).
4393
+ */
4394
+ async getProposalTimeline({ url, id: id2 }) {
4395
+ if (!url) throw new Error("subgraph url required");
4396
+ const pid = typeof id2 === "bigint" ? id2.toString() : String(id2);
4397
+ try {
4398
+ const data = await query(url, `
4399
+ query($id: ID!) {
4400
+ proposal(id: $id) {
4401
+ id
4402
+ createdAt
4403
+ updatedAt
4404
+ state
4405
+ eta
4406
+ queuedAt
4407
+ executedAt
4408
+ canceledAt
4409
+ }
4410
+ }
4411
+ `, { id: pid });
4412
+ if (data && data.proposal) {
4413
+ const p = data.proposal;
4414
+ return {
4415
+ id: p.id,
4416
+ createdAt: Number(p.createdAt || 0),
4417
+ queuedAt: p.queuedAt != null ? Number(p.queuedAt) : null,
4418
+ executedAt: p.executedAt != null ? Number(p.executedAt) : null,
4419
+ canceledAt: p.canceledAt != null ? Number(p.canceledAt) : null,
4420
+ eta: p.eta != null ? BigInt(String(p.eta)) : null,
4421
+ state: String(p.state || "")
4422
+ };
4423
+ }
4424
+ } catch (_) {
4425
+ }
4426
+ try {
4427
+ const data = await query(url, `
4428
+ query($id: String!) {
4429
+ proposalEvents(where: { proposal: $id }, orderBy: timestamp, orderDirection: asc) {
4430
+ type
4431
+ timestamp
4432
+ }
4433
+ proposals(where: { id: $id }, first:1) { id createdAt state eta }
4434
+ }
4435
+ `, { id: pid });
4436
+ const events = (data?.proposalEvents || []).map((e) => ({ type: String(e.type || ""), timestamp: Number(e.timestamp || 0) }));
4437
+ const base = data?.proposals?.[0] || {};
4438
+ const find = (t) => events.find((e) => e.type.toLowerCase() === t)?.timestamp || null;
4439
+ return {
4440
+ id: base.id || pid,
4441
+ createdAt: Number(base.createdAt || 0),
4442
+ queuedAt: find("queued"),
4443
+ executedAt: find("executed"),
4444
+ canceledAt: find("canceled") || find("cancelled") || null,
4445
+ eta: base.eta != null ? BigInt(String(base.eta)) : null,
4446
+ state: String(base.state || "")
4447
+ };
4448
+ } catch (_) {
4449
+ }
4450
+ return { id: pid, createdAt: 0, queuedAt: null, executedAt: null, canceledAt: null, eta: null, state: "" };
4451
+ },
4452
+ async listLiquidityAddPlans({ url, subdao = null, first = 50, skip = 0, orderBy = "blockTimestamp", orderDirection = "desc" }) {
4453
+ if (!url) throw new Error("subgraph url required");
4454
+ const filters = [];
4455
+ if (subdao) {
4456
+ const addr = safeGetAddress(subdao);
4457
+ if (!addr) throw new Error("invalid subdao address");
4458
+ filters.push(`subdao: "${addr.toLowerCase()}"`);
4459
+ }
4460
+ const where = filters.length ? `where: { ${filters.join(", ")} }` : "";
4461
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["blockTimestamp", "blockNumber"], "blockTimestamp");
4462
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
4463
+ const doc = `
4464
+ query($first:Int!,$skip:Int!){
4465
+ liquidityAddPlans(${where} first:$first, skip:$skip, orderBy: ${safeOrderBy}, orderDirection: ${safeOrderDirection}){
4466
+ id subdao pool sxxxToken stableToken sxxxAmount stableAmount lpRecipient blockNumber blockTimestamp transactionHash
4467
+ }
4468
+ }
4469
+ `;
4470
+ const data = await query(url, doc, { first, skip });
4471
+ return mapSafe(data?.liquidityAddPlans, (e) => {
4472
+ const sub = safeGetAddress(e.subdao);
4473
+ const pool = safeGetAddress(e.pool);
4474
+ const sxxxToken = safeGetAddress(e.sxxxToken);
4475
+ const stableToken = safeGetAddress(e.stableToken);
4476
+ const lpRecipient = safeGetAddress(e.lpRecipient);
4477
+ if (!sub || !pool || !sxxxToken || !stableToken || !lpRecipient) return null;
4478
+ return {
4479
+ id: String(e.id),
4480
+ subdao: sub,
4481
+ pool,
4482
+ sxxxToken,
4483
+ stableToken,
4484
+ sxxxAmount: BigInt(String(e.sxxxAmount)),
4485
+ stableAmount: BigInt(String(e.stableAmount)),
4486
+ lpRecipient,
4487
+ blockNumber: Number(e.blockNumber || 0),
4488
+ blockTimestamp: Number(e.blockTimestamp || 0),
4489
+ transactionHash: e.transactionHash
4490
+ };
4491
+ });
4492
+ },
4493
+ async listLiquidityRemovePlans({ url, subdao = null, first = 50, skip = 0, orderBy = "blockTimestamp", orderDirection = "desc" }) {
4494
+ if (!url) throw new Error("subgraph url required");
4495
+ const filters = [];
4496
+ if (subdao) {
4497
+ const addr = safeGetAddress(subdao);
4498
+ if (!addr) throw new Error("invalid subdao address");
4499
+ filters.push(`subdao: "${addr.toLowerCase()}"`);
4500
+ }
4501
+ const where = filters.length ? `where: { ${filters.join(", ")} }` : "";
4502
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["blockTimestamp", "blockNumber"], "blockTimestamp");
4503
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
4504
+ const doc = `
4505
+ query($first:Int!,$skip:Int!){
4506
+ liquidityRemovePlans(${where} first:$first, skip:$skip, orderBy: ${safeOrderBy}, orderDirection: ${safeOrderDirection}){
4507
+ id subdao pool lpToken lpAmount recipient blockNumber blockTimestamp transactionHash
4508
+ }
4509
+ }
4510
+ `;
4511
+ const data = await query(url, doc, { first, skip });
4512
+ return mapSafe(data?.liquidityRemovePlans, (e) => {
4513
+ const sub = safeGetAddress(e.subdao);
4514
+ const pool = safeGetAddress(e.pool);
4515
+ const lpToken = safeGetAddress(e.lpToken);
4516
+ const recipient = safeGetAddress(e.recipient);
4517
+ if (!sub || !pool || !lpToken || !recipient) return null;
4518
+ return {
4519
+ id: String(e.id),
4520
+ subdao: sub,
4521
+ pool,
4522
+ lpToken,
4523
+ lpAmount: BigInt(String(e.lpAmount)),
4524
+ recipient,
4525
+ blockNumber: Number(e.blockNumber || 0),
4526
+ blockTimestamp: Number(e.blockTimestamp || 0),
4527
+ transactionHash: e.transactionHash
4528
+ };
4529
+ });
4530
+ },
4531
+ async listPromptsByTag({ url, tagsHash, registry = null, first = 50, skip = 0, orderBy = "updatedAt", orderDirection = "desc" }) {
4532
+ if (!url) throw new Error("subgraph url required");
4533
+ const clauses = [`tagsHash: "${String(tagsHash)}"`];
4534
+ if (registry) {
4535
+ const addr = safeGetAddress(registry);
4536
+ if (!addr) throw new Error("invalid registry address");
4537
+ clauses.push(`registry: "${addr.toLowerCase()}"`);
4538
+ }
4539
+ const where = `where: { ${clauses.join(", ")} }`;
4540
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["updatedAt"], "updatedAt");
4541
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
4542
+ const doc = `
4543
+ query($first:Int!,$skip:Int!) {
4544
+ prompts(${where} first:$first, skip:$skip, orderBy: ${safeOrderBy}, orderDirection: ${safeOrderDirection}) {
4545
+ id key cid version author registry updatedAt tagsHash
4546
+ }
4547
+ }
4548
+ `;
4549
+ const data = await query(url, doc, { first, skip });
4550
+ return mapSafe(data?.prompts, (p) => {
4551
+ const author = safeGetAddress(p.author);
4552
+ const regAddr = safeGetAddress(p.registry);
4553
+ if (!author || !regAddr) return null;
4554
+ return {
4555
+ id: String(p.id),
4556
+ key: String(p.key),
4557
+ cid: String(p.cid),
4558
+ version: BigInt(p.version || "0"),
4559
+ author,
4560
+ registry: regAddr,
4561
+ updatedAt: Number(p.updatedAt || 0),
4562
+ tagsHash: String(p.tagsHash || "")
4563
+ };
4564
+ });
4565
+ },
4566
+ // Prompt helpers (registry scoped)
4567
+ async listRegistryPrompts({ url, registry, first = 50, skip = 0, orderBy = "updatedAt", orderDirection = "desc" }) {
4568
+ if (!url) throw new Error("subgraph url required");
4569
+ const reg = safeGetAddress(registry);
4570
+ if (!reg) throw new Error("invalid registry address");
4571
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["updatedAt"], "updatedAt");
4572
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
4573
+ const doc = `
4574
+ query($first:Int!,$skip:Int!,$registry:Bytes!) {
4575
+ prompts(where:{ registry: $registry }, first:$first, skip:$skip, orderBy: ${safeOrderBy}, orderDirection: ${safeOrderDirection}) {
4576
+ id
4577
+ key
4578
+ cid
4579
+ version
4580
+ author
4581
+ registry
4582
+ updatedAt
4583
+ }
4584
+ }
4585
+ `;
4586
+ const data = await query(url, doc, { first, skip, registry: reg.toLowerCase() });
4587
+ return mapSafe(data?.prompts, (p) => {
4588
+ const author = safeGetAddress(p.author);
4589
+ const regAddr = safeGetAddress(p.registry);
4590
+ if (!author || !regAddr) return null;
4591
+ return {
4592
+ id: String(p.id),
4593
+ key: String(p.key),
4594
+ cid: String(p.cid),
4595
+ version: BigInt(p.version || "0"),
4596
+ author,
4597
+ registry: regAddr,
4598
+ updatedAt: Number(p.updatedAt || 0)
4599
+ };
4600
+ });
4601
+ },
4602
+ async getPromptByKey({ url, registry, key }) {
4603
+ if (!url) throw new Error("subgraph url required");
4604
+ const reg = safeGetAddress(registry);
4605
+ if (!reg) throw new Error("invalid registry address");
4606
+ const doc = `
4607
+ query($registry:Bytes!,$key:String!) {
4608
+ prompts(where:{ registry: $registry, key: $key }, first:1) {
4609
+ id
4610
+ key
4611
+ cid
4612
+ version
4613
+ author
4614
+ registry
4615
+ updatedAt
4616
+ }
4617
+ }
4618
+ `;
4619
+ const data = await query(url, doc, { registry: reg.toLowerCase(), key: String(key) });
4620
+ const p = (data?.prompts || [])[0];
4621
+ if (!p) return null;
4622
+ const author = safeGetAddress(p.author);
4623
+ const regAddr = safeGetAddress(p.registry);
4624
+ if (!author || !regAddr) return null;
4625
+ return {
4626
+ id: String(p.id),
4627
+ key: String(p.key),
4628
+ cid: String(p.cid),
4629
+ version: BigInt(p.version || "0"),
4630
+ author,
4631
+ registry: regAddr,
4632
+ updatedAt: Number(p.updatedAt || 0)
4633
+ };
4634
+ },
4635
+ async getProposalById({ url, id: id2 }) {
4636
+ if (!url) throw new Error("subgraph url required");
4637
+ const doc = `query($id: ID!){ proposal(id:$id){ id proposer description createdAt updatedAt state eta targets values calldatas } }`;
4638
+ const data = await query(url, doc, { id: String(id2) });
4639
+ const p = data?.proposal;
4640
+ if (!p) return null;
4641
+ try {
4642
+ const proposer = safeGetAddress(p.proposer);
4643
+ if (!proposer) return null;
4644
+ const targets = (p.targets || []).map((t) => safeGetAddress(t)).filter(Boolean);
4645
+ if (!targets.length && (p.targets || []).length) return null;
4646
+ return {
4647
+ id: BigInt(p.id),
4648
+ proposer,
4649
+ description: p.description || "",
4650
+ createdAt: Number(p.createdAt || 0),
4651
+ updatedAt: Number(p.updatedAt || 0),
4652
+ state: String(p.state || ""),
4653
+ eta: p.eta ? BigInt(String(p.eta)) : null,
4654
+ targets,
4655
+ values: (p.values || []).map((v) => BigInt(String(v))),
4656
+ calldatas: p.calldatas || []
4657
+ };
4658
+ } catch {
4659
+ return null;
4660
+ }
4661
+ }
3804
4662
  };
3805
4663
  }
3806
4664
  });
@@ -4159,6 +5017,7 @@ var require_operations = __commonJS({
4159
5017
  cache = null,
4160
5018
  fromBlock = 0,
4161
5019
  helperAddress = null,
5020
+ subgraphUrl = null,
4162
5021
  hints = {},
4163
5022
  chunkSizeBlocks = 1e4,
4164
5023
  lookBackBlocks = 2e3,
@@ -4172,6 +5031,27 @@ var require_operations = __commonJS({
4172
5031
  const cached = await cacheAdapter.load(govAddr, id2);
4173
5032
  if (cached) return cached;
4174
5033
  }
5034
+ if (subgraphUrl) {
5035
+ try {
5036
+ const subgraph = require_subgraph2();
5037
+ const sgProposal = await subgraph.getProposalById({ url: subgraphUrl, id: String(id2) });
5038
+ if (sgProposal && sgProposal.targets && sgProposal.targets.length > 0) {
5039
+ const tuple2 = {
5040
+ id: id2,
5041
+ governor: govAddr,
5042
+ targets: sgProposal.targets,
5043
+ values: sgProposal.values || [],
5044
+ calldatas: sgProposal.calldatas || [],
5045
+ description: sgProposal.description || "",
5046
+ descriptionHash: sgProposal.description ? keccak256(toUtf8Bytes(sgProposal.description)) : null,
5047
+ createdBlock: sgProposal.createdAt || null
5048
+ };
5049
+ if (cacheAdapter) await cacheAdapter.save(govAddr, id2, tuple2);
5050
+ return tuple2;
5051
+ }
5052
+ } catch (_) {
5053
+ }
5054
+ }
4175
5055
  if (helperAddress) {
4176
5056
  try {
4177
5057
  const helperAbi = [
@@ -4385,8 +5265,14 @@ var require_operations = __commonJS({
4385
5265
  ]);
4386
5266
  let resolvedSubDAO = subdao;
4387
5267
  if (!resolvedSubDAO) {
4388
- resolvedSubDAO = await governorContract.subDAO().catch(() => null);
4389
- if (resolvedSubDAO === ZeroAddress) resolvedSubDAO = null;
5268
+ try {
5269
+ const subDAOInterface = new Interface(["function subDAO() view returns (address)"]);
5270
+ const subdaoContract = new Contract(govAddr, subDAOInterface, provider);
5271
+ resolvedSubDAO = await subdaoContract.subDAO().catch(() => null);
5272
+ if (resolvedSubDAO === ZeroAddress) resolvedSubDAO = null;
5273
+ } catch {
5274
+ resolvedSubDAO = null;
5275
+ }
4390
5276
  }
4391
5277
  let mode = null;
4392
5278
  let eligible = null;
@@ -4461,10 +5347,11 @@ var require_operations = __commonJS({
4461
5347
  refresh = false,
4462
5348
  cache = null,
4463
5349
  includeTimeline = false,
4464
- helperAddress = null
5350
+ helperAddress = null,
5351
+ subgraphUrl = null
4465
5352
  }) {
4466
5353
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
4467
- const tuple = await resolveProposalTuple({ provider, governor, proposalId, refresh, cache, helperAddress });
5354
+ const tuple = await resolveProposalTuple({ provider, governor, proposalId, refresh, cache, helperAddress, subgraphUrl });
4468
5355
  let proposal = null;
4469
5356
  try {
4470
5357
  proposal = await governance.getProposal({ provider, governor: tuple.governor, id: tuple.id });
@@ -4802,8 +5689,6 @@ var require_factory = __commonJS({
4802
5689
  stableCreationFee,
4803
5690
  feeReceiver,
4804
5691
  allowStableFee,
4805
- stablePromptForkFee,
4806
- allowStablePromptForkFee,
4807
5692
  stableForkFee,
4808
5693
  allowStableForkFee,
4809
5694
  timelockMinDelay,
@@ -4827,8 +5712,6 @@ var require_factory = __commonJS({
4827
5712
  }
4828
5713
  })(),
4829
5714
  contract.allowStableFee().catch(() => null),
4830
- contract.stablePromptForkFee().catch(() => null),
4831
- contract.allowStablePromptForkFee().catch(() => null),
4832
5715
  contract.stableForkFee().catch(() => null),
4833
5716
  contract.allowStableForkFee().catch(() => null),
4834
5717
  contract.timelockMinDelay().catch(() => null),
@@ -4844,8 +5727,6 @@ var require_factory = __commonJS({
4844
5727
  stableCreationFee,
4845
5728
  feeReceiver: feeReceiver && feeReceiver !== "0x0000000000000000000000000000000000000000" ? getAddress(feeReceiver) : null,
4846
5729
  allowStableFee,
4847
- stablePromptForkFee,
4848
- allowStablePromptForkFee,
4849
5730
  stableForkFee,
4850
5731
  allowStableForkFee,
4851
5732
  timelockMinDelay,
@@ -5177,6 +6058,113 @@ var require_factory = __commonJS({
5177
6058
  }
5178
6059
  });
5179
6060
 
6061
+ // src/lineage/index.js
6062
+ var require_lineage = __commonJS({
6063
+ "src/lineage/index.js"(exports2, module2) {
6064
+ var { Contract, getAddress } = require("ethers");
6065
+ var { SageSDKError, CODES } = require_errors();
6066
+ var LINEAGE_ABI = [
6067
+ "function libraryByDAO(address) view returns (string manifestCID, address lastUpdater, uint256 lastUpdated, string version, address forkedFromDAO, uint256 sxxxForkFee)",
6068
+ "function getLibraryForkFee(address) view returns (uint256)"
6069
+ ];
6070
+ var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
6071
+ function normalise(address, label) {
6072
+ if (!address) throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
6073
+ try {
6074
+ return getAddress(address);
6075
+ } catch (err) {
6076
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
6077
+ }
6078
+ }
6079
+ async function getParentLibrary({ provider, registry, subdao }) {
6080
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6081
+ if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
6082
+ if (!subdao) throw new SageSDKError(CODES.INVALID_ARGS, "subdao required");
6083
+ try {
6084
+ const contract = new Contract(normalise(registry, "registry"), LINEAGE_ABI, provider);
6085
+ const info = await contract.libraryByDAO(normalise(subdao, "subdao"));
6086
+ const parent = info.forkedFromDAO;
6087
+ if (!parent || parent === ZERO_ADDRESS) {
6088
+ return null;
6089
+ }
6090
+ return getAddress(parent).toLowerCase();
6091
+ } catch (err) {
6092
+ throw new SageSDKError(CODES.CONTRACT_ERROR, "Failed to fetch parent library", { cause: err });
6093
+ }
6094
+ }
6095
+ async function getLineageChain({ provider, registry, subdao }) {
6096
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6097
+ if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
6098
+ if (!subdao) throw new SageSDKError(CODES.INVALID_ARGS, "subdao required");
6099
+ try {
6100
+ const contract = new Contract(normalise(registry, "registry"), LINEAGE_ABI, provider);
6101
+ const chain = [];
6102
+ let current = normalise(subdao, "subdao");
6103
+ const MAX_DEPTH = 100;
6104
+ let iterations = 0;
6105
+ while (current && iterations < MAX_DEPTH) {
6106
+ chain.unshift(getAddress(current).toLowerCase());
6107
+ const info = await contract.libraryByDAO(current);
6108
+ const parent = info.forkedFromDAO;
6109
+ if (!parent || parent === ZERO_ADDRESS) {
6110
+ break;
6111
+ }
6112
+ current = parent;
6113
+ iterations++;
6114
+ }
6115
+ return {
6116
+ chain,
6117
+ depth: chain.length - 1,
6118
+ root: chain[0]
6119
+ };
6120
+ } catch (err) {
6121
+ throw new SageSDKError(CODES.CONTRACT_ERROR, "Failed to fetch lineage chain", { cause: err });
6122
+ }
6123
+ }
6124
+ async function isFork({ provider, registry, subdao }) {
6125
+ const parent = await getParentLibrary({ provider, registry, subdao });
6126
+ return parent !== null;
6127
+ }
6128
+ async function getLibraryForkFee({ provider, registry, subdao }) {
6129
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6130
+ if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
6131
+ if (!subdao) throw new SageSDKError(CODES.INVALID_ARGS, "subdao required");
6132
+ try {
6133
+ const contract = new Contract(normalise(registry, "registry"), LINEAGE_ABI, provider);
6134
+ const fee = await contract.getLibraryForkFee(normalise(subdao, "subdao"));
6135
+ return BigInt(fee.toString());
6136
+ } catch (err) {
6137
+ throw new SageSDKError(CODES.CONTRACT_ERROR, "Failed to fetch library fork fee", { cause: err });
6138
+ }
6139
+ }
6140
+ async function getLibraryInfo({ provider, registry, subdao }) {
6141
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6142
+ if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
6143
+ if (!subdao) throw new SageSDKError(CODES.INVALID_ARGS, "subdao required");
6144
+ try {
6145
+ const contract = new Contract(normalise(registry, "registry"), LINEAGE_ABI, provider);
6146
+ const info = await contract.libraryByDAO(normalise(subdao, "subdao"));
6147
+ const parent = info.forkedFromDAO;
6148
+ return {
6149
+ parentDAO: !parent || parent === ZERO_ADDRESS ? null : getAddress(parent).toLowerCase(),
6150
+ forkFee: BigInt(info.sxxxForkFee.toString()),
6151
+ manifestCID: info.manifestCID,
6152
+ version: info.version
6153
+ };
6154
+ } catch (err) {
6155
+ throw new SageSDKError(CODES.CONTRACT_ERROR, "Failed to fetch library info", { cause: err });
6156
+ }
6157
+ }
6158
+ module2.exports = {
6159
+ getParentLibrary,
6160
+ getLineageChain,
6161
+ isFork,
6162
+ getLibraryForkFee,
6163
+ getLibraryInfo
6164
+ };
6165
+ }
6166
+ });
6167
+
5180
6168
  // src/prompt/execute.js
5181
6169
  var require_execute = __commonJS({
5182
6170
  "src/prompt/execute.js"(exports2, module2) {
@@ -5849,7 +6837,6 @@ var require_ipns = __commonJS({
5849
6837
  headers["X-Wallet-Address"] = auth.address;
5850
6838
  headers["X-Wallet-Signature"] = auth.signature;
5851
6839
  headers["X-Wallet-Nonce"] = auth.nonce;
5852
- headers["X-Wallet-Message"] = auth.message;
5853
6840
  }
5854
6841
  return { headers, auth };
5855
6842
  }
@@ -5871,8 +6858,7 @@ var require_ipns = __commonJS({
5871
6858
  ...extraHeaders,
5872
6859
  "X-Wallet-Address": auth.address,
5873
6860
  "X-Wallet-Signature": auth.signature,
5874
- "X-Wallet-Nonce": auth.nonce,
5875
- "X-Wallet-Message": auth.message
6861
+ "X-Wallet-Nonce": auth.nonce
5876
6862
  };
5877
6863
  return { headers, auth };
5878
6864
  }
@@ -6509,8 +7495,34 @@ var require_time = __commonJS({
6509
7495
  var require_treasury = __commonJS({
6510
7496
  "src/treasury/index.js"(exports2, module2) {
6511
7497
  var { Contract, Interface, getAddress } = require("ethers");
6512
- var ABI = require_abi();
6513
7498
  var { SageSDKError, CODES } = require_errors();
7499
+ var SAGE_TREASURY_ABI = [
7500
+ // Aggregated views
7501
+ "function totalReserves() view returns (uint256)",
7502
+ "function totalPOL() view returns (uint256)",
7503
+ "function totalDebt() view returns (uint256)",
7504
+ // Canonical liquidity config
7505
+ "function canonicalPool() view returns (address)",
7506
+ "function routerOrVault() view returns (address)",
7507
+ // Withdrawal rate limits
7508
+ "function maxWithdrawalRate() view returns (uint256)",
7509
+ "function emergencyWithdrawalLimit() view returns (uint256)",
7510
+ // Reserve tokens
7511
+ "function getReserveTokens() view returns (address[])",
7512
+ "function getReserve(address token) view returns (tuple(uint256 amount, uint256 value, bool isLP, bool isActive))",
7513
+ // Withdrawal queue
7514
+ "function nextWithdrawalId() view returns (uint256)",
7515
+ "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))",
7516
+ "function withdraw(address token, uint256 amount, address recipient)",
7517
+ "function confirmWithdrawal(uint256 id)",
7518
+ "function cancelWithdrawal(uint256 id)",
7519
+ // Manual price overrides
7520
+ "function manualPrices(address token) view returns (tuple(uint256 price, uint256 expiresAt, bool active))",
7521
+ "function setPriceOverride(address token, uint256 price, uint256 ttlSeconds)",
7522
+ "function clearPriceOverride(address token)",
7523
+ // Events
7524
+ "event WithdrawalScheduled(uint256 indexed id, address indexed token, address indexed recipient, uint256 amount)"
7525
+ ];
6514
7526
  var LiquidityEvents = new Interface([
6515
7527
  "event CanonicalLiquidityUpdated(address indexed pool, address indexed routerOrVault)",
6516
7528
  "event LiquidityAddPlanned(address indexed subdao, address indexed pool, address sxxxToken, address stableToken, uint256 sxxxAmount, uint256 stableAmount, address lpRecipient)",
@@ -6555,7 +7567,7 @@ var require_treasury = __commonJS({
6555
7567
  async function getTreasuryInfo({ provider, treasury }) {
6556
7568
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6557
7569
  const addr = normalise(treasury, "treasury");
6558
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7570
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6559
7571
  const [totalReserves, totalPOL, totalDebt, canonicalPool, routerOrVault, maxWithdrawalRate, emergencyWithdrawalLimit] = await Promise.all([
6560
7572
  contract.totalReserves().catch(() => 0n),
6561
7573
  contract.totalPOL().catch(() => 0n),
@@ -6579,7 +7591,7 @@ var require_treasury = __commonJS({
6579
7591
  async function getPendingWithdrawals({ provider, treasury, ids, limit = 50 }) {
6580
7592
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6581
7593
  const addr = normalise(treasury, "treasury");
6582
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7594
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6583
7595
  let idList = ids;
6584
7596
  if (!Array.isArray(idList)) {
6585
7597
  const nextId = await contract.nextWithdrawalId().catch(() => 0n);
@@ -6611,14 +7623,14 @@ var require_treasury = __commonJS({
6611
7623
  async function getReserveTokens({ provider, treasury }) {
6612
7624
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6613
7625
  const addr = normalise(treasury, "treasury");
6614
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7626
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6615
7627
  const tokens = await contract.getReserveTokens().catch(() => []);
6616
7628
  return tokens.map((token) => getAddress(token));
6617
7629
  }
6618
7630
  async function getReserves({ provider, treasury, tokens, fetchMetadata = true }) {
6619
7631
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6620
7632
  const addr = normalise(treasury, "treasury");
6621
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7633
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6622
7634
  const tokenList = Array.isArray(tokens) && tokens.length ? tokens.map((token) => getAddress(token)) : await contract.getReserveTokens().catch(() => []);
6623
7635
  const reserves = [];
6624
7636
  for (const token of tokenList) {
@@ -6648,7 +7660,7 @@ var require_treasury = __commonJS({
6648
7660
  async function getManualPriceOverrides({ provider, treasury, tokens }) {
6649
7661
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6650
7662
  const addr = normalise(treasury, "treasury");
6651
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7663
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6652
7664
  const tokenList = Array.isArray(tokens) && tokens.length ? tokens.map((token) => getAddress(token)) : await contract.getReserveTokens().catch(() => []);
6653
7665
  const overrides = [];
6654
7666
  for (const token of tokenList) {
@@ -6753,7 +7765,7 @@ var require_treasury = __commonJS({
6753
7765
  async function getLPContribution({ provider, treasury, subdao, token }) {
6754
7766
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6755
7767
  const addr = normalise(treasury, "treasury");
6756
- const c = new Contract(addr, ABI.SageTreasury, provider);
7768
+ const c = new Contract(addr, SAGE_TREASURY_ABI, provider);
6757
7769
  const amount = await c.lpContributions(normalise(subdao, "subdao"), normalise(token, "token")).catch(() => 0n);
6758
7770
  return amount;
6759
7771
  }
@@ -6795,7 +7807,7 @@ var require_treasury = __commonJS({
6795
7807
  function createWriteContract({ signer, treasury }) {
6796
7808
  if (!signer) throw new SageSDKError(CODES.INVALID_ARGS, "signer required");
6797
7809
  const addr = normalise(treasury, "treasury");
6798
- return new Contract(addr, ABI.SageTreasury, signer);
7810
+ return new Contract(addr, SAGE_TREASURY_ABI, signer);
6799
7811
  }
6800
7812
  async function waitForReceipt({ signer, tx, waitMs }) {
6801
7813
  const provider = signer.provider;
@@ -7099,6 +8111,350 @@ var require_bounty = __commonJS({
7099
8111
  }
7100
8112
  });
7101
8113
 
8114
+ // src/votingMultiplier/index.js
8115
+ var require_votingMultiplier = __commonJS({
8116
+ "src/votingMultiplier/index.js"(exports2, module2) {
8117
+ var { Contract, Interface, getAddress } = require("ethers");
8118
+ var ABI = require_abi();
8119
+ var { SageSDKError, CODES } = require_errors();
8120
+ function normaliseAddress(address, label) {
8121
+ if (!address) throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
8122
+ try {
8123
+ return getAddress(address);
8124
+ } catch (err) {
8125
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
8126
+ }
8127
+ }
8128
+ function toBigInt(value, label) {
8129
+ if (value === void 0 || value === null) {
8130
+ throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
8131
+ }
8132
+ try {
8133
+ return BigInt(value.toString());
8134
+ } catch (err) {
8135
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
8136
+ }
8137
+ }
8138
+ function getNftContract(provider, nft) {
8139
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
8140
+ const addr = normaliseAddress(nft, "nft");
8141
+ return new Contract(addr, ABI.VotingMultiplierNFT, provider);
8142
+ }
8143
+ function getWrapperContract(provider, wrapper) {
8144
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
8145
+ const addr = normaliseAddress(wrapper, "wrapper");
8146
+ return new Contract(addr, ABI.MultipliedVotes, provider);
8147
+ }
8148
+ async function getTier({ provider, nft, tierId }) {
8149
+ const c = getNftContract(provider, nft);
8150
+ const id2 = toBigInt(tierId, "tierId");
8151
+ let tier;
8152
+ if (typeof c.getTier === "function") {
8153
+ tier = await c.getTier(id2);
8154
+ } else {
8155
+ tier = await c.tiers(id2);
8156
+ }
8157
+ const name = String(tier.name ?? tier[0]);
8158
+ const multiplier = BigInt((tier.multiplier ?? tier[1]).toString());
8159
+ const maxSupply = BigInt((tier.maxSupply ?? tier[2]).toString());
8160
+ const minted = BigInt((tier.minted ?? tier[3]).toString());
8161
+ const price = BigInt((tier.price ?? tier[4]).toString());
8162
+ const dao = getAddress(tier.dao ?? tier[5]);
8163
+ return { name, multiplier, maxSupply, minted, price, dao };
8164
+ }
8165
+ async function getTierCount({ provider, nft }) {
8166
+ const c = getNftContract(provider, nft);
8167
+ const count = await c.tierCount();
8168
+ return BigInt(count.toString());
8169
+ }
8170
+ function buildCreateTierTx({ nft, dao, name, multiplier, maxSupply, price }) {
8171
+ const addr = normaliseAddress(nft, "nft");
8172
+ const iface = new Interface(ABI.VotingMultiplierNFT);
8173
+ const data = iface.encodeFunctionData("createTier", [
8174
+ normaliseAddress(dao, "dao"),
8175
+ String(name ?? ""),
8176
+ toBigInt(multiplier, "multiplier"),
8177
+ toBigInt(maxSupply, "maxSupply"),
8178
+ toBigInt(price, "price")
8179
+ ]);
8180
+ return { to: addr, data, value: 0n };
8181
+ }
8182
+ function buildMintTx({ nft, to, tierId, uri }) {
8183
+ const addr = normaliseAddress(nft, "nft");
8184
+ const iface = new Interface(ABI.VotingMultiplierNFT);
8185
+ const data = iface.encodeFunctionData("mint", [
8186
+ normaliseAddress(to, "to"),
8187
+ toBigInt(tierId, "tierId"),
8188
+ String(uri ?? "")
8189
+ ]);
8190
+ return { to: addr, data, value: 0n };
8191
+ }
8192
+ function buildPublicMintTx({ nft, tierId, uri, value }) {
8193
+ const addr = normaliseAddress(nft, "nft");
8194
+ const iface = new Interface(ABI.VotingMultiplierNFT);
8195
+ const data = iface.encodeFunctionData("publicMint", [
8196
+ toBigInt(tierId, "tierId"),
8197
+ String(uri ?? "")
8198
+ ]);
8199
+ return { to: addr, data, value: toBigInt(value ?? 0n, "value") };
8200
+ }
8201
+ async function getMultiplier({ provider, nft, account, dao }) {
8202
+ const c = getNftContract(provider, nft);
8203
+ const res = await c.getMultiplier(normaliseAddress(account, "account"), normaliseAddress(dao, "dao"));
8204
+ return BigInt(res.toString());
8205
+ }
8206
+ async function getPastMultiplier({ provider, nft, account, dao, timepoint }) {
8207
+ const c = getNftContract(provider, nft);
8208
+ const res = await c.getPastMultiplier(
8209
+ normaliseAddress(account, "account"),
8210
+ normaliseAddress(dao, "dao"),
8211
+ toBigInt(timepoint, "timepoint")
8212
+ );
8213
+ return BigInt(res.toString());
8214
+ }
8215
+ async function getTokenMultiplier({ provider, nft, tokenId }) {
8216
+ const c = getNftContract(provider, nft);
8217
+ const res = await c.getTokenMultiplier(toBigInt(tokenId, "tokenId"));
8218
+ return BigInt(res.toString());
8219
+ }
8220
+ async function getTokenDAO({ provider, nft, tokenId }) {
8221
+ const c = getNftContract(provider, nft);
8222
+ const res = await c.getTokenDAO(toBigInt(tokenId, "tokenId"));
8223
+ return getAddress(res);
8224
+ }
8225
+ async function getTokenInfo({ provider, nft, tokenId }) {
8226
+ const c = getNftContract(provider, nft);
8227
+ const id2 = toBigInt(tokenId, "tokenId");
8228
+ const info = await c.getTokenInfo(id2);
8229
+ const owner = getAddress(info.owner ?? info[0]);
8230
+ const tierId = BigInt((info.tierId ?? info[1]).toString());
8231
+ const multiplier = BigInt((info.multiplier ?? info[2]).toString());
8232
+ const uri = String(info.uri ?? info[3]);
8233
+ return { owner, tierId, multiplier, uri };
8234
+ }
8235
+ async function getVotes({ provider, wrapper, account }) {
8236
+ const c = getWrapperContract(provider, wrapper);
8237
+ const res = await c.getVotes(normaliseAddress(account, "account"));
8238
+ return BigInt(res.toString());
8239
+ }
8240
+ async function getPastVotes({ provider, wrapper, account, timepoint }) {
8241
+ const c = getWrapperContract(provider, wrapper);
8242
+ const res = await c.getPastVotes(
8243
+ normaliseAddress(account, "account"),
8244
+ toBigInt(timepoint, "timepoint")
8245
+ );
8246
+ return BigInt(res.toString());
8247
+ }
8248
+ async function getVotingBreakdown({ provider, wrapper, account }) {
8249
+ const c = getWrapperContract(provider, wrapper);
8250
+ const [baseVotes, multiplier, effectiveVotes] = await c.getVotingBreakdown(normaliseAddress(account, "account"));
8251
+ return {
8252
+ baseVotes: BigInt(baseVotes.toString()),
8253
+ multiplier: BigInt(multiplier.toString()),
8254
+ effectiveVotes: BigInt(effectiveVotes.toString())
8255
+ };
8256
+ }
8257
+ async function getPastVotingBreakdown({ provider, wrapper, account, timepoint }) {
8258
+ const c = getWrapperContract(provider, wrapper);
8259
+ const [baseVotes, multiplier, effectiveVotes] = await c.getPastVotingBreakdown(
8260
+ normaliseAddress(account, "account"),
8261
+ toBigInt(timepoint, "timepoint")
8262
+ );
8263
+ return {
8264
+ baseVotes: BigInt(baseVotes.toString()),
8265
+ multiplier: BigInt(multiplier.toString()),
8266
+ effectiveVotes: BigInt(effectiveVotes.toString())
8267
+ };
8268
+ }
8269
+ async function hasMultiplierBonus({ provider, wrapper, account }) {
8270
+ const c = getWrapperContract(provider, wrapper);
8271
+ const res = await c.hasMultiplierBonus(normaliseAddress(account, "account"));
8272
+ return !!res;
8273
+ }
8274
+ module2.exports = {
8275
+ // Tier management
8276
+ getTier,
8277
+ getTierCount,
8278
+ buildCreateTierTx,
8279
+ // Minting
8280
+ buildMintTx,
8281
+ buildPublicMintTx,
8282
+ // Multiplier queries
8283
+ getMultiplier,
8284
+ getPastMultiplier,
8285
+ getTokenMultiplier,
8286
+ getTokenDAO,
8287
+ getTokenInfo,
8288
+ // Wrapper queries
8289
+ getVotes,
8290
+ getPastVotes,
8291
+ getVotingBreakdown,
8292
+ getPastVotingBreakdown,
8293
+ hasMultiplierBonus
8294
+ };
8295
+ }
8296
+ });
8297
+
8298
+ // src/auction/index.js
8299
+ var require_auction = __commonJS({
8300
+ "src/auction/index.js"(exports2, module2) {
8301
+ var { Contract, Interface, getAddress } = require("ethers");
8302
+ var ABI = require_abi();
8303
+ var { SageSDKError, CODES } = require_errors();
8304
+ function normaliseAddress(address, label) {
8305
+ if (!address) throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
8306
+ try {
8307
+ return getAddress(address);
8308
+ } catch (err) {
8309
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
8310
+ }
8311
+ }
8312
+ function toBigInt(value, label) {
8313
+ if (value === void 0 || value === null) {
8314
+ throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
8315
+ }
8316
+ try {
8317
+ return BigInt(value.toString());
8318
+ } catch (err) {
8319
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
8320
+ }
8321
+ }
8322
+ function getAuctionContract(provider, auctionHouse) {
8323
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
8324
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8325
+ return new Contract(addr, ABI.SageAuctionHouse, provider);
8326
+ }
8327
+ async function getAuction({ provider, auctionHouse }) {
8328
+ const c = getAuctionContract(provider, auctionHouse);
8329
+ const res = await c.auction();
8330
+ const nftId = BigInt(res.nftId.toString());
8331
+ const amount = BigInt(res.amount.toString());
8332
+ const startTime = BigInt(res.startTime.toString());
8333
+ const endTime = BigInt(res.endTime.toString());
8334
+ const bidder = getAddress(res.bidder);
8335
+ const settled = !!res.settled;
8336
+ return { nftId, amount, startTime, endTime, bidder, settled };
8337
+ }
8338
+ async function getConfig({ provider, auctionHouse }) {
8339
+ const c = getAuctionContract(provider, auctionHouse);
8340
+ const [nft, treasury, weth, timeBuffer, reservePrice, minBidIncrementPercentage, duration, mintTierId, defaultTokenURI, paused, owner] = await Promise.all([
8341
+ c.nft(),
8342
+ c.treasury(),
8343
+ c.weth(),
8344
+ c.timeBuffer(),
8345
+ c.reservePrice(),
8346
+ c.minBidIncrementPercentage(),
8347
+ c.duration(),
8348
+ c.mintTierId(),
8349
+ c.defaultTokenURI(),
8350
+ c.paused(),
8351
+ c.owner()
8352
+ ]);
8353
+ return {
8354
+ nft: getAddress(nft),
8355
+ treasury: getAddress(treasury),
8356
+ weth: getAddress(weth),
8357
+ timeBuffer: BigInt(timeBuffer.toString()),
8358
+ reservePrice: BigInt(reservePrice.toString()),
8359
+ minBidIncrementPercentage: BigInt(minBidIncrementPercentage.toString()),
8360
+ duration: BigInt(duration.toString()),
8361
+ mintTierId: BigInt(mintTierId.toString()),
8362
+ defaultTokenURI: String(defaultTokenURI),
8363
+ paused: !!paused,
8364
+ owner: getAddress(owner)
8365
+ };
8366
+ }
8367
+ function buildCreateBidTx({ auctionHouse, nftId, value }) {
8368
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8369
+ const iface = new Interface(ABI.SageAuctionHouse);
8370
+ const data = iface.encodeFunctionData("createBid", [toBigInt(nftId, "nftId")]);
8371
+ return { to: addr, data, value: toBigInt(value, "value") };
8372
+ }
8373
+ function buildSettleAndCreateTx({ auctionHouse }) {
8374
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8375
+ const iface = new Interface(ABI.SageAuctionHouse);
8376
+ const data = iface.encodeFunctionData("settleCurrentAndCreateNewAuction", []);
8377
+ return { to: addr, data, value: 0n };
8378
+ }
8379
+ function buildSettleTx({ auctionHouse }) {
8380
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8381
+ const iface = new Interface(ABI.SageAuctionHouse);
8382
+ const data = iface.encodeFunctionData("settleAuction", []);
8383
+ return { to: addr, data, value: 0n };
8384
+ }
8385
+ function buildCreateAuctionTx({ auctionHouse }) {
8386
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8387
+ const iface = new Interface(ABI.SageAuctionHouse);
8388
+ const data = iface.encodeFunctionData("createAuction", []);
8389
+ return { to: addr, data, value: 0n };
8390
+ }
8391
+ function buildPauseTx({ auctionHouse }) {
8392
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8393
+ const iface = new Interface(ABI.SageAuctionHouse);
8394
+ const data = iface.encodeFunctionData("pause", []);
8395
+ return { to: addr, data, value: 0n };
8396
+ }
8397
+ function buildUnpauseTx({ auctionHouse }) {
8398
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8399
+ const iface = new Interface(ABI.SageAuctionHouse);
8400
+ const data = iface.encodeFunctionData("unpause", []);
8401
+ return { to: addr, data, value: 0n };
8402
+ }
8403
+ function buildSetTimeBufferTx({ auctionHouse, timeBuffer }) {
8404
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8405
+ const iface = new Interface(ABI.SageAuctionHouse);
8406
+ const data = iface.encodeFunctionData("setTimeBuffer", [toBigInt(timeBuffer, "timeBuffer")]);
8407
+ return { to: addr, data, value: 0n };
8408
+ }
8409
+ function buildSetReservePriceTx({ auctionHouse, reservePrice }) {
8410
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8411
+ const iface = new Interface(ABI.SageAuctionHouse);
8412
+ const data = iface.encodeFunctionData("setReservePrice", [toBigInt(reservePrice, "reservePrice")]);
8413
+ return { to: addr, data, value: 0n };
8414
+ }
8415
+ function buildSetMinBidIncrementTx({ auctionHouse, percentage }) {
8416
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8417
+ const iface = new Interface(ABI.SageAuctionHouse);
8418
+ const data = iface.encodeFunctionData("setMinBidIncrementPercentage", [toBigInt(percentage, "percentage")]);
8419
+ return { to: addr, data, value: 0n };
8420
+ }
8421
+ function buildSetDurationTx({ auctionHouse, duration }) {
8422
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8423
+ const iface = new Interface(ABI.SageAuctionHouse);
8424
+ const data = iface.encodeFunctionData("setDuration", [toBigInt(duration, "duration")]);
8425
+ return { to: addr, data, value: 0n };
8426
+ }
8427
+ function buildSetMintTierIdTx({ auctionHouse, tierId }) {
8428
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8429
+ const iface = new Interface(ABI.SageAuctionHouse);
8430
+ const data = iface.encodeFunctionData("setMintTierId", [toBigInt(tierId, "tierId")]);
8431
+ return { to: addr, data, value: 0n };
8432
+ }
8433
+ function buildSetDefaultTokenURITx({ auctionHouse, uri }) {
8434
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8435
+ const iface = new Interface(ABI.SageAuctionHouse);
8436
+ const data = iface.encodeFunctionData("setDefaultTokenURI", [String(uri ?? "")]);
8437
+ return { to: addr, data, value: 0n };
8438
+ }
8439
+ module2.exports = {
8440
+ getAuction,
8441
+ getConfig,
8442
+ buildCreateBidTx,
8443
+ buildSettleAndCreateTx,
8444
+ buildSettleTx,
8445
+ buildCreateAuctionTx,
8446
+ buildPauseTx,
8447
+ buildUnpauseTx,
8448
+ buildSetTimeBufferTx,
8449
+ buildSetReservePriceTx,
8450
+ buildSetMinBidIncrementTx,
8451
+ buildSetDurationTx,
8452
+ buildSetMintTierIdTx,
8453
+ buildSetDefaultTokenURITx
8454
+ };
8455
+ }
8456
+ });
8457
+
7102
8458
  // src/utils/provider.js
7103
8459
  var require_provider = __commonJS({
7104
8460
  "src/utils/provider.js"(exports2, module2) {
@@ -9904,6 +11260,273 @@ var require_client2 = __commonJS({
9904
11260
  }
9905
11261
  });
9906
11262
 
11263
+ // src/clients/discovery-client.js
11264
+ var require_discovery_client = __commonJS({
11265
+ "src/clients/discovery-client.js"(exports2, module2) {
11266
+ var DiscoveryClient = class {
11267
+ /**
11268
+ * @param {string} baseUrl - Base URL of the discovery API
11269
+ * @param {object} [options] - Client options
11270
+ * @param {number} [options.timeout=10000] - Request timeout in milliseconds
11271
+ * @param {Record<string, string>} [options.headers] - Custom headers
11272
+ */
11273
+ constructor(baseUrl, options = {}) {
11274
+ this.baseUrl = baseUrl.replace(/\/$/, "");
11275
+ this.timeout = options.timeout || 1e4;
11276
+ this.headers = options.headers || {};
11277
+ }
11278
+ /**
11279
+ * Search prompts with keyword matching and trend ranking
11280
+ * @param {string} query - Search query
11281
+ * @param {object} [options] - Search options
11282
+ * @param {string} [options.category] - Filter by category
11283
+ * @param {string[]} [options.tags] - Filter by tags
11284
+ * @param {string} [options.author] - Filter by author
11285
+ * @param {number} [options.limit] - Max results to return
11286
+ * @param {number} [options.offset] - Number of results to skip
11287
+ * @param {boolean} [options.useVector] - Use vector search
11288
+ * @returns {Promise<{results: Array, total: number}>}
11289
+ */
11290
+ async search(query, options = {}) {
11291
+ const params = new URLSearchParams();
11292
+ if (query) params.set("q", query);
11293
+ if (options.category) params.set("category", options.category);
11294
+ if (options.author) params.set("author", options.author);
11295
+ if (options.tags) {
11296
+ options.tags.forEach((tag) => params.append("tags", tag));
11297
+ }
11298
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11299
+ if (options.offset !== void 0) params.set("offset", String(options.offset));
11300
+ if (options.useVector !== void 0) params.set("useVector", String(options.useVector));
11301
+ return this._get(`/discover/search?${params}`);
11302
+ }
11303
+ /**
11304
+ * Get trending prompts by time window
11305
+ * @param {object} [options] - Trending options
11306
+ * @param {'1h'|'24h'|'7d'|'30d'|'all'} [options.window] - Time window
11307
+ * @param {string} [options.category] - Filter by category
11308
+ * @param {number} [options.limit] - Max results to return
11309
+ * @param {number} [options.offset] - Number of results to skip
11310
+ * @returns {Promise<{results: Array}>}
11311
+ */
11312
+ async trending(options = {}) {
11313
+ const params = new URLSearchParams();
11314
+ if (options.window) params.set("window", options.window);
11315
+ if (options.category) params.set("category", options.category);
11316
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11317
+ if (options.offset !== void 0) params.set("offset", String(options.offset));
11318
+ return this._get(`/discover/trending?${params}`);
11319
+ }
11320
+ /**
11321
+ * Get trending prompts (alias for /trends/top endpoint)
11322
+ * @param {object} [options] - Trending options
11323
+ * @param {'1h'|'24h'|'7d'|'30d'|'all'} [options.window] - Time window
11324
+ * @param {number} [options.limit] - Max results to return
11325
+ * @param {number} [options.offset] - Number of results to skip
11326
+ * @returns {Promise<{results: Array}>}
11327
+ */
11328
+ async trendingTop(options = {}) {
11329
+ const params = new URLSearchParams();
11330
+ if (options.window) params.set("window", options.window);
11331
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11332
+ if (options.offset !== void 0) params.set("offset", String(options.offset));
11333
+ return this._get(`/trends/top?${params}`);
11334
+ }
11335
+ /**
11336
+ * Find prompts matching user preferences
11337
+ *
11338
+ * Note: This endpoint is not yet implemented in the backend.
11339
+ * This is a placeholder for future implementation.
11340
+ * @param {object} preferences - User preferences
11341
+ * @param {string[]} [preferences.recentPrompts] - Recent prompt CIDs
11342
+ * @param {string[]} [preferences.preferredTags] - Preferred tags
11343
+ * @param {string[]} [preferences.preferredCategories] - Preferred categories
11344
+ * @param {string[]} [preferences.excludeAuthors] - Authors to exclude
11345
+ * @param {number} [preferences.limit] - Max results
11346
+ * @param {boolean} [preferences.diversify] - Diversify results
11347
+ * @returns {Promise<{results: Array, total: number}>}
11348
+ */
11349
+ async match(preferences) {
11350
+ return this._post("/discover/match", preferences);
11351
+ }
11352
+ /**
11353
+ * Find prompts similar to a given prompt
11354
+ * @param {string} cid - Prompt CID to find similar prompts for
11355
+ * @param {object} [options] - Similar options
11356
+ * @param {number} [options.limit] - Max results to return
11357
+ * @param {'vector'|'keyword'|'hybrid'} [options.method] - Similarity method
11358
+ * @returns {Promise<{similar: Array}>}
11359
+ */
11360
+ async similar(cid, options = {}) {
11361
+ const params = new URLSearchParams();
11362
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11363
+ if (options.method) params.set("method", options.method);
11364
+ return this._get(`/discover/similar/${cid}?${params}`);
11365
+ }
11366
+ /**
11367
+ * Get popular tags with optional clustering
11368
+ * @param {object} [options] - Tags options
11369
+ * @param {number} [options.limit] - Max tags to return
11370
+ * @param {string} [options.category] - Filter by category
11371
+ * @param {boolean} [options.clusters] - Enable tag clustering
11372
+ * @returns {Promise<{tags: Array}>}
11373
+ */
11374
+ async tags(options = {}) {
11375
+ const params = new URLSearchParams();
11376
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11377
+ if (options.category) params.set("category", options.category);
11378
+ if (options.clusters !== void 0) params.set("clusters", String(options.clusters));
11379
+ return this._get(`/discover/tags?${params}`);
11380
+ }
11381
+ /**
11382
+ * Get category statistics
11383
+ *
11384
+ * Note: This endpoint is not yet implemented in the backend.
11385
+ * This is a placeholder for future implementation.
11386
+ * @returns {Promise<{categories: Array}>}
11387
+ */
11388
+ async categories() {
11389
+ return this._get("/discover/categories");
11390
+ }
11391
+ /**
11392
+ * Get prompts by tag
11393
+ * @param {string} tag - Tag to search for
11394
+ * @param {number} [limit] - Max results to return
11395
+ * @returns {Promise<{results: Array}>}
11396
+ */
11397
+ async promptsByTag(tag, limit) {
11398
+ const params = new URLSearchParams();
11399
+ if (limit !== void 0) params.set("limit", String(limit));
11400
+ const encodedTag = encodeURIComponent(tag);
11401
+ return this._get(`/discover/by-tag/${encodedTag}?${params}`);
11402
+ }
11403
+ /**
11404
+ * Get index statistics
11405
+ * @returns {Promise<{totalPrompts: number, totalTags: number, avgTrendScore: number}>}
11406
+ */
11407
+ async stats() {
11408
+ return this._get("/discover/stats");
11409
+ }
11410
+ /**
11411
+ * Get trend signals for a specific CID
11412
+ * @param {string} cid - Prompt CID
11413
+ * @returns {Promise<{usageCount: number, forkCount: number, purchaseCount: number, uniqueBuyers: number, governanceVotes: number, lastActivityAt: number}>}
11414
+ */
11415
+ async trendSignals(cid) {
11416
+ return this._get(`/trends/signals/${cid}`);
11417
+ }
11418
+ /**
11419
+ * Get trend history for a specific CID
11420
+ * @param {string} cid - Prompt CID
11421
+ * @param {object} [options] - History options
11422
+ * @param {number} [options.limit] - Max history entries
11423
+ * @param {number} [options.since] - Timestamp to start from
11424
+ * @returns {Promise<{history: Array}>}
11425
+ */
11426
+ async trendHistory(cid, options = {}) {
11427
+ const params = new URLSearchParams();
11428
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11429
+ if (options.since !== void 0) params.set("since", String(options.since));
11430
+ return this._get(`/trends/history/${cid}?${params}`);
11431
+ }
11432
+ /**
11433
+ * Get trend statistics
11434
+ * @returns {Promise<{totalTracked: number, avgScore: number, maxScore: number, recentlyActive: number}>}
11435
+ */
11436
+ async trendStats() {
11437
+ return this._get("/trends/stats");
11438
+ }
11439
+ /**
11440
+ * Record a usage event for a prompt (requires authentication)
11441
+ * @param {string} cid - Prompt CID
11442
+ * @returns {Promise<{ok: boolean}>}
11443
+ */
11444
+ async recordUsage(cid) {
11445
+ return this._post("/trends/usage", { cid });
11446
+ }
11447
+ // Private fetch helpers
11448
+ /**
11449
+ * Perform a GET request
11450
+ * @private
11451
+ * @param {string} path - API path
11452
+ * @returns {Promise<any>}
11453
+ */
11454
+ async _get(path2) {
11455
+ const controller = new AbortController();
11456
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
11457
+ try {
11458
+ const response = await fetch(`${this.baseUrl}${path2}`, {
11459
+ method: "GET",
11460
+ headers: {
11461
+ "Accept": "application/json",
11462
+ ...this.headers
11463
+ },
11464
+ signal: controller.signal
11465
+ });
11466
+ clearTimeout(timeoutId);
11467
+ if (!response.ok) {
11468
+ const errorBody = await response.text().catch(() => "Unknown error");
11469
+ throw new Error(`HTTP ${response.status}: ${errorBody}`);
11470
+ }
11471
+ return await response.json();
11472
+ } catch (error) {
11473
+ clearTimeout(timeoutId);
11474
+ if (error.name === "AbortError") {
11475
+ throw new Error(`Request timeout after ${this.timeout}ms`);
11476
+ }
11477
+ throw error;
11478
+ }
11479
+ }
11480
+ /**
11481
+ * Perform a POST request
11482
+ * @private
11483
+ * @param {string} path - API path
11484
+ * @param {any} body - Request body
11485
+ * @returns {Promise<any>}
11486
+ */
11487
+ async _post(path2, body) {
11488
+ const controller = new AbortController();
11489
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
11490
+ try {
11491
+ const response = await fetch(`${this.baseUrl}${path2}`, {
11492
+ method: "POST",
11493
+ headers: {
11494
+ "Accept": "application/json",
11495
+ "Content-Type": "application/json",
11496
+ ...this.headers
11497
+ },
11498
+ body: JSON.stringify(body),
11499
+ signal: controller.signal
11500
+ });
11501
+ clearTimeout(timeoutId);
11502
+ if (!response.ok) {
11503
+ const errorBody = await response.text().catch(() => "Unknown error");
11504
+ throw new Error(`HTTP ${response.status}: ${errorBody}`);
11505
+ }
11506
+ return await response.json();
11507
+ } catch (error) {
11508
+ clearTimeout(timeoutId);
11509
+ if (error.name === "AbortError") {
11510
+ throw new Error(`Request timeout after ${this.timeout}ms`);
11511
+ }
11512
+ throw error;
11513
+ }
11514
+ }
11515
+ };
11516
+ module2.exports = { DiscoveryClient };
11517
+ }
11518
+ });
11519
+
11520
+ // src/clients/index.js
11521
+ var require_clients = __commonJS({
11522
+ "src/clients/index.js"(exports2, module2) {
11523
+ var { DiscoveryClient } = require_discovery_client();
11524
+ module2.exports = {
11525
+ DiscoveryClient
11526
+ };
11527
+ }
11528
+ });
11529
+
9907
11530
  // src/hooks/useSubDAOs.js
9908
11531
  var require_useSubDAOs = __commonJS({
9909
11532
  "src/hooks/useSubDAOs.js"(exports2, module2) {
@@ -10114,6 +11737,7 @@ var require_src = __commonJS({
10114
11737
  var timelock = require_timelock();
10115
11738
  var factory = require_factory();
10116
11739
  var library = require_library();
11740
+ var lineage = require_lineage();
10117
11741
  var prompt = require_prompt();
10118
11742
  var { SageEchoExecutor } = require_execute();
10119
11743
  var ipfs = require_ipfs();
@@ -10127,6 +11751,8 @@ var require_src = __commonJS({
10127
11751
  var treasury = require_treasury();
10128
11752
  var boost = require_boost();
10129
11753
  var bounty = require_bounty();
11754
+ var votingMultiplier = require_votingMultiplier();
11755
+ var auction = require_auction();
10130
11756
  var wallet = require_wallet();
10131
11757
  wallet.session = require_session();
10132
11758
  var walletCastManager = require_cast_manager();
@@ -10147,6 +11773,7 @@ var require_src = __commonJS({
10147
11773
  var serviceErrors = require_errors2();
10148
11774
  var { SimpleCache } = require_cache();
10149
11775
  var { retryWithBackoff } = require_retry();
11776
+ var { DiscoveryClient } = require_clients();
10150
11777
  var hooks = null;
10151
11778
  try {
10152
11779
  hooks = require_hooks();
@@ -10162,6 +11789,7 @@ var require_src = __commonJS({
10162
11789
  timelock,
10163
11790
  factory,
10164
11791
  library,
11792
+ lineage,
10165
11793
  prompt,
10166
11794
  ipfs,
10167
11795
  ipns,
@@ -10174,6 +11802,8 @@ var require_src = __commonJS({
10174
11802
  subgraph,
10175
11803
  utils: { ...utils, privateTx, safe, time },
10176
11804
  bounty,
11805
+ votingMultiplier,
11806
+ auction,
10177
11807
  wallet: Object.assign(wallet, {
10178
11808
  cast: walletCastManager,
10179
11809
  cdp: walletCdpManager
@@ -10194,6 +11824,11 @@ var require_src = __commonJS({
10194
11824
  SimpleCache,
10195
11825
  retryWithBackoff
10196
11826
  },
11827
+ // Client exports
11828
+ clients: {
11829
+ DiscoveryClient
11830
+ },
11831
+ DiscoveryClient,
10197
11832
  // React hooks (optional - requires react + swr peer dependencies)
10198
11833
  hooks,
10199
11834
  // Legacy exports (deprecated): maintain compatibility while consumers migrate