跳转到主要内容

概述

Council 选举完成后,Council 成员可以创建提案。所有代币持有者可以通过锁定代币对提案投票。投票期结束后,结果被结算,胜出选项被确定。

治理周期

治理以周期运作,分为两个阶段:

读取治理状态

const council = new ethers.Contract(councilAddress, CouncilV1ABI, provider);

const state = await council.getCouncilState(tokenAddress);

console.log("阶段:", state.governancePhase); // 0=空闲, 1=提案, 2=投票
console.log("提案阶段截止:", new Date(Number(state.proposalPhaseEnd) * 1000));
console.log("投票阶段截止:", new Date(Number(state.votingPhaseEnd) * 1000));
console.log("当前提案 ID:", state.currentProposalId.toString());
console.log("国库:", ethers.formatEther(state.treasuryBalance));

对提案投票

投票前,必须先 approve Council 合约转移你的代币。
const tokenContract = new ethers.Contract(tokenAddress, [
  "function approve(address spender, uint256 amount) returns (bool)",
], signer);

const council = new ethers.Contract(councilAddress, CouncilV1ABI, signer);

// 1. 授权代币
const amount = ethers.parseEther("10000");
await (await tokenContract.approve(councilAddress, amount)).wait();

// 2. 对提案投票
// target: 通用提案使用 address(0)
// optionIndex: 你要投票的选项索引
// amount: 分配给该选项的代币数量
const votes = [
  {
    target: ethers.ZeroAddress,
    optionIndex: 0,  // 第一个选项
    amount: ethers.parseEther("10000"),
  },
];

const proposalId = 1; // 链上提案 ID
const tx = await council.voteProposal(tokenAddress, proposalId, votes);
await tx.wait();
你可以在一次交易中将代币分配给多个选项。

查看提案详情

// 获取提案信息
const proposal = await council.getProposal(tokenAddress, proposalId);

console.log("开始:", new Date(Number(proposal.startTime) * 1000));
console.log("结束:", new Date(Number(proposal.endTime) * 1000));
console.log("已结算:", proposal.finalized);
console.log("类型:", proposal.proposalType); // 0=通用, 1=税费
console.log("选项:", proposal.optionCodes);
console.log("胜出选项:", proposal.winningOption.toString());

// 获取每个选项的得票数
const optionVotes = await council.getProposalOptionVotes(tokenAddress, proposalId);
optionVotes.forEach((votes, i) => {
  console.log(`选项 ${i}: ${ethers.formatEther(votes)} 票`);
});

// 获取自己的投票
const myVotes = await council.getVoterOptionVotes(tokenAddress, proposalId, myAddress);

// 查看锁定金额(提案结束后可领回)
const locked = await council.getVoterLockedAmount(tokenAddress, proposalId, myAddress);

投票结束后领回代币

投票期结束后:
// 第一个调用者触发结算 + 领回
// 后续调用者直接领回代币
const tx = await council.claimProposalTokens(tokenAddress, proposalId);
await tx.wait();

税费配置

税费提案设置代币的交易税。税费提案结算并应用胜出选项后:
const taxConfig = await council.getTaxConfig(tokenAddress);

console.log("税率:", taxConfig.rate.toString()); // 基点
console.log("用途:", taxConfig.purpose); // 0=无, 1=销毁, 2=转账, 3=国库
console.log("目标:", taxConfig.target);

// 检查地址是否免税
const exempt = await council.isTaxExempt(tokenAddress, someAddress);
用途说明
None0无税
Burn1税收代币被销毁
Transfer2税收代币发送到指定地址
CouncilTreasury3税收代币进入 Council 国库

事件

事件说明
ProposalCreated(token, proposalId, nonce, proposer, proposalType, optionCodes, endTime)提案创建
ProposalFinalized(token, proposalId, winningOption, winningVotes)提案结算