Skip to content

Commit

Permalink
fix: require distributionsRequireVote to enable rage quit
Browse files Browse the repository at this point in the history
  • Loading branch information
0xble authored and arr00 committed Nov 29, 2023
1 parent 98e684c commit 68c0f3c
Show file tree
Hide file tree
Showing 4 changed files with 298 additions and 44 deletions.
17 changes: 15 additions & 2 deletions contracts/party/PartyGovernanceNFT.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ contract PartyGovernanceNFT is PartyGovernance, ERC721, IERC2981 {
error FixedRageQuitTimestampError(uint40 rageQuitTimestamp);
error CannotRageQuitError(uint40 rageQuitTimestamp);
error CannotDisableRageQuitAfterInitializationError();
error CannotEnableRageQuitIfNotDistributionsRequireVoteError();
error InvalidTokenOrderError();
error BelowMinWithdrawAmountError(uint256 amount, uint256 minAmount);
error NothingToBurnError();
Expand Down Expand Up @@ -97,7 +98,13 @@ contract PartyGovernanceNFT is PartyGovernance, ERC721, IERC2981 {
);
name = name_;
symbol = symbol_;
rageQuitTimestamp = rageQuitTimestamp_;
if (rageQuitTimestamp_ != 0) {
if (!proposalEngineOpts.distributionsRequireVote) {
revert CannotEnableRageQuitIfNotDistributionsRequireVoteError();
}

rageQuitTimestamp = rageQuitTimestamp_;
}
unchecked {
for (uint256 i; i < authorities.length; ++i) {
isAuthority[authorities[i]] = true;
Expand Down Expand Up @@ -321,6 +328,10 @@ contract PartyGovernanceNFT is PartyGovernance, ERC721, IERC2981 {
revert CannotDisableRageQuitAfterInitializationError();
}

// Prevent enabling ragequit if distributions can be created without a vote.
if (!_getSharedProposalStorage().opts.distributionsRequireVote)
revert CannotEnableRageQuitIfNotDistributionsRequireVoteError();

uint40 oldRageQuitTimestamp = rageQuitTimestamp;

// Prevent setting timestamp if it is permanently enabled/disabled.
Expand All @@ -331,7 +342,9 @@ contract PartyGovernanceNFT is PartyGovernance, ERC721, IERC2981 {
revert FixedRageQuitTimestampError(oldRageQuitTimestamp);
}

emit RageQuitSet(oldRageQuitTimestamp, rageQuitTimestamp = newRageQuitTimestamp);
rageQuitTimestamp = newRageQuitTimestamp;

emit RageQuitSet(oldRageQuitTimestamp, newRageQuitTimestamp);
}

/// @notice Burn a governance NFT and withdraw a fair share of fungible tokens from the party.
Expand Down
41 changes: 27 additions & 14 deletions test/TestUsers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -87,25 +87,28 @@ contract PartyAdmin is Test {

function createParty(
Party partyImpl,
PartyCreationMinimalOptions calldata opts
PartyCreationMinimalOptions calldata partyOpts,
ProposalStorage.ProposalEngineOpts memory engineOpts
)
public
returns (Party party, IERC721[] memory preciousTokens, uint256[] memory preciousTokenIds)
{
uint256 size = 2 - (opts.host1 == address(0) ? 1 : 0) - (opts.host2 == address(0) ? 1 : 0);
uint256 size = 2 -
(partyOpts.host1 == address(0) ? 1 : 0) -
(partyOpts.host2 == address(0) ? 1 : 0);
address[] memory hosts = new address[](size);
if (opts.host1 != address(0)) {
hosts[0] = opts.host1;
if (partyOpts.host1 != address(0)) {
hosts[0] = partyOpts.host1;
}
if (opts.host2 != address(0)) {
hosts[1] = opts.host2;
if (partyOpts.host2 != address(0)) {
hosts[1] = partyOpts.host2;
}

preciousTokens = new IERC721[](1);
preciousTokens[0] = IERC721(opts.preciousTokenAddress);
preciousTokens[0] = IERC721(partyOpts.preciousTokenAddress);

preciousTokenIds = new uint256[](1);
preciousTokenIds[0] = opts.preciousTokenId;
preciousTokenIds[0] = partyOpts.preciousTokenId;

address[] memory authorities = new address[](1);
authorities[0] = address(this);
Expand All @@ -118,23 +121,33 @@ contract PartyAdmin is Test {
hosts: hosts,
voteDuration: 99,
executionDelay: 300,
passThresholdBps: opts.passThresholdBps,
totalVotingPower: opts.totalVotingPower,
feeRecipient: opts.feeRecipient,
feeBps: opts.feeBps
passThresholdBps: partyOpts.passThresholdBps,
totalVotingPower: partyOpts.totalVotingPower,
feeRecipient: partyOpts.feeRecipient,
feeBps: partyOpts.feeBps
}),
proposalEngine: proposalEngineOpts,
proposalEngine: engineOpts,
name: "Dope party",
symbol: "DOPE",
customizationPresetId: 0
}),
preciousTokens,
preciousTokenIds,
opts.rageQuitTimestamp
partyOpts.rageQuitTimestamp
);
return (party, preciousTokens, preciousTokenIds);
}

function createParty(
Party partyImpl,
PartyCreationMinimalOptions calldata partyOpts
)
public
returns (Party party, IERC721[] memory preciousTokens, uint256[] memory preciousTokenIds)
{
return createParty(partyImpl, partyOpts, proposalEngineOpts);
}

function mintGovNft(
Party party,
address mintTo,
Expand Down
30 changes: 26 additions & 4 deletions test/party/PartyFactory.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ contract PartyFactoryTest is Test, TestUtils {
enableAddAuthorityProposal: randomBool,
allowArbCallsToSpendPartyEth: randomBool,
allowOperators: randomBool,
distributionsRequireVote: randomBool
// Needs to be true to set non-zero rageQuitTimestamp
distributionsRequireVote: true
}),
name: randomStr,
symbol: randomStr,
Expand Down Expand Up @@ -118,7 +119,7 @@ contract PartyFactoryTest is Test, TestUtils {
.getProposalEngineOpts();
assertEq(proposalEngineOpts.allowArbCallsToSpendPartyEth, randomBool);
assertEq(proposalEngineOpts.allowOperators, randomBool);
assertEq(proposalEngineOpts.distributionsRequireVote, randomBool);
assertEq(proposalEngineOpts.distributionsRequireVote, true);
assertEq(party.preciousListHash(), _hashPreciousList(preciousTokens, preciousTokenIds));
}

Expand Down Expand Up @@ -148,7 +149,8 @@ contract PartyFactoryTest is Test, TestUtils {
enableAddAuthorityProposal: randomBool,
allowArbCallsToSpendPartyEth: randomBool,
allowOperators: randomBool,
distributionsRequireVote: randomBool
// Needs to be true to set non-zero rageQuitTimestamp
distributionsRequireVote: true
}),
name: randomStr,
symbol: randomStr,
Expand Down Expand Up @@ -182,7 +184,7 @@ contract PartyFactoryTest is Test, TestUtils {
.getProposalEngineOpts();
assertEq(proposalEngineOpts.allowArbCallsToSpendPartyEth, randomBool);
assertEq(proposalEngineOpts.allowOperators, randomBool);
assertEq(proposalEngineOpts.distributionsRequireVote, randomBool);
assertEq(proposalEngineOpts.distributionsRequireVote, true);
assertEq(party.preciousListHash(), _hashPreciousList(preciousTokens, preciousTokenIds));
assertEq(address(registry.getProvider(address(party))), address(provider));
assertEq(provider.getMetadata(address(party), 0), metadata);
Expand Down Expand Up @@ -214,4 +216,24 @@ contract PartyFactoryTest is Test, TestUtils {
0
);
}

function testCreateParty_revertIfRagequitEnabledAndNotDistributionsRequireVote() external {
address authority = _randomAddress();
(IERC721[] memory preciousTokens, uint256[] memory preciousTokenIds) = _createPreciouses(3);

Party.PartyOptions memory opts = defaultPartyOptions;
uint40 ragequitTimestamp = 1;

vm.expectRevert(
PartyGovernanceNFT.CannotEnableRageQuitIfNotDistributionsRequireVoteError.selector
);
factory.createParty(
partyImpl,
_toAddressArray(authority),
opts,
preciousTokens,
preciousTokenIds,
ragequitTimestamp
);
}
}
Loading

0 comments on commit 68c0f3c

Please sign in to comment.