概述
Governance 预编译为 Cosmos SDK 的x/gov 模块提供了全面访问能力,使智能合约能够参与链上治理。它支持提交和取消提案、存入资金以及进行投票。此外,它还提供了丰富的查询能力,用于获取提案、投票、存款以及整体治理参数的信息。
预编译地址:0x0000000000000000000000000000000000000805
相关模块:x/gov
Gas 成本
Gas 成本为近似值,可能会因提案复杂度和链配置而有所不同。
| 方法 | Gas 成本 |
|---|---|
| 交易 | 2000 + (30 × 输入字节数) |
| 查询 | 1000 + (3 × 输入字节数) |
交易方法
submitProposal
提交一个新的治理提案。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceExample {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
struct Coin {
string denom;
uint256 amount;
}
event ProposalSubmitted(address indexed proposer, uint64 indexed proposalId);
function submitProposal(bytes calldata jsonProposal, Coin[] calldata initialDeposit)
external
payable
returns (uint64 proposalId)
{
require(jsonProposal.length > 0, "Proposal cannot be empty");
require(initialDeposit.length > 0, "Initial deposit required");
// Call the governance precompile
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.call(
abi.encodeWithSignature(
"submitProposal(address,bytes,tuple(string,uint256)[])",
msg.sender,
jsonProposal,
initialDeposit
)
);
require(success, "Proposal submission failed");
proposalId = abi.decode(result, (uint64));
emit ProposalSubmitted(msg.sender, proposalId);
return proposalId;
}
// Helper function to create a coin struct
function createCoin(string memory denom, uint256 amount) external pure returns (Coin memory) {
return Coin({denom: denom, amount: amount});
}
}
vote
对处于活动状态的提案投出单个选票。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceExample {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
enum VoteOption {
Unspecified,
Yes,
Abstain,
No,
NoWithVeto
}
event VoteCast(address indexed voter, uint64 indexed proposalId, VoteOption option);
function vote(uint64 proposalId, VoteOption option, string calldata metadata) external {
require(proposalId > 0, "Invalid proposal ID");
require(option != VoteOption.Unspecified, "Must specify a vote option");
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.call(
abi.encodeWithSignature(
"vote(address,uint64,uint8,string)",
msg.sender,
proposalId,
uint8(option),
metadata
)
);
require(success, "Vote failed");
bool voteSuccess = abi.decode(result, (bool));
require(voteSuccess, "Vote was rejected");
emit VoteCast(msg.sender, proposalId, option);
}
// Convenience function to vote yes
function voteYes(uint64 proposalId) external {
this.vote(proposalId, VoteOption.Yes, "");
}
// Convenience function to vote no
function voteNo(uint64 proposalId) external {
this.vote(proposalId, VoteOption.No, "");
}
}
voteWeighted
投加权票,将投票权拆分到多个选项之间。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceWeightedVote {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
enum VoteOption {
Unspecified,
Yes,
Abstain,
No,
NoWithVeto
}
struct WeightedVoteOption {
VoteOption option;
string weight;
}
event WeightedVoteCast(
address indexed voter,
uint64 indexed proposalId,
WeightedVoteOption[] options
);
function voteWeighted(
uint64 proposalId,
WeightedVoteOption[] calldata options,
string calldata metadata
) external returns (bool success) {
require(proposalId > 0, "Invalid proposal ID");
require(options.length > 0, "Must provide vote options");
// Validate that weights sum to 1.0 (represented as "1.000000000000000000")
// This is just a basic check - in practice you'd want more robust validation
(bool callSuccess, bytes memory result) = GOVERNANCE_PRECOMPILE.call(
abi.encodeWithSignature(
"voteWeighted(address,uint64,tuple(uint8,string)[],string)",
msg.sender,
proposalId,
options,
metadata
)
);
require(callSuccess, "Weighted vote failed");
success = abi.decode(result, (bool));
require(success, "Weighted vote was rejected");
emit WeightedVoteCast(msg.sender, proposalId, options);
return success;
}
// Helper function to create a split vote (e.g., 70% Yes, 30% Abstain)
function voteSplit(
uint64 proposalId,
uint256 yesPercent,
uint256 abstainPercent
) external returns (bool) {
require(yesPercent + abstainPercent == 100, "Percentages must sum to 100");
WeightedVoteOption[] memory options = new WeightedVoteOption[](2);
// Convert percentages to decimal weights (e.g., 70% = "0.700000000000000000")
options[0] = WeightedVoteOption({
option: VoteOption.Yes,
weight: string(abi.encodePacked("0.", _padPercentage(yesPercent)))
});
options[1] = WeightedVoteOption({
option: VoteOption.Abstain,
weight: string(abi.encodePacked("0.", _padPercentage(abstainPercent)))
});
return voteWeighted(proposalId, options, "Split vote");
}
// Helper function to pad percentage to 18 decimal places
function _padPercentage(uint256 percent) internal pure returns (string memory) {
require(percent <= 100, "Percent cannot exceed 100");
if (percent == 100) return "000000000000000000"; // Special case for 100%
// This is a simplified version - in practice you'd want more robust decimal handling
string memory percentStr = _toString(percent);
if (percent < 10) {
return string(abi.encodePacked("0", percentStr, "0000000000000000"));
} else {
return string(abi.encodePacked(percentStr, "0000000000000000"));
}
}
function _toString(uint256 value) internal pure returns (string memory) {
if (value == 0) return "0";
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
}
deposit
在存款期内向提案追加资金。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceExample {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
struct Coin {
string denom;
uint256 amount;
}
event DepositMade(address indexed depositor, uint64 indexed proposalId, uint256 amount);
function deposit(uint64 proposalId, Coin[] calldata amount) external payable {
require(proposalId > 0, "Invalid proposal ID");
require(amount.length > 0, "Deposit amount required");
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.call{value: msg.value}(
abi.encodeWithSignature(
"deposit(address,uint64,tuple(string,uint256)[])",
msg.sender,
proposalId,
amount
)
);
require(success, "Deposit failed");
bool depositSuccess = abi.decode(result, (bool));
require(depositSuccess, "Deposit was rejected");
// Calculate total deposited amount for event
uint256 totalAmount = 0;
for (uint i = 0; i < amount.length; i++) {
totalAmount += amount[i].amount;
}
emit DepositMade(msg.sender, proposalId, totalAmount);
}
// Convenience function to deposit native tokens
function depositNative(uint64 proposalId, uint256 amount, string memory denom) external payable {
require(msg.value >= amount, "Insufficient value sent");
Coin[] memory coins = new Coin[](1);
coins[0] = Coin({denom: denom, amount: amount});
this.deposit{value: amount}(proposalId, coins);
}
}
cancelProposal
取消一个仍处于存款期内的提案。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceCancelProposal {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
event ProposalCanceled(address indexed proposer, uint64 indexed proposalId, bool success);
function cancelProposal(uint64 proposalId) external returns (bool success) {
require(proposalId > 0, "Invalid proposal ID");
(bool callSuccess, bytes memory result) = GOVERNANCE_PRECOMPILE.call(
abi.encodeWithSignature("cancelProposal(address,uint64)", msg.sender, proposalId)
);
require(callSuccess, "Cancel proposal call failed");
success = abi.decode(result, (bool));
emit ProposalCanceled(msg.sender, proposalId, success);
return success;
}
// Function to safely cancel a proposal with additional checks
function safeCancelProposal(uint64 proposalId) external returns (bool success) {
// First, check if the proposal exists and can be canceled
// Note: In practice, you'd want to call getProposal first to verify status
success = cancelProposal(proposalId);
require(success, "Proposal cancellation failed - check if you're the proposer and proposal is in deposit period");
return success;
}
}
查询方法
getProposal
获取特定提案的详细信息。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceQueries {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
struct ProposalData {
uint64 id;
string[] messages;
uint32 status;
TallyResultData finalTallyResult;
uint64 submitTime;
uint64 depositEndTime;
Coin[] totalDeposit;
uint64 votingStartTime;
uint64 votingEndTime;
string metadata;
string title;
string summary;
address proposer;
}
struct TallyResultData {
string yes;
string abstain;
string no;
string noWithVeto;
}
struct Coin {
string denom;
uint256 amount;
}
function getProposal(uint64 proposalId) external view returns (ProposalData memory proposal) {
require(proposalId > 0, "无效的提案 ID");
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.staticcall(
abi.encodeWithSignature("getProposal(uint64)", proposalId)
);
require(success, "获取提案失败");
proposal = abi.decode(result, (ProposalData));
return proposal;
}
// 用于检查提案是否处于投票期的辅助函数
function isProposalInVotingPeriod(uint64 proposalId) external view returns (bool) {
ProposalData memory proposal = this.getProposal(proposalId);
return proposal.status == 2; // PROPOSAL_STATUS_VOTING_PERIOD
}
}
getProposals
获取经过筛选并分页的提案列表。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceProposalsList {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
struct PageRequest {
bytes key;
uint64 offset;
uint64 limit;
bool countTotal;
bool reverse;
}
struct PageResponse {
bytes nextKey;
uint64 total;
}
struct ProposalData {
uint64 id;
string[] messages;
uint32 status;
TallyResultData finalTallyResult;
uint64 submitTime;
uint64 depositEndTime;
Coin[] totalDeposit;
uint64 votingStartTime;
uint64 votingEndTime;
string metadata;
string title;
string summary;
address proposer;
}
struct TallyResultData {
string yes;
string abstain;
string no;
string noWithVeto;
}
struct Coin {
string denom;
uint256 amount;
}
function getProposals(
uint32 proposalStatus,
address voter,
address depositor,
PageRequest memory pagination
) external view returns (ProposalData[] memory proposals, PageResponse memory pageResponse) {
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.staticcall(
abi.encodeWithSignature(
"getProposals(uint32,address,address,(bytes,uint64,uint64,bool,bool))",
proposalStatus,
voter,
depositor,
pagination
)
);
require(success, "获取提案失败");
(proposals, pageResponse) = abi.decode(result, (ProposalData[], PageResponse));
return (proposals, pageResponse);
}
// 获取所有活跃提案(处于投票期)的辅助函数
function getActiveProposals(uint64 limit) external view returns (ProposalData[] memory) {
PageRequest memory pagination = PageRequest({
key: "",
offset: 0,
limit: limit,
countTotal: true,
reverse: false
});
uint32 votingStatus = 2; // PROPOSAL_STATUS_VOTING_PERIOD
(ProposalData[] memory proposals,) = this.getProposals(
votingStatus,
address(0),
address(0),
pagination
);
return proposals;
}
}
getTallyResult
获取提案当前或最终的投票计票结果。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceTally {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
struct TallyResultData {
string yes;
string abstain;
string no;
string noWithVeto;
}
function getTallyResult(uint64 proposalId) external view returns (TallyResultData memory tallyResult) {
require(proposalId > 0, "无效的提案 ID");
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.staticcall(
abi.encodeWithSignature("getTallyResult(uint64)", proposalId)
);
require(success, "获取计票结果失败");
tallyResult = abi.decode(result, (TallyResultData));
return tallyResult;
}
// 用于检查提案是否正在通过的辅助函数
function isProposalPassing(uint64 proposalId) external view returns (bool) {
TallyResultData memory tally = this.getTallyResult(proposalId);
// 将字符串票数转换为数字进行比较(简化示例)
// 在生产环境中,请使用合适的小数数学库
return keccak256(bytes(tally.yes)) > keccak256(bytes(tally.no));
}
}
getVote
获取某个提案中指定地址投出的票。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceVoteQuery {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
enum VoteOption {
Unspecified,
Yes,
Abstain,
No,
NoWithVeto
}
struct WeightedVoteOption {
VoteOption option;
string weight;
}
struct WeightedVote {
uint64 proposalId;
address voter;
WeightedVoteOption[] options;
string metadata;
}
function getVote(uint64 proposalId, address voter) external view returns (WeightedVote memory vote) {
require(proposalId > 0, "无效的提案 ID");
require(voter != address(0), "无效的投票者地址");
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.staticcall(
abi.encodeWithSignature("getVote(uint64,address)", proposalId, voter)
);
require(success, "获取投票失败");
vote = abi.decode(result, (WeightedVote));
return vote;
}
// 检查某个地址是否已投票的辅助函数
function hasVoted(uint64 proposalId, address voter) external view returns (bool) {
try this.getVote(proposalId, voter) returns (WeightedVote memory vote) {
return vote.options.length > 0;
} catch {
return false;
}
}
}
getVotes
获取某个提案上的全部投票,并支持分页。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceVotesList {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
struct PageRequest {
bytes key;
uint64 offset;
uint64 limit;
bool countTotal;
bool reverse;
}
struct PageResponse {
bytes nextKey;
uint64 total;
}
enum VoteOption {
Unspecified,
Yes,
Abstain,
No,
NoWithVeto
}
struct WeightedVoteOption {
VoteOption option;
string weight;
}
struct WeightedVote {
uint64 proposalId;
address voter;
WeightedVoteOption[] options;
string metadata;
}
function getVotes(
uint64 proposalId,
PageRequest memory pagination
) external view returns (WeightedVote[] memory votes, PageResponse memory pageResponse) {
require(proposalId > 0, "无效的提案 ID");
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.staticcall(
abi.encodeWithSignature(
"getVotes(uint64,(bytes,uint64,uint64,bool,bool))",
proposalId,
pagination
)
);
require(success, "获取投票列表失败");
(votes, pageResponse) = abi.decode(result, (WeightedVote[], PageResponse));
return (votes, pageResponse);
}
// 获取所有赞成票地址的辅助函数
function getYesVoters(uint64 proposalId, uint64 limit) external view returns (address[] memory) {
PageRequest memory pagination = PageRequest({
key: "",
offset: 0,
limit: limit,
countTotal: false,
reverse: false
});
(WeightedVote[] memory votes,) = this.getVotes(proposalId, pagination);
uint256 yesCount = 0;
for (uint i = 0; i < votes.length; i++) {
if (votes[i].options.length > 0 && votes[i].options[0].option == VoteOption.Yes) {
yesCount++;
}
}
address[] memory yesVoters = new address[](yesCount);
uint256 index = 0;
for (uint i = 0; i < votes.length; i++) {
if (votes[i].options.length > 0 && votes[i].options[0].option == VoteOption.Yes) {
yesVoters[index++] = votes[i].voter;
}
}
return yesVoters;
}
}
getDeposit
获取某个提案中指定存款人的存款信息。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceDepositQuery {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
struct Coin {
string denom;
uint256 amount;
}
struct DepositData {
uint64 proposalId;
address depositor;
Coin[] amount;
}
function getDeposit(uint64 proposalId, address depositor) external view returns (DepositData memory deposit) {
require(proposalId > 0, "无效的提案 ID");
require(depositor != address(0), "无效的存款人地址");
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.staticcall(
abi.encodeWithSignature("getDeposit(uint64,address)", proposalId, depositor)
);
require(success, "获取存款信息失败");
deposit = abi.decode(result, (DepositData));
return deposit;
}
// 获取特定 denom 的总存款金额的辅助函数
function getDepositAmount(uint64 proposalId, address depositor, string memory denom) external view returns (uint256) {
DepositData memory deposit = this.getDeposit(proposalId, depositor);
for (uint i = 0; i < deposit.amount.length; i++) {
if (keccak256(bytes(deposit.amount[i].denom)) == keccak256(bytes(denom))) {
return deposit.amount[i].amount;
}
}
return 0;
}
}
getDeposits
检索某个提案上的所有存款,并支持分页。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceDepositsList {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
struct PageRequest {
bytes key;
uint64 offset;
uint64 limit;
bool countTotal;
bool reverse;
}
struct PageResponse {
bytes nextKey;
uint64 total;
}
struct Coin {
string denom;
uint256 amount;
}
struct DepositData {
uint64 proposalId;
address depositor;
Coin[] amount;
}
function getDeposits(
uint64 proposalId,
PageRequest memory pagination
) external view returns (DepositData[] memory deposits, PageResponse memory pageResponse) {
require(proposalId > 0, "Invalid proposal ID");
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.staticcall(
abi.encodeWithSignature(
"getDeposits(uint64,(bytes,uint64,uint64,bool,bool))",
proposalId,
pagination
)
);
require(success, "Failed to get deposits");
(deposits, pageResponse) = abi.decode(result, (DepositData[], PageResponse));
return (deposits, pageResponse);
}
// Helper function to get all depositors
function getDepositors(uint64 proposalId, uint64 limit) external view returns (address[] memory) {
PageRequest memory pagination = PageRequest({
key: "",
offset: 0,
limit: limit,
countTotal: false,
reverse: false
});
(DepositData[] memory deposits,) = this.getDeposits(proposalId, pagination);
address[] memory depositors = new address[](deposits.length);
for (uint i = 0; i < deposits.length; i++) {
depositors[i] = deposits[i].depositor;
}
return depositors;
}
}
getParams
检索当前的治理参数。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceParams {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
struct Coin {
string denom;
uint256 amount;
}
struct Params {
int64 votingPeriod;
Coin[] minDeposit;
int64 maxDepositPeriod;
string quorum;
string threshold;
string vetoThreshold;
string minInitialDepositRatio;
string proposalCancelRatio;
string proposalCancelDest;
int64 expeditedVotingPeriod;
string expeditedThreshold;
Coin[] expeditedMinDeposit;
bool burnVoteQuorum;
bool burnProposalDepositPrevote;
bool burnVoteVeto;
string minDepositRatio;
}
function getParams() external view returns (Params memory params) {
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.staticcall(
abi.encodeWithSignature("getParams()")
);
require(success, "Failed to get params");
params = abi.decode(result, (Params));
return params;
}
// Helper function to get minimum deposit amount for a specific denom
function getMinDepositForDenom(string memory denom) external view returns (uint256) {
Params memory params = this.getParams();
for (uint i = 0; i < params.minDeposit.length; i++) {
if (keccak256(bytes(params.minDeposit[i].denom)) == keccak256(bytes(denom))) {
return params.minDeposit[i].amount;
}
}
return 0;
}
// Helper function to get voting period in seconds
function getVotingPeriodSeconds() external view returns (int64) {
Params memory params = this.getParams();
return params.votingPeriod;
}
}
getConstitution
检索当前的治理章程。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceConstitution {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
function getConstitution() external view returns (string memory constitution) {
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.staticcall(
abi.encodeWithSignature("getConstitution()")
);
require(success, "Failed to get constitution");
constitution = abi.decode(result, (string));
return constitution;
}
// Helper function to check if constitution is set
function hasConstitution() external view returns (bool) {
string memory constitution = this.getConstitution();
return bytes(constitution).length > 0;
}
// Helper function to get constitution length
function getConstitutionLength() external view returns (uint256) {
string memory constitution = this.getConstitution();
return bytes(constitution).length;
}
}
完整 Solidity 接口与 ABI
治理 Solidity 接口
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.8.17;
import "../common/Types.sol";
/// @dev IGov 合约地址。
address constant GOV_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000000805;
/// @dev IGov 合约实例。
IGov constant GOV_CONTRACT = IGov(GOV_PRECOMPILE_ADDRESS);
/**
* @dev VoteOption 枚举给定治理提案的有效投票选项。
*/
enum VoteOption {
// Unspecified 定义无操作投票选项。
Unspecified,
// Yes 定义赞成投票选项。
Yes,
// Abstain 定义弃权投票选项。
Abstain,
// No 定义反对投票选项。
No,
// NoWithVeto 定义带否决权的反对投票选项。
NoWithVeto
}
/// @dev WeightedVote 表示对治理提案的一次投票
struct WeightedVote {
uint64 proposalId;
address voter;
WeightedVoteOption[] options;
string metadata;
}
/// @dev WeightedVoteOption 表示一个加权投票选项
struct WeightedVoteOption {
VoteOption option;
string weight;
}
/// @dev DepositData 表示提案存款信息
struct DepositData {
uint64 proposalId;
address depositor;
Coin[] amount;
}
/// @dev TallyResultData 表示提案的计票结果
struct TallyResultData {
string yes;
string abstain;
string no;
string noWithVeto;
}
/// @dev ProposalData 表示一个治理提案
struct ProposalData {
uint64 id;
string[] messages;
uint32 status;
TallyResultData finalTallyResult;
uint64 submitTime;
uint64 depositEndTime;
Coin[] totalDeposit;
uint64 votingStartTime;
uint64 votingEndTime;
string metadata;
string title;
string summary;
address proposer;
}
/// @dev Params 定义治理参数
struct Params {
int64 votingPeriod;
Coin[] minDeposit;
int64 maxDepositPeriod;
string quorum;
string threshold;
string vetoThreshold;
string minInitialDepositRatio;
string proposalCancelRatio;
string proposalCancelDest;
int64 expeditedVotingPeriod;
string expeditedThreshold;
Coin[] expeditedMinDeposit;
bool burnVoteQuorum;
bool burnProposalDepositPrevote;
bool burnVoteVeto;
string minDepositRatio;
}
/// @author Evmos Core Team
/// @title Gov 预编译合约
/// @dev Solidity 合约通过该接口与 Gov 交互
interface IGov {
/// @dev SubmitProposal 定义提案提交时触发的事件。
/// @param proposer 提案人地址
/// @param proposalId 提案 ID
event SubmitProposal(address indexed proposer, uint64 proposalId);
/// @dev CancelProposal 定义提案取消时触发的事件。
/// @param proposer 提案人地址
/// @param proposalId 提案 ID
event CancelProposal(address indexed proposer, uint64 proposalId);
/// @dev Deposit 定义存款时触发的事件。
/// @param depositor 存款人地址
/// @param proposalId 提案 ID
/// @param amount 存款金额
event Deposit(address indexed depositor, uint64 proposalId, Coin[] amount);
/// @dev Vote 定义提案投票时触发的事件。
/// @param voter 投票人地址
/// @param proposalId 提案 ID
/// @param option 投票人的选项
event Vote(address indexed voter, uint64 proposalId, uint8 option);
/// @dev VoteWeighted 定义提案加权投票时触发的事件。
/// @param voter 投票人地址
/// @param proposalId 提案 ID
/// @param options 投票人的选项
event VoteWeighted(
address indexed voter,
uint64 proposalId,
WeightedVoteOption[] options
);
/// 交易
/// @notice submitProposal 从 protoJSON 文档创建新提案。
/// @dev submitProposal 定义提交提案的方法。
/// @param jsonProposal JSON 提案
/// @param deposit 提案的存款
/// @return proposalId 提案 ID
function submitProposal(
address proposer,
bytes calldata jsonProposal,
Coin[] calldata deposit
) external returns (uint64 proposalId);
/// @dev cancelProposal 定义取消提案的方法。
/// @param proposalId 提案 ID
/// @return success 交易是否成功
function cancelProposal(
address proposer,
uint64 proposalId
) external returns (bool success);
/// @dev deposit 定义为提案追加存款的方法。
/// @param proposalId 提案 ID
/// @param amount 存入金额
function deposit(
address depositor,
uint64 proposalId,
Coin[] calldata amount
) external returns (bool success);
/// @dev vote 定义对指定提案进行投票的方法。
/// @param voter 投票人地址
/// @param proposalId 提案 ID
/// @param option 投票人的选项
/// @param metadata 投票人发送的元数据
/// @return success 交易是否成功
function vote(
address voter,
uint64 proposalId,
VoteOption option,
string memory metadata
) external returns (bool success);
/// @dev voteWeighted 定义对指定提案进行加权投票的方法。
/// @param voter 投票人地址
/// @param proposalId 提案 ID
/// @param options 投票人的选项
/// @param metadata 投票人发送的元数据
/// @return success 交易是否成功
function voteWeighted(
address voter,
uint64 proposalId,
WeightedVoteOption[] calldata options,
string memory metadata
) external returns (bool success);
/// 查询
/// @dev getVote 返回单个投票人在
/// 给定 proposalId 下的投票。
/// @param proposalId 提案 ID
/// @param voter 该提案上的投票人
/// @return vote 投票人对该提案的投票
function getVote(
uint64 proposalId,
address voter
) external view returns (WeightedVote memory vote);
/// @dev getVotes 返回指定提案的所有投票。
/// @param proposalId 提案 ID
/// @param pagination 分页选项
/// @return votes 该提案的投票
/// @return pageResponse 分页信息
function getVotes(
uint64 proposalId,
PageRequest calldata pagination
)
external
view
returns (WeightedVote[] memory votes, PageResponse memory pageResponse);
/// @dev getDeposit 返回给定 proposalId 下单个存款人的存款。
/// @param proposalId 提案 ID
/// @param depositor 存款人地址
/// @return deposit 存款信息
function getDeposit(
uint64 proposalId,
address depositor
) external view returns (DepositData memory deposit);
/// @dev getDeposits 返回指定提案的所有存款。
/// @param proposalId 提案 ID
/// @param pagination 分页选项
/// @return deposits 该提案的存款
/// @return pageResponse 分页信息
function getDeposits(
uint64 proposalId,
PageRequest calldata pagination
)
external
view
returns (
DepositData[] memory deposits,
PageResponse memory pageResponse
);
/// @dev getTallyResult 返回提案的计票结果。
/// @param proposalId 提案 ID
/// @return tallyResult 提案的计票结果
function getTallyResult(
uint64 proposalId
) external view returns (TallyResultData memory tallyResult);
/// @dev getProposal 根据提案 ID 返回提案详情。
/// @param proposalId 提案 ID
/// @return proposal 提案数据
function getProposal(
uint64 proposalId
) external view returns (ProposalData memory proposal);
/// @dev getProposals 返回与状态匹配的提案。
/// @param proposalStatus 要筛选的提案状态
/// @param voter 用于筛选的投票人地址(如有)
/// @param depositor 用于筛选的存款人地址(如有)
/// @param pagination 分页配置
/// @return proposals 符合筛选条件的提案
/// @return pageResponse 分页信息
function getProposals(
uint32 proposalStatus,
address voter,
address depositor,
PageRequest calldata pagination
)
external
view
returns (
ProposalData[] memory proposals,
PageResponse memory pageResponse
);
/// @dev getParams 返回当前治理参数。
/// @return params 治理参数
function getParams() external view returns (Params memory params);
/// @dev getConstitution 返回当前宪章。
/// @return constitution 当前宪章
function getConstitution() external view returns (string memory constitution);
}
治理 ABI
{
"_format": "hh-sol-artifact-1",
"contractName": "IGov",
"sourceName": "solidity/precompiles/gov/IGov.sol",
"abi": [
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "proposer",
"type": "address"
},
{
"indexed": true,
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
}
],
"name": "CancelProposal",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "depositor",
"type": "address"
},
{
"indexed": true,
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"components": [
{
"internalType": "string",
"name": "denom",
"type": "string"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"indexed": false,
"internalType": "struct Coin[]",
"name": "amount",
"type": "tuple[]"
}
],
"name": "Deposit",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "proposer",
"type": "address"
},
{
"indexed": true,
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
}
],
"name": "SubmitProposal",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "voter",
"type": "address"
},
{
"indexed": true,
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"indexed": false,
"internalType": "uint8",
"name": "option",
"type": "uint8"
}
],
"name": "Vote",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "voter",
"type": "address"
},
{
"indexed": true,
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"components": [
{
"internalType": "enum VoteOption",
"name": "option",
"type": "uint8"
},
{
"internalType": "string",
"name": "weight",
"type": "string"
}
],
"indexed": false,
"internalType": "struct WeightedVoteOption[]",
"name": "options",
"type": "tuple[]"
}
],
"name": "VoteWeighted",
"type": "event"
},
{
"inputs": [
{
"internalType": "address",
"name": "proposer",
"type": "address"
},
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
}
],
"name": "cancelProposal",
"outputs": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "depositor",
"type": "address"
},
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"components": [
{
"internalType": "string",
"name": "denom",
"type": "string"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"internalType": "struct Coin[]",
"name": "amount",
"type": "tuple[]"
}
],
"name": "deposit",
"outputs": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "getConstitution",
"outputs": [
{
"internalType": "string",
"name": "constitution",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"internalType": "address",
"name": "depositor",
"type": "address"
}
],
"name": "getDeposit",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "depositor",
"type": "address"
},
{
"components": [
{
"internalType": "string",
"name": "denom",
"type": "string"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"internalType": "struct Coin[]",
"name": "amount",
"type": "tuple[]"
}
],
"internalType": "struct DepositData",
"name": "deposit",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"components": [
{
"internalType": "bytes",
"name": "key",
"type": "bytes"
},
{
"internalType": "uint64",
"name": "offset",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "limit",
"type": "uint64"
},
{
"internalType": "bool",
"name": "countTotal",
"type": "bool"
},
{
"internalType": "bool",
"name": "reverse",
"type": "bool"
}
],
"internalType": "struct PageRequest",
"name": "pagination",
"type": "tuple"
}
],
"name": "getDeposits",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "depositor",
"type": "address"
},
{
"components": [
{
"internalType": "string",
"name": "denom",
"type": "string"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"internalType": "struct Coin[]",
"name": "amount",
"type": "tuple[]"
}
],
"internalType": "struct DepositData[]",
"name": "deposits",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "bytes",
"name": "nextKey",
"type": "bytes"
},
{
"internalType": "uint64",
"name": "total",
"type": "uint64"
}
],
"internalType": "struct PageResponse",
"name": "pageResponse",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getParams",
"outputs": [
{
"components": [
{
"internalType": "string",
"name": "minDeposit",
"type": "string"
},
{
"internalType": "string",
"name": "maxDepositPeriod",
"type": "string"
},
{
"internalType": "string",
"name": "votingPeriod",
"type": "string"
},
{
"internalType": "string",
"name": "quorum",
"type": "string"
},
{
"internalType": "string",
"name": "threshold",
"type": "string"
},
{
"internalType": "string",
"name": "vetoThreshold",
"type": "string"
},
{
"internalType": "string",
"name": "minInitialDepositRatio",
"type": "string"
},
{
"internalType": "string",
"name": "proposalCancelRatio",
"type": "string"
},
{
"internalType": "string",
"name": "proposalCancelDest",
"type": "string"
},
{
"internalType": "string",
"name": "minDepositRatio",
"type": "string"
}
],
"internalType": "struct Params",
"name": "params",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
}
],
"name": "getProposal",
"outputs": [
{
"components": [
{
"internalType": "uint64",
"name": "id",
"type": "uint64"
},
{
"internalType": "address",
"name": "proposer",
"type": "address"
},
{
"internalType": "string",
"name": "metadata",
"type": "string"
},
{
"internalType": "uint64",
"name": "submitTime",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "votingStartTime",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "votingEndTime",
"type": "uint64"
},
{
"internalType": "uint8",
"name": "status",
"type": "uint8"
},
{
"components": [
{
"internalType": "string",
"name": "yesCount",
"type": "string"
},
{
"internalType": "string",
"name": "abstainCount",
"type": "string"
},
{
"internalType": "string",
"name": "noCount",
"type": "string"
},
{
"internalType": "string",
"name": "noWithVetoCount",
"type": "string"
}
],
"internalType": "struct TallyResultData",
"name": "finalTallyResult",
"type": "tuple"
},
{
"components": [
{
"internalType": "string",
"name": "denom",
"type": "string"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"internalType": "struct Coin[]",
"name": "totalDeposit",
"type": "tuple[]"
},
{
"internalType": "string[]",
"name": "messages",
"type": "string[]"
}
],
"internalType": "struct ProposalData",
"name": "proposal",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "bytes",
"name": "key",
"type": "bytes"
},
{
"internalType": "uint64",
"name": "offset",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "limit",
"type": "uint64"
},
{
"internalType": "bool",
"name": "countTotal",
"type": "bool"
},
{
"internalType": "bool",
"name": "reverse",
"type": "bool"
}
],
"internalType": "struct PageRequest",
"name": "pagination",
"type": "tuple"
},
{
"internalType": "uint8",
"name": "proposalStatus",
"type": "uint8"
},
{
"internalType": "address",
"name": "voter",
"type": "address"
},
{
"internalType": "address",
"name": "depositor",
"type": "address"
}
],
"name": "getProposals",
"outputs": [
{
"components": [
{
"internalType": "uint64",
"name": "id",
"type": "uint64"
},
{
"internalType": "address",
"name": "proposer",
"type": "address"
},
{
"internalType": "string",
"name": "metadata",
"type": "string"
},
{
"internalType": "uint64",
"name": "submitTime",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "votingStartTime",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "votingEndTime",
"type": "uint64"
},
{
"internalType": "uint8",
"name": "status",
"type": "uint8"
},
{
"components": [
{
"internalType": "string",
"name": "yesCount",
"type": "string"
},
{
"internalType": "string",
"name": "abstainCount",
"type": "string"
},
{
"internalType": "string",
"name": "noCount",
"type": "string"
},
{
"internalType": "string",
"name": "noWithVetoCount",
"type": "string"
}
],
"internalType": "struct TallyResultData",
"name": "finalTallyResult",
"type": "tuple"
},
{
"components": [
{
"internalType": "string",
"name": "denom",
"type": "string"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"internalType": "struct Coin[]",
"name": "totalDeposit",
"type": "tuple[]"
},
{
"internalType": "string[]",
"name": "messages",
"type": "string[]"
}
],
"internalType": "struct ProposalData[]",
"name": "proposals",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "bytes",
"name": "nextKey",
"type": "bytes"
},
{
"internalType": "uint64",
"name": "total",
"type": "uint64"
}
],
"internalType": "struct PageResponse",
"name": "pageResponse",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
}
],
"name": "getTallyResult",
"outputs": [
{
"components": [
{
"internalType": "string",
"name": "yesCount",
"type": "string"
},
{
"internalType": "string",
"name": "abstainCount",
"type": "string"
},
{
"internalType": "string",
"name": "noCount",
"type": "string"
},
{
"internalType": "string",
"name": "noWithVetoCount",
"type": "string"
}
],
"internalType": "struct TallyResultData",
"name": "tally",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"internalType": "address",
"name": "voter",
"type": "address"
}
],
"name": "getVote",
"outputs": [
{
"components": [
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"internalType": "address",
"name": "voter",
"type": "address"
},
{
"components": [
{
"internalType": "uint8",
"name": "option",
"type": "uint8"
},
{
"internalType": "string",
"name": "weight",
"type": "string"
}
],
"internalType": "struct WeightedVoteOption[]",
"name": "options",
"type": "tuple[]"
},
{
"internalType": "string",
"name": "metadata",
"type": "string"
}
],
"internalType": "struct WeightedVote",
"name": "vote",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"components": [
{
"internalType": "bytes",
"name": "key",
"type": "bytes"
},
{
"internalType": "uint64",
"name": "offset",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "limit",
"type": "uint64"
},
{
"internalType": "bool",
"name": "countTotal",
"type": "bool"
},
{
"internalType": "bool",
"name": "reverse",
"type": "bool"
}
],
"internalType": "struct PageRequest",
"name": "pagination",
"type": "tuple"
}
],
"name": "getVotes",
"outputs": [
{
"components": [
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"internalType": "address",
"name": "voter",
"type": "address"
},
{
"components": [
{
"internalType": "uint8",
"name": "option",
"type": "uint8"
},
{
"internalType": "string",
"name": "weight",
"type": "string"
}
],
"internalType": "struct WeightedVoteOption[]",
"name": "options",
"type": "tuple[]"
},
{
"internalType": "string",
"name": "metadata",
"type": "string"
}
],
"internalType": "struct WeightedVote[]",
"name": "votes",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "bytes",
"name": "nextKey",
"type": "bytes"
},
{
"internalType": "uint64",
"name": "total",
"type": "uint64"
}
],
"internalType": "struct PageResponse",
"name": "pageResponse",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "proposer",
"type": "address"
},
{
"internalType": "bytes",
"name": "jsonProposal",
"type": "bytes"
},
{
"components": [
{
"internalType": "string",
"name": "denom",
"type": "string"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"internalType": "struct Coin[]",
"name": "deposit",
"type": "tuple[]"
}
],
"name": "submitProposal",
"outputs": [
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "voter",
"type": "address"
},
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"internalType": "enum VoteOption",
"name": "option",
"type": "uint8"
},
{
"internalType": "string",
"name": "metadata",
"type": "string"
}
],
"name": "vote",
"outputs": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "voter",
"type": "address"
},
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"components": [
{
"internalType": "enum VoteOption",
"name": "option",
"type": "uint8"
},
{
"internalType": "string",
"name": "weight",
"type": "string"
}
],
"internalType": "struct WeightedVoteOption[]",
"name": "options",
"type": "tuple[]"
},
{
"internalType": "string",
"name": "metadata",
"type": "string"
}
],
"name": "voteWeighted",
"outputs": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
}
]
}
Overview
The Governance precompile provides comprehensive access to the Cosmos SDK’sx/gov module, enabling smart contracts to participate in on-chain governance. It allows for submitting and canceling proposals, depositing funds, and casting votes. Additionally, it offers extensive query capabilities to retrieve information about proposals, votes, deposits, and overall governance parameters.
Precompile Address: 0x0000000000000000000000000000000000000805
Related Module: x/gov
Gas Costs
Gas costs are approximated and may vary based on proposal complexity and chain settings.
| Method | Gas Cost |
|---|---|
| Transactions | 2000 + (30 × bytes of input) |
| Queries | 1000 + (3 × bytes of input) |
Transaction Methods
submitProposal
Submits a new governance proposal.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceExample {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
struct Coin {
string denom;
uint256 amount;
}
event ProposalSubmitted(address indexed proposer, uint64 indexed proposalId);
function submitProposal(bytes calldata jsonProposal, Coin[] calldata initialDeposit)
external
payable
returns (uint64 proposalId)
{
require(jsonProposal.length > 0, "Proposal cannot be empty");
require(initialDeposit.length > 0, "Initial deposit required");
// Call the governance precompile
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.call(
abi.encodeWithSignature(
"submitProposal(address,bytes,tuple(string,uint256)[])",
msg.sender,
jsonProposal,
initialDeposit
)
);
require(success, "Proposal submission failed");
proposalId = abi.decode(result, (uint64));
emit ProposalSubmitted(msg.sender, proposalId);
return proposalId;
}
// Helper function to create a coin struct
function createCoin(string memory denom, uint256 amount) external pure returns (Coin memory) {
return Coin({denom: denom, amount: amount});
}
}
vote
Casts a single vote on an active proposal.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceExample {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
enum VoteOption {
Unspecified,
Yes,
Abstain,
No,
NoWithVeto
}
event VoteCast(address indexed voter, uint64 indexed proposalId, VoteOption option);
function vote(uint64 proposalId, VoteOption option, string calldata metadata) external {
require(proposalId > 0, "Invalid proposal ID");
require(option != VoteOption.Unspecified, "Must specify a vote option");
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.call(
abi.encodeWithSignature(
"vote(address,uint64,uint8,string)",
msg.sender,
proposalId,
uint8(option),
metadata
)
);
require(success, "Vote failed");
bool voteSuccess = abi.decode(result, (bool));
require(voteSuccess, "Vote was rejected");
emit VoteCast(msg.sender, proposalId, option);
}
// Convenience function to vote yes
function voteYes(uint64 proposalId) external {
this.vote(proposalId, VoteOption.Yes, "");
}
// Convenience function to vote no
function voteNo(uint64 proposalId) external {
this.vote(proposalId, VoteOption.No, "");
}
}
voteWeighted
Casts a weighted vote, splitting voting power across multiple options.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceWeightedVote {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
enum VoteOption {
Unspecified,
Yes,
Abstain,
No,
NoWithVeto
}
struct WeightedVoteOption {
VoteOption option;
string weight;
}
event WeightedVoteCast(
address indexed voter,
uint64 indexed proposalId,
WeightedVoteOption[] options
);
function voteWeighted(
uint64 proposalId,
WeightedVoteOption[] calldata options,
string calldata metadata
) external returns (bool success) {
require(proposalId > 0, "Invalid proposal ID");
require(options.length > 0, "Must provide vote options");
// Validate that weights sum to 1.0 (represented as "1.000000000000000000")
// This is just a basic check - in practice you'd want more robust validation
(bool callSuccess, bytes memory result) = GOVERNANCE_PRECOMPILE.call(
abi.encodeWithSignature(
"voteWeighted(address,uint64,tuple(uint8,string)[],string)",
msg.sender,
proposalId,
options,
metadata
)
);
require(callSuccess, "Weighted vote failed");
success = abi.decode(result, (bool));
require(success, "Weighted vote was rejected");
emit WeightedVoteCast(msg.sender, proposalId, options);
return success;
}
// Helper function to create a split vote (e.g., 70% Yes, 30% Abstain)
function voteSplit(
uint64 proposalId,
uint256 yesPercent,
uint256 abstainPercent
) external returns (bool) {
require(yesPercent + abstainPercent == 100, "Percentages must sum to 100");
WeightedVoteOption[] memory options = new WeightedVoteOption[](2);
// Convert percentages to decimal weights (e.g., 70% = "0.700000000000000000")
options[0] = WeightedVoteOption({
option: VoteOption.Yes,
weight: string(abi.encodePacked("0.", _padPercentage(yesPercent)))
});
options[1] = WeightedVoteOption({
option: VoteOption.Abstain,
weight: string(abi.encodePacked("0.", _padPercentage(abstainPercent)))
});
return voteWeighted(proposalId, options, "Split vote");
}
// Helper function to pad percentage to 18 decimal places
function _padPercentage(uint256 percent) internal pure returns (string memory) {
require(percent <= 100, "Percent cannot exceed 100");
if (percent == 100) return "000000000000000000"; // Special case for 100%
// This is a simplified version - in practice you'd want more robust decimal handling
string memory percentStr = _toString(percent);
if (percent < 10) {
return string(abi.encodePacked("0", percentStr, "0000000000000000"));
} else {
return string(abi.encodePacked(percentStr, "0000000000000000"));
}
}
function _toString(uint256 value) internal pure returns (string memory) {
if (value == 0) return "0";
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
}
deposit
Adds funds to a proposal’s deposit during the deposit period.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceExample {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
struct Coin {
string denom;
uint256 amount;
}
event DepositMade(address indexed depositor, uint64 indexed proposalId, uint256 amount);
function deposit(uint64 proposalId, Coin[] calldata amount) external payable {
require(proposalId > 0, "Invalid proposal ID");
require(amount.length > 0, "Deposit amount required");
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.call{value: msg.value}(
abi.encodeWithSignature(
"deposit(address,uint64,tuple(string,uint256)[])",
msg.sender,
proposalId,
amount
)
);
require(success, "Deposit failed");
bool depositSuccess = abi.decode(result, (bool));
require(depositSuccess, "Deposit was rejected");
// Calculate total deposited amount for event
uint256 totalAmount = 0;
for (uint i = 0; i < amount.length; i++) {
totalAmount += amount[i].amount;
}
emit DepositMade(msg.sender, proposalId, totalAmount);
}
// Convenience function to deposit native tokens
function depositNative(uint64 proposalId, uint256 amount, string memory denom) external payable {
require(msg.value >= amount, "Insufficient value sent");
Coin[] memory coins = new Coin[](1);
coins[0] = Coin({denom: denom, amount: amount});
this.deposit{value: amount}(proposalId, coins);
}
}
cancelProposal
Cancels a proposal that is still in its deposit period.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceCancelProposal {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
event ProposalCanceled(address indexed proposer, uint64 indexed proposalId, bool success);
function cancelProposal(uint64 proposalId) external returns (bool success) {
require(proposalId > 0, "Invalid proposal ID");
(bool callSuccess, bytes memory result) = GOVERNANCE_PRECOMPILE.call(
abi.encodeWithSignature("cancelProposal(address,uint64)", msg.sender, proposalId)
);
require(callSuccess, "Cancel proposal call failed");
success = abi.decode(result, (bool));
emit ProposalCanceled(msg.sender, proposalId, success);
return success;
}
// Function to safely cancel a proposal with additional checks
function safeCancelProposal(uint64 proposalId) external returns (bool success) {
// First, check if the proposal exists and can be canceled
// Note: In practice, you'd want to call getProposal first to verify status
success = cancelProposal(proposalId);
require(success, "Proposal cancellation failed - check if you're the proposer and proposal is in deposit period");
return success;
}
}
Query Methods
getProposal
Retrieves detailed information about a specific proposal.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceQueries {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
struct ProposalData {
uint64 id;
string[] messages;
uint32 status;
TallyResultData finalTallyResult;
uint64 submitTime;
uint64 depositEndTime;
Coin[] totalDeposit;
uint64 votingStartTime;
uint64 votingEndTime;
string metadata;
string title;
string summary;
address proposer;
}
struct TallyResultData {
string yes;
string abstain;
string no;
string noWithVeto;
}
struct Coin {
string denom;
uint256 amount;
}
function getProposal(uint64 proposalId) external view returns (ProposalData memory proposal) {
require(proposalId > 0, "Invalid proposal ID");
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.staticcall(
abi.encodeWithSignature("getProposal(uint64)", proposalId)
);
require(success, "Failed to get proposal");
proposal = abi.decode(result, (ProposalData));
return proposal;
}
// Helper function to check if proposal is in voting period
function isProposalInVotingPeriod(uint64 proposalId) external view returns (bool) {
ProposalData memory proposal = this.getProposal(proposalId);
return proposal.status == 2; // PROPOSAL_STATUS_VOTING_PERIOD
}
}
getProposals
Retrieves a filtered and paginated list of proposals.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceProposalsList {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
struct PageRequest {
bytes key;
uint64 offset;
uint64 limit;
bool countTotal;
bool reverse;
}
struct PageResponse {
bytes nextKey;
uint64 total;
}
struct ProposalData {
uint64 id;
string[] messages;
uint32 status;
TallyResultData finalTallyResult;
uint64 submitTime;
uint64 depositEndTime;
Coin[] totalDeposit;
uint64 votingStartTime;
uint64 votingEndTime;
string metadata;
string title;
string summary;
address proposer;
}
struct TallyResultData {
string yes;
string abstain;
string no;
string noWithVeto;
}
struct Coin {
string denom;
uint256 amount;
}
function getProposals(
uint32 proposalStatus,
address voter,
address depositor,
PageRequest memory pagination
) external view returns (ProposalData[] memory proposals, PageResponse memory pageResponse) {
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.staticcall(
abi.encodeWithSignature(
"getProposals(uint32,address,address,(bytes,uint64,uint64,bool,bool))",
proposalStatus,
voter,
depositor,
pagination
)
);
require(success, "Failed to get proposals");
(proposals, pageResponse) = abi.decode(result, (ProposalData[], PageResponse));
return (proposals, pageResponse);
}
// Helper function to get all active proposals (in voting period)
function getActiveProposals(uint64 limit) external view returns (ProposalData[] memory) {
PageRequest memory pagination = PageRequest({
key: "",
offset: 0,
limit: limit,
countTotal: true,
reverse: false
});
uint32 votingStatus = 2; // PROPOSAL_STATUS_VOTING_PERIOD
(ProposalData[] memory proposals,) = this.getProposals(
votingStatus,
address(0),
address(0),
pagination
);
return proposals;
}
}
getTallyResult
Retrieves the current or final vote tally for a proposal.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceTally {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
struct TallyResultData {
string yes;
string abstain;
string no;
string noWithVeto;
}
function getTallyResult(uint64 proposalId) external view returns (TallyResultData memory tallyResult) {
require(proposalId > 0, "Invalid proposal ID");
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.staticcall(
abi.encodeWithSignature("getTallyResult(uint64)", proposalId)
);
require(success, "Failed to get tally result");
tallyResult = abi.decode(result, (TallyResultData));
return tallyResult;
}
// Helper function to check if proposal is passing
function isProposalPassing(uint64 proposalId) external view returns (bool) {
TallyResultData memory tally = this.getTallyResult(proposalId);
// Convert string votes to numbers for comparison (simplified)
// In production, use proper decimal math libraries
return keccak256(bytes(tally.yes)) > keccak256(bytes(tally.no));
}
}
getVote
Retrieves the vote cast by a specific address on a proposal.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceVoteQuery {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
enum VoteOption {
Unspecified,
Yes,
Abstain,
No,
NoWithVeto
}
struct WeightedVoteOption {
VoteOption option;
string weight;
}
struct WeightedVote {
uint64 proposalId;
address voter;
WeightedVoteOption[] options;
string metadata;
}
function getVote(uint64 proposalId, address voter) external view returns (WeightedVote memory vote) {
require(proposalId > 0, "Invalid proposal ID");
require(voter != address(0), "Invalid voter address");
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.staticcall(
abi.encodeWithSignature("getVote(uint64,address)", proposalId, voter)
);
require(success, "Failed to get vote");
vote = abi.decode(result, (WeightedVote));
return vote;
}
// Helper function to check if an address has voted
function hasVoted(uint64 proposalId, address voter) external view returns (bool) {
try this.getVote(proposalId, voter) returns (WeightedVote memory vote) {
return vote.options.length > 0;
} catch {
return false;
}
}
}
getVotes
Retrieves all votes cast on a proposal, with pagination.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceVotesList {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
struct PageRequest {
bytes key;
uint64 offset;
uint64 limit;
bool countTotal;
bool reverse;
}
struct PageResponse {
bytes nextKey;
uint64 total;
}
enum VoteOption {
Unspecified,
Yes,
Abstain,
No,
NoWithVeto
}
struct WeightedVoteOption {
VoteOption option;
string weight;
}
struct WeightedVote {
uint64 proposalId;
address voter;
WeightedVoteOption[] options;
string metadata;
}
function getVotes(
uint64 proposalId,
PageRequest memory pagination
) external view returns (WeightedVote[] memory votes, PageResponse memory pageResponse) {
require(proposalId > 0, "Invalid proposal ID");
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.staticcall(
abi.encodeWithSignature(
"getVotes(uint64,(bytes,uint64,uint64,bool,bool))",
proposalId,
pagination
)
);
require(success, "Failed to get votes");
(votes, pageResponse) = abi.decode(result, (WeightedVote[], PageResponse));
return (votes, pageResponse);
}
// Helper function to get all Yes votes
function getYesVoters(uint64 proposalId, uint64 limit) external view returns (address[] memory) {
PageRequest memory pagination = PageRequest({
key: "",
offset: 0,
limit: limit,
countTotal: false,
reverse: false
});
(WeightedVote[] memory votes,) = this.getVotes(proposalId, pagination);
uint256 yesCount = 0;
for (uint i = 0; i < votes.length; i++) {
if (votes[i].options.length > 0 && votes[i].options[0].option == VoteOption.Yes) {
yesCount++;
}
}
address[] memory yesVoters = new address[](yesCount);
uint256 index = 0;
for (uint i = 0; i < votes.length; i++) {
if (votes[i].options.length > 0 && votes[i].options[0].option == VoteOption.Yes) {
yesVoters[index++] = votes[i].voter;
}
}
return yesVoters;
}
}
getDeposit
Retrieves deposit information for a specific depositor on a proposal.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceDepositQuery {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
struct Coin {
string denom;
uint256 amount;
}
struct DepositData {
uint64 proposalId;
address depositor;
Coin[] amount;
}
function getDeposit(uint64 proposalId, address depositor) external view returns (DepositData memory deposit) {
require(proposalId > 0, "Invalid proposal ID");
require(depositor != address(0), "Invalid depositor address");
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.staticcall(
abi.encodeWithSignature("getDeposit(uint64,address)", proposalId, depositor)
);
require(success, "Failed to get deposit");
deposit = abi.decode(result, (DepositData));
return deposit;
}
// Helper function to get total deposit amount for a specific denom
function getDepositAmount(uint64 proposalId, address depositor, string memory denom) external view returns (uint256) {
DepositData memory deposit = this.getDeposit(proposalId, depositor);
for (uint i = 0; i < deposit.amount.length; i++) {
if (keccak256(bytes(deposit.amount[i].denom)) == keccak256(bytes(denom))) {
return deposit.amount[i].amount;
}
}
return 0;
}
}
getDeposits
Retrieves all deposits made on a proposal, with pagination.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceDepositsList {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
struct PageRequest {
bytes key;
uint64 offset;
uint64 limit;
bool countTotal;
bool reverse;
}
struct PageResponse {
bytes nextKey;
uint64 total;
}
struct Coin {
string denom;
uint256 amount;
}
struct DepositData {
uint64 proposalId;
address depositor;
Coin[] amount;
}
function getDeposits(
uint64 proposalId,
PageRequest memory pagination
) external view returns (DepositData[] memory deposits, PageResponse memory pageResponse) {
require(proposalId > 0, "Invalid proposal ID");
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.staticcall(
abi.encodeWithSignature(
"getDeposits(uint64,(bytes,uint64,uint64,bool,bool))",
proposalId,
pagination
)
);
require(success, "Failed to get deposits");
(deposits, pageResponse) = abi.decode(result, (DepositData[], PageResponse));
return (deposits, pageResponse);
}
// Helper function to get all depositors
function getDepositors(uint64 proposalId, uint64 limit) external view returns (address[] memory) {
PageRequest memory pagination = PageRequest({
key: "",
offset: 0,
limit: limit,
countTotal: false,
reverse: false
});
(DepositData[] memory deposits,) = this.getDeposits(proposalId, pagination);
address[] memory depositors = new address[](deposits.length);
for (uint i = 0; i < deposits.length; i++) {
depositors[i] = deposits[i].depositor;
}
return depositors;
}
}
getParams
Retrieves current governance parameters.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceParams {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
struct Coin {
string denom;
uint256 amount;
}
struct Params {
int64 votingPeriod;
Coin[] minDeposit;
int64 maxDepositPeriod;
string quorum;
string threshold;
string vetoThreshold;
string minInitialDepositRatio;
string proposalCancelRatio;
string proposalCancelDest;
int64 expeditedVotingPeriod;
string expeditedThreshold;
Coin[] expeditedMinDeposit;
bool burnVoteQuorum;
bool burnProposalDepositPrevote;
bool burnVoteVeto;
string minDepositRatio;
}
function getParams() external view returns (Params memory params) {
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.staticcall(
abi.encodeWithSignature("getParams()")
);
require(success, "Failed to get params");
params = abi.decode(result, (Params));
return params;
}
// Helper function to get minimum deposit amount for a specific denom
function getMinDepositForDenom(string memory denom) external view returns (uint256) {
Params memory params = this.getParams();
for (uint i = 0; i < params.minDeposit.length; i++) {
if (keccak256(bytes(params.minDeposit[i].denom)) == keccak256(bytes(denom))) {
return params.minDeposit[i].amount;
}
}
return 0;
}
// Helper function to get voting period in seconds
function getVotingPeriodSeconds() external view returns (int64) {
Params memory params = this.getParams();
return params.votingPeriod;
}
}
getConstitution
Retrieves the current governance constitution.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract GovernanceConstitution {
address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000805;
function getConstitution() external view returns (string memory constitution) {
(bool success, bytes memory result) = GOVERNANCE_PRECOMPILE.staticcall(
abi.encodeWithSignature("getConstitution()")
);
require(success, "Failed to get constitution");
constitution = abi.decode(result, (string));
return constitution;
}
// Helper function to check if constitution is set
function hasConstitution() external view returns (bool) {
string memory constitution = this.getConstitution();
return bytes(constitution).length > 0;
}
// Helper function to get constitution length
function getConstitutionLength() external view returns (uint256) {
string memory constitution = this.getConstitution();
return bytes(constitution).length;
}
}
Full Solidity Interface & ABI
Governance Solidity Interface
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.8.17;
import "../common/Types.sol";
/// @dev The IGov contract's address.
address constant GOV_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000000805;
/// @dev The IGov contract's instance.
IGov constant GOV_CONTRACT = IGov(GOV_PRECOMPILE_ADDRESS);
/**
* @dev VoteOption enumerates the valid vote options for a given governance proposal.
*/
enum VoteOption {
// Unspecified defines a no-op vote option.
Unspecified,
// Yes defines a yes vote option.
Yes,
// Abstain defines an abstain vote option.
Abstain,
// No defines a no vote option.
No,
// NoWithVeto defines a no with veto vote option.
NoWithVeto
}
/// @dev WeightedVote represents a vote on a governance proposal
struct WeightedVote {
uint64 proposalId;
address voter;
WeightedVoteOption[] options;
string metadata;
}
/// @dev WeightedVoteOption represents a weighted vote option
struct WeightedVoteOption {
VoteOption option;
string weight;
}
/// @dev DepositData represents information about a deposit on a proposal
struct DepositData {
uint64 proposalId;
address depositor;
Coin[] amount;
}
/// @dev TallyResultData represents the tally result of a proposal
struct TallyResultData {
string yes;
string abstain;
string no;
string noWithVeto;
}
/// @dev ProposalData represents a governance proposal
struct ProposalData {
uint64 id;
string[] messages;
uint32 status;
TallyResultData finalTallyResult;
uint64 submitTime;
uint64 depositEndTime;
Coin[] totalDeposit;
uint64 votingStartTime;
uint64 votingEndTime;
string metadata;
string title;
string summary;
address proposer;
}
/// @dev Params defines the governance parameters
struct Params {
int64 votingPeriod;
Coin[] minDeposit;
int64 maxDepositPeriod;
string quorum;
string threshold;
string vetoThreshold;
string minInitialDepositRatio;
string proposalCancelRatio;
string proposalCancelDest;
int64 expeditedVotingPeriod;
string expeditedThreshold;
Coin[] expeditedMinDeposit;
bool burnVoteQuorum;
bool burnProposalDepositPrevote;
bool burnVoteVeto;
string minDepositRatio;
}
/// @author The Evmos Core Team
/// @title Gov Precompile Contract
/// @dev The interface through which solidity contracts will interact with Gov
interface IGov {
/// @dev SubmitProposal defines an Event emitted when a proposal is submitted.
/// @param proposer the address of the proposer
/// @param proposalId the proposal of id
event SubmitProposal(address indexed proposer, uint64 proposalId);
/// @dev CancelProposal defines an Event emitted when a proposal is canceled.
/// @param proposer the address of the proposer
/// @param proposalId the proposal of id
event CancelProposal(address indexed proposer, uint64 proposalId);
/// @dev Deposit defines an Event emitted when a deposit is made.
/// @param depositor the address of the depositor
/// @param proposalId the proposal of id
/// @param amount the amount of the deposit
event Deposit(address indexed depositor, uint64 proposalId, Coin[] amount);
/// @dev Vote defines an Event emitted when a proposal voted.
/// @param voter the address of the voter
/// @param proposalId the proposal of id
/// @param option the option for voter
event Vote(address indexed voter, uint64 proposalId, uint8 option);
/// @dev VoteWeighted defines an Event emitted when a proposal voted.
/// @param voter the address of the voter
/// @param proposalId the proposal of id
/// @param options the options for voter
event VoteWeighted(
address indexed voter,
uint64 proposalId,
WeightedVoteOption[] options
);
/// TRANSACTIONS
/// @notice submitProposal creates a new proposal from a protoJSON document.
/// @dev submitProposal defines a method to submit a proposal.
/// @param jsonProposal The JSON proposal
/// @param deposit The deposit for the proposal
/// @return proposalId The proposal id
function submitProposal(
address proposer,
bytes calldata jsonProposal,
Coin[] calldata deposit
) external returns (uint64 proposalId);
/// @dev cancelProposal defines a method to cancel a proposal.
/// @param proposalId The proposal id
/// @return success Whether the transaction was successful or not
function cancelProposal(
address proposer,
uint64 proposalId
) external returns (bool success);
/// @dev deposit defines a method to add a deposit to a proposal.
/// @param proposalId The proposal id
/// @param amount The amount to deposit
function deposit(
address depositor,
uint64 proposalId,
Coin[] calldata amount
) external returns (bool success);
/// @dev vote defines a method to add a vote on a specific proposal.
/// @param voter The address of the voter
/// @param proposalId the proposal of id
/// @param option the option for voter
/// @param metadata the metadata for voter send
/// @return success Whether the transaction was successful or not
function vote(
address voter,
uint64 proposalId,
VoteOption option,
string memory metadata
) external returns (bool success);
/// @dev voteWeighted defines a method to add a vote on a specific proposal.
/// @param voter The address of the voter
/// @param proposalId The proposal id
/// @param options The options for voter
/// @param metadata The metadata for voter send
/// @return success Whether the transaction was successful or not
function voteWeighted(
address voter,
uint64 proposalId,
WeightedVoteOption[] calldata options,
string memory metadata
) external returns (bool success);
/// QUERIES
/// @dev getVote returns the vote of a single voter for a
/// given proposalId.
/// @param proposalId The proposal id
/// @param voter The voter on the proposal
/// @return vote Voter's vote for the proposal
function getVote(
uint64 proposalId,
address voter
) external view returns (WeightedVote memory vote);
/// @dev getVotes Returns the votes for a specific proposal.
/// @param proposalId The proposal id
/// @param pagination The pagination options
/// @return votes The votes for the proposal
/// @return pageResponse The pagination information
function getVotes(
uint64 proposalId,
PageRequest calldata pagination
)
external
view
returns (WeightedVote[] memory votes, PageResponse memory pageResponse);
/// @dev getDeposit returns the deposit of a single depositor for a given proposalId.
/// @param proposalId The proposal id
/// @param depositor The address of the depositor
/// @return deposit The deposit information
function getDeposit(
uint64 proposalId,
address depositor
) external view returns (DepositData memory deposit);
/// @dev getDeposits returns all deposits for a specific proposal.
/// @param proposalId The proposal id
/// @param pagination The pagination options
/// @return deposits The deposits for the proposal
/// @return pageResponse The pagination information
function getDeposits(
uint64 proposalId,
PageRequest calldata pagination
)
external
view
returns (
DepositData[] memory deposits,
PageResponse memory pageResponse
);
/// @dev getTallyResult returns the tally result of a proposal.
/// @param proposalId The proposal id
/// @return tallyResult The tally result of the proposal
function getTallyResult(
uint64 proposalId
) external view returns (TallyResultData memory tallyResult);
/// @dev getProposal returns the proposal details based on proposal id.
/// @param proposalId The proposal id
/// @return proposal The proposal data
function getProposal(
uint64 proposalId
) external view returns (ProposalData memory proposal);
/// @dev getProposals returns proposals with matching status.
/// @param proposalStatus The proposal status to filter by
/// @param voter The voter address to filter by, if any
/// @param depositor The depositor address to filter by, if any
/// @param pagination The pagination config
/// @return proposals The proposals matching the filter criteria
/// @return pageResponse The pagination information
function getProposals(
uint32 proposalStatus,
address voter,
address depositor,
PageRequest calldata pagination
)
external
view
returns (
ProposalData[] memory proposals,
PageResponse memory pageResponse
);
/// @dev getParams returns the current governance parameters.
/// @return params The governance parameters
function getParams() external view returns (Params memory params);
/// @dev getConstitution returns the current constitution.
/// @return constitution The current constitution
function getConstitution() external view returns (string memory constitution);
}
Governance ABI
{
"_format": "hh-sol-artifact-1",
"contractName": "IGov",
"sourceName": "solidity/precompiles/gov/IGov.sol",
"abi": [
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "proposer",
"type": "address"
},
{
"indexed": true,
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
}
],
"name": "CancelProposal",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "depositor",
"type": "address"
},
{
"indexed": true,
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"components": [
{
"internalType": "string",
"name": "denom",
"type": "string"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"indexed": false,
"internalType": "struct Coin[]",
"name": "amount",
"type": "tuple[]"
}
],
"name": "Deposit",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "proposer",
"type": "address"
},
{
"indexed": true,
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
}
],
"name": "SubmitProposal",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "voter",
"type": "address"
},
{
"indexed": true,
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"indexed": false,
"internalType": "uint8",
"name": "option",
"type": "uint8"
}
],
"name": "Vote",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "voter",
"type": "address"
},
{
"indexed": true,
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"components": [
{
"internalType": "enum VoteOption",
"name": "option",
"type": "uint8"
},
{
"internalType": "string",
"name": "weight",
"type": "string"
}
],
"indexed": false,
"internalType": "struct WeightedVoteOption[]",
"name": "options",
"type": "tuple[]"
}
],
"name": "VoteWeighted",
"type": "event"
},
{
"inputs": [
{
"internalType": "address",
"name": "proposer",
"type": "address"
},
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
}
],
"name": "cancelProposal",
"outputs": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "depositor",
"type": "address"
},
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"components": [
{
"internalType": "string",
"name": "denom",
"type": "string"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"internalType": "struct Coin[]",
"name": "amount",
"type": "tuple[]"
}
],
"name": "deposit",
"outputs": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "getConstitution",
"outputs": [
{
"internalType": "string",
"name": "constitution",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"internalType": "address",
"name": "depositor",
"type": "address"
}
],
"name": "getDeposit",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "depositor",
"type": "address"
},
{
"components": [
{
"internalType": "string",
"name": "denom",
"type": "string"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"internalType": "struct Coin[]",
"name": "amount",
"type": "tuple[]"
}
],
"internalType": "struct DepositData",
"name": "deposit",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"components": [
{
"internalType": "bytes",
"name": "key",
"type": "bytes"
},
{
"internalType": "uint64",
"name": "offset",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "limit",
"type": "uint64"
},
{
"internalType": "bool",
"name": "countTotal",
"type": "bool"
},
{
"internalType": "bool",
"name": "reverse",
"type": "bool"
}
],
"internalType": "struct PageRequest",
"name": "pagination",
"type": "tuple"
}
],
"name": "getDeposits",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "depositor",
"type": "address"
},
{
"components": [
{
"internalType": "string",
"name": "denom",
"type": "string"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"internalType": "struct Coin[]",
"name": "amount",
"type": "tuple[]"
}
],
"internalType": "struct DepositData[]",
"name": "deposits",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "bytes",
"name": "nextKey",
"type": "bytes"
},
{
"internalType": "uint64",
"name": "total",
"type": "uint64"
}
],
"internalType": "struct PageResponse",
"name": "pageResponse",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getParams",
"outputs": [
{
"components": [
{
"internalType": "string",
"name": "minDeposit",
"type": "string"
},
{
"internalType": "string",
"name": "maxDepositPeriod",
"type": "string"
},
{
"internalType": "string",
"name": "votingPeriod",
"type": "string"
},
{
"internalType": "string",
"name": "quorum",
"type": "string"
},
{
"internalType": "string",
"name": "threshold",
"type": "string"
},
{
"internalType": "string",
"name": "vetoThreshold",
"type": "string"
},
{
"internalType": "string",
"name": "minInitialDepositRatio",
"type": "string"
},
{
"internalType": "string",
"name": "proposalCancelRatio",
"type": "string"
},
{
"internalType": "string",
"name": "proposalCancelDest",
"type": "string"
},
{
"internalType": "string",
"name": "minDepositRatio",
"type": "string"
}
],
"internalType": "struct Params",
"name": "params",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
}
],
"name": "getProposal",
"outputs": [
{
"components": [
{
"internalType": "uint64",
"name": "id",
"type": "uint64"
},
{
"internalType": "address",
"name": "proposer",
"type": "address"
},
{
"internalType": "string",
"name": "metadata",
"type": "string"
},
{
"internalType": "uint64",
"name": "submitTime",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "votingStartTime",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "votingEndTime",
"type": "uint64"
},
{
"internalType": "uint8",
"name": "status",
"type": "uint8"
},
{
"components": [
{
"internalType": "string",
"name": "yesCount",
"type": "string"
},
{
"internalType": "string",
"name": "abstainCount",
"type": "string"
},
{
"internalType": "string",
"name": "noCount",
"type": "string"
},
{
"internalType": "string",
"name": "noWithVetoCount",
"type": "string"
}
],
"internalType": "struct TallyResultData",
"name": "finalTallyResult",
"type": "tuple"
},
{
"components": [
{
"internalType": "string",
"name": "denom",
"type": "string"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"internalType": "struct Coin[]",
"name": "totalDeposit",
"type": "tuple[]"
},
{
"internalType": "string[]",
"name": "messages",
"type": "string[]"
}
],
"internalType": "struct ProposalData",
"name": "proposal",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "bytes",
"name": "key",
"type": "bytes"
},
{
"internalType": "uint64",
"name": "offset",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "limit",
"type": "uint64"
},
{
"internalType": "bool",
"name": "countTotal",
"type": "bool"
},
{
"internalType": "bool",
"name": "reverse",
"type": "bool"
}
],
"internalType": "struct PageRequest",
"name": "pagination",
"type": "tuple"
},
{
"internalType": "uint8",
"name": "proposalStatus",
"type": "uint8"
},
{
"internalType": "address",
"name": "voter",
"type": "address"
},
{
"internalType": "address",
"name": "depositor",
"type": "address"
}
],
"name": "getProposals",
"outputs": [
{
"components": [
{
"internalType": "uint64",
"name": "id",
"type": "uint64"
},
{
"internalType": "address",
"name": "proposer",
"type": "address"
},
{
"internalType": "string",
"name": "metadata",
"type": "string"
},
{
"internalType": "uint64",
"name": "submitTime",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "votingStartTime",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "votingEndTime",
"type": "uint64"
},
{
"internalType": "uint8",
"name": "status",
"type": "uint8"
},
{
"components": [
{
"internalType": "string",
"name": "yesCount",
"type": "string"
},
{
"internalType": "string",
"name": "abstainCount",
"type": "string"
},
{
"internalType": "string",
"name": "noCount",
"type": "string"
},
{
"internalType": "string",
"name": "noWithVetoCount",
"type": "string"
}
],
"internalType": "struct TallyResultData",
"name": "finalTallyResult",
"type": "tuple"
},
{
"components": [
{
"internalType": "string",
"name": "denom",
"type": "string"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"internalType": "struct Coin[]",
"name": "totalDeposit",
"type": "tuple[]"
},
{
"internalType": "string[]",
"name": "messages",
"type": "string[]"
}
],
"internalType": "struct ProposalData[]",
"name": "proposals",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "bytes",
"name": "nextKey",
"type": "bytes"
},
{
"internalType": "uint64",
"name": "total",
"type": "uint64"
}
],
"internalType": "struct PageResponse",
"name": "pageResponse",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
}
],
"name": "getTallyResult",
"outputs": [
{
"components": [
{
"internalType": "string",
"name": "yesCount",
"type": "string"
},
{
"internalType": "string",
"name": "abstainCount",
"type": "string"
},
{
"internalType": "string",
"name": "noCount",
"type": "string"
},
{
"internalType": "string",
"name": "noWithVetoCount",
"type": "string"
}
],
"internalType": "struct TallyResultData",
"name": "tally",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"internalType": "address",
"name": "voter",
"type": "address"
}
],
"name": "getVote",
"outputs": [
{
"components": [
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"internalType": "address",
"name": "voter",
"type": "address"
},
{
"components": [
{
"internalType": "uint8",
"name": "option",
"type": "uint8"
},
{
"internalType": "string",
"name": "weight",
"type": "string"
}
],
"internalType": "struct WeightedVoteOption[]",
"name": "options",
"type": "tuple[]"
},
{
"internalType": "string",
"name": "metadata",
"type": "string"
}
],
"internalType": "struct WeightedVote",
"name": "vote",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"components": [
{
"internalType": "bytes",
"name": "key",
"type": "bytes"
},
{
"internalType": "uint64",
"name": "offset",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "limit",
"type": "uint64"
},
{
"internalType": "bool",
"name": "countTotal",
"type": "bool"
},
{
"internalType": "bool",
"name": "reverse",
"type": "bool"
}
],
"internalType": "struct PageRequest",
"name": "pagination",
"type": "tuple"
}
],
"name": "getVotes",
"outputs": [
{
"components": [
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"internalType": "address",
"name": "voter",
"type": "address"
},
{
"components": [
{
"internalType": "uint8",
"name": "option",
"type": "uint8"
},
{
"internalType": "string",
"name": "weight",
"type": "string"
}
],
"internalType": "struct WeightedVoteOption[]",
"name": "options",
"type": "tuple[]"
},
{
"internalType": "string",
"name": "metadata",
"type": "string"
}
],
"internalType": "struct WeightedVote[]",
"name": "votes",
"type": "tuple[]"
},
{
"components": [
{
"internalType": "bytes",
"name": "nextKey",
"type": "bytes"
},
{
"internalType": "uint64",
"name": "total",
"type": "uint64"
}
],
"internalType": "struct PageResponse",
"name": "pageResponse",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "proposer",
"type": "address"
},
{
"internalType": "bytes",
"name": "jsonProposal",
"type": "bytes"
},
{
"components": [
{
"internalType": "string",
"name": "denom",
"type": "string"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"internalType": "struct Coin[]",
"name": "deposit",
"type": "tuple[]"
}
],
"name": "submitProposal",
"outputs": [
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "voter",
"type": "address"
},
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"internalType": "enum VoteOption",
"name": "option",
"type": "uint8"
},
{
"internalType": "string",
"name": "metadata",
"type": "string"
}
],
"name": "vote",
"outputs": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "voter",
"type": "address"
},
{
"internalType": "uint64",
"name": "proposalId",
"type": "uint64"
},
{
"components": [
{
"internalType": "enum VoteOption",
"name": "option",
"type": "uint8"
},
{
"internalType": "string",
"name": "weight",
"type": "string"
}
],
"internalType": "struct WeightedVoteOption[]",
"name": "options",
"type": "tuple[]"
},
{
"internalType": "string",
"name": "metadata",
"type": "string"
}
],
"name": "voteWeighted",
"outputs": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
}
]
}