Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] Proposal vote check #6

Merged
merged 8 commits into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading