Skip to content

Commit 780bbed

Browse files
authored
Only join (#780)
* joinandquit fix * opt * remove ragequit and refund * tests * tests * spelling * bump version to "version": "0.1.2-rc.5",
1 parent 572d842 commit 780bbed

File tree

8 files changed

+648
-946
lines changed

8 files changed

+648
-946
lines changed

contracts/schemes/JoinAndQuit.sol renamed to contracts/schemes/Join.sol

Lines changed: 15 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,17 @@ import "./CommonInterface.sol";
99
/**
1010
* @title A scheme for join in a dao.
1111
* - A member can be proposed to join in by sending a min amount of fee.
12-
* - A member can ask to quite (RageQuit) a dao on any time.
1312
* - A member can donate to a dao.
1413
*/
15-
contract JoinAndQuit is
14+
contract Join is
1615
VotingMachineCallbacks,
1716
ProposalExecuteInterface,
1817
CommonInterface {
1918
using SafeMath for uint;
2019
using SafeERC20 for IERC20;
2120
using StringUtil for string;
2221

23-
enum MemeberState { None, Candidate, Accepted, Rejected, ReputationRedeemed }
22+
enum MemberState { None, Candidate, Accepted, Rejected, ReputationRedeemed }
2423

2524
event JoinInProposal(
2625
address indexed _avatar,
@@ -34,18 +33,6 @@ contract JoinAndQuit is
3433
address indexed _avatar
3534
);
3635

37-
event RageQuit(
38-
address indexed _avatar,
39-
address indexed _rageQuitter,
40-
uint256 indexed _refund
41-
);
42-
43-
event Refund(
44-
address indexed _avatar,
45-
address indexed _beneficiary,
46-
uint256 indexed _refund
47-
);
48-
4936
event RedeemReputation(
5037
address indexed _avatar,
5138
bytes32 indexed _proposalId,
@@ -59,22 +46,15 @@ contract JoinAndQuit is
5946
uint256 funding;
6047
}
6148

62-
struct MemberFund {
63-
MemeberState state;
64-
bool rageQuit;
65-
uint256 funding;
66-
}
67-
6849
mapping(bytes32=>Proposal) public proposals;
69-
mapping(address=>MemberFund) public fundings;
50+
mapping(address=>MemberState) public membersState;
7051

7152
IERC20 public fundingToken;
7253
uint256 public minFeeToJoin;
7354
uint256 public memberReputation;
7455
uint256 public fundingGoal;
7556
uint256 public fundingGoalDeadline;
7657
uint256 public totalDonation;
77-
bool public rageQuitEnable;
7858

7959
/**
8060
* @dev initialize
@@ -89,7 +69,6 @@ contract JoinAndQuit is
8969
if this param is zero so the repution will be allocated proportional to the fee paid
9070
* @param _fundingGoal the funding goal
9171
* @param _fundingGoalDeadline the funding goal deadline
92-
* @param _rageQuitEnable rageQuit enabling flag
9372
*/
9473
function initialize(
9574
Avatar _avatar,
@@ -101,8 +80,7 @@ contract JoinAndQuit is
10180
uint256 _minFeeToJoin,
10281
uint256 _memberReputation,
10382
uint256 _fundingGoal,
104-
uint256 _fundingGoalDeadline,
105-
bool _rageQuitEnable
83+
uint256 _fundingGoalDeadline
10684
)
10785
external
10886
{
@@ -112,7 +90,6 @@ contract JoinAndQuit is
11290
memberReputation = _memberReputation;
11391
fundingGoal = _fundingGoal;
11492
fundingGoalDeadline = _fundingGoalDeadline;
115-
rageQuitEnable = _rageQuitEnable;
11693
}
11794

11895
/**
@@ -127,13 +104,12 @@ contract JoinAndQuit is
127104
returns(bool) {
128105
Proposal memory proposal = proposals[_proposalId];
129106
require(proposal.proposedMember != address(0), "not a valid proposal");
130-
require(fundings[proposal.proposedMember].state == MemeberState.Candidate, "proposal already been executed");
107+
require(membersState[proposal.proposedMember] == MemberState.Candidate, "member is not a cadidate");
131108

132109
bool success;
133110
// Check if vote was successful:
134111
if ((_decision == 1) && (avatar.nativeReputation().balanceOf(proposal.proposedMember) == 0)) {
135-
fundings[proposal.proposedMember].state = MemeberState.Accepted;
136-
fundings[proposal.proposedMember].funding = proposal.funding;
112+
membersState[proposal.proposedMember] = MemberState.Accepted;
137113
totalDonation = totalDonation.add(proposal.funding);
138114
if (fundingToken == IERC20(0)) {
139115
// solhint-disable-next-line
@@ -145,7 +121,7 @@ contract JoinAndQuit is
145121
//this should be called/check after the transfer to the avatar.
146122
setFundingGoalReachedFlag();
147123
} else {
148-
fundings[proposal.proposedMember].state = MemeberState.Rejected;
124+
membersState[proposal.proposedMember] = MemberState.Rejected;
149125
if (fundingToken == IERC20(0)) {
150126
// solhint-disable-next-line
151127
(success, ) = proposal.proposedMember.call{value:proposal.funding}("");
@@ -174,11 +150,11 @@ contract JoinAndQuit is
174150
returns(bytes32)
175151
{
176152
address proposer = msg.sender;
177-
require(fundings[proposer].state != MemeberState.Candidate, "already a candidate");
178-
require(fundings[proposer].state != MemeberState.Accepted, "accepted and not redeemed yet");
179-
require(avatar.nativeReputation().balanceOf(proposer) == 0, "already a member");
180-
require(_feeAmount >= minFeeToJoin, "_feeAmount should be >= then the minFeeToJoin");
181-
fundings[proposer].state = MemeberState.Candidate;
153+
require(membersState[proposer] != MemberState.Candidate, "proposer is already a candidate");
154+
require(membersState[proposer] != MemberState.Accepted, "proposer is accepted and not redeemed yet");
155+
require(avatar.nativeReputation().balanceOf(proposer) == 0, "proposer is already a member");
156+
require(_feeAmount >= minFeeToJoin, "_feeAmount should be >= than the minFeeToJoin");
157+
membersState[proposer] = MemberState.Candidate;
182158
if (fundingToken == IERC20(0)) {
183159
require(_feeAmount == msg.value, "ETH received should match the _feeAmount");
184160
} else {
@@ -212,11 +188,11 @@ contract JoinAndQuit is
212188
function redeemReputation(bytes32 _proposalId) public returns(uint256 reputation) {
213189
Proposal memory proposal = proposals[_proposalId];
214190
require(proposal.proposedMember != address(0), "no member to redeem");
215-
require(!fundings[proposal.proposedMember].rageQuit, "member already rageQuit");
216-
require(fundings[proposal.proposedMember].state == MemeberState.Accepted, "member not accepeted");
191+
require(membersState[proposal.proposedMember] == MemberState.Accepted, "member not accepted");
217192
//set proposal proposedMember to zero to prevent reentrancy attack.
218193
proposals[_proposalId].proposedMember = address(0);
219-
fundings[proposal.proposedMember].state = MemeberState.ReputationRedeemed;
194+
proposals[_proposalId].proposedMember = address(0);
195+
membersState[proposal.proposedMember] = MemberState.ReputationRedeemed;
220196
if (memberReputation == 0) {
221197
reputation = proposal.funding;
222198
} else {
@@ -228,49 +204,6 @@ contract JoinAndQuit is
228204
emit RedeemReputation(address(avatar), _proposalId, proposal.proposedMember, reputation);
229205
}
230206

231-
/**
232-
* @dev refund refund donator if the the funding goal did not reached till the funding goal deadline.
233-
* @return refundAmount the refund amount
234-
*/
235-
function refund() public returns(uint256 refundAmount) {
236-
// solhint-disable-next-line not-rely-on-time
237-
require(now > fundingGoalDeadline, "can refund only after fundingGoalDeadline");
238-
require(
239-
(avatar.db(FUNDED_BEFORE_DEADLINE_KEY).hashCompareWithLengthCheck(FUNDED_BEFORE_DEADLINE_VALUE) == false),
240-
"can refund only if funding goal not reached");
241-
require(fundings[msg.sender].funding > 0, "no funds to refund");
242-
refundAmount = fundings[msg.sender].funding;
243-
fundings[msg.sender].funding = 0;
244-
sendToBeneficiary(refundAmount, msg.sender);
245-
emit Refund(address(avatar), msg.sender, refundAmount);
246-
}
247-
248-
/**
249-
* @dev rageQuit quit from the dao.
250-
* can be done on any time
251-
* REFUND = USER_DONATION * CURRENT_DAO_BALANCE / TOTAL_DONATIONS
252-
* @return refundAmount the refund amount
253-
*/
254-
function rageQuit() public returns(uint256 refundAmount) {
255-
require(rageQuitEnable, "RageQuit disabled");
256-
require(fundings[msg.sender].funding > 0, "no fund to RageQuit");
257-
uint256 userDonation = fundings[msg.sender].funding;
258-
fundings[msg.sender].funding = 0;
259-
fundings[msg.sender].rageQuit = true;
260-
if (fundingToken == IERC20(0)) {
261-
refundAmount = userDonation.mul(address(avatar.vault()).balance).div(totalDonation);
262-
} else {
263-
refundAmount = userDonation.mul(fundingToken.balanceOf(address(avatar))).div(totalDonation);
264-
}
265-
totalDonation = totalDonation.sub(userDonation);
266-
uint256 msgSenderReputation = avatar.nativeReputation().balanceOf(msg.sender);
267-
require(
268-
Controller(
269-
avatar.owner()).burnReputation(msgSenderReputation, msg.sender));
270-
sendToBeneficiary(refundAmount, msg.sender);
271-
emit RageQuit(address(avatar), msg.sender, refundAmount);
272-
}
273-
274207
/**
275208
* @dev setFundingGoalReachedFlag check if funding goal reached.
276209
*/
@@ -294,21 +227,4 @@ contract JoinAndQuit is
294227
}
295228
}
296229

