Welcome to Hemera! Hemera is a set of DAML Modules for interfacing between the Ethereum blockchain and the DAML Ledger. It also includes a reference application which drives the DAML Templates. The App is implemented in Java using DAML's Java bindings for interaction with the DAML Ledger, web3j for driving Ethereum's JSON-RPC API and ethereumj for compiling solidity on the fly. Communication with the Ethereum Network happens via an INFURA endpoint but the implementation is agnostic to the Ethereum node as all transaction signing happens locally.
The DAML Ethereum Library assumes a single operator party and multiple user parties. Users send requests to the operator in order to perform certain actions on the Ethereum network and get the results in the form of contract responses. The library is organized in a set of modules with distinct functionality. More specifically:
The Onboarding module is used for bootstrapping the DAML Ledger. The party which assumes the operator role creates an instance of the Operator
template and invites users by exercising the Operator_InviteUser
choice. The UserInvitation
contract is accepted by the user party through the UserInvitation_Accept
choice and the User
role contract is created. The user can now start sending requests to the operator. The operator can also offboard a user by exercising the User_Revoke
choice on the User
contract.
This module enables the user to request the creation and deployment of an Ethereum smart contract. The user creates a NewSmartContractRequest
by exercising the User_NewSmartContract
choice on their role contract. The user populates the request with the address from which the contract will be deployed, its name and the solidity source code or the hex formatted bytecode of the contract. Optionally the user can pass in constructor arguments, any initial value that the contract will hold as well as values for gas limit and gas price.
A successful request is accepted by the operator via the NewSmartContractRequest_Accept
choice and an UnsignedNewContractTransaction
is created which among others contains the raw unsigned transaction payload.
The user signs the payload locally and passes it as an argument to the UnsignedNewContractTransaction_Sign
choice creating a SignedNewContractTransaction
.
Finally the user requests deployment of the smart contract by exercising the SignedNewContractTransaction_Deploy
choice. The operator responds to the request by attempting to transmit the transaction to the Ethereum Network. If transmission was successful, the operator includes the transaction hash along with the broadcast time and Ethereum node client version.
The Call module is used to query deployed contracts for their state by calling functions that are constant and their "stateMutability"
property is set to "view"
. Such function calls do not alter the state, therefore they require no gas or transaction signing. The user creates a CallRequest
by exercising the User_Call
choice on their role contract and passes in the contract address, function name, any arguments and any function return types. Optionally they can include a caller address.
The operator responds to the request with a CallResponse
that contains the original data along with the function output and the broadcast details
For function calls that alter the state of the deployed contracts the Transaction module is used. Similar to the Call module, the user creates a TransactionRequest
specifying the contract address, the name of the function, the arguments and return types. Since the transaction will consume gas, the user specifies the caller address and optionally values for the gas limit and desired gas price. The user can also include ether to the request by using the optional optValue
field.
A successful request is converted to an UnsignedTransaction
by the operator and the raw unsigned transaction payload is populated for the user to sign. The user signs the transaction locally and exercises the UnsignedTransaction_Sign
choice creating a SignedTransaction
that is ready to be broadcasted. Finally the user requests transmission of the signed transaction by exercising the SignedTransaction_Send
choice. The operator attempts to transmit the signed payload and responds with transmission details and the transaction hash.
If the user wants to send ether to an address they use the Transfer module. The mechanics are similar to the Transaction module with the difference that the TransferRequest
only contains the from and to addresses as well as the value that will be sent. The user may also choose to use their custom gas limit and gas price values if they don't want to rely on the defaults.
The operator returns an UnsignedTransferTransaction
that the user has to locally sign and convert to a SignedTransferTransaction
which they can then broadcast to the Ethereum Network.
This module contains a user role contract for interacting with any ERC-20 compliant contract on the Ethereum Network. The choices of the ERC20Contract
template correspond to the functions of the ERC-20 interface. Exercising them creates fully populated CallRequest
s or TransactionRequest
s to the operator that follow the aforementioned flow.
This is a helper module specifying the various Ether units, the solidity ABI types and functions for converting as well as validating them.
To run Hemera, the DAML SDK must be installed on your system. Click here for the official installation instructions. The java app is a Maven project. You will also need to have that installed in order to download all dependencies and execute the various targets.
git clone git@github.com:liakakos/hemera.git
cd hemera
Although the app is agnostic to the type of Ethereum Node it connects to, you can use an INFURA endpoint to get up and running smoothly. To obtain your own endpoint, you can sign up at this link. Once you have the endpoint which should be of the form mainnet.infura.io/v3/[SomeHexProjectID]
(or ropsten.infura.io/v3/[SomeHexProjectID]
if you want to play with fake ether) you can paste it inside of the <infuraEndpoint></infuraEndpoint>
tag under the project properties in the pom.xml
file.
For the DAML sandbox to run you first need to compile the DAML Ethereum Library to a dar. To do this run
daml build -o target/daml/hemera.dar
from the parent hemera directory. After the dar is built, run the sandbox by issuing
daml sandbox target/daml/hemera.dar
In order to serve the requests from the users, you must run the operator java target. To do this open a new terminal and navigate to the parent hemera directory. You must first compile the java code:
mvn compile
This will generate the required java wrappers of the templates present in the DAML Ethereum Library and compile the project. Make sure that you have already created the dar file since the java codegen depends on it.
Before you run the operator target make sure that you have set the required properties in your pom.xml
project file:
<ledgerHost>localhost</ledgerHost>
<ledgerPort>6865</ledgerPort>
<operatorParty>Alice</operatorParty>
where ledgerHost
and ledgerPort
is the host and port where the DAML Sandbox is running and operatorParty
is the name of the operator DAML Party.
Start the Operator App by running:
mvn exec:java@run-operator
Time to launch the UI where you can create requests and view the results. For this you can use the Navigator which ships with the DAML SDK. On yet another tab, navigate to the parent hemera directory and run:
daml navigator server
You are now ready to create the Operator role contract invite users and start sending requests
The library is implemented in a way where the operator party has zero knowledge of the user's private keys. Unsigned requests need to be signed by the party who created the request using the private key that corresponds to the sender's address. Since manual transaction signing can be tedious, the java app comes with a separate client target that facilitates transaction signing. The client target is limited to a single private key per app instance. It will attempt to sign any unsigned request originating from the user on whose behalf it is running. Before executing the client target make sure you populate the clientParty
and privateKey
properties in your pom.xml
file. Start the Client App by running:
mvn exec:java@run-client
Note that the privateKey string must not contain any 0x prefix
As the License states I assume no liability for any damages or losses arising from the use of this Work. Please proceed at your own risk!