HD Wallet Usage
The HD wallet allows for submitting anonymous transactions, masking your identity and managing accounts. You can leverage an endless key tree for account management, identity masking and anonymizing transactions.
Deploying via the Console
- From within an existing environment dashboard, expand the Key Management section and click Managed Wallets from the left-hand navigation menu.
- Click Create New.
On the runtime configuration screen:
- Select a membership to bind the service runtime to.
- Optionally create a name for the wallet service, e.g.
MyHDWalletService
. - Select a cloud and deployment region.
- Click NEXT.
- Kaleido provides functionality for two managed wallet types, both HD Wallets and standard Kaleido Wallets. We'll be creating an HD Wallet, which provides convenient functionality for one time key usage and subsequent anonymity on transaction signing. HD Wallets are also useful constructs for managing accounts on behalf of end users via 1:1 mapping of individual users to a specific account index. Select HD Wallets and click Finish.
- Once finished provisioning, you'll now have the ability to create a HD Wallet from the runtime you just created. Click Create HD Wallet to continue.
- You will see a pop-up confirming your choice to create a new HD Wallet, click Create.
- Upon creation of the HD Wallet, you'll be prompted to store the Kaleido-generated ID and 12 word seed phrase. The seed phrase (i.e. the "menomic") allows for deterministic derivation of every key pair in the wallet.
Using HD Wallets
Once created, your HD Wallet will contain > 2.1 billion unique Ethereum addresses along with their associated private signing key. This allows you to easily mask your identity on a per-transaction basis through single-time key usage, or to use the available accounts for end user account management.
- Within the dashboard of your HD Wallet service, select a wallet by clicking on its unique wallet ID.
- A modal will be exposed allowing you to retrieve the address and private key for any account in the wallet. In this example, the fifth account has been fetched, and the private key is available for signing via a web3 library or thru the REST API Gateway.
Via the API
NOTE: The following deployment approach assumes a strong understanding of the Kaleido APIs. Please refer to the Kaleido Resource Model for object relationships, the API 101 topic for sample CRUD operations and api.kaleido.io for detailed descriptions of the various endpoints and routes.
The HD Wallet is provisioned against the /services
API endpoint and exists as an environment-specific member resource. The orchestration is identical to nodes and application credentials, where the object is directly bound to one of the consortium’s membership IDs. To create the service, specify the consortia and environment IDs in the path and POST
to the /services
endpoint with a name, the service type and membership ID in the body of the call. This sample assumes that the following environment variables have been set as follows:
export APIURL="https://console.kaleido.io/api/v1"
export APIKEY="YOUR_API_KEY"
export HDR_AUTH="Authorization: Bearer $APIKEY"
export HDR_CT="Content-Type: application/json"
If you are targeting an environment outside of the US, make sure to modify your URL accordingly. The <code
export APIURL="https://console-eu.kaleido.io/api/v1"
export APIURL="https://console-ap.kaleido.io/api/v1"
export APIURL="https://console-ko.kaleido.io/api/v1"
Use the POST
method to provision the service and optionally format the output using <code
# replace the membership_ID placeholder with one of your membership IDs
curl -X POST -H "$HDR_AUTH" -H "$HDR_CT" "$APIURL/consortia/{consortia_id}/environments/{environment_id}/services" -d '{"name":"ExampleHDwallet", "service":"hdwallet", "membership_id":"{membership_id}"}' | jq
This will return you the 10 character HD wallet service ID. For example:
{
"name": "ExampleHDwallet",
"service": "hdwallet",
"membership_id": "u0amsb3epp",
"service_guid": "1878bcdf-a5b5-45a9-b279-5f8bb38d36da",
"service_type": "member",
"details": {},
"zone_id": "u0iqva64fj",
"state": "provisioning",
"_id": "u0cyjmmgwt",
"_revision": "0",
"created_at": "2019-04-10T14:42:30.362Z",
"environment_id": "u0n9z64z07"
}
Query the Service ID and Retrieve the URL
curl -X GET -H $HDR_AUTH -H "$HDR_CT" "$APIURL/consortia/{consortia_id}/environments/{environment_id}/services/{service_id}" | jq
This will return you the HD Wallet details, including the targetable URL for account/key retrieval and transaction signing. For example:
{
"_id": "u0cyjmmgwt",
"name": "ExampleHDwallet",
"service": "hdwallet",
"membership_id": "u0amsb3epp",
"service_guid": "1878bcdf-a5b5-45a9-b279-5f8bb38d36da",
"service_type": "member",
"details": {},
"zone_id": "u0iqva64fj",
"state": "started",
"_revision": "1",
"created_at": "2019-04-10T14:42:30.362Z",
"environment_id": "u0n9z64z07",
"urls": {
"http": "https://u0n9z64z07-u0cyjmmgwt-hdwallet.us0-aws.kaleido.io"
},
"updated_at": "2019-04-10T14:42:40.431Z"
}
The URL of interest is "https://u0n9z64z07-u0cyjmmgwt-hdwallet.us0-aws.kaleido.io"
.
As with all Kaleido REST API calls, /api/v1
must be appended to the endpoint and application credentials must be supplied inline or as a base64 encoded object in the header auth. Therefore, using the above URL as a reference, the targetable endpoint would be as follows:
https://{username}:{password}@u0n9z64z07-u0cyjmmgwt-hdwallet.us0-aws.kaleido.io/api/v1
Deploying via the API
Similar to node connections, the HD Wallet ingress is secured via application credentials. Generate a
set of credentials against the same membership ID used to provision the wallet and construct your
fully qualified HD Wallet URL with the following syntax – https://{username}:{password}@{wallet_url}/api/v1
.
Using the fully qualified HD Wallet URL, send a POST
to the /wallets
endpoint to generate the wallet ID and seed phrase. An example call using the HD Wallet Service URL from the previous page might resemble
the following:
curl -X POST -H "$HDR_CT" https://{username}:{password}@u0n9z64z07-u0cyjmmgwt-hdwallet.us0-aws.kaleido.io/api/v1/wallets | jq
Alternatively, you can use one of the readily available API tools such as Postman to send your REST calls.
A successful wallet creation will return the wallet ID and 12 word mnemonic serving as the root seed for the wallet. For example:
{
"id": "no0008g9",
"secret": "image antique paper bonus vehicle menu budget wild tilt pitch equal lift"
}
The mnemonic should be stored safely in the same manner as you would secure a private key. This phrase is the root seed for the wallet and the only way it can be restored. The id
field is the specific path to the wallet and is used on the HTTP calls to target accounts and retrieve signing keys.
Retrieve an account and its private signing key
Once the wallet has been successfully initialized, you can enumerate an account index to retrieve an Ethereum address and its corresponding private key. This allows for the client side application to locally sign an Ethereum transaction object prior to submission. To retrieve an account and key, follow the same baseline URL:
https://{username}:{password}@{wallet_url}/api/v1
And then append /wallets/{wallet_id}/accounts/{index}
to the path. For example, using our previously created HD Wallet instance, a call to retrieve the initial account would resemble the following:
curl -X GET -H "$HDR_CT" https://{username}:{password}@u0n9z64z07-u0cyjmmgwt-hdwallet.us0-aws.kaleido.io/api/v1/wallets/no0008g9/accounts/0 | jq
This will return an Ethereum account address and its associated secp256k1 private signing key. For example:
{
"address": "0xA9337C15af4Fa03D0411fd4d1dFc7dA753A87D89",
"privateKey": "e4bffefd3dd3f9fbec0f264d6326e7cc139ac34531ededf950c5dd114ea327f6"
}
Specify an account and sign a transaction
Additionally, you can use the HD Wallet service as a signing utility by specifying an account and passing an unsigned Ethereum transaction object in the body of the call. To sign a transaction, follow the same base URL and append /wallets/{wallet_id}/accounts/{account_number}/sign
to the path. The body of the call is the standard Ethereum transaction object, with hex-encoded values for all fields except for chainID
. If desired, nonce
, gasPrice
and gasLimit
can be expressed as plaintext integers; this is up to the developer. The transaction body might resemble the following:
{
nonce: '0x1',
gasPrice: '0',
gasLimit: '10000',
to: '0xd0a6E6C54DbC68Db5db3A091B171A77407Ff7ccf',
value: '0x00',
data: '0x1',
// chainId of the Kaleido environment, displayed in the environment view in the Kaleido console UI
chainId: 1213888410
}
For example, using the wallet ID returned above, the first account in the wallet, a hex-encoded nonce of “0”, a hex-encoded data field of “1”, and a gasLimit
of 10000:
curl -X POST -H "$HDR_CT" https://{username}:{password}@u0n9z64z07-u0cyjmmgwt-hdwallet.us0-aws.kaleido.io/api/v1/wallets/no0008g9/accounts/0/sign -d '{"nonce":"0x00", "gasPrice":"0", "gasLimit":"10000", "to":"0xd0a6E6C54DbC68Db5db3A091B171A77407Ff7ccf", "value":"0x00", "data":"0x1", "chainID":"1213888410"}'
This will return the transaction signed with the private key of account 0. For example:
0xf84b02808227108080011ca0a4b459168b0d9ddf74a5723e4b6ad9d5ba6d62e5b8a72edc7222694730dc6943a03afe606962f0fe16565a8029f2a7f6c6a3adcc222ae7fe0d885942c310d3b1d6`
This is the hex string that an application would submit to the network via one of the Ethereum-compatible APIs. For example, using the sendSignedTransaction
method via the well known Web3.js library:
web3.eth.sendSignedTransaction('0xf84b02808227108080011ca0a4b459168b0d9ddf74a5723e4b6ad9d5ba6d62e5b8a72edc7222694730dc6943a03afe606962f0fe16565a8029f2a7f6c6a3adcc222ae7fe0d885942c310d3b1d6')
.on('receipt', console.log);
Transaction Management and Account Iteration
Hex-encoding, nonce management and gasLimit
values are the responsibilities of the wallet user. Once you are comfortable with your transaction modeling, you can sequentially iterate through the wallet accounts and obtain a different signing key for every transaction entering the network. This will effectively anonymize your identity for any transaction that is appended to the chain.
If complete anonymity is your desired result, then you should never use a signing key more than once. The wallet is capable of generating an infinite number of accounts and signing keys, so per-transaction incrementation is the recommended best practice.
Using with the REST API Gateway
Use the kld-from
parameter against the REST API Gateway to specify your HD Wallet service ID, wallet ID and account index for transaction signing. The full syntax is as follows:
The Wallet ID is a required string because you have the option to deploy multiple wallets within a single service instance, and the index enumerates the specific Ethereum account you wish to sign the transaction with. Kaleido will handle the internal API calls to retrieve the corresponding private key, and then sign, assemble and deliver the raw transaction payload to your node.
Use the Kaleido Address Book to identify the service ID for your HD Wallet runtime:
The specific wallet IDs are displayed on your HD Wallet runtime page:
Therefore, if we wanted to sign the transaction with the first account in the wallet (index 0), we would pass the following argument to kld-from
with the runtime ID u0aer3ckn5
and wallet ID kiiwoz64
.
Inside of your REST API Gateway Swagger interface, the header would look as such: