Compare commits

...

2 Commits

Author SHA1 Message Date
62af38c79f
ability to release locked funds based on state
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
2026-02-19 19:04:04 +03:00
f878ae44dd
proposer vote for automatically
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
2026-02-18 18:24:57 +03:00
2 changed files with 105 additions and 16 deletions

View File

@ -73,7 +73,12 @@ contract GhostGovernor is
uint256 releaseAmount = lockedAmounts[proposalId]; uint256 releaseAmount = lockedAmounts[proposalId];
address proposer = proposalProposer(proposalId); address proposer = proposalProposer(proposalId);
if (releaseAmount > 0 && clock() > proposalDeadline(proposalId)) { bytes32 currentProposalState = _encodeStateBitmap(state(proposalId));
bytes32 activePendingMask =
_encodeStateBitmap(ProposalState.Pending) |
_encodeStateBitmap(ProposalState.Active);
if (releaseAmount > 0 && (currentProposalState & activePendingMask == 0)) {
lockedAmounts[proposalId] = 0; lockedAmounts[proposalId] = 0;
IERC20(address(token())).transfer(proposer, releaseAmount); IERC20(address(token())).transfer(proposer, releaseAmount);
return releaseAmount; return releaseAmount;
@ -137,6 +142,7 @@ contract GhostGovernor is
} }
proposalId = _propose(targets, values, calldatas, description, proposer); proposalId = _propose(targets, values, calldatas, description, proposer);
_countVote(proposalId, proposer, 1, proposerVotes, "");
lockedAmounts[proposalId] += proposerVotes; lockedAmounts[proposalId] += proposerVotes;
activeProposedLock = proposerVotes; activeProposedLock = proposerVotes;

View File

