@sage-protocol/sdk 0.1.18 → 0.1.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.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.18",
17
+ version: "0.1.23",
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",
@@ -119,7 +119,12 @@ var require_abi = __commonJS({
119
119
  "function userForkCount(address) view returns (uint256)",
120
120
  "function forkCount(string) view returns (uint256)",
121
121
  "function stake(uint256)",
122
- "function unstake(uint256)"
122
+ "function unstake(uint256)",
123
+ // Fork functions
124
+ "function forkSubDAO(string,string)",
125
+ "function forkSubDAO(string,string,bool)",
126
+ "function forkSubDAOWithStable(string,string,(uint256,uint256,uint8,bytes32,bytes32))",
127
+ "function forkSubDAOWithStable(string,string,(uint256,uint256,uint8,bytes32,bytes32),bool)"
123
128
  ];
124
129
  var Factory = [
125
130
  "event SubDAOGovernanceDeployed(address indexed subDAO, address indexed governor, address timelock, address treasury)"
@@ -130,7 +135,6 @@ var require_abi = __commonJS({
130
135
  "function stableCreationFee() view returns (uint256)",
131
136
  "function stableFeeReceiver() view returns (address)",
132
137
  "function stableCreationEnabled() view returns (bool)",
133
- "function stablePromptForkFee() view returns (uint256)",
134
138
  "function stableForkFee() view returns (uint256)",
135
139
  // Core factory reads
136
140
  "function timelockMinDelay() view returns (uint256)",
@@ -160,8 +164,8 @@ var require_abi = __commonJS({
160
164
  "function createSubDAOOperatorWithStableAdvanced(string name, string description, uint8 accessModel, uint256 minStakeAmount, address operatorExecutor, address operatorAdmin, bool anyoneExec, bool governorProposer, (uint256 value,uint256 deadline,uint8 v,bytes32 r,bytes32 s) permit) returns (address subDAO, address registry)",
161
165
  "function createSubDAOOperator(string name, string description, uint8 accessModel, uint256 minStakeAmount, uint256 burnAmount, address operatorExecutor, address operatorAdmin) returns (address subDAO, address registry)",
162
166
  "function createSubDAOOperatorAdvanced(string name, string description, uint8 accessModel, uint256 minStakeAmount, uint256 burnAmount, address operatorExecutor, address operatorAdmin, bool anyoneExec, bool governorProposer) returns (address subDAO, address registry)",
163
- "function createForkedSubDAO(string newName, string newDescription, string originalName, address originalSubDAO, address forker) returns (address subDAO, address registry)",
164
- "function createForkedSubDAOWithStable(string newName, string newDescription, string originalName, address originalSubDAO, address forker, uint64 authorizationNonce, (uint256 value,uint256 deadline,uint8 v,bytes32 r,bytes32 s) permit) returns (address subDAO, address registry)"
167
+ "function createForkedSubDAO(string newName, string newDescription, string originalName, address originalSubDAO, address forker, bool copyLibrary) returns (address subDAO, address registry)",
168
+ "function createForkedSubDAOWithStable(string newName, string newDescription, string originalName, address originalSubDAO, address forker, uint64 authorizationNonce, (uint256 value,uint256 deadline,uint8 v,bytes32 r,bytes32 s) permit, bool copyLibrary) returns (address subDAO, address registry)"
165
169
  ];
166
170
  var TemplateModule = [
167
171
  "function getActiveTemplates() view returns (uint256[])",
@@ -172,13 +176,19 @@ var require_abi = __commonJS({
172
176
  "function maxCreationBurn() view returns (uint256)"
173
177
  ];
174
178
  var LibraryRegistry = [
175
- "function libraryByDAO(address) view returns (string manifestCID, address lastUpdater, uint256 lastUpdated, string version)",
179
+ "function libraryByDAO(address) view returns (string manifestCID, address lastUpdater, uint256 lastUpdated, string version, address forkedFromDAO, uint256 sxxxForkFee)",
176
180
  "function daoTimelock(address) view returns (address)",
177
- "function getLibrary(address) view returns (tuple(string manifestCID, address lastUpdater, uint256 lastUpdated, string version))",
181
+ "function getLibrary(address) view returns (tuple(string manifestCID, address lastUpdater, uint256 lastUpdated, string version, address forkedFromDAO, uint256 sxxxForkFee))",
182
+ "function getLibraryForkFee(address dao) view returns (uint256)",
183
+ "function setLibraryForkFee(address dao, uint256 fee)",
178
184
  "function updateLibrary(address dao, string manifestCID, string version)",
179
185
  "function registerDAO(address dao, address timelock)",
186
+ "function registerForkedDAO(address childDAO, address childTimelock, address parentDAO, string manifestCID, string version)",
187
+ "function initializeLibraryFromFork(address sourceDao, address forkedDao)",
180
188
  "event LibraryUpdated(address indexed dao, string manifestCID, address indexed timelock, string version)",
181
- "event DAORegistered(address indexed dao, address indexed timelock)"
189
+ "event DAORegistered(address indexed dao, address indexed timelock)",
190
+ "event LibraryForked(address indexed sourceDao, address indexed forkedDao, string manifestCID)",
191
+ "event LibraryForkFeeUpdated(address indexed dao, uint256 fee)"
182
192
  ];
183
193
  var PromptRegistry = [
184
194
  "function prompts(string key) view returns (string cid, uint256 version, uint256 timestamp, address author, string forkedFromCID, address originalAuthor, bool isFork, uint256 forkDepth)",
@@ -1507,19 +1517,656 @@ var require_subgraph = __commonJS({
1507
1517
  updatedAt: Number(p.updatedAt || 0)
1508
1518
  };
1509
1519
  },
1510
- async getProposalById({ url, id: id2 }) {
1520
+ async getProposalById({ url, id: id2 }) {
1521
+ if (!url) throw new Error("subgraph url required");
1522
+ const doc = `query($id: ID!){ proposal(id:$id){ id proposer description createdAt updatedAt state eta targets values calldatas } }`;
1523
+ const data = await query(url, doc, { id: String(id2) });
1524
+ const p = data?.proposal;
1525
+ if (!p) return null;
1526
+ try {
1527
+ const proposer = safeGetAddress(p.proposer);
1528
+ if (!proposer) return null;
1529
+ const targets = (p.targets || []).map((t) => safeGetAddress(t)).filter(Boolean);
1530
+ if (!targets.length && (p.targets || []).length) return null;
1531
+ return {
1532
+ id: BigInt(p.id),
1533
+ proposer,
1534
+ description: p.description || "",
1535
+ createdAt: Number(p.createdAt || 0),
1536
+ updatedAt: Number(p.updatedAt || 0),
1537
+ state: String(p.state || ""),
1538
+ eta: p.eta ? BigInt(String(p.eta)) : null,
1539
+ targets,
1540
+ values: (p.values || []).map((v) => BigInt(String(v))),
1541
+ calldatas: p.calldatas || []
1542
+ };
1543
+ } catch {
1544
+ return null;
1545
+ }
1546
+ }
1547
+ };
1548
+ }
1549
+ });
1550
+
1551
+ // src/adapters/transports.js
1552
+ var require_transports = __commonJS({
1553
+ "src/adapters/transports.js"(exports2, module2) {
1554
+ function createTransports({ provider, signer = null, subgraph: subgraph2 = null }) {
1555
+ return function resolve(kind) {
1556
+ switch (kind) {
1557
+ case "rpc":
1558
+ return provider;
1559
+ case "signer":
1560
+ return { signer };
1561
+ case "subgraph":
1562
+ return { url: subgraph2 };
1563
+ default:
1564
+ return null;
1565
+ }
1566
+ };
1567
+ }
1568
+ module2.exports = {
1569
+ createTransports
1570
+ };
1571
+ }
1572
+ });
1573
+
1574
+ // src/browser/utils.js
1575
+ var require_utils = __commonJS({
1576
+ "src/browser/utils.js"(exports2, module2) {
1577
+ function getAddress(address) {
1578
+ if (!address) return address;
1579
+ const addr = String(address).trim();
1580
+ const normalized = addr.startsWith("0x") ? addr.slice(2).toLowerCase() : addr.toLowerCase();
1581
+ return `0x${normalized}`;
1582
+ }
1583
+ async function keccak256Async(data) {
1584
+ const encoder = new TextEncoder();
1585
+ const dataBuffer = typeof data === "string" ? encoder.encode(data) : data;
1586
+ const hashBuffer = await crypto.subtle.digest("SHA-256", dataBuffer);
1587
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
1588
+ const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
1589
+ return `0x${hashHex}`;
1590
+ }
1591
+ function keccak256Sync(data) {
1592
+ const str = typeof data === "string" ? data : JSON.stringify(data);
1593
+ let hash = 0;
1594
+ for (let i = 0; i < str.length; i++) {
1595
+ const char = str.charCodeAt(i);
1596
+ hash = (hash << 5) - hash + char;
1597
+ hash = hash & hash;
1598
+ }
1599
+ const hex = Math.abs(hash).toString(16).padStart(8, "0");
1600
+ return `0x${hex.repeat(8)}`.slice(0, 66);
1601
+ }
1602
+ module2.exports = {
1603
+ getAddress,
1604
+ keccak256Async,
1605
+ keccak256Sync
1606
+ };
1607
+ }
1608
+ });
1609
+
1610
+ // src/browser/subgraph.js
1611
+ var require_subgraph2 = __commonJS({
1612
+ "src/browser/subgraph.js"(exports2, module2) {
1613
+ var { getAddress } = require_utils();
1614
+ function sanitizeOrderBy(orderBy, allowed, fallback) {
1615
+ const value = (orderBy || "").toString();
1616
+ return allowed.includes(value) ? value : fallback;
1617
+ }
1618
+ function sanitizeOrderDirection(direction, fallback = "desc") {
1619
+ const v = (direction || "").toString().toLowerCase();
1620
+ return v === "asc" ? "asc" : "desc";
1621
+ }
1622
+ function safeGetAddress(value) {
1623
+ try {
1624
+ return getAddress(value);
1625
+ } catch {
1626
+ return null;
1627
+ }
1628
+ }
1629
+ function mapSafe(list, mapper) {
1630
+ const out = [];
1631
+ for (const item of list || []) {
1632
+ try {
1633
+ const v = mapper(item);
1634
+ if (v != null) out.push(v);
1635
+ } catch {
1636
+ }
1637
+ }
1638
+ return out;
1639
+ }
1640
+ async function query(url, document, variables) {
1641
+ if (!url) throw new Error("subgraph url required");
1642
+ const controller = new AbortController();
1643
+ const timeoutId = setTimeout(() => controller.abort(), 1e4);
1644
+ try {
1645
+ const resp = await fetch(url, {
1646
+ method: "POST",
1647
+ headers: { "Content-Type": "application/json" },
1648
+ body: JSON.stringify({ query: document, variables }),
1649
+ signal: controller.signal
1650
+ });
1651
+ clearTimeout(timeoutId);
1652
+ if (!resp.ok) {
1653
+ throw new Error(`HTTP ${resp.status}: ${resp.statusText}`);
1654
+ }
1655
+ const data = await resp.json();
1656
+ if (data && data.errors) {
1657
+ throw new Error(data.errors.map((e) => e.message).join("; "));
1658
+ }
1659
+ return data.data;
1660
+ } catch (error) {
1661
+ clearTimeout(timeoutId);
1662
+ throw error;
1663
+ }
1664
+ }
1665
+ async function listProposals({ url, governor, first = 20, skip = 0 }) {
1666
+ const data = await query(url, `
1667
+ query($governor: Bytes!, $first: Int!, $skip: Int!) {
1668
+ proposals(where: { governor: $governor }, first: $first, skip: $skip, orderBy: createdAt, orderDirection: desc) {
1669
+ id
1670
+ proposer
1671
+ description
1672
+ createdAt
1673
+ targets
1674
+ values
1675
+ calldatas
1676
+ }
1677
+ }
1678
+ `, { governor: String(governor).toLowerCase(), first, skip });
1679
+ return mapSafe(data?.proposals, (p) => {
1680
+ const proposer = safeGetAddress(p.proposer);
1681
+ if (!proposer) return null;
1682
+ const targets = (p.targets || []).map((t) => safeGetAddress(t)).filter(Boolean);
1683
+ if (!targets.length && (p.targets || []).length) return null;
1684
+ return {
1685
+ id: BigInt(p.id),
1686
+ proposer,
1687
+ description: p.description,
1688
+ createdAt: Number(p.createdAt || 0),
1689
+ targets,
1690
+ values: (p.values || []).map((value) => BigInt(String(value))),
1691
+ calldatas: p.calldatas || []
1692
+ };
1693
+ });
1694
+ }
1695
+ var STATE_STRING_TO_NUMBER = {
1696
+ PENDING: 0,
1697
+ ACTIVE: 1,
1698
+ CANCELED: 2,
1699
+ CANCELLED: 2,
1700
+ // some indexes may use British spelling
1701
+ DEFEATED: 3,
1702
+ SUCCEEDED: 4,
1703
+ QUEUED: 5,
1704
+ EXPIRED: 6,
1705
+ EXECUTED: 7
1706
+ };
1707
+ async function listProposalsFiltered({ url, governor, states, fromTimestamp, toTimestamp, first = 20, skip = 0, orderBy = "createdAt", orderDirection = "desc" }) {
1708
+ const govLower = governor ? String(governor).toLowerCase() : null;
1709
+ const statesUpper = Array.isArray(states) && states.length ? states.map((s) => String(s).toUpperCase()) : null;
1710
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["createdAt", "updatedAt", "eta"], "createdAt");
1711
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
1712
+ const doc = `
1713
+ query($first: Int!, $skip: Int!, $governor: Bytes, $states: [String!], $from: Int, $to: Int) {
1714
+ proposals(
1715
+ where: {
1716
+ ${governor ? "governor: $governor," : ""}
1717
+ ${statesUpper ? "state_in: $states," : ""}
1718
+ ${fromTimestamp !== void 0 ? "createdAt_gte: $from," : ""}
1719
+ ${toTimestamp !== void 0 ? "createdAt_lte: $to," : ""}
1720
+ }
1721
+ first: $first
1722
+ skip: $skip
1723
+ orderBy: ${safeOrderBy}
1724
+ orderDirection: ${safeOrderDirection}
1725
+ ) {
1726
+ id
1727
+ proposer
1728
+ description
1729
+ createdAt
1730
+ updatedAt
1731
+ state
1732
+ eta
1733
+ targets
1734
+ values
1735
+ calldatas
1736
+ }
1737
+ }
1738
+ `;
1739
+ const variables = { first, skip };
1740
+ if (govLower) variables.governor = govLower;
1741
+ if (statesUpper) variables.states = statesUpper;
1742
+ if (fromTimestamp !== void 0) variables.from = Number(fromTimestamp);
1743
+ if (toTimestamp !== void 0) variables.to = Number(toTimestamp);
1744
+ const data = await query(url, doc, variables);
1745
+ return mapSafe(data?.proposals, (p) => {
1746
+ const stateStr = String(p.state || "").toUpperCase();
1747
+ const stateNum = STATE_STRING_TO_NUMBER[stateStr] != null ? STATE_STRING_TO_NUMBER[stateStr] : null;
1748
+ const proposer = safeGetAddress(p.proposer);
1749
+ if (!proposer) return null;
1750
+ const targets = (p.targets || []).map((t) => safeGetAddress(t)).filter(Boolean);
1751
+ if (!targets.length && (p.targets || []).length) return null;
1752
+ return {
1753
+ id: BigInt(p.id),
1754
+ proposer,
1755
+ description: p.description || "",
1756
+ createdAt: Number(p.createdAt || 0),
1757
+ updatedAt: Number(p.updatedAt || 0),
1758
+ state: stateStr,
1759
+ stateNum,
1760
+ eta: p.eta ? BigInt(String(p.eta)) : null,
1761
+ targets,
1762
+ values: (p.values || []).map((value) => BigInt(String(value))),
1763
+ calldatas: p.calldatas || []
1764
+ };
1765
+ });
1766
+ }
1767
+ async function listLibraries({ url, subdao: subdao2, first = 50, skip = 0 }) {
1768
+ const where = subdao2 ? `where: { subDAO: "${String(subdao2).toLowerCase()}" }` : "";
1769
+ const data = await query(url, `
1770
+ query($first: Int!, $skip: Int!) {
1771
+ libraries(${where} first: $first, skip: $skip, orderBy: createdAt, orderDirection: desc) {
1772
+ id
1773
+ manifestCID
1774
+ subDAO
1775
+ proposer
1776
+ createdAt
1777
+ }
1778
+ }
1779
+ `, { first, skip });
1780
+ return mapSafe(data?.libraries, (lib) => {
1781
+ const sub = safeGetAddress(lib.subDAO);
1782
+ const proposer = safeGetAddress(lib.proposer);
1783
+ if (!sub || !proposer) return null;
1784
+ return {
1785
+ id: lib.id,
1786
+ manifestCID: lib.manifestCID,
1787
+ subdao: sub,
1788
+ proposer,
1789
+ createdAt: Number(lib.createdAt || 0)
1790
+ };
1791
+ });
1792
+ }
1793
+ async function getSubdaoLibraries({ url, subdao: subdao2, first = 20, skip = 0 }) {
1794
+ if (!url) throw new Error("subgraph url required");
1795
+ const hasFilter = !!subdao2;
1796
+ const whereClause = hasFilter ? "where:{ subdao:$subdao }" : "";
1797
+ const doc = `
1798
+ query($subdao:Bytes,$first:Int!,$skip:Int!){
1799
+ subDAOLibraryPointers(
1800
+ ${whereClause}
1801
+ first:$first,
1802
+ skip:$skip,
1803
+ orderBy: updatedAt,
1804
+ orderDirection: desc
1805
+ ){
1806
+ id
1807
+ subdao
1808
+ libraryId
1809
+ manifestCID
1810
+ previousCID
1811
+ promptCount
1812
+ updatedAt
1813
+ }
1814
+ }
1815
+ `;
1816
+ const variables = {
1817
+ first: Math.min(Math.max(1, Number(first || 20)), 100),
1818
+ skip
1819
+ };
1820
+ if (hasFilter) {
1821
+ const addr = safeGetAddress(subdao2);
1822
+ if (!addr) throw new Error("invalid subdao address");
1823
+ variables.subdao = addr.toLowerCase();
1824
+ }
1825
+ const data = await query(url, doc, variables);
1826
+ return mapSafe(data?.subDAOLibraryPointers, (row) => {
1827
+ const id2 = row?.id;
1828
+ const manifestCID = row?.manifestCID;
1829
+ const sub = safeGetAddress(row?.subdao);
1830
+ if (!id2 || !manifestCID || !sub) return null;
1831
+ return {
1832
+ id: String(id2),
1833
+ subdao: sub,
1834
+ libraryId: String(row.libraryId || "main"),
1835
+ manifestCID: String(manifestCID),
1836
+ previousCID: row.previousCID || null,
1837
+ promptCount: row.promptCount != null ? Number(row.promptCount) : null,
1838
+ updatedAt: row.updatedAt != null ? Number(row.updatedAt) : null
1839
+ };
1840
+ });
1841
+ }
1842
+ async function getSubdaoPrompts({ url, registry, first = 50, skip = 0, orderBy = "updatedAt", orderDirection = "desc" }) {
1843
+ if (!url) throw new Error("subgraph url required");
1844
+ const reg = safeGetAddress(registry);
1845
+ if (!reg) throw new Error("invalid registry address");
1846
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["updatedAt"], "updatedAt");
1847
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
1848
+ const doc = `
1849
+ query($registry:Bytes!,$first:Int!,$skip:Int!){
1850
+ prompts(
1851
+ where:{ registry:$registry },
1852
+ first:$first,
1853
+ skip:$skip,
1854
+ orderBy: ${safeOrderBy},
1855
+ orderDirection: ${safeOrderDirection}
1856
+ ){
1857
+ id
1858
+ key
1859
+ cid
1860
+ version
1861
+ author
1862
+ registry
1863
+ updatedAt
1864
+ }
1865
+ }
1866
+ `;
1867
+ const data = await query(url, doc, {
1868
+ registry: reg.toLowerCase(),
1869
+ first: Math.min(Math.max(1, Number(first || 50)), 100),
1870
+ skip
1871
+ });
1872
+ return mapSafe(data?.prompts, (p) => {
1873
+ const author = safeGetAddress(p.author);
1874
+ const regAddr = safeGetAddress(p.registry);
1875
+ if (!author || !regAddr) return null;
1876
+ return {
1877
+ id: String(p.id),
1878
+ key: String(p.key),
1879
+ cid: String(p.cid),
1880
+ version: BigInt(p.version || "0"),
1881
+ author,
1882
+ registry: regAddr,
1883
+ updatedAt: Number(p.updatedAt || 0)
1884
+ };
1885
+ });
1886
+ }
1887
+ module2.exports = {
1888
+ query,
1889
+ listProposals,
1890
+ listProposalsFiltered,
1891
+ listLibraries,
1892
+ getSubdaoLibraries,
1893
+ getSubdaoPrompts,
1894
+ /**
1895
+ * Canonical proposal timeline. Tries common fields first, then event-style fallbacks.
1896
+ * Returns { id, createdAt, queuedAt, executedAt, canceledAt, eta, state } (numbers/strings may be null when unavailable).
1897
+ */
1898
+ async getProposalTimeline({ url, id: id2 }) {
1899
+ if (!url) throw new Error("subgraph url required");
1900
+ const pid = typeof id2 === "bigint" ? id2.toString() : String(id2);
1901
+ try {
1902
+ const data = await query(url, `
1903
+ query($id: ID!) {
1904
+ proposal(id: $id) {
1905
+ id
1906
+ createdAt
1907
+ updatedAt
1908
+ state
1909
+ eta
1910
+ queuedAt
1911
+ executedAt
1912
+ canceledAt
1913
+ }
1914
+ }
1915
+ `, { id: pid });
1916
+ if (data && data.proposal) {
1917
+ const p = data.proposal;
1918
+ return {
1919
+ id: p.id,
1920
+ createdAt: Number(p.createdAt || 0),
1921
+ queuedAt: p.queuedAt != null ? Number(p.queuedAt) : null,
1922
+ executedAt: p.executedAt != null ? Number(p.executedAt) : null,
1923
+ canceledAt: p.canceledAt != null ? Number(p.canceledAt) : null,
1924
+ eta: p.eta != null ? BigInt(String(p.eta)) : null,
1925
+ state: String(p.state || "")
1926
+ };
1927
+ }
1928
+ } catch (_) {
1929
+ }
1930
+ try {
1931
+ const data = await query(url, `
1932
+ query($id: String!) {
1933
+ proposalEvents(where: { proposal: $id }, orderBy: timestamp, orderDirection: asc) {
1934
+ type
1935
+ timestamp
1936
+ }
1937
+ proposals(where: { id: $id }, first:1) { id createdAt state eta }
1938
+ }
1939
+ `, { id: pid });
1940
+ const events = (data?.proposalEvents || []).map((e) => ({ type: String(e.type || ""), timestamp: Number(e.timestamp || 0) }));
1941
+ const base = data?.proposals?.[0] || {};
1942
+ const find = (t) => events.find((e) => e.type.toLowerCase() === t)?.timestamp || null;
1943
+ return {
1944
+ id: base.id || pid,
1945
+ createdAt: Number(base.createdAt || 0),
1946
+ queuedAt: find("queued"),
1947
+ executedAt: find("executed"),
1948
+ canceledAt: find("canceled") || find("cancelled") || null,
1949
+ eta: base.eta != null ? BigInt(String(base.eta)) : null,
1950
+ state: String(base.state || "")
1951
+ };
1952
+ } catch (_) {
1953
+ }
1954
+ return { id: pid, createdAt: 0, queuedAt: null, executedAt: null, canceledAt: null, eta: null, state: "" };
1955
+ },
1956
+ async listLiquidityAddPlans({ url, subdao: subdao2 = null, first = 50, skip = 0, orderBy = "blockTimestamp", orderDirection = "desc" }) {
1957
+ if (!url) throw new Error("subgraph url required");
1958
+ const filters = [];
1959
+ if (subdao2) {
1960
+ const addr = safeGetAddress(subdao2);
1961
+ if (!addr) throw new Error("invalid subdao address");
1962
+ filters.push(`subdao: "${addr.toLowerCase()}"`);
1963
+ }
1964
+ const where = filters.length ? `where: { ${filters.join(", ")} }` : "";
1965
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["blockTimestamp", "blockNumber"], "blockTimestamp");
1966
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
1967
+ const doc = `
1968
+ query($first:Int!,$skip:Int!){
1969
+ liquidityAddPlans(${where} first:$first, skip:$skip, orderBy: ${safeOrderBy}, orderDirection: ${safeOrderDirection}){
1970
+ id subdao pool sxxxToken stableToken sxxxAmount stableAmount lpRecipient blockNumber blockTimestamp transactionHash
1971
+ }
1972
+ }
1973
+ `;
1974
+ const data = await query(url, doc, { first, skip });
1975
+ return mapSafe(data?.liquidityAddPlans, (e) => {
1976
+ const sub = safeGetAddress(e.subdao);
1977
+ const pool = safeGetAddress(e.pool);
1978
+ const sxxxToken = safeGetAddress(e.sxxxToken);
1979
+ const stableToken = safeGetAddress(e.stableToken);
1980
+ const lpRecipient = safeGetAddress(e.lpRecipient);
1981
+ if (!sub || !pool || !sxxxToken || !stableToken || !lpRecipient) return null;
1982
+ return {
1983
+ id: String(e.id),
1984
+ subdao: sub,
1985
+ pool,
1986
+ sxxxToken,
1987
+ stableToken,
1988
+ sxxxAmount: BigInt(String(e.sxxxAmount)),
1989
+ stableAmount: BigInt(String(e.stableAmount)),
1990
+ lpRecipient,
1991
+ blockNumber: Number(e.blockNumber || 0),
1992
+ blockTimestamp: Number(e.blockTimestamp || 0),
1993
+ transactionHash: e.transactionHash
1994
+ };
1995
+ });
1996
+ },
1997
+ async listLiquidityRemovePlans({ url, subdao: subdao2 = null, first = 50, skip = 0, orderBy = "blockTimestamp", orderDirection = "desc" }) {
1998
+ if (!url) throw new Error("subgraph url required");
1999
+ const filters = [];
2000
+ if (subdao2) {
2001
+ const addr = safeGetAddress(subdao2);
2002
+ if (!addr) throw new Error("invalid subdao address");
2003
+ filters.push(`subdao: "${addr.toLowerCase()}"`);
2004
+ }
2005
+ const where = filters.length ? `where: { ${filters.join(", ")} }` : "";
2006
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["blockTimestamp", "blockNumber"], "blockTimestamp");
2007
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
2008
+ const doc = `
2009
+ query($first:Int!,$skip:Int!){
2010
+ liquidityRemovePlans(${where} first:$first, skip:$skip, orderBy: ${safeOrderBy}, orderDirection: ${safeOrderDirection}){
2011
+ id subdao pool lpToken lpAmount recipient blockNumber blockTimestamp transactionHash
2012
+ }
2013
+ }
2014
+ `;
2015
+ const data = await query(url, doc, { first, skip });
2016
+ return mapSafe(data?.liquidityRemovePlans, (e) => {
2017
+ const sub = safeGetAddress(e.subdao);
2018
+ const pool = safeGetAddress(e.pool);
2019
+ const lpToken = safeGetAddress(e.lpToken);
2020
+ const recipient = safeGetAddress(e.recipient);
2021
+ if (!sub || !pool || !lpToken || !recipient) return null;
2022
+ return {
2023
+ id: String(e.id),
2024
+ subdao: sub,
2025
+ pool,
2026
+ lpToken,
2027
+ lpAmount: BigInt(String(e.lpAmount)),
2028
+ recipient,
2029
+ blockNumber: Number(e.blockNumber || 0),
2030
+ blockTimestamp: Number(e.blockTimestamp || 0),
2031
+ transactionHash: e.transactionHash
2032
+ };
2033
+ });
2034
+ },
2035
+ async listPromptsByTag({ url, tagsHash, registry = null, first = 50, skip = 0, orderBy = "updatedAt", orderDirection = "desc" }) {
2036
+ if (!url) throw new Error("subgraph url required");
2037
+ const clauses = [`tagsHash: "${String(tagsHash)}"`];
2038
+ if (registry) {
2039
+ const addr = safeGetAddress(registry);
2040
+ if (!addr) throw new Error("invalid registry address");
2041
+ clauses.push(`registry: "${addr.toLowerCase()}"`);
2042
+ }
2043
+ const where = `where: { ${clauses.join(", ")} }`;
2044
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["updatedAt"], "updatedAt");
2045
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
2046
+ const doc = `
2047
+ query($first:Int!,$skip:Int!) {
2048
+ prompts(${where} first:$first, skip:$skip, orderBy: ${safeOrderBy}, orderDirection: ${safeOrderDirection}) {
2049
+ id key cid version author registry updatedAt tagsHash
2050
+ }
2051
+ }
2052
+ `;
2053
+ const data = await query(url, doc, { first, skip });
2054
+ return mapSafe(data?.prompts, (p) => {
2055
+ const author = safeGetAddress(p.author);
2056
+ const regAddr = safeGetAddress(p.registry);
2057
+ if (!author || !regAddr) return null;
2058
+ return {
2059
+ id: String(p.id),
2060
+ key: String(p.key),
2061
+ cid: String(p.cid),
2062
+ version: BigInt(p.version || "0"),
2063
+ author,
2064
+ registry: regAddr,
2065
+ updatedAt: Number(p.updatedAt || 0),
2066
+ tagsHash: String(p.tagsHash || "")
2067
+ };
2068
+ });
2069
+ },
2070
+ // Prompt helpers (registry scoped)
2071
+ async listRegistryPrompts({ url, registry, first = 50, skip = 0, orderBy = "updatedAt", orderDirection = "desc" }) {
2072
+ if (!url) throw new Error("subgraph url required");
2073
+ const reg = safeGetAddress(registry);
2074
+ if (!reg) throw new Error("invalid registry address");
2075
+ const safeOrderBy = sanitizeOrderBy(orderBy, ["updatedAt"], "updatedAt");
2076
+ const safeOrderDirection = sanitizeOrderDirection(orderDirection, "desc");
2077
+ const doc = `
2078
+ query($first:Int!,$skip:Int!,$registry:Bytes!) {
2079
+ prompts(where:{ registry: $registry }, first:$first, skip:$skip, orderBy: ${safeOrderBy}, orderDirection: ${safeOrderDirection}) {
2080
+ id
2081
+ key
2082
+ cid
2083
+ version
2084
+ author
2085
+ registry
2086
+ updatedAt
2087
+ }
2088
+ }
2089
+ `;
2090
+ const data = await query(url, doc, { first, skip, registry: reg.toLowerCase() });
2091
+ return mapSafe(data?.prompts, (p) => {
2092
+ const author = safeGetAddress(p.author);
2093
+ const regAddr = safeGetAddress(p.registry);
2094
+ if (!author || !regAddr) return null;
2095
+ return {
2096
+ id: String(p.id),
2097
+ key: String(p.key),
2098
+ cid: String(p.cid),
2099
+ version: BigInt(p.version || "0"),
2100
+ author,
2101
+ registry: regAddr,
2102
+ updatedAt: Number(p.updatedAt || 0)
2103
+ };
2104
+ });
2105
+ },
2106
+ async getPromptByKey({ url, registry, key }) {
2107
+ if (!url) throw new Error("subgraph url required");
2108
+ const reg = safeGetAddress(registry);
2109
+ if (!reg) throw new Error("invalid registry address");
2110
+ const doc = `
2111
+ query($registry:Bytes!,$key:String!) {
2112
+ prompts(where:{ registry: $registry, key: $key }, first:1) {
2113
+ id
2114
+ key
2115
+ cid
2116
+ version
2117
+ author
2118
+ registry
2119
+ updatedAt
2120
+ }
2121
+ }
2122
+ `;
2123
+ const data = await query(url, doc, { registry: reg.toLowerCase(), key: String(key) });
2124
+ const p = (data?.prompts || [])[0];
2125
+ if (!p) return null;
2126
+ const author = safeGetAddress(p.author);
2127
+ const regAddr = safeGetAddress(p.registry);
2128
+ if (!author || !regAddr) return null;
2129
+ return {
2130
+ id: String(p.id),
2131
+ key: String(p.key),
2132
+ cid: String(p.cid),
2133
+ version: BigInt(p.version || "0"),
2134
+ author,
2135
+ registry: regAddr,
2136
+ updatedAt: Number(p.updatedAt || 0)
2137
+ };
2138
+ },
2139
+ async getProposalById({ url, id: id2, governor }) {
1511
2140
  if (!url) throw new Error("subgraph url required");
1512
- const doc = `query($id: ID!){ proposal(id:$id){ id proposer description createdAt updatedAt state eta targets values calldatas } }`;
1513
- const data = await query(url, doc, { id: String(id2) });
1514
- const p = data?.proposal;
2141
+ let p = null;
2142
+ if (governor) {
2143
+ const govLower = String(governor).toLowerCase();
2144
+ const compositeId = `${govLower}-${String(id2)}`;
2145
+ const doc = `query($id: ID!){ proposal(id:$id){ id proposer description createdAt updatedAt state eta targets values calldatas } }`;
2146
+ const data = await query(url, doc, { id: compositeId });
2147
+ p = data?.proposal;
2148
+ }
2149
+ if (!p && governor) {
2150
+ const govLower = String(governor).toLowerCase();
2151
+ const doc = `query($gov: Bytes!, $first: Int!){ proposals(where:{governor:$gov}, first:$first, orderBy:createdAt, orderDirection:desc){ id proposer description createdAt updatedAt state eta targets values calldatas } }`;
2152
+ const data = await query(url, doc, { gov: govLower, first: 100 });
2153
+ const proposals = data?.proposals || [];
2154
+ p = proposals.find((prop) => {
2155
+ const parts = String(prop.id || "").split("-");
2156
+ const propId = parts.length > 1 ? parts[parts.length - 1] : prop.id;
2157
+ return String(propId) === String(id2) || propId && String(BigInt(propId)) === String(BigInt(id2));
2158
+ });
2159
+ }
1515
2160
  if (!p) return null;
1516
2161
  try {
1517
2162
  const proposer = safeGetAddress(p.proposer);
1518
2163
  if (!proposer) return null;
1519
2164
  const targets = (p.targets || []).map((t) => safeGetAddress(t)).filter(Boolean);
1520
2165
  if (!targets.length && (p.targets || []).length) return null;
2166
+ const idParts = String(p.id || "").split("-");
2167
+ const actualId = idParts.length > 1 ? idParts[idParts.length - 1] : p.id;
1521
2168
  return {
1522
- id: BigInt(p.id),
2169
+ id: BigInt(actualId),
1523
2170
  proposer,
1524
2171
  description: p.description || "",
1525
2172
  createdAt: Number(p.createdAt || 0),
@@ -1538,29 +2185,6 @@ var require_subgraph = __commonJS({
1538
2185
  }
1539
2186
  });
1540
2187
 
1541
- // src/adapters/transports.js
1542
- var require_transports = __commonJS({
1543
- "src/adapters/transports.js"(exports2, module2) {
1544
- function createTransports({ provider, signer = null, subgraph: subgraph2 = null }) {
1545
- return function resolve(kind) {
1546
- switch (kind) {
1547
- case "rpc":
1548
- return provider;
1549
- case "signer":
1550
- return { signer };
1551
- case "subgraph":
1552
- return { url: subgraph2 };
1553
- default:
1554
- return null;
1555
- }
1556
- };
1557
- }
1558
- module2.exports = {
1559
- createTransports
1560
- };
1561
- }
1562
- });
1563
-
1564
2188
  // src/ipfs/index.js
1565
2189
  var require_ipfs = __commonJS({
1566
2190
  "src/ipfs/index.js"(exports2, module2) {
@@ -1750,7 +2374,6 @@ var require_ipfs = __commonJS({
1750
2374
  headers["X-Wallet-Address"] = auth.address;
1751
2375
  headers["X-Wallet-Signature"] = auth.signature;
1752
2376
  headers["X-Wallet-Nonce"] = auth.nonce;
1753
- headers["X-Wallet-Message"] = auth.message;
1754
2377
  }
1755
2378
  return { headers, auth };
1756
2379
  }
@@ -1771,8 +2394,7 @@ var require_ipfs = __commonJS({
1771
2394
  ...extraHeaders,
1772
2395
  "X-Wallet-Address": auth.address,
1773
2396
  "X-Wallet-Signature": auth.signature,
1774
- "X-Wallet-Nonce": auth.nonce,
1775
- "X-Wallet-Message": auth.message
2397
+ "X-Wallet-Nonce": auth.nonce
1776
2398
  };
1777
2399
  return { headers, auth };
1778
2400
  }
@@ -1793,6 +2415,13 @@ var require_ipfs = __commonJS({
1793
2415
  order.push(name);
1794
2416
  };
1795
2417
  const normalizedPreference = Array.isArray(preference) ? preference.map((p) => toLowerSafe(p)).filter(Boolean) : preference ? [toLowerSafe(preference)].filter(Boolean) : [];
2418
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
2419
+ console.log("[SDK DEBUG] resolveProviderOrder preference:", preference);
2420
+ console.log("[SDK DEBUG] normalizedPreference:", normalizedPreference);
2421
+ console.log("[SDK DEBUG] config.provider:", config.provider);
2422
+ console.log("[SDK DEBUG] shouldUseWorker():", shouldUseWorker());
2423
+ console.log("[SDK DEBUG] hasPinataCreds():", hasPinataCreds());
2424
+ }
1796
2425
  normalizedPreference.forEach(append);
1797
2426
  if (shouldUseWorker()) append("worker");
1798
2427
  if (hasPinataCreds()) append("pinata");
@@ -1800,17 +2429,90 @@ var require_ipfs = __commonJS({
1800
2429
  if (config.simulate) append("simulate");
1801
2430
  return order;
1802
2431
  }
1803
- async function uploadViaWorker(payload, { warm, gateways } = {}) {
2432
+ async function uploadViaWorker(payload, { warm, gateways, pin: pin2 } = {}) {
2433
+ const uploadUrl = workerUrl("upload");
2434
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
2435
+ console.log("[SDK DEBUG] uploadViaWorker called");
2436
+ console.log("[SDK DEBUG] workerBaseUrl:", workerBaseUrl());
2437
+ console.log("[SDK DEBUG] uploadUrl:", uploadUrl);
2438
+ console.log("[SDK DEBUG] workerHasAuth:", workerHasAuth());
2439
+ }
1804
2440
  const { headers, auth } = await buildWorkerAuthHeaders({ "Content-Type": "application/json" });
1805
2441
  const body = { ...payload };
1806
2442
  if (auth) body.auth = auth;
1807
- const response = await axiosInstance.post(workerUrl("upload"), body, { headers, timeout: config.timeoutMs });
1808
- const cid = response?.data?.cid || response?.data?.IpfsHash;
2443
+ if (pin2) {
2444
+ body.pin = typeof pin2 === "string" ? { duration: pin2 } : pin2;
2445
+ }
2446
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
2447
+ console.log("[SDK DEBUG] headers:", Object.keys(headers));
2448
+ console.log("[SDK DEBUG] hasAuth:", !!auth);
2449
+ if (pin2) console.log("[SDK DEBUG] pin:", JSON.stringify(body.pin));
2450
+ }
2451
+ let response;
2452
+ try {
2453
+ response = await axiosInstance.post(uploadUrl, body, { headers, timeout: config.timeoutMs });
2454
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
2455
+ console.log("[SDK DEBUG] Upload response status:", response?.status);
2456
+ console.log("[SDK DEBUG] Upload response data:", JSON.stringify(response?.data || {}));
2457
+ }
2458
+ } catch (uploadErr) {
2459
+ if (process.env.SAGE_DEBUG_WORKER === "1") {
2460
+ console.log("[SDK DEBUG] Upload error:", uploadErr.message);
2461
+ console.log("[SDK DEBUG] Response status:", uploadErr.response?.status);
2462
+ console.log("[SDK DEBUG] Response data:", JSON.stringify(uploadErr.response?.data || {}));
2463
+ }
2464
+ const status = uploadErr.response?.status;
2465
+ const data2 = uploadErr.response?.data;
2466
+ if (status === 400 && data2?.error === "content_blocked") {
2467
+ const error = new Error("content_blocked");
2468
+ error.code = "CONTENT_BLOCKED";
2469
+ error.categories = data2.categories || [];
2470
+ error.reason = data2.reason;
2471
+ error.response = data2;
2472
+ throw error;
2473
+ }
2474
+ if (status === 402) {
2475
+ const error = new Error("payment_required");
2476
+ error.code = "PAYMENT_REQUIRED";
2477
+ error.creditsNeeded = data2?.creditsNeeded;
2478
+ error.balance = data2?.balance;
2479
+ error.duration = data2?.duration;
2480
+ error.accepts = data2?.accepts;
2481
+ error.response = data2;
2482
+ throw error;
2483
+ }
2484
+ throw uploadErr;
2485
+ }
2486
+ const data = response?.data || {};
2487
+ const cid = data.cid || data.IpfsHash;
2488
+ if (response?.status === 202 || data.status === "pending_review") {
2489
+ return {
2490
+ cid: cid || null,
2491
+ provider: "worker",
2492
+ status: "pending_review",
2493
+ categories: data.categories || [],
2494
+ response: data
2495
+ };
2496
+ }
1809
2497
  if (!cid) {
1810
2498
  throw new Error("Worker response missing cid");
1811
2499
  }
1812
2500
  if (warm || config.shouldWarm) await warmGateways(cid, { gateways });
1813
- return { cid, provider: "worker", response: response?.data || null };
2501
+ const result = {
2502
+ cid,
2503
+ provider: "worker",
2504
+ response: data
2505
+ };
2506
+ if (data.moderation) {
2507
+ result.moderation = data.moderation;
2508
+ }
2509
+ if (data.pinned !== void 0) {
2510
+ result.pinned = data.pinned;
2511
+ result.expiresAt = data.expiresAt;
2512
+ result.creditsPaid = data.creditsPaid;
2513
+ result.urls = data.urls;
2514
+ }
2515
+ return result;
1814
2516
  }
1815
2517
  async function uploadToPinata(payload, { filename = "payload.json", metadata, warm, gateways } = {}) {
1816
2518
  if (!hasPinataCreds()) {
@@ -1888,7 +2590,7 @@ var require_ipfs = __commonJS({
1888
2590
  return { cid, provider: "simulate" };
1889
2591
  }
1890
2592
  async function uploadPayload(payload, options2 = {}) {
1891
- const { providers, provider, warm, gateways, filename, metadata } = options2;
2593
+ const { providers, provider, warm, gateways, filename, metadata, pin: pin2 } = options2;
1892
2594
  const order = resolveProviderOrder(providers || provider);
1893
2595
  if (!order.length) {
1894
2596
  throw new Error("No IPFS providers configured. Set Pinata credentials, worker upload, or enable test mode");
@@ -1897,7 +2599,7 @@ var require_ipfs = __commonJS({
1897
2599
  for (const candidate of order) {
1898
2600
  try {
1899
2601
  if (candidate === "worker") {
1900
- return await uploadViaWorker(payload, { warm, gateways });
2602
+ return await uploadViaWorker(payload, { warm, gateways, pin: pin2 });
1901
2603
  }
1902
2604
  if (candidate === "pinata") {
1903
2605
  return await uploadToPinata(payload, { filename, metadata, warm, gateways });
@@ -1909,6 +2611,9 @@ var require_ipfs = __commonJS({
1909
2611
  return await uploadSimulated(payload, { warm, gateways });
1910
2612
  }
1911
2613
  } catch (error2) {
2614
+ if (error2.code === "CONTENT_BLOCKED" || error2.code === "PAYMENT_REQUIRED") {
2615
+ throw error2;
2616
+ }
1912
2617
  errors2.push({ provider: candidate, error: error2 });
1913
2618
  }
1914
2619
  }
@@ -1917,7 +2622,7 @@ var require_ipfs = __commonJS({
1917
2622
  throw error;
1918
2623
  }
1919
2624
  async function uploadPrompt(options2 = {}) {
1920
- const { prompt: prompt2, providers, provider, warm, gateways } = options2;
2625
+ const { prompt: prompt2, providers, provider, warm, gateways, pin: pin2 } = options2;
1921
2626
  if (!prompt2 || typeof prompt2 !== "object") {
1922
2627
  throw new Error("prompt payload required");
1923
2628
  }
@@ -1943,6 +2648,7 @@ var require_ipfs = __commonJS({
1943
2648
  provider,
1944
2649
  warm,
1945
2650
  gateways,
2651
+ pin: pin2,
1946
2652
  filename: `${prompt2.name || "prompt"}.json`,
1947
2653
  metadata
1948
2654
  });
@@ -2177,8 +2883,7 @@ var require_ipfs = __commonJS({
2177
2883
  "Content-Type": "application/json",
2178
2884
  "X-Wallet-Address": address,
2179
2885
  "X-Wallet-Signature": signature,
2180
- "X-Wallet-Nonce": nonce,
2181
- "X-Wallet-Message": message
2886
+ "X-Wallet-Nonce": nonce
2182
2887
  };
2183
2888
  let verified = false;
2184
2889
  try {
@@ -2422,6 +3127,15 @@ var require_validation = __commonJS({
2422
3127
  path2.join(__dirname, "..", "..", "docs", "schemas", "manifest.schema.json")
2423
3128
  ];
2424
3129
  }
3130
+ function normaliseV3SchemaPaths(v3SchemaPaths, { path: path2 }) {
3131
+ if (Array.isArray(v3SchemaPaths) && v3SchemaPaths.length) {
3132
+ return v3SchemaPaths;
3133
+ }
3134
+ return [
3135
+ path2.join(process.cwd(), "docs", "schemas", "manifest.v3.schema.json"),
3136
+ path2.join(__dirname, "..", "..", "docs", "schemas", "manifest.v3.schema.json")
3137
+ ];
3138
+ }
2425
3139
  function safeJsonParse(fs2, file) {
2426
3140
  try {
2427
3141
  const raw = fs2.readFileSync(file, "utf8");
@@ -2430,17 +3144,17 @@ var require_validation = __commonJS({
2430
3144
  return null;
2431
3145
  }
2432
3146
  }
2433
- function deriveHints(errors2 = []) {
3147
+ function deriveHints(errors2 = [], { version = "2.0.0" } = {}) {
2434
3148
  const hints = /* @__PURE__ */ new Set();
2435
3149
  for (const err of errors2) {
2436
3150
  const keyword = (err.keyword || "").toLowerCase();
2437
3151
  const instancePath = err.instancePath || "/";
2438
3152
  const message = (err.message || "").toLowerCase();
2439
3153
  if (keyword === "required" && instancePath === "/") {
2440
- hints.add('Add a top-level "library" object and set "version": "2.0.0"');
3154
+ hints.add('Add a top-level "library" object and set "version": "3.0.0"');
2441
3155
  }
2442
3156
  if (message.includes("version") || instancePath === "/version") {
2443
- hints.add('Ensure "version" is exactly the semver string "2.0.0"');
3157
+ hints.add('Ensure "version" is exactly the semver string "3.0.0"');
2444
3158
  }
2445
3159
  if (keyword === "required" && instancePath.includes("/prompts")) {
2446
3160
  hints.add('Each prompt should define a unique "key"');
@@ -2454,17 +3168,23 @@ var require_validation = __commonJS({
2454
3168
  path: path2 = pathDefault,
2455
3169
  ajvFactory = defaultAjvFactory,
2456
3170
  addFormats = defaultAddFormats,
2457
- schemaPaths
3171
+ schemaPaths,
3172
+ v3SchemaPaths
2458
3173
  } = options;
2459
3174
  const searchPaths = normaliseSchemaPaths(schemaPaths, { path: path2 });
2460
- function loadSchema() {
2461
- for (const schemaPath of searchPaths) {
3175
+ const v3SearchPaths = normaliseV3SchemaPaths(v3SchemaPaths, { path: path2 });
3176
+ function loadSchema(version = "2.0.0") {
3177
+ const paths = version === "3.0.0" ? v3SearchPaths : searchPaths;
3178
+ for (const schemaPath of paths) {
2462
3179
  if (!fs2.existsSync(schemaPath)) continue;
2463
3180
  const schema = safeJsonParse(fs2, schemaPath);
2464
3181
  if (schema) return { schema, schemaPath };
2465
3182
  }
2466
3183
  return { schema: null, schemaPath: null };
2467
3184
  }
3185
+ function detectVersion(manifest) {
3186
+ return "3.0.0";
3187
+ }
2468
3188
  function lintManifest(manifest, { enforceVersion = true, manifestPath = null } = {}) {
2469
3189
  if (!manifest || typeof manifest !== "object") {
2470
3190
  return {
@@ -2477,16 +3197,18 @@ var require_validation = __commonJS({
2477
3197
  manifestPath
2478
3198
  };
2479
3199
  }
2480
- const { schema, schemaPath } = loadSchema();
3200
+ const detectedVersion = detectVersion(manifest);
3201
+ const { schema, schemaPath } = loadSchema(detectedVersion);
2481
3202
  if (!schema) {
3203
+ const schemaFile = detectedVersion === "3.0.0" ? "manifest.v3.schema.json" : "manifest.schema.json";
2482
3204
  return {
2483
3205
  ok: false,
2484
3206
  versionOk: false,
2485
3207
  missingSchema: true,
2486
3208
  schemaPath: null,
2487
- errors: [{ keyword: "schema", instancePath: "/", message: "manifest schema not found" }],
3209
+ errors: [{ keyword: "schema", instancePath: "/", message: `manifest schema not found for version ${detectedVersion}` }],
2488
3210
  hints: [
2489
- 'Ensure docs/schemas/manifest.schema.json exists (run "sage project scaffold" to regenerate)'
3211
+ `Ensure docs/schemas/${schemaFile} exists (run "sage project scaffold" to regenerate)`
2490
3212
  ],
2491
3213
  manifestPath
2492
3214
  };
@@ -2505,19 +3227,19 @@ var require_validation = __commonJS({
2505
3227
  let versionOk = true;
2506
3228
  const version = manifest?.version;
2507
3229
  if (valid && enforceVersion) {
2508
- const isV2Semver = typeof version === "string" && version.trim() === "2.0.0";
2509
- versionOk = isV2Semver;
3230
+ const isValidVersion = detectedVersion === "3.0.0" ? typeof version === "string" && version.trim() === "3.0.0" : typeof version === "string" && version.trim() === "2.0.0";
3231
+ versionOk = isValidVersion;
2510
3232
  if (!versionOk) {
2511
3233
  validationErrors.push({
2512
3234
  keyword: "const",
2513
3235
  instancePath: "/version",
2514
- message: 'version must be the semver string "2.0.0"',
3236
+ message: `version must be the semver string "${detectedVersion}"`,
2515
3237
  schemaPath: "#/properties/version",
2516
- params: { allowedValue: "2.0.0" }
3238
+ params: { allowedValue: detectedVersion }
2517
3239
  });
2518
3240
  }
2519
3241
  }
2520
- const hints = deriveHints(validationErrors);
3242
+ const hints = deriveHints(validationErrors, { version: detectedVersion });
2521
3243
  return {
2522
3244
  ok: valid && versionOk,
2523
3245
  versionOk,
@@ -2526,7 +3248,8 @@ var require_validation = __commonJS({
2526
3248
  errors: validationErrors,
2527
3249
  hints,
2528
3250
  manifestPath,
2529
- version
3251
+ version,
3252
+ detectedVersion
2530
3253
  };
2531
3254
  }
2532
3255
  function lintManifestFile(manifestPath, options2 = {}) {
@@ -2598,6 +3321,7 @@ var require_validation = __commonJS({
2598
3321
  }
2599
3322
  return {
2600
3323
  loadSchema,
3324
+ detectVersion,
2601
3325
  lintManifest,
2602
3326
  lintManifestFile,
2603
3327
  bestPracticeCheck,
@@ -2695,7 +3419,6 @@ var require_library = __commonJS({
2695
3419
  ]);
2696
3420
  return { to, data, value: 0n };
2697
3421
  }
2698
- var buildUpdateLibraryForSubDAOTx = buildUpdateLibraryTx;
2699
3422
  module2.exports = {
2700
3423
  listManifests,
2701
3424
  getManifestInfo,
@@ -2703,7 +3426,6 @@ var require_library = __commonJS({
2703
3426
  getLatestLibrary,
2704
3427
  hasScopedOwnership,
2705
3428
  buildUpdateLibraryTx,
2706
- buildUpdateLibraryForSubDAOTx,
2707
3429
  _computeLibraryKey,
2708
3430
  getBeforeAfterForUpdate,
2709
3431
  /** Build an authorizeTimelock(timelock, subdao) call for a LibraryRegistry. */
@@ -2823,12 +3545,35 @@ var require_governance = __commonJS({
2823
3545
  votes: { against, for: _for, abstain }
2824
3546
  };
2825
3547
  }
2826
- async function listProposals({ provider, governor, fromBlock = 0, toBlock = "latest" }) {
3548
+ async function listProposals({ provider, governor, fromBlock, toBlock = "latest", subgraphUrl }) {
2827
3549
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
2828
3550
  const addr = normaliseGovernor(governor);
3551
+ const sgUrl = subgraphUrl || process.env.SAGE_SUBGRAPH_URL || process.env.SUBGRAPH_URL || null;
3552
+ if (sgUrl) {
3553
+ try {
3554
+ const browserSubgraph = require_subgraph2();
3555
+ const sgProposals = await browserSubgraph.listProposals({ url: sgUrl, governor: addr, first: 100 });
3556
+ if (sgProposals && sgProposals.length > 0) {
3557
+ return sgProposals.map((p) => ({
3558
+ id: BigInt(p.id),
3559
+ proposer: p.proposer,
3560
+ targets: p.targets || [],
3561
+ values: (p.values || []).map((v) => BigInt(v)),
3562
+ calldatas: p.calldatas || [],
3563
+ signatures: [],
3564
+ description: p.description || "",
3565
+ descriptionHash: p.description ? hashDescription(p.description) : null,
3566
+ createdAt: p.createdAt
3567
+ }));
3568
+ }
3569
+ } catch (_) {
3570
+ }
3571
+ }
3572
+ const currentBlock = await provider.getBlockNumber();
3573
+ const effectiveFromBlock = fromBlock !== void 0 ? fromBlock : Math.max(0, currentBlock - 5e4);
2829
3574
  const iface = new Interface([ABI.Events.ProposalCreated]);
2830
3575
  const topic = iface.getEvent("ProposalCreated").topicHash;
2831
- const logs = await provider.getLogs({ address: addr, fromBlock, toBlock, topics: [topic] });
3576
+ const logs = await provider.getLogs({ address: addr, fromBlock: effectiveFromBlock, toBlock, topics: [topic] });
2832
3577
  const proposals = [];
2833
3578
  for (const log of logs) {
2834
3579
  try {
@@ -2841,7 +3586,8 @@ var require_governance = __commonJS({
2841
3586
  calldatas: parsed.args.calldatas.map((data) => hexlify(data)),
2842
3587
  signatures: parsed.args.signatures ? parsed.args.signatures.map(String) : [],
2843
3588
  description: parsed.args.description,
2844
- descriptionHash: hashDescription(parsed.args.description)
3589
+ descriptionHash: hashDescription(parsed.args.description),
3590
+ blockNumber: log.blockNumber
2845
3591
  });
2846
3592
  } catch (err) {
2847
3593
  continue;
@@ -2849,13 +3595,38 @@ var require_governance = __commonJS({
2849
3595
  }
2850
3596
  return proposals;
2851
3597
  }
2852
- async function getProposalMetadata({ provider, governor, id: id2, fromBlock = 0, toBlock = "latest" }) {
3598
+ async function getProposalMetadata({ provider, governor, id: id2, fromBlock, toBlock = "latest", subgraphUrl }) {
2853
3599
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
2854
3600
  const addr = normaliseGovernor(governor);
3601
+ const pid = typeof id2 === "bigint" ? id2 : String(id2).startsWith("0x") ? BigInt(id2) : BigInt(String(id2));
3602
+ const sgUrl = subgraphUrl || process.env.SAGE_SUBGRAPH_URL || process.env.SUBGRAPH_URL || null;
3603
+ if (sgUrl) {
3604
+ try {
3605
+ const browserSubgraph = require_subgraph2();
3606
+ const sgProposal = await browserSubgraph.getProposalById({ url: sgUrl, id: String(pid), governor: addr });
3607
+ if (sgProposal && sgProposal.targets) {
3608
+ return {
3609
+ governor: addr,
3610
+ id: pid,
3611
+ proposer: sgProposal.proposer,
3612
+ targets: sgProposal.targets || [],
3613
+ values: (sgProposal.values || []).map((v) => BigInt(v)),
3614
+ calldatas: sgProposal.calldatas || [],
3615
+ signatures: [],
3616
+ description: sgProposal.description || "",
3617
+ descriptionHash: sgProposal.description ? hashDescription(sgProposal.description) : null,
3618
+ blockNumber: sgProposal.createdAt || null,
3619
+ source: "subgraph"
3620
+ };
3621
+ }
3622
+ } catch (_) {
3623
+ }
3624
+ }
3625
+ const currentBlock = await provider.getBlockNumber();
3626
+ const effectiveFromBlock = fromBlock !== void 0 ? fromBlock : Math.max(0, currentBlock - 5e4);
2855
3627
  const iface = new Interface([ABI.Events.ProposalCreated]);
2856
3628
  const topic = iface.getEvent("ProposalCreated").topicHash;
2857
- const pid = typeof id2 === "bigint" ? id2 : String(id2).startsWith("0x") ? BigInt(id2) : BigInt(String(id2));
2858
- const logs = await provider.getLogs({ address: addr, fromBlock, toBlock, topics: [topic] });
3629
+ const logs = await provider.getLogs({ address: addr, fromBlock: effectiveFromBlock, toBlock, topics: [topic] });
2859
3630
  for (const log of logs) {
2860
3631
  try {
2861
3632
  const parsed = iface.parseLog(log);
@@ -2973,25 +3744,40 @@ var require_governance = __commonJS({
2973
3744
  if (!parsed) throw new Error("ProposalCreated event not found");
2974
3745
  const targets = parsed.args.targets.map(getAddress);
2975
3746
  const calldatas = parsed.args.calldatas.map((d) => typeof d === "string" ? d : "0x" + Buffer.from(d).toString("hex"));
2976
- const LibraryIface = new Interface(["function updateLibraryForSubDAO(address,string,string,uint256)", "function subdaoLibraryLatest(bytes32) view returns (string)"]);
3747
+ const LibraryIface = new Interface(["function updateLibrary(address,string,string)"]);
2977
3748
  const PromptIface = new Interface(["function updatePromptByGovernance(string,string)"]);
2978
- const coder = AbiCoder.defaultAbiCoder ? AbiCoder.defaultAbiCoder() : new AbiCoder();
2979
3749
  const effects = [];
2980
3750
  for (let i = 0; i < calldatas.length; i++) {
2981
3751
  const data = calldatas[i];
2982
3752
  const sel = data.slice(0, 10);
2983
3753
  try {
2984
- const decoded = LibraryIface.decodeFunctionData("updateLibraryForSubDAO", data);
2985
- const [subdao2, libraryId, newCid, promptCount] = decoded;
3754
+ const decoded = LibraryIface.decodeFunctionData("updateLibrary", data);
3755
+ const [dao, newCid, version] = decoded;
2986
3756
  let previousCID = null;
3757
+ let previousVersion = null;
2987
3758
  try {
2988
- const reg = new Contract(targets[i], ["function subdaoLibraryLatest(bytes32) view returns (string)"], provider);
2989
- const key = keccak256(coder.encode(["address", "string"], [getAddress(subdao2), String(libraryId)]));
2990
- const prev = await reg.subdaoLibraryLatest(key).catch(() => "");
2991
- previousCID = prev && prev.length ? String(prev) : null;
3759
+ const reg = new Contract(
3760
+ targets[i],
3761
+ ["function libraryByDAO(address) view returns (tuple(string manifestCID,address lastUpdater,uint256 lastUpdated,string version,address forkedFromDAO,uint256 sxxxForkFee))"],
3762
+ provider
3763
+ );
3764
+ const info = await reg.libraryByDAO(dao).catch(() => null);
3765
+ if (info && typeof info.manifestCID === "string") {
3766
+ previousCID = info.manifestCID || null;
3767
+ previousVersion = info.version || null;
3768
+ }
2992
3769
  } catch (_) {
2993
3770
  }
2994
- effects.push({ type: "libraryUpdate", index: i, target: targets[i], subdao: getAddress(subdao2), libraryId: String(libraryId), previousCid: previousCID, newCid: String(newCid), promptCount: Number(promptCount) });
3771
+ effects.push({
3772
+ type: "libraryUpdateV4",
3773
+ index: i,
3774
+ target: targets[i],
3775
+ dao: getAddress(dao),
3776
+ previousCid: previousCID,
3777
+ previousVersion,
3778
+ newCid: String(newCid),
3779
+ newVersion: String(version)
3780
+ });
2995
3781
  continue;
2996
3782
  } catch (_) {
2997
3783
  }
@@ -3036,13 +3822,10 @@ var require_governance = __commonJS({
3036
3822
  } else {
3037
3823
  const govAddr = normaliseGovernor(governor);
3038
3824
  try {
3039
- const iface = new Interface(["function sxxxToken() view returns (address)"]);
3040
- const data = iface.encodeFunctionData("sxxxToken", []);
3041
- const ret = await provider.call({ to: govAddr, data });
3042
- const [tok] = AbiCoder.defaultAbiCoder().decode(["address"], ret);
3043
- addr = getAddress(tok);
3825
+ const chain = await resolveVotesTokenChain({ provider, governor: govAddr });
3826
+ addr = getAddress(chain.votingToken);
3044
3827
  } catch (err) {
3045
- throw new SageSDKError(CODES.NOT_FOUND, "failed to resolve governance token from governor", { cause: err });
3828
+ throw new SageSDKError(CODES.NOT_FOUND, "failed to resolve votes token from governor", { cause: err });
3046
3829
  }
3047
3830
  }
3048
3831
  const user = getAddress(account);
@@ -3123,6 +3906,210 @@ var require_governance = __commonJS({
3123
3906
  const token2 = await g.sxxxToken();
3124
3907
  return buildDelegateTx({ token: token2, delegatee: account });
3125
3908
  }
3909
+ async function resolveVotesTokenChain({ provider, subdao: subdao2, governor }) {
3910
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3911
+ if (!subdao2 && !governor) throw new SageSDKError(CODES.INVALID_ARGS, "subdao or governor required");
3912
+ let votingToken = null;
3913
+ if (governor) {
3914
+ const govAddr = normaliseGovernor(governor);
3915
+ try {
3916
+ const iTok = new Interface(["function token() view returns (address)"]);
3917
+ const data = iTok.encodeFunctionData("token", []);
3918
+ const ret = await provider.call({ to: govAddr, data });
3919
+ if (ret && ret !== "0x") {
3920
+ const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], ret);
3921
+ votingToken = addr;
3922
+ }
3923
+ } catch (_) {
3924
+ }
3925
+ if (!votingToken) {
3926
+ try {
3927
+ const iGov = new Interface(["function sxxxToken() view returns (address)"]);
3928
+ const d2 = iGov.encodeFunctionData("sxxxToken", []);
3929
+ const r2 = await provider.call({ to: govAddr, data: d2 });
3930
+ if (r2 && r2 !== "0x") {
3931
+ const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], r2);
3932
+ votingToken = addr;
3933
+ }
3934
+ } catch (_) {
3935
+ }
3936
+ }
3937
+ }
3938
+ if (!votingToken && subdao2) {
3939
+ try {
3940
+ const subAddr = getAddress(subdao2);
3941
+ const iSub = new Interface(["function stakeToken() view returns (address)"]);
3942
+ const d3 = iSub.encodeFunctionData("stakeToken", []);
3943
+ const r3 = await provider.call({ to: subAddr, data: d3 });
3944
+ if (r3 && r3 !== "0x") {
3945
+ const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], r3);
3946
+ votingToken = addr;
3947
+ }
3948
+ } catch (_) {
3949
+ }
3950
+ }
3951
+ if (!votingToken) {
3952
+ throw new SageSDKError(CODES.NOT_FOUND, "failed to resolve votes token");
3953
+ }
3954
+ const votingTokenNorm = getAddress(votingToken);
3955
+ let baseToken = votingTokenNorm;
3956
+ let isWrapper = false;
3957
+ try {
3958
+ const wrapperIface = new Interface([
3959
+ "function baseToken() view returns (address)",
3960
+ "function dao() view returns (address)"
3961
+ ]);
3962
+ const [rawBase, rawDao] = await Promise.all([
3963
+ provider.call({ to: votingTokenNorm, data: wrapperIface.encodeFunctionData("baseToken", []) }),
3964
+ provider.call({ to: votingTokenNorm, data: wrapperIface.encodeFunctionData("dao", []) })
3965
+ ]);
3966
+ if (rawBase && rawBase !== "0x" && rawDao && rawDao !== "0x") {
3967
+ const [decodedBase] = AbiCoder.defaultAbiCoder().decode(["address"], rawBase);
3968
+ const [decodedDao] = AbiCoder.defaultAbiCoder().decode(["address"], rawDao);
3969
+ const baseNorm = getAddress(decodedBase);
3970
+ const daoNorm = getAddress(decodedDao);
3971
+ if (!subdao2 || daoNorm === getAddress(subdao2)) {
3972
+ baseToken = baseNorm;
3973
+ isWrapper = true;
3974
+ }
3975
+ }
3976
+ } catch (_) {
3977
+ }
3978
+ return { votingToken: votingTokenNorm, baseToken, isWrapper };
3979
+ }
3980
+ async function describeVotesToken({ provider, subdao: subdao2, governor }) {
3981
+ const { votingToken, baseToken, isWrapper } = await resolveVotesTokenChain({ provider, subdao: subdao2, governor });
3982
+ let multiplierNFT = null;
3983
+ let basis = null;
3984
+ if (isWrapper) {
3985
+ try {
3986
+ const wrapper = new Contract(votingToken, ABI.MultipliedVotes, provider);
3987
+ multiplierNFT = await wrapper.multiplierNFT().catch(() => null);
3988
+ basis = await wrapper.BASIS().catch(() => null);
3989
+ } catch (_) {
3990
+ }
3991
+ }
3992
+ const votingNorm = getAddress(votingToken);
3993
+ const baseNorm = getAddress(baseToken);
3994
+ const multiplierNorm = multiplierNFT && /^0x[0-9a-fA-F]{40}$/.test(String(multiplierNFT)) ? getAddress(multiplierNFT) : null;
3995
+ const basisBig = basis != null ? BigInt(String(basis)) : null;
3996
+ let description;
3997
+ if (!isWrapper) {
3998
+ description = `Voting token = ERC20Votes at ${votingNorm}`;
3999
+ } else {
4000
+ const basisStr = basisBig != null ? basisBig.toString() : "10000";
4001
+ description = `Voting token = MultipliedVotes(base=${baseNorm}, multiplierNFT=${multiplierNorm || "unknown"}, BASIS=${basisStr})`;
4002
+ if (subdao2) {
4003
+ description += ` for DAO ${getAddress(subdao2)}`;
4004
+ }
4005
+ }
4006
+ return {
4007
+ votingToken: votingNorm,
4008
+ baseToken: baseNorm,
4009
+ isWrapper,
4010
+ multiplierNFT: multiplierNorm,
4011
+ basis: basisBig,
4012
+ description
4013
+ };
4014
+ }
4015
+ async function getVotingStatus({ provider, subdao: subdao2, governor, account }) {
4016
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
4017
+ if (!governor && !subdao2) throw new SageSDKError(CODES.INVALID_ARGS, "governor or subdao required");
4018
+ if (!account) throw new SageSDKError(CODES.INVALID_ARGS, "account required");
4019
+ const acct = getAddress(account);
4020
+ let govAddr = null;
4021
+ let subdaoAddr = null;
4022
+ if (governor) {
4023
+ govAddr = normaliseGovernor(governor);
4024
+ }
4025
+ if (subdao2) {
4026
+ subdaoAddr = getAddress(subdao2);
4027
+ if (!govAddr) {
4028
+ try {
4029
+ const sub = new Contract(subdaoAddr, ["function governor() view returns (address)"], provider);
4030
+ govAddr = getAddress(await sub.governor());
4031
+ } catch (_) {
4032
+ }
4033
+ }
4034
+ }
4035
+ if (!govAddr) throw new SageSDKError(CODES.INVALID_ARGS, "could not resolve governor address");
4036
+ let threshold = null;
4037
+ try {
4038
+ const g = new Contract(govAddr, ABI.Governor, provider);
4039
+ const t = await g.proposalThreshold();
4040
+ threshold = BigInt(t.toString());
4041
+ } catch (_) {
4042
+ }
4043
+ const desc = await describeVotesToken({ provider, subdao: subdaoAddr || void 0, governor: govAddr });
4044
+ let stakeToken = null;
4045
+ if (subdaoAddr) {
4046
+ try {
4047
+ const sub = new Contract(subdaoAddr, ["function stakeToken() view returns (address)"], provider);
4048
+ const st = await sub.stakeToken();
4049
+ if (st && /^0x[0-9a-fA-F]{40}$/.test(String(st))) {
4050
+ stakeToken = getAddress(st);
4051
+ }
4052
+ } catch (_) {
4053
+ }
4054
+ }
4055
+ const VotesABI = [
4056
+ "function getVotes(address) view returns (uint256)",
4057
+ "function delegates(address) view returns (address)",
4058
+ "function balanceOf(address) view returns (uint256)"
4059
+ ];
4060
+ let votingPower = null;
4061
+ let delegate = null;
4062
+ let tokenBalance = null;
4063
+ try {
4064
+ const votingC = new Contract(desc.votingToken, VotesABI, provider);
4065
+ const vp = await votingC.getVotes(acct).catch(() => null);
4066
+ if (vp != null) votingPower = BigInt(vp.toString());
4067
+ const del = await votingC.delegates(acct).catch(() => null);
4068
+ if (del && /^0x[0-9a-fA-F]{40}$/.test(String(del))) delegate = getAddress(del);
4069
+ const bal = await votingC.balanceOf(acct).catch(() => null);
4070
+ if (bal != null) tokenBalance = BigInt(bal.toString());
4071
+ } catch (_) {
4072
+ }
4073
+ const canPropose = threshold != null && votingPower != null ? votingPower >= threshold : null;
4074
+ let stakeTokenVotes = null;
4075
+ let stakeTokenDelegate = null;
4076
+ let stakeTokenBalance = null;
4077
+ const tokenMismatch = !!stakeToken && stakeToken.toLowerCase() !== desc.votingToken.toLowerCase();
4078
+ if (stakeToken && tokenMismatch) {
4079
+ try {
4080
+ const stakeC = new Contract(stakeToken, VotesABI, provider);
4081
+ const sv = await stakeC.getVotes(acct).catch(() => null);
4082
+ if (sv != null) stakeTokenVotes = BigInt(sv.toString());
4083
+ const sd = await stakeC.delegates(acct).catch(() => null);
4084
+ if (sd && /^0x[0-9a-fA-F]{40}$/.test(String(sd))) {
4085
+ stakeTokenDelegate = getAddress(sd);
4086
+ }
4087
+ const sb = await stakeC.balanceOf(acct).catch(() => null);
4088
+ if (sb != null) stakeTokenBalance = BigInt(sb.toString());
4089
+ } catch (_) {
4090
+ }
4091
+ }
4092
+ return {
4093
+ subdao: subdaoAddr,
4094
+ governor: govAddr,
4095
+ stakeToken,
4096
+ votingToken: desc.votingToken,
4097
+ baseToken: desc.baseToken,
4098
+ isWrapper: desc.isWrapper,
4099
+ multiplierNFT: desc.multiplierNFT,
4100
+ basis: desc.basis,
4101
+ threshold,
4102
+ votingPower,
4103
+ tokenBalance,
4104
+ delegate,
4105
+ canPropose,
4106
+ tokenMismatch,
4107
+ stakeTokenVotes,
4108
+ stakeTokenDelegate,
4109
+ stakeTokenBalance,
4110
+ description: desc.description
4111
+ };
4112
+ }
3126
4113
  module2.exports = {
3127
4114
  getGovernorInfo,
3128
4115
  getProposal,
@@ -3154,52 +4141,28 @@ var require_governance = __commonJS({
3154
4141
  * - SubDAO.stakeToken() (when subdao provided)
3155
4142
  */
3156
4143
  resolveVotesToken: async function resolveVotesToken({ provider, subdao: subdao2, governor }) {
3157
- if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3158
- if (!subdao2 && !governor) throw new SageSDKError(CODES.INVALID_ARGS, "subdao or governor required");
3159
- if (governor) {
3160
- const govAddr = normaliseGovernor(governor);
3161
- try {
3162
- const iTok = new Interface(["function token() view returns (address)"]);
3163
- const data = iTok.encodeFunctionData("token", []);
3164
- const ret = await provider.call({ to: govAddr, data });
3165
- if (ret && ret !== "0x") {
3166
- const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], ret);
3167
- return getAddress(addr);
3168
- }
3169
- } catch (_) {
3170
- }
3171
- try {
3172
- const iGov = new Interface(["function sxxxToken() view returns (address)"]);
3173
- const d2 = iGov.encodeFunctionData("sxxxToken", []);
3174
- const r2 = await provider.call({ to: govAddr, data: d2 });
3175
- if (r2 && r2 !== "0x") {
3176
- const [addr] = AbiCoder.defaultAbiCoder().decode(["address"], r2);
3177
- return getAddress(addr);
3178
- }
3179
- } catch (_) {
3180
- }
3181
- }
3182
- if (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");
4144
+ const { votingToken } = await resolveVotesTokenChain({ provider, subdao: subdao2, governor });
4145
+ return votingToken;
3196
4146
  },
4147
+ /**
4148
+ * Resolve the IVotes token chain used for voting (wrapper + base token).
4149
+ * See resolveVotesTokenChain() for details.
4150
+ */
4151
+ resolveVotesTokenChain,
4152
+ /**
4153
+ * Human-friendly description of the voting token wiring for a Governor/SubDAO.
4154
+ */
4155
+ describeVotesToken,
4156
+ /**
4157
+ * Get voting status for an account relative to a Governor/SubDAO.
4158
+ */
4159
+ getVotingStatus,
3197
4160
  /** Build a delegate(self) tx using the preferred votes token resolution path. */
3198
4161
  buildDelegateSelfPreferred: async function buildDelegateSelfPreferred({ provider, subdao: subdao2, governor, account }) {
3199
4162
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3200
4163
  if (!account) throw new SageSDKError(CODES.INVALID_ARGS, "account required");
3201
- const token2 = await this.resolveVotesToken({ provider, subdao: subdao2, governor });
3202
- return buildDelegateTx({ token: token2, delegatee: account });
4164
+ const { baseToken } = await resolveVotesTokenChain({ provider, subdao: subdao2, governor });
4165
+ return buildDelegateTx({ token: baseToken, delegatee: account });
3203
4166
  },
3204
4167
  /**
3205
4168
  * Send a delegate(self) and verify votes at latest-1.
@@ -3208,15 +4171,15 @@ var require_governance = __commonJS({
3208
4171
  delegateSelfAndVerify: async function delegateSelfAndVerify({ provider, subdao: subdao2, governor, account, signer = null, minVotes = null }) {
3209
4172
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3210
4173
  if (!account) throw new SageSDKError(CODES.INVALID_ARGS, "account required");
3211
- const token2 = await this.resolveVotesToken({ provider, subdao: subdao2, governor });
3212
- const payload = buildDelegateTx({ token: token2, delegatee: account });
4174
+ const { votingToken, baseToken } = await resolveVotesTokenChain({ provider, subdao: subdao2, governor });
4175
+ const payload = buildDelegateTx({ token: baseToken, delegatee: account });
3213
4176
  let txHash = null;
3214
4177
  if (signer && typeof signer.sendTransaction === "function") {
3215
4178
  const tx = await signer.sendTransaction({ to: payload.to, data: payload.data, value: payload.value });
3216
4179
  txHash = tx?.hash || null;
3217
4180
  if (tx?.wait) await tx.wait();
3218
4181
  }
3219
- const votes = await getVotesLatestMinusOne({ provider, token: token2, account });
4182
+ const votes = await getVotesLatestMinusOne({ provider, token: votingToken, account });
3220
4183
  const ok = minVotes != null ? votes >= BigInt(minVotes) : votes > 0n;
3221
4184
  return { txHash, ok, votes, payload };
3222
4185
  },
@@ -3270,8 +4233,8 @@ var require_governance = __commonJS({
3270
4233
  }
3271
4234
  let votesOk = null;
3272
4235
  try {
3273
- const token2 = sxxx || await this.resolveVotesToken({ provider, governor });
3274
- const votes = await getVotesLatestMinusOne({ provider, token: token2, account: user });
4236
+ const { votingToken } = await resolveVotesTokenChain({ provider, governor });
4237
+ const votes = await getVotesLatestMinusOne({ provider, token: votingToken, account: user });
3275
4238
  const th = threshold != null ? BigInt(threshold) : 0n;
3276
4239
  votesOk = votes >= th;
3277
4240
  } catch (_) {
@@ -3288,7 +4251,7 @@ var require_governance = __commonJS({
3288
4251
  },
3289
4252
  /**
3290
4253
  * Compose propose readiness with optional execution readiness checks.
3291
- * execution?: { provider, registry, timelock, subdao, libraryId, manifestCID, promptCount }
4254
+ * execution?: { provider, registry, timelock, subdao, manifestCID, version }
3292
4255
  */
3293
4256
  readinessToPropose: async function readinessToPropose({ provider, governor, proposer, execution = null }) {
3294
4257
  const gates = await this.ensureProposeGates({ provider, governor, proposer });
@@ -3297,12 +4260,11 @@ var require_governance = __commonJS({
3297
4260
  if (execution && execution.registry && execution.timelock && execution.subdao) {
3298
4261
  try {
3299
4262
  const library2 = require_library();
3300
- const { to, data } = library2.buildUpdateLibraryForSubDAOTx({
4263
+ const { to, data } = library2.buildUpdateLibraryTx({
3301
4264
  registry: execution.registry,
3302
4265
  subdao: execution.subdao,
3303
4266
  manifestCID: execution.manifestCID || "",
3304
- promptCount: execution.promptCount || 0,
3305
- libraryId: execution.libraryId || "main"
4267
+ version: execution.version || "1.0.0"
3306
4268
  });
3307
4269
  const sim = await library2.simulateAsTimelock({ provider, registry: execution.registry, to, data, timelock: execution.timelock });
3308
4270
  executionReady = !!sim.ok;
@@ -3836,13 +4798,13 @@ var require_openzeppelin = __commonJS({
3836
4798
  return null;
3837
4799
  }
3838
4800
  }
3839
- async function getProposals({ provider, governor, fromBlock = 0, toBlock = "latest", pageSize = 5e3, abiResolver = null, selectorResolver = null, chainId = null }) {
4801
+ async function getProposals({ provider, governor, fromBlock, toBlock = "latest", pageSize = 5e3, abiResolver = null, selectorResolver = null, chainId = null }) {
3840
4802
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3841
4803
  const addr = normaliseGovernor(governor);
3842
4804
  const iface = new Interface([Events.ProposalCreated]);
3843
4805
  const topic = iface.getEvent("ProposalCreated").topicHash;
3844
4806
  const latest = toBlock === "latest" ? await provider.getBlockNumber() : Number(toBlock);
3845
- const start = Number(fromBlock);
4807
+ const start = fromBlock !== void 0 ? Number(fromBlock) : Math.max(0, latest - 5e4);
3846
4808
  const end = latest;
3847
4809
  const items = [];
3848
4810
  const resolvedChainId = await resolveChainId(provider, chainId);
@@ -3871,7 +4833,7 @@ var require_openzeppelin = __commonJS({
3871
4833
  }
3872
4834
  return { items, nextCursor: null };
3873
4835
  }
3874
- async function getTimelineOnchain({ provider, governor, id: id2, fromBlock = 0, toBlock = "latest" }) {
4836
+ async function getTimelineOnchain({ provider, governor, id: id2, fromBlock, toBlock = "latest" }) {
3875
4837
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
3876
4838
  const addr = normaliseGovernor(governor);
3877
4839
  const pid = typeof id2 === "bigint" ? id2 : String(id2).startsWith("0x") ? BigInt(id2) : BigInt(String(id2));
@@ -3882,7 +4844,8 @@ var require_openzeppelin = __commonJS({
3882
4844
  iface.getEvent("ProposalCanceled").topicHash
3883
4845
  ];
3884
4846
  const latest = toBlock === "latest" ? await provider.getBlockNumber() : Number(toBlock);
3885
- const logs = await provider.getLogs({ address: addr, fromBlock: Number(fromBlock), toBlock: latest, topics: [topics] });
4847
+ const start = fromBlock !== void 0 ? Number(fromBlock) : Math.max(0, latest - 5e4);
4848
+ const logs = await provider.getLogs({ address: addr, fromBlock: start, toBlock: latest, topics: [topics] });
3886
4849
  const out = [];
3887
4850
  for (const log of logs) {
3888
4851
  try {
@@ -4159,6 +5122,7 @@ var require_operations = __commonJS({
4159
5122
  cache = null,
4160
5123
  fromBlock = 0,
4161
5124
  helperAddress = null,
5125
+ subgraphUrl = null,
4162
5126
  hints = {},
4163
5127
  chunkSizeBlocks = 1e4,
4164
5128
  lookBackBlocks = 2e3,
@@ -4172,6 +5136,27 @@ var require_operations = __commonJS({
4172
5136
  const cached = await cacheAdapter.load(govAddr, id2);
4173
5137
  if (cached) return cached;
4174
5138
  }
5139
+ if (subgraphUrl) {
5140
+ try {
5141
+ const subgraph2 = require_subgraph2();
5142
+ const sgProposal = await subgraph2.getProposalById({ url: subgraphUrl, id: String(id2), governor: govAddr });
5143
+ if (sgProposal && sgProposal.targets && sgProposal.targets.length > 0) {
5144
+ const tuple2 = {
5145
+ id: id2,
5146
+ governor: govAddr,
5147
+ targets: sgProposal.targets,
5148
+ values: sgProposal.values || [],
5149
+ calldatas: sgProposal.calldatas || [],
5150
+ description: sgProposal.description || "",
5151
+ descriptionHash: sgProposal.description ? keccak256(toUtf8Bytes(sgProposal.description)) : null,
5152
+ createdBlock: sgProposal.createdAt || null
5153
+ };
5154
+ if (cacheAdapter) await cacheAdapter.save(govAddr, id2, tuple2);
5155
+ return tuple2;
5156
+ }
5157
+ } catch (_) {
5158
+ }
5159
+ }
4175
5160
  if (helperAddress) {
4176
5161
  try {
4177
5162
  const helperAbi = [
@@ -4385,8 +5370,14 @@ var require_operations = __commonJS({
4385
5370
  ]);
4386
5371
  let resolvedSubDAO = subdao2;
4387
5372
  if (!resolvedSubDAO) {
4388
- resolvedSubDAO = await governorContract.subDAO().catch(() => null);
4389
- if (resolvedSubDAO === ZeroAddress) resolvedSubDAO = null;
5373
+ try {
5374
+ const subDAOInterface = new Interface(["function subDAO() view returns (address)"]);
5375
+ const subdaoContract = new Contract(govAddr, subDAOInterface, provider);
5376
+ resolvedSubDAO = await subdaoContract.subDAO().catch(() => null);
5377
+ if (resolvedSubDAO === ZeroAddress) resolvedSubDAO = null;
5378
+ } catch {
5379
+ resolvedSubDAO = null;
5380
+ }
4390
5381
  }
4391
5382
  let mode = null;
4392
5383
  let eligible = null;
@@ -4461,10 +5452,11 @@ var require_operations = __commonJS({
4461
5452
  refresh = false,
4462
5453
  cache = null,
4463
5454
  includeTimeline = false,
4464
- helperAddress = null
5455
+ helperAddress = null,
5456
+ subgraphUrl = null
4465
5457
  }) {
4466
5458
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
4467
- const tuple = await resolveProposalTuple({ provider, governor, proposalId, refresh, cache, helperAddress });
5459
+ const tuple = await resolveProposalTuple({ provider, governor, proposalId, refresh, cache, helperAddress, subgraphUrl });
4468
5460
  let proposal = null;
4469
5461
  try {
4470
5462
  proposal = await governance2.getProposal({ provider, governor: tuple.governor, id: tuple.id });
@@ -4802,8 +5794,6 @@ var require_factory = __commonJS({
4802
5794
  stableCreationFee,
4803
5795
  feeReceiver,
4804
5796
  allowStableFee,
4805
- stablePromptForkFee,
4806
- allowStablePromptForkFee,
4807
5797
  stableForkFee,
4808
5798
  allowStableForkFee,
4809
5799
  timelockMinDelay,
@@ -4827,8 +5817,6 @@ var require_factory = __commonJS({
4827
5817
  }
4828
5818
  })(),
4829
5819
  contract.allowStableFee().catch(() => null),
4830
- contract.stablePromptForkFee().catch(() => null),
4831
- contract.allowStablePromptForkFee().catch(() => null),
4832
5820
  contract.stableForkFee().catch(() => null),
4833
5821
  contract.allowStableForkFee().catch(() => null),
4834
5822
  contract.timelockMinDelay().catch(() => null),
@@ -4844,8 +5832,6 @@ var require_factory = __commonJS({
4844
5832
  stableCreationFee,
4845
5833
  feeReceiver: feeReceiver && feeReceiver !== "0x0000000000000000000000000000000000000000" ? getAddress(feeReceiver) : null,
4846
5834
  allowStableFee,
4847
- stablePromptForkFee,
4848
- allowStablePromptForkFee,
4849
5835
  stableForkFee,
4850
5836
  allowStableForkFee,
4851
5837
  timelockMinDelay,
@@ -5159,20 +6145,127 @@ var require_factory = __commonJS({
5159
6145
  }
5160
6146
  }
5161
6147
  module2.exports = {
5162
- getFactoryConfig,
5163
- getFactoryStats,
5164
- listSubDAOs,
5165
- listSubDAOsIndexed,
5166
- getSubDAORegistry,
5167
- listTemplates,
5168
- getTemplateDetails,
5169
- buildCreateSubDAOTx,
5170
- buildCreateSubDAOWithStableTx,
5171
- buildCreateSubDAOWithParamsTx,
5172
- buildCreateOperatorSubDAOWithStableTx,
5173
- buildCreateOperatorSubDAOWithStableAdvancedTx,
5174
- buildCreateForkedSubDAOTx,
5175
- buildCreateForkedSubDAOWithStableTx
6148
+ getFactoryConfig,
6149
+ getFactoryStats,
6150
+ listSubDAOs,
6151
+ listSubDAOsIndexed,
6152
+ getSubDAORegistry,
6153
+ listTemplates,
6154
+ getTemplateDetails,
6155
+ buildCreateSubDAOTx,
6156
+ buildCreateSubDAOWithStableTx,
6157
+ buildCreateSubDAOWithParamsTx,
6158
+ buildCreateOperatorSubDAOWithStableTx,
6159
+ buildCreateOperatorSubDAOWithStableAdvancedTx,
6160
+ buildCreateForkedSubDAOTx,
6161
+ buildCreateForkedSubDAOWithStableTx
6162
+ };
6163
+ }
6164
+ });
6165
+
6166
+ // src/lineage/index.js
6167
+ var require_lineage = __commonJS({
6168
+ "src/lineage/index.js"(exports2, module2) {
6169
+ var { Contract, getAddress } = require("ethers");
6170
+ var { SageSDKError, CODES } = require_errors();
6171
+ var LINEAGE_ABI = [
6172
+ "function libraryByDAO(address) view returns (string manifestCID, address lastUpdater, uint256 lastUpdated, string version, address forkedFromDAO, uint256 sxxxForkFee)",
6173
+ "function getLibraryForkFee(address) view returns (uint256)"
6174
+ ];
6175
+ var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
6176
+ function normalise(address, label) {
6177
+ if (!address) throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
6178
+ try {
6179
+ return getAddress(address);
6180
+ } catch (err) {
6181
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
6182
+ }
6183
+ }
6184
+ async function getParentLibrary({ provider, registry, subdao: subdao2 }) {
6185
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6186
+ if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
6187
+ if (!subdao2) throw new SageSDKError(CODES.INVALID_ARGS, "subdao required");
6188
+ try {
6189
+ const contract = new Contract(normalise(registry, "registry"), LINEAGE_ABI, provider);
6190
+ const info = await contract.libraryByDAO(normalise(subdao2, "subdao"));
6191
+ const parent = info.forkedFromDAO;
6192
+ if (!parent || parent === ZERO_ADDRESS) {
6193
+ return null;
6194
+ }
6195
+ return getAddress(parent).toLowerCase();
6196
+ } catch (err) {
6197
+ throw new SageSDKError(CODES.CONTRACT_ERROR, "Failed to fetch parent library", { cause: err });
6198
+ }
6199
+ }
6200
+ async function getLineageChain({ provider, registry, subdao: subdao2 }) {
6201
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6202
+ if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
6203
+ if (!subdao2) throw new SageSDKError(CODES.INVALID_ARGS, "subdao required");
6204
+ try {
6205
+ const contract = new Contract(normalise(registry, "registry"), LINEAGE_ABI, provider);
6206
+ const chain = [];
6207
+ let current = normalise(subdao2, "subdao");
6208
+ const MAX_DEPTH = 100;
6209
+ let iterations = 0;
6210
+ while (current && iterations < MAX_DEPTH) {
6211
+ chain.unshift(getAddress(current).toLowerCase());
6212
+ const info = await contract.libraryByDAO(current);
6213
+ const parent = info.forkedFromDAO;
6214
+ if (!parent || parent === ZERO_ADDRESS) {
6215
+ break;
6216
+ }
6217
+ current = parent;
6218
+ iterations++;
6219
+ }
6220
+ return {
6221
+ chain,
6222
+ depth: chain.length - 1,
6223
+ root: chain[0]
6224
+ };
6225
+ } catch (err) {
6226
+ throw new SageSDKError(CODES.CONTRACT_ERROR, "Failed to fetch lineage chain", { cause: err });
6227
+ }
6228
+ }
6229
+ async function isFork({ provider, registry, subdao: subdao2 }) {
6230
+ const parent = await getParentLibrary({ provider, registry, subdao: subdao2 });
6231
+ return parent !== null;
6232
+ }
6233
+ async function getLibraryForkFee({ provider, registry, subdao: subdao2 }) {
6234
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6235
+ if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
6236
+ if (!subdao2) throw new SageSDKError(CODES.INVALID_ARGS, "subdao required");
6237
+ try {
6238
+ const contract = new Contract(normalise(registry, "registry"), LINEAGE_ABI, provider);
6239
+ const fee = await contract.getLibraryForkFee(normalise(subdao2, "subdao"));
6240
+ return BigInt(fee.toString());
6241
+ } catch (err) {
6242
+ throw new SageSDKError(CODES.CONTRACT_ERROR, "Failed to fetch library fork fee", { cause: err });
6243
+ }
6244
+ }
6245
+ async function getLibraryInfo({ provider, registry, subdao: subdao2 }) {
6246
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6247
+ if (!registry) throw new SageSDKError(CODES.INVALID_ARGS, "registry required");
6248
+ if (!subdao2) throw new SageSDKError(CODES.INVALID_ARGS, "subdao required");
6249
+ try {
6250
+ const contract = new Contract(normalise(registry, "registry"), LINEAGE_ABI, provider);
6251
+ const info = await contract.libraryByDAO(normalise(subdao2, "subdao"));
6252
+ const parent = info.forkedFromDAO;
6253
+ return {
6254
+ parentDAO: !parent || parent === ZERO_ADDRESS ? null : getAddress(parent).toLowerCase(),
6255
+ forkFee: BigInt(info.sxxxForkFee.toString()),
6256
+ manifestCID: info.manifestCID,
6257
+ version: info.version
6258
+ };
6259
+ } catch (err) {
6260
+ throw new SageSDKError(CODES.CONTRACT_ERROR, "Failed to fetch library info", { cause: err });
6261
+ }
6262
+ }
6263
+ module2.exports = {
6264
+ getParentLibrary,
6265
+ getLineageChain,
6266
+ isFork,
6267
+ getLibraryForkFee,
6268
+ getLibraryInfo
5176
6269
  };
5177
6270
  }
5178
6271
  });
@@ -5849,7 +6942,6 @@ var require_ipns = __commonJS({
5849
6942
  headers["X-Wallet-Address"] = auth.address;
5850
6943
  headers["X-Wallet-Signature"] = auth.signature;
5851
6944
  headers["X-Wallet-Nonce"] = auth.nonce;
5852
- headers["X-Wallet-Message"] = auth.message;
5853
6945
  }
5854
6946
  return { headers, auth };
5855
6947
  }
@@ -5871,8 +6963,7 @@ var require_ipns = __commonJS({
5871
6963
  ...extraHeaders,
5872
6964
  "X-Wallet-Address": auth.address,
5873
6965
  "X-Wallet-Signature": auth.signature,
5874
- "X-Wallet-Nonce": auth.nonce,
5875
- "X-Wallet-Message": auth.message
6966
+ "X-Wallet-Nonce": auth.nonce
5876
6967
  };
5877
6968
  return { headers, auth };
5878
6969
  }
@@ -6509,8 +7600,34 @@ var require_time = __commonJS({
6509
7600
  var require_treasury = __commonJS({
6510
7601
  "src/treasury/index.js"(exports2, module2) {
6511
7602
  var { Contract, Interface, getAddress } = require("ethers");
6512
- var ABI = require_abi();
6513
7603
  var { SageSDKError, CODES } = require_errors();
7604
+ var SAGE_TREASURY_ABI = [
7605
+ // Aggregated views
7606
+ "function totalReserves() view returns (uint256)",
7607
+ "function totalPOL() view returns (uint256)",
7608
+ "function totalDebt() view returns (uint256)",
7609
+ // Canonical liquidity config
7610
+ "function canonicalPool() view returns (address)",
7611
+ "function routerOrVault() view returns (address)",
7612
+ // Withdrawal rate limits
7613
+ "function maxWithdrawalRate() view returns (uint256)",
7614
+ "function emergencyWithdrawalLimit() view returns (uint256)",
7615
+ // Reserve tokens
7616
+ "function getReserveTokens() view returns (address[])",
7617
+ "function getReserve(address token) view returns (tuple(uint256 amount, uint256 value, bool isLP, bool isActive))",
7618
+ // Withdrawal queue
7619
+ "function nextWithdrawalId() view returns (uint256)",
7620
+ "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))",
7621
+ "function withdraw(address token, uint256 amount, address recipient)",
7622
+ "function confirmWithdrawal(uint256 id)",
7623
+ "function cancelWithdrawal(uint256 id)",
7624
+ // Manual price overrides
7625
+ "function manualPrices(address token) view returns (tuple(uint256 price, uint256 expiresAt, bool active))",
7626
+ "function setPriceOverride(address token, uint256 price, uint256 ttlSeconds)",
7627
+ "function clearPriceOverride(address token)",
7628
+ // Events
7629
+ "event WithdrawalScheduled(uint256 indexed id, address indexed token, address indexed recipient, uint256 amount)"
7630
+ ];
6514
7631
  var LiquidityEvents = new Interface([
6515
7632
  "event CanonicalLiquidityUpdated(address indexed pool, address indexed routerOrVault)",
6516
7633
  "event LiquidityAddPlanned(address indexed subdao, address indexed pool, address sxxxToken, address stableToken, uint256 sxxxAmount, uint256 stableAmount, address lpRecipient)",
@@ -6555,7 +7672,7 @@ var require_treasury = __commonJS({
6555
7672
  async function getTreasuryInfo({ provider, treasury: treasury2 }) {
6556
7673
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6557
7674
  const addr = normalise(treasury2, "treasury");
6558
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7675
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6559
7676
  const [totalReserves, totalPOL, totalDebt, canonicalPool, routerOrVault, maxWithdrawalRate, emergencyWithdrawalLimit] = await Promise.all([
6560
7677
  contract.totalReserves().catch(() => 0n),
6561
7678
  contract.totalPOL().catch(() => 0n),
@@ -6579,7 +7696,7 @@ var require_treasury = __commonJS({
6579
7696
  async function getPendingWithdrawals({ provider, treasury: treasury2, ids, limit = 50 }) {
6580
7697
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6581
7698
  const addr = normalise(treasury2, "treasury");
6582
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7699
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6583
7700
  let idList = ids;
6584
7701
  if (!Array.isArray(idList)) {
6585
7702
  const nextId = await contract.nextWithdrawalId().catch(() => 0n);
@@ -6611,14 +7728,14 @@ var require_treasury = __commonJS({
6611
7728
  async function getReserveTokens({ provider, treasury: treasury2 }) {
6612
7729
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6613
7730
  const addr = normalise(treasury2, "treasury");
6614
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7731
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6615
7732
  const tokens = await contract.getReserveTokens().catch(() => []);
6616
7733
  return tokens.map((token2) => getAddress(token2));
6617
7734
  }
6618
7735
  async function getReserves({ provider, treasury: treasury2, tokens, fetchMetadata = true }) {
6619
7736
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6620
7737
  const addr = normalise(treasury2, "treasury");
6621
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7738
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6622
7739
  const tokenList = Array.isArray(tokens) && tokens.length ? tokens.map((token2) => getAddress(token2)) : await contract.getReserveTokens().catch(() => []);
6623
7740
  const reserves = [];
6624
7741
  for (const token2 of tokenList) {
@@ -6648,7 +7765,7 @@ var require_treasury = __commonJS({
6648
7765
  async function getManualPriceOverrides({ provider, treasury: treasury2, tokens }) {
6649
7766
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6650
7767
  const addr = normalise(treasury2, "treasury");
6651
- const contract = new Contract(addr, ABI.SageTreasury, provider);
7768
+ const contract = new Contract(addr, SAGE_TREASURY_ABI, provider);
6652
7769
  const tokenList = Array.isArray(tokens) && tokens.length ? tokens.map((token2) => getAddress(token2)) : await contract.getReserveTokens().catch(() => []);
6653
7770
  const overrides = [];
6654
7771
  for (const token2 of tokenList) {
@@ -6753,7 +7870,7 @@ var require_treasury = __commonJS({
6753
7870
  async function getLPContribution({ provider, treasury: treasury2, subdao: subdao2, token: token2 }) {
6754
7871
  if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
6755
7872
  const addr = normalise(treasury2, "treasury");
6756
- const c = new Contract(addr, ABI.SageTreasury, provider);
7873
+ const c = new Contract(addr, SAGE_TREASURY_ABI, provider);
6757
7874
  const amount = await c.lpContributions(normalise(subdao2, "subdao"), normalise(token2, "token")).catch(() => 0n);
6758
7875
  return amount;
6759
7876
  }
@@ -6795,7 +7912,7 @@ var require_treasury = __commonJS({
6795
7912
  function createWriteContract({ signer, treasury: treasury2 }) {
6796
7913
  if (!signer) throw new SageSDKError(CODES.INVALID_ARGS, "signer required");
6797
7914
  const addr = normalise(treasury2, "treasury");
6798
- return new Contract(addr, ABI.SageTreasury, signer);
7915
+ return new Contract(addr, SAGE_TREASURY_ABI, signer);
6799
7916
  }
6800
7917
  async function waitForReceipt({ signer, tx, waitMs }) {
6801
7918
  const provider = signer.provider;
@@ -7091,10 +8208,787 @@ var require_bounty = __commonJS({
7091
8208
  return { governor, proposalCall };
7092
8209
  }
7093
8210
  module2.exports = {
7094
- configureWinnerMode,
7095
- fundFromTreasury,
7096
- approveWinner,
7097
- proposeApproveWinner
8211
+ configureWinnerMode,
8212
+ fundFromTreasury,
8213
+ approveWinner,
8214
+ proposeApproveWinner
8215
+ };
8216
+ }
8217
+ });
8218
+
8219
+ // src/contributions/index.js
8220
+ var require_contributions = __commonJS({
8221
+ "src/contributions/index.js"(exports2, module2) {
8222
+ var { getAddress, isAddress } = require("ethers");
8223
+ var subgraph2 = require_subgraph();
8224
+ var GovernanceModel = {
8225
+ TOKEN_VOTING: "TOKEN_VOTING",
8226
+ COUNCIL: "COUNCIL",
8227
+ OPERATOR: "OPERATOR",
8228
+ DIRECT: "DIRECT"
8229
+ };
8230
+ function safeGetAddress(value) {
8231
+ try {
8232
+ return getAddress(value);
8233
+ } catch {
8234
+ return null;
8235
+ }
8236
+ }
8237
+ function mapSafe(list, mapper) {
8238
+ const out = [];
8239
+ for (const item of list || []) {
8240
+ try {
8241
+ const v = mapper(item);
8242
+ if (v != null) out.push(v);
8243
+ } catch {
8244
+ }
8245
+ }
8246
+ return out;
8247
+ }
8248
+ function detectGovernanceModel(subdaoInfo) {
8249
+ if (!subdaoInfo) return GovernanceModel.DIRECT;
8250
+ const playbook = subdaoInfo.playbook;
8251
+ if (playbook) {
8252
+ if (playbook === "council-closed" || playbook === "council-drafts") {
8253
+ return GovernanceModel.COUNCIL;
8254
+ }
8255
+ if (playbook === "community") {
8256
+ return GovernanceModel.TOKEN_VOTING;
8257
+ }
8258
+ }
8259
+ const governanceKind = subdaoInfo.governanceKind;
8260
+ if (governanceKind === 0) {
8261
+ return GovernanceModel.OPERATOR;
8262
+ }
8263
+ if (governanceKind === 1) {
8264
+ const proposalAccess = subdaoInfo.proposalAccess;
8265
+ if (proposalAccess === 0) {
8266
+ return GovernanceModel.COUNCIL;
8267
+ }
8268
+ return GovernanceModel.TOKEN_VOTING;
8269
+ }
8270
+ return GovernanceModel.TOKEN_VOTING;
8271
+ }
8272
+ async function listContributions({
8273
+ url,
8274
+ subdao: subdao2,
8275
+ promptKey,
8276
+ contributor,
8277
+ fromBounty,
8278
+ first = 50,
8279
+ skip = 0,
8280
+ orderBy = "updatedAt",
8281
+ orderDirection = "desc"
8282
+ }) {
8283
+ if (!url) throw new Error("subgraph url required");
8284
+ const filters = [];
8285
+ if (subdao2) {
8286
+ const addr = safeGetAddress(subdao2);
8287
+ if (!addr) throw new Error("invalid subdao address");
8288
+ filters.push(`dao: "${addr.toLowerCase()}"`);
8289
+ }
8290
+ if (promptKey) {
8291
+ filters.push(`promptKey: "${String(promptKey)}"`);
8292
+ }
8293
+ if (contributor) {
8294
+ const addr = safeGetAddress(contributor);
8295
+ if (!addr) throw new Error("invalid contributor address");
8296
+ filters.push(`contributor: "${addr.toLowerCase()}"`);
8297
+ }
8298
+ if (fromBounty !== void 0) {
8299
+ filters.push(`fromBounty: ${Boolean(fromBounty)}`);
8300
+ }
8301
+ const where = filters.length ? `where: { ${filters.join(", ")} }` : "";
8302
+ const safeOrderBy = ["updatedAt", "createdAt"].includes(orderBy) ? orderBy : "updatedAt";
8303
+ const safeOrderDirection = orderDirection === "asc" ? "asc" : "desc";
8304
+ const doc = `
8305
+ query($first: Int!, $skip: Int!) {
8306
+ promptContributions(
8307
+ ${where}
8308
+ first: $first
8309
+ skip: $skip
8310
+ orderBy: ${safeOrderBy}
8311
+ orderDirection: ${safeOrderDirection}
8312
+ ) {
8313
+ id
8314
+ dao
8315
+ promptKey
8316
+ contributor
8317
+ cid
8318
+ proposalId
8319
+ forVotes
8320
+ againstVotes
8321
+ abstainVotes
8322
+ uniqueVoters
8323
+ quorum
8324
+ fromBounty
8325
+ bountyId
8326
+ badgeId
8327
+ badgeEvidenceURI
8328
+ createdAt
8329
+ updatedAt
8330
+ transactionHash
8331
+ }
8332
+ }
8333
+ `;
8334
+ const data = await subgraph2.query(url, doc, {
8335
+ first: Math.min(Math.max(1, Number(first || 50)), 100),
8336
+ skip: Number(skip || 0)
8337
+ });
8338
+ return mapSafe(data?.promptContributions, mapContribution);
8339
+ }
8340
+ async function getByPrompt({ url, subdao: subdao2, promptKey }) {
8341
+ if (!url) throw new Error("subgraph url required");
8342
+ if (!subdao2) throw new Error("subdao required");
8343
+ if (!promptKey) throw new Error("promptKey required");
8344
+ const contributions2 = await listContributions({
8345
+ url,
8346
+ subdao: subdao2,
8347
+ promptKey,
8348
+ first: 100
8349
+ });
8350
+ const aggregates = computeAggregates(contributions2);
8351
+ return { contributions: contributions2, aggregates };
8352
+ }
8353
+ async function getById({ url, id: id2 }) {
8354
+ if (!url) throw new Error("subgraph url required");
8355
+ if (!id2) throw new Error("id required");
8356
+ const doc = `
8357
+ query($id: ID!) {
8358
+ promptContribution(id: $id) {
8359
+ id
8360
+ dao
8361
+ promptKey
8362
+ contributor
8363
+ cid
8364
+ proposalId
8365
+ forVotes
8366
+ againstVotes
8367
+ abstainVotes
8368
+ uniqueVoters
8369
+ quorum
8370
+ fromBounty
8371
+ bountyId
8372
+ badgeId
8373
+ badgeEvidenceURI
8374
+ createdAt
8375
+ updatedAt
8376
+ transactionHash
8377
+ }
8378
+ }
8379
+ `;
8380
+ const data = await subgraph2.query(url, doc, { id: String(id2) });
8381
+ const row = data?.promptContribution;
8382
+ if (!row) return null;
8383
+ return mapContribution(row);
8384
+ }
8385
+ function mapContribution(row) {
8386
+ const dao = safeGetAddress(row.dao);
8387
+ const contributor = safeGetAddress(row.contributor);
8388
+ if (!dao) return null;
8389
+ let governanceModel = GovernanceModel.DIRECT;
8390
+ if (row.proposalId != null) {
8391
+ governanceModel = GovernanceModel.TOKEN_VOTING;
8392
+ } else if (row.fromBounty) {
8393
+ governanceModel = GovernanceModel.DIRECT;
8394
+ }
8395
+ return {
8396
+ id: String(row.id),
8397
+ dao,
8398
+ daoName: null,
8399
+ // Enriched separately if needed
8400
+ promptKey: String(row.promptKey),
8401
+ contributor: contributor || "0x0000000000000000000000000000000000000000",
8402
+ cid: String(row.cid),
8403
+ timestamp: Number(row.updatedAt || 0),
8404
+ createdAt: Number(row.createdAt || 0),
8405
+ updatedAt: Number(row.updatedAt || 0),
8406
+ transactionHash: row.transactionHash || null,
8407
+ // Governance context
8408
+ governanceModel,
8409
+ proposalId: row.proposalId != null ? BigInt(String(row.proposalId)) : null,
8410
+ forVotes: row.forVotes != null ? BigInt(String(row.forVotes)) : null,
8411
+ againstVotes: row.againstVotes != null ? BigInt(String(row.againstVotes)) : null,
8412
+ abstainVotes: row.abstainVotes != null ? BigInt(String(row.abstainVotes)) : null,
8413
+ uniqueVoters: row.uniqueVoters != null ? Number(row.uniqueVoters) : null,
8414
+ quorum: row.quorum != null ? BigInt(String(row.quorum)) : null,
8415
+ // Bounty context
8416
+ fromBounty: Boolean(row.fromBounty),
8417
+ bountyId: row.bountyId != null ? BigInt(String(row.bountyId)) : null,
8418
+ // Badge context
8419
+ badgeId: row.badgeId != null ? BigInt(String(row.badgeId)) : null,
8420
+ badgeEvidenceURI: row.badgeEvidenceURI || null
8421
+ };
8422
+ }
8423
+ function computeAggregates(contributions2) {
8424
+ if (!contributions2 || contributions2.length === 0) {
8425
+ return {
8426
+ totalContributions: 0,
8427
+ uniqueContributors: 0,
8428
+ bountyOriginated: 0,
8429
+ governanceOriginated: 0,
8430
+ totalForVotes: 0n,
8431
+ totalAgainstVotes: 0n,
8432
+ averageVoterCount: 0,
8433
+ badgeCount: 0
8434
+ };
8435
+ }
8436
+ const contributorSet = /* @__PURE__ */ new Set();
8437
+ let bountyOriginated = 0;
8438
+ let governanceOriginated = 0;
8439
+ let totalForVotes = 0n;
8440
+ let totalAgainstVotes = 0n;
8441
+ let voterCountSum = 0;
8442
+ let voterCountN = 0;
8443
+ let badgeCount = 0;
8444
+ for (const c of contributions2) {
8445
+ if (c.contributor) contributorSet.add(c.contributor.toLowerCase());
8446
+ if (c.fromBounty) {
8447
+ bountyOriginated++;
8448
+ } else {
8449
+ governanceOriginated++;
8450
+ }
8451
+ if (c.forVotes != null) totalForVotes += c.forVotes;
8452
+ if (c.againstVotes != null) totalAgainstVotes += c.againstVotes;
8453
+ if (c.uniqueVoters != null) {
8454
+ voterCountSum += c.uniqueVoters;
8455
+ voterCountN++;
8456
+ }
8457
+ if (c.badgeId != null) badgeCount++;
8458
+ }
8459
+ return {
8460
+ totalContributions: contributions2.length,
8461
+ uniqueContributors: contributorSet.size,
8462
+ bountyOriginated,
8463
+ governanceOriginated,
8464
+ totalForVotes,
8465
+ totalAgainstVotes,
8466
+ averageVoterCount: voterCountN > 0 ? Math.round(voterCountSum / voterCountN) : 0,
8467
+ badgeCount
8468
+ };
8469
+ }
8470
+ function getGovernanceQuality(contribution, context = {}) {
8471
+ if (!contribution) {
8472
+ return {
8473
+ model: GovernanceModel.DIRECT,
8474
+ decentralization: 0,
8475
+ consensus: 0,
8476
+ raw: {}
8477
+ };
8478
+ }
8479
+ const model = contribution.governanceModel || GovernanceModel.DIRECT;
8480
+ switch (model) {
8481
+ case GovernanceModel.TOKEN_VOTING:
8482
+ return computeTokenVotingQuality(contribution, context);
8483
+ case GovernanceModel.COUNCIL:
8484
+ return computeCouncilQuality(contribution, context);
8485
+ case GovernanceModel.OPERATOR:
8486
+ return computeOperatorQuality(contribution, context);
8487
+ case GovernanceModel.DIRECT:
8488
+ default:
8489
+ return {
8490
+ model: GovernanceModel.DIRECT,
8491
+ decentralization: 0,
8492
+ consensus: 1,
8493
+ // Direct = full consensus (single decision maker)
8494
+ raw: {
8495
+ contributor: contribution.contributor
8496
+ }
8497
+ };
8498
+ }
8499
+ }
8500
+ function computeTokenVotingQuality(contribution, context) {
8501
+ const forVotes = contribution.forVotes || 0n;
8502
+ const againstVotes = contribution.againstVotes || 0n;
8503
+ const abstainVotes = contribution.abstainVotes || 0n;
8504
+ const totalVotes = forVotes + againstVotes + abstainVotes;
8505
+ const uniqueVoters = contribution.uniqueVoters || 0;
8506
+ const quorum = contribution.quorum || null;
8507
+ const totalHolders = context.totalHolders || null;
8508
+ let decentralization = 0;
8509
+ if (totalHolders && totalHolders > 0 && uniqueVoters > 0) {
8510
+ decentralization = Math.min(1, uniqueVoters / totalHolders);
8511
+ } else if (uniqueVoters > 0) {
8512
+ decentralization = Math.min(1, Math.log10(uniqueVoters + 1) / 3);
8513
+ }
8514
+ let consensus = 0;
8515
+ if (totalVotes > 0n) {
8516
+ consensus = Number(forVotes * 10000n / totalVotes) / 1e4;
8517
+ }
8518
+ let quorumMet = null;
8519
+ if (quorum != null && quorum > 0n) {
8520
+ quorumMet = totalVotes >= quorum;
8521
+ }
8522
+ return {
8523
+ model: GovernanceModel.TOKEN_VOTING,
8524
+ decentralization,
8525
+ consensus,
8526
+ raw: {
8527
+ forVotes,
8528
+ againstVotes,
8529
+ abstainVotes,
8530
+ totalVotes,
8531
+ uniqueVoters,
8532
+ quorum,
8533
+ quorumMet,
8534
+ proposalId: contribution.proposalId
8535
+ }
8536
+ };
8537
+ }
8538
+ function computeCouncilQuality(contribution, context) {
8539
+ const signerCount = contribution.signerCount || context.signerCount || 0;
8540
+ const threshold = contribution.threshold || context.threshold || 0;
8541
+ const totalCouncilMembers = context.totalCouncilMembers || threshold;
8542
+ let decentralization = 0;
8543
+ if (totalCouncilMembers > 0 && signerCount > 0) {
8544
+ decentralization = Math.min(1, signerCount / totalCouncilMembers);
8545
+ }
8546
+ let consensus = 0;
8547
+ if (threshold > 0) {
8548
+ consensus = Math.min(1, signerCount / threshold);
8549
+ }
8550
+ return {
8551
+ model: GovernanceModel.COUNCIL,
8552
+ decentralization,
8553
+ consensus,
8554
+ raw: {
8555
+ signerCount,
8556
+ threshold,
8557
+ totalCouncilMembers,
8558
+ signers: contribution.signers || []
8559
+ }
8560
+ };
8561
+ }
8562
+ function computeOperatorQuality(contribution, context) {
8563
+ return {
8564
+ model: GovernanceModel.OPERATOR,
8565
+ decentralization: 0,
8566
+ // Single operator = not decentralized
8567
+ consensus: 1,
8568
+ // Operator decision = full "consensus"
8569
+ raw: {
8570
+ operator: contribution.operator || contribution.contributor,
8571
+ operatorRole: contribution.operatorRole || context.operatorRole || null
8572
+ }
8573
+ };
8574
+ }
8575
+ function enrichWithGovernanceModel(contribution, subdaoInfo) {
8576
+ if (!contribution) return contribution;
8577
+ const model = detectGovernanceModel(subdaoInfo);
8578
+ return {
8579
+ ...contribution,
8580
+ governanceModel: model,
8581
+ daoName: subdaoInfo?.name || null
8582
+ };
8583
+ }
8584
+ async function getByContributor({ url, contributor, first = 50, skip = 0 }) {
8585
+ if (!url) throw new Error("subgraph url required");
8586
+ if (!contributor) throw new Error("contributor required");
8587
+ return listContributions({ url, contributor, first, skip });
8588
+ }
8589
+ async function getBadgesByRecipient({ url, recipient, first = 50 }) {
8590
+ if (!url) throw new Error("subgraph url required");
8591
+ if (!recipient) throw new Error("recipient required");
8592
+ const addr = safeGetAddress(recipient);
8593
+ if (!addr) throw new Error("invalid recipient address");
8594
+ const doc = `
8595
+ query($recipient: Bytes!, $first: Int!) {
8596
+ soulboundBadges(
8597
+ where: { recipient: $recipient }
8598
+ first: $first
8599
+ orderBy: blockTimestamp
8600
+ orderDirection: desc
8601
+ ) {
8602
+ id
8603
+ contract
8604
+ badgeId
8605
+ recipient
8606
+ evidenceURI
8607
+ blockNumber
8608
+ blockTimestamp
8609
+ transactionHash
8610
+ }
8611
+ }
8612
+ `;
8613
+ const data = await subgraph2.query(url, doc, {
8614
+ recipient: addr.toLowerCase(),
8615
+ first: Math.min(Math.max(1, Number(first || 50)), 100)
8616
+ });
8617
+ return mapSafe(data?.soulboundBadges, (row) => {
8618
+ const contract = safeGetAddress(row.contract);
8619
+ const recipient2 = safeGetAddress(row.recipient);
8620
+ if (!contract || !recipient2) return null;
8621
+ return {
8622
+ id: String(row.id),
8623
+ contract,
8624
+ badgeId: BigInt(String(row.badgeId || "0")),
8625
+ recipient: recipient2,
8626
+ evidenceURI: row.evidenceURI || null,
8627
+ blockNumber: Number(row.blockNumber || 0),
8628
+ blockTimestamp: Number(row.blockTimestamp || 0),
8629
+ transactionHash: row.transactionHash || null
8630
+ };
8631
+ });
8632
+ }
8633
+ module2.exports = {
8634
+ // Constants
8635
+ GovernanceModel,
8636
+ // Main queries
8637
+ listContributions,
8638
+ getByPrompt,
8639
+ getById,
8640
+ getByContributor,
8641
+ getBadgesByRecipient,
8642
+ // Governance quality helpers
8643
+ getGovernanceQuality,
8644
+ enrichWithGovernanceModel,
8645
+ detectGovernanceModel,
8646
+ // Aggregation helpers
8647
+ computeAggregates
8648
+ };
8649
+ }
8650
+ });
8651
+
8652
+ // src/votingMultiplier/index.js
8653
+ var require_votingMultiplier = __commonJS({
8654
+ "src/votingMultiplier/index.js"(exports2, module2) {
8655
+ var { Contract, Interface, getAddress } = require("ethers");
8656
+ var ABI = require_abi();
8657
+ var { SageSDKError, CODES } = require_errors();
8658
+ function normaliseAddress(address, label) {
8659
+ if (!address) throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
8660
+ try {
8661
+ return getAddress(address);
8662
+ } catch (err) {
8663
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
8664
+ }
8665
+ }
8666
+ function toBigInt(value, label) {
8667
+ if (value === void 0 || value === null) {
8668
+ throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
8669
+ }
8670
+ try {
8671
+ return BigInt(value.toString());
8672
+ } catch (err) {
8673
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
8674
+ }
8675
+ }
8676
+ function getNftContract(provider, nft) {
8677
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
8678
+ const addr = normaliseAddress(nft, "nft");
8679
+ return new Contract(addr, ABI.VotingMultiplierNFT, provider);
8680
+ }
8681
+ function getWrapperContract(provider, wrapper) {
8682
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
8683
+ const addr = normaliseAddress(wrapper, "wrapper");
8684
+ return new Contract(addr, ABI.MultipliedVotes, provider);
8685
+ }
8686
+ async function getTier({ provider, nft, tierId }) {
8687
+ const c = getNftContract(provider, nft);
8688
+ const id2 = toBigInt(tierId, "tierId");
8689
+ let tier;
8690
+ if (typeof c.getTier === "function") {
8691
+ tier = await c.getTier(id2);
8692
+ } else {
8693
+ tier = await c.tiers(id2);
8694
+ }
8695
+ const name = String(tier.name ?? tier[0]);
8696
+ const multiplier = BigInt((tier.multiplier ?? tier[1]).toString());
8697
+ const maxSupply = BigInt((tier.maxSupply ?? tier[2]).toString());
8698
+ const minted = BigInt((tier.minted ?? tier[3]).toString());
8699
+ const price = BigInt((tier.price ?? tier[4]).toString());
8700
+ const dao = getAddress(tier.dao ?? tier[5]);
8701
+ return { name, multiplier, maxSupply, minted, price, dao };
8702
+ }
8703
+ async function getTierCount({ provider, nft }) {
8704
+ const c = getNftContract(provider, nft);
8705
+ const count = await c.tierCount();
8706
+ return BigInt(count.toString());
8707
+ }
8708
+ function buildCreateTierTx({ nft, dao, name, multiplier, maxSupply, price }) {
8709
+ const addr = normaliseAddress(nft, "nft");
8710
+ const iface = new Interface(ABI.VotingMultiplierNFT);
8711
+ const data = iface.encodeFunctionData("createTier", [
8712
+ normaliseAddress(dao, "dao"),
8713
+ String(name ?? ""),
8714
+ toBigInt(multiplier, "multiplier"),
8715
+ toBigInt(maxSupply, "maxSupply"),
8716
+ toBigInt(price, "price")
8717
+ ]);
8718
+ return { to: addr, data, value: 0n };
8719
+ }
8720
+ function buildMintTx({ nft, to, tierId, uri }) {
8721
+ const addr = normaliseAddress(nft, "nft");
8722
+ const iface = new Interface(ABI.VotingMultiplierNFT);
8723
+ const data = iface.encodeFunctionData("mint", [
8724
+ normaliseAddress(to, "to"),
8725
+ toBigInt(tierId, "tierId"),
8726
+ String(uri ?? "")
8727
+ ]);
8728
+ return { to: addr, data, value: 0n };
8729
+ }
8730
+ function buildPublicMintTx({ nft, tierId, uri, value }) {
8731
+ const addr = normaliseAddress(nft, "nft");
8732
+ const iface = new Interface(ABI.VotingMultiplierNFT);
8733
+ const data = iface.encodeFunctionData("publicMint", [
8734
+ toBigInt(tierId, "tierId"),
8735
+ String(uri ?? "")
8736
+ ]);
8737
+ return { to: addr, data, value: toBigInt(value ?? 0n, "value") };
8738
+ }
8739
+ async function getMultiplier({ provider, nft, account, dao }) {
8740
+ const c = getNftContract(provider, nft);
8741
+ const res = await c.getMultiplier(normaliseAddress(account, "account"), normaliseAddress(dao, "dao"));
8742
+ return BigInt(res.toString());
8743
+ }
8744
+ async function getPastMultiplier({ provider, nft, account, dao, timepoint }) {
8745
+ const c = getNftContract(provider, nft);
8746
+ const res = await c.getPastMultiplier(
8747
+ normaliseAddress(account, "account"),
8748
+ normaliseAddress(dao, "dao"),
8749
+ toBigInt(timepoint, "timepoint")
8750
+ );
8751
+ return BigInt(res.toString());
8752
+ }
8753
+ async function getTokenMultiplier({ provider, nft, tokenId }) {
8754
+ const c = getNftContract(provider, nft);
8755
+ const res = await c.getTokenMultiplier(toBigInt(tokenId, "tokenId"));
8756
+ return BigInt(res.toString());
8757
+ }
8758
+ async function getTokenDAO({ provider, nft, tokenId }) {
8759
+ const c = getNftContract(provider, nft);
8760
+ const res = await c.getTokenDAO(toBigInt(tokenId, "tokenId"));
8761
+ return getAddress(res);
8762
+ }
8763
+ async function getTokenInfo({ provider, nft, tokenId }) {
8764
+ const c = getNftContract(provider, nft);
8765
+ const id2 = toBigInt(tokenId, "tokenId");
8766
+ const info = await c.getTokenInfo(id2);
8767
+ const owner = getAddress(info.owner ?? info[0]);
8768
+ const tierId = BigInt((info.tierId ?? info[1]).toString());
8769
+ const multiplier = BigInt((info.multiplier ?? info[2]).toString());
8770
+ const uri = String(info.uri ?? info[3]);
8771
+ return { owner, tierId, multiplier, uri };
8772
+ }
8773
+ async function getVotes({ provider, wrapper, account }) {
8774
+ const c = getWrapperContract(provider, wrapper);
8775
+ const res = await c.getVotes(normaliseAddress(account, "account"));
8776
+ return BigInt(res.toString());
8777
+ }
8778
+ async function getPastVotes({ provider, wrapper, account, timepoint }) {
8779
+ const c = getWrapperContract(provider, wrapper);
8780
+ const res = await c.getPastVotes(
8781
+ normaliseAddress(account, "account"),
8782
+ toBigInt(timepoint, "timepoint")
8783
+ );
8784
+ return BigInt(res.toString());
8785
+ }
8786
+ async function getVotingBreakdown({ provider, wrapper, account }) {
8787
+ const c = getWrapperContract(provider, wrapper);
8788
+ const [baseVotes, multiplier, effectiveVotes] = await c.getVotingBreakdown(normaliseAddress(account, "account"));
8789
+ return {
8790
+ baseVotes: BigInt(baseVotes.toString()),
8791
+ multiplier: BigInt(multiplier.toString()),
8792
+ effectiveVotes: BigInt(effectiveVotes.toString())
8793
+ };
8794
+ }
8795
+ async function getPastVotingBreakdown({ provider, wrapper, account, timepoint }) {
8796
+ const c = getWrapperContract(provider, wrapper);
8797
+ const [baseVotes, multiplier, effectiveVotes] = await c.getPastVotingBreakdown(
8798
+ normaliseAddress(account, "account"),
8799
+ toBigInt(timepoint, "timepoint")
8800
+ );
8801
+ return {
8802
+ baseVotes: BigInt(baseVotes.toString()),
8803
+ multiplier: BigInt(multiplier.toString()),
8804
+ effectiveVotes: BigInt(effectiveVotes.toString())
8805
+ };
8806
+ }
8807
+ async function hasMultiplierBonus({ provider, wrapper, account }) {
8808
+ const c = getWrapperContract(provider, wrapper);
8809
+ const res = await c.hasMultiplierBonus(normaliseAddress(account, "account"));
8810
+ return !!res;
8811
+ }
8812
+ module2.exports = {
8813
+ // Tier management
8814
+ getTier,
8815
+ getTierCount,
8816
+ buildCreateTierTx,
8817
+ // Minting
8818
+ buildMintTx,
8819
+ buildPublicMintTx,
8820
+ // Multiplier queries
8821
+ getMultiplier,
8822
+ getPastMultiplier,
8823
+ getTokenMultiplier,
8824
+ getTokenDAO,
8825
+ getTokenInfo,
8826
+ // Wrapper queries
8827
+ getVotes,
8828
+ getPastVotes,
8829
+ getVotingBreakdown,
8830
+ getPastVotingBreakdown,
8831
+ hasMultiplierBonus
8832
+ };
8833
+ }
8834
+ });
8835
+
8836
+ // src/auction/index.js
8837
+ var require_auction = __commonJS({
8838
+ "src/auction/index.js"(exports2, module2) {
8839
+ var { Contract, Interface, getAddress } = require("ethers");
8840
+ var ABI = require_abi();
8841
+ var { SageSDKError, CODES } = require_errors();
8842
+ function normaliseAddress(address, label) {
8843
+ if (!address) throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
8844
+ try {
8845
+ return getAddress(address);
8846
+ } catch (err) {
8847
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
8848
+ }
8849
+ }
8850
+ function toBigInt(value, label) {
8851
+ if (value === void 0 || value === null) {
8852
+ throw new SageSDKError(CODES.INVALID_ARGS, `${label} required`);
8853
+ }
8854
+ try {
8855
+ return BigInt(value.toString());
8856
+ } catch (err) {
8857
+ throw new SageSDKError(CODES.INVALID_ARGS, `invalid ${label}`, { cause: err });
8858
+ }
8859
+ }
8860
+ function getAuctionContract(provider, auctionHouse) {
8861
+ if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
8862
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8863
+ return new Contract(addr, ABI.SageAuctionHouse, provider);
8864
+ }
8865
+ async function getAuction({ provider, auctionHouse }) {
8866
+ const c = getAuctionContract(provider, auctionHouse);
8867
+ const res = await c.auction();
8868
+ const nftId = BigInt(res.nftId.toString());
8869
+ const amount = BigInt(res.amount.toString());
8870
+ const startTime = BigInt(res.startTime.toString());
8871
+ const endTime = BigInt(res.endTime.toString());
8872
+ const bidder = getAddress(res.bidder);
8873
+ const settled = !!res.settled;
8874
+ return { nftId, amount, startTime, endTime, bidder, settled };
8875
+ }
8876
+ async function getConfig({ provider, auctionHouse }) {
8877
+ const c = getAuctionContract(provider, auctionHouse);
8878
+ const [nft, treasury2, weth, timeBuffer, reservePrice, minBidIncrementPercentage, duration, mintTierId, defaultTokenURI, paused, owner] = await Promise.all([
8879
+ c.nft(),
8880
+ c.treasury(),
8881
+ c.weth(),
8882
+ c.timeBuffer(),
8883
+ c.reservePrice(),
8884
+ c.minBidIncrementPercentage(),
8885
+ c.duration(),
8886
+ c.mintTierId(),
8887
+ c.defaultTokenURI(),
8888
+ c.paused(),
8889
+ c.owner()
8890
+ ]);
8891
+ return {
8892
+ nft: getAddress(nft),
8893
+ treasury: getAddress(treasury2),
8894
+ weth: getAddress(weth),
8895
+ timeBuffer: BigInt(timeBuffer.toString()),
8896
+ reservePrice: BigInt(reservePrice.toString()),
8897
+ minBidIncrementPercentage: BigInt(minBidIncrementPercentage.toString()),
8898
+ duration: BigInt(duration.toString()),
8899
+ mintTierId: BigInt(mintTierId.toString()),
8900
+ defaultTokenURI: String(defaultTokenURI),
8901
+ paused: !!paused,
8902
+ owner: getAddress(owner)
8903
+ };
8904
+ }
8905
+ function buildCreateBidTx({ auctionHouse, nftId, value }) {
8906
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8907
+ const iface = new Interface(ABI.SageAuctionHouse);
8908
+ const data = iface.encodeFunctionData("createBid", [toBigInt(nftId, "nftId")]);
8909
+ return { to: addr, data, value: toBigInt(value, "value") };
8910
+ }
8911
+ function buildSettleAndCreateTx({ auctionHouse }) {
8912
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8913
+ const iface = new Interface(ABI.SageAuctionHouse);
8914
+ const data = iface.encodeFunctionData("settleCurrentAndCreateNewAuction", []);
8915
+ return { to: addr, data, value: 0n };
8916
+ }
8917
+ function buildSettleTx({ auctionHouse }) {
8918
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8919
+ const iface = new Interface(ABI.SageAuctionHouse);
8920
+ const data = iface.encodeFunctionData("settleAuction", []);
8921
+ return { to: addr, data, value: 0n };
8922
+ }
8923
+ function buildCreateAuctionTx({ auctionHouse }) {
8924
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8925
+ const iface = new Interface(ABI.SageAuctionHouse);
8926
+ const data = iface.encodeFunctionData("createAuction", []);
8927
+ return { to: addr, data, value: 0n };
8928
+ }
8929
+ function buildPauseTx({ auctionHouse }) {
8930
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8931
+ const iface = new Interface(ABI.SageAuctionHouse);
8932
+ const data = iface.encodeFunctionData("pause", []);
8933
+ return { to: addr, data, value: 0n };
8934
+ }
8935
+ function buildUnpauseTx({ auctionHouse }) {
8936
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8937
+ const iface = new Interface(ABI.SageAuctionHouse);
8938
+ const data = iface.encodeFunctionData("unpause", []);
8939
+ return { to: addr, data, value: 0n };
8940
+ }
8941
+ function buildSetTimeBufferTx({ auctionHouse, timeBuffer }) {
8942
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8943
+ const iface = new Interface(ABI.SageAuctionHouse);
8944
+ const data = iface.encodeFunctionData("setTimeBuffer", [toBigInt(timeBuffer, "timeBuffer")]);
8945
+ return { to: addr, data, value: 0n };
8946
+ }
8947
+ function buildSetReservePriceTx({ auctionHouse, reservePrice }) {
8948
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8949
+ const iface = new Interface(ABI.SageAuctionHouse);
8950
+ const data = iface.encodeFunctionData("setReservePrice", [toBigInt(reservePrice, "reservePrice")]);
8951
+ return { to: addr, data, value: 0n };
8952
+ }
8953
+ function buildSetMinBidIncrementTx({ auctionHouse, percentage }) {
8954
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8955
+ const iface = new Interface(ABI.SageAuctionHouse);
8956
+ const data = iface.encodeFunctionData("setMinBidIncrementPercentage", [toBigInt(percentage, "percentage")]);
8957
+ return { to: addr, data, value: 0n };
8958
+ }
8959
+ function buildSetDurationTx({ auctionHouse, duration }) {
8960
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8961
+ const iface = new Interface(ABI.SageAuctionHouse);
8962
+ const data = iface.encodeFunctionData("setDuration", [toBigInt(duration, "duration")]);
8963
+ return { to: addr, data, value: 0n };
8964
+ }
8965
+ function buildSetMintTierIdTx({ auctionHouse, tierId }) {
8966
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8967
+ const iface = new Interface(ABI.SageAuctionHouse);
8968
+ const data = iface.encodeFunctionData("setMintTierId", [toBigInt(tierId, "tierId")]);
8969
+ return { to: addr, data, value: 0n };
8970
+ }
8971
+ function buildSetDefaultTokenURITx({ auctionHouse, uri }) {
8972
+ const addr = normaliseAddress(auctionHouse, "auctionHouse");
8973
+ const iface = new Interface(ABI.SageAuctionHouse);
8974
+ const data = iface.encodeFunctionData("setDefaultTokenURI", [String(uri ?? "")]);
8975
+ return { to: addr, data, value: 0n };
8976
+ }
8977
+ module2.exports = {
8978
+ getAuction,
8979
+ getConfig,
8980
+ buildCreateBidTx,
8981
+ buildSettleAndCreateTx,
8982
+ buildSettleTx,
8983
+ buildCreateAuctionTx,
8984
+ buildPauseTx,
8985
+ buildUnpauseTx,
8986
+ buildSetTimeBufferTx,
8987
+ buildSetReservePriceTx,
8988
+ buildSetMinBidIncrementTx,
8989
+ buildSetDurationTx,
8990
+ buildSetMintTierIdTx,
8991
+ buildSetDefaultTokenURITx
7098
8992
  };
7099
8993
  }
7100
8994
  });
@@ -8962,8 +10856,8 @@ var require_doppler = __commonJS({
8962
10856
  return res;
8963
10857
  };
8964
10858
  module2.exports.getStaticPoolInfo = async function getStaticPoolInfo(sdk, poolAddress) {
8965
- const auction = await sdk.getStaticAuction(poolAddress);
8966
- return auction.getPoolInfo();
10859
+ const auction2 = await sdk.getStaticAuction(poolAddress);
10860
+ return auction2.getPoolInfo();
8967
10861
  };
8968
10862
  module2.exports.quoteV3ExactIn = async function quoteV3ExactIn(sdk, { tokenIn, tokenOut, amountIn, fee, sqrtPriceLimitX96 = 0n }) {
8969
10863
  return sdk.quoter.quoteExactInputV3({ tokenIn, tokenOut, amountIn, fee, sqrtPriceLimitX96 });
@@ -8986,8 +10880,8 @@ var require_doppler = __commonJS({
8986
10880
  return { deposited: needed, hash };
8987
10881
  };
8988
10882
  module2.exports.getDynamicHookInfo = async function getDynamicHookInfo(sdk, hookAddress) {
8989
- const auction = await sdk.getDynamicAuction(hookAddress);
8990
- return auction.getHookInfo();
10883
+ const auction2 = await sdk.getDynamicAuction(hookAddress);
10884
+ return auction2.getHookInfo();
8991
10885
  };
8992
10886
  module2.exports.quoteV4ExactIn = async function quoteV4ExactIn(sdk, { poolKey, zeroForOne, exactAmount, hookData }) {
8993
10887
  return sdk.quoter.quoteExactInputV4({ poolKey, zeroForOne, exactAmount, hookData });
@@ -9904,6 +11798,885 @@ var require_client2 = __commonJS({
9904
11798
  }
9905
11799
  });
9906
11800
 
11801
+ // src/clients/discovery-client.js
11802
+ var require_discovery_client = __commonJS({
11803
+ "src/clients/discovery-client.js"(exports2, module2) {
11804
+ var DiscoveryClient2 = class {
11805
+ /**
11806
+ * @param {string} baseUrl - Base URL of the discovery API
11807
+ * @param {object} [options] - Client options
11808
+ * @param {number} [options.timeout=10000] - Request timeout in milliseconds
11809
+ * @param {Record<string, string>} [options.headers] - Custom headers
11810
+ */
11811
+ constructor(baseUrl, options = {}) {
11812
+ this.baseUrl = baseUrl.replace(/\/$/, "");
11813
+ this.timeout = options.timeout || 1e4;
11814
+ this.headers = options.headers || {};
11815
+ }
11816
+ /**
11817
+ * Search prompts with keyword matching and trend ranking
11818
+ * @param {string} query - Search query
11819
+ * @param {object} [options] - Search options
11820
+ * @param {string} [options.category] - Filter by category
11821
+ * @param {string[]} [options.tags] - Filter by tags
11822
+ * @param {string} [options.author] - Filter by author
11823
+ * @param {number} [options.limit] - Max results to return
11824
+ * @param {number} [options.offset] - Number of results to skip
11825
+ * @param {boolean} [options.useVector] - Use vector search
11826
+ * @returns {Promise<{results: Array, total: number}>}
11827
+ */
11828
+ async search(query, options = {}) {
11829
+ const params = new URLSearchParams();
11830
+ if (query) params.set("q", query);
11831
+ if (options.category) params.set("category", options.category);
11832
+ if (options.author) params.set("author", options.author);
11833
+ if (options.tags) {
11834
+ options.tags.forEach((tag) => params.append("tags", tag));
11835
+ }
11836
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11837
+ if (options.offset !== void 0) params.set("offset", String(options.offset));
11838
+ if (options.useVector !== void 0) params.set("useVector", String(options.useVector));
11839
+ return this._get(`/discover/search?${params}`);
11840
+ }
11841
+ /**
11842
+ * Get trending prompts by time window
11843
+ * @param {object} [options] - Trending options
11844
+ * @param {'1h'|'24h'|'7d'|'30d'|'all'} [options.window] - Time window
11845
+ * @param {string} [options.category] - Filter by category
11846
+ * @param {number} [options.limit] - Max results to return
11847
+ * @param {number} [options.offset] - Number of results to skip
11848
+ * @returns {Promise<{results: Array}>}
11849
+ */
11850
+ async trending(options = {}) {
11851
+ const params = new URLSearchParams();
11852
+ if (options.window) params.set("window", options.window);
11853
+ if (options.category) params.set("category", options.category);
11854
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11855
+ if (options.offset !== void 0) params.set("offset", String(options.offset));
11856
+ return this._get(`/discover/trending?${params}`);
11857
+ }
11858
+ /**
11859
+ * Get trending prompts (alias for /trends/top endpoint)
11860
+ * @param {object} [options] - Trending options
11861
+ * @param {'1h'|'24h'|'7d'|'30d'|'all'} [options.window] - Time window
11862
+ * @param {number} [options.limit] - Max results to return
11863
+ * @param {number} [options.offset] - Number of results to skip
11864
+ * @returns {Promise<{results: Array}>}
11865
+ */
11866
+ async trendingTop(options = {}) {
11867
+ const params = new URLSearchParams();
11868
+ if (options.window) params.set("window", options.window);
11869
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11870
+ if (options.offset !== void 0) params.set("offset", String(options.offset));
11871
+ return this._get(`/trends/top?${params}`);
11872
+ }
11873
+ /**
11874
+ * Find prompts matching user preferences
11875
+ *
11876
+ * Note: This endpoint is not yet implemented in the backend.
11877
+ * This is a placeholder for future implementation.
11878
+ * @param {object} preferences - User preferences
11879
+ * @param {string[]} [preferences.recentPrompts] - Recent prompt CIDs
11880
+ * @param {string[]} [preferences.preferredTags] - Preferred tags
11881
+ * @param {string[]} [preferences.preferredCategories] - Preferred categories
11882
+ * @param {string[]} [preferences.excludeAuthors] - Authors to exclude
11883
+ * @param {number} [preferences.limit] - Max results
11884
+ * @param {boolean} [preferences.diversify] - Diversify results
11885
+ * @returns {Promise<{results: Array, total: number}>}
11886
+ */
11887
+ async match(preferences) {
11888
+ return this._post("/discover/match", preferences);
11889
+ }
11890
+ /**
11891
+ * Find prompts similar to a given prompt
11892
+ * @param {string} cid - Prompt CID to find similar prompts for
11893
+ * @param {object} [options] - Similar options
11894
+ * @param {number} [options.limit] - Max results to return
11895
+ * @param {'vector'|'keyword'|'hybrid'} [options.method] - Similarity method
11896
+ * @returns {Promise<{similar: Array}>}
11897
+ */
11898
+ async similar(cid, options = {}) {
11899
+ const params = new URLSearchParams();
11900
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11901
+ if (options.method) params.set("method", options.method);
11902
+ return this._get(`/discover/similar/${cid}?${params}`);
11903
+ }
11904
+ /**
11905
+ * Get popular tags with optional clustering
11906
+ * @param {object} [options] - Tags options
11907
+ * @param {number} [options.limit] - Max tags to return
11908
+ * @param {string} [options.category] - Filter by category
11909
+ * @param {boolean} [options.clusters] - Enable tag clustering
11910
+ * @returns {Promise<{tags: Array}>}
11911
+ */
11912
+ async tags(options = {}) {
11913
+ const params = new URLSearchParams();
11914
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11915
+ if (options.category) params.set("category", options.category);
11916
+ if (options.clusters !== void 0) params.set("clusters", String(options.clusters));
11917
+ return this._get(`/discover/tags?${params}`);
11918
+ }
11919
+ /**
11920
+ * Get category statistics
11921
+ *
11922
+ * Note: This endpoint is not yet implemented in the backend.
11923
+ * This is a placeholder for future implementation.
11924
+ * @returns {Promise<{categories: Array}>}
11925
+ */
11926
+ async categories() {
11927
+ return this._get("/discover/categories");
11928
+ }
11929
+ /**
11930
+ * Get prompts by tag
11931
+ * @param {string} tag - Tag to search for
11932
+ * @param {number} [limit] - Max results to return
11933
+ * @returns {Promise<{results: Array}>}
11934
+ */
11935
+ async promptsByTag(tag, limit) {
11936
+ const params = new URLSearchParams();
11937
+ if (limit !== void 0) params.set("limit", String(limit));
11938
+ const encodedTag = encodeURIComponent(tag);
11939
+ return this._get(`/discover/by-tag/${encodedTag}?${params}`);
11940
+ }
11941
+ /**
11942
+ * Get index statistics
11943
+ * @returns {Promise<{totalPrompts: number, totalTags: number, avgTrendScore: number}>}
11944
+ */
11945
+ async stats() {
11946
+ return this._get("/discover/stats");
11947
+ }
11948
+ /**
11949
+ * Get trend signals for a specific CID
11950
+ * @param {string} cid - Prompt CID
11951
+ * @returns {Promise<{usageCount: number, forkCount: number, purchaseCount: number, uniqueBuyers: number, governanceVotes: number, lastActivityAt: number}>}
11952
+ */
11953
+ async trendSignals(cid) {
11954
+ return this._get(`/trends/signals/${cid}`);
11955
+ }
11956
+ /**
11957
+ * Get trend history for a specific CID
11958
+ * @param {string} cid - Prompt CID
11959
+ * @param {object} [options] - History options
11960
+ * @param {number} [options.limit] - Max history entries
11961
+ * @param {number} [options.since] - Timestamp to start from
11962
+ * @returns {Promise<{history: Array}>}
11963
+ */
11964
+ async trendHistory(cid, options = {}) {
11965
+ const params = new URLSearchParams();
11966
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
11967
+ if (options.since !== void 0) params.set("since", String(options.since));
11968
+ return this._get(`/trends/history/${cid}?${params}`);
11969
+ }
11970
+ /**
11971
+ * Get trend statistics
11972
+ * @returns {Promise<{totalTracked: number, avgScore: number, maxScore: number, recentlyActive: number}>}
11973
+ */
11974
+ async trendStats() {
11975
+ return this._get("/trends/stats");
11976
+ }
11977
+ /**
11978
+ * Record a usage event for a prompt (requires authentication)
11979
+ * @param {string} cid - Prompt CID
11980
+ * @returns {Promise<{ok: boolean}>}
11981
+ */
11982
+ async recordUsage(cid) {
11983
+ return this._post("/trends/usage", { cid });
11984
+ }
11985
+ // Private fetch helpers
11986
+ /**
11987
+ * Perform a GET request
11988
+ * @private
11989
+ * @param {string} path - API path
11990
+ * @returns {Promise<any>}
11991
+ */
11992
+ async _get(path2) {
11993
+ const controller = new AbortController();
11994
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
11995
+ try {
11996
+ const response = await fetch(`${this.baseUrl}${path2}`, {
11997
+ method: "GET",
11998
+ headers: {
11999
+ "Accept": "application/json",
12000
+ ...this.headers
12001
+ },
12002
+ signal: controller.signal
12003
+ });
12004
+ clearTimeout(timeoutId);
12005
+ if (!response.ok) {
12006
+ const errorBody = await response.text().catch(() => "Unknown error");
12007
+ throw new Error(`HTTP ${response.status}: ${errorBody}`);
12008
+ }
12009
+ return await response.json();
12010
+ } catch (error) {
12011
+ clearTimeout(timeoutId);
12012
+ if (error.name === "AbortError") {
12013
+ throw new Error(`Request timeout after ${this.timeout}ms`);
12014
+ }
12015
+ throw error;
12016
+ }
12017
+ }
12018
+ /**
12019
+ * Perform a POST request
12020
+ * @private
12021
+ * @param {string} path - API path
12022
+ * @param {any} body - Request body
12023
+ * @returns {Promise<any>}
12024
+ */
12025
+ async _post(path2, body) {
12026
+ const controller = new AbortController();
12027
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
12028
+ try {
12029
+ const response = await fetch(`${this.baseUrl}${path2}`, {
12030
+ method: "POST",
12031
+ headers: {
12032
+ "Accept": "application/json",
12033
+ "Content-Type": "application/json",
12034
+ ...this.headers
12035
+ },
12036
+ body: JSON.stringify(body),
12037
+ signal: controller.signal
12038
+ });
12039
+ clearTimeout(timeoutId);
12040
+ if (!response.ok) {
12041
+ const errorBody = await response.text().catch(() => "Unknown error");
12042
+ throw new Error(`HTTP ${response.status}: ${errorBody}`);
12043
+ }
12044
+ return await response.json();
12045
+ } catch (error) {
12046
+ clearTimeout(timeoutId);
12047
+ if (error.name === "AbortError") {
12048
+ throw new Error(`Request timeout after ${this.timeout}ms`);
12049
+ }
12050
+ throw error;
12051
+ }
12052
+ }
12053
+ };
12054
+ module2.exports = { DiscoveryClient: DiscoveryClient2 };
12055
+ }
12056
+ });
12057
+
12058
+ // src/clients/git-storage-client.js
12059
+ var require_git_storage_client = __commonJS({
12060
+ "src/clients/git-storage-client.js"(exports2, module2) {
12061
+ var GitStorageClient2 = class {
12062
+ /**
12063
+ * @param {string} baseUrl - Base URL of the API (e.g., 'https://api.sageprotocol.io')
12064
+ * @param {Object} [options] - Client options
12065
+ * @param {number} [options.timeout=30000] - Request timeout in milliseconds
12066
+ * @param {Record<string, string>} [options.headers] - Custom headers
12067
+ * @param {AuthProvider} [options.signer] - Ethers signer for authenticated requests
12068
+ * @param {() => Promise<{address: string, signature: string, nonce: string}>} [options.getAuth] - Custom auth provider
12069
+ * @param {string} [options.token] - Bearer token for authentication
12070
+ */
12071
+ constructor(baseUrl, options = {}) {
12072
+ this.baseUrl = baseUrl.replace(/\/$/, "");
12073
+ this.timeout = options.timeout || 3e4;
12074
+ this.headers = options.headers || {};
12075
+ this.signer = options.signer || null;
12076
+ this.getAuth = options.getAuth || null;
12077
+ this.token = options.token || null;
12078
+ this._authCache = null;
12079
+ this._authCacheExpiry = 0;
12080
+ }
12081
+ // =========================================================================
12082
+ // Library Management
12083
+ // =========================================================================
12084
+ /**
12085
+ * Create a new library
12086
+ * @param {string} subdao - SubDAO address
12087
+ * @param {string} name - Library name
12088
+ * @param {Object} [options] - Creation options
12089
+ * @param {string} [options.description] - Library description
12090
+ * @param {'public'|'private'} [options.visibility='public'] - Library visibility
12091
+ * @returns {Promise<LibraryMetadata>}
12092
+ */
12093
+ async createLibrary(subdao2, name, options = {}) {
12094
+ return this._post("/git/libraries", {
12095
+ subdao: subdao2,
12096
+ name,
12097
+ description: options.description,
12098
+ visibility: options.visibility || "public"
12099
+ }, { auth: true });
12100
+ }
12101
+ /**
12102
+ * Get library metadata
12103
+ * @param {string} subdao - SubDAO address
12104
+ * @returns {Promise<LibraryMetadata>}
12105
+ */
12106
+ async getLibrary(subdao2) {
12107
+ return this._get(`/git/libraries/${encodeURIComponent(subdao2)}`);
12108
+ }
12109
+ /**
12110
+ * List all libraries
12111
+ * @param {Object} [options] - List options
12112
+ * @param {number} [options.limit=50] - Max results to return
12113
+ * @param {string} [options.cursor] - Pagination cursor
12114
+ * @returns {Promise<{libraries: LibraryMetadata[], cursor?: string}>}
12115
+ */
12116
+ async listLibraries(options = {}) {
12117
+ const params = new URLSearchParams();
12118
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
12119
+ if (options.cursor) params.set("cursor", options.cursor);
12120
+ const queryString = params.toString();
12121
+ return this._get(`/git/libraries${queryString ? "?" + queryString : ""}`);
12122
+ }
12123
+ /**
12124
+ * Delete a library (admin only)
12125
+ * @param {string} subdao - SubDAO address
12126
+ * @returns {Promise<{ok: boolean}>}
12127
+ */
12128
+ async deleteLibrary(subdao2) {
12129
+ return this._delete(`/git/libraries/${encodeURIComponent(subdao2)}`, { auth: true });
12130
+ }
12131
+ // =========================================================================
12132
+ // Git Object Operations
12133
+ // =========================================================================
12134
+ /**
12135
+ * Store git objects (batch)
12136
+ * @param {string} subdao - SubDAO address
12137
+ * @param {GitObject[]} objects - Objects to store
12138
+ * @returns {Promise<{stored: number}>}
12139
+ */
12140
+ async putObjects(subdao2, objects) {
12141
+ return this._post(`/git/${encodeURIComponent(subdao2)}/objects`, { objects }, { auth: true });
12142
+ }
12143
+ /**
12144
+ * Get a single git object
12145
+ * @param {string} subdao - SubDAO address
12146
+ * @param {string} oid - Object ID
12147
+ * @returns {Promise<GitObject>}
12148
+ */
12149
+ async getObject(subdao2, oid) {
12150
+ return this._get(`/git/${encodeURIComponent(subdao2)}/objects/${oid}`);
12151
+ }
12152
+ /**
12153
+ * Get multiple git objects
12154
+ * @param {string} subdao - SubDAO address
12155
+ * @param {string[]} oids - Object IDs
12156
+ * @returns {Promise<{objects: GitObject[]}>}
12157
+ */
12158
+ async getObjects(subdao2, oids) {
12159
+ return this._get(`/git/${encodeURIComponent(subdao2)}/objects?oids=${oids.join(",")}`);
12160
+ }
12161
+ // =========================================================================
12162
+ // Reference Operations
12163
+ // =========================================================================
12164
+ /**
12165
+ * List all refs
12166
+ * @param {string} subdao - SubDAO address
12167
+ * @returns {Promise<{refs: GitRef[]}>}
12168
+ */
12169
+ async listRefs(subdao2) {
12170
+ return this._get(`/git/${encodeURIComponent(subdao2)}/refs`);
12171
+ }
12172
+ /**
12173
+ * Get a specific ref
12174
+ * @param {string} subdao - SubDAO address
12175
+ * @param {string} refName - Reference name (e.g., 'refs/heads/main')
12176
+ * @returns {Promise<GitRef>}
12177
+ */
12178
+ async getRef(subdao2, refName) {
12179
+ return this._get(`/git/${encodeURIComponent(subdao2)}/refs/${encodeURIComponent(refName)}`);
12180
+ }
12181
+ /**
12182
+ * Update a ref
12183
+ * @param {string} subdao - SubDAO address
12184
+ * @param {string} refName - Reference name
12185
+ * @param {string} oid - New object ID
12186
+ * @param {Object} [options] - Update options
12187
+ * @param {string} [options.oldOid] - Expected current OID (for optimistic concurrency)
12188
+ * @returns {Promise<{ok: boolean}>}
12189
+ */
12190
+ async updateRef(subdao2, refName, oid, options = {}) {
12191
+ return this._post(
12192
+ `/git/${encodeURIComponent(subdao2)}/refs/${encodeURIComponent(refName)}`,
12193
+ { oid, oldOid: options.oldOid },
12194
+ { auth: true }
12195
+ );
12196
+ }
12197
+ // =========================================================================
12198
+ // Sync Operations
12199
+ // =========================================================================
12200
+ /**
12201
+ * Push changes to library
12202
+ * @param {string} subdao - SubDAO address
12203
+ * @param {Object} payload - Push payload
12204
+ * @param {GitObject[]} payload.objects - Objects to push
12205
+ * @param {Record<string, string>} payload.refs - Ref updates (name -> oid)
12206
+ * @param {string} payload.message - Commit message
12207
+ * @returns {Promise<PushResult>}
12208
+ */
12209
+ async push(subdao2, payload) {
12210
+ return this._post(`/git/${encodeURIComponent(subdao2)}/push`, payload, { auth: true });
12211
+ }
12212
+ /**
12213
+ * Clone a library (get all objects and refs)
12214
+ * @param {string} subdao - SubDAO address
12215
+ * @returns {Promise<{objects: GitObject[], refs: Record<string, string>, metadata: LibraryMetadata}>}
12216
+ */
12217
+ async clone(subdao2) {
12218
+ return this._get(`/git/${encodeURIComponent(subdao2)}/clone`);
12219
+ }
12220
+ /**
12221
+ * Fetch changes since a commit
12222
+ * @param {string} subdao - SubDAO address
12223
+ * @param {string} [since] - Commit OID to fetch since
12224
+ * @returns {Promise<{objects: GitObject[], refs: Record<string, string>}>}
12225
+ */
12226
+ async fetch(subdao2, since) {
12227
+ const params = since ? `?since=${since}` : "";
12228
+ return this._get(`/git/${encodeURIComponent(subdao2)}/fetch${params}`);
12229
+ }
12230
+ // =========================================================================
12231
+ // File Access
12232
+ // =========================================================================
12233
+ /**
12234
+ * Get commit history
12235
+ * @param {string} subdao - SubDAO address
12236
+ * @param {Object} [options] - History options
12237
+ * @param {string} [options.ref='refs/heads/main'] - Reference to get history from
12238
+ * @param {number} [options.limit=50] - Max commits to return
12239
+ * @returns {Promise<{commits: GitCommit[]}>}
12240
+ */
12241
+ async getHistory(subdao2, options = {}) {
12242
+ const params = new URLSearchParams();
12243
+ if (options.ref) params.set("ref", options.ref);
12244
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
12245
+ return this._get(`/git/${encodeURIComponent(subdao2)}/log?${params}`);
12246
+ }
12247
+ /**
12248
+ * Get directory listing
12249
+ * @param {string} subdao - SubDAO address
12250
+ * @param {string} ref - Reference (e.g., 'main')
12251
+ * @param {string} path - Directory path
12252
+ * @returns {Promise<{entries: Array}>}
12253
+ */
12254
+ async getTree(subdao2, ref, path2) {
12255
+ return this._get(
12256
+ `/git/${encodeURIComponent(subdao2)}/tree/${encodeURIComponent(ref)}/${encodeURIComponent(path2)}`
12257
+ );
12258
+ }
12259
+ /**
12260
+ * Get file contents
12261
+ * @param {string} subdao - SubDAO address
12262
+ * @param {string} ref - Reference (e.g., 'main')
12263
+ * @param {string} path - File path
12264
+ * @returns {Promise<{content: string}>}
12265
+ */
12266
+ async getBlob(subdao2, ref, path2) {
12267
+ return this._get(
12268
+ `/git/${encodeURIComponent(subdao2)}/blob/${encodeURIComponent(ref)}/${encodeURIComponent(path2)}`
12269
+ );
12270
+ }
12271
+ /**
12272
+ * Get file contents as string (convenience method)
12273
+ * @param {string} subdao - SubDAO address
12274
+ * @param {string} ref - Reference (e.g., 'main')
12275
+ * @param {string} path - File path
12276
+ * @returns {Promise<string>}
12277
+ */
12278
+ async getFile(subdao2, ref, path2) {
12279
+ const result = await this.getBlob(subdao2, ref, path2);
12280
+ return result.content;
12281
+ }
12282
+ // =========================================================================
12283
+ // Fork Operations
12284
+ // =========================================================================
12285
+ /**
12286
+ * Fork a library to a new SubDAO
12287
+ * @param {string} sourceSubdao - Source SubDAO address to fork from
12288
+ * @param {string} targetSubdao - Target SubDAO address for the fork
12289
+ * @param {Object} [options] - Fork options
12290
+ * @param {string} [options.targetName] - Name for the forked library
12291
+ * @param {string} [options.targetDescription] - Description for the forked library
12292
+ * @returns {Promise<{ok: boolean, forkedLibrary: string, sourceLibrary: string, commitsCopied: number}>}
12293
+ */
12294
+ async fork(sourceSubdao, targetSubdao, options = {}) {
12295
+ return this._post(`/git/libraries/${encodeURIComponent(sourceSubdao)}/fork`, {
12296
+ targetSubdao,
12297
+ targetName: options.targetName,
12298
+ targetDescription: options.targetDescription
12299
+ }, { auth: true });
12300
+ }
12301
+ /**
12302
+ * List forks of a library
12303
+ * @param {string} subdao - SubDAO address
12304
+ * @returns {Promise<{forks: Array, count: number}>}
12305
+ */
12306
+ async getForks(subdao2) {
12307
+ return this._get(`/git/libraries/${encodeURIComponent(subdao2)}/forks`);
12308
+ }
12309
+ /**
12310
+ * Get upstream fork info (for forked libraries)
12311
+ * @param {string} subdao - SubDAO address
12312
+ * @returns {Promise<{upstreamSubdao: string, upstreamCommit: string, forkedAt: number}>}
12313
+ */
12314
+ async getUpstream(subdao2) {
12315
+ return this._get(`/git/${encodeURIComponent(subdao2)}/upstream`);
12316
+ }
12317
+ /**
12318
+ * Check if a library is a fork
12319
+ * @param {string} subdao - SubDAO address
12320
+ * @returns {Promise<boolean>}
12321
+ */
12322
+ async isFork(subdao2) {
12323
+ try {
12324
+ await this.getUpstream(subdao2);
12325
+ return true;
12326
+ } catch (e) {
12327
+ if (e.message && e.message.includes("404")) {
12328
+ return false;
12329
+ }
12330
+ throw e;
12331
+ }
12332
+ }
12333
+ // =========================================================================
12334
+ // Collaborator Operations
12335
+ // =========================================================================
12336
+ /**
12337
+ * List collaborators
12338
+ * @param {string} subdao - SubDAO address
12339
+ * @returns {Promise<{collaborators: Collaborator[]}>}
12340
+ */
12341
+ async listCollaborators(subdao2) {
12342
+ return this._get(`/git/${encodeURIComponent(subdao2)}/collaborators`);
12343
+ }
12344
+ /**
12345
+ * Add a collaborator
12346
+ * @param {string} subdao - SubDAO address
12347
+ * @param {string} address - Collaborator wallet address
12348
+ * @param {'read'|'write'|'admin'} permission - Permission level
12349
+ * @returns {Promise<{ok: boolean}>}
12350
+ */
12351
+ async addCollaborator(subdao2, address, permission) {
12352
+ return this._post(`/git/${encodeURIComponent(subdao2)}/collaborators`, {
12353
+ address,
12354
+ permission
12355
+ }, { auth: true });
12356
+ }
12357
+ /**
12358
+ * Remove a collaborator
12359
+ * @param {string} subdao - SubDAO address
12360
+ * @param {string} address - Collaborator wallet address
12361
+ * @returns {Promise<{ok: boolean}>}
12362
+ */
12363
+ async removeCollaborator(subdao2, address) {
12364
+ return this._delete(
12365
+ `/git/${encodeURIComponent(subdao2)}/collaborators/${encodeURIComponent(address)}`,
12366
+ { auth: true }
12367
+ );
12368
+ }
12369
+ /**
12370
+ * Check permissions for an address
12371
+ * @param {string} subdao - SubDAO address
12372
+ * @param {string} address - Wallet address to check
12373
+ * @returns {Promise<{canRead: boolean, canWrite: boolean, isAdmin: boolean, permission?: string}>}
12374
+ */
12375
+ async getPermissions(subdao2, address) {
12376
+ return this._get(
12377
+ `/git/${encodeURIComponent(subdao2)}/collaborators/${encodeURIComponent(address)}/permissions`
12378
+ );
12379
+ }
12380
+ // =========================================================================
12381
+ // High-Level Convenience Methods
12382
+ // =========================================================================
12383
+ /**
12384
+ * Push a manifest file (convenience method)
12385
+ * @param {string} subdao - SubDAO address
12386
+ * @param {Object} manifest - Manifest object to push
12387
+ * @param {string} message - Commit message
12388
+ * @returns {Promise<PushResult>}
12389
+ */
12390
+ async pushManifest(subdao2, manifest, message) {
12391
+ const content = JSON.stringify(manifest, null, 2);
12392
+ const oid = await this._computeOid(content);
12393
+ const objects = [{
12394
+ oid,
12395
+ type: "blob",
12396
+ size: content.length,
12397
+ data: this._toBase64(content)
12398
+ }];
12399
+ const treeContent = JSON.stringify({ "manifest.json": oid });
12400
+ const treeOid = await this._computeOid(treeContent);
12401
+ objects.push({
12402
+ oid: treeOid,
12403
+ type: "tree",
12404
+ size: treeContent.length,
12405
+ data: this._toBase64(treeContent)
12406
+ });
12407
+ let parentOid = null;
12408
+ try {
12409
+ const currentRef = await this.getRef(subdao2, "refs/heads/main");
12410
+ parentOid = currentRef.oid;
12411
+ } catch (e) {
12412
+ }
12413
+ const author = await this._getAuthAddress();
12414
+ const commitContent = JSON.stringify({
12415
+ tree: treeOid,
12416
+ parent: parentOid,
12417
+ message,
12418
+ author: { address: author },
12419
+ timestamp: Date.now()
12420
+ });
12421
+ const commitOid = await this._computeOid(commitContent);
12422
+ objects.push({
12423
+ oid: commitOid,
12424
+ type: "commit",
12425
+ size: commitContent.length,
12426
+ data: this._toBase64(commitContent)
12427
+ });
12428
+ return this.push(subdao2, {
12429
+ objects,
12430
+ refs: { "refs/heads/main": commitOid },
12431
+ message
12432
+ });
12433
+ }
12434
+ /**
12435
+ * Get manifest from library (convenience method)
12436
+ * @param {string} subdao - SubDAO address
12437
+ * @param {string} [ref='main'] - Reference to get manifest from
12438
+ * @returns {Promise<Object>}
12439
+ */
12440
+ async getManifest(subdao2, ref = "main") {
12441
+ const content = await this.getFile(subdao2, ref, "manifest.json");
12442
+ return JSON.parse(content);
12443
+ }
12444
+ // =========================================================================
12445
+ // Private HTTP Methods
12446
+ // =========================================================================
12447
+ /**
12448
+ * Get authentication headers
12449
+ * @private
12450
+ * @returns {Promise<Record<string, string>>}
12451
+ */
12452
+ async _getAuthHeaders() {
12453
+ if (this._authCache && Date.now() < this._authCacheExpiry) {
12454
+ return this._authCache;
12455
+ }
12456
+ if (this.token) {
12457
+ const headers = { Authorization: `Bearer ${this.token}` };
12458
+ this._authCache = headers;
12459
+ this._authCacheExpiry = Date.now() + 36e5;
12460
+ return headers;
12461
+ }
12462
+ if (typeof this.getAuth === "function") {
12463
+ const auth = await this.getAuth();
12464
+ const headers = {
12465
+ "X-Wallet-Address": auth.address,
12466
+ "X-Wallet-Signature": auth.signature,
12467
+ "X-Wallet-Nonce": auth.nonce
12468
+ };
12469
+ this._authCache = headers;
12470
+ this._authCacheExpiry = Date.now() + 3e5;
12471
+ return headers;
12472
+ }
12473
+ if (this.signer) {
12474
+ const signer = typeof this.signer === "function" ? await this.signer() : this.signer;
12475
+ if (!signer) throw new Error("signer_unavailable");
12476
+ const address = await signer.getAddress();
12477
+ const challengeResponse = await this._post("/ipfs/auth/challenge", { address }, { auth: false });
12478
+ const { message, nonce } = challengeResponse;
12479
+ if (!message || !nonce) throw new Error("challenge_response_invalid");
12480
+ const signature = await signer.signMessage(message);
12481
+ const headers = {
12482
+ "X-Wallet-Address": address,
12483
+ "X-Wallet-Signature": signature,
12484
+ "X-Wallet-Nonce": nonce
12485
+ };
12486
+ this._authCache = headers;
12487
+ this._authCacheExpiry = Date.now() + 3e5;
12488
+ return headers;
12489
+ }
12490
+ return {};
12491
+ }
12492
+ /**
12493
+ * Get authenticated address
12494
+ * @private
12495
+ * @returns {Promise<string>}
12496
+ */
12497
+ async _getAuthAddress() {
12498
+ if (this.signer) {
12499
+ const signer = typeof this.signer === "function" ? await this.signer() : this.signer;
12500
+ return signer.getAddress();
12501
+ }
12502
+ if (typeof this.getAuth === "function") {
12503
+ const auth = await this.getAuth();
12504
+ return auth.address;
12505
+ }
12506
+ return "0x0000000000000000000000000000000000000000";
12507
+ }
12508
+ /**
12509
+ * Perform a GET request
12510
+ * @private
12511
+ * @param {string} path - API path
12512
+ * @param {Object} [options] - Request options
12513
+ * @param {boolean} [options.auth=false] - Whether to include auth headers
12514
+ * @returns {Promise<any>}
12515
+ */
12516
+ async _get(path2, options = {}) {
12517
+ const controller = new AbortController();
12518
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
12519
+ try {
12520
+ const authHeaders = options.auth ? await this._getAuthHeaders() : {};
12521
+ const response = await fetch(`${this.baseUrl}${path2}`, {
12522
+ method: "GET",
12523
+ headers: {
12524
+ Accept: "application/json",
12525
+ ...this.headers,
12526
+ ...authHeaders
12527
+ },
12528
+ signal: controller.signal
12529
+ });
12530
+ clearTimeout(timeoutId);
12531
+ if (!response.ok) {
12532
+ const errorBody = await response.text().catch(() => "Unknown error");
12533
+ throw new Error(`HTTP ${response.status}: ${errorBody}`);
12534
+ }
12535
+ return await response.json();
12536
+ } catch (error) {
12537
+ clearTimeout(timeoutId);
12538
+ if (error.name === "AbortError") {
12539
+ throw new Error(`Request timeout after ${this.timeout}ms`);
12540
+ }
12541
+ throw error;
12542
+ }
12543
+ }
12544
+ /**
12545
+ * Perform a POST request
12546
+ * @private
12547
+ * @param {string} path - API path
12548
+ * @param {any} body - Request body
12549
+ * @param {Object} [options] - Request options
12550
+ * @param {boolean} [options.auth=false] - Whether to include auth headers
12551
+ * @returns {Promise<any>}
12552
+ */
12553
+ async _post(path2, body, options = {}) {
12554
+ const controller = new AbortController();
12555
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
12556
+ try {
12557
+ const authHeaders = options.auth ? await this._getAuthHeaders() : {};
12558
+ const response = await fetch(`${this.baseUrl}${path2}`, {
12559
+ method: "POST",
12560
+ headers: {
12561
+ Accept: "application/json",
12562
+ "Content-Type": "application/json",
12563
+ ...this.headers,
12564
+ ...authHeaders
12565
+ },
12566
+ body: JSON.stringify(body),
12567
+ signal: controller.signal
12568
+ });
12569
+ clearTimeout(timeoutId);
12570
+ if (!response.ok) {
12571
+ const errorBody = await response.text().catch(() => "Unknown error");
12572
+ throw new Error(`HTTP ${response.status}: ${errorBody}`);
12573
+ }
12574
+ return await response.json();
12575
+ } catch (error) {
12576
+ clearTimeout(timeoutId);
12577
+ if (error.name === "AbortError") {
12578
+ throw new Error(`Request timeout after ${this.timeout}ms`);
12579
+ }
12580
+ throw error;
12581
+ }
12582
+ }
12583
+ /**
12584
+ * Perform a DELETE request
12585
+ * @private
12586
+ * @param {string} path - API path
12587
+ * @param {Object} [options] - Request options
12588
+ * @param {boolean} [options.auth=false] - Whether to include auth headers
12589
+ * @returns {Promise<any>}
12590
+ */
12591
+ async _delete(path2, options = {}) {
12592
+ const controller = new AbortController();
12593
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
12594
+ try {
12595
+ const authHeaders = options.auth ? await this._getAuthHeaders() : {};
12596
+ const response = await fetch(`${this.baseUrl}${path2}`, {
12597
+ method: "DELETE",
12598
+ headers: {
12599
+ Accept: "application/json",
12600
+ ...this.headers,
12601
+ ...authHeaders
12602
+ },
12603
+ signal: controller.signal
12604
+ });
12605
+ clearTimeout(timeoutId);
12606
+ if (!response.ok) {
12607
+ const errorBody = await response.text().catch(() => "Unknown error");
12608
+ throw new Error(`HTTP ${response.status}: ${errorBody}`);
12609
+ }
12610
+ return await response.json();
12611
+ } catch (error) {
12612
+ clearTimeout(timeoutId);
12613
+ if (error.name === "AbortError") {
12614
+ throw new Error(`Request timeout after ${this.timeout}ms`);
12615
+ }
12616
+ throw error;
12617
+ }
12618
+ }
12619
+ // =========================================================================
12620
+ // Private Utility Methods
12621
+ // =========================================================================
12622
+ /**
12623
+ * Compute a simple hash for object IDs
12624
+ * @private
12625
+ * @param {string} content - Content to hash
12626
+ * @returns {Promise<string>}
12627
+ */
12628
+ async _computeOid(content) {
12629
+ if (typeof crypto !== "undefined" && crypto.subtle) {
12630
+ const encoder = new TextEncoder();
12631
+ const data = encoder.encode(content);
12632
+ const hashBuffer = await crypto.subtle.digest("SHA-1", data);
12633
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
12634
+ return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
12635
+ }
12636
+ let hash = 0;
12637
+ for (let i = 0; i < content.length; i++) {
12638
+ const char = content.charCodeAt(i);
12639
+ hash = (hash << 5) - hash + char;
12640
+ hash = hash & hash;
12641
+ }
12642
+ return Math.abs(hash).toString(16).padStart(40, "0");
12643
+ }
12644
+ /**
12645
+ * Convert string to base64
12646
+ * @private
12647
+ * @param {string} str - String to encode
12648
+ * @returns {string}
12649
+ */
12650
+ _toBase64(str) {
12651
+ if (typeof btoa !== "undefined") {
12652
+ return btoa(str);
12653
+ }
12654
+ return Buffer.from(str).toString("base64");
12655
+ }
12656
+ /**
12657
+ * Clear auth cache (useful after logout)
12658
+ */
12659
+ clearAuthCache() {
12660
+ this._authCache = null;
12661
+ this._authCacheExpiry = 0;
12662
+ }
12663
+ };
12664
+ module2.exports = { GitStorageClient: GitStorageClient2 };
12665
+ }
12666
+ });
12667
+
12668
+ // src/clients/index.js
12669
+ var require_clients = __commonJS({
12670
+ "src/clients/index.js"(exports2, module2) {
12671
+ var { DiscoveryClient: DiscoveryClient2 } = require_discovery_client();
12672
+ var { GitStorageClient: GitStorageClient2 } = require_git_storage_client();
12673
+ module2.exports = {
12674
+ DiscoveryClient: DiscoveryClient2,
12675
+ GitStorageClient: GitStorageClient2
12676
+ };
12677
+ }
12678
+ });
12679
+
9907
12680
  // src/hooks/useSubDAOs.js
9908
12681
  var require_useSubDAOs = __commonJS({
9909
12682
  "src/hooks/useSubDAOs.js"(exports2, module2) {
@@ -10112,6 +12885,7 @@ var subdao = require_subdao();
10112
12885
  var timelock = require_timelock();
10113
12886
  var factory = require_factory();
10114
12887
  var library = require_library();
12888
+ var lineage = require_lineage();
10115
12889
  var prompt = require_prompt();
10116
12890
  var { SageEchoExecutor } = require_execute();
10117
12891
  var ipfs = require_ipfs();
@@ -10125,6 +12899,9 @@ var time = require_time();
10125
12899
  var treasury = require_treasury();
10126
12900
  var boost = require_boost();
10127
12901
  var bounty = require_bounty();
12902
+ var contributions = require_contributions();
12903
+ var votingMultiplier = require_votingMultiplier();
12904
+ var auction = require_auction();
10128
12905
  var wallet = require_wallet();
10129
12906
  wallet.session = require_session();
10130
12907
  var walletCastManager = require_cast_manager();
@@ -10145,6 +12922,7 @@ var { IPFSService } = require_client2();
10145
12922
  var serviceErrors = require_errors2();
10146
12923
  var { SimpleCache } = require_cache();
10147
12924
  var { retryWithBackoff } = require_retry();
12925
+ var { DiscoveryClient, GitStorageClient } = require_clients();
10148
12926
  var hooks = null;
10149
12927
  try {
10150
12928
  hooks = require_hooks();
@@ -10160,6 +12938,7 @@ module.exports = {
10160
12938
  timelock,
10161
12939
  factory,
10162
12940
  library,
12941
+ lineage,
10163
12942
  prompt,
10164
12943
  ipfs,
10165
12944
  ipns,
@@ -10172,6 +12951,9 @@ module.exports = {
10172
12951
  subgraph,
10173
12952
  utils: { ...utils, privateTx, safe, time },
10174
12953
  bounty,
12954
+ contributions,
12955
+ votingMultiplier,
12956
+ auction,
10175
12957
  wallet: Object.assign(wallet, {
10176
12958
  cast: walletCastManager,
10177
12959
  cdp: walletCdpManager
@@ -10192,6 +12974,13 @@ module.exports = {
10192
12974
  SimpleCache,
10193
12975
  retryWithBackoff
10194
12976
  },
12977
+ // Client exports
12978
+ clients: {
12979
+ DiscoveryClient,
12980
+ GitStorageClient
12981
+ },
12982
+ DiscoveryClient,
12983
+ GitStorageClient,
10195
12984
  // React hooks (optional - requires react + swr peer dependencies)
10196
12985
  hooks,
10197
12986
  // Legacy exports (deprecated): maintain compatibility while consumers migrate