297-
/**
298-
* @dev sendToBeneficiary send amount of eth or token to beneficiary
299-
* @param _amount the amount to send
300-
* @param _beneficiary the beneficiary
301-
*/
302-
function sendToBeneficiary(uint256 _amount, address payable _beneficiary) private {
303-
if (fundingToken == IERC20(0)) {
304-
require(
305-
Controller(
306-
avatar.owner()).sendEther(_amount, _beneficiary), "send ether failed");
307-
} else {
308-
require(
309-
Controller(
310-
avatar.owner()).externalTokenTransfer(fundingToken, _beneficiary, _amount), "send token failed");
311-
}
312-
}
313-
314230
}

contracts/utils/Redeemer.sol

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pragma solidity ^0.6.12;
44
import "../schemes/ContributionReward.sol";
55
import "../schemes/ContributionRewardExt.sol";
66
import "../schemes/FundingRequest.sol";
7-
import "../schemes/JoinAndQuit.sol";
7+
import "../schemes/Join.sol";
88
import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/IERC20.sol";
99

1010

@@ -125,11 +125,11 @@ contract Redeemer {
125125
* @dev helper to redeem rewards for a proposal
126126
* It calls execute on the proposal if it is not yet executed.
127127
* It tries to redeem reputation and stake from the GenesisProtocol.
128-
* It tries to redeem proposal rewards from the JoinAndQuit scheme.
128+
* It tries to redeem proposal rewards from the Join scheme.
129129
* This function does not emit events.
130-
* A client should listen to GenesisProtocol and JoinAndQuit redemption events
130+
* A client should listen to GenesisProtocol and Join redemption events
131131
* to monitor redemption operations.
132-
* @param _joinAndQuit joinAndQuit scheme
132+
* @param _join join scheme
133133
* @param _genesisProtocol genesisProtocol
134134
* @param _proposalId the ID of the voting in the voting machine
135135
* @param _beneficiary beneficiary
@@ -145,9 +145,9 @@ contract Redeemer {
145145
* @return winningVote
146146
* 1 - executed or closed and the winning vote is YES
147147
* 2 - executed or closed and the winning vote is NO
148-
* @return joinAndQuitReputationReward Reputation - from JoinAndQuit reputation reward
148+
* @return joinReputationReward Reputation - from Join reputation reward
149149
*/
150-
function redeemJoinAndQuit(JoinAndQuit _joinAndQuit,
150+
function redeemJoin(Join _join,
151151
GenesisProtocol _genesisProtocol,
152152
bytes32 _proposalId,
153153
address _beneficiary)
@@ -156,14 +156,14 @@ contract Redeemer {
156156
uint[2] memory gpDaoBountyReward,
157157
bool executed,
158158
uint256 winningVote,
159-
uint256 joinAndQuitReputationReward
159+
uint256 joinReputationReward
160160
)
161161
{
162-
bool callJoinAndQuit;
163-
(gpRewards, gpDaoBountyReward, executed, winningVote, callJoinAndQuit) =
162+
bool callJoin;
163+
(gpRewards, gpDaoBountyReward, executed, winningVote, callJoin) =
164164
genesisProtocolRedeem(_genesisProtocol, _proposalId, _beneficiary);
165-
if (callJoinAndQuit) {
166-
joinAndQuitReputationReward = _joinAndQuit.redeemReputation(_proposalId);
165+
if (callJoin) {
166+
joinReputationReward = _join.redeemReputation(_proposalId);
167167
}
168168
}
169169

0 commit comments

Comments
 (0)