-
Notifications
You must be signed in to change notification settings - Fork 33
/
AtomicManualParty.sol
182 lines (167 loc) · 6.33 KB
/
AtomicManualParty.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.20;
import { IPartyFactory } from "../party/IPartyFactory.sol";
import { Party } from "../party/Party.sol";
import { IERC721 } from "../tokens/IERC721.sol";
import { MetadataProvider } from "../renderers/MetadataProvider.sol";
/// @title AtomicManualParty
/// @notice Singleton that is called to create a party manually with an array
/// of party members and their voting power.
contract AtomicManualParty {
/// @notice Emitted when an atomic manual party is created
event AtomicManualPartyCreated(
Party indexed party,
address[] partyMembers,
uint96[] partyMemberVotingPowers,
Party.PartyOptions opts,
IERC721[] preciousTokens,
uint256[] preciousTokenIds,
uint40 rageQuitTimestamp,
address creator
);
/// @notice Returned if the `AtomicManualParty` is created with no members
error NoPartyMembers();
/// @notice Returned if the lengths of `partyMembers` and `partyMemberVotingPowers` do not match
error PartyMembersArityMismatch();
/// @notice Returned if a party card would be issued to the null address
error InvalidPartyMember();
/// @notice Returned if a party card would be issued with no voting power
error InvalidPartyMemberVotingPower();
IPartyFactory private immutable PARTY_FACTORY;
constructor(IPartyFactory partyFactory) {
PARTY_FACTORY = partyFactory;
}
/// @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 partyMemberVotingPowers,
address[] memory authorities
) public returns (Party party) {
uint96 totalVotingPower = _validateAtomicManualPartyArrays(
partyMembers,
partyMemberVotingPowers
);
opts.governance.totalVotingPower = totalVotingPower;
address[] memory authorities_;
{
uint256 authoritiesLength = authorities.length + 1;
authorities_ = new address[](authoritiesLength);
for (uint i = 0; i < authoritiesLength - 1; ++i) {
authorities_[i] = authorities[i];
}
authorities_[authoritiesLength - 1] = address(this);
}
party = PARTY_FACTORY.createParty(
partyImpl,
authorities_,
opts,
preciousTokens,
preciousTokenIds,
rageQuitTimestamp
);
_issuePartyCards(party, partyMembers, partyMemberVotingPowers);
emit AtomicManualPartyCreated(
party,
partyMembers,
partyMemberVotingPowers,
opts,
preciousTokens,
preciousTokenIds,
rageQuitTimestamp,
msg.sender
);
}
/// @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 partyMemberVotingPowers,
address[] memory authorities
) external returns (Party party) {
uint96 totalVotingPower = _validateAtomicManualPartyArrays(
partyMembers,
partyMemberVotingPowers
);
opts.governance.totalVotingPower = totalVotingPower;
address[] memory authorities_;
{
uint256 authoritiesLength = authorities.length + 1;
authorities_ = new address[](authoritiesLength);
for (uint i = 0; i < authoritiesLength - 1; ++i) {
authorities_[i] = authorities[i];
}
authorities_[authoritiesLength - 1] = address(this);
}
party = PARTY_FACTORY.createPartyWithMetadata(
partyImpl,
authorities_,
opts,
preciousTokens,
preciousTokenIds,
rageQuitTimestamp,
provider,
metadata
);
_issuePartyCards(party, partyMembers, partyMemberVotingPowers);
emit AtomicManualPartyCreated(
party,
partyMembers,
partyMemberVotingPowers,
opts,
preciousTokens,
preciousTokenIds,
rageQuitTimestamp,
msg.sender
);
}
/// @notice Issue party cards to the party members and finishes up creation
/// @param party The party to issue cards for
/// @param partyMembers The party members to issue cards to
/// @param partyMemberVotingPowers The voting power each party member gets
function _issuePartyCards(
Party party,
address[] memory partyMembers,
uint96[] memory partyMemberVotingPowers
) internal {
for (uint256 i; i < partyMembers.length; i++) {
party.mint(partyMembers[i], partyMemberVotingPowers[i], partyMembers[i]);
}
party.abdicateAuthority();
}
/// @notice Validate manual party cards arrays, returns total voting power
/// @param partyMembers The party members to issue cards to
/// @param partyMemberVotingPowers The voting power each party member gets
/// @return totalVotingPower The total voting power of the party
function _validateAtomicManualPartyArrays(
address[] memory partyMembers,
uint96[] memory partyMemberVotingPowers
) private pure returns (uint96 totalVotingPower) {
if (partyMembers.length == 0) {
revert NoPartyMembers();
}
if (partyMembers.length != partyMemberVotingPowers.length) {
revert PartyMembersArityMismatch();
}
for (uint256 i = 0; i < partyMemberVotingPowers.length; ++i) {
if (partyMemberVotingPowers[i] == 0) {
revert InvalidPartyMemberVotingPower();
}
if (partyMembers[i] == address(0)) {
revert InvalidPartyMember();
}
totalVotingPower += partyMemberVotingPowers[i];
}
}
}