Initialising Clef
First things first, Clef needs to store some data itself. Since that data might be sensitive (passwords, signing rules, accounts), Clef’s entire storage is encrypted. To support encrypting data, the first step is to initialize Clef with a random master seed, itself too encrypted with a password:Remote interactions
This tutorial will use Clef with the Parallax client on testnet. The accounts used will be in the testnet keystore with the path~/parallax/testnet/keystore
. The tutorial assumes there are two accounts in this keystore. Instructions for creating accounts can be found on the Account managament page. Note that Clef can also interact with hardware wallets, although that is not demonstrated here.
Clef should be started before the Parallax client, otherwise the client will complain that it cannot find a Clef instance to connect to. Clef should be started with the correct chainid for testnet. Clef itself does not connect to a blockchain, but the chainID parameter is included in the data that is aggregated to form a signature. Clef also needs a path to the correct keystore passed to the --keystore
command. A custom path to the config directory can also be provided. This is where the ipc file will be saved which is needed to connect Clef to the Parallax client:
Note, the number of things that can be done from the External API is deliberately small to limit the power of remote calls as much as possible! Clef has an Internal API too for the UI (User Interface) which is much richer and can support custom interfaces on top. But that’s out of scope here.
request
- confirm
- result
pattern to any interaction with the local Parallax node that touches accounts, including requests made using RPC or an attached Javascript console. To demonstrate this, the Parallax client can be started, with Clef as the signer:
Automatic rules
For most users, manually confirming every transaction is the right way to use Clef because a human-in-the-loop can review every action. However, there are cases when it makes sense to set up some rules which permit Clef to sign a transaction without prompting the user. For example, well defined rules such as:- Auto-approve transactions with
Uniswap v2
, with value between0.1
and0.5 Lax
per 24h period - Auto-approve transactions to address
0xD9C9Cd5f6779558b6e0eD4e6Acf6b1947E7fA1F3
as long asgas < 44k
andgasPrice < 80Gwei
can be encoded and interpreted by Clef’s built-in ruleset engine.
Rule files
Rules are implemented as Javascript code in js files. The ruleset engine includes the same methods as the JSON_RPC defined in the UI Protocol. The following code snippet demonstrates a rule file that approves a transaction if it satisfies the following conditions:- the recipient is
0xae967917c465db8578ca9024c205720b1a3651a9
- the value is less than 50000000000000000 wei (0.05 Lax)
- the request has arrived via ipc
RETURN VALUE | ACTION |
---|---|
”Approve” | Auto-approve request |
”Reject” | Auto-approve request |
Error | Pass decision to UI for manual approval |
Unexpected value | Pass decision to UI for manual approval |
Nothing | Pass decision to UI for manual approval |
Attestations
Clef will not just accept and run arbitrary scripts - that would create an attack vector because a malicious party could change the rule file. Instead, the user explicitly attests to a rule file, which involves injecting the file’s SHA256 hash into Clef’s secure store. The following code snippet shows how to calculate a SHA256 hash for a file namedrules.js
and pass it to Clef. Note that Clef will prompt the user to provide the master password because the Clef store has to be decrypted in order to add the attestation to it.
Account passwords
The rules described inrules.js
above require access to the accounts in the Clef keystore which are protected by user-defined passwords. The signer therefore requires access to these passwords in order to automatically unlock the keystore and sign data and transactions using the accounts.
This is done using clef setpw, passing the account address as the sole argument:
Implementing rules
Clef can be instructed to run an attested rule file simply by passing the path to rules.js to the —rules flag:0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3
has already been provided to setpw and the recipient and value comply with the rules in rules.js
):
rules.js
, are not automatically approved, but instead pass the decision back to the UI for manual approval by the user.
Summary of basic usage
To summarize, the steps required to run Clef with an automated ruleset that requires account access is as follows: 1) Define rules as Javascript and save as a.js
file, e.g. rules.js
2) Calculate hash of rule file using sha256sum rules.js
3) Attest the rules in Clef using clef attest <hash>
4) Set account passwords in Clef using clef --setpw <address>
5) Start Clef with rule file enabled using clef --keystore <path-to-keystore> --chainid <chainID> --rules rules.js
6) Make requests directly to Clef using the external API or connect to the Parallax client by passing --signer=<path to clef.ipc>
at client startup
More rules
Since rules are defined as Javascript code, rulesets of arbitrary complexity can be created and they can impose conditions on any part of a transaction, not only the recipient and value. A simple example is implementing a “whitelist” of recipients where transactions that have those accounts in the to field are automatically signed (for example perhaps transactions between a user’s own accounts might be whitelisted):approve_signData
imposing the following conditions on a transaction’s sender and message data.
- The sender must be
0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3
- The transaction message must include the text wen-merge, which is
77656E2D6D65726765
in hex.
0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3
has been provided to setpw).
wen-merge
. The plaintext clefdemotextthatincludeswen-merge
is 636c656664656d6f7465787474686174696e636c7564657377656e2d6d65726765
when represented as a hexadecimal string. This can be passed as data to an account_signData
request as follows:
wen-merge
will not automatically approve. For example, the following request passes the hexadecimal string representing the plaintext clefdemotextwithoutspecialtext:
Under the hood
The examples on this page have provided step-by-step instructions for various operations using Clef. However, they have not provided much detail as to what is happening under the hood. This section will provide some more details about how Clef organizes itself locally. Initializing Clef with a master password and providing an account password toclef setpw
and attesting a ruleset creates the following files in the directory ~/.clef/
(this path is independent of the paths provided to --keystore
and --configdir
on startup):
masterseed.json
includes a json object containing the masterseed which was used to derive the vault directory (in this case 02f90c0603f4f2f60188
). The vault is encrypted using a password which is also derived from the masterseed. Inside the vault are two subdirectories:
credentials.json
config.json
Inside credentials.json
are the confidential ksp
data (standing for “keystore pass” - these are the account passwords used to unlock the keystore).
The config.json file
contains encrypted key/value pairs for configuration data. Usually this is only the sha256
hashes of any attested rulesets.
Vault locations map uniquely to masterseeds so that multiple instances of Clef can co-exist each with their own attested rules and their own set of keystore passwords. This is useful for, for example, maintaining separate setups for Mainnet and testnets.
The contents of each of these json files can be viewed using cat and should look something like the following:
For config.json: