Commit d6715188 authored by didi's avatar didi
Browse files

initial commit

parents
build
node_modules
/*
* Called when the contract changed and/or was (re-)deployed.
* Updates the JS contract code in the frontend accordingly (ABI and address)
* by wrapping the json data in the source file to JS and writing it to the destination file
*/
var fs = require('fs')
var process = require('process')
// 0 is the exec, 1 the js file being executed.
// Arg2 is the source file, Arg2 the destination file
const inFile = process.argv[2]
const outFile = process.argv[3]
const jsonStr = fs.readFileSync(inFile)
const outStr = `
// !!! this is autogenerated by a setup script. Changes will be overwritten !!!
const contract = ${jsonStr}`
fs.writeFileSync(outFile, outStr)
#!/bin/bash
# Invokes 'truffle migrate' (compile, re-deploy)
# and tells the node script in frontend to update the JS file representing the contract
set -e
set -u
truffle migrate
node apply_contract_update.js build/contracts/Streem.json ../frontend/js/streem_contract.js
echo "update applied"
pragma solidity ^0.4.4;
contract Migrations {
address public owner;
uint public last_completed_migration;
modifier restricted() {
if (msg.sender == owner) _;
}
function Migrations() {
owner = msg.sender;
}
function setCompleted(uint completed) restricted {
last_completed_migration = completed;
}
function upgrade(address new_address) restricted {
Migrations upgraded = Migrations(new_address);
upgraded.setCompleted(last_completed_migration);
}
}
// TODO: use the SafeMath lib of openzeppelin (implicit overflow checks etc)?
// Status of this contract: PoC of a basic ERC-20 token with streaming functionality (1 outgoing/incoming stream per account)
pragma solidity ^0.4.11;
contract Streem {
uint256 public totalSupply;
string public constant name = "Streem";
string public constant symbol = "STR";
uint8 public constant decimals = 0;
address owner;
mapping (address => uint256) staticBalances;
struct Stream {
address sender;
address receiver;
uint256 perSecond;
uint256 startTimestamp;
}
// TODO: map to array of Streams (support more than 1 per account)
mapping (address => Stream) outStreams;
mapping (address => Stream) inStreams;
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event StreamOpened(address indexed _from, address indexed _to, uint256 _perSecond);
event StreamClosed(address indexed _from, address indexed _to, uint256 _perSecond, uint256 _settledBalance, uint256 _outstandingBalance);
function Streem(uint initialSupply) {
owner = msg.sender;
staticBalances[msg.sender] = initialSupply;
totalSupply = initialSupply;
}
// TODO: this is just for the test token. Issuance mechanism for mainnet token to be decided.
function issueTo(address receiver, uint256 amount) {
require(msg.sender == owner);
staticBalances[receiver] += amount;
totalSupply += amount;
}
// TODO: return value?
function openStream(address receiver, uint256 perSecond) {
// TODO: right now it will just overwrite the config of a previous stream if any.
assert(balanceOf(msg.sender) > 0);
// now is an alias to block.timestamp. See http://solidity.readthedocs.io/en/develop/units-and-global-variables.html?highlight=blocknumber
var s = Stream(msg.sender, receiver, perSecond, now);
outStreams[msg.sender] = s;
inStreams[receiver] = s;
StreamOpened(msg.sender, receiver, perSecond);
}
// settle and close
function closeStream() {
var stream = outStreams[msg.sender];
// fail if no stream is open. TODO: support more than 1 per pair
assert(stream.startTimestamp != 0);
uint256 streamBal = (now - stream.startTimestamp) * stream.perSecond;
uint256 settleBal = 0;
uint256 outstandingBal = 0;
if(streamBal <= staticBalances[msg.sender]) {
settleBal = streamBal;
} else {
// special case: the receiver (partially) defaults on the stream
settleBal = staticBalances[msg.sender];
outstandingBal = streamBal - settleBal;
}
staticBalances[msg.sender] -= settleBal;
staticBalances[stream.receiver] += settleBal;
delete inStreams[stream.receiver];
delete outStreams[msg.sender];
StreamClosed(msg.sender, stream.receiver, stream.perSecond, settleBal, outstandingBal);
}
function transfer(address _to, uint256 _value) {
//Default assumes totalSupply can't be over max (2^256 - 1).
//If your token leaves out totalSupply and can issue more tokens as time goes on, you need to check if it doesn't wrap.
//Replace the if with this one instead.
//if (balances[msg.sender] >= _value && balances[_to] + _value > balances[_to]) {
assert(staticBalances[msg.sender] >= _value && _value > 0);
staticBalances[msg.sender] -= _value;
staticBalances[_to] += _value;
Transfer(msg.sender, _to, _value);
}
// this balance function can return a negative value if a stream went "under water"
// note that this is NOT the actual balance, just a theoretical value
function honestBalanceOf(address _owner) constant returns (int256 balance) {
uint256 inStreamBal = 0;
var inStream = inStreams[_owner];
// no prettier null check possible? https://ethereum.stackexchange.com/questions/871/what-is-the-zero-empty-or-null-value-of-a-struct
if(inStream.startTimestamp != 0) {
inStreamBal = (now - inStream.startTimestamp) * inStream.perSecond;
}
uint256 outStreamBal = 0;
var outStream = outStreams[_owner];
if(outStream.startTimestamp != 0) {
outStreamBal = (now - outStream.startTimestamp) * outStream.perSecond;
}
// TODO: check overflow before casting
balance = int256(staticBalances[_owner] + inStreamBal - outStreamBal);
return balance;
}
// the ERC-20 standard requires an uint return value
// TODO: remove duplication. Maybe call honestBalance instead and take min(0, bal)
function balanceOf(address _owner) constant returns (uint256 balance) {
uint256 inStreamBal = 0;
var inStream = inStreams[_owner];
// no prettier null check possible? https://ethereum.stackexchange.com/questions/871/what-is-the-zero-empty-or-null-value-of-a-struct
if(inStream.startTimestamp != 0) {
inStreamBal = (now - inStream.startTimestamp) * inStream.perSecond;
}
uint256 outStreamBal = 0;
var outStream = outStreams[_owner];
if(outStream.startTimestamp != 0) {
outStreamBal = (now - outStream.startTimestamp) * outStream.perSecond;
}
// TODO: check overflow before casting
balance = staticBalances[_owner] + inStreamBal - outStreamBal;
return balance;
}
}
\ No newline at end of file
var Migrations = artifacts.require("./Migrations.sol");
module.exports = function(deployer) {
deployer.deploy(Migrations);
};
var Streem = artifacts.require("./Streem.sol");
module.exports = function(deployer) {
deployer.deploy(Streem, 100000000); // the second param is for the contract constructor
};
pragma solidity ^0.4.2;
import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/Streem.sol";
contract TestStreem {
function testInitialBalanceUsingDeployedContract() {
Streem streem = Streem(DeployedAddresses.Streem());
uint expected = 100000000;
Assert.equal(streem.balanceOf(tx.origin), expected, "Owner should have 10000 STR initially");
}
function testTotalSupplyWithNewContract() {
uint expected = 10000;
Streem streem = new Streem(expected);
Assert.equal(streem.totalSupply(), expected, "totalSupply should be 10000");
}
// TODO: test actual streaming functionality
}
module.exports = {
networks: {
development: {
host: "localhost",
port: 8545,
network_id: "*" // Match any network id
}
}
};
// for contract metadata (format as produced by truffle)
function initContract() {
const abi = contract.abi;
// get address - in case of multiple network entries, the last seems to be a safe bet
for(let networkId in contract.networks) {
console.log(contract.networks[networkId])
var address = contract.networks[networkId].address
}
var Web3 = require('web3');
if (typeof web3 !== 'undefined') {
// Mist / Metamask
console.log('web3 connects to provider')
web3 = new Web3(web3.currentProvider);
} else {
// standalone
//alert("This Dapp needs web3 injected (e.g. through the Metamask plugin.");
console.log('web3 connects to rpc')
web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"))
// TODO: use the async getAccounts() instead
web3.eth.defaultAccount = web3.eth.accounts[0]
}
// contract is the contract template based on our abi
const Streem = web3.eth.contract(abi);
streem = Streem.at(address);
console.log(`contract loaded at ${address} for defaultAccount ${web3.eth.defaultAccount}`)
web3.eth.getBlockNumber((err, ret) => {
console.log("Block: " + ret);
});
// callback on block advance
web3.eth.filter('latest').watch((err, hash) => {
console.log(`new block: ${hash}`)
if (typeof onNextBlock == 'function') {
onNextBlock(hash)
}
})
}
function onOpenStreamButton() {
console.log("start stream clicked")
const rcv = document.getElementById('receiver').value
const speed = document.getElementById('speed').value
console.log(`starting stream to ${rcv} with speed ${speed}`)
streem.openStream(rcv, speed, {gas: 200000}) // TODO: gas is just a guess to make it working on testrpc
}
function onCloseStreamButton() {
console.log("stop stream clicked")
streem.closeStream({gas: 200000}) // TODO: gas is just a guess to make it working on testrpc
}
// shows the balance of <address> by calling the function <updateUi> with the balance as parameter
function showBalance(address, updateUi) {
streem.balanceOf(address, (err, ret) => {
window.balance = ret
const bal = web3.toDecimal(ret)
console.log(`balance is ${bal}`)
//resultElem.innerHTML = bal
updateUi(bal)
})
}
// callback for new block event
function onNextBlock(hash) {
showBalance(web3.eth.defaultAccount, (bal) => { document.getElementById('mybalance-result').innerHTML = bal } )
const receiverAddr = document.getElementById('receiver').value
if(receiverAddr != "") {
showBalance(receiverAddr, (bal) => { document.getElementById('somebalance-result').innerHTML = bal } )
}
}
// trigger block creation every <blocktime> seconds by transferring 1 wei (useful for testrpc).
function keepBlockchainAlive(blocktime) {
window.setTimeout( () => {
web3.eth.sendTransaction( {to: web3.eth.accounts[0], value: 1})
keepBlockchainAlive(blocktime)
}, blocktime * 1000)
}
// UI init
document.addEventListener('DOMContentLoaded', () => {
console.log('DOM loaded')
document.querySelector('#start-stream').onclick = onOpenStreamButton
document.querySelector('#stop-stream').onclick = onCloseStreamButton
})
window.addEventListener('load', () => {
console.log('window loaded')
initContract()
if(web3.eth.defaultAccount == undefined) {
alert("no Ethereum account found")
}
web3.eth.getBalance(web3.eth.defaultAccount, (err, ret) => {
if(! err) {
window.balance = ret
console.log(`Ether balance is ${web3.fromWei(web3.toDecimal(ret))}`)
} else {
alert("Something went wront: can't read Ether balance. Blockchain node connected?")
}
})
if(web3.version.node.toLocaleLowerCase().indexOf("testrpc") != -1) {
keepBlockchainAlive(5)
}
})
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
<!DOCTYPE html>
<html>
<head>
<title>Streem</title>
<meta charset="UTF-8">
</head>
<body>
<header>
<div class="headerInner">
<h1>
<span class="line1">Übersicht </span>
<span class="line2">Unternehmen</span>
</h1>
<div class="selectUser">
<select id="preset-selector">
<option hidden selected>Beispiel-Daten wählen</option>
<option value="producer1">AGCS-2016-06-01</option>
<option value="producer2">AGCS-2016-06-02</option>
</select>
</div>
</div>
</header>
<section class="main">
<div class="sectionInner">
<h2><span>Daten für ein neues Zertifikat übermitteln</span></h2>
<div class="newCertificate">
<form class="formBox" id="form1">
<div class="formItem formItemSend">
<div class="formItemLabel"><label for="send-org">Sende-Unternehmen</label></div>
<div class="formItemField"><input id="send-org" type="text"/></div>
<div class="clear"></div>
</div>
<div class="formItem formItemText formItemCharge">
<div class="formItemLabel"><label for="charge-id">Chargen-ID im Senderegister</label></div>
<div class="formItemField"><input id="charge-id" type="text"/></div>
<div class="clear"></div>
</div>
<div class="formItem formItemAmount">
<div class="formItemLabel"><label for="amount-kwh">Menge in kWh</label></div>
<div class="formItemField"><input id="amount-kwh" type="number" min="1" step="1"></div>
<div class="clear"></div>
</div>
<div class="newCertificateMoreFieldsTrigger">
<span class="show">Weitere Felder anzeigen</span>
<span class="hide">Felder Ausblenden</span>
</div>
<div class="newCertificateMoreFields">
<div class="formItem formItemText">
<div class="formItemLabel"><label for="exchange-id">Austausch-ID</label></div>
<div class="formItemField"><input id="exchange-id" type="text"/></div>
<div class="clear"></div>
</div>
<div class="formItem formItemSend">
<div class="formItemLabel"><label for="send-addr">Sende-Unternehmen Anschrift</label></div>
<div class="formItemField"><input id="send-addr" type="text"/></div>
<div class="clear"></div>
</div>
<div class="formItem formItemText">
<div class="formItemLabel"><label for="send-reg">Senderegister</label></div>
<div class="formItemField"><input id="send-reg" type="text"/></div>
<div class="clear"></div>
</div>
<div class="formItem formItemText">
<div class="formItemLabel"><label for="target-reg">Zielregister</label></div>
<div class="formItemField"><input id="target-reg" type="text"/></div>
<div class="clear"></div>
</div>
<div class="formItem formItemText">
<div class="formItemLabel"><label for="date-application">Datum der
Transfer-Antragstellung</label></div>
<div class="formItemField"><input id="date-application" type="text"/></div>
<div class="clear"></div>
</div>
<div class="formItem formItemText">
<div class="formItemLabel"><label for="recv-org">Empfänger-Unternehmen</label></div>
<div class="formItemField"><input id="recv-org" type="text"/></div>
<div class="clear"></div>
</div>
<div class="formItem formItemText">
<div class="formItemLabel"><label for="recv-addr">Empfänger-Unternehmen Anschrift</label></div>
<div class="formItemField"><input id="recv-addr" type="text"/></div>
<div class="clear"></div>
</div>
<div class="formItem formItemText">
<div class="formItemLabel"><label for="recv-id">Empfänger-ID/Kontonummer</label></div>
<div class="formItemField"><input id="recv-id" type="text"/></div>
<div class="clear"></div>
</div>
<div class="formItem formItemText">
<div class="formItemLabel"><label for="location-handover">Ort der Übergabe</label></div>
<div class="formItemField"><input id="location-handover" type="text"/></div>
<div class="clear"></div>
</div>
<div class="formItem formItemText">
<div class="formItemLabel"><label for="feed-start">Einspeisezeitraum Beginn</label></div>
<div class="formItemField"><input id="feed-start" type="text"/></div>
<div class="clear"></div>
</div>
<div class="formItem formItemText">
<div class="formItemLabel"><label for="feed-end">Einspeisezeitraum Ende</label></div>
<div class="formItemField"><input id="feed-end" type="text"/></div>
<div class="clear"></div>
</div>
<div class="formItem formItemText">
<div class="formItemLabel"><label for="delivery-kind">Art der Lieferung</label></div>
<div class="formItemField"><input id="delivery-kind" type="text"/></div>
<div class="clear"></div>
</div>
<div class="formItem formItemText">
<div class="formItemLabel"><label for="country">Herkunftsland</label></div>
<div class="formItemField"><input id="country" type="text"/></div>
<div class="clear"></div>
</div>
<div class="formItem formItemText">
<div class="formItemLabel"><label for="plant-nr">Anlagennummer</label></div>
<div class="formItemField"><input id="plant-nr" type="text"/></div>
<div class="clear"></div>
</div>
<div class="formItem formItemText">
<div class="formItemLabel"><label for="plant-name">Anlagename</label></div>
<div class="formItemField"><input id="plant-name" type="text"/></div>
<div class="clear"></div>
</div>
<div class="formItem formItemText">
<div class="formItemLabel"><label for="plant-addr">Anlagenadresse</label></div>
<div class="formItemField"><input id="plant-addr" type="text"/></div>
<div class="clear"></div>
</div>
<div class="formItem formItemText">
<div class="formItemLabel"><label for="prod-startdate">Inbetriebnahme-Datum</label></div>
<div class="formItemField"><input id="prod-startdate" type="text"/></div>
<div class="clear"></div>
</div>
<div class="formItem formItemText">
<div class="formItemLabel"><label for="count-point">Zählpunkt der Einspeisung</label></div>
<div class="formItemField"><input id="count-point" type="text"/></div>
<div class="clear"></div>
</div>
<div class="formItem formItemText">
<div class="formItemLabel"><label for="counter-nr">Zählernummer</label></div>
<div class="formItemField"><input id="counter-nr" type="text"/></div>
<div class="clear"></div>
</div>
</div>
<div class="submitContainer">
<input class="btn btn-default" value="Abschicken &raquo;" readonly onclick="onCertRequestClicked()">
</div>
</form>
<p>Kontostand: <span id="token-balance">-</span> MET-Token <a href="https://wallet.ethereum.org/"
target="_blank">Mein Token-Konto</a></p>
</div>
<h2><span>Existierende Zertifikate</span></h2>
<div class="myCertificates">
<div class="myCertificatesHeadline">
<div class="column col1">Unternehmen</div>
<div class="column col2">Chargen-ID</div>
<div class="column col3">Menge in kWh</div>
<div class="column col4">PDF</div>
<div class="column col5">Status</div>
<div class="column col6">Bestätigungen</div>
<div class="clear"></div>
</div>
<div id="cert-list">
</div>
</div>
</div>
</section>
<footer>
<p>Demo v.0.1 / May 2017 / <a href="produce.html">.</a><a href="produce_manual.html">.</a><a
href="certify.html">.</a><a href="certificate-pdf.html" target="_blank">.</a></p>
</footer>
<script type="text/javascript" src="lib/web3.js"></script>
<script type="text/javascript" src="js/contracts.js"></script>
<script type="text/javascript" src="js/config.js"></script>
<script type="text/javascript" src="js/web3-init.js"></script>
<script type="text/javascript" src="js/produce.js"></script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Streem</title>
<meta charset="UTF-8">
</head>
<body>
<h3>Streem PoC Demo</h3>
<p>Works only in an Ethereum aware Browser (e.g. Mist, Browser with Metamask plugin).<br>
The connected Blockchain needs to have the Streem contract deployed and the file js/streem_contract.js needs to have the correct contract ABI and address.<br></p>
Receiver: <input id="receiver" type="text"/><br>
Speed (units per second): <input id="speed" type="number"/><br>
<button id="start-stream">Start Stream</button><br>
<button id="stop-stream">Stop Stream</button><br>
<hr>
My balance: <span id="mybalance-result">-</span><br>
Receiver balance: <span id="somebalance-result">-</span><br>
<p>(Automatically updated with every new block)</p>
<script type="text/javascript" src="lib/web3.js"></script>
<script type="text/javascript" src="js/streem_contract.js"></script>
<script type="text/javascript" src="js/streem.js"></script>
</body>
</html>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment