Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save drandreaskrueger/ae3027daa95492465f4c37940de40de7 to your computer and use it in GitHub Desktop.
Save drandreaskrueger/ae3027daa95492465f4c37940de40de7 to your computer and use it in GitHub Desktop.
ordered concatenation of all 20 solidity contracts at https://github.com/energywebfoundation/ew-origin/tree/master/contracts on 2018 September 11th (Latest commit b724754 on Jul 31)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ordered concatenation of all 20 solidity contracts at
// https://github.com/energywebfoundation/ew-origin/tree/master/contracts
// on 2018 September 11th (Latest commit b724754 on Jul 31)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright 2018 Energy Web Foundation
// This file is part of the Origin Application brought to you by the Energy Web Foundation,
// a global non-profit organization focused on accelerating blockchain technology across the energy sector,
// incorporated in Zug, Switzerland.
//
// The Origin Application is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY and without an implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
//
// @authors: slock.it GmbH, Simon Jentzsch, simon.jentzsch@slock.it
contract Owned {
/// @dev `owner` is the only address that can call a function with this
modifier onlyOwner { require (msg.sender == owner); _; }
event LogChangeOwner(address _newOwner);
address public owner;
/// @notice The Constructor assigns the message sender to be `owner`
function Owned(address _initOwner) public { owner = _initOwner;}
/// @notice `owner` can step down and assign some other address to this role
/// @param _newOwner The address of the new owner. 0x0 can be used to create
function changeOwner (address _newOwner) public onlyOwner {
require(_newOwner != address(0));
owner = _newOwner;
LogChangeOwner(_newOwner);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright 2018 Energy Web Foundation
// This file is part of the Origin Application brought to you by the Energy Web Foundation,
// a global non-profit organization focused on accelerating blockchain technology across the energy sector,
// incorporated in Zug, Switzerland.
//
// The Origin Application is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY and without an implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
//
// @authors: slock.it GmbH, Martin Kuechler, martin.kuchler@slock.it
/// @title this contracts provides those functions that both consuming and producing assets share
contract AssetGeneralDefinition is Owned {
struct GeneralInformation {
address smartMeter;
address owner;
uint operationalSince;
uint lastSmartMeterReadWh;
bool active;
bytes32 lastSmartMeterReadFileHash;
uint lastMeterReadReceived;
bool exists;
}
/// @notice function to set all the location Informations for an asset, gets called internally
/// @param _loc the storage location of the location informations
/// @param _country The country where the asset is located
/// @param _region The region / state where the asset is located
/// @param _zip The zip-code of the region where the asset is located
/// @param _city The city where the asset is located
/// @param _street The streetname where the asset is located
/// @param _houseNumber the housenumber where the asset is located
/// @param _gpsLatitude The gps-latitude
/// @param _gpsLongitude The gps-longitude
function initLocationInternal(
LocationDefinition.Location storage _loc,
bytes32 _country,
bytes32 _region,
bytes32 _zip,
bytes32 _city,
bytes32 _street,
bytes32 _houseNumber,
bytes32 _gpsLatitude,
bytes32 _gpsLongitude
)
internal
{
_loc.country = _country;
_loc.region = _region;
_loc.zip = _zip;
_loc.city = _city;
_loc.street = _street;
_loc.houseNumber = _houseNumber;
_loc.gpsLatitude = _gpsLatitude;
_loc.gpsLongitude = _gpsLongitude;
_loc.exists = true;
}
/// @notice internal function to set the general information
/// @param _gi storage location of the general information
/// @param _smartMeter smartMeter-address
/// @param _owner owner-of the asset
/// @param _operationalSince operatinal since that timestamp
/// @param _lastSmartMeterReadWh the last meterreading in Wh
/// @param _active flag if the asset is active
/// @param _lastSmartMeterReadFileHash the last filehash
function setGeneralInformationInternal(
GeneralInformation storage _gi,
address _smartMeter,
address _owner,
uint _operationalSince,
uint _lastSmartMeterReadWh,
bool _active,
bytes32 _lastSmartMeterReadFileHash
)
internal
{
_gi.smartMeter = _smartMeter;
_gi.owner = _owner;
_gi.operationalSince = _operationalSince;
_gi.lastSmartMeterReadWh = _lastSmartMeterReadWh;
_gi.active = _active;
_gi.lastSmartMeterReadFileHash = _lastSmartMeterReadFileHash;
_gi.lastMeterReadReceived = 0;
_gi.exists = true;
}
/// @notice function to get the informations about the location of a struct
/// @param _loc storage location of the locationInformations
/// @return country, region, zip, city, street, houseNumber, gpsLatitude, gpsLongitude
function getAssetLocationInternal(LocationDefinition.Location memory _loc)
internal
pure
returns(
bytes32 country,
bytes32 region,
bytes32 zip,
bytes32 city,
bytes32 street,
bytes32 houseNumber,
bytes32 gpsLatitude,
bytes32 gpsLongitude
)
{
country = _loc.country;
region = _loc.region;
zip = _loc.zip;
city = _loc.city;
street = _loc.street;
houseNumber = _loc.houseNumber;
gpsLatitude = _loc.gpsLatitude;
gpsLongitude = _loc.gpsLongitude;
return (country, region, zip, city, street, houseNumber, gpsLatitude, gpsLongitude);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright 2018 Energy Web Foundation
// This file is part of the Origin Application brought to you by the Energy Web Foundation,
// a global non-profit organization focused on accelerating blockchain technology across the energy sector,
// incorporated in Zug, Switzerland.
//
// The Origin Application is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY and without an implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
//
// @authors: slock.it GmbH, Martin Kuechler, martin.kuchler@slock.it
/// @title this interface defines the functions that both consuming and producing assets are sharing
interface AssetDbInterface {
function getActive(uint _assetId) external view returns(bool);
function getExistStatus(uint _assetId) external view returns (bool general, bool location, bool asset);
function createAsset() external returns (uint);
function initLocation(uint _assetId, bytes32 _country, bytes32 _region, bytes32 _zip, bytes32 _city, bytes32 _street, bytes32 _houseNumber, bytes32 _gpsLatitude, bytes32 _gpsLongitude) external;
function setActive(uint _assetId, bool _active) external;
function setAssetExistStatus(uint _assetId, bool _exist) external;
function setCapacityWh(uint _assetId, uint _capacityWh) external;
function setLastSmartMeterReadDate(uint _assetId, uint _timestamp) external;
function setLastSmartMeterReadFileHash(uint _assetId, bytes32 _lastSmartMeterReadFileHash) external;
function setSmartMeter(uint _assetId, address _smartMeter) external;
function getAssetListLength() external view returns (uint);
function getAssetLocation(uint _assetId) external view returns(bytes32 country, bytes32 region, bytes32 zip, bytes32 city, bytes32 street, bytes32 houseNumber, bytes32 gpsLatitude, bytes32 gpsLongitude);
function getLastSmartMeterRead(uint _assetId) external returns (uint);
function getLastSmartMeterReadDate(uint _assetId) external returns(uint);
function getLastSmartMeterReadFileHash(uint _assetId) external view returns(bytes32);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright 2018 Energy Web Foundation
//
// This file is part of the Origin Application brought to you by the Energy Web Foundation,
// a global non-profit organization focused on accelerating blockchain technology across the energy sector,
// incorporated in Zug, Switzerland.
//
// The Origin Application is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY and without an implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
//
// @authors: slock.it GmbH, Martin Kuechler, martin.kuechler@slock.it
pragma solidity ^0.4.18;
/// @title The Database contract for the Asset Registration
/// @notice This contract only provides getter and setter methods
contract AssetConsumingRegistryDB is Owned, AssetGeneralDefinition, AssetDbInterface {
struct ConsumingProperties {
uint capacityWh;
bool maxCapacitySet;
uint certificatesUsedForWh;
}
struct Asset {
GeneralInformation general;
ConsumingProperties consumingProps;
LocationDefinition.Location location;
bool exists;
}
/// @notice An array containing all registerd assets
Asset[] private assets;
/// @dev empty structs for initializing, used to avoid compile warnings
GeneralInformation generalEmpty;
LocationDefinition.Location locationEmpty;
ConsumingProperties consumingEmpty;
/// @notice Constructor
/// @param _owner The owner of the contract
function AssetConsumingRegistryDB(address _owner)
public
Owned(_owner)
{
}
/// @notice function to create a new empty asset
/// @return returns the array-position and thus the index / identifier of this new asset
function createAsset()
external
onlyOwner
returns (uint _assetId)
{
_assetId = assets.length;
assets.push(AssetConsumingRegistryDB.Asset({
general: generalEmpty,
consumingProps: consumingEmpty,
location: locationEmpty,
exists: false
}));
}
/// @notice Sets the general information for an asset
/// @param _assetId The index / identifier for that asset
/// @param _smartMeter The address of the smart meter
/// @param _owner The address of the asset owner
/// @param _operationalSince The timestamp since the asset is operational
/// @param _capacityWh The capacity in Wh of the asset
/// @param _lastSmartMeterReadWh The smart meter read in Wh
/// @param _certificatesUsedForWh The amount of Wh used to issue certificates
/// @param _active true if active
/// @param _lastSmartMeterReadFileHash The last meter read file hash
function initGeneral (
uint _assetId,
address _smartMeter,
address _owner,
uint _operationalSince,
uint _capacityWh,
bool _maxCapacitySet,
uint _lastSmartMeterReadWh,
uint _certificatesUsedForWh,
bool _active,
bytes32 _lastSmartMeterReadFileHash
)
onlyOwner
external
{
Asset storage a = assets[_assetId];
GeneralInformation storage gi = a.general; // just want to doublecheck, gi is a pointer to the storage, right?
ConsumingProperties storage cp = a.consumingProps;
setGeneralInformationInternal(gi, _smartMeter, _owner, _operationalSince,_lastSmartMeterReadWh, _active, _lastSmartMeterReadFileHash);
cp.certificatesUsedForWh = _certificatesUsedForWh;
cp.capacityWh = _capacityWh;
cp.maxCapacitySet = _maxCapacitySet;
}
/// @notice function to set all the location Informations for an asset
/// @param _assetId The identifier / index of an asset
/// @param _country The country where the asset is located
/// @param _region The region / state where the asset is located
/// @param _zip The zip-code of the region where the asset is located
/// @param _city The city where the asset is located
/// @param _street The streetname where the asset is located
/// @param _houseNumber the housenumber where the asset is located
/// @param _gpsLatitude The gps-latitude
/// @param _gpsLongitude The gps-longitude
function initLocation(
uint _assetId,
bytes32 _country,
bytes32 _region,
bytes32 _zip,
bytes32 _city,
bytes32 _street,
bytes32 _houseNumber,
bytes32 _gpsLatitude,
bytes32 _gpsLongitude
)
onlyOwner
external
{
LocationDefinition.Location storage loc = assets[_assetId].location;
initLocationInternal(loc, _country, _region, _zip, _city, _street, _houseNumber, _gpsLatitude, _gpsLongitude);
}
/// @notice Sets if an entry in the asset registry is active
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _active true if active
function setActive(uint _assetId, bool _active)
onlyOwner
external
{
assets[_assetId].general.active = _active;
}
/// @notice function to set the existing status of an asset
/// @param _assetId The index position / identifier of an asset
/// @param _exist flag if the asset should exist
function setAssetExistStatus(uint _assetId, bool _exist)
external
onlyOwner
{
assets[_assetId].exists = _exist;
}
/// @notice Sets the capacity in Wh of an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _capacityWh The capacity in Wh
function setCapacityWh(uint _assetId, uint _capacityWh)
onlyOwner
external
{
assets[_assetId].consumingProps.capacityWh = _capacityWh;
}
/// @notice Sets amount of Wh used to issue certificates belonging to an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _certificatesUsedForWh The amount of Wh used to issue certificates
function setCertificatesUsedForWh(uint _assetId, uint _certificatesUsedForWh)
onlyOwner
external
{
assets[_assetId].consumingProps.certificatesUsedForWh = _certificatesUsedForWh;
}
/// @notice Sets a timestamp for the last meterreading
/// @param _assetId the id belonging to an entry in the asset registry
/// @param _timestamp new UNIX-timestamp
function setLastSmartMeterReadDate(uint _assetId, uint _timestamp)
onlyOwner
external
{
assets[_assetId].general.lastMeterReadReceived = _timestamp;
}
/// @notice Sets last meter read file hash
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _lastSmartMeterReadFileHash Last meter read file hash
function setLastSmartMeterReadFileHash(uint _assetId, bytes32 _lastSmartMeterReadFileHash)
onlyOwner
external
{
assets[_assetId].general.lastSmartMeterReadFileHash = _lastSmartMeterReadFileHash;
}
/// @notice Sets the last smart meter read in Wh of an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _lastSmartMeterReadWh The smart meter read in Wh
function setLastSmartMeterReadWh(uint _assetId, uint _lastSmartMeterReadWh)
onlyOwner
external
{
assets[_assetId].general.lastSmartMeterReadWh = _lastSmartMeterReadWh;
}
/// @notice Sets the location-country of an asset
/// @param _assetId the id belonging to an entry in the asset registry
/// @param _country the new country
function setLocationCountry(uint _assetId, bytes32 _country)
onlyOwner
external
{
assets[_assetId].location.country = _country;
}
/// @notice Sets the location-region of an asset
/// @param _assetId the id belonging to an entry in the asset registry
/// @param _region the new region
function setLocationRegion(uint _assetId, bytes32 _region)
onlyOwner
external
{
assets[_assetId].location.region = _region;
}
/// @notice Sets the operational since field of an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _operationalSince The timestamp since the asset is operational
function setOperationalSince(uint _assetId, uint _operationalSince)
onlyOwner
external
{
assets[_assetId].general.operationalSince = _operationalSince;
}
/// @notice Sets the owner of an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _owner The new owner
function setOwner(uint _assetId, address _owner)
onlyOwner
external
{
assets[_assetId].general.owner = _owner;
}
/// @notice Sets the smart meter address belonging to an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _smartMeter The new smart meter address
function setSmartMeter(uint _assetId, address _smartMeter)
onlyOwner
external
{
assets[_assetId].general.smartMeter = _smartMeter;
}
/// @notice Sets multiple information of a meterreading
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _newMeterRead the new meterreading
/// @param _lastSmartMeterReadFileHash the filehash belonging to that reading
/// @param _timestamp the timestamp of that reading
function setSmartMeterReadData(uint _assetId, uint _newMeterRead, bytes32 _lastSmartMeterReadFileHash, uint _timestamp)
onlyOwner
external
{
assets[_assetId].general.lastSmartMeterReadWh = _newMeterRead;
assets[_assetId].general.lastSmartMeterReadFileHash = _lastSmartMeterReadFileHash;
assets[_assetId].general.lastMeterReadReceived = _timestamp;
}
/// @notice Gets if an entry in the asset registry is active
/// @param _assetId The id belonging to an entry in the asset registry
/// @return true if asset is active
function getActive(uint _assetId)
onlyOwner
external
view
returns(bool)
{
return assets[_assetId].general.active;
}
/// @notice Gets the general information of an asset
/// @param _assetId The id belonging to an entry in the asset registry
/// @return general information of an asset
function getAssetGeneral(uint _assetId)
onlyOwner
external
view
returns(
address _smartMeter,
address _owner,
uint _operationalSince,
uint _capacityWh,
bool _maxCapacitySet,
uint _lastSmartMeterReadWh,
uint _certificatesUsedForWh,
bool _active,
bytes32 _lastSmartMeterReadFileHash
)
{
Asset storage asset = assets[_assetId];
GeneralInformation memory gi = asset.general;
ConsumingProperties memory cp = asset.consumingProps;
_smartMeter = gi.smartMeter;
_owner = gi.owner;
_operationalSince = gi.operationalSince;
_capacityWh = cp.capacityWh;
_maxCapacitySet = cp.maxCapacitySet;
_lastSmartMeterReadWh = gi.lastSmartMeterReadWh;
_certificatesUsedForWh = cp.certificatesUsedForWh;
_active = gi.active;
_lastSmartMeterReadFileHash = gi.lastSmartMeterReadFileHash;
}
/// @notice function to get the amount of assets
/// @return amount of assets
function getAssetListLength()
onlyOwner
external
view
returns (uint)
{
return assets.length;
}
/// @notice function to get the informations about the location of a struct
/// @param _assetId The id belonging to an entry in the asset registry
/// @return country, region, zip, city, street, houseNumber, gpsLatitude, gpsLongitude
function getAssetLocation(uint _assetId)
onlyOwner
external
view
returns(
bytes32 country,
bytes32 region,
bytes32 zip,
bytes32 city,
bytes32 street,
bytes32 houseNumber,
bytes32 gpsLatitude,
bytes32 gpsLongitude
)
{
LocationDefinition.Location memory loc = assets[_assetId].location;
return getAssetLocationInternal(loc);
}
/// @notice Gets the capacity in Wh of an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @return the capacity in Wh
function getCapacityWh(uint _assetId)
onlyOwner
external
view
returns(uint)
{
return assets[_assetId].consumingProps.capacityWh;
}
/// @notice Gets amount of Wh used to issue certificates belonging to an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @return the amount of Wh used to issue certificates
function getCertificatesUsedForWh(uint _assetId)
onlyOwner
external
view
returns(uint)
{
return assets[_assetId].consumingProps.certificatesUsedForWh;
}
/// @notice gets the consuming properties of an asset
/// @param _assetId the id belonging to an entry in the asset registry
/// @return the consuming properteis
function getConsumingProperies(uint _assetId)
onlyOwner
external
view
returns (
uint _capacityWh,
bool _maxCapacitySet,
uint _certificatesUsedForWh
)
{
ConsumingProperties memory c = assets[_assetId].consumingProps;
_capacityWh = c.capacityWh;
_maxCapacitySet = c.maxCapacitySet;
_certificatesUsedForWh = c.certificatesUsedForWh;
}
/// @notice function the retrieve the existing status of the general information, the location information and the asset itself
/// @param _assetId The index position / identifier of the asset
/// @return existing status of the general informaiton, existing status of the location informaiton and where the asset-structs exists
function getExistStatus(uint _assetId)
onlyOwner
external
view
returns (bool general, bool location, bool asset)
{
Asset memory a = assets[_assetId];
return(a.general.exists, a.location.exists, a.exists);
}
/// @notice function to retrieve the last smartmeter-reading of an asset
/// @param _assetId the asset-id
/// @return the last smartmeter-reading
function getLastSmartMeterRead(uint _assetId)
onlyOwner
external
returns (uint)
{
return assets[_assetId].general.lastSmartMeterReadWh;
}
/// @notice function to retrieve the timestamp of the last smartmeter-reading
/// @param _assetId the asset-id
/// @return the timestamp of the last smartmeter-reading
function getLastSmartMeterReadDate(uint _assetId)
onlyOwner
external
returns(uint)
{
return assets[_assetId].general.lastMeterReadReceived;
}
/// @notice Gets last smart merter read file hash
/// @param _assetId The id belonging to an entry in the asset registry
/// @return last smart merter read file hash
function getLastSmartMeterReadFileHash(uint _assetId)
onlyOwner
external
view
returns(bytes32)
{
return assets[_assetId].general.lastSmartMeterReadFileHash;
}
/// @notice Gets the last smart merter read in Wh of an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @return the last loged smart meter read in Wh
function getLastSmartMeterReadWh(uint _assetId)
onlyOwner
external
view
returns(uint)
{
return assets[_assetId].general.lastSmartMeterReadWh;
}
/// @notice Gets the location country of an asset
/// @param _assetId the id belonging to an entry in the asset registry
/// @return country where the asset is based
function getLocationCountry(uint _assetId)
onlyOwner
external
view
returns(bytes32)
{
return assets[_assetId].location.country;
}
/// @notice Gets the location region of an asset
/// @param _assetId the id belonging to an entry in the asset registry
/// @return region of the country where the asset is based
function getLocationRegion(uint _assetId)
onlyOwner
external
view
returns(bytes32)
{
return assets[_assetId].location.region;
}
/// @notice Gets the operational since field of an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @return date when the asset went into production
function getOperationalSince(uint _assetId)
onlyOwner
external
view
returns(uint)
{
return assets[_assetId].general.operationalSince;
}
/// @notice Gets the owner of an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @return the owner address
function getOwner(uint _assetId)
onlyOwner
external
view
returns(address)
{
return assets[_assetId].general.owner;
}
/// @notice Gets the smart meter address belonging to an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @return the smart meter address
function getSmartMeter(uint _assetId)
onlyOwner
external
view
returns(address)
{
return assets[_assetId].general.smartMeter;
}
}// Copyright 2018 Energy Web Foundation
// This file is part of the Origin Application brought to you by the Energy Web Foundation,
// a global non-profit organization focused on accelerating blockchain technology across the energy sector,
// incorporated in Zug, Switzerland.
//
// The Origin Application is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY and without an implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
//
// @authors: slock.it GmbH, Martin Kuechler, martin.kuechler@slock.it
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright 2018 Energy Web Foundation
// This file is part of the Origin Application brought to you by the Energy Web Foundation,
// a global non-profit organization focused on accelerating blockchain technology across the energy sector,
// incorporated in Zug, Switzerland.
//
// The Origin Application is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY and without an implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
//
// @authors: slock.it GmbH, Martin Kuechler, martin.kuchler@slock.it
/// @notice contract for managing the rights and roles
contract RoleManagement {
/// @notice central registry contract
CoO public cooContract;
/// @notice all possible available roles
/*
no role: 0x0...0000000
TopAdmin: 0x0...------1
UserAdmin: 0x0...-----1-
AssetAdmin: 0x0...----1--
AgreementAdmin: 0x0...---1---
AssetManager: 0x0...--1----
Trader: 0x0...-1-----
Matcher: 0x0...1-----
*/
enum Role{
TopAdmin,
UserAdmin,
AssetAdmin,
AgreementAdmin,
AssetManager,
Trader,
Matcher
}
/// @notice modifier for checking if an user is allowed to execute the intended action
modifier onlyRole (RoleManagement.Role _role) {
require (isRole(_role, msg.sender));
_;
}
modifier onlyAccount(address accountAddress) {
require(msg.sender == accountAddress);
_;
}
modifier userExists(address _user){
require(RolesInterface(cooContract.userRegistry()).doesUserExist(_user));
_;
}
modifier userHasRole(RoleManagement.Role _role, address _user){
require (isRole(_role, _user));
_;
}
/// @notice constructor
/// @param _cooContract CoO.sol-registry contract
function RoleManagement (CoO _cooContract) public {
cooContract = _cooContract;
}
/// @notice funciton for comparing the role and the needed rights of an user
/// @param _role role of a user
/// @param _caller the address calling that function
/// @return whether the user has the corresponding rights for the intended action
function isRole(RoleManagement.Role _role, address _caller) public view returns (bool) {
require(uint(_role) <= 7);
if (cooContract.owner() == _caller) {
return true;
}
/// @dev reading the rights for the user from the userDB-contract
uint rights = RolesInterface(cooContract.userRegistry()).getRolesRights(_caller);
/// @dev converting the used enum to the corresponding bitmask
uint role = uint(2) ** uint(_role);
/// @dev comparing rights and roles, if the result is not 0 the user has the right (bitwise comparison)
/// we also don't have to check for a potential overflow here, because the used enum will prevent using roles that do not exist
return (rights & role != 0);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright 2018 Energy Web Foundation
// This file is part of the Origin Application brought to you by the Energy Web Foundation,
// a global non-profit organization focused on accelerating blockchain technology across the energy sector,
// incorporated in Zug, Switzerland.
//
// The Origin Application is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY and without an implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
//
// @authors: slock.it GmbH, Martin Kuechler, martin.kuchler@slock.it
/// @title this interface defines the required update-function that every updatable-contract has to implement
interface Updatable {
function update(address _newLogic) external;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright 2018 Energy Web Foundation
// This file is part of the Origin Application brought to you by the Energy Web Foundation,
// a global non-profit organization focused on accelerating blockchain technology across the energy sector,
// incorporated in Zug, Switzerland.
//
// The Origin Application is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY and without an implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
//
// @authors: slock.it GmbH, Martin Kuechler, martin.kuchler@slock.it
/// @title Contract for storing the current logic-contracts-addresses for the certificate of origin
contract AssetLogic is RoleManagement, Updatable {
event LogAssetCreated(address sender, uint indexed _assetId);
event LogAssetFullyInitialized(uint indexed _assetId);
event LogAssetSetActive(uint indexed _assetId);
event LogAssetSetInactive(uint indexed _assetId);
AssetDbInterface public db;
modifier isInitialized {
require(address(db) != 0x0);
_;
}
/// @notice Constructor
/// @param _cooContract The address of the coo contract
function AssetLogic(CoO _cooContract)
public
RoleManagement(_cooContract)
{
}
/// @notice function to create a new empty asset, triggers event with created AssetID. To actually create an Asset the functions initGeneral and initLocations have to be called
function createAsset()
external
onlyRole(RoleManagement.Role.AssetAdmin)
isInitialized
{
uint assetId = db.createAsset();
LogAssetCreated(msg.sender, assetId);
}
/// @notice function toinizialize the database, can only be called once
/// @param _dbAddress address of the database contract
function init(address _dbAddress)
public
onlyRole(RoleManagement.Role.TopAdmin)
{
require(address(db) == 0x0);
db = AssetDbInterface(_dbAddress);
}
/// @notice Sets the location information of an asset in the database
/// @param _assetId the The index / identifier of an asset
/// @param _country The country where the asset is located
/// @param _region The region where the asset is located
/// @param _zip The zip coe where the asset is located
/// @param _city The city where the asset is located
/// @param _street The street where the asset is located
/// @param _houseNumber The house number where the asset is located
/// @param _gpsLatitude The gps-latitude of the asset
/// @param _gpsLongitude The gps-longitude of the asset
function initLocation (
uint _assetId,
bytes32 _country,
bytes32 _region,
bytes32 _zip,
bytes32 _city,
bytes32 _street,
bytes32 _houseNumber,
bytes32 _gpsLatitude,
bytes32 _gpsLongitude
)
external
isInitialized
onlyRole(RoleManagement.Role.AssetAdmin)
{
db.initLocation(_assetId, _country, _region, _zip, _city, _street, _houseNumber, _gpsLatitude, _gpsLongitude);
updateAssetExistStatus(_assetId);
}
/// @notice Sets active to false
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _active flag if the asset is asset or not
function setActive(uint _assetId, bool _active)
external
isInitialized
onlyRole(RoleManagement.Role.AssetAdmin)
{
db.setActive(_assetId, _active);
if (_active) {
LogAssetSetActive(_assetId);
} else {
LogAssetSetInactive(_assetId);
}
}
/// @notice Updates the logic contract
/// @param _newLogic Address of the new logic contract
function update(address _newLogic)
external
onlyAccount(address(cooContract))
{
Owned(db).changeOwner(_newLogic);
}
/// @notice gets the active flag on an asset
/// @param _assetId the assetId
/// @return the active flag
function getActive(uint _assetId)
external
view
returns (bool)
{
return db.getActive(_assetId);
}
/// @notice Gets the last filehash of the smart reader
/// @param _assetId the assetId
/// @return the alst smartmeterread-filehash
function getLastSmartMeterReadFileHash(uint _assetId)
external
view
returns (bytes32 datalog)
{
return db.getLastSmartMeterReadFileHash(_assetId);
}
/// @notice Function to get the amount of all assets
/// @dev needed to iterate though all the asset
/// @return the amount of all assets
function getAssetListLength()
external
view
returns (uint)
{
return db.getAssetListLength();
}
/// @notice Funtion to get the informaiton of the location of an asset
/// @param _assetId The identifier / index of the asset
/// @return country, region, zip-code, city, street, houseNumber, gpsLatitude, gpsLongitude
function getAssetLocation(uint _assetId)
external
view
returns(
bytes32 country,
bytes32 region,
bytes32 zip,
bytes32 city,
bytes32 street,
bytes32 houseNumber,
bytes32 gpsLatitude,
bytes32 gpsLongitude
)
{
return db.getAssetLocation(_assetId);
}
/// @notice Changes the address of a smart meter belonging to an asset
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _newSmartMeter The address of the new smart meter
function updateSmartMeter(uint _assetId, address _newSmartMeter)
external
isInitialized
onlyRole(RoleManagement.Role.AssetAdmin)
{
db.setSmartMeter(_assetId, _newSmartMeter);
}
/// @notice Checks if a fully Asset-struct is created, enabled if asset all information are there
/// @dev only for internal use
/// @param _assetId the The index / identifier of an asset
function updateAssetExistStatus(uint _assetId)
internal
{
var (general, location, asset) = db.getExistStatus(_assetId);
if(general && location && !asset) {
db.setAssetExistStatus(_assetId,true);
LogAssetFullyInitialized(_assetId);
db.setLastSmartMeterReadDate(_assetId, now);
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @title The logic contract for the asset registration
/// @notice This contract provides the logic that determines how the data is stored
/// @dev Needs a valid AssetProducingRegistryDB contract to function correctly
contract AssetConsumingRegistryLogic is AssetLogic {
event LogNewMeterRead(
uint indexed _assetId,
bytes32 indexed _fileHash,
uint _oldMeterRead,
uint _newMeterRead,
uint _certificatesUsedForWh,
bool _smartMeterDown
);
/// @notice Constructor
/// @param _cooContract The address of the coo contract
function AssetConsumingRegistryLogic(CoO _cooContract)
public
AssetLogic(_cooContract)
{
}
/// @notice Sets the general information of an asset in the database
/// @param _assetId the The index / identifier of an asset
/// @param _smartMeter The address of the smart meter
/// @param _owner The address of the asset owner
/// @param _operationalSince The timestamp since the asset is operational
/// @param _capacityWh The capacity in Wh of the asset
/// @param _maxCapacitySet flag whether there should be a max capacity
/// @param _active true if active
function initGeneral (
uint _assetId,
address _smartMeter,
address _owner,
uint _operationalSince,
uint _capacityWh,
bool _maxCapacitySet,
bool _active
)
external
isInitialized
userHasRole(RoleManagement.Role.AssetManager, _owner)
onlyRole(RoleManagement.Role.AssetAdmin)
{
AssetConsumingRegistryDB(db).initGeneral(_assetId, _smartMeter, _owner, _operationalSince, _capacityWh, _maxCapacitySet, 0, 0, _active, 0x0);
updateAssetExistStatus(_assetId);
}
/// @notice Logs meter read
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _newMeterRead The current meter read of the asset
/// @param _lastSmartMeterReadFileHash Last meter read file hash
/// @param _smartMeterDown flag whether the smartmeter was down
/// @dev The client needs to check if the blockgas limit could be reached and if so the log should be splitted
function saveSmartMeterRead(uint _assetId, uint _newMeterRead, bytes32 _lastSmartMeterReadFileHash, bool _smartMeterDown)
external
isInitialized
onlyAccount(AssetConsumingRegistryDB((db)).getSmartMeter(_assetId))
{
require(db.getActive(_assetId));
uint oldMeterRead = AssetConsumingRegistryDB((db)).getLastSmartMeterReadWh(_assetId);
LogNewMeterRead(_assetId, _lastSmartMeterReadFileHash, oldMeterRead, _newMeterRead, AssetConsumingRegistryDB((db)).getCertificatesUsedForWh(_assetId), _smartMeterDown);
/// @dev need to check if new meter read is higher then the old one
AssetConsumingRegistryDB((db)).setSmartMeterReadData(_assetId, _newMeterRead, _lastSmartMeterReadFileHash, now);
}
/// @notice Gets an asset
/// @param _assetId The id belonging to an entry in the asset registry
/// @return general information of an asset
function getAssetGeneral(uint _assetId)
external
view
returns (
address _smartMeter,
address _owner,
uint _operationalSince,
uint _capacityWh,
bool _maxCapacitySet,
uint _lastSmartMeterReadWh,
uint _certificatesUsedForWh,
bool _active,
bytes32 _lastSmartMeterReadFileHash
)
{
return AssetConsumingRegistryDB(address(db)).getAssetGeneral(_assetId);
}
/// @notice gets the consuming properties of an asset
/// @param _assetId the assetId
/// @return retuns capacity, maxCapacitySet-falg and certificatesUsedForWh
function getConsumingProperies(uint _assetId)
external
view
returns (
uint capacityWh,
bool maxCapacitySet,
uint certificatesUsedForWh
)
{
(capacityWh, maxCapacitySet, certificatesUsedForWh) = AssetConsumingRegistryDB(address(db)).getConsumingProperies(_assetId);
}
/// @notice sets the consumption for a period (in Wh)
/// @param _assetId assetId
/// @param _consumed the amount of energy consumed
function setConsumptionForPeriode(uint _assetId, uint _consumed)
external
onlyAccount(address(cooContract.demandRegistry()))
{
AssetConsumingRegistryDB(db).setCertificatesUsedForWh(_assetId, _consumed);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright 2018 Energy Web Foundation
//
// This file is part of the Origin Application brought to you by the Energy Web Foundation,
// a global non-profit organization focused on accelerating blockchain technology across the energy sector,
// incorporated in Zug, Switzerland.
//
// The Origin Application is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY and without an implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
//
// @authors: slock.it GmbH, Heiko Burkhardt, heiko.burkhardt@slock.it
/// @title The Database contract for the Asset Registration
/// @notice This contract only provides getter and setter methods
contract AssetProducingRegistryDB is AssetGeneralDefinition, AssetDbInterface {
struct ProducingProperties {
uint assetType;
uint capacityWh;
uint certificatesCreatedForWh;
uint lastSmartMeterCO2OffsetRead;
uint cO2UsedForCertificate;
uint registryCompliance;
bytes32 otherGreenAttributes;
bytes32 typeOfPublicSupport;
}
struct Asset {
AssetGeneralDefinition.GeneralInformation general;
ProducingProperties producingProps;
LocationDefinition.Location location;
bool exists;
}
/// @notice An array containing all registerd assets
Asset[] private assets;
/// @dev empty structs for initializing, used to avoid compile warnings
AssetGeneralDefinition.GeneralInformation generalEmpty;
LocationDefinition.Location locationEmpty;
ProducingProperties producingEmpty;
/// @notice Constructor
/// @param _owner The owner of the contract
function AssetProducingRegistryDB(address _owner)
public
Owned(_owner)
{
}
/// @notice function to create a new empty asset
/// @return returns the array-position and thus the index / identifier of this new asset
function createAsset()
external
onlyOwner
returns (uint _assetId)
{
_assetId = assets.length;
assets.push(AssetProducingRegistryDB.Asset({
general: generalEmpty,
producingProps: producingEmpty,
location: locationEmpty,
exists: false
}));
}
/// @notice function to set the general information for an asset
/// @param _assetId the ID belonging to the asset
/// @param _smartMeter the smart-meter address
/// @param _owner the owner of the asset
/// @param _operationalSince timestamp of when the asset started producing energy
/// @param _lastSmartMeterReadWh the last reading of the smartmeter
/// @param _active active-flag
/// @param _lastSmartMeterReadFileHash the last filehash of the smartmeter-readings
function initGeneral(
uint _assetId,
address _smartMeter,
address _owner,
uint _operationalSince,
uint _lastSmartMeterReadWh,
bool _active,
bytes32 _lastSmartMeterReadFileHash
)
onlyOwner
external
{
Asset storage a = assets[_assetId];
setGeneralInformationInternal(a.general, _smartMeter, _owner, _operationalSince,_lastSmartMeterReadWh, _active, _lastSmartMeterReadFileHash);
}
/// @notice function to set the producing-properties of an asset
/// @param _assetId the ID belonging to the asset
/// @param _assetType the assetType of the asset
/// @param _lastSmartMeterCO2OffsetRead the last CO2-Offsetreading of the smartmeter
/// @param _cO2UsedForCertificate the amount of CO2 used for certificates already
/// @param _capacityWh the capacity of the asset in Wh
/// @param _certificatesCreatedForWh the amount of Wh already certificated
/// @param _registryCompliance the registry-compliance
/// @param _otherGreenAttributes other green attributes
/// @param _typeOfPublicSupport type of public support
function initProducing(
uint _assetId,
uint _assetType,
uint _lastSmartMeterCO2OffsetRead,
uint _cO2UsedForCertificate,
uint _capacityWh,
uint _certificatesCreatedForWh,
uint _registryCompliance,
bytes32 _otherGreenAttributes,
bytes32 _typeOfPublicSupport
)
onlyOwner
external
{
Asset storage a = assets[_assetId];
a.producingProps.assetType = _assetType;
a.producingProps.lastSmartMeterCO2OffsetRead = _lastSmartMeterCO2OffsetRead;
a.producingProps.cO2UsedForCertificate = _cO2UsedForCertificate;
a.producingProps.certificatesCreatedForWh = _certificatesCreatedForWh;
a.producingProps.capacityWh = _capacityWh;
a.producingProps.registryCompliance = _registryCompliance;
a.producingProps.otherGreenAttributes = _otherGreenAttributes;
a.producingProps.typeOfPublicSupport = _typeOfPublicSupport;
}
/// @notice function to set all the location Informations for an asset
/// @param _assetId The identifier / index of an asset
/// @param _country The country where the asset is located
/// @param _region The region / state where the asset is located
/// @param _zip The zip-code of the region where the asset is located
/// @param _city The city where the asset is located
/// @param _street The streetname where the asset is located
/// @param _houseNumber the housenumber where the asset is located
/// @param _gpsLatitude The gps-latitude
/// @param _gpsLongitude The gps-longitude
function initLocation(
uint _assetId,
bytes32 _country,
bytes32 _region,
bytes32 _zip,
bytes32 _city,
bytes32 _street,
bytes32 _houseNumber,
bytes32 _gpsLatitude,
bytes32 _gpsLongitude
)
onlyOwner
external
{
LocationDefinition.Location storage loc = assets[_assetId].location;
initLocationInternal(loc,_country,_region,_zip,_city,_street,_houseNumber,_gpsLatitude,_gpsLongitude);
}
/// @notice Sets if an entry in the asset registry is active
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _active true if active
function setActive(uint _assetId, bool _active)
onlyOwner
external
{
assets[_assetId].general.active = _active;
}
/// @notice function to set the existing status of an asset
/// @param _assetId The index position / identifier of an asset
/// @param _exist flag if the asset should exist
function setAssetExistStatus(uint _assetId, bool _exist)
external
onlyOwner
{
Asset storage a = assets[_assetId];
a.exists = _exist;
}
/// @notice Sets the fuel type belonging to an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _assetType The new fuel type
function setAssetType(uint _assetId, uint _assetType)
onlyOwner
external
{
assets[_assetId].producingProps.assetType = _assetType;
}
/// @notice Sets the capacity in Wh of an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _capacityWh The capacity in Wh
function setCapacityWh(uint _assetId, uint _capacityWh)
onlyOwner
external
{
assets[_assetId].producingProps.capacityWh = _capacityWh;
}
/// @notice Sets amount of Wh used to issue certificates belonging to an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _certificatesCreatedForWh The amount of Wh used to issue certificates
function setCertificatesCreatedForWh(uint _assetId, uint _certificatesCreatedForWh)
onlyOwner
external
{
assets[_assetId].producingProps.certificatesCreatedForWh = _certificatesCreatedForWh;
}
/// @notice Sets amount of saved CO2 used to issue certificates belonging to an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _used The amount of saved CO2 used to issue certificates
function setCO2UsedForCertificate(uint _assetId, uint _used)
onlyOwner
external
{
assets[_assetId].producingProps.cO2UsedForCertificate = _used;
}
/// @notice Sets the last smart meter read in saved CO2 of an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _lastCO2OffsetReading The new amount of saved CO2
function setLastCO2OffsetReading(uint _assetId, uint _lastCO2OffsetReading)
onlyOwner
external
{
assets[_assetId].producingProps.lastSmartMeterCO2OffsetRead = _lastCO2OffsetReading;
}
/// @notice Sets the timestamp of the last smartmeter-reading
/// @param _assetId the id belonging to the asset
/// @param _timestamp the new timestamp of reading
function setLastSmartMeterReadDate(uint _assetId, uint _timestamp)
onlyOwner
external
{
assets[_assetId].general.lastMeterReadReceived = _timestamp;
}
/// @notice Sets last meter read file hash
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _lastSmartMeterReadFileHash Last meter read file hash
function setLastSmartMeterReadFileHash(uint _assetId, bytes32 _lastSmartMeterReadFileHash)
onlyOwner
external
{
assets[_assetId].general.lastSmartMeterReadFileHash = _lastSmartMeterReadFileHash;
}
/// @notice Sets the last smart meter read in Wh of an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _lastSmartMeterReadWh The smart meter read in Wh
function setLastSmartMeterReadWh(uint _assetId, uint _lastSmartMeterReadWh)
onlyOwner
external
{
assets[_assetId].general.lastSmartMeterReadWh = _lastSmartMeterReadWh;
}
/// @notice Sets the location-country of an asset
/// @param _assetId the id belonging to an entry in the asset registry
/// @param _country the new country
function setLocationCountry(uint _assetId, bytes32 _country)
onlyOwner
external
{
assets[_assetId].location.country = _country;
}
/// @notice Sets the location-region of an asset
/// @param _assetId the id belonging to an entry in the asset registry
/// @param _region the new region
function setLocationRegion(uint _assetId, bytes32 _region)
onlyOwner
external
{
assets[_assetId].location.region = _region;
}
/// @notice Sets multiple information of a meterreading
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _newMeterRead the new meterreading of the smart meter
/// @param _CO2OffsetMeterRead the new CO2-offset reading
/// @param _lastSmartMeterReadFileHash the filehash belonging to that reading
/// @param _timestamp the timestamp of that reading
function setSmartMeterReadData(
uint _assetId,
uint _newMeterRead,
uint _CO2OffsetMeterRead,
bytes32 _lastSmartMeterReadFileHash,
uint _timestamp
)
onlyOwner
external
{
assets[_assetId].producingProps.lastSmartMeterCO2OffsetRead = _CO2OffsetMeterRead;
assets[_assetId].general.lastSmartMeterReadWh = _newMeterRead;
assets[_assetId].general.lastSmartMeterReadFileHash = _lastSmartMeterReadFileHash;
assets[_assetId].general.lastMeterReadReceived = _timestamp;
}
/// @notice Sets the operational since field of an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _operationalSince The timestamp since the asset is operational
function setOperationalSince(uint _assetId, uint _operationalSince)
onlyOwner
external
{
assets[_assetId].general.operationalSince = _operationalSince;
}
/// @notice Sets the owner of an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _owner The new owner
function setOwner(uint _assetId, address _owner)
onlyOwner
external
{
assets[_assetId].general.owner = _owner;
}
/// @notice Sets the smart meter address belonging to an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _smartMeter The new smart meter address
function setSmartMeter(uint _assetId, address _smartMeter)
onlyOwner
external
{
assets[_assetId].general.smartMeter = _smartMeter;
}
/// @notice Gets if an entry in the asset registry is active
/// @param _assetId The id belonging to an entry in the asset registry
/// @return true if asset is active
function getActive(uint _assetId)
onlyOwner
external
view
returns(bool)
{
return assets[_assetId].general.active;
}
/// @notice Returns the general information of an asset
/// @param _assetId the id belonging to an entry in the asset registry
/// @return smartmeter-address, owner-address, operationalSince, lastSmartMeterReading in Wh, active flag and the filehash of the last reading
function getAssetGeneral(uint _assetId)
onlyOwner
external
view
returns
(
address _smartMeter,
address _owner,
uint _operationalSince,
uint _lastSmartMeterReadWh,
bool _active,
bytes32 _lastSmartMeterReadFileHash
)
{
Asset memory asset = assets[_assetId];
_smartMeter = asset.general.smartMeter;
_owner = asset.general.owner;
_operationalSince = asset.general.operationalSince;
_lastSmartMeterReadWh = asset.general.lastSmartMeterReadWh;
_active = asset.general.active;
_lastSmartMeterReadFileHash = asset.general.lastSmartMeterReadFileHash;
}
/// @notice function to get the amount of assets
/// @return amount of assets
function getAssetListLength()
onlyOwner
external
view
returns (uint)
{
return assets.length;
}
/// @notice function to get the informations about the location of a struct
/// @param _assetId The id belonging to an entry in the asset registry
/// @return country, region, zip, city, street, houseNumber, gpsLatitude, gpsLongitude
function getAssetLocation(uint _assetId)
onlyOwner
external
view
returns(
bytes32 country,
bytes32 region,
bytes32 zip,
bytes32 city,
bytes32 street,
bytes32 houseNumber,
bytes32 gpsLatitude,
bytes32 gpsLongitude
)
{
LocationDefinition.Location memory loc = assets[_assetId].location;
return getAssetLocationInternal(loc);
}
/// @notice function to get the producing-properties of an asset
/// @param _assetId the id belonging to the asset
/// @return returns the producing-properties of an asset
function getAssetProducingProperties(uint _assetId)
onlyOwner
external
view
returns (
uint assetType,
uint capacityWh,
uint certificatesCreatedForWh,
uint lastSmartMeterCO2OffsetRead,
uint cO2UsedForCertificate,
uint registryCompliance,
bytes32 otherGreenAttributes,
bytes32 typeOfPublicSupport
)
{
Asset memory a = assets[_assetId];
ProducingProperties memory pp = a.producingProps;
assetType = pp.assetType;
capacityWh = pp.capacityWh;
certificatesCreatedForWh = pp.certificatesCreatedForWh;
lastSmartMeterCO2OffsetRead = pp.lastSmartMeterCO2OffsetRead;
cO2UsedForCertificate = pp.cO2UsedForCertificate;
registryCompliance = pp.registryCompliance;
otherGreenAttributes = pp.otherGreenAttributes;
typeOfPublicSupport = pp.typeOfPublicSupport;
}
/// @notice Gets the asset type belonging to an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @return the type of asset
function getAssetType(uint _assetId)
onlyOwner
external
view
returns(uint)
{
return assets[_assetId].producingProps.assetType;
}
/// @notice Gets the capacity in Wh of an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @return the capacity in Wh
function getCapacityWh(uint _assetId)
onlyOwner
external
view
returns(uint)
{
return assets[_assetId].producingProps.capacityWh;
}
/// @notice Gets amount of Wh used to issue certificates belonging to an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @return the amount of Wh used to issue certificates
function getCertificatesCreatedForWh(uint _assetId)
onlyOwner
external
view
returns(uint)
{
return assets[_assetId].producingProps.certificatesCreatedForWh;
}
/// @notice Gets the amount of already used CO2-offset for creating certificates
/// @param _assetId The id belonging to an entry in the asset registry
/// @return the aount of already used CO2-offset
function getCo2UsedForCertificate(uint _assetId)
onlyOwner
external
view
returns (uint)
{
return assets[_assetId].producingProps.cO2UsedForCertificate;
}
/// @notice function the retrieve the existing status of the general information, the location information and the asset itself
/// @param _assetId The index position / identifier of the asset
/// @return existing status of the general informaiton, existing status of the location informaiton and where the asset-structs exists
function getExistStatus(uint _assetId)
onlyOwner
external
view
returns (bool general, bool location, bool asset)
{
Asset memory a = assets[_assetId];
return(a.general.exists && a.producingProps.capacityWh > 0, a.location.exists, a.exists);
}
/// @notice function to get the last smartmeter-reading of an asset
/// @param _assetId the id belonging to the asset
/// @return the last smartmeter-reading
function getLastSmartMeterRead(uint _assetId)
onlyOwner
external
returns (uint)
{
return assets[_assetId].general.lastSmartMeterReadWh;
}
/// @notice Gets the last CO2-offset read of an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @return the last logged CO2-offset read tru
function getlastSmartMeterCO2OffsetRead(uint _assetId)
onlyOwner
external
view
returns (uint)
{
return assets[_assetId].producingProps.lastSmartMeterCO2OffsetRead;
}
/// @notice gets the timestamp of the last reading
/// @param _assetId the Id belonging to an entry in the asset registry
/// @return the timestamp of the last reading
function getLastSmartMeterReadDate(uint _assetId)
onlyOwner
external
returns(uint)
{
return assets[_assetId].general.lastMeterReadReceived;
}
/// @notice Gets last smart merter read file hash
/// @param _assetId The id belonging to an entry in the asset registry
/// @return last smart merter read file hash
function getLastSmartMeterReadFileHash(uint _assetId)
onlyOwner
external
view
returns(bytes32)
{
return assets[_assetId].general.lastSmartMeterReadFileHash;
}
/// @notice Gets the last smart merter read in Wh of an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @return the last loged smart meter read in Wh
function getLastSmartMeterReadWh(uint _assetId)
onlyOwner
external
view
returns(uint)
{
return assets[_assetId].general.lastSmartMeterReadWh;
}
/// @notice Gets the location country of an asset
/// @param _assetId the id belonging to an entry in the asset registry
/// @return country where the asset is based
function getLocationCountry(uint _assetId)
onlyOwner
external
view
returns(bytes32)
{
return assets[_assetId].location.country;
}
/// @notice Gets the location region of an asset
/// @param _assetId the id belonging to an entry in the asset registry
/// @return region of the country where the asset is based
function getLocationRegion(uint _assetId)
onlyOwner
external
view
returns(bytes32)
{
return assets[_assetId].location.region;
}
/// @notice Gets the operational since field of an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
function getOperationalSince(uint _assetId)
external
onlyOwner
view
returns(uint)
{
return assets[_assetId].general.operationalSince;
}
/// @notice Gets the owner of an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @return the owner address
function getOwner(uint _assetId)
external
onlyOwner
view
returns(address)
{
return assets[_assetId].general.owner;
}
/// @notice Gets the smart meter address belonging to an entry in the asset registry
/// @param _assetId The id belonging to an entry in the asset registry
/// @return the smart meter address
function getSmartMeter(uint _assetId)
external
onlyOwner
view
returns(address)
{
return assets[_assetId].general.smartMeter;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright 2018 Energy Web Foundation
// This file is part of the Origin Application brought to you by the Energy Web Foundation,
// a global non-profit organization focused on accelerating blockchain technology across the energy sector,
// incorporated in Zug, Switzerland.
//
// The Origin Application is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY and without an implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
//
// @authors: slock.it GmbH, Jonas Bentke, jonas.bentke@slock.it
/// @title The logic contract for the asset registration
/// @notice This contract provides the logic that determines how the data is stored
/// @dev Needs a valid AssetProducingRegistryDB contract to function correctly
contract AssetProducingRegistryLogic is AssetLogic {
event LogNewMeterRead(uint indexed _assetId, bytes32 indexed _fileHash, uint _oldMeterRead, uint _newMeterRead, bool _smartMeterDown, uint _certificatesCreatedForWh, uint _oldCO2OffsetReading, uint _newCO2OffsetReading, bool _serviceDown);
enum AssetType {
Wind,
Solar,
RunRiverHydro,
BiomassGas
}
enum Compliance{
none,
IREC,
EEC,
TIGR
}
/// @notice Constructor
/// @param _cooContract The address of the coo contract
function AssetProducingRegistryLogic(CoO _cooContract)
public
AssetLogic(_cooContract)
{
}
/// @notice Sets the general information of an asset in the database
/// @param _assetId the The index / identifier of an asset
/// @param _smartMeter The address of the smart meter
/// @param _owner The address of the asset owner
/// @param _operationalSince the timestamp of when the asset was activated for production
/// @param _active true if active
function initGeneral(
uint _assetId,
address _smartMeter,
address _owner,
uint _operationalSince,
bool _active
)
external
isInitialized
userHasRole(RoleManagement.Role.AssetManager, _owner)
onlyRole(RoleManagement.Role.AssetAdmin)
{
AssetProducingRegistryDB((db)).initGeneral(_assetId, _smartMeter, _owner, _operationalSince,0, _active, 0x0);
updateAssetExistStatus(_assetId);
}
/// @notice sets the producing properties of an asset
/// @param _assetId the id belonging to an asset
/// @param _assetType the asset-type
/// @param _capacityWh the capacity of the asset
/// @param _registryCompliance the compliance
/// @param _otherGreenAttributes other green attributes
/// @param _typeOfPublicSupport type of public support
function initProducingProperties(
uint _assetId,
AssetType _assetType,
uint _capacityWh,
Compliance _registryCompliance,
bytes32 _otherGreenAttributes,
bytes32 _typeOfPublicSupport
)
external
isInitialized
onlyRole(RoleManagement.Role.AssetAdmin)
{
AssetProducingRegistryDB((db)).initProducing(_assetId, uint(_assetType), 0, 0, _capacityWh, 0, uint(_registryCompliance), _otherGreenAttributes, _typeOfPublicSupport);
updateAssetExistStatus(_assetId);
}
/// @notice Logs meter read
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _newMeterRead The current meter read of the asset
/// @param _smartMeterDown flag if there was an error with the smart meter
/// @param _lastSmartMeterReadFileHash Last meter read file hash
/// @param _CO2OffsetServiceDown flag if there was an error with the co2-offset-server
/// @param _CO2OffsetMeterRead The new CO2-offset reading
/// @dev The client needs to check if the blockgas limit could be reached and if so the log should be splitted
function saveSmartMeterRead(
uint _assetId,
uint _newMeterRead,
bool _smartMeterDown,
bytes32 _lastSmartMeterReadFileHash,
uint _CO2OffsetMeterRead,
bool _CO2OffsetServiceDown
)
external
isInitialized
onlyAccount(AssetProducingRegistryDB(db).getSmartMeter(_assetId))
{
require(db.getActive(_assetId));
LogNewMeterRead(_assetId, _lastSmartMeterReadFileHash, AssetProducingRegistryDB(db).getLastSmartMeterReadWh(_assetId), _newMeterRead, _smartMeterDown, AssetProducingRegistryDB(db).getCertificatesCreatedForWh(_assetId), AssetProducingRegistryDB(db).getlastSmartMeterCO2OffsetRead(_assetId), _CO2OffsetMeterRead, _CO2OffsetServiceDown);
/// @dev need to check if new meter read is higher then the old one
AssetProducingRegistryDB(address(db)).setSmartMeterReadData(_assetId, _newMeterRead, _CO2OffsetMeterRead, _lastSmartMeterReadFileHash, now);
}
/// @notice function to set the amount of CO2 used for certificates
/// @param _assetId the assetId
/// @param _co2 the amount of CO2 saved
function setCO2UsedForCertificate(uint _assetId, uint _co2)
external
isInitialized
onlyAccount(address(cooContract.certificateRegistry()))
{
uint currentCO = AssetProducingRegistryDB(address(db)).getCo2UsedForCertificate(_assetId);
uint fullCO = AssetProducingRegistryDB(address(db)).getlastSmartMeterCO2OffsetRead(_assetId);
uint temp = currentCO + _co2;
assert(temp >= currentCO);
// we have to check that we can only account that amount of CO2 that was actually saved
require(temp <= fullCO);
AssetProducingRegistryDB(address(db)).setCO2UsedForCertificate(_assetId, temp);
}
/// @notice increases the amount of wh used for the creation of certificates
/// @param _assetId The id belonging to an entry in the asset registry
/// @param _whUsed The amount of wh that is about to be used for a new certificate
function useWhForCertificate(uint _assetId, uint _whUsed)
external
isInitialized
onlyAccount(address(cooContract.certificateRegistry()))
returns(bool)
{
uint temp = AssetProducingRegistryDB(address(db)).getCertificatesCreatedForWh(_assetId) + _whUsed;
require(AssetProducingRegistryDB(address(db)).getLastSmartMeterReadWh(_assetId) >= temp);
AssetProducingRegistryDB(address(db)).setCertificatesCreatedForWh(_assetId, temp);
return true;
}
/// @notice Gets the general information of an asset
/// @param _assetId the id belonging to an entry in the asset registry
/// @return the general information of an asset
function getAssetGeneral(uint _assetId)
external
view
returns(
address _smartMeter,
address _owner,
uint _operationalSince,
uint _lastSmartMeterReadWh,
bool _active,
bytes32 _lastSmartMeterReadFileHash
)
{
return AssetProducingRegistryDB(address(db)).getAssetGeneral(_assetId);
}
/// @notice get the producing properties of an asset
/// @param _assetId the id belonging to an entry in the asset registry
/// @return the producing properties
function getAssetProducingProperties(uint _assetId)
external
view
returns(
uint assetType,
uint capacityWh,
uint certificatesCreatedForWh,
uint lastSmartMeterCO2OffsetRead,
uint cO2UsedForCertificate,
uint registryCompliance,
bytes32 otherGreenAttributes,
bytes32 typeOfPublicSupport
)
{
return AssetProducingRegistryDB(address(db)).getAssetProducingProperties(_assetId);
}
/// @notice Function to get the Asset-Type
/// @dev The asset-type gets converted from unsigned integer to an Asset-type enum, can still be accessed as uint
/// @param _assetId The identifier / index of an asset
/// @return AssetType as enum
function getAssetType(uint _assetId)
external
view
returns(
AssetType
)
{
return AssetType(AssetProducingRegistryDB(address(db)).getAssetType(_assetId));
}
/// @notice function to get the compliance
/// @param _assetId the assetId
/// @return the compliance
function getCompliance(uint _assetId)
external
view
returns (Compliance c)
{
var ( , , , , , ctemp, , ) = AssetProducingRegistryDB(address(db)).getAssetProducingProperties(_assetId);
c = Compliance(ctemp);
}
/// @notice Function to get the amount of already used CO2 for creating certificates
/// @param _assetId The identifier / index of an asset
/// @return the amount of already used CO2 for creating certificates
function getCo2UsedForCertificate(uint _assetId)
external
view
returns (uint)
{
return AssetProducingRegistryDB(address(db)).getCo2UsedForCertificate(_assetId);
}
/// @notice function to calculated how much CO2-offset can be used for a certificate
/// @param _assetId The identifier / index of an asset
/// @param _wh The amount of wh produced
/// @return amount of CO2-offset used for a certificate
function getCoSaved(uint _assetId, uint _wh) external view returns(uint) {
uint lastRead = AssetProducingRegistryDB(address(db)).getLastSmartMeterReadWh(_assetId);
uint lastUsedWh = AssetProducingRegistryDB(address(db)).getCertificatesCreatedForWh(_assetId);
uint availableWh = lastRead - lastUsedWh;
// we have to check for an underflow and if there are even availale Wh
assert(lastUsedWh <= lastRead);
if (availableWh == 0) return 0;
uint coRead = AssetProducingRegistryDB(address(db)).getlastSmartMeterCO2OffsetRead(_assetId);
uint coUsed = AssetProducingRegistryDB(address(db)).getCo2UsedForCertificate(_assetId);
uint availableCo = coRead - coUsed;
assert(coUsed <= coRead);
return (availableCo*((_wh*1000000)/availableWh))/1000000;
}
/// @notice returns whether an asset exists
/// @param _assetId The identifier of an asset
/// @return bool if asset exists, false if some information are missing
function getExistStatus(uint _assetId) external view returns (bool) {
var (general, location, asset) = db.getExistStatus(_assetId);
return (general && location && asset);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright 2018 Energy Web Foundation
// This file is part of the Origin Application brought to you by the Energy Web Foundation,
// a global non-profit organization focused on accelerating blockchain technology across the energy sector,
// incorporated in Zug, Switzerland.
//
// The Origin Application is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY and without an implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
//
// @authors: slock.it GmbH, Jonas Bentke, jonas.bentke@slock.it
/// @title The Database contract for the Certificate of Origin list
/// @notice This contract only provides getter and setter methods
contract CertificateDB is Owned {
struct Certificate {
uint assetId;
address owner;
uint powerInW;
bool retired;
bytes32 dataLog;
uint coSaved;
address escrow;
uint creationTime;
}
/// @notice An array containing all created certificates
Certificate[] private certificateList; // why is it private read? People can still read it, just not use from within a smart contract (even there it is possible)
/// @notice Constructor
/// @param _certificateLogic The address of the corresbonding logic contract
function CertificateDB(address _certificateLogic) Owned(_certificateLogic) public {
}
/// @notice Creates a new certificate
/// @param _assetId The id of the Certificate
/// @param _owner The owner of the Certificate
/// @param _powerInW The amount of Watts the Certificate holds
/// @return The id of the certificate
function createCertificate(uint _assetId, address _owner, uint _powerInW, bytes32 _dataLog, uint _coSaved, address _escrow) public onlyOwner returns (uint _certId) {
_certId = certificateList.length;
certificateList.push(Certificate(_assetId, _owner, _powerInW, false, _dataLog, _coSaved, _escrow, now));
}
/// @notice sets the escrow-address of a certificate
/// @param _certificateId certificateId
/// @param _escrow new escrow-address
function setCertificateEscrow(uint _certificateId, address _escrow)
public
onlyOwner
{
certificateList[_certificateId].escrow = _escrow;
}
/// @notice Sets the owner of a certificate
/// @param _certificateId The array position in which the certificate is stored
/// @param _owner The address of the new owner
function setCertificateOwner(uint _certificateId, address _owner) public onlyOwner {
certificateList[_certificateId].owner = _owner;
}
/// @notice Sets a certificate to retired
/// @param _certificateId The array position in which the certificate is stored
function retireCertificate(uint _certificateId) public onlyOwner {
certificateList[_certificateId].retired = true;
}
/// @notice Returns the certificate that corresponds to the given array id
/// @param _certificateId The array position in which the certificate is stored
/// @return all elements of the certificate
function getCertificate(uint _certificateId)
public
view
returns (
uint _assetId,
address _owner,
uint _powerInW,
bool _retired,
bytes32 _dataLog,
uint _coSaved,
address _escrow,
uint _creationTime
)
{
Certificate memory c = certificateList[_certificateId];
_assetId = c.assetId;
_owner = c.owner;
_powerInW = c.powerInW;
_retired = c.retired;
_dataLog = c.dataLog;
_coSaved = c.coSaved;
_escrow = c.escrow;
_creationTime = c.creationTime;
}
/// @notice Returns the certificate owner
/// @param _certificateId The array position in which the certificate is stored
/// @return address owner
function getCertificateOwner(uint _certificateId)
public
onlyOwner
view
returns (address)
{
return certificateList[_certificateId].owner;
}
/// @notice Getter for state of retirement
/// @param _certificateId The id of the requested certificate
/// @return bool if it is retired
function isRetired(uint _certificateId)
public
onlyOwner
view
returns (bool)
{
return certificateList[_certificateId].retired;
}
/// @notice function to get the amount of all certificates
/// @return the amount of all certificates
function getCertificateListLength()
public
onlyOwner
view
returns (uint)
{
return certificateList.length;
}
/// @notice function to get the escrow-address of a certificate
/// @param _certificateId certificate-ID
/// @return escrow-address
function getCertificateEscrow(uint _certificateId)
public
onlyOwner
view
returns (address)
{
return certificateList[_certificateId].escrow;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright 2018 Energy Web Foundation
// This file is part of the Origin Application brought to you by the Energy Web Foundation,
// a global non-profit organization focused on accelerating blockchain technology across the energy sector,
// incorporated in Zug, Switzerland.
//
// The Origin Application is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY and without an implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
//
// @authors: slock.it GmbH, Jonas Bentke, jonas.bentke@slock.it
/// @title The logic contract for the Certificate of Origin list
/// @notice This contract provides the logic that determines how the data is stored
/// @dev Needs a valid CertificateDB contract to function correctly
contract CertificateLogic is RoleManagement, Updatable {
///@notice The address of a CertificateDB contract
CertificateDB public certificateDb;
/// @notice Logs the creation of an event
event LogCreatedCertificate(uint indexed _certificateId, uint powerInW, address owner, address escrow);
/// @notice Logs the request of an retirement of a certificate
event LogRetireRequest(uint indexed _certificateId, bool _retire);
event LogCertificateOwnerChanged(uint indexed _certificateId, address _oldOwner, address _newOwner, address _oldEscrow, address _newEscrow);
/// @notice Checks if the contract is initialized
modifier isInitialized() {
require(certificateDb != CertificateDB(0x0));
_;
}
/// @notice Constructor
/// @param _coo The Master contract
function CertificateLogic(CoO _coo) RoleManagement(_coo) public {
}
/// @notice Initialises the contract by binding it to a logic contract
/// @param _database Sets the logic contract
function init(address _database) public onlyRole(RoleManagement.Role.TopAdmin) {
require(certificateDb == CertificateDB(0x0));
certificateDb = CertificateDB(_database);
}
/// @notice Creates a certificate of origin. Checks in the AssetRegistry if requested wh are available.
/// @param _assetId The id of the Certificate
/// @param _owner The owner of the Certificate
/// @param _powerInW The amount of Watts the Certificate holds
function createCertificate(uint _assetId, address _owner, uint _powerInW)
public
isInitialized
onlyAccount(address(cooContract.demandRegistry()) )
returns (uint)
{
return createCertificateIntern(_assetId, _owner, _powerInW, 0x0);
}
/// @notice Creates a certificate of origin. Checks in the AssetRegistry if requested wh are available.
/// @param _assetId The id of the Certificate
/// @param _owner The owner of the Certificate
/// @param _powerInW The amount of Watts the Certificate holds
/// @param _escrow The escrow of a certificate
/// @return a certificate-id
function createCertificateIntern(uint _assetId, address _owner, uint _powerInW, address _escrow)
internal
isInitialized
returns (uint)
{
uint co = AssetProducingRegistryLogic(address(cooContract.assetProducingRegistry())).getCoSaved(_assetId, _powerInW);
require(AssetProducingRegistryLogic(address(cooContract.assetProducingRegistry())).useWhForCertificate(_assetId, _powerInW));
bytes32 dataLog = AssetProducingRegistryLogic(address(cooContract.assetProducingRegistry())).getLastSmartMeterReadFileHash(_assetId);
uint certId = certificateDb.createCertificate(_assetId, _owner, _powerInW, dataLog, co, _escrow);
LogCreatedCertificate(certId, _powerInW, _owner, _escrow);
AssetProducingRegistryLogic(address(cooContract.assetProducingRegistry())).setCO2UsedForCertificate(_assetId,co);
return certId;
}
/// @notice Creates a certificate of origin for the asset owner. Checks in the AssetRegistry if requested wh are available.
/// @dev the msg.sender (a matcher) will become the escrow-of that certificate and is allowed to change the change the ownership
/// @param _assetId The id of the Certificate
/// @param _powerInW The amount of Watts the Certificate holds
/// @return the certificate-id
function createCertificateForAssetOwner(uint _assetId, uint _powerInW)
public
onlyRole(RoleManagement.Role.Matcher)
isInitialized
returns (uint)
{
require( AssetProducingRegistryLogic(address(cooContract.assetProducingRegistry())).getExistStatus(_assetId));
var ( , ownerAddress, , , , ) = AssetProducingRegistryLogic(address(cooContract.assetProducingRegistry())).getAssetGeneral(_assetId);
return createCertificateIntern(_assetId, ownerAddress, _powerInW, msg.sender);
}
/// @notice Request a certificate to retire. Only Certificate owner can retire
/// @param _id The id of the certificate
function retireCertificate(uint _id)
public
isInitialized
{
var (, owner, , retired,, ,,) = certificateDb.getCertificate(_id);
require(owner == msg.sender);
if (!retired) {
certificateDb.setCertificateEscrow(_id, 0x0);
certificateDb.retireCertificate(_id);
LogRetireRequest(_id, true);
}
}
/// @notice function to allow an escrow-address to change the ownership of a certificate
/// @dev this function can only be called by the demandLogic
/// @param _id the certificate-id
/// @param _newOwner the new owner of the certificate
function transferOwnershipByEscrow(uint _id, address _newOwner)
public
isInitialized
onlyAccount(address(cooContract.demandRegistry()) )
{
address oldOwner;
bool retired;
address oldEscrow;
( ,oldOwner,,retired,,,oldEscrow,) = certificateDb.getCertificate(_id);
require(!retired);
certificateDb.setCertificateOwner(_id, _newOwner);
certificateDb.setCertificateEscrow(_id, 0x0);
LogCertificateOwnerChanged(_id, oldOwner, _newOwner, oldEscrow, 0x0);
}
/// @notice Sets a new owner for the certificate
/// @param _id The id of the certificate
/// @param _newOwner The address of the new owner of the certificate
function changeCertificateOwner(uint _id, address _newOwner)
public
isInitialized()
userExists(_newOwner)
{
require(msg.sender == certificateDb.getCertificateOwner(_id) && !(certificateDb.isRetired(_id)));
certificateDb.setCertificateOwner(_id, _newOwner);
address oldOwner = certificateDb.getCertificateOwner(_id);
address oldEscrow = certificateDb.getCertificateEscrow(_id);
LogCertificateOwnerChanged(_id, oldOwner, _newOwner, oldEscrow, oldEscrow);
}
/// @notice Getter for a specific Certificate
/// @param _certificateId The id of the requested certificate
/// @return the certificate as single values
function getCertificate(uint _certificateId)
public
view
returns (
uint _assetId,
address _owner,
uint _powerInW,
bool _retired,
bytes32 _dataLog,
uint _coSaved,
address _escrow,
uint _creationTime
)
{
return certificateDb.getCertificate(_certificateId);
}
/// @notice Getter for a specific Certificate
/// @param _certificateId The id of the requested certificate
/// @return the certificate as single values
function getCertificateOwner(uint _certificateId)
public
view
returns (address)
{
return certificateDb.getCertificateOwner(_certificateId);
}
/// @notice Getter for a specific Certificate
/// @param _certificateId The id of the requested certificate
/// @return the certificate as single values
function isRetired(uint _certificateId)
public
view
returns (bool)
{
return certificateDb.isRetired(_certificateId);
}
/// @notice Getter for the length of the list of certificates
/// @return the length of the array
function getCertificateListLength()
public
view
returns (uint)
{
return certificateDb.getCertificateListLength();
}
/// @notice Updates the logic contract
/// @param _newLogic Address of the new logic contract
function update(address _newLogic)
external
onlyAccount(address(cooContract))
{
require(address(cooContract) == msg.sender);
certificateDb.changeOwner(_newLogic);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright 2018 Energy Web Foundation
// This file is part of the Origin Application brought to you by the Energy Web Foundation,
// a global non-profit organization focused on accelerating blockchain technology across the energy sector,
// incorporated in Zug, Switzerland.
//
// The Origin Application is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY and without an implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
//
// @authors: slock.it GmbH, Martin Kuechler, martin.kuchler@slock.it
/// @title Contract for storing the current logic-contracts-addresses for the certificate of origin
contract CoO is Owned {
event LogUserRegistryUpdated(address _old, address _new);
event LogAssetProducingRegistryUpdated(address _old, address _new);
event LogCertificateRegistryUpdated(address _old, address _new);
event LogDemandRegistryUpdated(address _old, address _new);
event LogAssetConsumingRegistryUpdated(address _old, address _new);
Updatable public userRegistry;
Updatable public assetProducingRegistry;
Updatable public certificateRegistry;
Updatable public demandRegistry;
Updatable public assetConsumingRegistry;
/// @notice The constructor of the UserDB
function CoO()
Owned(msg.sender)
public
{
}
/// @notice function to initialize the contracts, setting the needed contract-addresses
/// @param _userRegistry user-registry logic contract address
/// @param _assetProducingRegistry producing-asset-registry logic contract address
/// @param _certificateRegistry certificate-registry logic contract address
/// @param _demandRegistry demand-registry logic contract address
/// @param _assetConsumingRegistry consuming-asset-registry logic contract address
function init(
Updatable _userRegistry,
Updatable _assetProducingRegistry,
Updatable _certificateRegistry,
Updatable _demandRegistry,
Updatable _assetConsumingRegistry
)
onlyOwner
external
{
require(
_userRegistry != address(0) && _assetProducingRegistry != address(0) && _certificateRegistry != address(0) && _demandRegistry != address(0) && _assetConsumingRegistry != address(0)
&& userRegistry == address(0) && assetProducingRegistry == address(0) && certificateRegistry == address(0) && demandRegistry == address(0) && assetConsumingRegistry == address(0)
);
userRegistry = _userRegistry;
assetProducingRegistry = _assetProducingRegistry;
certificateRegistry = _certificateRegistry;
demandRegistry = _demandRegistry;
assetConsumingRegistry = _assetConsumingRegistry;
}
/// @notice function to update one or more logic-contracts
/// @param _userRegistry address of the new user-registry-logic-contract
/// @param _assetProducingRegistry address of the new asset-registry-logic-contract
/// @param _certificateRegistry address of the new certificate-registry-logic-contract
/// @param _demandRegistry demand-registry logic contract address
/// @param _assetConsumingRegistry consuming-asset-registry logic contract address
function update(
Updatable _userRegistry,
Updatable _assetProducingRegistry,
Updatable _certificateRegistry,
Updatable _demandRegistry,
Updatable _assetConsumingRegistry
)
onlyOwner
external
{
if (_userRegistry != address(0)) {
LogUserRegistryUpdated(userRegistry, _userRegistry);
userRegistry.update(_userRegistry);
userRegistry = _userRegistry;
}
if (_assetProducingRegistry != address(0)) {
LogAssetProducingRegistryUpdated(assetProducingRegistry, _assetProducingRegistry);
assetProducingRegistry.update(_assetProducingRegistry);
assetProducingRegistry = _assetProducingRegistry;
}
if (_certificateRegistry != address(0)) {
LogCertificateRegistryUpdated(certificateRegistry, _certificateRegistry);
certificateRegistry.update(_certificateRegistry);
certificateRegistry = _certificateRegistry;
}
if (_demandRegistry != address(0)) {
LogDemandRegistryUpdated(demandRegistry, _demandRegistry);
demandRegistry.update(_demandRegistry);
demandRegistry = _demandRegistry;
}
if(_assetConsumingRegistry != address(0)) {
LogAssetConsumingRegistryUpdated(assetConsumingRegistry, _assetConsumingRegistry);
assetConsumingRegistry.update(_assetConsumingRegistry);
assetConsumingRegistry = _assetConsumingRegistry;
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright 2018 Energy Web Foundation
// This file is part of the Origin Application brought to you by the Energy Web Foundation,
// a global non-profit organization focused on accelerating blockchain technology across the energy sector,
// incorporated in Zug, Switzerland.
//
// The Origin Application is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY and without an implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
//
// @authors: slock.it GmbH, Martin Kuechler, martin.kuchler@slock.it
/// @title The Database contract for the AgreementDB of Origin list
/// @notice This contract only provides getter and setter methods and only its logic-contract is able to call the functions
contract DemandDB is Owned {
/// @notice struct for all the data belonging to the matcher
struct MatcherProperties {
// how many Wh per Period
uint targetWhPerperiod;
// amount of Wh the demand has already received
uint currentWhPerperiod;
uint certInCurrentperiod;
uint productionLastSetInPeriod;
// simple address of privateKey-keypair
address matcher;
}
/// @notice struct for all the information belonging to the coupling, can be 0
struct Coupling {
uint producingAssets;
uint consumingAssets;
}
/// @notice struct for all the information that can affect a price
struct PriceDriving {
LocationDefinition.Location location;
uint registryCompliance;
uint assettype;
// proportion between CO2 and wh in percent (100 * CO2 / Wh)
uint minCO2Offset;
bytes32 otherGreenAttributes;
bytes32 typeOfPublicSupport;
bool isInitialized;
}
/// @notice struct for all the general information about a demand
struct GeneralInfo {
address originator;
address buyer;
uint startTime;
uint endTime;
uint timeframe;
uint pricePerCertifiedKWh;
uint currency;
}
/// @notice struct for gather all information
struct Demand {
GeneralInfo general;
Coupling couple;
PriceDriving priceDriving;
MatcherProperties matchProp;
bool enabled;
uint created;
uint demandMask;
}
GeneralInfo generalEmpty;
Coupling coupleEmpty;
PriceDriving priceDrivingEmpty;
MatcherProperties matchPropEmpty;
/// @notice list with all currenty active Demands
uint[] private activeDemands;
/// @notice empty location struct for initializing, used to avoid compile warnings
LocationDefinition.Location private locationEmpty;
/// @notice list with all created demands
Demand[] private allDemands;
/// @notice Constructor
/// @param _owner The owner of the contract
function DemandDB(address _owner)
public
Owned(_owner)
{
}
/// @notice function to add a demand to the activeDemands-array
/// @param _demandId hash-identifier of a demand
function addActiveDemand(uint _demandId)
external
onlyOwner
{
activeDemands.push(_demandId);
}
/// @notice function to create a coupling
/// @param _demandId identifier
/// @param _prodAssets array with assets that are allowed to produce energy for this agreement
/// @param _consAssets array with assets that are allowed to consume energy for this agreement
function createCoupling(
uint _demandId,
uint _prodAssets,
uint _consAssets
)
external
onlyOwner
{
Demand storage d = allDemands[_demandId];
Coupling storage c = d.couple;
c.producingAssets = _prodAssets;
c.consumingAssets = _consAssets;
}
/// @notice function to create an empty demand
/// @param _mask bitmask with the demand properties
/// @return the index and thus the identifier of a demand
function createEmptyDemand(uint _mask)
external
onlyOwner
returns (uint _demandId)
{
_demandId = allDemands.length;
allDemands.push(Demand({
general: generalEmpty,
couple: coupleEmpty,
priceDriving: priceDrivingEmpty,
matchProp: matchPropEmpty,
enabled: false,
created : 0,
demandMask: _mask
}));
}
/// @notice function to create the general informations of a demand
/// @param _demandId identifier
/// @param _originator producer of energy
/// @param _buyer buyer of a certiface, can be 0x0
/// @param _startTime eariest accepted certificates
/// @param _endTime latest accepted certificates
/// @param _timeframe the timeframe for the demand
/// @param _pricePerCertifiedKWh price per certified kWh
/// @param _currency currency the originator wants to be paid with
function createGeneralDemand(
uint _demandId,
address _originator,
address _buyer,
uint _startTime,
uint _endTime,
uint _timeframe,
uint _pricePerCertifiedKWh,
uint _currency
)
external
onlyOwner
{
Demand storage d = allDemands[_demandId];
GeneralInfo storage g = d.general;
g.originator = _originator;
g.buyer = _buyer;
g.startTime = _startTime;
g.endTime = _endTime;
g.timeframe = _timeframe;
g.pricePerCertifiedKWh = _pricePerCertifiedKWh;
g.currency = _currency;
}
/// @notice function to create the matching-properties
/// @param _demandId identifier
/// @param _WhAmountPerperiod the desired amount of Wh per period
/// @param _currentWhPerperiod the current amount of Wh
/// @param _certInCurrentperiod the amount of certificates created in the current period
/// @param _productionLastSetInPeriod the last period where the consumption was set
/// @param _matcher account of the javaScript-matcher
function createMatchProperties(
uint _demandId,
uint _WhAmountPerperiod,
uint _currentWhPerperiod,
uint _certInCurrentperiod,
uint _productionLastSetInPeriod,
address _matcher
)
external
onlyOwner
{
Demand storage d = allDemands[_demandId];
MatcherProperties storage m = d.matchProp;
m.targetWhPerperiod = _WhAmountPerperiod;
m.currentWhPerperiod = _currentWhPerperiod;
m.certInCurrentperiod = _certInCurrentperiod;
m.productionLastSetInPeriod = _productionLastSetInPeriod;
m.matcher = _matcher;
}
/// @notice function to create the pricedriving-factors of a demand
/// @param _demandId identifier
/// @param _country country the engery has to come from
/// @param _region region the energy has to come from
/// @param _zip zip code the energy has to come from
/// @param _street the streetname
/// @param _houseNumber the housenumber
/// @param _gpsLatitude latitude of coordinates
/// @param _gpsLongitude longitude of coordinates
/// @param _type fuel-tyoe
/// @param _minCO2Offset CO2-offset
/// @param _registryCompliance compliance
/// @param _otherGreenAttributes other green attributes
/// @param _typeOfPublicSupport type of public support
function createPriceDriving(
uint _demandId,
bytes32 _country,
bytes32 _region,
bytes32 _zip,
bytes32 _city,
bytes32 _street,
bytes32 _houseNumber,
bytes32 _gpsLatitude,
bytes32 _gpsLongitude,
uint _type,
uint _minCO2Offset,
uint _registryCompliance,
bytes32 _otherGreenAttributes,
bytes32 _typeOfPublicSupport
)
external
onlyOwner
{
allDemands[_demandId].priceDriving.location = locationEmpty;
allDemands[_demandId].priceDriving.assettype = _type;
allDemands[_demandId].priceDriving.minCO2Offset = _minCO2Offset;
allDemands[_demandId].priceDriving.registryCompliance = _registryCompliance;
allDemands[_demandId].priceDriving.otherGreenAttributes = _otherGreenAttributes;
allDemands[_demandId].priceDriving.typeOfPublicSupport = _typeOfPublicSupport;
setDemandLocation(_demandId,_country,_region,_zip,_city,_street, _houseNumber, _gpsLatitude, _gpsLongitude);
allDemands[_demandId].priceDriving.isInitialized = true;
}
/// @notice function to remove an entry in the activeDemands-array
/// @param _demandId the index position of the full demand in the allDemands-array
/// @param _from the start-index to search for the demandID
/// @param _to the end-index to search for the demandID
/// @dev due to the design the order of elements in the array will change when removing an element!
function removeActiveDemand(uint _demandId, uint _from, uint _to)
external
onlyOwner
returns (bool _success)
{
/*
uint end = _to < activeDemands.length ? _to : activeDemands.length-1;
for (uint i = _from; i < end; i++) {
if ( activeDemands[i] == _demandId) {
activeDemands[i] = activeDemands[activeDemands.length-1];
activeDemands.length--;
return _success;
}
}*/
var (found, index) = searchForDemand(_demandId, _from, _to);
if(found){
activeDemands[index] = activeDemands[activeDemands.length-1];
activeDemands.length--;
}
return found;
}
/// @notice function to set the creation-time of a demand
/// @param _demandId identifier
/// @param _time creation-time
function setDemandCreationTime(uint _demandId, uint _time)
external
onlyOwner
{
allDemands[_demandId].created = _time;
}
/// @notice function to en- or disable a demand
/// @param _demandId identifier
/// @param _enabled flag if the demand should be enabled
function setEnabled(uint _demandId, bool _enabled)
external
onlyOwner
{
Demand storage d = allDemands[_demandId];
d.enabled = _enabled;
}
/// @notice function to update some matching parameters
/// @param _demandId identifier
/// @param _currentWhPerperiod the current amount of Wh
/// @param _certInCurrentperiod the amount of certificates created in the current period
/// @param _productionLastSetInPeriod the last period where the consumption was set
function updateMatchProperties(
uint _demandId,
uint _currentWhPerperiod,
uint _certInCurrentperiod,
uint _productionLastSetInPeriod
)
external
onlyOwner
{
Demand storage d = allDemands[_demandId];
MatcherProperties storage m = d.matchProp;
m.currentWhPerperiod = _currentWhPerperiod;
m.certInCurrentperiod = _certInCurrentperiod;
m.productionLastSetInPeriod = _productionLastSetInPeriod;
}
/// @notice function that returns if a demands exists
/// @param _demandId identifier
/// @return true if demand exists
function demandExists(uint _demandId)
onlyOwner
external
view
returns (bool)
{
return allDemands[_demandId].enabled;
}
/// @notice function to get the hash-identifier of an active demand in the activeDemands-array
/// @param _demandId index of the element in the array
/// @return hash-identifier of an active demand
function getActiveDemandIdAt(uint _demandId)
external
onlyOwner
view
returns (uint)
{
return activeDemands[_demandId];
}
/// @notice function to retrieve the length of the activeDemands-array
/// @return the length of the activeDemands-array
function getActiveDemandListLength()
external
onlyOwner
view
returns (uint)
{
return activeDemands.length;
}
/// @notice funtion to retrieve the length of the allDemands-array
/// @return the length of the allDemands-array
function getAllDemandListLength()
external
onlyOwner
view
returns (uint)
{
return allDemands.length;
}
/// @notice function to get the information if the coupling-struct
/// @dev at the moment arrays can't be accessed in other contracts due to their dynamic length
/// @param _demandId identifier
/// @return used timeFrame, arrays of producing and consuming assets
function getDemandCoupling(uint _demandId)
external
onlyOwner
view
returns(
uint producingAssets,
uint consumingAssets
)
{
Coupling memory s = allDemands[_demandId].couple;
return (s.producingAssets,s.consumingAssets);
}
/// @notice function to retrieve the general informations of a demand
/// @param _assetId identifier of the demand
/// @return the originator, buyer, startTime, endTime, currency, coupled
function getDemandGeneral(uint _assetId)
external
onlyOwner
view
returns(
address originator,
address buyer,
uint startTime,
uint endTime,
uint timeframe,
uint pricePerCertifiedKWh,
uint currency,
uint demandMask
)
{
Demand memory d = allDemands[_assetId];
GeneralInfo memory g = allDemands[_assetId].general;
return (g.originator, g.buyer, g.startTime, g.endTime, g.timeframe, g.pricePerCertifiedKWh, g.currency, d.demandMask);
}
/// @notice function to get the matcher-properties of a demand
/// @param _assetId identifier
/// @return amount of Wh per period, current Wh per period, certificates in current period, last period where a consumption was set and the matcher-address
function getDemandMatcherProperties(uint _assetId)
external
onlyOwner
view
returns (
uint wHAmountPerperiod,
uint currentWhPerperiod,
uint certInCurrentperiod,
uint productionLastSetInPeriod,
address matcher
)
{
MatcherProperties memory m = allDemands[_assetId].matchProp;
return (m.targetWhPerperiod, m.currentWhPerperiod, m.certInCurrentperiod, m.productionLastSetInPeriod, m.matcher);
}
/// @notice function to get the price-driving informations
/// @param _assetId identifier
/// @return location country and region, fueltype and CO2-offset
function getDemandPriceDriving(uint _assetId)
external
onlyOwner
view
returns (
bytes32 locationCountry,
bytes32 locationRegion,
uint assettype,
uint minCO2Offset,
uint registryCompliance,
bytes32 _otherGreenAttributes,
bytes32 _typeOfPublicSupport,
bool isInitialized
)
{
PriceDriving memory p = allDemands[_assetId].priceDriving;
return (p.location.country, p.location.region, p.assettype, p.minCO2Offset, p.registryCompliance, p.otherGreenAttributes, p.typeOfPublicSupport, p.isInitialized);
}
/// @notice gets the bitmask of a demand
/// @param _demandId the demand-id
/// @return bitmask with the set properties of a demand
function getDemandMask(uint _demandId)
external
onlyOwner
view
returns (uint)
{
return allDemands[_demandId].demandMask;
}
/// @notice function to return the creationtime of the demand
/// @param _demandId identifier
/// @return blocktime of the creation of the demand
function getStartEpoche(uint _demandId)
external
onlyOwner
view
returns (uint)
{
return allDemands[_demandId].created;
}
/// @notice Funtion to get the used timeframe for an demand
/// @param _assetId the asset-id
/// @dev will return an unsigned integer, that has to be converted to a timeframe in the logic-contract
/// @return the chosen timeframe for a demand
function getTimeFrame(uint _assetId)
public
onlyOwner
view
returns (uint)
{
return allDemands[_assetId].general.timeframe;
}
/// @notice funciton to search for an active demands
/// @param _demandId the demandId to search for
/// @param _from starting index
/// @param _to ending index
/// @return returns true and index if an index was found, otherwise false and 0
function searchForDemand(
uint _demandId,
uint _from,
uint _to
)
onlyOwner
public
view
returns (bool, uint)
{
uint end = _to < activeDemands.length ? _to : activeDemands.length-1;
for(uint i = _from; i < end; i++){
if(activeDemands[i] == _demandId) {
return (true,i);
}
}
}
/// @notice sets the demand Location
/// @dev internal helper function
/// @param _assetId identifier
/// @param _country country the engery has to come from
/// @param _region region the energy has to come from
/// @param _zip zip code the energy has to come from
/// @param _city the city the energy has to come from
/// @param _street the streetname
/// @param _houseNumber the housenumber the energy has to come from
/// @param _gpsLatitude latitude of coordinates
/// @param _gpsLongitude longitude of coordinates
function setDemandLocation(
uint _assetId,
bytes32 _country,
bytes32 _region,
bytes32 _zip,
bytes32 _city,
bytes32 _street,
bytes32 _houseNumber,
bytes32 _gpsLatitude,
bytes32 _gpsLongitude
)
internal
{
allDemands[_assetId].priceDriving.location.country = _country;
allDemands[_assetId].priceDriving.location.region = _region;
allDemands[_assetId].priceDriving.location.zip = _zip;
allDemands[_assetId].priceDriving.location.city = _city;
allDemands[_assetId].priceDriving.location.street = _street;
allDemands[_assetId].priceDriving.location.houseNumber = _houseNumber;
allDemands[_assetId].priceDriving.location.gpsLatitude = _gpsLatitude;
allDemands[_assetId].priceDriving.location.gpsLongitude = _gpsLongitude;
allDemands[_assetId].priceDriving.location.exists = true;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright 2018 Energy Web Foundation
// This file is part of the Origin Application brought to you by the Energy Web Foundation,
// a global non-profit organization focused on accelerating blockchain technology across the energy sector,
// incorporated in Zug, Switzerland.
//
// The Origin Application is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY and without an implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
//
// @authors: slock.it GmbH, Martin Kuechler, martin.kuchler@slock.it
/// @title The logic contract for the AgreementDB of Origin list
contract DemandLogic is RoleManagement, Updatable {
/// @notice database contract
DemandDB public db;
event createdEmptyDemand(address sender, uint indexed _demandId);
event LogDemandFullyCreated(uint indexed _demandId);
event LogDemandExpired(uint indexed _demandId);
event LogMatcherPropertiesUpdate(uint indexed _demandId, uint currentWhPerPeriod, uint certInCurrentPeriod, uint currentPeriod, uint certID);
enum TimeFrame{
yearly,
monthly,
daily,
hourly
}
enum Currency{
Euro,
USD,
SingaporeDollar,
Ether
}
/*
none: 0x0...0000000000
originator: 0x0...---------1
assetTyoe: 0x0...--------1-
complaince: 0x0...-------1--
country: 0x0...------1---
region: 0x0...-----1----
minCO2: 0x0...----1-----
producing 0x0...---1------
consuming 0x0...--1-------
otherGreenAttributes 0x0...-1--------
typeOfPublicSupport 0x0...1---------
*/
enum DemandProperties {
originator,
assetType,
compliance,
country,
region,
minCO2,
producing,
consuming,
otherGreenAttributes,
typeOfPublicSupport
}
modifier isInitialized {
require((db) != address(0x0));
_;
}
modifier doesNotExist(uint _demandId) {
require(!db.demandExists(_demandId));
_;
}
/// @notice constructor
/// @param _cooContract coo-contract
function DemandLogic(CoO _cooContract)
public
RoleManagement(_cooContract)
{
}
/// @notice Function to create an empty demand, functions initGeneralandCouplong, initMatcherProperties and initPricedriving have to be called in order to fully create a demandc
/// @param _properties array with the to be enabled demandproperties (see DemandProperties struct)
/// @dev will return an event with the event-Id
function createDemand(bool[] _properties)
external
isInitialized
onlyRole(RoleManagement.Role.AgreementAdmin)
{
// if the 1st and the 6th property are set (originator and producing) we will abort because those properties are not allowed to be set at the same time
if(_properties[0] && _properties[6]) {
revert();
}
require(_properties.length == 10);
uint demandID = db.createEmptyDemand(createDemandBitmask(_properties));
createdEmptyDemand(msg.sender, demandID);
}
/// @notice fuction to set the database contract, can only be called once
/// @param _dbAddress address of the database contract
function init(DemandDB _dbAddress)
external
onlyRole(RoleManagement.Role.TopAdmin)
{
require(address(db) == 0x0);
db = _dbAddress;
}
/// @notice function to create a demand and coupling of a new demand, should be called 1st
/// @param _demandId identifier
/// @param _originator address of an energy-producer, can be 0x0
/// @param _buyer address oh the buyer
/// @param _startTime the starttime for a demand
/// @param _endTime the endtime for a demand
/// @param _tf timeFrame
/// @param _pricePerCertifiedKWh price per certified kWh
/// @param _currency currency to be used
/// @param _prodAsset array with producing assets, can be empty
/// @param _consAsset array with consuming assets, can be empty
function initGeneralAndCoupling(
uint _demandId,
address _originator,
address _buyer,
uint _startTime,
uint _endTime,
TimeFrame _tf,
uint _pricePerCertifiedKWh,
Currency _currency,
uint _prodAsset,
uint _consAsset
)
external
onlyRole(RoleManagement.Role.AgreementAdmin)
isInitialized
doesNotExist(_demandId)
{
uint demandMask = db.getDemandMask(_demandId);
createGeneralDemandInternal(_demandId, _originator, _buyer, _startTime, _endTime, _tf, _pricePerCertifiedKWh, _currency);
createCouplingInternal(_demandId, _prodAsset, _consAsset, demandMask);
checkForFullDemand(_demandId);
}
/// @notice function to create the matcher-properties
/// @param _demandId identifier
/// @param _kWAmountPerPeriod amounts of KW per Period
/// @param _productionLastSetInPeriod todo: needed?
/// @param _matcher address of the matcher
function initMatchProperties(
uint _demandId,
uint _kWAmountPerPeriod,
uint _productionLastSetInPeriod,
address _matcher
)
external
onlyRole(RoleManagement.Role.AgreementAdmin)
isInitialized
doesNotExist(_demandId)
{
require(isRole(RoleManagement.Role.Matcher,_matcher));
db.createMatchProperties(_demandId, _kWAmountPerPeriod, 0, 0, _productionLastSetInPeriod, _matcher);
checkForFullDemand(_demandId);
}
/// @notice function to create a priceDriving-struct
/// @param _demandId identifier
/// @param _locationCountry country where the energy should be generated
/// @param _locationRegion region where the energy should be generated
/// @param _type fueltype
/// @param _minCO2Offset CO2-offset
/// @param _registryCompliance compliance
/// @param _otherGreenAttributes other green attributes
/// @param _typeOfPublicSupport type of public support
function initPriceDriving(
uint _demandId,
bytes32 _locationCountry,
bytes32 _locationRegion,
AssetProducingRegistryLogic.AssetType _type,
uint _minCO2Offset,
uint _registryCompliance,
bytes32 _otherGreenAttributes,
bytes32 _typeOfPublicSupport
)
external
isInitialized
{
// we can't use modifier for this function due to the stack limitation. So we have to call the checkForDemandExist function that checks the requirements while bypassing the stacklimit
checkForDemandExist(_demandId);
db.createPriceDriving( _demandId, _locationCountry, _locationRegion, 0x0, 0x0, 0x0, 0, 0x0, 0x0, uint(_type), _minCO2Offset, _registryCompliance, _otherGreenAttributes, _typeOfPublicSupport);
checkForFullDemand(_demandId);
}
/// @notice function to match a certificate to a demand
/// @param _demandId the demand-id
/// @param _certificateId the id of a non retired certificate
function matchCertificate(uint _demandId, uint _certificateId)
external
isInitialized
{
// we get all the needed data from a certificate
var(prodAssetId, , powerInW, retired, , coSaved, escrow, creationTime) = CertificateLogic(address(cooContract.certificateRegistry())).getCertificate(_certificateId);
// we accept only non retired certificates and they have to creates less then 1 year ago
// we also make sure that only the scrow-address (aka a matcher) is able to call this function
require(!retired && (creationTime + 365 days) >= now && msg.sender == escrow);
require(!hasDemandPropertySet(DemandProperties.consuming, db.getDemandMask(_demandId)));
// we're trying to match the certificate to a demand. If there is a non-match the function will revert
var (owner, currentWhPerPeriod, certInCurrentPeriod, currentPeriod) = matchInternal(_demandId, powerInW, prodAssetId, coSaved);
// at the end we have to update the matcher-properties
db.updateMatchProperties(_demandId, currentWhPerPeriod,certInCurrentPeriod, currentPeriod);
CertificateLogic(address(cooContract.certificateRegistry())).transferOwnershipByEscrow( _certificateId, owner);
LogMatcherPropertiesUpdate(_demandId, currentWhPerPeriod, certInCurrentPeriod, currentPeriod, _certificateId);
}
/// @notice function to check whether an active demand lies within the provided range
/// @param _demandId the demandId to search for
/// @param _from starting index
/// @param _to ending index
function searchForDemand(
uint _demandId,
uint _from,
uint _to
)
external
view
returns (bool _found, uint index)
{
return db.searchForDemand(_demandId, _from, _to);
}
/// @notice function for internal matching, gets called by both matchDemand and matchCertificate
/// @param _demandId demandid
/// @param _wCreated amount of power created
/// @param _prodAssetId id of the producing-asset
/// @param _co2Saved amount of CO2-saved
/// @return the owner, the new (increased) amount of CurrentWhPerPeriod, the new (increased) amount of certificatesCreated per period and the current period
function matchInternal(
uint _demandId,
uint _wCreated,
uint _prodAssetId,
uint _co2Saved
)
internal
view
isInitialized
returns (address owner, uint currentWhPerPeriod, uint certInCurrentPeriod, uint currentPeriod)
{
// we have to check if a demand with that identifier actually exists
var (generalExists, priceDrivingExists, matcherExists) = getExistStatus(_demandId);
require(generalExists && priceDrivingExists && matcherExists);
bool passCheck;
// we're comparing the demand-properties
(owner, passCheck,) = checkDemandGeneral(_demandId, _prodAssetId);
require(passCheck);
(passCheck,) = checkPriceDriving(_demandId, _prodAssetId, _wCreated, _co2Saved);
require(passCheck);
(currentWhPerPeriod,certInCurrentPeriod, currentPeriod,passCheck,) = checkMatcher(_demandId, _wCreated);
require(passCheck);
(passCheck,) = checkDemandCoupling(_demandId, _prodAssetId, _wCreated);
require(passCheck);
}
/// @notice Updates the logic contract
/// @param _newLogic Address of the new logic contract
function update(address _newLogic)
external
onlyAccount(address(cooContract))
{
db.changeOwner(_newLogic);
}
/// @notice funciton to retrieve the identifier-hash of an active demand
/// @param _demandId position in the array
/// @return identifier-hash
function getActiveDemandIdAt(uint _demandId) external isInitialized view returns (uint) {
return db.getActiveDemandIdAt(_demandId);
}
/// @notice function to return the length of the acticeDemands-array in the database
/// @return length if the activeDemands-array in the database
function getActiveDemandListLength() external isInitialized view returns (uint) {
return db.getActiveDemandListLength();
}
/// @notice function to return the length of the allDemands-array in the database
/// @return length of the allDemansa-array
function getAllDemandListLength() external isInitialized view returns (uint) {
return db.getAllDemandListLength();
}
/// @notice function to get the information if the coupling-struct
/// @param _demandId identifier
/// @return used timeFrame
function getDemandCoupling(uint _demandId)
external
view
isInitialized
returns(
uint producingAssets,
uint consumingAssets
)
{
return db.getDemandCoupling(_demandId);
}
/// @notice function to retrieve the general informations of a demand
/// @param _demandId identifier of the demand
/// @return the originator, buyer, startTime, endTime, currency, coupled
function getDemandGeneral(uint _demandId)
external
isInitialized
view
returns (
address originator,
address buyer,
uint startTime,
uint endTime,
uint timeframe,
uint pricePerCertifiedKWh,
uint currency,
uint demandMask
)
{
return db.getDemandGeneral(_demandId);
}
/// @notice function to get the matcher-properties of a demand
/// @param _demandId identifier
/// @return amount of Wh per Period, current Wh per Period, certificates in current Period, last Period where a consumption was set and the matcher-address
function getDemandMatcherProperties(uint _demandId)
external
view
isInitialized
returns (
uint targetWhPerPeriod,
uint currentWhPerPeriod,
uint certInCurrentPeriod,
uint productionLastSetInPeriod,
address matcher
)
{
return db.getDemandMatcherProperties(_demandId);
}
/// @notice function to get the price-driving informations
/// @param _demandId identifier
/// @return location country and region, assettype, CO2-offset, compliance, green attributes and type of public support
function getDemandPriceDriving(uint _demandId)
external
view
isInitialized
returns (
bytes32 locationCountry,
bytes32 locationRegion,
uint assettype,
uint minCO2Offset,
uint registryCompliance,
bytes32 _otherGreenAttributes,
bytes32 _typeOfPublicSupport,
bool isInit
)
{
return db.getDemandPriceDriving(_demandId);
}
/// @notice function to get the existing status of the different demand-structs
/// @param _demandId identifier
/// @return returns existing of generalInformation, priceDriving and matcher-Properties
function getExistStatus(uint _demandId)
public
view
returns (bool general, bool priceDriving, bool matchProp)
{
var(,buyer,,,,,,) = db.getDemandGeneral(_demandId);
general = (buyer != address(0));
var(,,,,matcher) = db.getDemandMatcherProperties(_demandId);
matchProp = (matcher != address(0));
(,,,,priceDriving) = db.getDemandPriceDriving(_demandId);
}
/// @notice funciton to remove an active demand, can only be successfully processed if the the endTime already passed
/// @param _demandId index of the demand in the activeDemands-array
/// @param _from index of the starting element
/// @param _to index of the end-element
function removeActiveDemand(
uint _demandId,
uint _from,
uint _to
)
public
{
var ( , , , endTime, , , , ) = db.getDemandGeneral(_demandId);
require(endTime < now);
require(db.removeActiveDemand( _demandId, _from, _to));
LogDemandExpired(_demandId);
}
/// @notice function to check the coupling properties of a demand
/// @param _demandId demand-Id
/// @param _prodAssetId production-asset id
/// @param _wCreated amount of Wh created
/// @return flag if the check was successfull and a string with the result
function checkDemandCoupling(uint _demandId, uint _prodAssetId, uint _wCreated)
public
view
returns (bool, string)
{
var (prodAsset, consAsset ) = db.getDemandCoupling(_demandId);
if (hasDemandPropertySet(DemandProperties.producing, db.getDemandMask(_demandId))) {
if (_prodAssetId != prodAsset){
return (false, "wrong prodAssetId");
}
}
if (hasDemandPropertySet(DemandProperties.consuming, db.getDemandMask(_demandId))) {
var (capacityWh, maxCapacitySet, certificatesUsedForWh) = AssetConsumingRegistryLogic(address(cooContract.assetConsumingRegistry())).getConsumingProperies(consAsset);
if(maxCapacitySet){
if(certificatesUsedForWh + _wCreated > capacityWh ){
assert(capacityWh >= certificatesUsedForWh);
return (false, "too much energy for max capacity");
}
} else {
var(wHAmountPerperiod, , , , ) = db.getDemandMatcherProperties(_demandId);
if(certificatesUsedForWh + _wCreated > wHAmountPerperiod) {
assert(wHAmountPerperiod >= certificatesUsedForWh);
return (false, "too much energy for for consuming target");}
}
}
return(true,"");
}
/// @notice function to check the fitting of the general-demand information with a matching
/// @param _demandId identifier
/// @param _prodAssetId asset-id that produced some energy
/// @return originator-address, coupled-flag, if there was an error and what check failed
function checkDemandGeneral(uint _demandId, uint _prodAssetId)
public
view
returns (address, bool, string)
{
var ( originator, buyer, startTime, endTime, , , ,demandMask) = db.getDemandGeneral(_demandId);
var ( , owner, , , , ) = AssetProducingRegistryLogic(address(cooContract.assetProducingRegistry())).getAssetGeneral(_prodAssetId);
if(hasDemandPropertySet(DemandProperties.originator, demandMask)){
if(originator != owner){
return (0x0, false, "wrong originator");
}
}
if(!(
startTime <= now &&
endTime >= now
&& isRole(RoleManagement.Role.Trader,owner)
&& isRole(RoleManagement.Role.Trader, buyer)
&& isRole(RoleManagement.Role.AssetManager, owner)
)) return (0x0, false, "starttime or rolecheck");
return (buyer, true, "everything ok");
}
/// @notice function to check the matcher-properties
/// @param _demandId identifier
/// @param _wCreated Wh created
/// @return currentWhPerPeriod, certInCurrentPeriod, currentPeriod, if there was an error and what check failed
function checkMatcher(uint _demandId, uint _wCreated)
public
view
returns (uint , uint , uint, bool, string )
{
var( whAmountPerPeriod, currentWhPerPeriod, certInCurrentPeriod, lastPeriod, matcher) = db.getDemandMatcherProperties(_demandId);
whAmountPerPeriod = getMaxEnergyCoupling(_demandId, whAmountPerPeriod);
if (matcher != msg.sender) return (0,0,0, false, "wrong matcher");
uint currentPeriod = getCurrentPeriod(_demandId);
if (currentPeriod == lastPeriod) {
if(currentWhPerPeriod+_wCreated > whAmountPerPeriod) {
return (0,0,0, false, "too much whPerPeriode");
}
} else {
if(_wCreated > whAmountPerPeriod) {
return (0,0,0, false, "too much whPerPeriode and currentPeriod != lastPeriod");
}
lastPeriod = currentPeriod;
currentWhPerPeriod = 0;
certInCurrentPeriod = 0;
}
currentWhPerPeriod += _wCreated;
certInCurrentPeriod += 1;
return (currentWhPerPeriod, certInCurrentPeriod, currentPeriod, true, "everything OK");
}
/// @notice function to check the priceDriving-oarameters for the matching
/// @param _demandId identifier
/// @param _prodAssetId the producing asset-id
/// @param _wCreated the amount of energy created
/// @param _co2Saved the amount of CO2 saved
/// @return if there was an error and what check failed
function checkPriceDriving(
uint _demandId,
uint _prodAssetId,
uint _wCreated,
uint _co2Saved
)
public
view
returns (bool, string)
{
if(_wCreated == 0) {
return (false, "no energy created");
}
var (,,, minCO2OffsetDemand, compliance,,,) = db.getDemandPriceDriving(_demandId);
var(checkRes, error) = checkAssetType(_demandId, _prodAssetId);
if(!checkRes) {
return (checkRes,error);
}
(checkRes, error) = checkLocation(_demandId, _prodAssetId);
if(!checkRes) {
return (checkRes,error);
}
if(hasDemandPropertySet(DemandProperties.compliance, db.getDemandMask(_demandId))){
if(uint(AssetProducingRegistryLogic(cooContract.assetProducingRegistry()).getCompliance(_prodAssetId)) !=compliance) {
return (false, "wrong compliance");
}
}
if(hasDemandPropertySet(DemandProperties.minCO2, db.getDemandMask(_demandId))){
if(_co2Saved == 0) {
_co2Saved = AssetProducingRegistryLogic(cooContract.assetProducingRegistry()).getCoSaved(_prodAssetId, _wCreated);
}
uint co2PerWh = ((_co2Saved * 1000) / _wCreated)/10;
if(co2PerWh < minCO2OffsetDemand){
return (false, "wrong CO2");
}
}
if(hasDemandPropertySet(DemandProperties.otherGreenAttributes, db.getDemandMask(_demandId))){
if(!checkGreenAttributes(_demandId, _prodAssetId)) {
return (false,"wrong Green Attribute");
}
}
if(hasDemandPropertySet(DemandProperties.typeOfPublicSupport, db.getDemandMask(_demandId))){
if(!checkTypeOfPublicSupport(_demandId, _prodAssetId)) {
return (false,"wrong Type of public support");
}
}
return (true,"everything OK");
}
/// @notice function to calculate the current Period for a demand
/// @param _demandId identifier
/// @return current Period
function getCurrentPeriod(uint _demandId)
public
view
isInitialized
returns (uint)
{
uint tf = db.getTimeFrame(_demandId);
if ( TimeFrame(tf) == TimeFrame.yearly)
{
return ( now - db.getStartEpoche(_demandId) ) / (1 years);
}
if ( TimeFrame(tf) == TimeFrame.monthly) {
return ( now - db.getStartEpoche(_demandId) ) / (30 days);
}
if ( TimeFrame(tf) == TimeFrame.daily) {
return ( now - db.getStartEpoche(_demandId) ) / (1 days);
}
if ( TimeFrame(tf) == TimeFrame.hourly) {
return ( now - db.getStartEpoche(_demandId) ) / (1 hours);
}
}
/// @notice function to calculate the maximum amount of energy left for a demand and period
/// @param _demandId the demand-id
/// @param _whAmountPerPeriod the amount of Wh per Period
/// @return the maximum ammount of energy left for a demand
function getMaxEnergyCoupling(uint _demandId, uint _whAmountPerPeriod)
public
view
returns(uint)
{
// there is no coupling, so we don't have to go further
if (!hasDemandPropertySet(DemandProperties.consuming, db.getDemandMask(_demandId))) return _whAmountPerPeriod;
//we're getting the consuming Assets and its properties
var (, consAsset ) = db.getDemandCoupling(_demandId);
var (capacityWh, maxCapacitySet, certificatesUsedForWh) = AssetConsumingRegistryLogic(address(cooContract.assetConsumingRegistry())).getConsumingProperies(consAsset);
// the maxCapacitySet-flag was set
if(maxCapacitySet){
//we do not allow to let the capacity exceeds the amount of energy set in the demand
if(capacityWh > _whAmountPerPeriod) {
capacityWh = _whAmountPerPeriod;
}
if(certificatesUsedForWh <= capacityWh){
return (capacityWh-certificatesUsedForWh);
}
else {
return 0;
}
}
// there is no max capacity set, so only the demand-energy is counting
else {
if(certificatesUsedForWh <= _whAmountPerPeriod){
return (_whAmountPerPeriod-certificatesUsedForWh);
}
else{
return 0;
}
}
return _whAmountPerPeriod;
}
/// @notice function to check if a full demand is created and enabling him
/// @param _demandId identifier
function checkForFullDemand(uint _demandId)
private
{
var (generalExists, priceDrivingExists, matcherExists) = getExistStatus(_demandId);
if (generalExists && priceDrivingExists && matcherExists) {
db.setEnabled(_demandId,true);
db.addActiveDemand(_demandId);
db.setDemandCreationTime(_demandId, now);
LogDemandFullyCreated(_demandId);
}
}
/// @notice function to create the bitmask for a demand
/// @param _demandArray the array with demand properties
/// @return the calculated bitmask
function createDemandBitmask (bool[] _demandArray)
public
pure
returns (uint demandMask)
{
/** Bitmask: originator, assetType, compliance, country, region, minCO2, producing, consuming */
for(uint8 i = 0; i < 10; i++) {
if(_demandArray[i]){
demandMask += uint(2) ** uint(i);
}
}
}
/// @notice function for comparing the role and the needed rights of an user
/// @param _props entry of the demandProperties-enum
/// @param _demandMask the bitmask of the demand
/// @return the demand has the property set
function hasDemandPropertySet(
DemandProperties _props,
uint _demandMask
)
public
pure
returns (bool)
{
uint demandActive = uint(2) ** uint(_props);
return (_demandMask & demandActive != 0);
}
/// @notice function to check the assetType
/// @param _demandId the demand-id
/// @param _prodAssetId the production-asset id
/// @return the bool-flag for check and error-message
function checkAssetType(uint _demandId, uint _prodAssetId)
internal
view
returns (bool, string)
{
if(hasDemandPropertySet(DemandProperties.assetType, db.getDemandMask(_demandId))){
var (, , assettypeDemand, ,,,, ) = db.getDemandPriceDriving(_demandId);
if(AssetProducingRegistryLogic.AssetType(assettypeDemand) != AssetProducingRegistryLogic(cooContract.assetProducingRegistry()).getAssetType( _prodAssetId)){
return (false, "wrong asset type");
}
}
return (true, "");
}
/// @notice internal helper function to check if the demand exists and the sender has the right role
/// @param _demandId the demandid
function checkForDemandExist(uint _demandId)
internal
view
{
require(!db.demandExists(_demandId));
require(isRole(RoleManagement.Role.AgreementAdmin, msg.sender));
}
/// @notice function to check the location
/// @param _demandId the demand-id
/// @param _prodAssetId the production-asset id
/// @return the bool-flag for check and error-message
function checkLocation(uint _demandId, uint _prodAssetId)
internal
view returns (bool, string)
{
if(hasDemandPropertySet(DemandProperties.country, db.getDemandMask(_demandId))){
var (countryAsset, regionAsset, , , , , ) = AssetProducingRegistryLogic(cooContract.assetProducingRegistry()).getAssetLocation(_prodAssetId);
var (locationCountryDemand, locationRegionDemand, , , , ) = db.getDemandPriceDriving(_demandId);
if(locationCountryDemand != countryAsset){
return (false, "wrong country");
}
if(hasDemandPropertySet(DemandProperties.region, db.getDemandMask(_demandId))){
if(locationRegionDemand != regionAsset) {
return (false, "wrong region");
}
}
}
return (true,"");
}
/// @notice internal helper function to check green attributes
/// @param _demandId the demandId
/// @param _prodAssetId the id of the producing asset
/// @return true if the attributes are matching
function checkGreenAttributes(uint _demandId, uint _prodAssetId)
internal
view
returns(bool)
{
var ( , , , , , demandGreenAttribute, , ) = db.getDemandPriceDriving(_demandId);
var ( , , , , , , assetGreenAttribute,) = AssetProducingRegistryLogic(cooContract.assetProducingRegistry()).getAssetProducingProperties(_prodAssetId);
return(demandGreenAttribute == assetGreenAttribute );
}
/// @notice internal helper function to check the type of public support
/// @param _demandId the id of the demand
/// @param _prodAssetId the id of the producing asset
/// @return true if the green attributes are matching
function checkTypeOfPublicSupport(uint _demandId, uint _prodAssetId)
internal
view
returns (bool)
{
var ( , , , , , ,demandTypeOfPublicSupport , ) = db.getDemandPriceDriving(_demandId);
var ( , , , , , , ,assetTypeOfPublicSupport) = AssetProducingRegistryLogic(cooContract.assetProducingRegistry()).getAssetProducingProperties(_prodAssetId);
return(demandTypeOfPublicSupport == assetTypeOfPublicSupport);
}
/// @notice internal function to create a coupling
/// @param _demandId demand-id
/// @param _prodAsset production-AssetId, gets only checked if the flag in the demand-Bitmask is set
/// @param _consAsset consuming-AssetId, gets only checked if the flag in the demand-Bitmask is set
function createCouplingInternal(uint _demandId, uint _prodAsset, uint _consAsset, uint _demandMask)
internal
{
if(hasDemandPropertySet(DemandProperties.producing, _demandMask)){
require(AssetProducingRegistryLogic(address(cooContract.assetProducingRegistry())).getActive((_prodAsset)));
}
if(hasDemandPropertySet(DemandProperties.consuming, _demandMask)){
require(AssetConsumingRegistryLogic(address(cooContract.assetConsumingRegistry())).getActive((_consAsset)));
}
db.createCoupling(_demandId, _prodAsset, _consAsset);
}
/// @notice internal function to create a demand
/// @param _demandId the demand-Id
/// @param _originator the originator (can be set)
/// @param _buyer the buyer, has to bet set
/// @param _startTime starttime of the demand
/// @param _endTime endtime of the demand
/// @param _tf timeframe
/// @param _pricePerCertifiedKWh price per certified KWh
/// @param _currency used currency
function createGeneralDemandInternal(
uint _demandId,
address _originator,
address _buyer,
uint _startTime,
uint _endTime,
TimeFrame _tf,
uint _pricePerCertifiedKWh,
Currency _currency)
internal
{
db.createGeneralDemand(_demandId, _originator, _buyer, _startTime, _endTime, uint(_tf), _pricePerCertifiedKWh, uint(_currency));
}
/// @notice function to match produced energy with the needed demand
/// @param _demandId identifier of the demand
/// @param _wCreated amount of Wh created
/// @param _prodAssetId asset-Id that produced the energy
function matchDemand(uint _demandId, uint _wCreated, uint _prodAssetId)
external
isInitialized
{
var (owner, currentWhPerPeriod, certInCurrentPeriod, currentPeriod) = matchInternal(_demandId, _wCreated, _prodAssetId, 0);
// all the criteria are matched, so we can create the certificate
uint certId = CertificateLogic(address(cooContract.certificateRegistry())).createCertificate(_prodAssetId, owner, _wCreated);
// at the end we have to update the matcher-properties
db.updateMatchProperties(_demandId, currentWhPerPeriod, certInCurrentPeriod, currentPeriod);
LogMatcherPropertiesUpdate(_demandId, currentWhPerPeriod, certInCurrentPeriod, currentPeriod, certId);
// there is a consuming activated, so we have to write the new amount of consumed energy into the asset information
if(hasDemandPropertySet(DemandProperties.consuming, db.getDemandMask(_demandId))){
writeConsumingEnergy(_demandId, _wCreated, currentPeriod);
}
}
/// @notice function to write the consumed energy into the asset
/// @param _demandId the demandId
/// @param _wCreated the amount of energy created / consumed
/// @param _currentPeriod the current period
function writeConsumingEnergy(uint _demandId, uint _wCreated, uint _currentPeriod)
internal
isInitialized
{
var( , , , lastPeriod, ) = db.getDemandMatcherProperties(_demandId);
var (, consAsset ) = db.getDemandCoupling(_demandId);
if (_currentPeriod == lastPeriod) {
var(,,currentConsumption) = AssetConsumingRegistryLogic(address(cooContract.assetConsumingRegistry())).getConsumingProperies(consAsset);
AssetConsumingRegistryLogic(address(cooContract.assetConsumingRegistry())).setConsumptionForPeriode(consAsset,_wCreated+currentConsumption);
} else {
AssetConsumingRegistryLogic(address(cooContract.assetConsumingRegistry())).setConsumptionForPeriode(consAsset,_wCreated);
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright 2018 Energy Web Foundation
// This file is part of the Origin Application brought to you by the Energy Web Foundation,
// a global non-profit organization focused on accelerating blockchain technology across the energy sector,
// incorporated in Zug, Switzerland.
//
// The Origin Application is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY and without an implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
//
// @authors: slock.it GmbH, Martin Kuechler, martin.kuchler@slock.it
/// @title the locationDefinition for the contracts
contract LocationDefinition {
struct Location {
bytes32 country; //why do you use bytes32 for everything instead of string, uint, ...?
bytes32 region;
bytes32 city;
bytes32 street;
bytes32 zip;
bytes32 houseNumber;
bytes32 gpsLatitude;
bytes32 gpsLongitude;
bool exists;
}
}// Copyright 2018 Energy Web Foundation
// This file is part of the Origin Application brought to you by the Energy Web Foundation,
// a global non-profit organization focused on accelerating blockchain technology across the energy sector,
// incorporated in Zug, Switzerland.
//
// The Origin Application is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY and without an implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
//
// @authors: slock.it GmbH, Martin Kuchler, martin.kuchler@slock.it
pragma solidity ^0.4.17;
contract Migrations {
address public owner;
uint public last_completed_migration;
modifier restricted() {
if (msg.sender == owner) _;
}
function Migrations() public {
owner = msg.sender;
}
function setCompleted(uint completed) external restricted {
last_completed_migration = completed;
}
function upgrade(address new_address) external restricted {
Migrations upgraded = Migrations(new_address);
upgraded.setCompleted(last_completed_migration);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright 2018 Energy Web Foundation
// This file is part of the Origin Application brought to you by the Energy Web Foundation,
// a global non-profit organization focused on accelerating blockchain technology across the energy sector,
// incorporated in Zug, Switzerland.
//
// The Origin Application is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY and without an implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
//
// @authors: slock.it GmbH, Martin Kuechler, martin.kuchler@slock.it
/// @title this interface defines functions for defining functions of the user-logic in order to call them in different contracts
interface RolesInterface {
/// @notice function to retrieve the rights of an user
/// @dev if the user does not exist in the mapping it will return 0x0 thus preventing them from accidently getting any rights
/// @param _user user someone wants to know its rights
/// @return bitmask with the rights of the user
function getRolesRights(address _user) external view returns (uint);
/// @notice function that checks if there is an user for the provided ethereum-address
/// @param _user ethereum-address of that user
/// @return bool if the user exists
function doesUserExist(address _user) external view returns (bool);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright 2018 Energy Web Foundation
// This file is part of the Origin Application brought to you by the Energy Web Foundation,
// a global non-profit organization focused on accelerating blockchain technology across the energy sector,
// incorporated in Zug, Switzerland.
//
// The Origin Application is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY and without an implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
//
// @authors: slock.it GmbH, Martin Kuechler, martin.kuchler@slock.it
/// @title The database contract for the users, traders and admins of the certificate of origin
/// @notice This contract only provides getter and setter methods that are only callable by the corresponging owner-contract
contract UserDB is Owned {
/// @notice The structure of an user / admin / trader
/// @dev as it's for now impossible to return a struct, there is a special get-function for this struct.
/// @dev keep in mind to update that function aswell when changing the user-struct
struct User {
bytes32 firstName;
bytes32 surname;
bytes32 organization;
LocationDefinition.Location location;
uint roles;
bool active;
}
/// @notice mapping for addresses to users
mapping(address => User) private userList; // why private?
modifier userExists(address _user) {
require(userList[_user].firstName != 0x0 && userList[_user].surname != 0x0);
_;
}
/// @notice The constructor of the UserDB
/// @dev the deployer of this contract will get full adminrights!
function UserDB(address _logic) Owned(_logic) public {
}
/// @notice function to set a new address for an existing organization
/// @dev the onlyOwner-modifier is used, so that only the logic-contract is allowed to write into the storage
/// @param _user ethereum-address of the organization
/// @param _street new streetname
/// @param _number new number
/// @param _zip new zip-code
/// @param _city new city
/// @param _country new country
/// @param _state new state
function setAddress(
address _user,
bytes32 _street,
bytes32 _number,
bytes32 _zip,
bytes32 _city,
bytes32 _country,
bytes32 _state
)
external
onlyOwner
userExists(_user)
{
User storage u = userList[_user];
u.location.street = _street;
u.location.houseNumber = _number;
u.location.zip = _zip;
u.location.city = _city;
u.location.country = _country;
u.location.region = _state;
u.active = true;
}
/// @notice function to change the name of an existing organization, can only be used when the user already exists
/// @dev the onlyOwner-modifier is used, so that only the logic-contract is allowed to write into the storage
/// @param _user ethereum-address of an user
/// @param _organization new name of the organization
function setOrganization(
address _user,
bytes32 _organization
)
external
onlyOwner
userExists(_user)
{
User storage u = userList[_user];
u.organization = _organization;
u.active = true;
}
/// @notice function for creating, editing an user, it cannot be used to set a Role of an user
/// @notice if the user does not exists yet it will be creates, otherwise the older userdata will be overwritten
/// @dev the onlyOwner-modifier is used, so that only the logic-contract is allowed to write into the storage
/// @param _user address of the user
/// @param _firstName first name of the user
/// @param _surname surname of the user
/// @param _organization organization the user is representing
/// @param _street streetname
/// @param _number housenumber
/// @param _zip zip-code
/// @param _city city-name
/// @param _country country-name
/// @param _state state
function setUser(
address _user,
bytes32 _firstName,
bytes32 _surname,
bytes32 _organization,
bytes32 _street,
bytes32 _number,
bytes32 _zip,
bytes32 _city,
bytes32 _country,
bytes32 _state
)
external
onlyOwner
{
User storage u = userList[_user];
LocationDefinition.Location storage loc = u.location;
u.firstName = _firstName;
u.surname = _surname;
u.organization = _organization;
u.location = loc;
loc = u.location;
loc.country = _country;
loc.region = _state;
loc.city = _city;
loc.street = _street;
loc.zip = _zip;
loc.houseNumber = _number;
loc.gpsLatitude = 0x0;
loc.gpsLongitude = 0x0;
loc.exists = true;
u.active = true;
}
/// @notice function to (de-)active a user, dan only be used when the user already exists
/// @dev the onlyOwner-modifier is used, so that only the logic-contract is allowed to write into the storage
/// @param _user ethereum-address of an user
/// @param _active flag if the account should be active
function setUserActive(
address _user,
bool _active
)
external
onlyOwner
{
User storage u = userList[_user];
u.active = _active;
}
/// @notice function to change the username, can only be used when the user already exists
/// @dev the onlyOwner-modifier is used, so that only the logic-contract is allowed to write into the storage
/// @param _user ethereum-address of an user
/// @param _firstName new first name
/// @param _surname new surname
function setUserName(
address _user,
bytes32 _firstName,
bytes32 _surname
)
external
onlyOwner
userExists(_user)
{
User storage u = userList[_user];
u.firstName = _firstName;
u.surname = _surname;
u.active = true;
}
/// @notice function for editing the rights of an user
/// @dev the onlyOwner-modifier is used, so that only the logic-contract is allowed to write into the storage
/// @param _user address of the user
/// @param _roles first name of the user
function setRoles(
address _user,
uint _roles
)
external
onlyOwner
{
User storage u = userList[_user];
u.roles = _roles;
}
/// @notice function that checks if there is an user for the provided ethereum-address
/// @dev the onlyOwner-modifier is used, so that only the logic-contract is allowed to read directly from the contract
/// @param _user ethereum-address of that user
/// @return bool if the user exists
function doesUserExist(address _user)
external
view
returns (bool) {
return userList[_user].active;
}
/// @notice function to return all the data of an user
/// @dev the onlyOwner-modifier is used, so that only the logic-contract is allowed to read directly from the contract
/// @param _user user
/// @return returns firstName, surname, organization, street, number, zip, city, country, state, roles and the active-flag
function getFullUser(address _user)
external
view
returns (
bytes32 firstName,
bytes32 surname,
bytes32 organization,
bytes32 street,
bytes32 number,
bytes32 zip,
bytes32 city,
bytes32 country,
bytes32 state,
uint roles,
bool active
)
{
User memory u = userList[_user];
return (u.firstName, u.surname, u.organization, u.location.street, u.location.houseNumber, u.location.zip, u.location.city, u.location.country, u.location.region, u.roles, u.active);
}
/// @notice function to retrieve the rights of an user
/// @dev the onlyOwner-modifier is used, so that only the logic-contract is allowed to read directly from the contract
/// @dev if the user does not exist in the mapping it will return 0x0 thus preventing them from accidently getting any rights
/// @param _user user someone wants to know its rights
/// @return bitmask with the rights of the user
function getRolesRights(address _user)
external
view
returns (uint)
{
return userList[_user].roles;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright 2018 Energy Web Foundation
// This file is part of the Origin Application brought to you by the Energy Web Foundation,
// a global non-profit organization focused on accelerating blockchain technology across the energy sector,
// incorporated in Zug, Switzerland.
//
// The Origin Application is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY and without an implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
//
// @authors: slock.it GmbH, Martin Kuechler, martin.kuchler@slock.it
/// @title The logic-contract for the user-data
/// @notice this contract will not directly store any data, instead it will store them into the userDB-contract
contract UserLogic is RoleManagement, Updatable, RolesInterface {
/// @notice db user-db for storing the contract
UserDB public db;
modifier isInitialized {
require(address(db) != 0x0);
_;
}
/// @notice constructor
/// @param _coo address of the Certificate Registry contract (CoO.sol)
/// @dev it will also call the RoleManagement-constructor
function UserLogic(CoO _coo) RoleManagement(_coo) public {
}
/// @notice grant a user a an admin-right
/// @param _user user that should get rights
/// @param role admin-right to be granted
function addAdminRole(address _user, RoleManagement.Role role)
external
userExists(_user)
onlyRole(RoleManagement.Role.TopAdmin)
{
if ((role == RoleManagement.Role.TopAdmin || role == RoleManagement.Role.UserAdmin
|| role == RoleManagement.Role.AssetAdmin || role == RoleManagement.Role.Trader)
// && role != RoleManagement.Role.Trader && role != RoleManagement.Role.AssetManager
) {
if (!isRole(role,_user)) {
uint roles = db.getRolesRights(_user);
db.setRoles(_user, roles + uint(2) ** uint(role));
}
}
}
/// @notice grants a user the role AssetManager
/// @param _user user
function addAssetManagerRole(address _user)
external
userExists(_user)
onlyRole(RoleManagement.Role.AssetAdmin)
{
if (!isRole(RoleManagement.Role.AssetManager,_user)) {
uint roles = db.getRolesRights(_user);
db.setRoles(_user, roles + uint(2) ** uint(RoleManagement.Role.AssetManager));
}
}
/// @notice grants an ethereum-account the matcher-rights
/// @param _user ethereum-account
function addMatcherRole(address _user)
external
onlyRole(RoleManagement.Role.TopAdmin)
{
if (!isRole(RoleManagement.Role.Matcher,_user)) {
uint roles = db.getRolesRights(_user);
db.setRoles(_user, roles + uint(2) ** uint(RoleManagement.Role.Matcher));
}
}
/// @notice grants a user the trader-Role
/// @param _user user
function addTraderRole(address _user)
external
userExists(_user)
onlyRole(RoleManagement.Role.AgreementAdmin)
{
if (!isRole(RoleManagement.Role.Trader,_user)) {
uint roles = db.getRolesRights(_user);
db.setRoles(_user, roles + uint(2) ** uint(RoleManagement.Role.Trader));
}
}
/// @notice Initialises the contract by binding it to a logic contract
/// @param _database Sets the logic contract
function init(address _database) external {
require(db == UserDB(0x0) && cooContract.owner() == msg.sender);
db = UserDB(_database);
}
/// @notice function to deactive an use, only executable for user-admins
/// @param _user the user that should be deactivated
function deactivateUser(address _user)
external
onlyRole(RoleManagement.Role.UserAdmin)
isInitialized
{
require(!isRole(RoleManagement.Role.TopAdmin,_user)
&& !isRole(RoleManagement.Role.UserAdmin,_user)
&& !isRole(RoleManagement.Role.AssetAdmin,_user)
&& !isRole(RoleManagement.Role.AgreementAdmin,_user)
);
db.setUserActive(_user, false);
}
/// @notice function to remove an admin-right from a user
/// @param _user user
/// @param role role to be removed
function removeAdminRole(address _user, RoleManagement.Role role)
external
userExists(_user)
onlyRole(RoleManagement.Role.TopAdmin)
{
if ((role == RoleManagement.Role.TopAdmin || role == RoleManagement.Role.UserAdmin
|| role == RoleManagement.Role.AssetAdmin || role == RoleManagement.Role.AgreementAdmin)
) {
if (isRole(role,_user)) {
uint roles = db.getRolesRights(_user);
db.setRoles(_user, roles - uint(2) ** uint(role));
}
}
}
/// @notice removes the assetManagerRole from a user
/// @param _user user
function removeAssetManagerRole(address _user)
external
userExists(_user)
onlyRole(RoleManagement.Role.AssetAdmin)
{
if (isRole(RoleManagement.Role.AssetManager,_user)) {
uint roles = db.getRolesRights(_user);
db.setRoles(_user, roles - uint(2) ** uint(RoleManagement.Role.AssetManager));
}
}
/// @notice removes the traderRole from a user
/// @param _user user
function removeTraderRole(address _user)
external
userExists(_user)
onlyRole(RoleManagement.Role.AgreementAdmin)
{
if (isRole(RoleManagement.Role.Trader,_user)) {
uint roles = db.getRolesRights(_user);
db.setRoles(_user, roles - uint(2) ** uint(RoleManagement.Role.Trader));
}
}
/// @notice function set change the name of an organization
/// @param _user ethereum-address of an user / organization
function setOrganization(address _user, bytes32 _organization)
external
onlyRole(RoleManagement.Role.UserAdmin)
{
require(_organization != 0x0);
db.setOrganization(_user,_organization);
}
/// @notice function to set a new address for an existing organization
/// @param _user ethereum-address of the organization
/// @param _street new streetname
/// @param _number new number
/// @param _zip new zip-code
/// @param _city new city
/// @param _country new country
/// @param _state new state
function setOrganizationAddress(
address _user,
bytes32 _street,
bytes32 _number,
bytes32 _zip,
bytes32 _city,
bytes32 _country,
bytes32 _state
)
external
onlyRole(RoleManagement.Role.UserAdmin)
{
require(_city != 0x0 && _street != 0x0 && _number > 0 && _zip != 0x0 && _country != 0x0);
db.setAddress(_user, _street, _number, _zip, _city, _country, _state);
}
/// @notice funciton that can be called to create a new user in the storage-contract, only executable for user-admins!
/// @notice if the user does not exists yet it will be creates, otherwise the older userdata will be overwritten
/// @param _user address of the user
/// @param _firstName first name of the user
/// @param _surname surname of the user
/// @param _organization organization the user is representing
/// @param _street streetname
/// @param _number housenumber
/// @param _zip zip-code
/// @param _city city-name
/// @param _country country-name
/// @param _state state
function setUser(
address _user,
bytes32 _firstName,
bytes32 _surname,
bytes32 _organization,
bytes32 _street,
bytes32 _number,
bytes32 _zip,
bytes32 _city,
bytes32 _country,
bytes32 _state
)
external
onlyRole(RoleManagement.Role.UserAdmin)
isInitialized
{
require(
_user != address(0x0)
&& _firstName != 0x0 && _surname != 0x0
&& _organization != 0x0
&& _city != 0x0 && _street != 0x0 && _number > 0 && _zip != 0x0 && _country != 0x0
);
db.setUser( _user, _firstName, _surname, _organization, _street, _number, _zip, _city, _country, _state);
}
/// @notice function to change the name of an user
/// @param _user ethereum-account of that user
/// @param _firstName new first name
/// @param _surname new surname
function setUserName(
address _user,
bytes32 _firstName,
bytes32 _surname
)
external
onlyRole(RoleManagement.Role.UserAdmin)
{
require(_firstName != 0x0 && _surname != 0x0);
db.setUserName(_user, _firstName, _surname);
}
/// @notice function to set / edit the rights of an user / account, only executable for Top-Admins!
/// @param _user user that rights will change
/// @param _rights rights encoded as bitmask
function setRoles(address _user, uint _rights)
external
onlyRole(RoleManagement.Role.UserAdmin)
isInitialized
userExists(_user)
{
db.setRoles(_user, _rights);
}
/// @notice function to update the logic of a smart contract
/// @param _newLogic contract-address of the new smart contract, replacing the currently active one
function update(address _newLogic)
external
onlyAccount(address(cooContract))
isInitialized
{
db.changeOwner(_newLogic);
}
/// @notice function that checks if there is an user for the provided ethereum-address
/// @param _user ethereum-address of that user
/// @return bool if the user exists
function doesUserExist(address _user)
external
view
returns (bool)
{
return db.doesUserExist(_user);
}
/// @notice function to return all the data of an user
/// @param _user user
/// @return returns firstName, surname, organization, street, number, zip, city, country, state, roles and the active-flag
function getFullUser(address _user)
external
view
returns (
bytes32 firstName,
bytes32 surname,
bytes32 organization,
bytes32 street,
bytes32 number,
bytes32 zip,
bytes32 city,
bytes32 country,
bytes32 state,
uint roles,
bool active
)
{
return db.getFullUser(_user);
}
/// @notice function to retrieve the rights of an user
/// @dev if the user does not exist in the mapping it will return 0x0 thus preventing them from accidently getting any rights
/// @param _user user someone wants to know its rights
/// @return bitmask with the rights of the user
function getRolesRights(address _user)
external
view
returns (uint)
{
return db.getRolesRights(_user);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment