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: atomic manual parties #267

Closed
wants to merge 14 commits into from
128 changes: 128 additions & 0 deletions contracts/crowdfund/AtomicManualParty.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.20;

import { IGlobals } from "../globals/IGlobals.sol";
import { LibGlobals } from "../globals/LibGlobals.sol";
import { IPartyFactory } from "../party/IPartyFactory.sol";
import { Party } from "../party/Party.sol";
import { IERC721 } from "../tokens/IERC721.sol";
import { MetadataProvider } from "../renderers/MetadataProvider.sol";
import { Proxy } from "../utils/Proxy.sol";
import { Implementation } from "../utils/Implementation.sol";
arr00 marked this conversation as resolved.
Show resolved Hide resolved

/// @title AtomicManualParty
/// @notice Singleton that is called to create a party manually with an array
/// of party members and their votes.
contract AtomicManualParty {
/// @notice Returned if the `AtomicManualParty` is created with no members
error NoPartyMembers();
/// @notice Returned if the lengths of `partyMembers` and `partyMemberVotes` do not match
error PartyMembersArityMismatch();
arr00 marked this conversation as resolved.
Show resolved Hide resolved

// The `Globals` contract storing global configuration values. This contract
// is immutable and it’s address will never change.
IGlobals private immutable _GLOBALS;

constructor(IGlobals globals) {
_GLOBALS = globals;
}

/// @notice Atomically creates the party and distributes the party cards
function createParty(
Party partyImpl,
Party.PartyOptions memory opts,
IERC721[] memory preciousTokens,
uint256[] memory preciousTokenIds,
uint40 rageQuitTimestamp,
address[] memory partyMembers,
uint96[] memory partyMemberVotes
arr00 marked this conversation as resolved.
Show resolved Hide resolved
) public returns (Party party) {
_validateAtomicManualPartyArrays(partyMembers, partyMemberVotes);

address[] memory authorities = new address[](1);
authorities[0] = address(this);

uint96 totalVotes;
for (uint256 i; i < partyMemberVotes.length; i++) {
totalVotes += partyMemberVotes[i];
}
opts.governance.totalVotingPower = totalVotes;

party = IPartyFactory(_GLOBALS.getAddress(LibGlobals.GLOBAL_PARTY_FACTORY)).createParty(
partyImpl,
authorities,
opts,
preciousTokens,
preciousTokenIds,
rageQuitTimestamp
);

_issuePartyCards(party, partyMembers, partyMemberVotes);
}

/// @notice Atomically creates the party and distributes the party cards
/// with metadata
function createPartyWithMetadata(
Party partyImpl,
Party.PartyOptions memory opts,
IERC721[] memory preciousTokens,
uint256[] memory preciousTokenIds,
uint40 rageQuitTimestamp,
MetadataProvider provider,
bytes memory metadata,
address[] memory partyMembers,
uint96[] memory partyMemberVotes
) external returns (Party party) {
_validateAtomicManualPartyArrays(partyMembers, partyMemberVotes);

address[] memory authorities = new address[](1);
authorities[0] = address(this);

uint96 totalVotes;
for (uint256 i; i < partyMemberVotes.length; i++) {
totalVotes += partyMemberVotes[i];
}
opts.governance.totalVotingPower = totalVotes;

party = IPartyFactory(_GLOBALS.getAddress(LibGlobals.GLOBAL_PARTY_FACTORY))
.createPartyWithMetadata(
partyImpl,
authorities,
opts,
preciousTokens,
preciousTokenIds,
rageQuitTimestamp,
provider,
metadata
);

_issuePartyCards(party, partyMembers, partyMemberVotes);
}

/// @notice Issue party cards to the party members
/// @param party The party to issue cards for
/// @param partyMembers The party members to issue cards to
/// @param partyMemberVotes The number of votes each party member gets
function _issuePartyCards(
Party party,
address[] memory partyMembers,
uint96[] memory partyMemberVotes
) internal {
for (uint256 i; i < partyMembers.length; i++) {
party.mint(partyMembers[i], partyMemberVotes[i], partyMembers[i]);
}
party.abdicateAuthority();
}

function _validateAtomicManualPartyArrays(
address[] memory partyMembers,
uint96[] memory partyMemberVotes
) private pure {
if (partyMembers.length == 0) {
revert NoPartyMembers();
}
if (partyMembers.length != partyMemberVotes.length) {
revert PartyMembersArityMismatch();
}
}
}
2 changes: 1 addition & 1 deletion contracts/globals/LibGlobals.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ library LibGlobals {

uint256 internal constant GLOBAL_PARTY_IMPL = 1;
uint256 internal constant GLOBAL_PROPOSAL_ENGINE_IMPL = 2;
// uint256 internal constant GLOBAL_PARTY_FACTORY = 3;
uint256 internal constant GLOBAL_PARTY_FACTORY = 3;
uint256 internal constant GLOBAL_GOVERNANCE_NFT_RENDER_IMPL = 4;
uint256 internal constant GLOBAL_CF_NFT_RENDER_IMPL = 5;
uint256 internal constant GLOBAL_OS_ZORA_AUCTION_TIMEOUT = 6;
Expand Down
Loading