Skip to content

Commit a869bd6

Browse files
committedOct 29, 2018
Added contracts
1 parent c39c3e0 commit a869bd6

File tree

6 files changed

+564
-0
lines changed

6 files changed

+564
-0
lines changed
 

‎contracts/ribbonincentive.sol

+311
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
pragma solidity ^0.4.24;
2+
pragma experimental ABIEncoderV2;
3+
4+
contract ribbonincentive {
5+
address private ribbonOwner;
6+
7+
struct Donation {
8+
uint amount;
9+
uint timeStamp;
10+
}
11+
12+
struct Practitioner {
13+
uint allowance;
14+
uint pastSentTokens;
15+
uint arrayPosition;
16+
}
17+
18+
struct User {
19+
bool registered;
20+
uint balance;
21+
uint totalEarned;
22+
uint arrayPosition;
23+
}
24+
25+
struct Program {
26+
string name;
27+
address owner;
28+
mapping (address => Donation[]) sponsors;
29+
address[] allSponsors;
30+
mapping (address => Practitioner) practitioners;
31+
address[] allPractitioners;
32+
mapping (address => User) users;
33+
address[] allUsers;
34+
uint balance;
35+
uint totalDonated;
36+
}
37+
38+
Program[] allPrograms;
39+
uint[] allDonationAmounts;
40+
uint[] allDonationTimeStamps;
41+
42+
modifier onlyOwnerOfProgram(uint _programID) {
43+
require(msg.sender == allPrograms[_programID].owner, "Function is only accessable by program owner");
44+
_;
45+
}
46+
47+
modifier onlyRibbon() {
48+
require(msg.sender == ribbonOwner, "Function is only accessable by Ribbon owner");
49+
_;
50+
}
51+
52+
constructor()
53+
public
54+
{
55+
ribbonOwner = msg.sender;
56+
}
57+
58+
//PROGRAM functions
59+
60+
function createProgram(string _name, address _owner)
61+
public
62+
payable
63+
onlyRibbon()
64+
returns(uint programID)
65+
{
66+
address[] memory _allSponsors;
67+
address[] memory _allPractitioners;
68+
address[] memory _allUsers;
69+
programID = allPrograms.push(Program({
70+
name: _name,
71+
owner: _owner,
72+
allSponsors: _allSponsors,
73+
allPractitioners: _allPractitioners,
74+
allUsers: _allUsers,
75+
balance: msg.value,
76+
totalDonated: 0
77+
}));
78+
}
79+
80+
function getProgramDetails(uint _programID)
81+
public
82+
view
83+
returns(
84+
string name,
85+
address owner,
86+
address[] allSponsors,
87+
address[] allPractitioners,
88+
address[] allUsers,
89+
uint balance,
90+
uint totalDonated
91+
)
92+
{
93+
name = allPrograms[_programID].name;
94+
owner = allPrograms[_programID].owner;
95+
allSponsors = allPrograms[_programID].allSponsors;
96+
allPractitioners = allPrograms[_programID].allPractitioners;
97+
allUsers = allPrograms[_programID].allUsers;
98+
balance = allPrograms[_programID].balance;
99+
totalDonated = allPrograms[_programID].totalDonated;
100+
}
101+
102+
function deleteProgram(uint _programID)
103+
public
104+
onlyOwnerOfProgram(_programID)
105+
{
106+
delete allPrograms[_programID];
107+
}
108+
109+
function changeProgramName(uint _projectID, string _newName)
110+
public
111+
onlyOwnerOfProgram(_projectID)
112+
returns(string projectName)
113+
{
114+
allPrograms[_projectID].name = _newName;
115+
return _newName;
116+
}
117+
118+
function changeProgramOwner(uint _projectID, address _newOwner)
119+
public
120+
onlyOwnerOfProgram(_projectID)
121+
returns(address newOwner)
122+
{
123+
allPrograms[_projectID].owner = _newOwner;
124+
return _newOwner;
125+
}
126+
127+
//DONOR functions
128+
129+
function donate(uint _programID)
130+
public
131+
payable
132+
{
133+
uint donationAmount = msg.value;
134+
require(allPrograms[_programID].owner != 0x0, "Invalid program ID");
135+
if(allPrograms[_programID].sponsors[msg.sender].length == 0){
136+
allPrograms[_programID].allSponsors.push(msg.sender);
137+
}
138+
allPrograms[_programID].sponsors[msg.sender].push(Donation({
139+
amount: donationAmount,
140+
timeStamp: now
141+
}));
142+
allPrograms[_programID].balance += donationAmount;
143+
allPrograms[_programID].totalDonated += donationAmount;
144+
}
145+
146+
function getAllDonations(uint _programID)
147+
public
148+
view
149+
returns(uint)
150+
{
151+
return allPrograms[_programID].totalDonated;
152+
}
153+
154+
function getDonations(uint _programID, address _donor)
155+
public
156+
view
157+
returns(
158+
uint[],
159+
uint[]
160+
)
161+
{
162+
for(uint i = 0; i < allPrograms[_programID].sponsors[_donor].length; i++){
163+
allDonationAmounts.push((uint)(allPrograms[_programID].sponsors[_donor][i].amount));
164+
allDonationTimeStamps.push((uint)(allPrograms[_programID].sponsors[_donor][i].timeStamp));
165+
}
166+
return(allDonationAmounts, allDonationTimeStamps);
167+
}
168+
169+
//USER functions
170+
171+
function addUsers(uint _programID, address[] _users)
172+
public
173+
onlyOwnerOfProgram(_programID)
174+
returns(address[])
175+
{
176+
for(uint i = 0; i < _users.length; i++){
177+
allPrograms[_programID].users[_users[i]] = User({
178+
registered: true,
179+
balance: 0,
180+
totalEarned: 0,
181+
arrayPosition: i
182+
});
183+
allPrograms[_programID].allUsers.push(_users[i]);
184+
}
185+
return allPrograms[_programID].allUsers;
186+
}
187+
188+
function getAllUsers(uint _programID)
189+
public
190+
view
191+
returns(address[])
192+
{
193+
return allPrograms[_programID].allUsers;
194+
}
195+
196+
function getUser(uint _programID, address _user)
197+
public
198+
view
199+
returns(
200+
bool registered,
201+
uint balance,
202+
uint totalEarned,
203+
uint arrayPosition
204+
)
205+
{
206+
registered = allPrograms[_programID].users[_user].registered;
207+
balance = allPrograms[_programID].users[_user].balance;
208+
totalEarned = allPrograms[_programID].users[_user].totalEarned;
209+
arrayPosition = allPrograms[_programID].users[_user].arrayPosition;
210+
}
211+
212+
function userEarned(
213+
uint _programID,
214+
address _user,
215+
uint _amountEarned,
216+
address _practitioner
217+
)
218+
public
219+
{
220+
require(msg.sender == _practitioner);
221+
require(allPrograms[_programID].practitioners[_practitioner].allowance != 0);
222+
require(_amountEarned <= allPrograms[_programID].practitioners[_practitioner].allowance,"Exceeds your practitioner limit. Please request a rest");
223+
allPrograms[_programID].users[_user].balance += _amountEarned;
224+
allPrograms[_programID].users[_user].totalEarned += _amountEarned;
225+
allPrograms[_programID].practitioners[_practitioner].allowance -= _amountEarned;
226+
allPrograms[_programID].practitioners[_practitioner].pastSentTokens += _amountEarned;
227+
allPrograms[_programID].balance -= _amountEarned;
228+
}
229+
230+
function userWithdraw(uint _programID, uint _amount)
231+
public
232+
{
233+
require(allPrograms[_programID].users[msg.sender].registered == true, "You are not registered");
234+
require( allPrograms[_programID].users[msg.sender].balance >= _amount, "Insufficient funds");
235+
allPrograms[_programID].users[msg.sender].balance -= _amount;
236+
}
237+
238+
function removeUser(uint _programID, address _user)
239+
public
240+
onlyOwnerOfProgram(_programID)
241+
{
242+
require(allPrograms[_programID].users[_user].balance == 0, "Please withdraw remaining balance before removing user.");
243+
delete allPrograms[_programID].allUsers[allPrograms[_programID].users[_user].arrayPosition];
244+
allPrograms[_programID].users[_user] = User({
245+
registered: false,
246+
balance: 0,
247+
totalEarned: 0,
248+
arrayPosition: 999
249+
});
250+
//could refractor to move last position to removed position.
251+
}
252+
253+
//PRACTITIONERS functions
254+
255+
function addPractitioners(uint _programID, address[] _practitioners, uint _practitionerAllowance)
256+
public
257+
onlyOwnerOfProgram(_programID)
258+
returns(address[])
259+
{
260+
for(uint i = 0; i < _practitioners.length; i++){
261+
allPrograms[_programID].practitioners[_practitioners[i]] = Practitioner({
262+
allowance: _practitionerAllowance,
263+
pastSentTokens: 0,
264+
arrayPosition: i
265+
});
266+
allPrograms[_programID].allPractitioners.push(_practitioners[i]);
267+
}
268+
return allPrograms[_programID].allPractitioners;
269+
}
270+
271+
function changePractitionersAllowance(uint _programID, address _practitioner, uint _newAllowance)
272+
public
273+
onlyOwnerOfProgram(_programID)
274+
{
275+
allPrograms[_programID].practitioners[_practitioner].allowance += _newAllowance;
276+
}
277+
278+
function removePractitioner(uint _programID, address _practitioner)
279+
public
280+
onlyOwnerOfProgram(_programID)
281+
{
282+
delete allPrograms[_programID].allPractitioners[allPrograms[_programID].practitioners[_practitioner].arrayPosition];
283+
allPrograms[_programID].practitioners[_practitioner] = Practitioner({
284+
allowance: 0,
285+
pastSentTokens: 0,
286+
arrayPosition: 999
287+
});
288+
}
289+
290+
function getAllPractitioners(uint _programID)
291+
public
292+
view
293+
returns(address[])
294+
{
295+
return allPrograms[_programID].allPractitioners;
296+
}
297+
298+
function getPractitioner(uint _programID, address _practitioner)
299+
public
300+
view
301+
returns(
302+
uint allowance,
303+
uint pastSentTokens,
304+
uint arrayPosition
305+
)
306+
{
307+
allowance = allPrograms[_programID].practitioners[_practitioner].allowance;
308+
pastSentTokens = allPrograms[_programID].practitioners[_practitioner].pastSentTokens;
309+
arrayPosition = allPrograms[_programID].practitioners[_practitioner].arrayPosition;
310+
}
311+
}

