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