@@ -20,6 +20,8 @@ contract JoinAndQuit is
20
20
using SafeERC20 for IERC20 ;
21
21
using StringUtil for string ;
22
22
23
+ enum MemeberState { None, Candidate, Accepted, Rejected, ReputationRedeemed }
24
+
23
25
event JoinInProposal (
24
26
address indexed _avatar ,
25
27
bytes32 indexed _proposalId ,
@@ -55,12 +57,10 @@ contract JoinAndQuit is
55
57
struct Proposal {
56
58
address proposedMember;
57
59
uint256 funding;
58
- bool executed;
59
- bool accepted;
60
60
}
61
61
62
62
struct MemberFund {
63
- bool candidate ;
63
+ MemeberState state ;
64
64
bool rageQuit;
65
65
uint256 funding;
66
66
}
@@ -127,13 +127,12 @@ contract JoinAndQuit is
127
127
returns (bool ) {
128
128
Proposal memory proposal = proposals[_proposalId];
129
129
require (proposal.proposedMember != address (0 ), "not a valid proposal " );
130
- require (proposal.executed == false , "proposal already been executed " );
131
- proposals[_proposalId].executed = true ;
130
+ require (fundings[proposal.proposedMember].state == MemeberState.Candidate, "proposal already been executed " );
132
131
133
132
bool success;
134
133
// Check if vote was successful:
135
134
if ((_decision == 1 ) && (avatar.nativeReputation ().balanceOf (proposal.proposedMember) == 0 )) {
136
- proposals[_proposalId].accepted = true ;
135
+ fundings[proposal.proposedMember].state = MemeberState.Accepted ;
137
136
fundings[proposal.proposedMember].funding = proposal.funding;
138
137
totalDonation = totalDonation.add (proposal.funding);
139
138
if (fundingToken == IERC20 (0 )) {
@@ -146,15 +145,16 @@ contract JoinAndQuit is
146
145
//this should be called/check after the transfer to the avatar.
147
146
setFundingGoalReachedFlag ();
148
147
} else {
148
+ fundings[proposal.proposedMember].state = MemeberState.Rejected;
149
149
if (fundingToken == IERC20 (0 )) {
150
150
// solhint-disable-next-line
151
151
(success, ) = proposal.proposedMember.call {value:proposal.funding}("" );
152
- require (success, "sendEther to avatar failed " );
152
+ require (success, "sendEther back to candidate failed " );
153
153
} else {
154
154
fundingToken.safeTransfer (proposal.proposedMember, proposal.funding);
155
155
}
156
156
}
157
- fundings[proposal.proposedMember].candidate = false ;
157
+
158
158
emit ProposalExecuted (address (avatar), _proposalId, _decision);
159
159
return true ;
160
160
}
@@ -174,22 +174,21 @@ contract JoinAndQuit is
174
174
returns (bytes32 )
175
175
{
176
176
address proposer = msg .sender ;
177
- require (! fundings[proposer].candidate, "already a candidate " );
177
+ require (fundings[proposer].state != MemeberState.Candidate, "already a candidate " );
178
+ require (fundings[proposer].state != MemeberState.Accepted, "accepted and not redeemed yet " );
178
179
require (avatar.nativeReputation ().balanceOf (proposer) == 0 , "already a member " );
179
180
require (_feeAmount >= minFeeToJoin, "_feeAmount should be >= then the minFeeToJoin " );
180
- fundings[proposer].candidate = true ;
181
+ fundings[proposer].state = MemeberState.Candidate ;
181
182
if (fundingToken == IERC20 (0 )) {
182
- require (_feeAmount == msg .value , "ETH received shoul match the _feeAmount " );
183
+ require (_feeAmount == msg .value , "ETH received should match the _feeAmount " );
183
184
} else {
184
185
fundingToken.safeTransferFrom (proposer, address (this ), _feeAmount);
185
186
}
186
187
bytes32 proposalId = votingMachine.propose (2 , voteParamsHash, proposer, address (avatar));
187
188
188
189
Proposal memory proposal = Proposal ({
189
- executed: false ,
190
190
proposedMember: proposer,
191
- funding : _feeAmount,
192
- accepted: false
191
+ funding : _feeAmount
193
192
});
194
193
proposals[proposalId] = proposal;
195
194
@@ -211,22 +210,22 @@ contract JoinAndQuit is
211
210
* @return reputation the redeemed reputation.
212
211
*/
213
212
function redeemReputation (bytes32 _proposalId ) public returns (uint256 reputation ) {
214
- Proposal memory _proposal = proposals[_proposalId];
215
- Proposal storage proposal = proposals[_proposalId];
213
+ Proposal memory proposal = proposals[_proposalId];
216
214
require (proposal.proposedMember != address (0 ), "no member to redeem " );
217
215
require (! fundings[proposal.proposedMember].rageQuit, "member already rageQuit " );
218
- require (proposal.accepted == true , " proposal not accepted " );
216
+ require (fundings[ proposal.proposedMember].state == MemeberState.Accepted , "member not accepeted " );
219
217
//set proposal proposedMember to zero to prevent reentrancy attack.
220
- proposal.proposedMember = address (0 );
218
+ proposals[_proposalId].proposedMember = address (0 );
219
+ fundings[proposal.proposedMember].state = MemeberState.ReputationRedeemed;
221
220
if (memberReputation == 0 ) {
222
- reputation = _proposal .funding;
221
+ reputation = proposal .funding;
223
222
} else {
224
223
reputation = memberReputation;
225
224
}
226
225
require (
227
226
Controller (
228
- avatar.owner ()).mintReputation (reputation, _proposal .proposedMember), "failed to mint reputation " );
229
- emit RedeemReputation (address (avatar), _proposalId, _proposal .proposedMember, reputation);
227
+ avatar.owner ()).mintReputation (reputation, proposal .proposedMember), "failed to mint reputation " );
228
+ emit RedeemReputation (address (avatar), _proposalId, proposal .proposedMember, reputation);
230
229
}
231
230
232
231
/**
@@ -264,11 +263,11 @@ contract JoinAndQuit is
264
263
refundAmount = userDonation.mul (fundingToken.balanceOf (address (avatar))).div (totalDonation);
265
264
}
266
265
totalDonation = totalDonation.sub (userDonation);
267
- sendToBeneficiary (refundAmount, msg .sender );
268
266
uint256 msgSenderReputation = avatar.nativeReputation ().balanceOf (msg .sender );
269
267
require (
270
268
Controller (
271
269
avatar.owner ()).burnReputation (msgSenderReputation, msg .sender ));
270
+ sendToBeneficiary (refundAmount, msg .sender );
272
271
emit RageQuit (address (avatar), msg .sender , refundAmount);
273
272
}
274
273
0 commit comments