This repository is used to deploy all the contracts for the Origin project of the Energy Web Foundation.
npm install
- Install the dependencies
Method 1
npm run start-ganache
- Starts a local blockchain instance- (new terminal window)
npm run origin-backend
- Starts a local backend instance - (new terminal window)
npm start
- Deploys the contracts and the configuration in config/demo-config.json
Method 2
npm run start-all
- Starts all script from Method 1 using concurrently
This will deploy all the contracts to a local Ganache instance and a local test backend.
After they have been deployed, you can use the EW Origin UI to interact with the contracts through a user-friendly interface.
This repo is for demonstration purposes and to show how the certificate of origin can work. This repo will:
- deploy and setup all required smart contracts with the provided private key
- onboard users and devices
- set meterreading of devices
- trade certificates through transferring ownership and/or buying through ERC20 test tokens
- split certificates
- create demands, supplies and agreements
Currently the repo will not start the ui. You still have to do this by yourself.
After you clone this repo you have to run the command npm install
. It will install all the required dependencies.
When the command is finished you have to start a blockchain:
- ganache / testrpc: to run this testchain simply run the command
npm run start-ganache
- your own blockchain client connected to any ethereum-like chain (e.g. Tobalaba)
This demo is using raw-transactions, so you don't have to unlock your accounts in the blockchain-client. Because this demo was developed with Tobalaba in mind the current gasPrice is set to 0 thus enabling sending transaction from accounts without any balance.
Currently the demo is configured to use the port 8545
. In case you're using your own client please make sure that the client is listening to that port.
Apart from starting a blockchain you must also start a test backend server using the command npm run origin-backend
. This is because, with release B some of the non-vital data is stored off chain on a server. Hence the deployment of test backend is necessary for demo purposes.
We strongly recommend to change the keys included in this repo when running on a public chain (see configuration)
The configuration and flow of actions is done "by default" with the file demo-config.json in the config-folder.
NOTE: you could also pass a customized demo file into the marketDemo()
function in the test script(/src/test.ts
)
The following keys are required:
- flow: an array with flow actions. They will get executed in the ordering within the config-file
Every flowaction has two entries:
type
: the action typedata
: the corresponding data for the action type
Currently the following action types are supported:
- APPROVE_CERTIFICATION_REQUEST
- CREATE_ACCOUNT
- CREATE_PRODUCING_DEVICE
- SAVE_SMARTMETER_READ_PRODUCING
- SEND_ERC20_TOKENS_TO
- TRANSFER_CERTIFICATE
- SPLIT_CERTIFICATE
- PUBLISH_CERTIFICATE_FOR_SALE
- PUBLISH_CERTIFICATE_FOR_SALE_OFFCHAIN
- REQUEST_CERTIFICATES
- UNPUBLISH_CERTIFICATE_FROM_SALE
- BUY_CERTIFICATE
- BUY_CERTIFICATE_BULK
- CREATE_DEMAND
usage: command to approve certification requests, it creates certificates
params:
certificationRequestIndex
: index of certification request to be approvedissuer
: address of issuerissuerPK
: private key of issuer
{
"type": "APPROVE_CERTIFICATION_REQUEST",
"data": {
"certificationRequestIndex": 0,
"issuer": "0xcea1c413a570654fa85e78f7c17b755563fec5a5",
"issuerPK": "0x5c0b28bff67916a879953c50b25c73827ae0b777a2ad13abba2e4b67f843294e"
}
}
usage: command to onboard a new user
params:
firstName
: the first name of a usersurname
: the surname of a useremail
: the email of a userorganization
: the organization of a userstreet
the streetname of the organizationnumber
the housenumber of the organizationzip
the zipcode of the organizationcity
the city of the organization,country
the country of the organizationstate
the state of the organizationaddress
the ethereum address of the userprivateKey
the corresponding private key of anrights
the bitmask with rights
Onboard the user John Doe
working for the UserAdmin Organization
which is located in Main Street 1, 01234 Anytown, anstate, USA
{
"type": "CREATE_ACCOUNT",
"data": {
"firstName": "John",
"surname": "Doe",
"email": "[email protected]",
"organization": "UserAdmin Organization",
"street": "Main Street",
"number": "1",
"zip": "01234",
"city": "Anytown",
"country": "USA",
"state": " anystate",
"address": "0x71c31ff1faa17b1cb5189fd845e0cca650d215d3",
"privateKey:" "0xbfb423a193614c6712efd02951289192c20d70b3fc8a8b7cdee7360ead486",
"rights": 1
}
}
usage: command to onboard a new producing device
params:
smartMeter
: ethereum address of the smart metersmartMeterPK
: private key of the ethereum address (needed to simuate meterreading)owner
: ethereum address of the owner of the device, has to have to device manager rightsoperationalSince
: UNIX-timestamp when the device entered servicecapacityInW
: capacity of the devicelastSmartMeterReadWh
: last meterreading in Whstatus
: device status (Submitted, Denied, Active)lastSmartMeterReadFileHash
: last filehashcountry
: the country where the device is locatedaddress
: the address where the device is locatedregion
: the region where the device is locatedprovince
: the province where the device is locatedgpsLatitude
: latitude of the device as stringgpsLongitude
: longitude of the device as stringtimezone
: timezone of the device as stringdeviceType
: Type of device as string, eg. "Solar;Photovoltaic;Roof mounted"otherGreenAttributes
: green attributes as stringtypeOfPublicSupport
: type of public support as string
Onboard a new energy producing device for the owner 0x33496f621350cea01b18ea5b5c43c6c233c3f72d (John Doe Four of the DeviceManager Organization)
. The device has a smart meter connected with the ethereum account 0x1112ec367b20d2bffd40ee11523c3d36d61adf1b
. We're also passing the private key 50764e302e4ed8ce624003deca642c03ce06934fe77585175c5576723f084d4c
of that smart meter because we want to log new data within the demonstration.
The device has a capacity of 10000
Wh and went into producition on 01/01/2018 (1514764800)
. It's some kind of BiomassGas-powerplant and is compliant to TIGR. In addition, it has the green Attributes of N.A.
and also the N.A.
type of public support. Because we're freshly deploying that device, it does not have a meterreading thus no need for a filehash.
The device is located in Main Street 11, 01234 Anytown, AnyState, USA
. If you're passing the some GPS coordinates, you will see the location of the device within the webapplication in the consuming device detail view. Also the certificate once created can only change owners upto 3 times
{
type": "CREATE_PRODUCING_DEVICE",
data": {
"smartMeter": "0x00f4af465162c05843ea38d203d37f7aad2e2c17",
"smartMeterPK": "09f08bc14bfdaf427fdd0eb676db21a86fa908a25870158345e4f847b5ada35e",
"owner": "0x33496f621350cea01b18ea5b5c43c6c233c3f72d",
"operationalSince": 1514764800,
"capacityInW": 10000,
"lastSmartMeterReadWh": 0,
"active": true,
"lastSmartMeterReadFileHash": "",
"country": "USA",
"region": "AnyState",
"zip": "01234",
"city": "Anytown",
"street": "Main Street",
"houseNumber": "10",
"gpsLatitude": "0",
"gpsLongitude": "0",
"timezone": "America/Los_Angeles",
"deviceType": "Biomass from agriculture",
"cO2UsedForCertificate": 0,
"otherGreenAttributes": "N.A.",
"typeOfPublicSupport": "N.A"
}
}
usage: command store a new meterreading of an producing device
params:
deviceId
: the deviceID for the meterreadingsmartMeter
: the smartMeter address associated with the devicesmartMeterPK
: the smartMeter private key associated with the devicemeterreading
: the amount of energy to be logged (counter)filehash
: the filehash
We want to log a new meterreading for the producing device with id 0
. The transaction to do so must be signed with smartMeter's privatekey associated with the device. The new meterreading will be 100000
Wh with the filehash newMeterRead
.
Keep in mind that the meterrading is not doing any addition, so the meterreading you pass here will be the new reading of the device.
{
"type": "SAVE_SMARTMETER_READ_PRODUCING",
"data": {
"deviceId": 0,
"smartMeter": "0x00f4af465162c05843ea38d203d37f7aad2e2c17",
"smartMeterPK": "09f08bc14bfdaf427fdd0eb676db21a86fa908a25870158345e4f847b5ada35e",
"meterreading": 100000,
"filehash": "newMeterRead",
}
}
usage: send some ERC20 tokens to an address
params:
address
: address to which ERC20 tokens should be sentamount
: amount of ERC20 tokens
{
"type": "SEND_ERC20_TOKENS_TO",
"data": {
"address": "0x7672fa3f8c04abbcbad14d896aad8bedece72d2b",
"amount": 500
}
}
usage: command to transfer the ownership of a certificate
params:
certId
: id of the certificate to be transferreddeviceOwner
: address of the current owner of the certificate(must have trading rights)deviceOwnerPK
: private key of the current owner of the certificateaddressTo
: address of the trader account to whom the certificate is to be transferred(must having trading rights)
We want to transfer the certificate with id 0
. The transaction to do so must be signed by the deviceOwner proving the current ownership of the certificate. Therefore the device owner's address and private key are required. The certificate's ownership will be transferred to 0x4095f1db44884764C17c7A9A31B4Bf20f5779691
{
"type": "TRANSFER_CERTIFICATE",
"data": {
"certId": 0,
"deviceOwner": "0x33496f621350cea01b18ea5b5c43c6c233c3f72d",
"deviceOwnerPK": "0x96ce644659ea5572aedc29296c866a62c36c6cdcafc8801c1c46d02abc8c0047",
"addressTo": "0x4095f1db44884764C17c7A9A31B4Bf20f5779691"
}
}
usage: command to split the certificate into two certificates carrying varying Wh readings
params:
certId
: id of the certificate to be transferreddeviceOwner
: address of the current owner of the certificate(must have trading rights)deviceOwnerPK
: private key of the current owner of the certificatesplitValue
: splitting of the certificate with respect to Wh readings(need not be 50% of the parent certificate)
We want to split the certificate with id 1
. The transaction to do so must be signed by the deviceOwner proving the current ownership of the certificate. Therefore the device owner's address and private key are required. The certificate will be broken into two, one containing 15000 Wh
worth readings and other containing the remaining Wh
of the parent certificate.
{
"type": "SPLIT_CERTIFICATE",
"data": {
"certId":1,
"deviceOwner": "0x33496f621350cea01b18ea5b5c43c6c233c3f72d",
"deviceOwnerPK": "0x96ce644659ea5572aedc29296c866a62c36c6cdcafc8801c1c46d02abc8c0047",
"splitValue": 15000
}
}
usage: command to publish a certificate for sale using ERC-20 tokens
params:
certId
: id of the certificate to be transferredcertificateOwner
: address of the current owner of the certificate(must have trading rights)certificateOwnerPK
: private key of the current owner of the certificateprice
: price of the certificate in unit of the ERC20 test token
{
"type": "PUBLISH_CERTIFICATE_FOR_SALE",
"data": {
"certId": 4,
"price": 1000,
"certificateOwner": "0x33496f621350cea01b18ea5b5c43c6c233c3f72d",
"certificateOwnerPK": "0x96ce644659ea5572aedc29296c866a62c36c6cdcafc8801c1c46d02abc8c0047"
}
}
usage: command to publish a certificate for sale using off chain settlement in fiat currencies (EUR, USD)
params:
certId
: id of the certificate to be transferredprice
: price of the certificate in unit of the ERC20 test tokencertificateOwner
: address of the current owner of the certificate(must have trading rights)certificateOwnerPK
: private key of the current owner of the certificatecurrency
: currency that will be used to do perform the settlement. The list of currencies can be found here
{
"type": "PUBLISH_CERTIFICATE_FOR_SALE_OFFCHAIN",
"data": {
"certId": 4,
"price": 1000,
"certificateOwner": "0x33496f621350cea01b18ea5b5c43c6c233c3f72d",
"certificateOwnerPK": "0x96ce644659ea5572aedc29296c866a62c36c6cdcafc8801c1c46d02abc8c0047",
"currency": "USD"
}
}
usage: command to request certificates for smart meter reads, to get certificate this request has to be later approved, for example using: APPROVE_CERTIFICATION_REQUEST action
params:
deviceId
: id of the devicelastRequestedSMRead
: index of last smart meter read to be included in certification requestdeviceOwner
: address of device ownerdeviceOwnerPK
: private key of the device owner
{
"type": "REQUEST_CERTIFICATES",
"data": {
"deviceId": 0,
"lastRequestedSMRead": 2,
"deviceOwner": "0x33496f621350cea01b18ea5b5c43c6c233c3f72d",
"deviceOwnerPK": "0x96ce644659ea5572aedc29296c866a62c36c6cdcafc8801c1c46d02abc8c0047"
}
}
usage: command to unbpublish (remove) a certificate from sale
params:
certId
: id of the certificate to be transferredcertificateOwner
: address of the current owner of the certificate(must have trading rights)certificateOwnerPK
: private key of the current owner of the certificate
{
"type": "UNPUBLISH_CERTIFICATE_FOR_SALE_OFFCHAIN",
"data": {
"certId": 4,
"certificateOwner": "0x33496f621350cea01b18ea5b5c43c6c233c3f72d",
"certificateOwnerPK": "0x96ce644659ea5572aedc29296c866a62c36c6cdcafc8801c1c46d02abc8c0047"
}
}
usage: command to transfer the ownership of a certificate
params:
certId
: id of the certificate to be transferredprice
: price of the certificate in unit of the ERC20 test tokenbuyer
: address of the trader who wants to buy the certificatebuyerPK
: private key of the trader who wants to buy the certificateaddressTo
: address of the trader account to whom the certificate is to be transferred(must having trading rights)
We want to buy the certificate with id 4
at the specified price of 1000
. The transaction to do so must be signed by the trader to prevent repudiation of fund transfer. Therefore the trader's address and private key are required. Before the certificate can be bought the trader must approve the device owner (0x4095f1db44884764C17c7A9A31B4Bf20f5779691
) of the funds specified as price on the certificate.
{
"type": "BUY_CERTIFICATE",
"data": {
"certId": 4,
"price": 1000,
"buyer": "0x4095f1db44884764C17c7A9A31B4Bf20f5779691",
"buyerPK": "0x9d66d342a3b6014a7cff6ff0379b192dbe193e43bb6979625c600c4996bb3b85",
"deviceOwner": "0x33496f621350cea01b18ea5b5c43c6c233c3f72d"
}
}
usage: command to buy multiple certificates
params:
certificateIds
: ids of the certificates that want to be boughtbuyer
: address of the trader who wants to buy the certificatesbuyerPK
: private key of the trader who wants to buy the certificates
We want to buy the certificates 0
, 1
and 2
.
{
"type": "BUY_CERTIFICATE_BULK",
"data": {
"certificateIds": [0, 1, 2],
"buyer": "0x7672fa3f8c04abbcbad14d896aad8bedece72d2b",
"buyerPK": "0x50397ee7580b44c966c3975f561efb7b58a54febedaa68a5dc482e52fb696ae7"
}
}
usage: command to create a demand
params:
trader
: address of the trader creating the demandtraderPK
: private key of the trader creating the demandtimeframe
: timeframe of contractmaxPricePerMwh
: maximum price per MWhcurrency
: currency of exchange as string (USD, EUR, THB, SGD)producingDevice
:country
: country where the device is locatedregion
: region where the device is locateddevicetype
: Type of device as string (Wind, Solar, RunRiverHydro, BiomassGas)otherGreenAttributes
: green attributes as stringtypeOfPublicSupport
: type of public support as stringenergyPerTimeFrame
: required energy per time frameregistryCompliance
: complaince as string (none, IREC, EEC, TIGR)
We want to report a demand with target watt-hour per period(timeframe) as 10
and price per certified watt-hour as 10
. The device type required is BiomassGas
which must comply with EEC
. It is preferred to be a hourly
contract with the currency of exchange set as USD
. Trader account 0x4095f1db44884764C17c7A9A31B4Bf20f5779691
is making the demand.
{
"type": "CREATE_DEMAND",
"data": {
"trader": "0x4095f1db44884764C17c7A9A31B4Bf20f5779691",
"traderPK": "0x9d66d342a3b6014a7cff6ff0379b192dbe193e43bb6979625c600c4996bb3b85",
"timeframe": "hourly",
"maxPricePerMwh": 10,
"currency": "USD",
"producingDevice": 0,
"country": "string",
"region": "string",
"devicetype": "Biomass from agriculture",
"otherGreenAttributes": "string",
"typeOfPublicSupport": "string",
"energyPerTimeFrame": 10,
"registryCompliance": "EEC"
}
}
usage: command to pause the flow for a certain amount of time
params:
data
: amount of ms to sleep
We want to pause the flow for 2
secondss
{"type": "SLEEP", "data": 2000}
docker-compose build
docker-compose run demo npm run start
If you would like to start a local Ganache server instance running on localhost:8545 please run this command:
docker-compose run -p 8545:8545 demo npm run start-ganache
And replace localhost
in connection-config.json
, src/config.ts
to Docker host machine IP, for example: 172.17.0.1
.
For more comprehensive Docker deployment instructions please refer to this page.