@sage-protocol/sdk 0.1.21 → 0.1.24
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 +2 -2
- package/dist/browser/index.mjs +495 -45
- package/dist/index.cjs +5235 -2939
- package/dist/index.mjs +5249 -2953
- package/dist/node/index.cjs +5249 -2953
- package/dist/node/index.mjs +5249 -2953
- package/package.json +1 -1
- package/types/index.d.ts +429 -15
package/dist/browser/index.mjs
CHANGED
|
@@ -14,7 +14,7 @@ var require_package = __commonJS({
|
|
|
14
14
|
"package.json"(exports, module) {
|
|
15
15
|
module.exports = {
|
|
16
16
|
name: "@sage-protocol/sdk",
|
|
17
|
-
version: "0.1.
|
|
17
|
+
version: "0.1.24",
|
|
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",
|
|
@@ -106,20 +106,26 @@ var require_abi = __commonJS({
|
|
|
106
106
|
var SubDAO = [
|
|
107
107
|
"function governor() view returns (address)",
|
|
108
108
|
"function timelock() view returns (address)",
|
|
109
|
+
// SubDAO ops Safe / treasury (multisig) address. On newer deployments opsSafe() is an alias.
|
|
110
|
+
"function treasury() view returns (address)",
|
|
111
|
+
"function opsSafe() view returns (address)",
|
|
109
112
|
"function getGovernanceMode() view returns (uint8)",
|
|
113
|
+
// New governance profile (3-axis model). May be unavailable on legacy SubDAOs.
|
|
114
|
+
"function profileInitialized() view returns (bool)",
|
|
115
|
+
"function getGovernanceProfile() view returns (uint8 kind, uint8 proposalAccess, uint8 executionAccess)",
|
|
110
116
|
"function promptRegistry() view returns (address)",
|
|
111
117
|
"function sageTreasury() view returns (address)",
|
|
112
|
-
"function stakeToken() view returns (address)",
|
|
113
|
-
"function minStakeAmount() view returns (uint256)",
|
|
114
118
|
"function accessModel() view returns (uint8)",
|
|
115
119
|
"function membershipPolicy() view returns (uint8)",
|
|
116
120
|
"function profileCID() view returns (string)",
|
|
117
121
|
"function factoryDeployer() view returns (address)",
|
|
118
|
-
"function stakedAmount(address) view returns (uint256)",
|
|
119
122
|
"function userForkCount(address) view returns (uint256)",
|
|
120
123
|
"function forkCount(string) view returns (uint256)",
|
|
121
|
-
|
|
122
|
-
"function
|
|
124
|
+
// Fork functions
|
|
125
|
+
"function forkSubDAO(string,string)",
|
|
126
|
+
"function forkSubDAO(string,string,bool)",
|
|
127
|
+
"function forkSubDAOWithStable(string,string,(uint256,uint256,uint8,bytes32,bytes32))",
|
|
128
|
+
"function forkSubDAOWithStable(string,string,(uint256,uint256,uint8,bytes32,bytes32),bool)"
|
|
123
129
|
];
|
|
124
130
|
var Factory = [
|
|
125
131
|
"event SubDAOGovernanceDeployed(address indexed subDAO, address indexed governor, address timelock, address treasury)"
|
|
@@ -154,13 +160,13 @@ var require_abi = __commonJS({
|
|
|
154
160
|
var FactoryWrite = [
|
|
155
161
|
"function createSubDAO(string name, string description, uint8 accessModel, uint256 minStakeAmount, uint256 burnAmount) returns (address subDAO, address registry)",
|
|
156
162
|
"function createSubDAOWithStable(string name, string description, uint8 accessModel, uint256 minStakeAmount, (uint256 value,uint256 deadline,uint8 v,bytes32 r,bytes32 s) permit) returns (address subDAO, address registry)",
|
|
157
|
-
"function createSubDAOWithParams(string name, string description, uint8 accessModel, uint256 minStakeAmount, uint256 burnAmount, uint256 votingDelay, uint256 votingPeriod, uint256 proposalThreshold, uint256 quorumPercentage, uint8 initialForkPolicy, uint8 initialMembershipPolicy, string profileCID) returns (address subDAO, address registry)",
|
|
163
|
+
"function createSubDAOWithParams(string name, string description, uint8 accessModel, uint256 minStakeAmount, uint256 burnAmount, uint256 votingDelay, uint256 votingPeriod, uint256 proposalThreshold, uint256 quorumPercentage, uint8 initialForkPolicy, uint8 initialMembershipPolicy, string profileCID, string manifestCID, string manifestVersion) returns (address subDAO, address registry)",
|
|
158
164
|
"function createSubDAOOperatorWithStable(string name, string description, uint8 accessModel, uint256 minStakeAmount, address operatorExecutor, address operatorAdmin, (uint256 value,uint256 deadline,uint8 v,bytes32 r,bytes32 s) permit) returns (address subDAO, address registry)",
|
|
159
165
|
"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)",
|
|
160
166
|
"function createSubDAOOperator(string name, string description, uint8 accessModel, uint256 minStakeAmount, uint256 burnAmount, address operatorExecutor, address operatorAdmin) returns (address subDAO, address registry)",
|
|
161
167
|
"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)",
|
|
162
|
-
"function createForkedSubDAO(string newName, string newDescription, string originalName, address originalSubDAO, address forker) returns (address subDAO, address registry)",
|
|
163
|
-
"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)"
|
|
168
|
+
"function createForkedSubDAO(string newName, string newDescription, string originalName, address originalSubDAO, address forker, bool copyLibrary) returns (address subDAO, address registry)",
|
|
169
|
+
"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)"
|
|
164
170
|
];
|
|
165
171
|
var TemplateModule = [
|
|
166
172
|
"function getActiveTemplates() view returns (uint256[])",
|
|
@@ -171,18 +177,21 @@ var require_abi = __commonJS({
|
|
|
171
177
|
"function maxCreationBurn() view returns (uint256)"
|
|
172
178
|
];
|
|
173
179
|
var LibraryRegistry = [
|
|
174
|
-
"function libraryByDAO(address) view returns (string manifestCID, address lastUpdater, uint256 lastUpdated, string version, address forkedFromDAO, uint256 sxxxForkFee)",
|
|
180
|
+
"function libraryByDAO(address) view returns (string manifestCID, address lastUpdater, uint256 lastUpdated, string version, address forkedFromDAO, uint256 sxxxForkFee, uint256 nonce)",
|
|
175
181
|
"function daoTimelock(address) view returns (address)",
|
|
176
|
-
"function getLibrary(address) view returns (tuple(string manifestCID, address lastUpdater, uint256 lastUpdated, string version, address forkedFromDAO, uint256 sxxxForkFee))",
|
|
182
|
+
"function getLibrary(address) view returns (tuple(string manifestCID, address lastUpdater, uint256 lastUpdated, string version, address forkedFromDAO, uint256 sxxxForkFee, uint256 nonce))",
|
|
177
183
|
"function getLibraryForkFee(address dao) view returns (uint256)",
|
|
178
184
|
"function setLibraryForkFee(address dao, uint256 fee)",
|
|
179
185
|
"function updateLibrary(address dao, string manifestCID, string version)",
|
|
186
|
+
"function updateLibraryCAS(address dao, string manifestCID, string version, uint256 expectedNonce)",
|
|
180
187
|
"function registerDAO(address dao, address timelock)",
|
|
181
188
|
"function registerForkedDAO(address childDAO, address childTimelock, address parentDAO, string manifestCID, string version)",
|
|
182
|
-
"
|
|
189
|
+
"function initializeLibraryFromFork(address sourceDao, address forkedDao)",
|
|
190
|
+
"event LibraryUpdated(address indexed dao, string manifestCID, address indexed timelock, string version, uint256 nonce)",
|
|
183
191
|
"event DAORegistered(address indexed dao, address indexed timelock)",
|
|
184
|
-
"event LibraryForked(address indexed
|
|
185
|
-
"event LibraryForkFeeUpdated(address indexed dao, uint256 fee)"
|
|
192
|
+
"event LibraryForked(address indexed sourceDao, address indexed forkedDao, string manifestCID)",
|
|
193
|
+
"event LibraryForkFeeUpdated(address indexed dao, uint256 fee)",
|
|
194
|
+
"error NonceMismatch(uint256 expected, uint256 actual)"
|
|
186
195
|
];
|
|
187
196
|
var PromptRegistry = [
|
|
188
197
|
"function prompts(string key) view returns (string cid, uint256 version, uint256 timestamp, address author, string forkedFromCID, address originalAuthor, bool isFork, uint256 forkDepth)",
|
|
@@ -209,14 +218,23 @@ var require_abi = __commonJS({
|
|
|
209
218
|
];
|
|
210
219
|
var Governor = [
|
|
211
220
|
"function name() view returns (string)",
|
|
221
|
+
// ERC6372 clock (Governor uses this for vote snapshots)
|
|
222
|
+
"function clock() view returns (uint48)",
|
|
212
223
|
"function timelock() view returns (address)",
|
|
213
224
|
"function _executor() view returns (address)",
|
|
214
225
|
"function sxxxToken() view returns (address)",
|
|
215
226
|
"function votingDelay() view returns (uint256)",
|
|
216
227
|
"function votingPeriod() view returns (uint256)",
|
|
217
228
|
"function proposalThreshold() view returns (uint256)",
|
|
229
|
+
"function minVotesToVote() view returns (uint256)",
|
|
230
|
+
// OZ Governor: voting power at a past timepoint
|
|
231
|
+
"function getVotes(address,uint256) view returns (uint256)",
|
|
218
232
|
// OZ Governor: quorum at a past block
|
|
219
233
|
"function quorum(uint256) view returns (uint256)",
|
|
234
|
+
// Fixed quorumVotes model (PromptGovernor v2+)
|
|
235
|
+
"function quorumVotes() view returns (uint256)",
|
|
236
|
+
"function setQuorumVotes(uint256)",
|
|
237
|
+
// Legacy OZ Governor: percentage-based quorum (deprecated)
|
|
220
238
|
"function quorumNumerator() view returns (uint256)",
|
|
221
239
|
"function proposalStakeAmount(uint256) view returns (uint256)",
|
|
222
240
|
"function state(uint256) view returns (uint8)",
|
|
@@ -229,9 +247,24 @@ var require_abi = __commonJS({
|
|
|
229
247
|
"function castVoteWithReason(uint256 proposalId, uint8 support, string reason) returns (uint256)",
|
|
230
248
|
"function queue(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash)",
|
|
231
249
|
"function execute(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash)",
|
|
250
|
+
"function cancel(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) returns (uint256)",
|
|
232
251
|
// Some Governors expose id-based queue/execute via TimelockController
|
|
233
252
|
"function queue(uint256)",
|
|
234
|
-
"function execute(uint256)"
|
|
253
|
+
"function execute(uint256)",
|
|
254
|
+
// Threshold model (PromptGovernor)
|
|
255
|
+
"function proposalProposer(uint256 proposalId) view returns (address)",
|
|
256
|
+
"function proposalThresholdSnapshot(uint256 proposalId) view returns (uint256)",
|
|
257
|
+
"function proposalCreator(uint256 proposalId) view returns (address)",
|
|
258
|
+
"function proposalCooldown() view returns (uint256)",
|
|
259
|
+
"function lastProposalTimestamp(address) view returns (uint256)",
|
|
260
|
+
"function getProposalCooldownInfo(address) view returns (bool canPropose, uint256 cooldownRemaining)",
|
|
261
|
+
"function canCreateProposal(address) view returns (bool)",
|
|
262
|
+
"function setMinVotesToVote(uint256)",
|
|
263
|
+
// Multiplier helpers
|
|
264
|
+
"function baseVotesToken() view returns (address)",
|
|
265
|
+
"function isMultiplierEnabled() view returns (bool)",
|
|
266
|
+
"function multiplierNFT() view returns (address)",
|
|
267
|
+
"function getVotingBreakdown(address) view returns (uint256 baseVotes, uint256 multiplier, uint256 effectiveVotes)"
|
|
235
268
|
];
|
|
236
269
|
var Timelock = [
|
|
237
270
|
"function getMinDelay() view returns (uint256)",
|
|
@@ -451,13 +484,11 @@ var require_abi = __commonJS({
|
|
|
451
484
|
"function governanceConfig() view returns (address)",
|
|
452
485
|
"function communityTreasury() view returns (address)",
|
|
453
486
|
"function governanceContract() view returns (address)",
|
|
454
|
-
"function libraryRegistry() view returns (address)",
|
|
455
487
|
"function subdao() view returns (address)",
|
|
456
488
|
"function soulboundBadge() view returns (address)",
|
|
457
489
|
// Admin
|
|
458
490
|
"function setGovernanceContract(address _gov)",
|
|
459
491
|
"function setCommunityTreasury(address _treasury)",
|
|
460
|
-
"function setLibraryRegistry(address _registry)",
|
|
461
492
|
"function setSoulboundBadge(address _sbtAddress)",
|
|
462
493
|
"function grantRole(bytes32 role, address account)",
|
|
463
494
|
"function revokeRole(bytes32 role, address account)",
|
|
@@ -471,7 +502,7 @@ var require_abi = __commonJS({
|
|
|
471
502
|
"event VotingStarted(uint256 indexed bountyId, uint256 votingEndTime)",
|
|
472
503
|
"event BountyCompleted(uint256 indexed bountyId, address indexed winner, uint256 reward, string deliverable)",
|
|
473
504
|
"event BountyAutoApproved(uint256 indexed bountyId, address indexed winner)",
|
|
474
|
-
"event
|
|
505
|
+
"event BountyWinnerSelected(uint256 indexed bountyId, address indexed subdao, string libraryKey, string winnerCid, address indexed winner, uint8 libraryAction)",
|
|
475
506
|
"event BountyCancelled(uint256 indexed bountyId, address indexed creator)",
|
|
476
507
|
"event BountyExpired(uint256 indexed bountyId)",
|
|
477
508
|
"event BountyRewardIncreased(uint256 indexed bountyId, uint256 additionalReward, uint256 newTotal)",
|
|
@@ -1107,19 +1138,37 @@ var require_subgraph = __commonJS({
|
|
|
1107
1138
|
updatedAt: Number(p.updatedAt || 0)
|
|
1108
1139
|
};
|
|
1109
1140
|
},
|
|
1110
|
-
async getProposalById({ url, id }) {
|
|
1141
|
+
async getProposalById({ url, id, governor }) {
|
|
1111
1142
|
if (!url) throw new Error("subgraph url required");
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1143
|
+
let p = null;
|
|
1144
|
+
if (governor) {
|
|
1145
|
+
const govLower = String(governor).toLowerCase();
|
|
1146
|
+
const compositeId = `${govLower}-${String(id)}`;
|
|
1147
|
+
const doc = `query($id: ID!){ proposal(id:$id){ id proposer description createdAt updatedAt state eta targets values calldatas } }`;
|
|
1148
|
+
const data = await query(url, doc, { id: compositeId });
|
|
1149
|
+
p = data?.proposal;
|
|
1150
|
+
}
|
|
1151
|
+
if (!p && governor) {
|
|
1152
|
+
const govLower = String(governor).toLowerCase();
|
|
1153
|
+
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 } }`;
|
|
1154
|
+
const data = await query(url, doc, { gov: govLower, first: 100 });
|
|
1155
|
+
const proposals = data?.proposals || [];
|
|
1156
|
+
p = proposals.find((prop) => {
|
|
1157
|
+
const parts = String(prop.id || "").split("-");
|
|
1158
|
+
const propId = parts.length > 1 ? parts[parts.length - 1] : prop.id;
|
|
1159
|
+
return String(propId) === String(id) || propId && String(BigInt(propId)) === String(BigInt(id));
|
|
1160
|
+
});
|
|
1161
|
+
}
|
|
1115
1162
|
if (!p) return null;
|
|
1116
1163
|
try {
|
|
1117
1164
|
const proposer = safeGetAddress(p.proposer);
|
|
1118
1165
|
if (!proposer) return null;
|
|
1119
1166
|
const targets = (p.targets || []).map((t) => safeGetAddress(t)).filter(Boolean);
|
|
1120
1167
|
if (!targets.length && (p.targets || []).length) return null;
|
|
1168
|
+
const idParts = String(p.id || "").split("-");
|
|
1169
|
+
const actualId = idParts.length > 1 ? idParts[idParts.length - 1] : p.id;
|
|
1121
1170
|
return {
|
|
1122
|
-
id: BigInt(
|
|
1171
|
+
id: BigInt(actualId),
|
|
1123
1172
|
proposer,
|
|
1124
1173
|
description: p.description || "",
|
|
1125
1174
|
createdAt: Number(p.createdAt || 0),
|
|
@@ -1292,8 +1341,9 @@ var require_ipfs = __commonJS({
|
|
|
1292
1341
|
baseUrl: removeTrailingSlash(options.workerBaseUrl || env.SAGE_IPFS_WORKER_URL || ""),
|
|
1293
1342
|
uploadUrl: removeTrailingSlash(options.workerUploadUrl || env.SAGE_IPFS_UPLOAD_URL || ""),
|
|
1294
1343
|
token: options.workerUploadToken || env.SAGE_IPFS_UPLOAD_TOKEN || "",
|
|
1295
|
-
challengePath: options.workerChallengePath || env.SAGE_IPFS_WORKER_CHALLENGE_PATH || "/auth/challenge",
|
|
1344
|
+
challengePath: options.workerChallengePath || env.SAGE_IPFS_WORKER_CHALLENGE_PATH || "/ipfs/auth/challenge",
|
|
1296
1345
|
uploadPath: options.workerUploadPath || env.SAGE_IPFS_WORKER_UPLOAD_PATH || "/ipfs/upload",
|
|
1346
|
+
uploadRawPath: options.workerUploadRawPath || env.SAGE_IPFS_WORKER_UPLOAD_RAW_PATH || "/ipfs/upload-raw",
|
|
1297
1347
|
pinPath: options.workerPinPath || env.SAGE_IPFS_WORKER_PIN_PATH || "/ipfs/pin",
|
|
1298
1348
|
warmPath: options.workerWarmPath || env.SAGE_IPFS_WORKER_WARM_PATH || "/ipfs/warm",
|
|
1299
1349
|
pinUrl: removeTrailingSlash(options.workerPinUrl || env.SAGE_IPFS_WORKER_PIN_URL || ""),
|
|
@@ -1301,11 +1351,13 @@ var require_ipfs = __commonJS({
|
|
|
1301
1351
|
signer: options.workerSigner || options.signer || null,
|
|
1302
1352
|
getAuth: options.workerGetAuth || null,
|
|
1303
1353
|
address: options.workerAddress || env.SAGE_SANDBOX_ADDRESS || "",
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1354
|
+
// All event types route to /trends/usage - worker tracks usage for trend scoring
|
|
1355
|
+
discoveryEventsPath: options.workerDiscoveryEventsPath || env.SAGE_IPFS_WORKER_DISCOVERY_EVENTS_PATH || "/trends/usage",
|
|
1356
|
+
discoveryMcpPath: options.workerDiscoveryMcpPath || env.SAGE_IPFS_WORKER_DISCOVERY_MCP_PATH || "/trends/usage",
|
|
1357
|
+
discoveryLaunchPath: options.workerDiscoveryLaunchPath || env.SAGE_IPFS_WORKER_DISCOVERY_LAUNCH_PATH || "/trends/usage",
|
|
1307
1358
|
discoveryFeedPath: options.workerDiscoveryFeedPath || env.SAGE_IPFS_WORKER_DISCOVERY_FEED_PATH || "/discover",
|
|
1308
|
-
|
|
1359
|
+
// Metrics uses /discover/stats which returns index statistics
|
|
1360
|
+
discoveryMetricsPath: options.workerDiscoveryMetricsPath || env.SAGE_IPFS_WORKER_DISCOVERY_METRICS_PATH || "/discover/stats",
|
|
1309
1361
|
governanceReportPath: options.workerGovernanceReportPath || env.SAGE_IPFS_WORKER_GOVERNANCE_REPORT_PATH || "/governance/report",
|
|
1310
1362
|
governanceReportsPath: options.workerGovernanceReportsPath || env.SAGE_IPFS_WORKER_GOVERNANCE_REPORTS_PATH || "/governance/reports",
|
|
1311
1363
|
governanceReviewPath: options.workerGovernanceReviewPath || env.SAGE_IPFS_WORKER_GOVERNANCE_REVIEW_PATH || "/governance/report/review",
|
|
@@ -1339,8 +1391,9 @@ var require_ipfs = __commonJS({
|
|
|
1339
1391
|
const base = workerBaseUrl();
|
|
1340
1392
|
const ensure = (path) => path.startsWith("/") ? path : `/${path}`;
|
|
1341
1393
|
if (base) {
|
|
1342
|
-
if (kind === "challenge") return `${base}${ensure(config.worker.challengePath || "/auth/challenge")}`;
|
|
1394
|
+
if (kind === "challenge") return `${base}${ensure(config.worker.challengePath || "/ipfs/auth/challenge")}`;
|
|
1343
1395
|
if (kind === "upload") return `${base}${ensure(config.worker.uploadPath || "/ipfs/upload")}`;
|
|
1396
|
+
if (kind === "upload-raw") return `${base}${ensure(config.worker.uploadRawPath || "/ipfs/upload-raw")}`;
|
|
1344
1397
|
if (kind === "pin") return `${base}${ensure(config.worker.pinPath || "/ipfs/pin")}`;
|
|
1345
1398
|
if (kind === "warm") return `${base}${ensure(config.worker.warmPath || "/ipfs/warm")}`;
|
|
1346
1399
|
if (kind === "status") return `${base}${ensure(config.worker.pinPath || "/ipfs/pin")}/${cid}`;
|
|
@@ -1375,6 +1428,26 @@ var require_ipfs = __commonJS({
|
|
|
1375
1428
|
const response = await axiosInstance.get(url, { headers, params, timeout: config.timeoutMs });
|
|
1376
1429
|
return response?.data;
|
|
1377
1430
|
}
|
|
1431
|
+
async function withRetry(fn, { retries = 2, baseMs = 500 } = {}) {
|
|
1432
|
+
let attempt = 0;
|
|
1433
|
+
let lastErr;
|
|
1434
|
+
while (attempt <= retries) {
|
|
1435
|
+
try {
|
|
1436
|
+
return await fn();
|
|
1437
|
+
} catch (e) {
|
|
1438
|
+
lastErr = e;
|
|
1439
|
+
const status = e?.response?.status;
|
|
1440
|
+
if (status && status >= 400 && status < 500 && status !== 429) {
|
|
1441
|
+
throw e;
|
|
1442
|
+
}
|
|
1443
|
+
if (attempt === retries) break;
|
|
1444
|
+
const delay = baseMs * Math.pow(2, attempt);
|
|
1445
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
1446
|
+
attempt++;
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
throw lastErr;
|
|
1450
|
+
}
|
|
1378
1451
|
async function buildWorkerAuthHeaders(extraHeaders = {}) {
|
|
1379
1452
|
if (config.worker.token) {
|
|
1380
1453
|
return { headers: { ...extraHeaders, Authorization: `Bearer ${config.worker.token}` }, auth: null };
|
|
@@ -1447,6 +1520,51 @@ var require_ipfs = __commonJS({
|
|
|
1447
1520
|
if (warm || config.shouldWarm) await warmGateways(cid, { gateways });
|
|
1448
1521
|
return { cid, provider: "worker", response: response?.data || null };
|
|
1449
1522
|
}
|
|
1523
|
+
async function uploadRawViaWorker(content, { name, warm, gateways } = {}) {
|
|
1524
|
+
const { headers, auth } = await buildWorkerAuthHeaders({ "Content-Type": "application/json" });
|
|
1525
|
+
const body = { content };
|
|
1526
|
+
if (auth) body.auth = auth;
|
|
1527
|
+
if (name) body.name = name;
|
|
1528
|
+
const response = await axiosInstance.post(workerUrl("upload-raw"), body, { headers, timeout: config.timeoutMs });
|
|
1529
|
+
const cid = response?.data?.cid || response?.data?.IpfsHash;
|
|
1530
|
+
if (!cid) {
|
|
1531
|
+
throw new Error("Worker response missing cid");
|
|
1532
|
+
}
|
|
1533
|
+
if (warm || config.shouldWarm) await warmGateways(cid, { gateways });
|
|
1534
|
+
return { cid, provider: "worker", response: response?.data || null };
|
|
1535
|
+
}
|
|
1536
|
+
async function uploadRawJson(content, options2 = {}) {
|
|
1537
|
+
if (!content || typeof content !== "object") {
|
|
1538
|
+
throw new Error("content object required");
|
|
1539
|
+
}
|
|
1540
|
+
const { providers, provider, warm, gateways, name = "manifest.json" } = options2;
|
|
1541
|
+
const order = resolveProviderOrder(providers || provider);
|
|
1542
|
+
if (!order.length) {
|
|
1543
|
+
throw new Error("No IPFS providers configured");
|
|
1544
|
+
}
|
|
1545
|
+
const errors = [];
|
|
1546
|
+
for (const candidate of order) {
|
|
1547
|
+
try {
|
|
1548
|
+
if (candidate === "worker") {
|
|
1549
|
+
return await uploadRawViaWorker(content, { name, warm, gateways });
|
|
1550
|
+
}
|
|
1551
|
+
if (candidate === "pinata") {
|
|
1552
|
+
return await uploadToPinata(content, { filename: name, warm, gateways });
|
|
1553
|
+
}
|
|
1554
|
+
if (candidate === "web3") {
|
|
1555
|
+
return await uploadToWeb3Storage(content, { warm, gateways });
|
|
1556
|
+
}
|
|
1557
|
+
if (candidate === "simulate") {
|
|
1558
|
+
return await uploadSimulated(content, { warm, gateways });
|
|
1559
|
+
}
|
|
1560
|
+
} catch (error2) {
|
|
1561
|
+
errors.push({ provider: candidate, error: error2 });
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
const error = new Error("All IPFS providers failed");
|
|
1565
|
+
error.details = errors;
|
|
1566
|
+
throw error;
|
|
1567
|
+
}
|
|
1450
1568
|
async function uploadToPinata(payload, { filename = "payload.json", metadata, warm, gateways } = {}) {
|
|
1451
1569
|
if (!hasPinataCreds()) {
|
|
1452
1570
|
throw new Error("Missing Pinata credentials");
|
|
@@ -1651,28 +1769,28 @@ var require_ipfs = __commonJS({
|
|
|
1651
1769
|
}
|
|
1652
1770
|
async function recordDiscoveryEvent(event = {}) {
|
|
1653
1771
|
if (!event || typeof event !== "object") throw new Error("event required");
|
|
1654
|
-
const
|
|
1655
|
-
if (!
|
|
1656
|
-
const payload = { ...event,
|
|
1657
|
-
return postWorkerJson("discoveryEventsPath", "/
|
|
1658
|
-
}
|
|
1659
|
-
async function recordMcpUsageEvent({ promptId, metadata, address } = {}) {
|
|
1660
|
-
const id = typeof promptId === "string" ? promptId.trim() : "";
|
|
1661
|
-
if (!id) throw new Error("promptId required");
|
|
1662
|
-
const payload = {
|
|
1772
|
+
const cid = typeof event.promptId === "string" ? event.promptId.trim() : typeof event.cid === "string" ? event.cid.trim() : "";
|
|
1773
|
+
if (!cid) throw new Error("promptId or cid required");
|
|
1774
|
+
const payload = { ...event, cid };
|
|
1775
|
+
return withRetry(() => postWorkerJson("discoveryEventsPath", "/trends/usage", payload));
|
|
1776
|
+
}
|
|
1777
|
+
async function recordMcpUsageEvent({ promptId, cid, metadata, address } = {}) {
|
|
1778
|
+
const id = typeof promptId === "string" ? promptId.trim() : typeof cid === "string" ? cid.trim() : "";
|
|
1779
|
+
if (!id) throw new Error("promptId or cid required");
|
|
1780
|
+
const payload = { cid: id };
|
|
1663
1781
|
if (metadata && typeof metadata === "object") payload.metadata = metadata;
|
|
1664
1782
|
const actor = address || config.worker.address;
|
|
1665
1783
|
if (actor) payload.address = actor;
|
|
1666
|
-
return postWorkerJson("discoveryMcpPath", "/
|
|
1784
|
+
return withRetry(() => postWorkerJson("discoveryMcpPath", "/trends/usage", payload));
|
|
1667
1785
|
}
|
|
1668
|
-
async function recordLaunchEvent({ promptId, metadata, address } = {}) {
|
|
1669
|
-
const id = typeof promptId === "string" ? promptId.trim() : "";
|
|
1670
|
-
if (!id) throw new Error("promptId required");
|
|
1671
|
-
const payload = {
|
|
1786
|
+
async function recordLaunchEvent({ promptId, cid, metadata, address } = {}) {
|
|
1787
|
+
const id = typeof promptId === "string" ? promptId.trim() : typeof cid === "string" ? cid.trim() : "";
|
|
1788
|
+
if (!id) throw new Error("promptId or cid required");
|
|
1789
|
+
const payload = { cid: id };
|
|
1672
1790
|
if (metadata && typeof metadata === "object") payload.metadata = metadata;
|
|
1673
1791
|
const actor = address || config.worker.address;
|
|
1674
1792
|
if (actor) payload.address = actor;
|
|
1675
|
-
return postWorkerJson("discoveryLaunchPath", "/
|
|
1793
|
+
return withRetry(() => postWorkerJson("discoveryLaunchPath", "/trends/usage", payload));
|
|
1676
1794
|
}
|
|
1677
1795
|
async function submitGovernanceReport(payload = {}) {
|
|
1678
1796
|
if (!payload || typeof payload !== "object") throw new Error("payload required");
|
|
@@ -1734,6 +1852,7 @@ var require_ipfs = __commonJS({
|
|
|
1734
1852
|
uploadPrompt,
|
|
1735
1853
|
uploadJson,
|
|
1736
1854
|
uploadText,
|
|
1855
|
+
uploadRawJson,
|
|
1737
1856
|
downloadJson,
|
|
1738
1857
|
warmGateways,
|
|
1739
1858
|
buildGatewayUrls: (cid, extra) => buildGatewayUrls(cid, config.gateway, extra),
|
|
@@ -1760,7 +1879,7 @@ var require_ipfs = __commonJS({
|
|
|
1760
1879
|
const timeoutMs = Number(options.timeoutMs ?? env.SAGE_IPFS_TIMEOUT_MS ?? 15e3);
|
|
1761
1880
|
const challengePath = ensureLeadingSlash(
|
|
1762
1881
|
options.workerChallengePath || env.SAGE_IPFS_WORKER_CHALLENGE_PATH,
|
|
1763
|
-
"/auth/challenge"
|
|
1882
|
+
"/ipfs/auth/challenge"
|
|
1764
1883
|
);
|
|
1765
1884
|
const warmPath = ensureLeadingSlash(
|
|
1766
1885
|
options.workerWarmPath || env.SAGE_IPFS_WORKER_WARM_PATH,
|
|
@@ -1827,6 +1946,335 @@ var require_ipfs = __commonJS({
|
|
|
1827
1946
|
}
|
|
1828
1947
|
});
|
|
1829
1948
|
|
|
1949
|
+
// src/browser/reputation.js
|
|
1950
|
+
var require_reputation = __commonJS({
|
|
1951
|
+
"src/browser/reputation.js"(exports, module) {
|
|
1952
|
+
var { getAddress } = require_utils();
|
|
1953
|
+
var subgraph = require_subgraph();
|
|
1954
|
+
function safeGetAddress(value) {
|
|
1955
|
+
try {
|
|
1956
|
+
return getAddress(value);
|
|
1957
|
+
} catch {
|
|
1958
|
+
return null;
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
function clampInt(value, { min = 1, max = 100, fallback = 100 } = {}) {
|
|
1962
|
+
const n = Number(value);
|
|
1963
|
+
if (!Number.isFinite(n)) return fallback;
|
|
1964
|
+
return Math.min(max, Math.max(min, Math.trunc(n)));
|
|
1965
|
+
}
|
|
1966
|
+
function toBigIntString(value, fallback = "0") {
|
|
1967
|
+
try {
|
|
1968
|
+
if (typeof value === "bigint") return value.toString();
|
|
1969
|
+
if (typeof value === "number") return String(Math.trunc(value));
|
|
1970
|
+
const str = String(value).trim();
|
|
1971
|
+
if (!str) return fallback;
|
|
1972
|
+
if (!/^-?\d+$/.test(str)) return fallback;
|
|
1973
|
+
return str;
|
|
1974
|
+
} catch {
|
|
1975
|
+
return fallback;
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
function mapSafe(list, mapper) {
|
|
1979
|
+
const out = [];
|
|
1980
|
+
for (const item of list || []) {
|
|
1981
|
+
try {
|
|
1982
|
+
const v = mapper(item);
|
|
1983
|
+
if (v != null) out.push(v);
|
|
1984
|
+
} catch {
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
return out;
|
|
1988
|
+
}
|
|
1989
|
+
async function getBadgesByRecipient({ url, recipient, first = 50 }) {
|
|
1990
|
+
if (!url) throw new Error("subgraph url required");
|
|
1991
|
+
if (!recipient) throw new Error("recipient required");
|
|
1992
|
+
const addr = safeGetAddress(recipient);
|
|
1993
|
+
if (!addr) throw new Error("invalid recipient address");
|
|
1994
|
+
const doc = `
|
|
1995
|
+
query($recipient: Bytes!, $first: Int!) {
|
|
1996
|
+
soulboundBadges(
|
|
1997
|
+
where: { recipient: $recipient }
|
|
1998
|
+
first: $first
|
|
1999
|
+
orderBy: blockTimestamp
|
|
2000
|
+
orderDirection: desc
|
|
2001
|
+
) {
|
|
2002
|
+
id
|
|
2003
|
+
contract
|
|
2004
|
+
badgeId
|
|
2005
|
+
recipient
|
|
2006
|
+
evidenceURI
|
|
2007
|
+
blockNumber
|
|
2008
|
+
blockTimestamp
|
|
2009
|
+
transactionHash
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
`;
|
|
2013
|
+
const data = await subgraph.query(url, doc, {
|
|
2014
|
+
recipient: addr.toLowerCase(),
|
|
2015
|
+
first: clampInt(first, { min: 1, max: 100, fallback: 50 })
|
|
2016
|
+
});
|
|
2017
|
+
return mapSafe(data?.soulboundBadges, (row) => {
|
|
2018
|
+
const contract = safeGetAddress(row.contract);
|
|
2019
|
+
const recipientAddr = safeGetAddress(row.recipient);
|
|
2020
|
+
if (!contract || !recipientAddr) return null;
|
|
2021
|
+
return {
|
|
2022
|
+
id: String(row.id),
|
|
2023
|
+
contract,
|
|
2024
|
+
badgeId: toBigIntString(row.badgeId, "0"),
|
|
2025
|
+
recipient: recipientAddr,
|
|
2026
|
+
evidenceURI: row.evidenceURI || null,
|
|
2027
|
+
blockNumber: Number(row.blockNumber || 0),
|
|
2028
|
+
blockTimestamp: Number(row.blockTimestamp || 0),
|
|
2029
|
+
transactionHash: row.transactionHash || null
|
|
2030
|
+
};
|
|
2031
|
+
});
|
|
2032
|
+
}
|
|
2033
|
+
async function listContributions({ url, contributor, subdao, first = 50, orderBy = "updatedAt", orderDirection = "desc" }) {
|
|
2034
|
+
if (!url) throw new Error("subgraph url required");
|
|
2035
|
+
const filters = [];
|
|
2036
|
+
if (contributor) {
|
|
2037
|
+
const addr = safeGetAddress(contributor);
|
|
2038
|
+
if (!addr) throw new Error("invalid contributor address");
|
|
2039
|
+
filters.push(`contributor: "${addr.toLowerCase()}"`);
|
|
2040
|
+
}
|
|
2041
|
+
if (subdao) {
|
|
2042
|
+
const addr = safeGetAddress(subdao);
|
|
2043
|
+
if (!addr) throw new Error("invalid subdao address");
|
|
2044
|
+
filters.push(`dao: "${addr.toLowerCase()}"`);
|
|
2045
|
+
}
|
|
2046
|
+
const where = filters.length ? `where: { ${filters.join(", ")} }` : "";
|
|
2047
|
+
const safeOrderBy = ["updatedAt", "createdAt"].includes(orderBy) ? orderBy : "updatedAt";
|
|
2048
|
+
const safeOrderDirection = orderDirection === "asc" ? "asc" : "desc";
|
|
2049
|
+
const doc = `
|
|
2050
|
+
query($first: Int!) {
|
|
2051
|
+
promptContributions(
|
|
2052
|
+
${where}
|
|
2053
|
+
first: $first
|
|
2054
|
+
orderBy: ${safeOrderBy}
|
|
2055
|
+
orderDirection: ${safeOrderDirection}
|
|
2056
|
+
) {
|
|
2057
|
+
id
|
|
2058
|
+
dao
|
|
2059
|
+
promptKey
|
|
2060
|
+
contributor
|
|
2061
|
+
cid
|
|
2062
|
+
proposalId
|
|
2063
|
+
forVotes
|
|
2064
|
+
againstVotes
|
|
2065
|
+
abstainVotes
|
|
2066
|
+
uniqueVoters
|
|
2067
|
+
quorum
|
|
2068
|
+
fromBounty
|
|
2069
|
+
bountyId
|
|
2070
|
+
badgeId
|
|
2071
|
+
badgeEvidenceURI
|
|
2072
|
+
createdAt
|
|
2073
|
+
updatedAt
|
|
2074
|
+
transactionHash
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
`;
|
|
2078
|
+
const data = await subgraph.query(url, doc, {
|
|
2079
|
+
first: clampInt(first, { min: 1, max: 100, fallback: 50 })
|
|
2080
|
+
});
|
|
2081
|
+
return mapSafe(data?.promptContributions, (row) => {
|
|
2082
|
+
const dao = safeGetAddress(row.dao);
|
|
2083
|
+
const contributorAddr = safeGetAddress(row.contributor);
|
|
2084
|
+
if (!dao) return null;
|
|
2085
|
+
return {
|
|
2086
|
+
id: String(row.id),
|
|
2087
|
+
dao,
|
|
2088
|
+
promptKey: String(row.promptKey),
|
|
2089
|
+
contributor: contributorAddr || "0x0000000000000000000000000000000000000000",
|
|
2090
|
+
cid: String(row.cid),
|
|
2091
|
+
timestamp: Number(row.updatedAt || 0),
|
|
2092
|
+
createdAt: Number(row.createdAt || 0),
|
|
2093
|
+
updatedAt: Number(row.updatedAt || 0),
|
|
2094
|
+
transactionHash: row.transactionHash || null,
|
|
2095
|
+
proposalId: row.proposalId != null ? toBigIntString(row.proposalId) : null,
|
|
2096
|
+
forVotes: row.forVotes != null ? toBigIntString(row.forVotes) : null,
|
|
2097
|
+
againstVotes: row.againstVotes != null ? toBigIntString(row.againstVotes) : null,
|
|
2098
|
+
abstainVotes: row.abstainVotes != null ? toBigIntString(row.abstainVotes) : null,
|
|
2099
|
+
uniqueVoters: row.uniqueVoters != null ? Number(row.uniqueVoters) : null,
|
|
2100
|
+
quorum: row.quorum != null ? toBigIntString(row.quorum) : null,
|
|
2101
|
+
fromBounty: Boolean(row.fromBounty),
|
|
2102
|
+
bountyId: row.bountyId != null ? toBigIntString(row.bountyId) : null,
|
|
2103
|
+
badgeId: row.badgeId != null ? toBigIntString(row.badgeId) : null,
|
|
2104
|
+
badgeEvidenceURI: row.badgeEvidenceURI || null
|
|
2105
|
+
};
|
|
2106
|
+
});
|
|
2107
|
+
}
|
|
2108
|
+
function computeAggregates(contributions) {
|
|
2109
|
+
if (!contributions || contributions.length === 0) {
|
|
2110
|
+
return {
|
|
2111
|
+
totalContributions: 0,
|
|
2112
|
+
uniqueContributors: 0,
|
|
2113
|
+
bountyOriginated: 0,
|
|
2114
|
+
governanceOriginated: 0,
|
|
2115
|
+
totalForVotes: "0",
|
|
2116
|
+
totalAgainstVotes: "0",
|
|
2117
|
+
averageVoterCount: 0,
|
|
2118
|
+
badgeCount: 0
|
|
2119
|
+
};
|
|
2120
|
+
}
|
|
2121
|
+
const contributorSet = /* @__PURE__ */ new Set();
|
|
2122
|
+
let bountyOriginated = 0;
|
|
2123
|
+
let governanceOriginated = 0;
|
|
2124
|
+
let totalForVotes = 0n;
|
|
2125
|
+
let totalAgainstVotes = 0n;
|
|
2126
|
+
let voterCountSum = 0;
|
|
2127
|
+
let voterCountN = 0;
|
|
2128
|
+
let badgeCount = 0;
|
|
2129
|
+
for (const c of contributions) {
|
|
2130
|
+
if (c.contributor) contributorSet.add(c.contributor.toLowerCase());
|
|
2131
|
+
if (c.fromBounty) {
|
|
2132
|
+
bountyOriginated++;
|
|
2133
|
+
} else {
|
|
2134
|
+
governanceOriginated++;
|
|
2135
|
+
}
|
|
2136
|
+
if (c.forVotes != null) {
|
|
2137
|
+
try {
|
|
2138
|
+
totalForVotes += BigInt(c.forVotes);
|
|
2139
|
+
} catch {
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
if (c.againstVotes != null) {
|
|
2143
|
+
try {
|
|
2144
|
+
totalAgainstVotes += BigInt(c.againstVotes);
|
|
2145
|
+
} catch {
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
if (c.uniqueVoters != null) {
|
|
2149
|
+
voterCountSum += c.uniqueVoters;
|
|
2150
|
+
voterCountN++;
|
|
2151
|
+
}
|
|
2152
|
+
if (c.badgeId != null) badgeCount++;
|
|
2153
|
+
}
|
|
2154
|
+
return {
|
|
2155
|
+
totalContributions: contributions.length,
|
|
2156
|
+
uniqueContributors: contributorSet.size,
|
|
2157
|
+
bountyOriginated,
|
|
2158
|
+
governanceOriginated,
|
|
2159
|
+
totalForVotes: totalForVotes.toString(),
|
|
2160
|
+
totalAgainstVotes: totalAgainstVotes.toString(),
|
|
2161
|
+
averageVoterCount: voterCountN > 0 ? Math.round(voterCountSum / voterCountN) : 0,
|
|
2162
|
+
badgeCount
|
|
2163
|
+
};
|
|
2164
|
+
}
|
|
2165
|
+
async function getByAddress({
|
|
2166
|
+
url,
|
|
2167
|
+
address,
|
|
2168
|
+
subdao,
|
|
2169
|
+
includeBadges = true,
|
|
2170
|
+
includeContributions = true,
|
|
2171
|
+
first = 100
|
|
2172
|
+
} = {}) {
|
|
2173
|
+
if (!url) throw new Error("subgraph url required");
|
|
2174
|
+
if (!address) throw new Error("address required");
|
|
2175
|
+
const addr = safeGetAddress(address);
|
|
2176
|
+
if (!addr) throw new Error("invalid address");
|
|
2177
|
+
const subdaoAddr = subdao ? safeGetAddress(subdao) : null;
|
|
2178
|
+
if (subdao && !subdaoAddr) throw new Error("invalid subdao address");
|
|
2179
|
+
const limit = clampInt(first, { min: 1, max: 200, fallback: 100 });
|
|
2180
|
+
let badges = void 0;
|
|
2181
|
+
if (includeBadges) {
|
|
2182
|
+
badges = await getBadgesByRecipient({ url, recipient: addr, first: limit });
|
|
2183
|
+
}
|
|
2184
|
+
let contributionAggregates = void 0;
|
|
2185
|
+
let lastContributionAt = null;
|
|
2186
|
+
if (includeContributions) {
|
|
2187
|
+
const rows = await listContributions({
|
|
2188
|
+
url,
|
|
2189
|
+
contributor: addr,
|
|
2190
|
+
subdao: subdaoAddr || void 0,
|
|
2191
|
+
first: limit,
|
|
2192
|
+
orderBy: "updatedAt",
|
|
2193
|
+
orderDirection: "desc"
|
|
2194
|
+
});
|
|
2195
|
+
if (rows && rows.length) {
|
|
2196
|
+
const updatedAt = rows[0]?.updatedAt ?? rows[0]?.timestamp ?? null;
|
|
2197
|
+
lastContributionAt = updatedAt != null ? Number(updatedAt) : null;
|
|
2198
|
+
if (!Number.isFinite(lastContributionAt)) lastContributionAt = null;
|
|
2199
|
+
}
|
|
2200
|
+
contributionAggregates = computeAggregates(rows || []);
|
|
2201
|
+
}
|
|
2202
|
+
const signals = {
|
|
2203
|
+
badgeCount: includeBadges ? badges ? badges.length : 0 : null,
|
|
2204
|
+
totalContributions: includeContributions ? contributionAggregates ? contributionAggregates.totalContributions : 0 : null,
|
|
2205
|
+
governanceOriginated: includeContributions ? contributionAggregates ? contributionAggregates.governanceOriginated : 0 : null,
|
|
2206
|
+
bountyOriginated: includeContributions ? contributionAggregates ? contributionAggregates.bountyOriginated : 0 : null,
|
|
2207
|
+
lastContributionAt: includeContributions ? lastContributionAt : null
|
|
2208
|
+
};
|
|
2209
|
+
const out = {
|
|
2210
|
+
address: addr,
|
|
2211
|
+
subdao: subdaoAddr || null,
|
|
2212
|
+
signals
|
|
2213
|
+
};
|
|
2214
|
+
if (includeBadges) out.badges = badges;
|
|
2215
|
+
if (includeContributions) {
|
|
2216
|
+
out.contributionAggregates = contributionAggregates;
|
|
2217
|
+
out.lastContributionAt = lastContributionAt;
|
|
2218
|
+
}
|
|
2219
|
+
return out;
|
|
2220
|
+
}
|
|
2221
|
+
function normalizeGateInt(value, name) {
|
|
2222
|
+
if (value === void 0 || value === null) return null;
|
|
2223
|
+
const n = Number(value);
|
|
2224
|
+
if (!Number.isFinite(n) || n < 0) {
|
|
2225
|
+
throw new Error(`invalid gate: ${name}`);
|
|
2226
|
+
}
|
|
2227
|
+
return Math.trunc(n);
|
|
2228
|
+
}
|
|
2229
|
+
function normalizeRequiredBadgeIds(value) {
|
|
2230
|
+
const list = Array.isArray(value) ? value : value != null ? [value] : [];
|
|
2231
|
+
const out = [];
|
|
2232
|
+
for (const item of list) {
|
|
2233
|
+
const id = toBigIntString(item, "");
|
|
2234
|
+
if (id) out.push(id);
|
|
2235
|
+
}
|
|
2236
|
+
return out;
|
|
2237
|
+
}
|
|
2238
|
+
function evaluate(result, gates = {}) {
|
|
2239
|
+
const reasons = [];
|
|
2240
|
+
const minBadges = normalizeGateInt(gates.minBadges, "minBadges");
|
|
2241
|
+
const minContributions = normalizeGateInt(gates.minContributions, "minContributions");
|
|
2242
|
+
const requiredBadges = normalizeRequiredBadgeIds(gates.requireBadges ?? gates.requireBadge);
|
|
2243
|
+
const badgeCount = Number(result?.signals?.badgeCount ?? (result?.badges?.length ?? 0));
|
|
2244
|
+
const totalContributions = Number(result?.signals?.totalContributions ?? (result?.contributionAggregates?.totalContributions ?? 0));
|
|
2245
|
+
if (minBadges != null) {
|
|
2246
|
+
if (!Number.isFinite(badgeCount)) {
|
|
2247
|
+
reasons.push("badges_unavailable");
|
|
2248
|
+
} else if (badgeCount < minBadges) {
|
|
2249
|
+
reasons.push(`minBadges:${badgeCount}<${minBadges}`);
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
if (minContributions != null) {
|
|
2253
|
+
if (!Number.isFinite(totalContributions)) {
|
|
2254
|
+
reasons.push("contributions_unavailable");
|
|
2255
|
+
} else if (totalContributions < minContributions) {
|
|
2256
|
+
reasons.push(`minContributions:${totalContributions}<${minContributions}`);
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
if (requiredBadges.length) {
|
|
2260
|
+
const have = new Set((result?.badges || []).map((b) => toBigIntString(b?.badgeId, "")).filter(Boolean));
|
|
2261
|
+
for (const req of requiredBadges) {
|
|
2262
|
+
if (!have.has(req)) reasons.push(`missingBadge:${req}`);
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
return { ok: reasons.length === 0, reasons };
|
|
2266
|
+
}
|
|
2267
|
+
module.exports = {
|
|
2268
|
+
getByAddress,
|
|
2269
|
+
evaluate,
|
|
2270
|
+
// Expose lower-level functions for advanced usage
|
|
2271
|
+
getBadgesByRecipient,
|
|
2272
|
+
listContributions,
|
|
2273
|
+
computeAggregates
|
|
2274
|
+
};
|
|
2275
|
+
}
|
|
2276
|
+
});
|
|
2277
|
+
|
|
1830
2278
|
// src/errors/index.js
|
|
1831
2279
|
var require_errors = __commonJS({
|
|
1832
2280
|
"src/errors/index.js"(exports, module) {
|
|
@@ -2232,6 +2680,7 @@ var require_browser = __commonJS({
|
|
|
2232
2680
|
var governance = require_governance();
|
|
2233
2681
|
var subgraph = require_subgraph();
|
|
2234
2682
|
var ipfs = require_ipfs();
|
|
2683
|
+
var reputation = require_reputation();
|
|
2235
2684
|
var serviceErrors = require_errors();
|
|
2236
2685
|
var { SimpleCache } = require_cache();
|
|
2237
2686
|
var { retryWithBackoff } = require_retry();
|
|
@@ -2252,6 +2701,7 @@ var require_browser = __commonJS({
|
|
|
2252
2701
|
// Browser-safe modules (no ethers dependencies)
|
|
2253
2702
|
subgraph,
|
|
2254
2703
|
ipfs,
|
|
2704
|
+
reputation,
|
|
2255
2705
|
// Service utilities
|
|
2256
2706
|
utils: {
|
|
2257
2707
|
SimpleCache,
|