Skip to content

Commit 5f47038

Browse files
authored
Add FundingRequest scheme (#725)
* Add FundingRequest scheme * Update FundingRequest scheme * lint * Update * Update FundingRequest.sol
1 parent c9921be commit 5f47038

File tree

5 files changed

+1583
-235
lines changed

5 files changed

+1583
-235
lines changed
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
pragma solidity ^0.5.16;
2+
3+
import "../votingMachines/VotingMachineCallbacks.sol";
4+
import "../libs/StringUtil.sol";
5+
import "@openzeppelin/upgrades/contracts/Initializable.sol";
6+
import "./CommonInterface.sol";
7+
8+
9+
/**
10+
* @title A scheme for requesting funding from an organization
11+
*/
12+
13+
contract FundingRequest is
14+
VotingMachineCallbacks,
15+
ProposalExecuteInterface,
16+
Initializable,
17+
CommonInterface {
18+
using SafeMath for uint;
19+
using StringUtil for string;
20+
21+
event NewFundingProposal(
22+
address indexed _avatar,
23+
bytes32 indexed _proposalId,
24+
address payable _beneficiary,
25+
uint256 _amount,
26+
string _descriptionHash
27+
);
28+
29+
event ProposalExecuted(address indexed _avatar, bytes32 indexed _proposalId, bool _decision);
30+
31+
event Redeem(
32+
address indexed _avatar,
33+
bytes32 indexed _proposalId,
34+
address indexed _beneficiary,
35+
uint256 _amount
36+
);
37+
38+
struct Proposal {
39+
address payable beneficiary;
40+
uint256 amount;
41+
string descriptionHash;
42+
uint256 executionTime;
43+
}
44+
45+
mapping(bytes32=>Proposal) public proposals;
46+
47+
IntVoteInterface public votingMachine;
48+
bytes32 public voteParams;
49+
Avatar public avatar;
50+
IERC20 public fundingToken;
51+
52+
/**
53+
* @dev initialize
54+
* @param _avatar the avatar this scheme referring to.
55+
* @param _votingMachine the voting machines address to
56+
* @param _voteParams voting machine parameters.
57+
* @param _fundingToken token to transfer to funding requests. 0x0 address for the native coin
58+
*/
59+
function initialize(
60+
Avatar _avatar,
61+
IntVoteInterface _votingMachine,
62+
bytes32 _voteParams,
63+
IERC20 _fundingToken
64+
)
65+
external
66+
initializer
67+
{
68+
require(_avatar != Avatar(0), "avatar cannot be zero");
69+
avatar = _avatar;
70+
votingMachine = _votingMachine;
71+
voteParams = _voteParams;
72+
fundingToken = _fundingToken;
73+
}
74+
75+
/**
76+
* @dev execution of proposals, can only be called by the voting machine in which the vote is held.
77+
* @param _proposalId the ID of the voting in the voting machine
78+
* @param _decision a parameter of the voting result, 1 yes and 2 is no.
79+
*/
80+
function executeProposal(bytes32 _proposalId, int256 _decision)
81+
external
82+
onlyVotingMachine(_proposalId)
83+
returns(bool) {
84+
require(proposals[_proposalId].executionTime == 0);
85+
require(proposals[_proposalId].beneficiary != address(0));
86+
// Check if vote was successful:
87+
if (_decision == 1) {
88+
// solhint-disable-next-line not-rely-on-time
89+
proposals[_proposalId].executionTime = now;
90+
}
91+
emit ProposalExecuted(address(avatar), _proposalId, _decision == 1);
92+
return true;
93+
}
94+
95+
/**
96+
* @dev Submit a funding request:
97+
* @param _beneficiary Who gets the funding
98+
* @param _amount Funding amount requested
99+
* @param _descriptionHash A hash of the proposal's description
100+
*/
101+
function propose(
102+
address payable _beneficiary,
103+
uint256 _amount,
104+
string memory _descriptionHash
105+
)
106+
public
107+
returns(bytes32)
108+
{
109+
require(
110+
avatar.db(FUNDED_BEFORE_DEADLINE_KEY).hashCompareWithLengthCheck(FUNDED_BEFORE_DEADLINE_VALUE),
111+
"funding is not allowed yet"
112+
);
113+
bytes32 proposalId = votingMachine.propose(2, voteParams, msg.sender, address(avatar));
114+
address payable beneficiary = _beneficiary;
115+
if (beneficiary == address(0)) {
116+
beneficiary = msg.sender;
117+
}
118+
119+
Proposal memory proposal = Proposal({
120+
beneficiary: beneficiary,
121+
amount: _amount,
122+
descriptionHash: _descriptionHash,
123+
executionTime: 0
124+
});
125+
proposals[proposalId] = proposal;
126+
127+
emit NewFundingProposal(
128+
address(avatar),
129+
proposalId,
130+
beneficiary,
131+
_amount,
132+
_descriptionHash
133+
);
134+
135+
proposalsInfo[address(votingMachine)][proposalId] = ProposalInfo({
136+
blockNumber:block.number,
137+
avatar:avatar
138+
});
139+
return proposalId;
140+
}
141+
142+
/**
143+
* @dev Redeem proposal funding
144+
* @param _proposalId the ID of the voting in the voting machine
145+
*/
146+
function redeem(bytes32 _proposalId) public {
147+
Proposal memory _proposal = proposals[_proposalId];
148+
Proposal storage proposal = proposals[_proposalId];
149+
require(proposal.executionTime != 0, "proposal does not exist or not approved");
150+
proposal.executionTime = 0;
151+
if (address(fundingToken) == address(0)) {
152+
require(
153+
Controller(avatar.owner()).sendEther(_proposal.amount, _proposal.beneficiary),
154+
"failed to transfer network token from DAO"
155+
);
156+
} else {
157+
require(
158+
Controller(avatar.owner()).externalTokenTransfer(
159+
fundingToken,
160+
_proposal.beneficiary,
161+
_proposal.amount
162+
),
163+
"failed to transfer tokens from DAO"
164+
);
165+
}
166+
emit Redeem(address(avatar), _proposalId, _proposal.beneficiary, _proposal.amount);
167+
168+
delete proposals[_proposalId];
169+
}
170+
}

0 commit comments

Comments
 (0)