From 9bba721652a2be80637aaa3970faf092bb604125 Mon Sep 17 00:00:00 2001 From: Felipe Novaes F Rocha Date: Wed, 27 Dec 2023 02:11:10 -0300 Subject: [PATCH] :bug: fix stakedAmount updates :bug: fix threshold formula :sparkles: created better constants for testing :test_tube: 2 new tests, totalStaked and threshold --- pkg/contracts/src/CVStrategy.sol | 21 +++- pkg/contracts/src/RegistryGardens.sol | 2 +- pkg/contracts/test/CVStrategyTest.t.sol | 123 +++++++++++++++++++++--- 3 files changed, 125 insertions(+), 21 deletions(-) diff --git a/pkg/contracts/src/CVStrategy.sol b/pkg/contracts/src/CVStrategy.sol index 7080d2132..2ba989bbd 100644 --- a/pkg/contracts/src/CVStrategy.sol +++ b/pkg/contracts/src/CVStrategy.sol @@ -442,8 +442,15 @@ contract CVStrategy is BaseStrategy, IWithdrawMember { uint256 stakedAmount = convertPctToTokens(stakedPointsPct); console.log("stakedAmount", stakedAmount); proposal.voterStake[_sender] = stakedAmount; - proposal.stakedAmount += proposal.voterStake[_sender]; - + // proposal.stakedAmount += stakedAmount; + // uint256 diff =_diffStakedTokens(previousStakedAmount, stakedAmount); + if (previousStakedAmount <= stakedAmount) { + totalStaked += stakedAmount - previousStakedAmount; + proposal.stakedAmount += stakedAmount - previousStakedAmount; + } else { + totalStaked -= previousStakedAmount - stakedAmount; + proposal.stakedAmount -= previousStakedAmount - stakedAmount; + } //@todo: should emit event if (proposal.blockLast == 0) { proposal.blockLast = block.number; @@ -512,7 +519,7 @@ contract CVStrategy is BaseStrategy, IWithdrawMember { uint256 funds = poolAmount; // require(maxRatio.mul(funds) > _requestedAmount.mul(D), ERROR_AMOUNT_OVER_MAX_RATIO); // console.log("maxRatio", maxRatio); - // console.log("funds", funds); + // console.log("funds/poolAmount", funds); // console.log("_requestedAmount", _requestedAmount); // console.log("D", D); // console.log("maxRatio * funds", maxRatio * funds); @@ -530,7 +537,10 @@ contract CVStrategy is BaseStrategy, IWithdrawMember { // _threshold = // ((weight << 128).div(D).div(denom.mul(denom) >> 64)).mul(D).div(D.sub(decay)).mul(_totalStaked()) >> 64; // _threshold = (((weight << 128) / D) / (denom.mul(denom) >> 64)) * D / (D - decay) * (_totalStaked()) >> 64; - _threshold = ((weight * 2 ** 128 / D / (denom * denom >> 64)) * D / (D - decay) * _totalStaked()) >> 64; + // _threshold = ((weight * 2 ** 128 / D / (denom * denom >> 64)) * D / (D - decay) * _totalStaked()) >> 64; + + // _threshold = ( (weight << 128).div(D).div(denom.mul(denom) >> 64)).mul(D).div(D.sub(decay)).mul(_totalStaked()) >> 64; + _threshold = ((((((weight << 128) / D) / ((denom * denom) >> 64)) * D) / (D - decay)) * _totalStaked()) >> 64; // console.log("_threshold", _threshold); } @@ -596,11 +606,12 @@ contract CVStrategy is BaseStrategy, IWithdrawMember { if (address(registryGardens.gardenToken()) == address(0)) { revert TokenCannotBeZero(); } - // console.log("totalStaked", totalStaked); // console.log("registryGardens.gardenToken.totalSupply()", registryGardens.gardenToken().totalSupply()); // console.log("minThresholdStakePercentage", minThresholdStakePercentage); uint256 minTotalStake = (registryGardens.gardenToken().totalSupply() * minThresholdStakePercentage) / ONE_HUNDRED_PERCENT; + // console.log("minTotalStake", minTotalStake); + // console.log("totalStaked", totalStaked); return totalStaked < minTotalStake ? minTotalStake : totalStaked; } } diff --git a/pkg/contracts/src/RegistryGardens.sol b/pkg/contracts/src/RegistryGardens.sol index 8c6952c9b..eff452854 100644 --- a/pkg/contracts/src/RegistryGardens.sol +++ b/pkg/contracts/src/RegistryGardens.sol @@ -109,7 +109,7 @@ contract RegistryGardens is ReentrancyGuard { //@todo: maybe we want use ROLES instead fixed address that give mroe flexibility //@todo: also who should be allowed to set the council members? the DAO? the garden owner? - function setCouncilMembers(address[] memory _members) public onlyGardenOwner{ + function setCouncilMembers(address[] memory _members) public onlyGardenOwner { for (uint256 i = 0; i < _members.length; i++) { councilMembers[_members[i]] = true; } diff --git a/pkg/contracts/test/CVStrategyTest.t.sol b/pkg/contracts/test/CVStrategyTest.t.sol index 6cd988863..9ebf9455c 100644 --- a/pkg/contracts/test/CVStrategyTest.t.sol +++ b/pkg/contracts/test/CVStrategyTest.t.sol @@ -34,8 +34,12 @@ import {RegistryFactory} from "../src/RegistryFactory.sol"; contract CVStrategyTest is Test, AlloSetup, RegistrySetupFull, Native, Errors, GasHelpers { CVStrategy public strategy; MockERC20 public token; - uint256 public mintAmount = 1_000_000 * 10 ** 18; + // uint256 public mintAmount = 1_000 * 10 ** 18; + uint256 public mintAmount = 15000; + uint256 public constant TOTAL_SUPPLY = 45000; + uint256 public constant POOL_AMOUNT = 15000; uint256 public constant MINIMUM_STAKE = 50; + uint256 public constant REQUESTED_AMOUNT = 1000; Metadata public metadata = Metadata({protocol: 1, pointer: "strategy pointer"}); @@ -54,12 +58,7 @@ contract CVStrategyTest is Test, AlloSetup, RegistrySetupFull, Native, Errors, G vm.stopPrank(); token = new MockERC20(); - token.mint(local(), mintAmount); - token.mint(allo_owner(), mintAmount); - token.mint(pool_admin(), mintAmount); - token.approve(address(allo()), mintAmount); - - vm.prank(pool_admin()); + token.mint(local(), TOTAL_SUPPLY); token.approve(address(allo()), mintAmount); strategy = new CVStrategy(address(allo())); @@ -77,6 +76,12 @@ contract CVStrategyTest is Test, AlloSetup, RegistrySetupFull, Native, Errors, G params._protocolFee = 2; params._metadata = metadata; registryGardens = RegistryGardens(registryFactory.createRegistry(params)); + + address[] memory initialmembers = new address[](2); + initialmembers[0] = local(); + initialmembers[1] = pool_admin(); + + registryGardens.setCouncilMembers(initialmembers); } function _registryGardens() internal view returns (RegistryGardens) { @@ -92,8 +97,6 @@ contract CVStrategyTest is Test, AlloSetup, RegistrySetupFull, Native, Errors, G Metadata metadata ); - // bytes data; - /** * HELPERS FUNCTIONS */ @@ -122,14 +125,14 @@ contract CVStrategyTest is Test, AlloSetup, RegistrySetupFull, Native, Errors, G pool = allo().getPool(poolId); vm.deal(address(this), 1 ether); - allo().fundPool{value: 1 ether}(poolId, 1 ether); + allo().fundPool{value: POOL_AMOUNT}(poolId, POOL_AMOUNT); assertEq(pool.profileId, poolProfile_id()); assertNotEq(address(pool.strategy), address(strategy)); startMeasuringGas("createProposal"); CVStrategy.CreateProposal memory proposal = CVStrategy.CreateProposal( - 1, poolId, pool_admin(), pool_admin(), CVStrategy.ProposalType.Signaling, 0.1 ether, NATIVE + 1, poolId, pool_admin(), pool_admin(), CVStrategy.ProposalType.Signaling, REQUESTED_AMOUNT, NATIVE ); bytes memory data = abi.encode(proposal); allo().registerRecipient(poolId, data); @@ -230,7 +233,7 @@ contract CVStrategyTest is Test, AlloSetup, RegistrySetupFull, Native, Errors, G assertEq(cv.getProposalStakedAmount(1), 40 + 50); } - function test_proposalSupported_conviction_check() public { + function test_conviction_check_function() public { (IAllo.Pool memory pool, uint256 poolId) = _createProposal(); /** @@ -238,15 +241,15 @@ contract CVStrategyTest is Test, AlloSetup, RegistrySetupFull, Native, Errors, G */ startMeasuringGas("Support a Proposal"); CVStrategy.ProposalSupport[] memory votes = new CVStrategy.ProposalSupport[](1); - votes[0] = CVStrategy.ProposalSupport(1, 80); // 0 + 70 = 70% = 35 + votes[0] = CVStrategy.ProposalSupport(1, 80); bytes memory data = abi.encode(votes); allo().allocate(poolId, data); stopMeasuringGas(); uint256 AMOUNT_STAKED = 40; CVStrategy cv = CVStrategy(payable(address(pool.strategy))); - assertEq(cv.getProposalVoterStake(1, address(this)), AMOUNT_STAKED); // 80% of 50 = 40 - assertEq(cv.getProposalStakedAmount(1), AMOUNT_STAKED); // 80% of 50 = 40 + assertEq(cv.getProposalVoterStake(1, address(this)), AMOUNT_STAKED); + assertEq(cv.getProposalStakedAmount(1), AMOUNT_STAKED); uint256 cv_amount = cv.calculateConviction(10, 0, AMOUNT_STAKED); console.log("cv_amount: %s", cv_amount); @@ -255,6 +258,96 @@ contract CVStrategyTest is Test, AlloSetup, RegistrySetupFull, Native, Errors, G assertEq(cv_amount, cv_cmp); } + function test_conviction_check_as_js_test() public { + (IAllo.Pool memory pool, uint256 poolId) = _createProposal(); + uint256 AMOUNT_STAKED = 45000; + + registryGardens.setBasisStakedAmount(AMOUNT_STAKED); + /** + * ASSERTS + */ + startMeasuringGas("Support a Proposal"); + CVStrategy.ProposalSupport[] memory votes = new CVStrategy.ProposalSupport[](1); + votes[0] = CVStrategy.ProposalSupport(1, 100); + bytes memory data = abi.encode(votes); + allo().allocate(poolId, data); + stopMeasuringGas(); + + CVStrategy cv = CVStrategy(payable(address(pool.strategy))); + assertEq(cv.getProposalVoterStake(1, address(this)), AMOUNT_STAKED); + assertEq(cv.getProposalStakedAmount(1), AMOUNT_STAKED); + + uint256 AMOUNT_STAKED_1 = 15000; + uint256 cv_amount = cv.calculateConviction(10, 0, AMOUNT_STAKED_1); + + console.log("cv_amount: %s", cv_amount); + uint256 cv_cmp = _calculateConviction(10, 0, AMOUNT_STAKED_1, 0.9 ether / 10 ** 11); + console.log("cv_cmp: %s", cv_cmp); + + assertEq(cv_amount, cv_cmp); + assertEq(AMOUNT_STAKED_1, 15000); + assertEq(AMOUNT_STAKED, 45000); + assertEq(cv_amount, 97698); + + registryGardens.setBasisStakedAmount(MINIMUM_STAKE); + } + + function test_threshold_check_as_js_test() public { + (IAllo.Pool memory pool, uint256 poolId) = _createProposal(); + registryGardens.setBasisStakedAmount(45000); + /** + * ASSERTS + */ + startMeasuringGas("Support a Proposal"); + CVStrategy.ProposalSupport[] memory votes = new CVStrategy.ProposalSupport[](1); + votes[0] = CVStrategy.ProposalSupport(1, 100); // 0 + 70 = 70% = 35 + bytes memory data = abi.encode(votes); + allo().allocate(poolId, data); + stopMeasuringGas(); + + uint256 AMOUNT_STAKED = 45000; + CVStrategy cv = CVStrategy(payable(address(pool.strategy))); + assertEq(cv.getProposalVoterStake(1, address(this)), AMOUNT_STAKED); // 80% of 50 = 40 + assertEq(cv.getProposalStakedAmount(1), AMOUNT_STAKED); // 80% of 50 = 40 + + uint256 ct1 = cv.calculateThreshold(REQUESTED_AMOUNT); + + assertEq(AMOUNT_STAKED, 45000); + assertEq(ct1, 50625); + + registryGardens.setBasisStakedAmount(MINIMUM_STAKE); + } + + function test_total_staked_amount() public { + (IAllo.Pool memory pool, uint256 poolId) = _createProposal(); + registryGardens.setBasisStakedAmount(45000); + /** + * ASSERTS + */ + // startMeasuringGas("Support a Proposal"); + CVStrategy.ProposalSupport[] memory votes = new CVStrategy.ProposalSupport[](1); + votes[0] = CVStrategy.ProposalSupport(1, 100); + bytes memory data = abi.encode(votes); + allo().allocate(poolId, data); + // stopMeasuringGas(); + + uint256 AMOUNT_STAKED = 45000; + CVStrategy cv = CVStrategy(payable(address(pool.strategy))); + assertEq(cv.getProposalVoterStake(1, address(this)), AMOUNT_STAKED); + assertEq(cv.getProposalStakedAmount(1), AMOUNT_STAKED); + + votes[0] = CVStrategy.ProposalSupport(1, -100); + data = abi.encode(votes); + allo().allocate(poolId, data); + + assertEq(cv.getProposalVoterStake(1, address(this)), 0, "VoterStake"); + assertEq(cv.getProposalStakedAmount(1), 0, "StakedAmount"); + + assertEq(cv.totalStaked(), 0, "TotalStaked"); + + registryGardens.setBasisStakedAmount(MINIMUM_STAKE); + } + function testRevert_allocate_removeSupport_wo_support_before_SUPPORT_UNDERFLOW() public { (IAllo.Pool memory pool, uint256 poolId) = _createProposal();