@sage-protocol/sdk 0.1.24 → 0.1.25
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 +1 -1
- package/dist/browser/index.mjs +1 -1
- package/dist/index.cjs +332 -1
- package/dist/index.mjs +332 -1
- package/dist/node/index.cjs +332 -1
- package/dist/node/index.mjs +332 -1
- package/package.json +1 -1
package/dist/node/index.mjs
CHANGED
|
@@ -20,7 +20,7 @@ var require_package = __commonJS({
|
|
|
20
20
|
"package.json"(exports2, module2) {
|
|
21
21
|
module2.exports = {
|
|
22
22
|
name: "@sage-protocol/sdk",
|
|
23
|
-
version: "0.1.
|
|
23
|
+
version: "0.1.25",
|
|
24
24
|
description: "Backend-agnostic SDK for interacting with the Sage Protocol (governance, SubDAOs, tokens).",
|
|
25
25
|
main: "dist/index.cjs",
|
|
26
26
|
module: "dist/index.mjs",
|
|
@@ -9795,6 +9795,335 @@ var require_contributions = __commonJS({
|
|
|
9795
9795
|
}
|
|
9796
9796
|
});
|
|
9797
9797
|
|
|
9798
|
+
// src/browser/reputation.js
|
|
9799
|
+
var require_reputation = __commonJS({
|
|
9800
|
+
"src/browser/reputation.js"(exports2, module2) {
|
|
9801
|
+
var { getAddress } = require_utils();
|
|
9802
|
+
var subgraph = require_subgraph2();
|
|
9803
|
+
function safeGetAddress(value) {
|
|
9804
|
+
try {
|
|
9805
|
+
return getAddress(value);
|
|
9806
|
+
} catch {
|
|
9807
|
+
return null;
|
|
9808
|
+
}
|
|
9809
|
+
}
|
|
9810
|
+
function clampInt(value, { min = 1, max = 100, fallback = 100 } = {}) {
|
|
9811
|
+
const n = Number(value);
|
|
9812
|
+
if (!Number.isFinite(n)) return fallback;
|
|
9813
|
+
return Math.min(max, Math.max(min, Math.trunc(n)));
|
|
9814
|
+
}
|
|
9815
|
+
function toBigIntString(value, fallback = "0") {
|
|
9816
|
+
try {
|
|
9817
|
+
if (typeof value === "bigint") return value.toString();
|
|
9818
|
+
if (typeof value === "number") return String(Math.trunc(value));
|
|
9819
|
+
const str = String(value).trim();
|
|
9820
|
+
if (!str) return fallback;
|
|
9821
|
+
if (!/^-?\d+$/.test(str)) return fallback;
|
|
9822
|
+
return str;
|
|
9823
|
+
} catch {
|
|
9824
|
+
return fallback;
|
|
9825
|
+
}
|
|
9826
|
+
}
|
|
9827
|
+
function mapSafe(list, mapper) {
|
|
9828
|
+
const out = [];
|
|
9829
|
+
for (const item of list || []) {
|
|
9830
|
+
try {
|
|
9831
|
+
const v = mapper(item);
|
|
9832
|
+
if (v != null) out.push(v);
|
|
9833
|
+
} catch {
|
|
9834
|
+
}
|
|
9835
|
+
}
|
|
9836
|
+
return out;
|
|
9837
|
+
}
|
|
9838
|
+
async function getBadgesByRecipient({ url, recipient, first = 50 }) {
|
|
9839
|
+
if (!url) throw new Error("subgraph url required");
|
|
9840
|
+
if (!recipient) throw new Error("recipient required");
|
|
9841
|
+
const addr = safeGetAddress(recipient);
|
|
9842
|
+
if (!addr) throw new Error("invalid recipient address");
|
|
9843
|
+
const doc = `
|
|
9844
|
+
query($recipient: Bytes!, $first: Int!) {
|
|
9845
|
+
soulboundBadges(
|
|
9846
|
+
where: { recipient: $recipient }
|
|
9847
|
+
first: $first
|
|
9848
|
+
orderBy: blockTimestamp
|
|
9849
|
+
orderDirection: desc
|
|
9850
|
+
) {
|
|
9851
|
+
id
|
|
9852
|
+
contract
|
|
9853
|
+
badgeId
|
|
9854
|
+
recipient
|
|
9855
|
+
evidenceURI
|
|
9856
|
+
blockNumber
|
|
9857
|
+
blockTimestamp
|
|
9858
|
+
transactionHash
|
|
9859
|
+
}
|
|
9860
|
+
}
|
|
9861
|
+
`;
|
|
9862
|
+
const data = await subgraph.query(url, doc, {
|
|
9863
|
+
recipient: addr.toLowerCase(),
|
|
9864
|
+
first: clampInt(first, { min: 1, max: 100, fallback: 50 })
|
|
9865
|
+
});
|
|
9866
|
+
return mapSafe(data?.soulboundBadges, (row) => {
|
|
9867
|
+
const contract = safeGetAddress(row.contract);
|
|
9868
|
+
const recipientAddr = safeGetAddress(row.recipient);
|
|
9869
|
+
if (!contract || !recipientAddr) return null;
|
|
9870
|
+
return {
|
|
9871
|
+
id: String(row.id),
|
|
9872
|
+
contract,
|
|
9873
|
+
badgeId: toBigIntString(row.badgeId, "0"),
|
|
9874
|
+
recipient: recipientAddr,
|
|
9875
|
+
evidenceURI: row.evidenceURI || null,
|
|
9876
|
+
blockNumber: Number(row.blockNumber || 0),
|
|
9877
|
+
blockTimestamp: Number(row.blockTimestamp || 0),
|
|
9878
|
+
transactionHash: row.transactionHash || null
|
|
9879
|
+
};
|
|
9880
|
+
});
|
|
9881
|
+
}
|
|
9882
|
+
async function listContributions({ url, contributor, subdao, first = 50, orderBy = "updatedAt", orderDirection = "desc" }) {
|
|
9883
|
+
if (!url) throw new Error("subgraph url required");
|
|
9884
|
+
const filters = [];
|
|
9885
|
+
if (contributor) {
|
|
9886
|
+
const addr = safeGetAddress(contributor);
|
|
9887
|
+
if (!addr) throw new Error("invalid contributor address");
|
|
9888
|
+
filters.push(`contributor: "${addr.toLowerCase()}"`);
|
|
9889
|
+
}
|
|
9890
|
+
if (subdao) {
|
|
9891
|
+
const addr = safeGetAddress(subdao);
|
|
9892
|
+
if (!addr) throw new Error("invalid subdao address");
|
|
9893
|
+
filters.push(`dao: "${addr.toLowerCase()}"`);
|
|
9894
|
+
}
|
|
9895
|
+
const where = filters.length ? `where: { ${filters.join(", ")} }` : "";
|
|
9896
|
+
const safeOrderBy = ["updatedAt", "createdAt"].includes(orderBy) ? orderBy : "updatedAt";
|
|
9897
|
+
const safeOrderDirection = orderDirection === "asc" ? "asc" : "desc";
|
|
9898
|
+
const doc = `
|
|
9899
|
+
query($first: Int!) {
|
|
9900
|
+
promptContributions(
|
|
9901
|
+
${where}
|
|
9902
|
+
first: $first
|
|
9903
|
+
orderBy: ${safeOrderBy}
|
|
9904
|
+
orderDirection: ${safeOrderDirection}
|
|
9905
|
+
) {
|
|
9906
|
+
id
|
|
9907
|
+
dao
|
|
9908
|
+
promptKey
|
|
9909
|
+
contributor
|
|
9910
|
+
cid
|
|
9911
|
+
proposalId
|
|
9912
|
+
forVotes
|
|
9913
|
+
againstVotes
|
|
9914
|
+
abstainVotes
|
|
9915
|
+
uniqueVoters
|
|
9916
|
+
quorum
|
|
9917
|
+
fromBounty
|
|
9918
|
+
bountyId
|
|
9919
|
+
badgeId
|
|
9920
|
+
badgeEvidenceURI
|
|
9921
|
+
createdAt
|
|
9922
|
+
updatedAt
|
|
9923
|
+
transactionHash
|
|
9924
|
+
}
|
|
9925
|
+
}
|
|
9926
|
+
`;
|
|
9927
|
+
const data = await subgraph.query(url, doc, {
|
|
9928
|
+
first: clampInt(first, { min: 1, max: 100, fallback: 50 })
|
|
9929
|
+
});
|
|
9930
|
+
return mapSafe(data?.promptContributions, (row) => {
|
|
9931
|
+
const dao = safeGetAddress(row.dao);
|
|
9932
|
+
const contributorAddr = safeGetAddress(row.contributor);
|
|
9933
|
+
if (!dao) return null;
|
|
9934
|
+
return {
|
|
9935
|
+
id: String(row.id),
|
|
9936
|
+
dao,
|
|
9937
|
+
promptKey: String(row.promptKey),
|
|
9938
|
+
contributor: contributorAddr || "0x0000000000000000000000000000000000000000",
|
|
9939
|
+
cid: String(row.cid),
|
|
9940
|
+
timestamp: Number(row.updatedAt || 0),
|
|
9941
|
+
createdAt: Number(row.createdAt || 0),
|
|
9942
|
+
updatedAt: Number(row.updatedAt || 0),
|
|
9943
|
+
transactionHash: row.transactionHash || null,
|
|
9944
|
+
proposalId: row.proposalId != null ? toBigIntString(row.proposalId) : null,
|
|
9945
|
+
forVotes: row.forVotes != null ? toBigIntString(row.forVotes) : null,
|
|
9946
|
+
againstVotes: row.againstVotes != null ? toBigIntString(row.againstVotes) : null,
|
|
9947
|
+
abstainVotes: row.abstainVotes != null ? toBigIntString(row.abstainVotes) : null,
|
|
9948
|
+
uniqueVoters: row.uniqueVoters != null ? Number(row.uniqueVoters) : null,
|
|
9949
|
+
quorum: row.quorum != null ? toBigIntString(row.quorum) : null,
|
|
9950
|
+
fromBounty: Boolean(row.fromBounty),
|
|
9951
|
+
bountyId: row.bountyId != null ? toBigIntString(row.bountyId) : null,
|
|
9952
|
+
badgeId: row.badgeId != null ? toBigIntString(row.badgeId) : null,
|
|
9953
|
+
badgeEvidenceURI: row.badgeEvidenceURI || null
|
|
9954
|
+
};
|
|
9955
|
+
});
|
|
9956
|
+
}
|
|
9957
|
+
function computeAggregates(contributions) {
|
|
9958
|
+
if (!contributions || contributions.length === 0) {
|
|
9959
|
+
return {
|
|
9960
|
+
totalContributions: 0,
|
|
9961
|
+
uniqueContributors: 0,
|
|
9962
|
+
bountyOriginated: 0,
|
|
9963
|
+
governanceOriginated: 0,
|
|
9964
|
+
totalForVotes: "0",
|
|
9965
|
+
totalAgainstVotes: "0",
|
|
9966
|
+
averageVoterCount: 0,
|
|
9967
|
+
badgeCount: 0
|
|
9968
|
+
};
|
|
9969
|
+
}
|
|
9970
|
+
const contributorSet = /* @__PURE__ */ new Set();
|
|
9971
|
+
let bountyOriginated = 0;
|
|
9972
|
+
let governanceOriginated = 0;
|
|
9973
|
+
let totalForVotes = 0n;
|
|
9974
|
+
let totalAgainstVotes = 0n;
|
|
9975
|
+
let voterCountSum = 0;
|
|
9976
|
+
let voterCountN = 0;
|
|
9977
|
+
let badgeCount = 0;
|
|
9978
|
+
for (const c of contributions) {
|
|
9979
|
+
if (c.contributor) contributorSet.add(c.contributor.toLowerCase());
|
|
9980
|
+
if (c.fromBounty) {
|
|
9981
|
+
bountyOriginated++;
|
|
9982
|
+
} else {
|
|
9983
|
+
governanceOriginated++;
|
|
9984
|
+
}
|
|
9985
|
+
if (c.forVotes != null) {
|
|
9986
|
+
try {
|
|
9987
|
+
totalForVotes += BigInt(c.forVotes);
|
|
9988
|
+
} catch {
|
|
9989
|
+
}
|
|
9990
|
+
}
|
|
9991
|
+
if (c.againstVotes != null) {
|
|
9992
|
+
try {
|
|
9993
|
+
totalAgainstVotes += BigInt(c.againstVotes);
|
|
9994
|
+
} catch {
|
|
9995
|
+
}
|
|
9996
|
+
}
|
|
9997
|
+
if (c.uniqueVoters != null) {
|
|
9998
|
+
voterCountSum += c.uniqueVoters;
|
|
9999
|
+
voterCountN++;
|
|
10000
|
+
}
|
|
10001
|
+
if (c.badgeId != null) badgeCount++;
|
|
10002
|
+
}
|
|
10003
|
+
return {
|
|
10004
|
+
totalContributions: contributions.length,
|
|
10005
|
+
uniqueContributors: contributorSet.size,
|
|
10006
|
+
bountyOriginated,
|
|
10007
|
+
governanceOriginated,
|
|
10008
|
+
totalForVotes: totalForVotes.toString(),
|
|
10009
|
+
totalAgainstVotes: totalAgainstVotes.toString(),
|
|
10010
|
+
averageVoterCount: voterCountN > 0 ? Math.round(voterCountSum / voterCountN) : 0,
|
|
10011
|
+
badgeCount
|
|
10012
|
+
};
|
|
10013
|
+
}
|
|
10014
|
+
async function getByAddress({
|
|
10015
|
+
url,
|
|
10016
|
+
address,
|
|
10017
|
+
subdao,
|
|
10018
|
+
includeBadges = true,
|
|
10019
|
+
includeContributions = true,
|
|
10020
|
+
first = 100
|
|
10021
|
+
} = {}) {
|
|
10022
|
+
if (!url) throw new Error("subgraph url required");
|
|
10023
|
+
if (!address) throw new Error("address required");
|
|
10024
|
+
const addr = safeGetAddress(address);
|
|
10025
|
+
if (!addr) throw new Error("invalid address");
|
|
10026
|
+
const subdaoAddr = subdao ? safeGetAddress(subdao) : null;
|
|
10027
|
+
if (subdao && !subdaoAddr) throw new Error("invalid subdao address");
|
|
10028
|
+
const limit = clampInt(first, { min: 1, max: 200, fallback: 100 });
|
|
10029
|
+
let badges = void 0;
|
|
10030
|
+
if (includeBadges) {
|
|
10031
|
+
badges = await getBadgesByRecipient({ url, recipient: addr, first: limit });
|
|
10032
|
+
}
|
|
10033
|
+
let contributionAggregates = void 0;
|
|
10034
|
+
let lastContributionAt = null;
|
|
10035
|
+
if (includeContributions) {
|
|
10036
|
+
const rows = await listContributions({
|
|
10037
|
+
url,
|
|
10038
|
+
contributor: addr,
|
|
10039
|
+
subdao: subdaoAddr || void 0,
|
|
10040
|
+
first: limit,
|
|
10041
|
+
orderBy: "updatedAt",
|
|
10042
|
+
orderDirection: "desc"
|
|
10043
|
+
});
|
|
10044
|
+
if (rows && rows.length) {
|
|
10045
|
+
const updatedAt = rows[0]?.updatedAt ?? rows[0]?.timestamp ?? null;
|
|
10046
|
+
lastContributionAt = updatedAt != null ? Number(updatedAt) : null;
|
|
10047
|
+
if (!Number.isFinite(lastContributionAt)) lastContributionAt = null;
|
|
10048
|
+
}
|
|
10049
|
+
contributionAggregates = computeAggregates(rows || []);
|
|
10050
|
+
}
|
|
10051
|
+
const signals = {
|
|
10052
|
+
badgeCount: includeBadges ? badges ? badges.length : 0 : null,
|
|
10053
|
+
totalContributions: includeContributions ? contributionAggregates ? contributionAggregates.totalContributions : 0 : null,
|
|
10054
|
+
governanceOriginated: includeContributions ? contributionAggregates ? contributionAggregates.governanceOriginated : 0 : null,
|
|
10055
|
+
bountyOriginated: includeContributions ? contributionAggregates ? contributionAggregates.bountyOriginated : 0 : null,
|
|
10056
|
+
lastContributionAt: includeContributions ? lastContributionAt : null
|
|
10057
|
+
};
|
|
10058
|
+
const out = {
|
|
10059
|
+
address: addr,
|
|
10060
|
+
subdao: subdaoAddr || null,
|
|
10061
|
+
signals
|
|
10062
|
+
};
|
|
10063
|
+
if (includeBadges) out.badges = badges;
|
|
10064
|
+
if (includeContributions) {
|
|
10065
|
+
out.contributionAggregates = contributionAggregates;
|
|
10066
|
+
out.lastContributionAt = lastContributionAt;
|
|
10067
|
+
}
|
|
10068
|
+
return out;
|
|
10069
|
+
}
|
|
10070
|
+
function normalizeGateInt(value, name) {
|
|
10071
|
+
if (value === void 0 || value === null) return null;
|
|
10072
|
+
const n = Number(value);
|
|
10073
|
+
if (!Number.isFinite(n) || n < 0) {
|
|
10074
|
+
throw new Error(`invalid gate: ${name}`);
|
|
10075
|
+
}
|
|
10076
|
+
return Math.trunc(n);
|
|
10077
|
+
}
|
|
10078
|
+
function normalizeRequiredBadgeIds(value) {
|
|
10079
|
+
const list = Array.isArray(value) ? value : value != null ? [value] : [];
|
|
10080
|
+
const out = [];
|
|
10081
|
+
for (const item of list) {
|
|
10082
|
+
const id2 = toBigIntString(item, "");
|
|
10083
|
+
if (id2) out.push(id2);
|
|
10084
|
+
}
|
|
10085
|
+
return out;
|
|
10086
|
+
}
|
|
10087
|
+
function evaluate(result, gates = {}) {
|
|
10088
|
+
const reasons = [];
|
|
10089
|
+
const minBadges = normalizeGateInt(gates.minBadges, "minBadges");
|
|
10090
|
+
const minContributions = normalizeGateInt(gates.minContributions, "minContributions");
|
|
10091
|
+
const requiredBadges = normalizeRequiredBadgeIds(gates.requireBadges ?? gates.requireBadge);
|
|
10092
|
+
const badgeCount = Number(result?.signals?.badgeCount ?? (result?.badges?.length ?? 0));
|
|
10093
|
+
const totalContributions = Number(result?.signals?.totalContributions ?? (result?.contributionAggregates?.totalContributions ?? 0));
|
|
10094
|
+
if (minBadges != null) {
|
|
10095
|
+
if (!Number.isFinite(badgeCount)) {
|
|
10096
|
+
reasons.push("badges_unavailable");
|
|
10097
|
+
} else if (badgeCount < minBadges) {
|
|
10098
|
+
reasons.push(`minBadges:${badgeCount}<${minBadges}`);
|
|
10099
|
+
}
|
|
10100
|
+
}
|
|
10101
|
+
if (minContributions != null) {
|
|
10102
|
+
if (!Number.isFinite(totalContributions)) {
|
|
10103
|
+
reasons.push("contributions_unavailable");
|
|
10104
|
+
} else if (totalContributions < minContributions) {
|
|
10105
|
+
reasons.push(`minContributions:${totalContributions}<${minContributions}`);
|
|
10106
|
+
}
|
|
10107
|
+
}
|
|
10108
|
+
if (requiredBadges.length) {
|
|
10109
|
+
const have = new Set((result?.badges || []).map((b) => toBigIntString(b?.badgeId, "")).filter(Boolean));
|
|
10110
|
+
for (const req2 of requiredBadges) {
|
|
10111
|
+
if (!have.has(req2)) reasons.push(`missingBadge:${req2}`);
|
|
10112
|
+
}
|
|
10113
|
+
}
|
|
10114
|
+
return { ok: reasons.length === 0, reasons };
|
|
10115
|
+
}
|
|
10116
|
+
module2.exports = {
|
|
10117
|
+
getByAddress,
|
|
10118
|
+
evaluate,
|
|
10119
|
+
// Expose lower-level functions for advanced usage
|
|
10120
|
+
getBadgesByRecipient,
|
|
10121
|
+
listContributions,
|
|
10122
|
+
computeAggregates
|
|
10123
|
+
};
|
|
10124
|
+
}
|
|
10125
|
+
});
|
|
10126
|
+
|
|
9798
10127
|
// src/votingMultiplier/index.js
|
|
9799
10128
|
var require_votingMultiplier = __commonJS({
|
|
9800
10129
|
"src/votingMultiplier/index.js"(exports2, module2) {
|
|
@@ -14049,6 +14378,7 @@ var require_src = __commonJS({
|
|
|
14049
14378
|
var boost = require_boost();
|
|
14050
14379
|
var bounty = require_bounty();
|
|
14051
14380
|
var contributions = require_contributions();
|
|
14381
|
+
var reputation = require_reputation();
|
|
14052
14382
|
var votingMultiplier = require_votingMultiplier();
|
|
14053
14383
|
var auction = require_auction();
|
|
14054
14384
|
var wallet = require_wallet();
|
|
@@ -14102,6 +14432,7 @@ var require_src = __commonJS({
|
|
|
14102
14432
|
utils: { ...utils, privateTx, safe, time },
|
|
14103
14433
|
bounty,
|
|
14104
14434
|
contributions,
|
|
14435
|
+
reputation,
|
|
14105
14436
|
votingMultiplier,
|
|
14106
14437
|
auction,
|
|
14107
14438
|
wallet: Object.assign(wallet, {
|
package/package.json
CHANGED