Skip to content
This repository has been archived by the owner on Apr 29, 2019. It is now read-only.

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jakub-wojciechowski committed Jun 28, 2017
0 parents commit ae10d77
Show file tree
Hide file tree
Showing 28 changed files with 2,099 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .gitignore
@@ -0,0 +1,9 @@
# Dependency directory
node_modules

# Generated files
build
environments

# IDE
.idea
21 changes: 21 additions & 0 deletions LICENSE.txt
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2017 Alice Ltd. (Jakub Wojciechowski jakub@alice.si)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
82 changes: 82 additions & 0 deletions README.md
@@ -0,0 +1,82 @@
# Alice Smart Contracts

This project is a collection of smart contracts that are used by <https://alice.si>.

### Overview

Smart contracts implement a Pay for success donation model. After a donor sends money to the campaign, a corresponding amount of Alice Tokens are being generated and credited to the Charity contract. Tokens are held in an escrow and are released only if a dedicated Validator confirms that the expected outcome has been achieved. Tokens are moved to the Beneficiary account after the validation is performed. Any outstanding tokens may be returned to donors and reused for future donations.

### Installation
This project requires [node-js](https://github.com/nodejs/node) runtime and uses [truffle](https://github.com/trufflesuite/truffle) Ethereum smart contracts development framework. In order to run it, install truffle first:

npm install -g truffle

Then install all of the node-js dependencies

npm install

Connection to blockchain node is defined in truffle.js:

networks: {
dev: {
network_id: "*",
gas: 4000000,
host: 'localhost',
port: '8545'
}
}

We recommend using popular Ethereum test client [testrpc](https://github.com/ethereumjs/testrpc) as a default node:

npm install -g ethereumjs-testrpc

### Running tests

To run all of the smart contract tests use following truffle command in your console:

truffle test --network dev

If you are using testrpc client remember to start it with sufficient number of test accounts:

testrpc -a 100

### Demo dApp

We created a demo dApp so you can interact and test smart contract in a visual environment rather than hacking console scripts. To run this mode please deploy the smart contracts to your blockchain network:

truffle migrate --network dev

... and then launch a demo server:

truffle serve

This demo dApp should be available at: http://localhost:8080/ a look like that:
![screenshot](https://s3.eu-west-2.amazonaws.com/alice-res/alice-dApp.png)

## Contributions

All comments, ideas for improvements and pull requests are welcomed. We want to improve the project based on feedback from the community.

## License

MIT License

Copyright (c) 2017 Alice Ltd. (Jakub Wojciechowski jakub@alice.si)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
122 changes: 122 additions & 0 deletions app/index.html
@@ -0,0 +1,122 @@
<!DOCTYPE html>
<html>
<head>
<title>Alice</title>
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ionicons/2.0.1/css/ionicons.min.css">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<link href="./app.css" rel='stylesheet' type='text/css'>
<script src="//code.jquery.com/jquery-1.10.2.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="./app.js"></script>
</head>
<body>
<section class="content-header">
<h1>
Alice
<small>Smart Contracts Demo</small>
</h1>
</section>

<div class="row">
<div class="col-lg-3 col-xs-6">
<!-- small box -->
<div class="small-box bg-aqua">
<div class="inner" style="height: 128px">
<h3>Donor 1</h3>
<p><i class="fa fa-database"></i> <span id="balance_donor_1"></span> LHC</p>
</div>
<div class="icon">
<i class="ion ion-person"></i>
</div>
<a href="#" class="small-box-footer" onclick="donate(donor1Account, 20)">Donate (20) <i class="fa fa-arrow-circle-right"></i></a>
<a href="#" class="small-box-footer" onclick="reuseUnspent(donor1Account)">Reuse Unspent <i class="fa fa-arrow-circle-right"></i></a>
</div>

<div class="small-box bg-aqua">
<div class="inner" style="height: 128px">
<h3>Donor 2</h3>
<p><i class="fa fa-database"></i> <span id="balance_donor_2"></span> LHC</p>
</div>
<div class="icon">
<i class="ion ion-person"></i>
</div>
<a href="#" class="small-box-footer" onclick="donate(donor2Account, 20)">Donate (20) <i class="fa fa-arrow-circle-right"></i></a>
<a href="#" class="small-box-footer" onclick="reuseUnspent(donor2Account)">Reuse Unspent <i class="fa fa-arrow-circle-right"></i></a>
</div>

</div>

<!-- ./col -->
<div class="col-lg-3 col-xs-6">
<!-- small box -->
<div class="small-box bg-yellow">
<div class="inner" style="height: 355px">
<h3>Contract</h3>
<p><i class="fa fa-databas"></i> <span id="balance_charity"></span> LHC</p>
<p><i class="fa fa-databas"></i> <span id="accounts"></span> unspent accounts</p>
<div style="font-style: italic; text-align: center; padding-top: 20px">
Smart contract. Works as an escrow keeping donations before an outcome payment is authorized.
</div>
</div>
<div class="icon">
<i class="ion ion-ios-list-outline"></i>
</div>
<a href="#" class="small-box-footer" onclick="payBackAll()"><i class="fa fa-arrow-circle-left"></i> Pay back</a>
</div>
</div>
<!-- ./col -->
<div class="col-lg-3 col-xs-6">
<!-- small box -->
<div class="small-box bg-red">
<div class="inner" style="height: 330px">
<h3>Judge</h3>

<p>External validator</p>

<div style="font-style: italic; text-align: center; padding-top: 20px">
Trusted organization (e.g. government agency) which authorize outcome payments.
</div>
</div>
<div class="icon">
<i class="ion ion-android-checkbox-outline"></i>
</div>
<a href="#" class="small-box-footer" onclick="validateOutcome('Tenancy', 200)">Tenancy agreement (200) <i class="fa fa-arrow-circle-right"></i></a>
<a href="#" class="small-box-footer" onclick="validateOutcome('Employment', 100)">Employment contract (100) <i class="fa fa-arrow-circle-right"></i></a>
</div>
</div>
<div class="col-lg-3 col-xs-6">
<!-- small box -->
<div class="small-box bg-green">
<div class="inner" style="height: 383px">
<h3>Beneficiary</h3>

<p><i class="fa fa-database"></i> <span id="balance_beneficiary"></span> LHC</p>

<div style="font-style: italic; text-align: center; padding-top: 20px">
Charity organization which use the money to provide help for homeless people.
</div>

</div>
<div class="icon">
<i class="ion ion-ios-people-outline"></i>
</div>
</div>
</div>
<!-- ./col -->
</div>

<div class="box box-primary" style="background-color: #F0F0F0; border-color: #ddd">
<div class="box-header with-border" style="border-bottom: 1px solid #ddd;">
<h3 class="box-title">Blockchain logs</h3>
</div>
<!-- /.box-header -->
<div class="box-body" id="log">

</div>
<!-- /.box-body -->
</div>

</body>
</html>
154 changes: 154 additions & 0 deletions app/javascripts/app.js
@@ -0,0 +1,154 @@
var accounts;
var aliceAccount;
var donor1Account;
var donor2Account;
var beneficiaryAccount;
var judgeAccount;

var TokenContract;
var CharityContract;
var ImpactContract;

var balances = {};

function refreshBalance() {
showBalance(donor1Account, "balance_donor_1");
showBalance(donor2Account, "balance_donor_2");
showBalance(CharityContract.address, "balance_charity");
showBalance(beneficiaryAccount, "balance_beneficiary");
}

function showBalance(account, element) {
TokenContract.balanceOf(account).then(function(value) {
var balance_element = document.getElementById(element);
balance_element.innerHTML = value.valueOf();
balances[account] = value;
});
}

function showAllImpacts() {
showImpact('Tenancy');
showImpact('Employment');
}

function showImpact(name) {
ImpactContract.getImpactCount.call(name).then(function(c) {
var count = c.valueOf();
console.log(name + ' impact: ' + count);
for(var i=0; i < count; i++) {
(function(index) {
ImpactContract.getImpactDonor.call(name, i).then(function (address) {
console.log(name + ' address[' + index + ']: ' + address);
ImpactContract.getImpactValue.call(name, address).then(function (value) {
console.log(name + ' value[' + index + ']: ' + value);
});
});
})(i);
}
});
}

function donate(account, value) {
TokenContract.mint(CharityContract.address, value, {from: aliceAccount, gas: 1000000}).then(function(tx) {
return CharityContract.notify(account, value, {from: aliceAccount, gas: 1000000})
.then(function () {
refreshBalance();
return null;
});
})
}

function reuseUnspent(account) {
TokenContract.transfer(CharityContract.address, balances[account], {from: account, gas: 1000000})
.then(function(tx) {
return CharityContract.notify(account, balances[account], {from: aliceAccount, gas: 1000000})
.then(function () {
console.log("Donated remaining funds: " + balances[account]);
refreshBalance();
return null;
});
});
}

function validateOutcome(name, value) {
return CharityContract.unlockOutcome(name, value, {from: judgeAccount, gas: 500000}).then(function() {
console.log("Validating outcome: " + name + " valued at: " + value);
refreshBalance();
showAllImpacts();
return linkImpact(name, value);
});
}

function payBackAll() {
payBack(donor1Account);
payBack(donor2Account);
}

function payBack(account) {
CharityContract.payBack(account, {from: aliceAccount, gas: 1000000}).then(function() {
console.log("Payback done");
refreshBalance();
return null;
});
}

function linkImpact(name, outcomeValue) {
return ImpactContract.getImpactLinked.call(name, {from: aliceAccount}).then(function(val) {
console.log("Linked: " + val + " of: " + outcomeValue);
if (val < outcomeValue) {
console.log("Linking impact: " + val + " of: " + outcomeValue);
return ImpactContract.linkImpact(name, {from: aliceAccount, gas: 2000000}).then(function(tx) {
return linkImpact(name, outcomeValue);
});
}
});
}

function mapAccounts(accounts) {
aliceAccount = accounts[0];
judgeAccount = accounts[1];
beneficiaryAccount = accounts[2];
donor1Account = accounts[3];
donor2Account = accounts[4];
}

function setupWeb3Filter() {
var filter = web3.eth.filter({});

filter.watch(function (error, log) {
console.log(log);
var logBox = document.getElementById("log");
logBox.innerHTML += "Transaction hash: " + log.transactionHash + "<br/>";
});
}

window.onload = function() {
AliceToken.deployed()
.then(function (instance) {
TokenContract = instance;
console.log(TokenContract);
return Charity.deployed();
}).then(function(instance) {
CharityContract = instance;
return ImpactRegistry.deployed();
}).then(function(instance) {
ImpactContract = instance;
web3.eth.getAccounts(function(err, accs) {
if (err != null) {
alert("There was an error fetching your accounts.");
return;
}

if (accs.length == 0) {
alert("Couldn't get any accounts! Make sure your Ethereum client is configured correctly.");
return;
}

mapAccounts(accs);
refreshBalance();
});
});

setupWeb3Filter();

}

0 comments on commit ae10d77

Please sign in to comment.