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);
| 用途 | 值 | 说明 |
|---|
| None | 0 | 无税 |
| Burn | 1 | 税收代币被销毁 |
| Transfer | 2 | 税收代币发送到指定地址 |
| CouncilTreasury | 3 | 税收代币进入 Council 国库 |
| 事件 | 说明 |
|---|
ProposalCreated(token, proposalId, nonce, proposer, proposalType, optionCodes, endTime) | 提案创建 |
ProposalFinalized(token, proposalId, winningOption, winningVotes) | 提案结算 |