@sage-protocol/sdk 0.1.18 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +97 -0
- package/dist/browser/index.mjs +11 -10
- package/dist/index.cjs +1735 -100
- package/dist/index.mjs +1731 -96
- package/dist/node/index.cjs +1731 -96
- package/dist/node/index.mjs +1731 -96
- package/package.json +1 -1
- package/types/index.d.ts +169 -1
package/dist/index.cjs
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
1808
|
-
|
|
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
|
-
|
|
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
|
errors2.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: prompt2, providers, provider, warm, gateways } = options2;
|
|
2005
|
+
const { prompt: prompt2, providers, provider, warm, gateways, pin: pin2 } = options2;
|
|
1921
2006
|
if (!prompt2 || typeof prompt2 !== "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: `${prompt2.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
|
|
3040
|
-
|
|
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
|
|
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 token2 = await g.sxxxToken();
|
|
3124
3206
|
return buildDelegateTx({ token: token2, delegatee: account });
|
|
3125
3207
|
}
|
|
3208
|
+
async function resolveVotesTokenChain({ provider, subdao: subdao2, governor }) {
|
|
3209
|
+
if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
|
|
3210
|
+
if (!subdao2 && !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 && subdao2) {
|
|
3238
|
+
try {
|
|
3239
|
+
const subAddr = getAddress(subdao2);
|
|
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 (!subdao2 || daoNorm === getAddress(subdao2)) {
|
|
3271
|
+
baseToken = baseNorm;
|
|
3272
|
+
isWrapper = true;
|
|
3273
|
+
}
|
|
3274
|
+
}
|
|
3275
|
+
} catch (_) {
|
|
3276
|
+
}
|
|
3277
|
+
return { votingToken: votingTokenNorm, baseToken, isWrapper };
|
|
3278
|
+
}
|
|
3279
|
+
async function describeVotesToken({ provider, subdao: subdao2, governor }) {
|
|
3280
|
+
const { votingToken, baseToken, isWrapper } = await resolveVotesTokenChain({ provider, subdao: subdao2, 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 (subdao2) {
|
|
3302
|
+
description += ` for DAO ${getAddress(subdao2)}`;
|
|
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: subdao2, governor, account }) {
|
|
3315
|
+
if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
|
|
3316
|
+
if (!governor && !subdao2) 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 (subdao2) {
|
|
3325
|
+
subdaoAddr = getAddress(subdao2);
|
|
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: subdao2, governor }) {
|
|
3157
|
-
|
|
3158
|
-
|
|
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 (subdao2) {
|
|
3183
|
-
try {
|
|
3184
|
-
const subAddr = getAddress(subdao2);
|
|
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: subdao2, 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: subdao2, 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
|
|
3202
|
-
return buildDelegateTx({ token:
|
|
3463
|
+
const { baseToken } = await resolveVotesTokenChain({ provider, subdao: subdao2, 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: subdao2, 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
|
|
3212
|
-
const payload = buildDelegateTx({ token:
|
|
3473
|
+
const { votingToken, baseToken } = await resolveVotesTokenChain({ provider, subdao: subdao2, 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:
|
|
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
|
|
3274
|
-
const votes = await getVotesLatestMinusOne({ provider, token:
|
|
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: timelock2, receipts };
|
|
3800
|
-
}
|
|
3801
|
-
module2.exports = {
|
|
3802
|
-
communityDraftsBoardExec,
|
|
3803
|
-
tokenDemocracy
|
|
4060
|
+
const receipts = await executeSequence(actions);
|
|
4061
|
+
return { governor, timelock: timelock2, 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: subdao2, first = 50, skip = 0 }) {
|
|
4264
|
+
const where = subdao2 ? `where: { subDAO: "${String(subdao2).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: subdao2, first = 20, skip = 0 }) {
|
|
4290
|
+
if (!url) throw new Error("subgraph url required");
|
|
4291
|
+
const hasFilter = !!subdao2;
|
|
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(subdao2);
|
|
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: subdao2 = null, first = 50, skip = 0, orderBy = "blockTimestamp", orderDirection = "desc" }) {
|
|
4453
|
+
if (!url) throw new Error("subgraph url required");
|
|
4454
|
+
const filters = [];
|
|
4455
|
+
if (subdao2) {
|
|
4456
|
+
const addr = safeGetAddress(subdao2);
|
|
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: subdao2 = null, first = 50, skip = 0, orderBy = "blockTimestamp", orderDirection = "desc" }) {
|
|
4494
|
+
if (!url) throw new Error("subgraph url required");
|
|
4495
|
+
const filters = [];
|
|
4496
|
+
if (subdao2) {
|
|
4497
|
+
const addr = safeGetAddress(subdao2);
|
|
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 subgraph2 = require_subgraph2();
|
|
5037
|
+
const sgProposal = await subgraph2.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 = subdao2;
|
|
4387
5267
|
if (!resolvedSubDAO) {
|
|
4388
|
-
|
|
4389
|
-
|
|
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 governance2.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: subdao2 }) {
|
|
6080
|
+
if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
|
|
6081
|
+
if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
|
|
6082
|
+
if (!subdao2) 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(subdao2, "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: subdao2 }) {
|
|
6096
|
+
if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
|
|
6097
|
+
if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
|
|
6098
|
+
if (!subdao2) 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(subdao2, "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: subdao2 }) {
|
|
6125
|
+
const parent = await getParentLibrary({ provider, registry, subdao: subdao2 });
|
|
6126
|
+
return parent !== null;
|
|
6127
|
+
}
|
|
6128
|
+
async function getLibraryForkFee({ provider, registry, subdao: subdao2 }) {
|
|
6129
|
+
if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
|
|
6130
|
+
if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
|
|
6131
|
+
if (!subdao2) 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(subdao2, "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: subdao2 }) {
|
|
6141
|
+
if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
|
|
6142
|
+
if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
|
|
6143
|
+
if (!subdao2) 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(subdao2, "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: treasury2 }) {
|
|
6556
7568
|
if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
|
|
6557
7569
|
const addr = normalise(treasury2, "treasury");
|
|
6558
|
-
const contract = new Contract(addr,
|
|
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: treasury2, ids, limit = 50 }) {
|
|
6580
7592
|
if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
|
|
6581
7593
|
const addr = normalise(treasury2, "treasury");
|
|
6582
|
-
const contract = new Contract(addr,
|
|
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: treasury2 }) {
|
|
6612
7624
|
if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
|
|
6613
7625
|
const addr = normalise(treasury2, "treasury");
|
|
6614
|
-
const contract = new Contract(addr,
|
|
7626
|
+
const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
|
|
6615
7627
|
const tokens = await contract.getReserveTokens().catch(() => []);
|
|
6616
7628
|
return tokens.map((token2) => getAddress(token2));
|
|
6617
7629
|
}
|
|
6618
7630
|
async function getReserves({ provider, treasury: treasury2, tokens, fetchMetadata = true }) {
|
|
6619
7631
|
if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
|
|
6620
7632
|
const addr = normalise(treasury2, "treasury");
|
|
6621
|
-
const contract = new Contract(addr,
|
|
7633
|
+
const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
|
|
6622
7634
|
const tokenList = Array.isArray(tokens) && tokens.length ? tokens.map((token2) => getAddress(token2)) : await contract.getReserveTokens().catch(() => []);
|
|
6623
7635
|
const reserves = [];
|
|
6624
7636
|
for (const token2 of tokenList) {
|
|
@@ -6648,7 +7660,7 @@ var require_treasury = __commonJS({
|
|
|
6648
7660
|
async function getManualPriceOverrides({ provider, treasury: treasury2, tokens }) {
|
|
6649
7661
|
if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
|
|
6650
7662
|
const addr = normalise(treasury2, "treasury");
|
|
6651
|
-
const contract = new Contract(addr,
|
|
7663
|
+
const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
|
|
6652
7664
|
const tokenList = Array.isArray(tokens) && tokens.length ? tokens.map((token2) => getAddress(token2)) : await contract.getReserveTokens().catch(() => []);
|
|
6653
7665
|
const overrides = [];
|
|
6654
7666
|
for (const token2 of tokenList) {
|
|
@@ -6753,7 +7765,7 @@ var require_treasury = __commonJS({
|
|
|
6753
7765
|
async function getLPContribution({ provider, treasury: treasury2, subdao: subdao2, token: token2 }) {
|
|
6754
7766
|
if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
|
|
6755
7767
|
const addr = normalise(treasury2, "treasury");
|
|
6756
|
-
const c = new Contract(addr,
|
|
7768
|
+
const c = new Contract(addr, SAGE_TREASURY_ABI, provider);
|
|
6757
7769
|
const amount = await c.lpContributions(normalise(subdao2, "subdao"), normalise(token2, "token")).catch(() => 0n);
|
|
6758
7770
|
return amount;
|
|
6759
7771
|
}
|
|
@@ -6795,7 +7807,7 @@ var require_treasury = __commonJS({
|
|
|
6795
7807
|
function createWriteContract({ signer, treasury: treasury2 }) {
|
|
6796
7808
|
if (!signer) throw new SageSDKError(CODES.INVALID_ARGS, "signer required");
|
|
6797
7809
|
const addr = normalise(treasury2, "treasury");
|
|
6798
|
-
return new Contract(addr,
|
|
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, treasury2, 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(treasury2),
|
|
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) {
|
|
@@ -8962,8 +10318,8 @@ var require_doppler = __commonJS({
|
|
|
8962
10318
|
return res;
|
|
8963
10319
|
};
|
|
8964
10320
|
module2.exports.getStaticPoolInfo = async function getStaticPoolInfo(sdk, poolAddress) {
|
|
8965
|
-
const
|
|
8966
|
-
return
|
|
10321
|
+
const auction2 = await sdk.getStaticAuction(poolAddress);
|
|
10322
|
+
return auction2.getPoolInfo();
|
|
8967
10323
|
};
|
|
8968
10324
|
module2.exports.quoteV3ExactIn = async function quoteV3ExactIn(sdk, { tokenIn, tokenOut, amountIn, fee, sqrtPriceLimitX96 = 0n }) {
|
|
8969
10325
|
return sdk.quoter.quoteExactInputV3({ tokenIn, tokenOut, amountIn, fee, sqrtPriceLimitX96 });
|
|
@@ -8986,8 +10342,8 @@ var require_doppler = __commonJS({
|
|
|
8986
10342
|
return { deposited: needed, hash };
|
|
8987
10343
|
};
|
|
8988
10344
|
module2.exports.getDynamicHookInfo = async function getDynamicHookInfo(sdk, hookAddress) {
|
|
8989
|
-
const
|
|
8990
|
-
return
|
|
10345
|
+
const auction2 = await sdk.getDynamicAuction(hookAddress);
|
|
10346
|
+
return auction2.getHookInfo();
|
|
8991
10347
|
};
|
|
8992
10348
|
module2.exports.quoteV4ExactIn = async function quoteV4ExactIn(sdk, { poolKey, zeroForOne, exactAmount, hookData }) {
|
|
8993
10349
|
return sdk.quoter.quoteExactInputV4({ poolKey, zeroForOne, exactAmount, hookData });
|
|
@@ -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 DiscoveryClient2 = 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: DiscoveryClient2 };
|
|
11517
|
+
}
|
|
11518
|
+
});
|
|
11519
|
+
|
|
11520
|
+
// src/clients/index.js
|
|
11521
|
+
var require_clients = __commonJS({
|
|
11522
|
+
"src/clients/index.js"(exports2, module2) {
|
|
11523
|
+
var { DiscoveryClient: DiscoveryClient2 } = require_discovery_client();
|
|
11524
|
+
module2.exports = {
|
|
11525
|
+
DiscoveryClient: DiscoveryClient2
|
|
11526
|
+
};
|
|
11527
|
+
}
|
|
11528
|
+
});
|
|
11529
|
+
|
|
9907
11530
|
// src/hooks/useSubDAOs.js
|
|
9908
11531
|
var require_useSubDAOs = __commonJS({
|
|
9909
11532
|
"src/hooks/useSubDAOs.js"(exports2, module2) {
|
|
@@ -10112,6 +11735,7 @@ var subdao = require_subdao();
|
|
|
10112
11735
|
var timelock = require_timelock();
|
|
10113
11736
|
var factory = require_factory();
|
|
10114
11737
|
var library = require_library();
|
|
11738
|
+
var lineage = require_lineage();
|
|
10115
11739
|
var prompt = require_prompt();
|
|
10116
11740
|
var { SageEchoExecutor } = require_execute();
|
|
10117
11741
|
var ipfs = require_ipfs();
|
|
@@ -10125,6 +11749,8 @@ var time = require_time();
|
|
|
10125
11749
|
var treasury = require_treasury();
|
|
10126
11750
|
var boost = require_boost();
|
|
10127
11751
|
var bounty = require_bounty();
|
|
11752
|
+
var votingMultiplier = require_votingMultiplier();
|
|
11753
|
+
var auction = require_auction();
|
|
10128
11754
|
var wallet = require_wallet();
|
|
10129
11755
|
wallet.session = require_session();
|
|
10130
11756
|
var walletCastManager = require_cast_manager();
|
|
@@ -10145,6 +11771,7 @@ var { IPFSService } = require_client2();
|
|
|
10145
11771
|
var serviceErrors = require_errors2();
|
|
10146
11772
|
var { SimpleCache } = require_cache();
|
|
10147
11773
|
var { retryWithBackoff } = require_retry();
|
|
11774
|
+
var { DiscoveryClient } = require_clients();
|
|
10148
11775
|
var hooks = null;
|
|
10149
11776
|
try {
|
|
10150
11777
|
hooks = require_hooks();
|
|
@@ -10160,6 +11787,7 @@ module.exports = {
|
|
|
10160
11787
|
timelock,
|
|
10161
11788
|
factory,
|
|
10162
11789
|
library,
|
|
11790
|
+
lineage,
|
|
10163
11791
|
prompt,
|
|
10164
11792
|
ipfs,
|
|
10165
11793
|
ipns,
|
|
@@ -10172,6 +11800,8 @@ module.exports = {
|
|
|
10172
11800
|
subgraph,
|
|
10173
11801
|
utils: { ...utils, privateTx, safe, time },
|
|
10174
11802
|
bounty,
|
|
11803
|
+
votingMultiplier,
|
|
11804
|
+
auction,
|
|
10175
11805
|
wallet: Object.assign(wallet, {
|
|
10176
11806
|
cast: walletCastManager,
|
|
10177
11807
|
cdp: walletCdpManager
|
|
@@ -10192,6 +11822,11 @@ module.exports = {
|
|
|
10192
11822
|
SimpleCache,
|
|
10193
11823
|
retryWithBackoff
|
|
10194
11824
|
},
|
|
11825
|
+
// Client exports
|
|
11826
|
+
clients: {
|
|
11827
|
+
DiscoveryClient
|
|
11828
|
+
},
|
|
11829
|
+
DiscoveryClient,
|
|
10195
11830
|
// React hooks (optional - requires react + swr peer dependencies)
|
|
10196
11831
|
hooks,
|
|
10197
11832
|
// Legacy exports (deprecated): maintain compatibility while consumers migrate
|