Skip to content

Commit

Permalink
Merge pull request #6 from 1Hive/proposal-vote-check
Browse files Browse the repository at this point in the history
[feat] Proposal vote check
  • Loading branch information
kamikazebr authored Jan 4, 2024
2 parents f7afcf8 + fecf7cf commit 662d339
Show file tree
Hide file tree
Showing 15 changed files with 459 additions and 206 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
[submodule "lib/allo-v2"]
path = lib/allo-v2
url = https://github.com/allo-protocol/allo-v2
[submodule "lib/safe-contracts"]
path = lib/safe-contracts
url = https://github.com/safe-global/safe-contracts
3 changes: 3 additions & 0 deletions apps/web/next.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/** @type {import('next').NextConfig} */
module.exports = {
reactStrictMode: true,
experimental:{
appDir: true,
},
webpack: (config) => {
config.externals.push("pino-pretty", "lokijs", "encoding");
return config;
Expand Down
4 changes: 2 additions & 2 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"build_": "next build",
"start": "next start",
"lint": "next lint"
"lint_": "next lint"
},
"dependencies": {
"@headlessui/react": "^1.7.17",
Expand Down
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#default-profile
[profile.default]
solc-version = "0.8.19"
# solc-version = "0.8.19"
src = 'pkg/contracts/src'
test = 'pkg/contracts/test'
out = 'pkg/contracts/out'
Expand Down
1 change: 1 addition & 0 deletions lib/safe-contracts
Submodule safe-contracts added at bf943f
29 changes: 22 additions & 7 deletions pkg/contracts/src/CVStrategy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ contract CVStrategy is BaseStrategy, IWithdrawMember {
error NotEnoughPointsToSupport(uint256 pointsSupport, uint256 pointsBalance);
error TokenCannotBeZero();
error ProposalSupportDuplicated(uint256 _proposalId, uint256 index);
/*|--------------------------------------------|*/
/*| CUSTOM EVENTS |*/
/*|--------------------------------------------|*/
event InitializedCV(uint256 poolId, bytes data);
/*|--------------------------------------------|*o
/*| STRUCTS/ENUMS |*/
/*|--------------------------------------------|*/
Expand Down Expand Up @@ -125,7 +129,7 @@ contract CVStrategy is BaseStrategy, IWithdrawMember {
weight = ip.weight;
minThresholdStakePercentage = ip.minThresholdStakePercentage;

emit Initialized(_poolId, _data);
emit InitializedCV(_poolId, _data);
}
/*|--------------------------------------------|*/
/*| FALLBACK |*/
Expand Down Expand Up @@ -442,8 +446,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;
Expand Down Expand Up @@ -482,7 +493,7 @@ contract CVStrategy is BaseStrategy, IWithdrawMember {
// @audit-ok they use 2^128 as the container for the result of the _pow function

// uint256 atTWO_128 = _pow((decay << 128).div(D), t);
uint256 atTWO_128 = ((decay << 128) / D) ** t;
uint256 atTWO_128 = _pow((decay << 128) / D, t);
// solium-disable-previous-line
// conviction = (atTWO_128 * _lastConv + _oldAmount * D * (2^128 - atTWO_128) / (D - aD) + 2^127) / 2^128
// return (atTWO_128.mul(_lastConv).add(_oldAmount.mul(D).mul(TWO_128.sub(atTWO_128)).div(D - decay))).add(TWO_127)
Expand Down Expand Up @@ -512,7 +523,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);
Expand All @@ -530,7 +541,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);
}

Expand Down Expand Up @@ -596,11 +610,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;
}
}
109 changes: 67 additions & 42 deletions pkg/contracts/src/RegistryGardens.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,50 @@
pragma solidity ^0.8.19;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import {IAllo, Metadata} from "allo-v2-contracts/core/interfaces/IAllo.sol";
import {IRegistry} from "allo-v2-contracts/core/interfaces/IRegistry.sol";
import {ISafe} from "./interfaces/ISafe.sol";

