stromdao-businessobject
Version:
Abstract BusinessObject for StromDAO Energy Blockchain. Abstraction layer between blockchain technology and business logic providing energy market related entities and use cases.
608 lines (547 loc) • 21 kB
JavaScript
/**
* StromDAO Business Object
* =========================================
* [DE] Binding für den StromDAO Node zur Anbindung der Energy Blockchain und Arbeit mit den unterschiedlichen BC Objekten (SmartContracts)
* [EN] Binding for StromDAO Node to the Energy Blockchain.
*
* @author Thorsten Zoerner thorsten.zoerner@stromdao.de
* */
const fs = require("fs");
//const sync = require("sync");
var ethers = require('ethers');
var srequest = require('sync-request');
var NodeRSA = require('node-rsa');
if(typeof window == "undefined") {
var node_persist = require('node-persist');
var storage_locale = {
initSync:function() {
if(typeof process.env.persist != "undefined") {
node_persist.initSync({dir: process.env.persist});
} else {
node_persist.initSync();
}
},
getItemSync:function(key) {
return node_persist.getItemSync(key);
},
setItemSync:function(key,value) {
return node_persist.setItemSync(key,value);
}
};
} else {
var storage_locale = {
initSync:function() {},
getItemSync:function(key) {
return window.localStorage.getItem(key);
},
setItemSync:function(key,value) {
return window.localStorage.setItem(key,value);
}
};
}
var bo_storage = {
initSync:function() {
storage_locale.initSync();
},
getItemSync:function(key) {
return storage_locale.getItemSync(key);
},
setItemSync:function(key,value) {
return storage_locale.setItemSync(key,value);
}
};
module.exports = {
Util:function() {
this.decrypt=function(data,salt) {
var crypto=require("crypto");
var decipher = crypto.createDecipher('aes-256-ctr',salt);
var dec = decipher.update(data,'hex','utf8')
dec += decipher.final('utf8');
return dec;
}
this.encrypt=function(data,salt) {
var crypto=require("crypto");
var cipher = crypto.createCipher( 'aes-256-ctr',salt);
var crypted = cipher.update(data,'utf8','hex');
crypted += cipher.final('hex');
return crypted;
}
this.toMoney=function(uint256) {
return uint256/100000000;
}
this.fromMoney=function(value) {
return value*100000000;
}
},
Account:function(username,password) {
this.username=username;
this.password=password;
this.encrypt=function(data) {
var p2 = new Promise(function(resolve2, reject2) {
new ethers.Wallet.fromBrainWallet(username,password).then(function(account_wallet) {
var crypto=require("crypto");
var cipher = crypto.createCipher( 'aes-256-ctr',account_wallet.privateKey);
var crypted = cipher.update(data,'utf8','hex');
crypted += cipher.final('hex');
resolve2(crypted);
});
});
return p2;
}
this.decrypt=function(data) {
var p2 = new Promise(function(resolve2, reject2) {
new ethers.Wallet.fromBrainWallet(username,password).then(function(account_wallet) {
var crypto=require("crypto");
var decipher = crypto.createDecipher('aes-256-ctr',account_wallet.privateKey);
var dec = decipher.update(data,'hex','utf8')
dec += decipher.final('utf8');
resolve2(dec);
});
});
return p2;
}
this.wallet=function() {
var p2 = new Promise(function(resolve2, reject2) {
new ethers.Wallet.fromBrainWallet(username,password).then(function(account_wallet) {
resolve2(account_wallet);
});
});
return p2;
}
},
Node:function(user_options) {
parent = this;
this._memcach=[];
this._utils=ethers.utils;
this._defaults = require("./Defaults.js").deployment;
this._deployment = require("./Defaults.js").loadDefaults;
this._resolveName = function(address) {
var a=parent.storage.getItemSync("name_"+address);
if((typeof a!="undefined")&&(a!=null)) return ""+a; else return ""+address;
}
/**
* Core Function to create a new key-pair.
*/
this._createNewPK = function() {
var getRandomValues = require('get-random-values');
var array = new Uint8Array(32);
var pk = ethers.utils.keccak256(getRandomValues(array));
return pk;
};
/**
* Core Function to wait for a transaction to be processed
* @param Transaction hash to wait for
*/
this._waitForTransaction = function(tx) {
return parent.rpcprovider.waitForTransaction(tx);
};
this._waitForTransactionKeepRef = function(o,resolve2) {
this._waitForTransaction(o.hash).then(function() {
resolve2(parent._keepHashRef(o));
});
};
/**
* RSA Key Object
*/
this._key = function(str) {
return new NodeRSA(str);
}
/**
* Core Function - Get latest Block Number in Energy Blockchain
*/
this._getBlockNumber=function() {
return parent.rpcprovider.getBlockNumber();
}
this._waitNextBlock = function(cb) {
var block1=0;
var interval = setInterval(function() {
parent.rpcprovider.getBlockNumber().then(function(blockNumber) {
if(block1 === 0) block1=blockNumber;
var block2=blockNumber;
if(block1!=block2) {
clearInterval(interval);
cb();
}
});
},1000);
};
/**
* Keeps a reference of the object in local persitance store
*/
this._keepObjRef=function(address,contract_type) {
if(typeof parent.objRef[contract_type]=="undefined") {
parent.objRef[contract_type] = {};
}
if(typeof parent.objRef[address] == "undefined") {
parent.objRef[address] = {type: contract_type };
parent.objRef[contract_type][address]={ type: contract_type};
storage.setItemSync("objRef",parent.objRef);
}
};
/** Stores Simple Labels for addresses
*/
this._saveLabel=function(address_type,address) {
if(address_type.length<2) {address_type=address_type+" "+address.substring(5,10);}
if(typeof window != "undefined") {
window.localStorage.removeItem("label_"+address.toLowerCase());
}
storage.setItemSync("label_"+address.toLowerCase(),address_type);
}
this._label=function(address) {
address=address.toLowerCase();
var label = storage.getItemSync("label_"+address);
if((typeof label =="undefined")||(label==null)) {
label = "tbd "+address.substring(5,10);
}
return label;
}
/**
* Keeps transaction receipt for in local persistance store (Key=Hash, Value=Receipt)
*/
this._keepHashRef=function(transaction) {
storage.setItemSync(transaction.hash,JSON.stringify(transaction));
return transaction.hash;
};
/**
* Retrieves a value fromm local persistance store (Key=>Value)
*/
this.getRef=function(ref) {
return storage.getItemSync(ref);
};
/**
* Load a contract to be used in BO Instance
*/
this._loadContract=function(address,contract_type,roles_address) {
var abi="";
contract_type=contract_type.replace(":","_");
contract_type=contract_type.replace("/","");
if((typeof this._memcach[contract_type] != "undefined")&&(this._memcach[contract_type].length>10)) {
abi = JSON.parse(this._memcach[contract_type]);
} else {
if(typeof this.options.abilocation !="undefined") {
var raw = srequest('GET',this.options.abilocation+"/"+contract_type+".abi");
abi =JSON.parse(raw.body);
} else
if(typeof window == "undefined") {
if(fs.existsSync("smart_contracts/"+contract_type+".abi")) {
abi = JSON.parse(fs.readFileSync("smart_contracts/"+contract_type+".abi"));
} else
if(fs.existsSync("smart_contracts/"+contract_type+".abi")) {
abi = JSON.parse(fs.readFileSync("node_modules/stromdao-businessobject/smart_contracts/"+contract_type+".abi"));
} else {
var raw = srequest('GET',"https://stromkonto.net/abi/"+contract_type+".abi");
abi =JSON.parse(raw.body);
}
} else {
var raw = srequest('GET',"js/node_modules/stromdao-businessobject/smart_contracts/"+contract_type+".abi");
abi =JSON.parse(raw.body);
}
this._memcach[contract_type]=JSON.stringify(abi);
}
if(address!="0x0") {
contract = new ethers.Contract(address, abi, this.wallet);
parent._keepObjRef(address,contract_type);
} else {
// Deploy new?
}
contract.abi=abi;
return contract;
};
/**
* Promise to retrieve general Owner() Function of SmartContracts
*/
this._owner_promise = function(instance) {
var p2 = new Promise(function(resolve2, reject2) {
instance.obj.owner().then(function(o) {
resolve2(o);
});
});
return p2;
};
/**
* Deploy a new contract to the Energy Blockchain
*/
this._deployContract=function(contract_type,roles_address) {
// if we are in a test situation we will simply use a test deployment.
var abi="";
contract_type=contract_type.replace(":","_");
if(typeof this.options.abilocation !="undefined") {
var raw = srequest('GET',this.options.abilocation+"/"+contract_type+".abi");
abi =JSON.parse(raw.body);
} else
if(typeof window == "undefined") {
if(fs.existsSync("smart_contracts/"+contract_type+".abi")) {
abi = JSON.parse(fs.readFileSync("smart_contracts/"+contract_type+".abi"));
} else
if(fs.existsSync("smart_contracts/"+contract_type+".abi")) {
abi = JSON.parse(fs.readFileSync("node_modules/stromdao-businessobject/smart_contracts/"+contract_type+".abi"));
} else
{
var raw = srequest('GET',"js/node_modules/stromdao-businessobject/smart_contracts/"+contract_type+".abi");
abi =JSON.parse(raw.body);
}
} else {
var raw = srequest('GET',"http://stromkonto.net/abi/"+contract_type+".abi");
abi =JSON.parse(raw.body);
}
var p1 = new Promise(function(resolve, reject) {
if(parent.options.testMode===true) {
resolve(parent.options.contracts[contract_type]);
} else {
var bin = fs.readFileSync("smart_contracts/"+contract_type+".bin");
var deployTransaction = ethers.Contract.getDeployTransaction("0x"+ bin, abi, roles_address);
var sendPromise = parent.wallet.sendTransaction(deployTransaction);
sendPromise.then(function(transaction) {
parent._waitForTransaction(transaction.hash).then(function() {
var address = ethers.utils.getContractAddress(transaction);
resolve(address);
});
});
}
});
return p1;
};
/**
* Get generic instance of a smart contract as object
*/
this._objInstance=function(obj_or_address,type_of_object) {
var instance = {};
instance.obj=obj_or_address;
if(typeof obj != "object") {
instance.obj = parent._loadContract(instance.obj,type_of_object);
}
return instance;
};
/**
* Binding for Log Cache from BC
*/
this._txlog = function(address,blockNumber) {
var p1 = new Promise(function(resolve, reject) {
var stored = parent.storage.getItemSync("log_"+address+"_"+blockNumber);
if((typeof stored == "undefined")||(stored==null)) {
parent.wallet.provider.getLogs({address:address,fromBlock:blockNumber,toBlock:blockNumber}).then(function(logs) {
parent.storage.setItemSync("log_"+address+"_"+blockNumber,JSON.stringify(logs));
resolve(logs);
});
} else {
resolve(JSON.parse(stored));
}
});
return p1;
}
this._txlogfull = function(address) {
var p1 = new Promise(function(resolve, reject) {
parent.wallet.provider.getLogs({address:address,fromBlock:0,toBlock:1000000}).then(function(logs) {
resolve(logs);
});
});
return p1;
}
/**
* Bridge to DSO Smart Contract
*/
this.dso = require("./DSO.js").dso;
/**
* Bridge to MPO Smart Contract
*/
this.mpo = require("./MPO.js").mpo;
/**
* Bridge to MPR Smart Contract
*/
this.mpr = require("./MPR.js").mpr;
/**
* Bridge to MP Clearing (Mieterstrom, Kostenverrechnung..)
*/
this.mpset = require("./MPSet.js").mpset;
this.mpdelta = require("./MPDelta.js").mpdelta;
this.mprset = require("./MPRSet.js").mprset;
this.mpsetfactory = require("./MPSetFactory.js").factory;
this.mprsetfactory = require("./MPRSetFactory.js").factory;
this.mprdecoratefactory = require("./MPRDecorateFactory.js").factory;
this.settlementfactory = require("./SettlementFactory.js").factory;
this.stromkontoproxyfactory = require("./StromkontoProxyFactory.js").factory;
this.assetsliabilitiesfactory = require("./AssetsLiabilitiesFactory.js").factory;
this.clearingfactory = require("./ClearingFactory.js").factory;
this.directclearingfactory = require("./DirectClearingFactory.js").factory;
this.singleclearingfactory = require("./SingleClearingFactory.js").factory;
this.singleclearing = require("./SingleClearing.js").singleclearing;
this.directclearing = require("./DirectClearing.js").directclearing;
this.clearing = require("./Clearing.js").clearing;
this.settlement = require("./Settlement.js").settlement;
this.txcache = require("./TXcache.js").txcache;
this.mprdecorate = require("./MPRDecorate.js").mprdecorate;
this.directclearing=require("./DirectClearing.js").directclearing;
this.xtokenfactory = require("./XTokenFactory.js").factory;
this.mptokenfactory = require("./MPTokenFactory.js").factory;
this.mptoken = require("./MPToken.js").mptoken;
this.xtoken = require("./XToken.js").xtoken;
this.erc20token = require("./ERC20Token.js").erc20token;
this.hystoken = require("./HySToken.js").hystoken;
this.cutokenfactory = require("./CUTokenFactory.js").factory;
this.spvfactory = require("./SPVfactory.js").factory;
this.spv = require("./SPV.js").spv;
this.cutoken = require("./CUToken.js").cutoken;
this.prosumer = require("./Prosumer.js").prosumer;
this.furyuser = require("./Furyuser.js").furyuser;
this.hysm = require("./HySM.js").hysm;
this.apexfund = require("./ApexFund.js").apexfund;
this.apextoken = require("./ApexToken.js").apextoken;
this.apexcommissions = require("./ApexCommissions.js").apexcommissions;
this.infostorage = require("./InfoStorage.js").infostorage;
/**
* Bridge to DirectConnectionFactory Smart Contract
*/
this.directconnectionfactory = require("./DirectConnectionFactory.js").directconnectionfactory;
/**
* Bridge to DirectChargingFactory Smart Contract
*/
this.directchargingfactory = require("./DirectChargingFactory.js").directchargingfactory;
/**
* Bridge to DirectChargingFactory Smart Contract
*/
this.directbalancinggroupfactory = require("./DirectBalancingGroupFactory.js").blgfactory;
/**
* Bridge to DirectCharging Smart Contract
*/
this.directcharging = require("./DirectCharging.js").directcharging;
/**
* Bridge to DirectCharging Smart Contract
*/
this.directconnection = require("./DirectConnection.js").directconnection;
/**
* Bridge to DirectBalancigGroup Smart Contract
*/
this.blg = require("./BLG.js").blg;
/**
* Bridge to Provider Smart Contract
*/
this.provider = require("./Provider.js").provider;
/**
* Bridge to DeliveryMux Smart Contract
*/
this.deliverymux = require("./DeliveryMux.js").provider;
/**
* Bridge to Billing Smart Contract
*/
this.billing = require("./Billing.js").billing;
/**
* Bridge to Delivery Smart Contract
*/
this.delivery = require("./Delivery.js").delivery;
/**
* Bridge to Stromkonto Smart Contract
*/
this.stromkonto = require("./Stromkonto.js").stromkonto;
this.transferable = require("./Transferable.js").transferable;
this.stromkontoproxy = require("./StromkontoProxy.js").stromkontoproxy;
this.assetsliabilities = require("./AssetsLiabilities.js").assetsliabilities;
/**
* Bridge to RoleLookup Smart Contract
*/
this.roleLookup = require("./RoleLookup").rolelookup;
/**
* Bridge to String Storage (Reader)
*/
this.stringstorage = require("./StringStorage").stringstorage;
/**
* Bridge to Meta Data Publish
*/
this.metaset = require("./MetaPublish").metaset;
/**
* Bridge to String Storage (Factory)
*/
this.stringstoragefactory = require("./StringStorageFactory").stringstoragefactory;
this.coldstorage =require("./Coldstorage.js").coldstorage;
if(typeof user_options.storage != "undefined") {
var storage=user_options.storage;
} else {
var storage=bo_storage;
}
storage.initSync();
this.storage=storage;
var options=this._defaults(user_options);
if(typeof web3 != "undefined") {
// set default provider to same host as we are comming from (if available)
var rpcprovider = new ethers.providers.JsonRpcProvider("http://127.0.0.1:8080/rpc","ropsten");
if(typeof window != "undefined") {
if(options.rpc == "undefined") {
var rpcprovider = new ethers.providers.JsonRpcProvider(location.origin+"/rpc","ropsten");
} else {
var rpcprovider = new ethers.providers.JsonRpcProvider(options.rpc,"ropsten");
}
}
} else {
var rpcprovider = new ethers.providers.JsonRpcProvider(options.rpc,"ropsten");
}
if(typeof options.external_id !="undefined") {
if(typeof options.privateKey !="undefined") {
storage.setItemSync("ext:"+options.external_id,options.privateKey);
} else {
options.privateKey=storage.getItemSync("ext:"+options.external_id);
}
if((typeof options.privateKey=="undefined")||(options.privateKey==null)) {
this.options=options;
options.privateKey=this._createNewPK();
storage.setItemSync("ext:"+options.external_id,options.privateKey);
}
} else
if(typeof options.privateKey == "undefined") options.privateKey='0x1471693ac4ae1646256c6a96edf2d808ad2dc6b75df69aa2709c4140e16bc7c4';
this.options=options;
this.nodePrivateKey = storage.getItemSync("node_pk");
if((typeof this.nodePrivateKey == "undefined")||(this.nodePrivateKey==null)) {
this.nodePrivateKey=this._createNewPK();
storage.setItemSync("node_pk",this.nodePrivateKey);
}
// Node RSA Handling
this.nodeRSAPrivateKey = storage.getItemSync("node_rsa_priv");
if((typeof this.nodeRSAPrivateKey == "undefined")||(this.nodeRSAPrivateKey==null)) {
var key = new NodeRSA();
key.generateKeyPair(1024);
storage.setItemSync("node_rsa_priv",key.exportKey('private').toString());
storage.setItemSync("node_rsa_pub",key.exportKey('public').toString());
}
this.nodeRSAPrivateKey=storage.getItemSync("node_rsa_priv");
this.nodeRSAPublicKey=storage.getItemSync("node_rsa_pub");
// EXTId RSA Handling
this.RSAPrivateKey = storage.getItemSync(options.external_id+"_rsa_priv");
if((typeof this.RSAPrivateKey == "undefined")||(this.RSAPrivateKey==null)) {
var key = new NodeRSA();
key.generateKeyPair(1024);
storage.setItemSync(options.external_id+"_rsa_priv",key.exportKey('private').toString());
storage.setItemSync(options.external_id+"_rsa_pub",key.exportKey('public').toString());
}
this.RSAPrivateKey=storage.getItemSync(options.external_id+"_rsa_priv");
this.RSAPublicKey=storage.getItemSync(options.external_id+"_rsa_pub");
this.nodeWallet = new ethers.Wallet(this.nodePrivateKey,rpcprovider);
this.wallet = new ethers.Wallet(options.privateKey,rpcprovider);
if((typeof storage.getItemSync("name_"+options.external_id) == "undefined")||(storage.getItemSync("name_"+options.external_id) == null)) {
storage.setItemSync("name_"+options.external_id,this.wallet.address);
storage.setItemSync("address_"+this.wallet.address,options.external_id);
}
this.options.address = this.wallet.address;
this._saveLabel('EXT '+options.external_id,this.wallet.address);
this.objRef = storage.getItemSync("objRef");
if((typeof this.objRef == "undefined")||(typeof this.options.clearRefCache != "undefined")||(typeof window != "undefined")) {
storage.setItemSync("objRef",{});
this.objRef={};
}
this.rpcprovider=rpcprovider;
this.options=this._deployment(this.options);
if(typeof sync != "undefined") {
sync(function() {
var provider = ethers.providers.getDefaultProvider();
provider.getBlockNumber();
});
}
this.hash = function(data) {
return this._utils.keccak256(this._utils.toUtf8Bytes(data));
}
this.sign = function(data) {
return this.wallet.sign({data:this._utils.keccak256(this._utils.toUtf8Bytes(data))});
}
this.verify = function(signedData) {
var transaction = ethers.Wallet.parseTransaction(signedData);
return transaction.from;
}
}
};