‎test/helpers/EVMRevert.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const EVMRevert = 'revert';
2+
3+
module.exports = {
4+
EVMRevert,
5+
};

‎test/helpers/assertRevert.js

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
const should = require('chai')
2+
.should();
3+
4+
async function assertRevert (promise) {
5+
try {
6+
await promise;
7+
} catch (error) {
8+
error.message.should.include('revert', `Expected "revert", got ${error} instead`);
9+
return;
10+
}
11+
should.fail('Expected revert not received');
12+
}
13+
14+
module.exports = {
15+
assertRevert,
16+
};

‎test/helpers/ether.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
function ether(n) {
2+
return new web3.BigNumber(web3.toWei(n, 'ether'));
3+
}
4+
5+
module.exports = {
6+
ether,
7+
};

‎test/helpers/expectThrow.js

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
const should = require('chai')
2+
.should();
3+
4+
async function expectThrow(promise, message) {
5+
try {
6+
await promise;
7+
} catch (error) {
8+
// Message is an optional parameter here
9+
if (message) {
10+
error.message.should.include(message, 'Expected \'' + message + '\', got \'' + error + '\' instead');
11+
return;
12+
} else {
13+
// TODO: Check jump destination to destinguish between a throw
14+
// and an actual invalid jump.
15+
// TODO: When we contract A calls contract B, and B throws, instead
16+
// of an 'invalid jump', we get an 'out of gas' error. How do
17+
// we distinguish this from an actual out of gas event? (The
18+
// ganache log actually show an 'invalid jump' event.)
19+
error.message.should.match(/[invalid opcode|out of gas|revert]/, 'Expected throw, got \'' + error + '\' instead');
20+
return;
21+
}
22+
}
23+
should.fail('Expected throw not received');
24+
}
25+
26+
module.exports = {
27+
expectThrow,
28+
};

0 commit comments

Comments
 (0)
Please sign in to comment.