contract RegistryGardens is ReentrancyGuard {

import {Safe} from "safe-contracts/contracts/Safe.sol";

contract RegistryGardens is ReentrancyGuard, AccessControl {
/*|--------------------------------------------|*/
/*| ROLES |*/
/*|--------------------------------------------|*/
bytes32 public constant COUNCIL_MEMBER_CHANGE = keccak256("COUNCIL_MEMBER_CHANGE");
/*|--------------------------------------------|*/
/*| EVENTS |*/
/*|--------------------------------------------|*/

event StrategyAdded(address _strategy);
event StrategyRemoved(address _strategy);
event MemberRegistered(address _member, uint256 _amountStaked);
event MemberUnregistered(address _member, uint256 _amountReturned);
event StakeAmountUpdated(address _member, uint256 _newAmount);
event CouncilMemberSet(address [] _councilMembers);
event CouncilSafeSet(address _safe);
event CouncilSafeChangeStarted(address _safeOwner, address _newSafeOwner);
event ProtocolFeeUpdated(uint256 _newFee);
event AlloSet(address _allo);
/*|--------------------------------------------|*/
/*| MODIFIERS |*/
/*|--------------------------------------------|*/

modifier onlyCouncilMember() {
if(!isCouncilMember(msg.sender)) {
if (!hasRole(COUNCIL_MEMBER_CHANGE, msg.sender)) {
revert UserNotInCouncil();
}
_;
}

modifier onlyRegistryMember(){
if(!isMember(msg.sender)) {
revert UserNotInRegistry();
}
_;
}

modifier onlyGardenOwner(){
if(msg.sender!=gardenOwner) {
revert UserNotGardenOwner();
modifier onlyRegistryMember() {
if (!isMember(msg.sender)) {
revert UserNotInRegistry();
}
_;
}


/*|--------------------------------------------|*/
/*| CUSTOM ERRORS |*/
/*|--------------------------------------------|*/
Expand All @@ -54,7 +55,8 @@ contract RegistryGardens is ReentrancyGuard {
error UserNotInRegistry();
error UserNotGardenOwner();
error StrategyExists();

error CallerIsNotNewOnwer();

/*|--------------------------------------------|*o
/*| STRUCTS/ENUMS |*/
/*|--------------------------------------------|*/
Expand All @@ -71,6 +73,7 @@ contract RegistryGardens is ReentrancyGuard {
uint256 _protocolFee;
uint256 _nonce;
Metadata _metadata;
address payable _councilSafe;
}

//TODO: can change to uint32 with optimized storage order
Expand All @@ -81,60 +84,79 @@ contract RegistryGardens is ReentrancyGuard {
IERC20 public gardenToken;
uint256 public protocolFee;
string private covenantIpfsHash;
address private gardenOwner;
bytes32 public profileId;

ISafe public councilSafe;
mapping(address => bool) public councilMembers;
address payable public pendingCouncilSafe;
Safe public councilSafe;

mapping(address => bool) public tribunalMembers;

mapping(address => Member) public addressToMemberInfo;
mapping(address => bool) public enabledStrategies;

constructor() {}
constructor() {
// _grantRole(DEFAULT_ADMIN_ROLE, address(this));
_setRoleAdmin(COUNCIL_MEMBER_CHANGE, DEFAULT_ADMIN_ROLE);
}

function initialize(RegistryGardens.InitializeParams memory params) public {
allo = IAllo(params._allo);
gardenToken = params._gardenToken;
minimumStakeAmount = params._minimumStakeAmount;
protocolFee = params._protocolFee;
gardenOwner = msg.sender;
if (params._councilSafe == address(0)) {
revert AddressCannotBeZero();
}
councilSafe = Safe(params._councilSafe);
_grantRole(COUNCIL_MEMBER_CHANGE, params._councilSafe);

// gardenOwner = msg.sender; //@todo: RegistryFactory is the onwer of that contract, that need be able to change the owner
// gardenOwner = params.owner; //@todo: check if address(0) is a valid owner
registry = IRegistry(allo.getRegistry());
address[] memory initialmembers = new address[](0);
profileId = registry.createProfile(params._nonce, communityName, params._metadata, msg.sender, initialmembers);
}

function setCouncilMembers(address[] memory _members) public {}

function addStrategy(address _newStrategy) public onlyRegistryMember{
function addStrategy(address _newStrategy) public onlyRegistryMember {
if (enabledStrategies[_newStrategy]) {
revert StrategyExists();
}
enabledStrategies[_newStrategy] = true;
emit StrategyAdded(_newStrategy);
}

function revertZeroAddress(address _address) internal pure {
if(_address == address(0)) revert AddressCannotBeZero();
if (_address == address(0)) revert AddressCannotBeZero();
}
function removeStrategy(address _strategy) public onlyCouncilMember{

function removeStrategy(address _strategy) public onlyCouncilMember {
revertZeroAddress(_strategy);
enabledStrategies[_strategy] = false;
emit StrategyRemoved(_strategy);

}
function setAllo(address _allo) public {

function setAllo(address _allo) public {
allo = IAllo(_allo);
emit AlloSet(_allo);
}

function setCouncilSafe(address _safe) public {
require(msg.sender == gardenOwner, "Only the owner can call this method.");
councilSafe = ISafe(_safe);
emit CouncilSafeSet(_safe);
function setCouncilSafe(address payable _safe) public onlyCouncilMember {
pendingCouncilSafe = _safe;
emit CouncilSafeChangeStarted(address(councilSafe), pendingCouncilSafe);
}

function _changeCouncilSafe() internal {
councilSafe = Safe(pendingCouncilSafe);
delete pendingCouncilSafe;
emit CouncilSafeSet(pendingCouncilSafe);
}

function acceptCouncilSafe() public {
if (msg.sender != pendingCouncilSafe){
revert CallerIsNotNewOnwer();
}
_changeCouncilSafe();
}

function isMember(address _member) public view returns (bool _isMember) {
Member memory newMember = addressToMemberInfo[_member];
Expand All @@ -147,18 +169,19 @@ contract RegistryGardens is ReentrancyGuard {
Member storage newMember = addressToMemberInfo[msg.sender];
require(
//If fee percentage => minimumStakeAmount*protocolFee/100
gardenToken.balanceOf(msg.sender) >= minimumStakeAmount+ protocolFee,
gardenToken.balanceOf(msg.sender) >= minimumStakeAmount + protocolFee,
"[Registry]: Amount staked must be greater than minimum staked amount"
);
if(newMember.stakedAmount>= minimumStakeAmount){revert("already Staked");}
if (newMember.stakedAmount >= minimumStakeAmount) revert("already Staked");
//Check if already member
newMember.isRegistered = true;
newMember.stakedAmount = minimumStakeAmount;
gardenToken.transferFrom(msg.sender, address(this), minimumStakeAmount);
emit MemberRegistered(msg.sender, minimumStakeAmount);
}
//Check use of payable and msg.value
function modifyStakeAmount(uint256 newTotalAmount) public payable nonReentrant onlyRegistryMember{

function modifyStakeAmount(uint256 newTotalAmount) public payable nonReentrant onlyRegistryMember {
Member storage member = addressToMemberInfo[msg.sender];
uint256 oldAmount = member.stakedAmount;
member.stakedAmount = newTotalAmount;
Expand All @@ -171,30 +194,32 @@ contract RegistryGardens is ReentrancyGuard {
gardenToken.transferFrom(address(this), msg.sender, oldAmount - newTotalAmount);
}

emit StakeAmountUpdated(msg.sender,newTotalAmount);
emit StakeAmountUpdated(msg.sender, newTotalAmount);
}

function getBasisStakedAmount() external view returns (uint256) {
return minimumStakeAmount;
}

function updateProtocolFee(uint256 _newProtocolFee) public{
if(!isCouncilMember(msg.sender)) {
revert("Must be in council safe");
}
function setBasisStakedAmount(uint256 _newAmount) external onlyCouncilMember {
minimumStakeAmount = _newAmount;
}

function updateProtocolFee(uint256 _newProtocolFee) public onlyCouncilMember {
protocolFee = _newProtocolFee;
emit ProtocolFeeUpdated(_newProtocolFee);
}
//function updateMinimumStake()

function isCouncilMember(address _member) public view returns (bool) {
return councilMembers[_member];
return hasRole(COUNCIL_MEMBER_CHANGE, _member);
}

function unregisterMember(address _member) public nonReentrant {
require(isMember(_member) || isCouncilMember(msg.sender), "[Registry]: Must be active member to unregister");
Member memory member = addressToMemberInfo[msg.sender];
delete addressToMemberInfo[msg.sender];
gardenToken.transfer( msg.sender, member.stakedAmount);
gardenToken.transfer(msg.sender, member.stakedAmount);
emit MemberUnregistered(msg.sender, member.stakedAmount);
}
}
Loading

0 comments on commit 662d339

Please sign in to comment.