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