@ -168,10 +168,12 @@ contract GhostGovernorTest is Test {
assertEq(uint8(governor.state(proposalId)), uint8(IGovernor.ProposalState.Active)); assertEq(uint8(governor.state(proposalId)), uint8(IGovernor.ProposalState.Active));
_castVoteWrapper(proposalId, bob, 1, true, true); _castVoteWrapper(proposalId, bob, 1, true, true);
assertEq(uint8(governor.state(proposalId)), uint8(IGovernor.ProposalState.Active));
_castVoteWrapper(proposalId, carol, 1, true, true);
assertEq(uint8(governor.state(proposalId)), uint8(IGovernor.ProposalState.Succeeded)); assertEq(uint8(governor.state(proposalId)), uint8(IGovernor.ProposalState.Succeeded));
vm.expectRevert();
vm.prank(carol);
governor.castVote(proposalId, 0);
vm.expectRevert(); vm.expectRevert();
vm.prank(dave); vm.prank(dave);
governor.castVote(proposalId, 0); governor.castVote(proposalId, 0);
@ -219,16 +221,15 @@ contract GhostGovernorTest is Test {
assertEq(governor.lockedAmounts(proposalId), amount); assertEq(governor.lockedAmounts(proposalId), amount);
assertEq(ghst.balanceOf(alice), 0); assertEq(ghst.balanceOf(alice), 0);
_castVoteWrapper(proposalId, alice, 1, false, false);
(uint256 againstVotes, uint256 forVotes, uint256 abstainVotes) = governor.proposalVotes(proposalId); (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes) = governor.proposalVotes(proposalId);
assertEq(againstVotes, 0); assertEq(againstVotes, 0);
assertEq(forVotes, 0); assertEq(forVotes, amount);
assertEq(abstainVotes, 0); assertEq(abstainVotes, 0);
_castVoteWrapper(proposalId, bob, 1, true, true); _castVoteWrapper(proposalId, bob, 1, true, true);
(againstVotes, forVotes, abstainVotes) = governor.proposalVotes(proposalId); (againstVotes, forVotes, abstainVotes) = governor.proposalVotes(proposalId);
assertEq(againstVotes, 0); assertEq(againstVotes, 0);
assertEq(forVotes, 2 * amount); assertEq(forVotes, 3 * amount);
assertEq(abstainVotes, 0); assertEq(abstainVotes, 0);
assertEq(ghst.balanceOf(alice), 0); assertEq(ghst.balanceOf(alice), 0);
@ -254,7 +255,7 @@ contract GhostGovernorTest is Test {
(proposalId,,,,) = _proposeDummy(bob, 420); (proposalId,,,,) = _proposeDummy(bob, 420);
_waitForActive(proposalId); _waitForActive(proposalId);
_castVoteWrapper(proposalId, alice, 1, false, true); _castVoteWrapper(proposalId, alice, 1, true, true);
_castVoteWrapper(proposalId, carol, 1, true, true); _castVoteWrapper(proposalId, carol, 1, true, true);
vm.roll(block.number + 3); vm.roll(block.number + 3);
@ -267,13 +268,6 @@ contract GhostGovernorTest is Test {
assertEq(ghst.balanceOf(bob), 0); assertEq(ghst.balanceOf(bob), 0);
assertEq(ghst.balanceOf(carol), 0); assertEq(ghst.balanceOf(carol), 0);
vm.prank(bob);
assertEq(governor.releaseLocked(proposalId), 0);
assertEq(governor.lockedAmounts(proposalId), 2 * amount);
assertEq(ghst.balanceOf(bob), 0);
vm.roll(governor.proposalDeadline(proposalId) + 1);
vm.prank(bob); vm.prank(bob);
assertEq(governor.releaseLocked(proposalId), 2 * amount); assertEq(governor.releaseLocked(proposalId), 2 * amount);
assertEq(governor.lockedAmounts(proposalId), 0); assertEq(governor.lockedAmounts(proposalId), 0);
@ -375,9 +369,9 @@ contract GhostGovernorTest is Test {
assertEq(governor.voteOf(proposalId, eve), 0); assertEq(governor.voteOf(proposalId, eve), 0);
vm.roll(governor.proposalDeadline(proposalId)); vm.roll(governor.proposalDeadline(proposalId));
_castVoteWrapper(proposalId, bob, 1, false, false); _castVoteWrapper(proposalId, bob, 1, false, true);
vm.roll(governor.proposalDeadline(proposalId)); vm.roll(governor.proposalDeadline(proposalId));
_castVoteWrapper(proposalId, carol, 0, false, false); _castVoteWrapper(proposalId, carol, 0, true, false);
vm.roll(governor.proposalDeadline(proposalId)); vm.roll(governor.proposalDeadline(proposalId));
_castVoteWrapper(proposalId, dave, 1, true, false); _castVoteWrapper(proposalId, dave, 1, true, false);
vm.roll(governor.proposalDeadline(proposalId)); vm.roll(governor.proposalDeadline(proposalId));
@ -492,6 +486,95 @@ contract GhostGovernorTest is Test {
assertEq(ghst.totalSupply(), 200); assertEq(ghst.totalSupply(), 200);
} }
function test_proposeAutoForVote() public {
vm.startPrank(init);
ghst.mint(alice, PROPOSAL_THRESHOLD);
vm.stopPrank();
vm.roll(block.number + 1);
(uint256 proposalId,,,,) = _proposeDummy(alice, 69);
(uint256 againstVotes, uint256 forVotes, uint256 abstainVotes) = governor.proposalVotes(proposalId);
assertEq(forVotes, PROPOSAL_THRESHOLD);
assertEq(againstVotes, 0);
assertEq(abstainVotes, 0);
vm.roll(block.number + 1);
vm.expectRevert();
vm.prank(alice);
governor.castVote(proposalId, 1);
}
function test_releaseAfterDefeated() public {
vm.startPrank(init);
ghst.mint(alice, PROPOSAL_THRESHOLD);
ghst.mint(bob, PROPOSAL_THRESHOLD);
ghst.mint(carol, PROPOSAL_THRESHOLD);
vm.stopPrank();
vm.roll(block.number + 1);
(uint256 proposalId,,,,) = _proposeDummy(alice, 69);
assertEq(governor.releaseLocked(proposalId), 0);
assertEq(ghst.balanceOf(alice), 0);
assertEq(ghst.balanceOf(address(governor)), PROPOSAL_THRESHOLD);
_waitForActive(proposalId);
_castVoteWrapper(proposalId, bob, 0, true, false);
_castVoteWrapper(proposalId, carol, 0, true, false);
assertEq(uint8(governor.state(proposalId)), uint8(IGovernor.ProposalState.Defeated));
assertEq(governor.releaseLocked(proposalId), PROPOSAL_THRESHOLD);
assertEq(ghst.balanceOf(alice), PROPOSAL_THRESHOLD);
assertEq(ghst.balanceOf(address(governor)), 0);
}
function test_releaseAfterSucceeded() public {
vm.startPrank(init);
ghst.mint(alice, PROPOSAL_THRESHOLD);
ghst.mint(bob, PROPOSAL_THRESHOLD);
ghst.mint(carol, PROPOSAL_THRESHOLD);
vm.stopPrank();
vm.roll(block.number + 1);
(uint256 proposalId,,,,) = _proposeDummy(alice, 69);
assertEq(governor.releaseLocked(proposalId), 0);
assertEq(ghst.balanceOf(alice), 0);
assertEq(ghst.balanceOf(address(governor)), PROPOSAL_THRESHOLD);
_waitForActive(proposalId);
_castVoteWrapper(proposalId, bob, 1, true, true);
assertEq(uint8(governor.state(proposalId)), uint8(IGovernor.ProposalState.Succeeded));
assertEq(governor.releaseLocked(proposalId), PROPOSAL_THRESHOLD);
assertEq(ghst.balanceOf(alice), PROPOSAL_THRESHOLD);
assertEq(ghst.balanceOf(address(governor)), 0);
}
function test_releaseAfterDeadline() public {
vm.startPrank(init);
ghst.mint(alice, PROPOSAL_THRESHOLD);
ghst.mint(bob, 420 * PROPOSAL_THRESHOLD);
vm.stopPrank();
vm.roll(block.number + 1);
(uint256 proposalId,,,,) = _proposeDummy(alice, 69);
assertEq(governor.releaseLocked(proposalId), 0);
assertEq(ghst.balanceOf(alice), 0);
assertEq(ghst.balanceOf(address(governor)), PROPOSAL_THRESHOLD);
_waitForActive(proposalId);
vm.roll(block.number + governor.proposalDeadline(proposalId));
assertEq(uint8(governor.state(proposalId)), uint8(IGovernor.ProposalState.Defeated));
assertEq(governor.releaseLocked(proposalId), PROPOSAL_THRESHOLD);
assertEq(ghst.balanceOf(alice), PROPOSAL_THRESHOLD);
assertEq(ghst.balanceOf(address(governor)), 0);
}
function _proposeDummy(address who, uint256 index) function _proposeDummy(address who, uint256 index)
private private
returns ( returns (