@sage-protocol/sdk 0.2.4 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/index.mjs +1 -1
- package/dist/index.cjs +119 -1
- package/dist/index.mjs +119 -1
- package/dist/node/index.cjs +119 -1
- package/dist/node/index.mjs +119 -1
- package/package.json +1 -1
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.2.
|
|
17
|
+
version: "0.2.5",
|
|
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",
|
package/dist/index.cjs
CHANGED
|
@@ -14,7 +14,7 @@ var require_package = __commonJS({
|
|
|
14
14
|
"package.json"(exports2, module2) {
|
|
15
15
|
module2.exports = {
|
|
16
16
|
name: "@sage-protocol/sdk",
|
|
17
|
-
version: "0.2.
|
|
17
|
+
version: "0.2.5",
|
|
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",
|
|
@@ -5022,9 +5022,127 @@ var require_governance = __commonJS({
|
|
|
5022
5022
|
description: desc.description
|
|
5023
5023
|
};
|
|
5024
5024
|
}
|
|
5025
|
+
async function getProposalVotingStatus({ provider, governor, proposalId }) {
|
|
5026
|
+
if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
|
|
5027
|
+
if (!proposalId) throw new SageSDKError(CODES.INVALID_ARGS, "proposalId required");
|
|
5028
|
+
const addr = normaliseGovernor(governor);
|
|
5029
|
+
const g = new Contract(addr, ABI.Governor, provider);
|
|
5030
|
+
const pid = typeof proposalId === "bigint" ? proposalId : BigInt(String(proposalId));
|
|
5031
|
+
const [
|
|
5032
|
+
stateNum,
|
|
5033
|
+
snapshot,
|
|
5034
|
+
deadline,
|
|
5035
|
+
votes,
|
|
5036
|
+
votingDelay,
|
|
5037
|
+
votingPeriod,
|
|
5038
|
+
proposalThreshold,
|
|
5039
|
+
govName
|
|
5040
|
+
] = await Promise.all([
|
|
5041
|
+
g.state(pid).catch(() => null),
|
|
5042
|
+
g.proposalSnapshot(pid).catch(() => null),
|
|
5043
|
+
g.proposalDeadline(pid).catch(() => null),
|
|
5044
|
+
g.proposalVotes(pid).catch(() => null),
|
|
5045
|
+
g.votingDelay().catch(() => null),
|
|
5046
|
+
g.votingPeriod().catch(() => null),
|
|
5047
|
+
g.proposalThreshold().catch(() => null),
|
|
5048
|
+
g.name().catch(() => null)
|
|
5049
|
+
]);
|
|
5050
|
+
let quorum = null;
|
|
5051
|
+
if (snapshot != null) {
|
|
5052
|
+
try {
|
|
5053
|
+
quorum = await g.quorum(snapshot);
|
|
5054
|
+
quorum = BigInt(quorum.toString());
|
|
5055
|
+
} catch {
|
|
5056
|
+
try {
|
|
5057
|
+
const qv = await g.quorumVotes();
|
|
5058
|
+
quorum = BigInt(qv.toString());
|
|
5059
|
+
} catch {
|
|
5060
|
+
}
|
|
5061
|
+
}
|
|
5062
|
+
}
|
|
5063
|
+
let forVotes = 0n;
|
|
5064
|
+
let againstVotes = 0n;
|
|
5065
|
+
let abstainVotes = 0n;
|
|
5066
|
+
if (Array.isArray(votes)) {
|
|
5067
|
+
againstVotes = BigInt(votes[0]);
|
|
5068
|
+
forVotes = BigInt(votes[1]);
|
|
5069
|
+
abstainVotes = BigInt(votes[2]);
|
|
5070
|
+
} else if (votes && typeof votes === "object") {
|
|
5071
|
+
if (votes.againstVotes != null) againstVotes = BigInt(votes.againstVotes);
|
|
5072
|
+
if (votes.forVotes != null) forVotes = BigInt(votes.forVotes);
|
|
5073
|
+
if (votes.abstainVotes != null) abstainVotes = BigInt(votes.abstainVotes);
|
|
5074
|
+
}
|
|
5075
|
+
const totalVotes = forVotes + againstVotes + abstainVotes;
|
|
5076
|
+
const participatingVotes = forVotes + againstVotes;
|
|
5077
|
+
const quorumMet = quorum != null ? forVotes >= quorum : null;
|
|
5078
|
+
const quorumProgress = quorum != null && quorum > 0n ? Number(forVotes * 10000n / quorum) / 100 : null;
|
|
5079
|
+
const stateMap = ["PENDING", "ACTIVE", "CANCELED", "DEFEATED", "SUCCEEDED", "QUEUED", "EXPIRED", "EXECUTED"];
|
|
5080
|
+
const state = typeof stateNum === "number" && stateNum >= 0 && stateNum < stateMap.length ? stateMap[stateNum] : null;
|
|
5081
|
+
const BLOCK_TIME_SECONDS = 2;
|
|
5082
|
+
const votingDelaySeconds = votingDelay != null ? Number(votingDelay) * BLOCK_TIME_SECONDS : null;
|
|
5083
|
+
const votingPeriodSeconds = votingPeriod != null ? Number(votingPeriod) * BLOCK_TIME_SECONDS : null;
|
|
5084
|
+
const formatSXXX = (val) => {
|
|
5085
|
+
if (val == null) return null;
|
|
5086
|
+
const num = Number(val) / 1e18;
|
|
5087
|
+
if (num >= 1e6) return `${(num / 1e6).toFixed(1)}M`;
|
|
5088
|
+
if (num >= 1e3) return `${(num / 1e3).toFixed(1)}K`;
|
|
5089
|
+
return num.toFixed(2);
|
|
5090
|
+
};
|
|
5091
|
+
const formatDuration = (seconds) => {
|
|
5092
|
+
if (seconds == null) return null;
|
|
5093
|
+
if (seconds < 60) return `${seconds} seconds`;
|
|
5094
|
+
if (seconds < 3600) return `${Math.round(seconds / 60)} minutes`;
|
|
5095
|
+
if (seconds < 86400) return `${(seconds / 3600).toFixed(1)} hours`;
|
|
5096
|
+
return `${(seconds / 86400).toFixed(1)} days`;
|
|
5097
|
+
};
|
|
5098
|
+
return {
|
|
5099
|
+
governor: addr,
|
|
5100
|
+
governorName: govName,
|
|
5101
|
+
proposalId: pid.toString(),
|
|
5102
|
+
state,
|
|
5103
|
+
stateNum: typeof stateNum === "number" ? stateNum : null,
|
|
5104
|
+
// Raw values (bigint as string for JSON serialization)
|
|
5105
|
+
votes: {
|
|
5106
|
+
for: forVotes.toString(),
|
|
5107
|
+
against: againstVotes.toString(),
|
|
5108
|
+
abstain: abstainVotes.toString(),
|
|
5109
|
+
total: totalVotes.toString()
|
|
5110
|
+
},
|
|
5111
|
+
quorum: quorum?.toString() || null,
|
|
5112
|
+
proposalThreshold: proposalThreshold?.toString() || null,
|
|
5113
|
+
snapshot: snapshot?.toString() || null,
|
|
5114
|
+
deadline: deadline?.toString() || null,
|
|
5115
|
+
votingDelay: votingDelay?.toString() || null,
|
|
5116
|
+
votingPeriod: votingPeriod?.toString() || null,
|
|
5117
|
+
// Computed status
|
|
5118
|
+
quorumMet,
|
|
5119
|
+
quorumProgress,
|
|
5120
|
+
// percentage (0-100+)
|
|
5121
|
+
passing: forVotes > againstVotes,
|
|
5122
|
+
// Formatted for display
|
|
5123
|
+
formatted: {
|
|
5124
|
+
forVotes: formatSXXX(forVotes),
|
|
5125
|
+
againstVotes: formatSXXX(againstVotes),
|
|
5126
|
+
abstainVotes: formatSXXX(abstainVotes),
|
|
5127
|
+
totalVotes: formatSXXX(totalVotes),
|
|
5128
|
+
quorum: formatSXXX(quorum),
|
|
5129
|
+
proposalThreshold: formatSXXX(proposalThreshold),
|
|
5130
|
+
votingDelay: formatDuration(votingDelaySeconds),
|
|
5131
|
+
votingPeriod: formatDuration(votingPeriodSeconds)
|
|
5132
|
+
},
|
|
5133
|
+
// Plain language summary
|
|
5134
|
+
summary: {
|
|
5135
|
+
quorumStatus: quorum != null ? quorumMet ? `Quorum reached (${formatSXXX(forVotes)} of ${formatSXXX(quorum)} SXXX required)` : `${formatSXXX(forVotes)} of ${formatSXXX(quorum)} SXXX needed for quorum (${quorumProgress?.toFixed(1)}%)` : "Quorum information unavailable",
|
|
5136
|
+
voteStatus: `${formatSXXX(forVotes)} SXXX for, ${formatSXXX(againstVotes)} SXXX against`,
|
|
5137
|
+
outcome: forVotes > againstVotes ? "Currently passing" : forVotes < againstVotes ? "Currently failing" : "Tied",
|
|
5138
|
+
votingPeriod: votingPeriodSeconds ? `Voting period: ${formatDuration(votingPeriodSeconds)}` : null
|
|
5139
|
+
}
|
|
5140
|
+
};
|
|
5141
|
+
}
|
|
5025
5142
|
module2.exports = {
|
|
5026
5143
|
getGovernorInfo,
|
|
5027
5144
|
getProposal,
|
|
5145
|
+
getProposalVotingStatus,
|
|
5028
5146
|
listProposals,
|
|
5029
5147
|
getProposalMetadata,
|
|
5030
5148
|
hashDescription,
|
package/dist/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.2.
|
|
23
|
+
version: "0.2.5",
|
|
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",
|
|
@@ -5028,9 +5028,127 @@ var require_governance = __commonJS({
|
|
|
5028
5028
|
description: desc.description
|
|
5029
5029
|
};
|
|
5030
5030
|
}
|
|
5031
|
+
async function getProposalVotingStatus({ provider, governor, proposalId }) {
|
|
5032
|
+
if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
|
|
5033
|
+
if (!proposalId) throw new SageSDKError(CODES.INVALID_ARGS, "proposalId required");
|
|
5034
|
+
const addr = normaliseGovernor(governor);
|
|
5035
|
+
const g = new Contract(addr, ABI.Governor, provider);
|
|
5036
|
+
const pid = typeof proposalId === "bigint" ? proposalId : BigInt(String(proposalId));
|
|
5037
|
+
const [
|
|
5038
|
+
stateNum,
|
|
5039
|
+
snapshot,
|
|
5040
|
+
deadline,
|
|
5041
|
+
votes,
|
|
5042
|
+
votingDelay,
|
|
5043
|
+
votingPeriod,
|
|
5044
|
+
proposalThreshold,
|
|
5045
|
+
govName
|
|
5046
|
+
] = await Promise.all([
|
|
5047
|
+
g.state(pid).catch(() => null),
|
|
5048
|
+
g.proposalSnapshot(pid).catch(() => null),
|
|
5049
|
+
g.proposalDeadline(pid).catch(() => null),
|
|
5050
|
+
g.proposalVotes(pid).catch(() => null),
|
|
5051
|
+
g.votingDelay().catch(() => null),
|
|
5052
|
+
g.votingPeriod().catch(() => null),
|
|
5053
|
+
g.proposalThreshold().catch(() => null),
|
|
5054
|
+
g.name().catch(() => null)
|
|
5055
|
+
]);
|
|
5056
|
+
let quorum = null;
|
|
5057
|
+
if (snapshot != null) {
|
|
5058
|
+
try {
|
|
5059
|
+
quorum = await g.quorum(snapshot);
|
|
5060
|
+
quorum = BigInt(quorum.toString());
|
|
5061
|
+
} catch {
|
|
5062
|
+
try {
|
|
5063
|
+
const qv = await g.quorumVotes();
|
|
5064
|
+
quorum = BigInt(qv.toString());
|
|
5065
|
+
} catch {
|
|
5066
|
+
}
|
|
5067
|
+
}
|
|
5068
|
+
}
|
|
5069
|
+
let forVotes = 0n;
|
|
5070
|
+
let againstVotes = 0n;
|
|
5071
|
+
let abstainVotes = 0n;
|
|
5072
|
+
if (Array.isArray(votes)) {
|
|
5073
|
+
againstVotes = BigInt(votes[0]);
|
|
5074
|
+
forVotes = BigInt(votes[1]);
|
|
5075
|
+
abstainVotes = BigInt(votes[2]);
|
|
5076
|
+
} else if (votes && typeof votes === "object") {
|
|
5077
|
+
if (votes.againstVotes != null) againstVotes = BigInt(votes.againstVotes);
|
|
5078
|
+
if (votes.forVotes != null) forVotes = BigInt(votes.forVotes);
|
|
5079
|
+
if (votes.abstainVotes != null) abstainVotes = BigInt(votes.abstainVotes);
|
|
5080
|
+
}
|
|
5081
|
+
const totalVotes = forVotes + againstVotes + abstainVotes;
|
|
5082
|
+
const participatingVotes = forVotes + againstVotes;
|
|
5083
|
+
const quorumMet = quorum != null ? forVotes >= quorum : null;
|
|
5084
|
+
const quorumProgress = quorum != null && quorum > 0n ? Number(forVotes * 10000n / quorum) / 100 : null;
|
|
5085
|
+
const stateMap = ["PENDING", "ACTIVE", "CANCELED", "DEFEATED", "SUCCEEDED", "QUEUED", "EXPIRED", "EXECUTED"];
|
|
5086
|
+
const state = typeof stateNum === "number" && stateNum >= 0 && stateNum < stateMap.length ? stateMap[stateNum] : null;
|
|
5087
|
+
const BLOCK_TIME_SECONDS = 2;
|
|
5088
|
+
const votingDelaySeconds = votingDelay != null ? Number(votingDelay) * BLOCK_TIME_SECONDS : null;
|
|
5089
|
+
const votingPeriodSeconds = votingPeriod != null ? Number(votingPeriod) * BLOCK_TIME_SECONDS : null;
|
|
5090
|
+
const formatSXXX = (val) => {
|
|
5091
|
+
if (val == null) return null;
|
|
5092
|
+
const num = Number(val) / 1e18;
|
|
5093
|
+
if (num >= 1e6) return `${(num / 1e6).toFixed(1)}M`;
|
|
5094
|
+
if (num >= 1e3) return `${(num / 1e3).toFixed(1)}K`;
|
|
5095
|
+
return num.toFixed(2);
|
|
5096
|
+
};
|
|
5097
|
+
const formatDuration = (seconds) => {
|
|
5098
|
+
if (seconds == null) return null;
|
|
5099
|
+
if (seconds < 60) return `${seconds} seconds`;
|
|
5100
|
+
if (seconds < 3600) return `${Math.round(seconds / 60)} minutes`;
|
|
5101
|
+
if (seconds < 86400) return `${(seconds / 3600).toFixed(1)} hours`;
|
|
5102
|
+
return `${(seconds / 86400).toFixed(1)} days`;
|
|
5103
|
+
};
|
|
5104
|
+
return {
|
|
5105
|
+
governor: addr,
|
|
5106
|
+
governorName: govName,
|
|
5107
|
+
proposalId: pid.toString(),
|
|
5108
|
+
state,
|
|
5109
|
+
stateNum: typeof stateNum === "number" ? stateNum : null,
|
|
5110
|
+
// Raw values (bigint as string for JSON serialization)
|
|
5111
|
+
votes: {
|
|
5112
|
+
for: forVotes.toString(),
|
|
5113
|
+
against: againstVotes.toString(),
|
|
5114
|
+
abstain: abstainVotes.toString(),
|
|
5115
|
+
total: totalVotes.toString()
|
|
5116
|
+
},
|
|
5117
|
+
quorum: quorum?.toString() || null,
|
|
5118
|
+
proposalThreshold: proposalThreshold?.toString() || null,
|
|
5119
|
+
snapshot: snapshot?.toString() || null,
|
|
5120
|
+
deadline: deadline?.toString() || null,
|
|
5121
|
+
votingDelay: votingDelay?.toString() || null,
|
|
5122
|
+
votingPeriod: votingPeriod?.toString() || null,
|
|
5123
|
+
// Computed status
|
|
5124
|
+
quorumMet,
|
|
5125
|
+
quorumProgress,
|
|
5126
|
+
// percentage (0-100+)
|
|
5127
|
+
passing: forVotes > againstVotes,
|
|
5128
|
+
// Formatted for display
|
|
5129
|
+
formatted: {
|
|
5130
|
+
forVotes: formatSXXX(forVotes),
|
|
5131
|
+
againstVotes: formatSXXX(againstVotes),
|
|
5132
|
+
abstainVotes: formatSXXX(abstainVotes),
|
|
5133
|
+
totalVotes: formatSXXX(totalVotes),
|
|
5134
|
+
quorum: formatSXXX(quorum),
|
|
5135
|
+
proposalThreshold: formatSXXX(proposalThreshold),
|
|
5136
|
+
votingDelay: formatDuration(votingDelaySeconds),
|
|
5137
|
+
votingPeriod: formatDuration(votingPeriodSeconds)
|
|
5138
|
+
},
|
|
5139
|
+
// Plain language summary
|
|
5140
|
+
summary: {
|
|
5141
|
+
quorumStatus: quorum != null ? quorumMet ? `Quorum reached (${formatSXXX(forVotes)} of ${formatSXXX(quorum)} SXXX required)` : `${formatSXXX(forVotes)} of ${formatSXXX(quorum)} SXXX needed for quorum (${quorumProgress?.toFixed(1)}%)` : "Quorum information unavailable",
|
|
5142
|
+
voteStatus: `${formatSXXX(forVotes)} SXXX for, ${formatSXXX(againstVotes)} SXXX against`,
|
|
5143
|
+
outcome: forVotes > againstVotes ? "Currently passing" : forVotes < againstVotes ? "Currently failing" : "Tied",
|
|
5144
|
+
votingPeriod: votingPeriodSeconds ? `Voting period: ${formatDuration(votingPeriodSeconds)}` : null
|
|
5145
|
+
}
|
|
5146
|
+
};
|
|
5147
|
+
}
|
|
5031
5148
|
module2.exports = {
|
|
5032
5149
|
getGovernorInfo,
|
|
5033
5150
|
getProposal,
|
|
5151
|
+
getProposalVotingStatus,
|
|
5034
5152
|
listProposals,
|
|
5035
5153
|
getProposalMetadata,
|
|
5036
5154
|
hashDescription,
|
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.2.
|
|
17
|
+
version: "0.2.5",
|
|
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",
|
|
@@ -5022,9 +5022,127 @@ var require_governance = __commonJS({
|
|
|
5022
5022
|
description: desc.description
|
|
5023
5023
|
};
|
|
5024
5024
|
}
|
|
5025
|
+
async function getProposalVotingStatus({ provider, governor, proposalId }) {
|
|
5026
|
+
if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
|
|
5027
|
+
if (!proposalId) throw new SageSDKError(CODES.INVALID_ARGS, "proposalId required");
|
|
5028
|
+
const addr = normaliseGovernor(governor);
|
|
5029
|
+
const g = new Contract(addr, ABI.Governor, provider);
|
|
5030
|
+
const pid = typeof proposalId === "bigint" ? proposalId : BigInt(String(proposalId));
|
|
5031
|
+
const [
|
|
5032
|
+
stateNum,
|
|
5033
|
+
snapshot,
|
|
5034
|
+
deadline,
|
|
5035
|
+
votes,
|
|
5036
|
+
votingDelay,
|
|
5037
|
+
votingPeriod,
|
|
5038
|
+
proposalThreshold,
|
|
5039
|
+
govName
|
|
5040
|
+
] = await Promise.all([
|
|
5041
|
+
g.state(pid).catch(() => null),
|
|
5042
|
+
g.proposalSnapshot(pid).catch(() => null),
|
|
5043
|
+
g.proposalDeadline(pid).catch(() => null),
|
|
5044
|
+
g.proposalVotes(pid).catch(() => null),
|
|
5045
|
+
g.votingDelay().catch(() => null),
|
|
5046
|
+
g.votingPeriod().catch(() => null),
|
|
5047
|
+
g.proposalThreshold().catch(() => null),
|
|
5048
|
+
g.name().catch(() => null)
|
|
5049
|
+
]);
|
|
5050
|
+
let quorum = null;
|
|
5051
|
+
if (snapshot != null) {
|
|
5052
|
+
try {
|
|
5053
|
+
quorum = await g.quorum(snapshot);
|
|
5054
|
+
quorum = BigInt(quorum.toString());
|
|
5055
|
+
} catch {
|
|
5056
|
+
try {
|
|
5057
|
+
const qv = await g.quorumVotes();
|
|
5058
|
+
quorum = BigInt(qv.toString());
|
|
5059
|
+
} catch {
|
|
5060
|
+
}
|
|
5061
|
+
}
|
|
5062
|
+
}
|
|
5063
|
+
let forVotes = 0n;
|
|
5064
|
+
let againstVotes = 0n;
|
|
5065
|
+
let abstainVotes = 0n;
|
|
5066
|
+
if (Array.isArray(votes)) {
|
|
5067
|
+
againstVotes = BigInt(votes[0]);
|
|
5068
|
+
forVotes = BigInt(votes[1]);
|
|
5069
|
+
abstainVotes = BigInt(votes[2]);
|
|
5070
|
+
} else if (votes && typeof votes === "object") {
|
|
5071
|
+
if (votes.againstVotes != null) againstVotes = BigInt(votes.againstVotes);
|
|
5072
|
+
if (votes.forVotes != null) forVotes = BigInt(votes.forVotes);
|
|
5073
|
+
if (votes.abstainVotes != null) abstainVotes = BigInt(votes.abstainVotes);
|
|
5074
|
+
}
|
|
5075
|
+
const totalVotes = forVotes + againstVotes + abstainVotes;
|
|
5076
|
+
const participatingVotes = forVotes + againstVotes;
|
|
5077
|
+
const quorumMet = quorum != null ? forVotes >= quorum : null;
|
|
5078
|
+
const quorumProgress = quorum != null && quorum > 0n ? Number(forVotes * 10000n / quorum) / 100 : null;
|
|
5079
|
+
const stateMap = ["PENDING", "ACTIVE", "CANCELED", "DEFEATED", "SUCCEEDED", "QUEUED", "EXPIRED", "EXECUTED"];
|
|
5080
|
+
const state = typeof stateNum === "number" && stateNum >= 0 && stateNum < stateMap.length ? stateMap[stateNum] : null;
|
|
5081
|
+
const BLOCK_TIME_SECONDS = 2;
|
|
5082
|
+
const votingDelaySeconds = votingDelay != null ? Number(votingDelay) * BLOCK_TIME_SECONDS : null;
|
|
5083
|
+
const votingPeriodSeconds = votingPeriod != null ? Number(votingPeriod) * BLOCK_TIME_SECONDS : null;
|
|
5084
|
+
const formatSXXX = (val) => {
|
|
5085
|
+
if (val == null) return null;
|
|
5086
|
+
const num = Number(val) / 1e18;
|
|
5087
|
+
if (num >= 1e6) return `${(num / 1e6).toFixed(1)}M`;
|
|
5088
|
+
if (num >= 1e3) return `${(num / 1e3).toFixed(1)}K`;
|
|
5089
|
+
return num.toFixed(2);
|
|
5090
|
+
};
|
|
5091
|
+
const formatDuration = (seconds) => {
|
|
5092
|
+
if (seconds == null) return null;
|
|
5093
|
+
if (seconds < 60) return `${seconds} seconds`;
|
|
5094
|
+
if (seconds < 3600) return `${Math.round(seconds / 60)} minutes`;
|
|
5095
|
+
if (seconds < 86400) return `${(seconds / 3600).toFixed(1)} hours`;
|
|
5096
|
+
return `${(seconds / 86400).toFixed(1)} days`;
|
|
5097
|
+
};
|
|
5098
|
+
return {
|
|
5099
|
+
governor: addr,
|
|
5100
|
+
governorName: govName,
|
|
5101
|
+
proposalId: pid.toString(),
|
|
5102
|
+
state,
|
|
5103
|
+
stateNum: typeof stateNum === "number" ? stateNum : null,
|
|
5104
|
+
// Raw values (bigint as string for JSON serialization)
|
|
5105
|
+
votes: {
|
|
5106
|
+
for: forVotes.toString(),
|
|
5107
|
+
against: againstVotes.toString(),
|
|
5108
|
+
abstain: abstainVotes.toString(),
|
|
5109
|
+
total: totalVotes.toString()
|
|
5110
|
+
},
|
|
5111
|
+
quorum: quorum?.toString() || null,
|
|
5112
|
+
proposalThreshold: proposalThreshold?.toString() || null,
|
|
5113
|
+
snapshot: snapshot?.toString() || null,
|
|
5114
|
+
deadline: deadline?.toString() || null,
|
|
5115
|
+
votingDelay: votingDelay?.toString() || null,
|
|
5116
|
+
votingPeriod: votingPeriod?.toString() || null,
|
|
5117
|
+
// Computed status
|
|
5118
|
+
quorumMet,
|
|
5119
|
+
quorumProgress,
|
|
5120
|
+
// percentage (0-100+)
|
|
5121
|
+
passing: forVotes > againstVotes,
|
|
5122
|
+
// Formatted for display
|
|
5123
|
+
formatted: {
|
|
5124
|
+
forVotes: formatSXXX(forVotes),
|
|
5125
|
+
againstVotes: formatSXXX(againstVotes),
|
|
5126
|
+
abstainVotes: formatSXXX(abstainVotes),
|
|
5127
|
+
totalVotes: formatSXXX(totalVotes),
|
|
5128
|
+
quorum: formatSXXX(quorum),
|
|
5129
|
+
proposalThreshold: formatSXXX(proposalThreshold),
|
|
5130
|
+
votingDelay: formatDuration(votingDelaySeconds),
|
|
5131
|
+
votingPeriod: formatDuration(votingPeriodSeconds)
|
|
5132
|
+
},
|
|
5133
|
+
// Plain language summary
|
|
5134
|
+
summary: {
|
|
5135
|
+
quorumStatus: quorum != null ? quorumMet ? `Quorum reached (${formatSXXX(forVotes)} of ${formatSXXX(quorum)} SXXX required)` : `${formatSXXX(forVotes)} of ${formatSXXX(quorum)} SXXX needed for quorum (${quorumProgress?.toFixed(1)}%)` : "Quorum information unavailable",
|
|
5136
|
+
voteStatus: `${formatSXXX(forVotes)} SXXX for, ${formatSXXX(againstVotes)} SXXX against`,
|
|
5137
|
+
outcome: forVotes > againstVotes ? "Currently passing" : forVotes < againstVotes ? "Currently failing" : "Tied",
|
|
5138
|
+
votingPeriod: votingPeriodSeconds ? `Voting period: ${formatDuration(votingPeriodSeconds)}` : null
|
|
5139
|
+
}
|
|
5140
|
+
};
|
|
5141
|
+
}
|
|
5025
5142
|
module2.exports = {
|
|
5026
5143
|
getGovernorInfo,
|
|
5027
5144
|
getProposal,
|
|
5145
|
+
getProposalVotingStatus,
|
|
5028
5146
|
listProposals,
|
|
5029
5147
|
getProposalMetadata,
|
|
5030
5148
|
hashDescription,
|
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.2.
|
|
23
|
+
version: "0.2.5",
|
|
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",
|
|
@@ -5028,9 +5028,127 @@ var require_governance = __commonJS({
|
|
|
5028
5028
|
description: desc.description
|
|
5029
5029
|
};
|
|
5030
5030
|
}
|
|
5031
|
+
async function getProposalVotingStatus({ provider, governor, proposalId }) {
|
|
5032
|
+
if (!provider) throw new SageSDKError(CODES.INVALID_ARGS, "provider required");
|
|
5033
|
+
if (!proposalId) throw new SageSDKError(CODES.INVALID_ARGS, "proposalId required");
|
|
5034
|
+
const addr = normaliseGovernor(governor);
|
|
5035
|
+
const g = new Contract(addr, ABI.Governor, provider);
|
|
5036
|
+
const pid = typeof proposalId === "bigint" ? proposalId : BigInt(String(proposalId));
|
|
5037
|
+
const [
|
|
5038
|
+
stateNum,
|
|
5039
|
+
snapshot,
|
|
5040
|
+
deadline,
|
|
5041
|
+
votes,
|
|
5042
|
+
votingDelay,
|
|
5043
|
+
votingPeriod,
|
|
5044
|
+
proposalThreshold,
|
|
5045
|
+
govName
|
|
5046
|
+
] = await Promise.all([
|
|
5047
|
+
g.state(pid).catch(() => null),
|
|
5048
|
+
g.proposalSnapshot(pid).catch(() => null),
|
|
5049
|
+
g.proposalDeadline(pid).catch(() => null),
|
|
5050
|
+
g.proposalVotes(pid).catch(() => null),
|
|
5051
|
+
g.votingDelay().catch(() => null),
|
|
5052
|
+
g.votingPeriod().catch(() => null),
|
|
5053
|
+
g.proposalThreshold().catch(() => null),
|
|
5054
|
+
g.name().catch(() => null)
|
|
5055
|
+
]);
|
|
5056
|
+
let quorum = null;
|
|
5057
|
+
if (snapshot != null) {
|
|
5058
|
+
try {
|
|
5059
|
+
quorum = await g.quorum(snapshot);
|
|
5060
|
+
quorum = BigInt(quorum.toString());
|
|
5061
|
+
} catch {
|
|
5062
|
+
try {
|
|
5063
|
+
const qv = await g.quorumVotes();
|
|
5064
|
+
quorum = BigInt(qv.toString());
|
|
5065
|
+
} catch {
|
|
5066
|
+
}
|
|
5067
|
+
}
|
|
5068
|
+
}
|
|
5069
|
+
let forVotes = 0n;
|
|
5070
|
+
let againstVotes = 0n;
|
|
5071
|
+
let abstainVotes = 0n;
|
|
5072
|
+
if (Array.isArray(votes)) {
|
|
5073
|
+
againstVotes = BigInt(votes[0]);
|
|
5074
|
+
forVotes = BigInt(votes[1]);
|
|
5075
|
+
abstainVotes = BigInt(votes[2]);
|
|
5076
|
+
} else if (votes && typeof votes === "object") {
|
|
5077
|
+
if (votes.againstVotes != null) againstVotes = BigInt(votes.againstVotes);
|
|
5078
|
+
if (votes.forVotes != null) forVotes = BigInt(votes.forVotes);
|
|
5079
|
+
if (votes.abstainVotes != null) abstainVotes = BigInt(votes.abstainVotes);
|
|
5080
|
+
}
|
|
5081
|
+
const totalVotes = forVotes + againstVotes + abstainVotes;
|
|
5082
|
+
const participatingVotes = forVotes + againstVotes;
|
|
5083
|
+
const quorumMet = quorum != null ? forVotes >= quorum : null;
|
|
5084
|
+
const quorumProgress = quorum != null && quorum > 0n ? Number(forVotes * 10000n / quorum) / 100 : null;
|
|
5085
|
+
const stateMap = ["PENDING", "ACTIVE", "CANCELED", "DEFEATED", "SUCCEEDED", "QUEUED", "EXPIRED", "EXECUTED"];
|
|
5086
|
+
const state = typeof stateNum === "number" && stateNum >= 0 && stateNum < stateMap.length ? stateMap[stateNum] : null;
|
|
5087
|
+
const BLOCK_TIME_SECONDS = 2;
|
|
5088
|
+
const votingDelaySeconds = votingDelay != null ? Number(votingDelay) * BLOCK_TIME_SECONDS : null;
|
|
5089
|
+
const votingPeriodSeconds = votingPeriod != null ? Number(votingPeriod) * BLOCK_TIME_SECONDS : null;
|
|
5090
|
+
const formatSXXX = (val) => {
|
|
5091
|
+
if (val == null) return null;
|
|
5092
|
+
const num = Number(val) / 1e18;
|
|
5093
|
+
if (num >= 1e6) return `${(num / 1e6).toFixed(1)}M`;
|
|
5094
|
+
if (num >= 1e3) return `${(num / 1e3).toFixed(1)}K`;
|
|
5095
|
+
return num.toFixed(2);
|
|
5096
|
+
};
|
|
5097
|
+
const formatDuration = (seconds) => {
|
|
5098
|
+
if (seconds == null) return null;
|
|
5099
|
+
if (seconds < 60) return `${seconds} seconds`;
|
|
5100
|
+
if (seconds < 3600) return `${Math.round(seconds / 60)} minutes`;
|
|
5101
|
+
if (seconds < 86400) return `${(seconds / 3600).toFixed(1)} hours`;
|
|
5102
|
+
return `${(seconds / 86400).toFixed(1)} days`;
|
|
5103
|
+
};
|
|
5104
|
+
return {
|
|
5105
|
+
governor: addr,
|
|
5106
|
+
governorName: govName,
|
|
5107
|
+
proposalId: pid.toString(),
|
|
5108
|
+
state,
|
|
5109
|
+
stateNum: typeof stateNum === "number" ? stateNum : null,
|
|
5110
|
+
// Raw values (bigint as string for JSON serialization)
|
|
5111
|
+
votes: {
|
|
5112
|
+
for: forVotes.toString(),
|
|
5113
|
+
against: againstVotes.toString(),
|
|
5114
|
+
abstain: abstainVotes.toString(),
|
|
5115
|
+
total: totalVotes.toString()
|
|
5116
|
+
},
|
|
5117
|
+
quorum: quorum?.toString() || null,
|
|
5118
|
+
proposalThreshold: proposalThreshold?.toString() || null,
|
|
5119
|
+
snapshot: snapshot?.toString() || null,
|
|
5120
|
+
deadline: deadline?.toString() || null,
|
|
5121
|
+
votingDelay: votingDelay?.toString() || null,
|
|
5122
|
+
votingPeriod: votingPeriod?.toString() || null,
|
|
5123
|
+
// Computed status
|
|
5124
|
+
quorumMet,
|
|
5125
|
+
quorumProgress,
|
|
5126
|
+
// percentage (0-100+)
|
|
5127
|
+
passing: forVotes > againstVotes,
|
|
5128
|
+
// Formatted for display
|
|
5129
|
+
formatted: {
|
|
5130
|
+
forVotes: formatSXXX(forVotes),
|
|
5131
|
+
againstVotes: formatSXXX(againstVotes),
|
|
5132
|
+
abstainVotes: formatSXXX(abstainVotes),
|
|
5133
|
+
totalVotes: formatSXXX(totalVotes),
|
|
5134
|
+
quorum: formatSXXX(quorum),
|
|
5135
|
+
proposalThreshold: formatSXXX(proposalThreshold),
|
|
5136
|
+
votingDelay: formatDuration(votingDelaySeconds),
|
|
5137
|
+
votingPeriod: formatDuration(votingPeriodSeconds)
|
|
5138
|
+
},
|
|
5139
|
+
// Plain language summary
|
|
5140
|
+
summary: {
|
|
5141
|
+
quorumStatus: quorum != null ? quorumMet ? `Quorum reached (${formatSXXX(forVotes)} of ${formatSXXX(quorum)} SXXX required)` : `${formatSXXX(forVotes)} of ${formatSXXX(quorum)} SXXX needed for quorum (${quorumProgress?.toFixed(1)}%)` : "Quorum information unavailable",
|
|
5142
|
+
voteStatus: `${formatSXXX(forVotes)} SXXX for, ${formatSXXX(againstVotes)} SXXX against`,
|
|
5143
|
+
outcome: forVotes > againstVotes ? "Currently passing" : forVotes < againstVotes ? "Currently failing" : "Tied",
|
|
5144
|
+
votingPeriod: votingPeriodSeconds ? `Voting period: ${formatDuration(votingPeriodSeconds)}` : null
|
|
5145
|
+
}
|
|
5146
|
+
};
|
|
5147
|
+
}
|
|
5031
5148
|
module2.exports = {
|
|
5032
5149
|
getGovernorInfo,
|
|
5033
5150
|
getProposal,
|
|
5151
|
+
getProposalVotingStatus,
|
|
5034
5152
|
listProposals,
|
|
5035
5153
|
getProposalMetadata,
|
|
5036
5154
|
hashDescription,
|
package/package.json
CHANGED