Work is well underway for our second Nervos grant: Hardware Wallet Support in CKB-CLI and Additional Ledger Features. Here's an update on the progress that has been made so far!
Milestone 1 Progress
Done: Storage of Hardware Wallet Root Public Keys in CKB-CLI
account import command can be used to store the extended root public key (
m/44'/309'/0') of a Ledger hardware wallet in CKB-CLI. Here's the full list of commands we've adjusted as part of this shift:
account import: This subcommand can be used to import the hardware wallet account.
account list: Once imported, hardware wallet accounts now appear here even when the Ledger device is not connected.
account extended-address: This subcommand is used to verify your receiving address before sharing it with someone so you are sure the address is correct. Non-default options which were required at the end of our first grant are no longer required.
account bip44-addresses: This subcommand can now be used to list hardware wallet change and receiving addresses. Currently CKB-CLI prompts the user for their passphrase during this command, but our fork does not and soon neither will CKB-CLI.
wallet get-capacity --derived: This subcommand can now be used with hardware wallets. Like
account bip44-addresses, this command will not prompt the user for their passphrase or device confirmation.
wallet transfer: While supported at the end of our first grant, this subcommand now uses the hardware wallet information stored in the client. It also knows when to use the default Ledger path
- DAO Operations: All 3 DAO operations now use hardware wallet stored in the client and will soon use the correct default path of
- Message Signing Subcommands:
sign-datasubcommands both use hardware wallet data stored in the client. See 'Message Signing' below for more details on this feature.
Done: Pass Hardware Wallets Unhashed Transaction and Context Data
Now that hardware wallet information is being stored in CKB-CLI, we are using this information to clean up UX and make it easier to securely verify operations before signing them. In particular, we are:
- Passing raw transaction data to the hardware wallet. This informs the on-device prompt and is hashed on the device before signing.
- Passing context transactions to the hardware wallet. Context transactions are the transactions that create an operation's input cells and they are necessary to properly calculate the capacity being transferred in an operation.
- Computing receiving and change addresses using the extended root public key. As a result, the user is no longer prompted to 'Provide Public Key' before doing other operations such as a transfer.
In Progress: List Multiple Connected Ledger Devices
We use ledger-rs to communicate between the rust client CKB-CLI and Ledger devices. Currently the library does not support listing multiple Ledger devices which are connected with the Nervos app open. We'll be adding support for this to the library so
account list shows all connected devices.
In Progress: Message Signing
We have completed the work described in our proposal related to message signing! Message signing operations are now prepended with a magic byte to differentiate them from other operations. You can also sign a raw string message with your Ledger device and verify the string on your hardware wallet's UI! For instance, if you enter the command
util sign-message --from-account <lock-arg> --message “Nervos message signing", the hardware wallet will ask you to 'Sign Message' and ask you to verify the exact message you entered: “Nervos message signing”.
In coordination with the Nervos' CKB-CLI team, we've decided to expand upon this and cover additional use cases, such as messages that are generated from DApps which are formatted differently. In total, we'll allow signing of three types of messages: raw strings (done), binary hex (not started), and pre-hashed data (not started). We've completed specification for these additional features and will be starting work on them soon!
The spec is as follows:
- To sign a raw string:
util sign-data --from-account <lock-arg> --string <string>
- To sign binary hex data:
util sign-data --from-account <lock-arg> --binary-hex <binary-hex>
- To sign hashed data:
util sign-message --from-account <lock-arg> --message <message>
sign-message subcommands will also accept the an
extended-address flag to sign with extended addresses, which is not yet supported upstream but will be.
sign-data will also support a
no-magic-byte flag which will tell the client to not prepend the message with the magic byte, “Nervos Message:”.
Signing hashed data, or messages that are not prepended with the magic byte, is an advanced use case we don't recommend for everyday users because the Ledger device cannot determine what it is signing. This is why we've put the effort into getting raw transaction data and context transactions sent to the hardware wallet for all common uses: it is necessary to securely display what you are signing. However, this simply isn't possible in all use cases due to the variance in data that may be produced by DApps or use cases which have not yet emerged. For that reason, we're also adding a configuration to the Ledger application to 'Sign Hash'. With this enabled, you can sign hashed data. The hash of that data will appear on the device and in the client for you to confirm. Note that this doesn't completely make signing hashed data secure! We recommend users confirm the same hash is generated in more than one client to be sure the client is not compromised and thus the hashed data is not malicious.
In Progress: Multisig Lock Script Support / Transaction Variants
We've made good progress towards supporting multisigs in our Ledger application. This is two-fold: both signing operations from a multisig address and sending funds to one since multisig addresses are formatted differently.
Supporting multisigs is part of a broader initiative to support all the transaction variants someone can reasonably expect to create. After conversations with Nervos' CKB-CLI team, we've decided it is best to support all of them as a part of Milestone 1 to our grant. This includes:
- Multisigs and Timelock addresses: Timelock addresses essentially are multisig addresses. They can be created with a 1 of 1 signing requirement.
- Transactions with inputs from different addresses: Transactions created in a JSON file can have inputs from different accounts/addresses, meaning the Ledger device user may not be signing for the entire transaction or the inputs may all be from addresses they own but must each be signed with their respective key. Both of these use cases will be supported.
- Transaction with multiple outputs: We'll allow the user to verify each output that's part of their transaction so they will be able to verify exactly how much CKB is being sent to each destination.
- Self-transfers: These are a unique case because both the destination and change address are associated with the same account which makes calculating the amount being 'transferred' tricky. This can be especially useful for miners looking to consolidate many small cells. Support for this feature was recently completed.
Supporting all of these variants increases this project's scope which will take more time than originally estimated, but fits our broad goals of being feature complete before beginning Milestone 2, providing strong security in all use cases, and making Ledger's security review and listing of our application easier.
Furthermore, we've become very familiar with constructing complex transactions using CKB-CLI and wanted to make it easier for others in the community to do so as well. For that reason, we'll be publishing a series of guides focusing on the different transaction variants we've described above. The first of which, which covers Multisigs, was just published last week!
Everything we've described above contributes to the checkpoints which are a part of Milestone 1: 1) Client Changes Complete Natively and 2) Ledger Features Complete. When they are complete, we'll present progress and produce a video demonstration for the community. At that time we'll also begin Milestone 2's checkpoints: 1) Moving Ledger-specific code in CKB-CLI to a plugin and 2) updating LedgerJS to support new features and upstream changes.
While we haven't yet begun development of the Ledger plugin, we've been actively working with the CKB-CLI team to specify how their plugin system will work with hardware wallet plugins. As a result, they have been able to add the features we'll need to the plugin system, paving the way for us to make the Ledger plugin during Milestone 2. We'd like to take this opportunity to thank them for their excellent cooperation and support!
We originally estimated this grant would take up to 8 weeks to complete with the first milestone taking the majority of that time. While we are on track to complete our original specifications within that time frame, the added message signing features and transaction variants will require additional development. As a result, Milestone 1 should be completed near the end of July and Milestone 2 in mid-August. As always, we remain committed to delivering high quality, comprehensive solutions as quickly as we can.
We'd like to thank Nervos for their grant to work on this application and the Nervos community for their enthusiasm surrounding this project!
If you have any questions or feature requests, we encourage you to email us at firstname.lastname@example.org.