Skip to content

Commit

Permalink
feat: skip veto period when all hosts accept (#268)
Browse files Browse the repository at this point in the history
* feat: skip veto period when all hosts accept

* test: add tests

* bug: checkpoint `numHosts` at proposal creation

* switch num hosts ordering

* create new flag for hosts accepted

* address comments
  • Loading branch information
arr00 committed Oct 2, 2023
1 parent b4f9ed3 commit b05770b
Show file tree
Hide file tree
Showing 9 changed files with 359 additions and 12 deletions.
25 changes: 24 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,30 @@ jobs:
- name: Install dependencies
run: forge install
- name: "Run Foundry tests"
run: forge test -vvv --fork-url $FORK_URL --etherscan-api-key $ETHERSCAN_API_KEY --ffi
run: forge test -vvv --ffi
test-forked:
runs-on: ubuntu-latest
steps:
- name: "Check out the repo"
uses: actions/checkout@v3
with:
submodules: recursive
- name: Use Node.js 16.x
uses: actions/setup-node@v3
with:
node-version: 16.x
- name: Install yarn dependencies
run: yarn install
- name: Build ts
run: yarn build:ts
- name: "Install Foundry"
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly
- name: Install dependencies
run: forge install
- name: "Run Foundry tests"
run: forge test -vvv --fork-url $FORK_URL --ffi
coverage:
runs-on: ubuntu-latest
steps:
Expand Down
39 changes: 35 additions & 4 deletions contracts/party/PartyGovernance.sol
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ abstract contract PartyGovernance is
uint40 executionDelay;
uint16 passThresholdBps;
uint96 totalVotingPower;
/// @notice Number of hosts for this party
uint8 numHosts;
}

// A snapshot of voting power for a member.
Expand Down Expand Up @@ -136,6 +138,10 @@ abstract contract PartyGovernance is
uint96 votes; // -1 == vetoed
// Number of total voting power at time proposal created.
uint96 totalVotingPower;
/// @notice Number of hosts at time proposal created
uint8 numHosts;
/// @notice Number of hosts that accepted proposal
uint8 numHostsAccepted;
}

// Storage states for a proposal.
Expand Down Expand Up @@ -185,6 +191,7 @@ abstract contract PartyGovernance is
error DistributionsRequireVoteError();
error PartyNotStartedError();
error CannotRageQuitAndAcceptError();
error TooManyHosts();

uint256 private constant UINT40_HIGH_BIT = 1 << 39;
uint96 private constant VETO_VALUE = type(uint96).max;
Expand Down Expand Up @@ -299,14 +306,18 @@ abstract contract PartyGovernance is
voteDuration: govOpts.voteDuration,
executionDelay: govOpts.executionDelay,
passThresholdBps: govOpts.passThresholdBps,
totalVotingPower: govOpts.totalVotingPower
totalVotingPower: govOpts.totalVotingPower,
numHosts: uint8(govOpts.hosts.length)
});
// Set fees.
feeBps = govOpts.feeBps;
feeRecipient = govOpts.feeRecipient;
// Set the precious list.
_setPreciousList(preciousTokens, preciousTokenIds);
// Set the party hosts.
if (govOpts.hosts.length > type(uint8).max) {
revert TooManyHosts();
}
for (uint256 i = 0; i < govOpts.hosts.length; ++i) {
isHost[govOpts.hosts[i]] = true;
}
Expand Down Expand Up @@ -455,6 +466,9 @@ abstract contract PartyGovernance is
revert InvalidNewHostError();
}
isHost[newPartyHost] = true;
} else {
// Burned the host status
--_governanceValues.numHosts;
}
isHost[msg.sender] = false;
emit HostStatusTransferred(msg.sender, newPartyHost);
Expand Down Expand Up @@ -558,7 +572,9 @@ abstract contract PartyGovernance is
executedTime: 0,
completedTime: 0,
votes: 0,
totalVotingPower: _governanceValues.totalVotingPower
totalVotingPower: _governanceValues.totalVotingPower,
numHosts: _governanceValues.numHosts,
numHostsAccepted: 0
}),
getProposalHash(proposal)
);
Expand Down Expand Up @@ -622,6 +638,9 @@ abstract contract PartyGovernance is
// Increase the total votes that have been cast on this proposal.
uint96 votingPower = getVotingPowerAt(msg.sender, values.proposedTime - 1, snapIndex);
values.votes += votingPower;
if (isHost[msg.sender]) {
++values.numHostsAccepted;
}
info.values = values;
emit ProposalAccepted(proposalId, msg.sender, votingPower);

Expand Down Expand Up @@ -1021,10 +1040,14 @@ abstract contract PartyGovernance is
}

function _getProposalFlags(ProposalStateValues memory pv) private pure returns (uint256) {
uint256 flags = 0;
if (_isUnanimousVotes(pv.votes, pv.totalVotingPower)) {
return LibProposal.PROPOSAL_FLAG_UNANIMOUS;
flags = flags | LibProposal.PROPOSAL_FLAG_UNANIMOUS;
}
return 0;
if (_hostsAccepted(pv.numHosts, pv.numHostsAccepted)) {
flags = flags | LibProposal.PROPOSAL_FLAG_HOSTS_ACCEPT;
}
return flags;
}

function _getProposalStatus(
Expand Down Expand Up @@ -1060,6 +1083,10 @@ abstract contract PartyGovernance is
if (_isUnanimousVotes(pv.votes, pv.totalVotingPower)) {
return ProposalStatus.Ready;
}
// If all hosts voted, skip execution delay
if (_hostsAccepted(pv.numHosts, pv.numHostsAccepted)) {
return ProposalStatus.Ready;
}
// Passed.
return ProposalStatus.Passed;
}
Expand All @@ -1081,6 +1108,10 @@ abstract contract PartyGovernance is
return acceptanceRatio >= 0.9999e4;
}

function _hostsAccepted(uint8 numHosts, uint8 numHostsAccepted) private pure returns (bool) {
return numHosts > 0 && numHosts == numHostsAccepted;
}

function _areVotesPassing(
uint96 voteCount,
uint96 totalVotingPower,
Expand Down
1 change: 1 addition & 0 deletions contracts/proposals/LibProposal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "../tokens/IERC721.sol";

library LibProposal {
uint256 internal constant PROPOSAL_FLAG_UNANIMOUS = 0x1;
uint256 internal constant PROPOSAL_FLAG_HOSTS_ACCEPT = 0x2;

function isTokenPrecious(
IERC721 token,
Expand Down
11 changes: 8 additions & 3 deletions test/TestUsers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,14 @@ contract PartyAdmin is Test {
public
returns (Party party, IERC721[] memory preciousTokens, uint256[] memory preciousTokenIds)
{
address[] memory hosts = new address[](2);
hosts[0] = opts.host1;
hosts[1] = opts.host2;
uint256 size = 2 - (opts.host1 == address(0) ? 1 : 0) - (opts.host2 == address(0) ? 1 : 0);
address[] memory hosts = new address[](size);
if (opts.host1 != address(0)) {
hosts[0] = opts.host1;
}
if (opts.host2 != address(0)) {
hosts[1] = opts.host2;
}

preciousTokens = new IERC721[](1);
preciousTokens[0] = IERC721(opts.preciousTokenAddress);
Expand Down
1 change: 1 addition & 0 deletions test/distribution/DummyTokenDistributorParty.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ contract DummyTokenDistributorParty {
uint40 executionDelay;
uint16 passThresholdBps;
uint96 totalVotingPower;
uint8 numHosts;
}

GovernanceValues _governanceValues;
Expand Down
3 changes: 3 additions & 0 deletions test/distribution/TokenDistributor.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ contract PartyWithoutVersionId {
uint40 executionDelay;
uint16 passThresholdBps;
uint96 totalVotingPower;
uint8 numHosts;
}

GovernanceValues _governanceValues;
Expand All @@ -325,6 +326,7 @@ contract PartyWithInvalidVersionId {
uint40 executionDelay;
uint16 passThresholdBps;
uint96 totalVotingPower;
uint8 numHosts;
}

uint16 VERSION_ID = 0;
Expand All @@ -346,6 +348,7 @@ contract PartyWithValidVersionId {
uint40 executionDelay;
uint16 passThresholdBps;
uint96 totalVotingPower;
uint8 numHosts;
}

uint16 VERSION_ID = 1;
Expand Down
1 change: 1 addition & 0 deletions test/distribution/TokenDistributorUnit.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ contract TestParty {
uint40 executionDelay;
uint16 passThresholdBps;
uint96 totalVotingPower;
uint8 numHosts;
}

GovernanceValues _governanceValues;
Expand Down
Loading

0 comments on commit b05770b

Please sign in to comment.