GitHub Logo HIP-820: Integration of Wallet Connect 2.0 Protocol for Wallets and dApps on Hedera

Author Jason Fabritz
Working Group Jason Fabritz, Milan Wiercx van Rhijn, Tyler McDonald, Ken Anderson, Tony Camero, Tyler Cote, Adrian Marin, Volodymyr Rozhnov
Discussions-To https://github.com/hashgraph/hedera-improvement-proposal/discussions/819
Status Accepted
Needs Council Approval No
Review period ends Thu, 28 Dec 2023 07:00:00 +0000
Type Standards Track
Category Application
Created 2023-10-05
Updated 2024-01-02
Requires 30
Replaces 179

Abstract

This HIP proposes a specification for wallets and dApps on the Hedera platform to connect using the Wallet Connect 2.0 protocol. It introduces standardized methods to facilitate native Hedera network operations; including signing transactions and sending transactions to the hedera network.

Motivation

With the increasing adoption of dApps on Hedera, there’s a growing need for a standardized native hedera network protocol to connect wallets and dApps. Integrating widely recognized standards like Wallet Connect 2.0 reinforces Hedera community’s commitment to interoperability, user-centric design, and forward-thinking development. Adoption would not only enhance the current user experience but would also pave the way for attracting new developers and users, fostering a more inclusive and interconnected Hedera ecosystem.

Rationale

Wallet Connect 2.0 has been successfully implemented across various blockchain platforms. Its adoption for Hedera will ensure future compatibility with a broad range of wallets and dApps, enhancing user experience and interoperability. Key considerations supporting this approach include:

Interoperability Across Platforms: Wallet Connect 2.0 has already been adopted and implemented across a multitude of blockchain platforms. Its widespread acceptance is a testament to its robustness and versatility. By integrating it into Hedera, we ensure that Hedera-based dApps and wallets can seamlessly interact with other platforms that also support Wallet Connect, fostering a more interconnected decentralized world.

User Experience: One of the primary challenges in the decentralized space is the steep learning curve and fragmented user experience. Different dApps support different wallets, and users often have to switch between multiple wallets or undergo tedious processes to interact with their desired dApps. Wallet Connect 2.0 offers a unified protocol that simplifies this interaction, providing users with a consistent and intuitive experience.

Developer Friendliness: For developers, integrating multiple wallets can be a time-consuming and complex task. By standardizing the connection protocol with Wallet Connect 2.0, developers can streamline the integration process, allowing them to focus on building innovative features and improving their dApps rather than getting bogged down with wallet compatibility issues.

Future-Proofing the Ecosystem: As the decentralized space evolves, new wallets and dApps will continue to emerge. Adopting a standardized protocol like Wallet Connect 2.0 ensures that Hedera participates in this evolution. It provides a foundation that can easily accommodate future innovations, ensuring that the Hedera ecosystem remains dynamic and adaptable.

Security and Trust: Wallet Connect 2.0 has undergone rigorous scrutiny by the broader blockchain community. Its design principles prioritize security, ensuring that users’ assets and data remain protected. By adopting a protocol that has already been vetted and trusted by the community, Hedera reinforces its commitment to user security.

User stories

  • As a dApp developer, I wish to create a native Hedera transaction that a remote user can sign and submit to the network on my behalf; returning the receipt (or error) when that action is completed. I do not need to know the brand of wallet submitting my transaction, only that it follows the known protocol I understand.
  • As a dApp developer, I wish to have a remote user sign a transaction and return it so that I can submit the transaction to the network myself on the key-owner’s behalf. I do not need to know the brand of wallet signing the transaction I created for them, only that the signer follows the known protocol I understand.
  • As a dApp developer, I need the functionality above to facilitate coordination of multiple signatures by separate parties. I do not need the protocol to orchestrate multiple party signatures, only create and return or pass thru existing signatures when required.
  • As a dApp developer, I may not have direct gRPC or Mirror Node access to the Hedera Network. In this scenario, I need to rely on the controller (wallet) to query the hedera network to retrieve live information such as account balances and other information using the native Hedera API Query Services.
  • As a dApp developer, I need to know which hedera nodes the remote client is willing to sign and/or send transactions to. There is no point in creating a transaction delivered to a Hedera node that the remote wallet is unwilling or unable to interact with.
  • As a dApp developer, I need to challenge the controller (wallet) for the purposes of authentication for an off-ledger purpose, such as authenticating on a web site. I need functionality similar to Wallet Connect’s personal_sign method for the Ethereum chain.
  • As a key-owner (account/wallet owner) I want to utilize any dApp of my choosing with any wallet or key-signing tool of my choosing to facilitate my desired interaction with the dApp or Hedera Network.
  • As a key-owner (account/wallet owner) I want to utilize any dApp of my choosing with any wallet or key-signing tool of my choosing to participate in multi-party, multi-signature transactions when and where required.
  • As a wallet or dApp developer, I wish to leverage the Wallet Connect libraries provided by Wallet Connect with the Hedera SDK or tooling of my choosing. I require that the protocol be SDK and programming language agnostic.

Specification

Portions of a specification required to implement a Wallet Connect 2.0 protocol for the Hedera Network already exist. The accepted HIP-30, CAIP Identifiers for the Hedera Network, ratifies the format for identifying hedera networks and addresses. It includes definitions for the Chain Agnostic Standards Alliance profiles 2, 10 and 19 for the Hedera Network, to summarize:

The hedera namespace will be used for CAIP blockchain identifiers. There will be 4 distinct references: mainnet, testnet, previewnet, and devnet…. hedera:devnet refers to any non-shared developer local network.

The account address is the standard account identifier format. Each of realm, shard, and account ID separated with a dash [period] (.). The format of the realm, shard, and account ID are unsigned integer in decimal representation…

The identifiers described above shall be used during the Wallet Connect 2.0 pairing session negotiation to identify the hedera ledgers and accounts that will participate in transaction signing and submission to the Hedera network.

What is not included in previous work is the definition of the Wallet Connect custom methods and events that complete the support for the use cases identified above. The following namespace methods shall be supported:

hedera_signTransaction

When a dApp requires only the signature from the controller (wallet), it can use the hedera_signTransaction method. This method accepts a base64 encoded protobuf representation of the Hedera API TransactionBody message as input. The controller decodes and interprets the contents, and if valid and approved, returns an encoded SignatureMap structure that includes one or more signatures generated by the controller.

Parameters

transactionBody – a base64 encoding of the protobuf endoded Hedera API TransactionBody message. While the controller should decode the contents for security reasons, it should sign the literal bytes provided, not a re-encoding of the TransactionBody message. This is necessary because re-encoding the message could potentially result in slightly different array of bytes.

signerAccountId – an Hedera Account identifier in HIP-30 (<nework>:<shard>.<realm>.<num>-<optional-checksum>) form. This value identifies the account (and therefore associated key set) that the dApp is requesting to sign the transaction. It is permissible to omit this value if necessary for keys not associated with an account (for example, a token supply key). The controller (wallet) may choose to reject the request based on the identifed account or omission of this property, or provide additional signatures beyond the request if the controller deems it necessary or proper.

Returns

signatureMap – a base64 encoding of the protobuf endoded Hedera API SignatureMap message. The encoded structure must include at least one signature within the property’s SignatureMap structure. It is allowed to provide more if the context warrants multiple signatures.

hedera_signAndExecuteTransaction

When a dApp needs the services of the controller to sign a transaction message and then submit it to the network, it can use the hedera_signAndExecuteTransaction method. This method accepts a base64 encoded protobuf representation of the Hedera SDK TransactionList message as input. The controller decodes the messages, interprets the contents, and if valid and approved, appends its signature(s) to the SignatureMap structure identified as the sigMap property of each SignedTransaction then repackages the messages as appropriate for transmission to the Hedera network and sends it to the network. The controller shall wait for the initial response from the Hedera node and return the resulting Node Precheck Code generated by the submission.

The controller is allowed to retry submitting the signed transaction to the Hedera Network for certain types of error conditions; such as gRPC connection droppage or Hedera BUSY signals. This specification does not obligate the controller to retry, but recommends the practice to help improve perceived user experience for consumer applications.

Parameters

transactionList – a base64 encoding of the protobuf of the Hedera SDK TransactionList message. The contained transactions must include the bodyBytes field representing the transaction, but inclusion of a sigMap is optional. If included, and if it is pre-populated with signatures, the pre-existing signatures must also be included in the signed transaction sent to the Hedera Node.

signerAccountId – an Hedera Account identifier in HIP-30 (<nework>:<shard>.<realm>.<num>-<optional-checksum>) form. This value identifies the account (and therefore associated key set) that the dApp is requesting to sign the transaction. It is permissible to omit this value if necessary for keys not associated with an account (for example, a token supply key). The controller (wallet) may choose to reject the request based on the identifed account or omission of this property, or provide additional signatures beyond the request if the controller deems it necessary or proper.

Returns

For Success (when ResponseCodeEnum is 0)

transactionId – a string encoded transaction identifier of the signed message that was sent to the Hedera node, in <shard>.<realm>.<number>@<seconds>.<nanos> format.

nodeId – a string encoded transaction identifier of the Hedera Gossip Node’s Account that the transaction was submitted to, in <shard>.<realm>.<number> format.

transactionHash– a base64 encoding of the SHA384 digest of the signedTransactionBytes of the Transaction message that was submitted to the Hedera Network.

For Submission Failure (when ResponseCodeEnum is non zero)

When the Hedera network responds with a non-zero ResponseCodeEnum, this indicates an error. This error is passed to the remote requestor using the error property of the underlying Wallet Connect JsonRpc response. The error object shall include the following properties:

code - 9000, the reserved Wallet Connect error code for unknown or errors not related to the Wallet Connect protocol.

message - A human readable string describing the nature of the failure.

data – an integer representing the ResponseCodeEnum value returned from the Hedera Node, which indicates the reason for the failure.

hedera_executeTransaction

When a dApp only requires the services of the controller to act as a relay to the Hedera network for submitting an already signed transaction, it can use the hedera_executeTransaction method. This method accepts a base64 encoded protobuf representation of the Hedera SDK TransactionList message as input. The controller decodes the message, interprets the contents, and if valid and approved, transmits the signed transaction unaltered to the Hedera network. The controller shall wait for the initial response from the Hedera node and return the resulting Node Precheck Code generated by the submission.

The controller is allowed to retry submitting the signed transaction to the Hedera Network for certain types of error conditions; such as gRPC connection droppage or Hedera BUSY signals. This specification does not obligate the controller to retry, but recommends the practice to help improve perceived user experience for consumer applications.

Parameters

transactionList – a base64 encoding of the protobuf of the Hedera SDK TransactionList message. The contained transactions must include the bodyBytes field representing the transaction, and the sigMap field containing one or more valid signatures.

Note: the CAIP-217 Scope property of the RPC call shall be used to identify which network shall be assumed when sending the transaction if multiple chainids were authorized in the pairing process. It is not necessary to transmit that value as a method parameter.

Returns

For Success (when ResponseCodeEnum is 0)

transactionId – a string encoded transaction identifier of the signed message that was sent to the Hedera node, in <shard>.<realm>.<number>@<seconds>.<nanos> format.

nodeId – a string encoded transaction identifier of the Hedera Gossip Node’s Account that the transaction was submitted to, in <shard>.<realm>.<number> format.

transactionHash– a base64 encoding of the SHA384 digest of the signedTransactionBytes of the Transaction message that was submitted to the Hedera Network.

For Submission Failure (when ResponseCodeEnum is non zero)

When the Hedera network responds with a non-zero ResponseCodeEnum, this indicates an error. This error is passed to the remote requestor using the error property of the underlying Wallet Connect JsonRpc response. The error object shall include the following properties:

code - 9000, the reserved Wallet Connect error code for unknown or errors not related to the Wallet Connect protocol.

message - A human readable string describing the nature of the failure.

data – an integer representing the ResponseCodeEnum value returned from the Hedera Node, which indicates the reason for the failure.

hedera_signAndExecuteQuery

When a dApp needs the services of the controller to perform an Hedera Network Query, it can use the hedera_signAndExecuteQuery method. This method accepts a base64 encoded protobuf representation of the Hedera API Query message as input. The controller decodes the message, interprets the contents, and if valid and approved, adds an appropriate signed transaction to the header field of the Query (if applicable), repackages the message as appropriate and sends the message to the network. The controller shall wait for the query response and returns the resulting base64 encoded protobuf Response message received from the network.

The controller is allowed to retry submitting the query to the Hedera Network for certain types of error conditions, such as gRPC connection droppage or Hedera BUSY signals. This specification does not obligate the controller to retry, but recommends the practice to help improve perceived user experience for consumer applications.

Parameters

query – a base64 encoding of the protobuf encoded Hedera API Query message. The message may or may not contain a preliminary QueryHeader value in the header field of the enclosed typed query message. It is the responsibility of the controller to complete the necessary information contained in the header field prior to submission to the network.

signerAccountId – an Hedera Account identifier in HIP-30 (<nework>:<shard>.<realm>.<num>-<optional-checksum>) form. This value identifies the account (and therefore associated key set) that the dApp is requesting to sign the query (if necessary). It is permissible to omit this value. The controller (wallet) may choose to reject the request based on the identifed account or omission of this property, or provide substitute the payer account if the controller deems it necessary or proper.

Returns

response – a base64 encoding of the protobuf encoded Hedera API Response message. The response is passed back to the caller without modification and may or may not indicate success. It is the responsibility of the dApp to decode this protobuf representation into the expected query response results.

hedera_signMessage

When a dApp needs to challenge the controller for an off-ledger authentication such as a website login, it can use the hedera_signMessage method. This method accepts a plain text string value as input. If approved by the user, the controller UTF-8 encodes this message prepended with "\x19Hedera Signed Message:\n" plus the length of the message and signs the resulting bytes in the same manner as HAPI transactions are signed. The resulting signature(s) is transmitted back to the user encoded in a SignatureMap structure. The pseudo code for computing the signature is as follows:

<Ed25519 or ECDSA Key>.sign("\x19Hedera Signed Message:\n" + len(message) + message)

It is necessary to add the prefix to the message prior to signing to prevent misuse of the method where a bad actor could request a signature from the controller that could be executable on the hedera network or other chain (in the case where the controller is a multi-chain controller).

Parameters

message – a plain text string to present to the user prior to authorizing a signature. It is recommended that this be a human readable string and contain identifying information including a timestamp and/or other transient information that can be validated by the user to help prevent replay attacks.

signerAccountId – an Hedera Account identifier in HIP-30 (<nework>:<shard>.<realm>.<num>-<optional-checksum>) form. This value identifies the account (and therefore associated key set) that the dApp is requesting to sign the message. It is permissible to omit this value. The controller (wallet) may choose to reject the request based on the identifed account or omission of this property, or provide additional signatures beyond the request if the controller deems it necessary or proper.

Returns

signatureMap – a base64 encoding of the protobuf endoded Hedera API SignatureMap message. The encoded structure must include at least one signature within the property’s SignatureMap structure. It is allowed to provide more if the context warrants multiple signatures.

hedera_getNodeAddresses

While constructing a transaction for transmission to a controller, a dApp needs to choose which Hedera Network node shall receive the transaction prior to signing (this is a requirement of the Hedera API Protocol). While a dApp can easily obtain a list of potential Hedera Nodes, a controller may not have an all-inclusive list nor a path to the node’s gRPC endpoint. The hedera_getNodeAddresses method allows a dApp to request a list of node wallet addresses known to the controller. The controller should only include nodes in this list that it is willing and able to submit transactions to at the time of the request.

Parameters

This method requires no input parameters. The CAIP-217 Scope property of the RPC call shall be used to identify which network shall be assumed when obtaining the list of known network nodes.

Returns

nodes – an array of strings formatted in the <shard>.<realm>.<num> format identifying an Hedera Address. The controller should only return known nodes that it can communicate with to submit transactions.

Backwards Compatibility

This is a new protocol specification, it does not have backwards compatibility concerns.

Security Implications

Wallet Connect 2.0 has been designed with a strong emphasis on security. Its architecture has undergone extensive peer review and has been adopted by numerous blockchain platforms. By leveraging this protocol, Hedera can ensure that the foundational communication between wallets and dApps is secure. The protocol implements end-to-end encryption between dApps and wallets. It employs a QR code-based pairing system ensuring the communication channel is established directly between the user’s wallet and the dApp. Controllers (wallets) have full control over actions such as signing and communicating with the Hedera Network.

How to Teach This

The Wallet Connect documentation is quite comprehensive and can be leveraged to document most of the steps required to implement both dApps and controllers (wallets). Additionally, it might be useful to create reference implementations in various programming languages to help bootstrap adoption of this protocol.

Reference Implementation

No reference implementation presently exists, however there are some non-conforming prototypes presently under development.

Rejected Ideas

HashConnect

Wallet Connect 2.0 has advantages over the HashConnect 1.0 protocol: It has a more robust pairing handshake, larger community support which extends across blockchain projects. Additionally, the HashPack team has announced that HashConnect 2.0 will be a re-branded Wallet Connect implementation.

HIP-179

HIP-179, External Transaction Signing for SDK and other clients, was designed before the Wallet Connect 2.0 protocol was released. It describes similar functionality, however it requires redundant method calls and data exchange that is implemented and managed by the Wallet Connect protocol itself. It is unnecessary to include this duplication in the specification. Also, at this time, there is no known open-source library supporting the handshake protocol described in HIP-179.

Explicit Batching of Transactions

Explicitly supporting batches of transactions in one method call was considered out of scope for this HIP. HIP-551 proposes the introduction of a method for atomically batching transactions as a part of the native Hedera API protocol. If passed and implemented, it is likely that this specification will be forward compatible with the HIP-551 implementation. If not, an additional HIP can be created in the future to amend this specification to add this feature to the list of native hedera methods.

hedera_signQuery

This spec will not support a method where the controller signs a query and returns it to the dApp for submission (sign query and return). This is necessary for security reasons due to the design of the protobuf Query message. It is possible to extract the paying transaction from a signed Query and execute it without submitting the outer the query envelope. While this attack vector has limited bad actor utility, it should not be included in this spec. This is different from other transactions where the transaction that is signed can not be altered by the dApp after it is signed.

Open Issues

This specification does not yet address a common set of error codes that may be produced by controllers, defining this information is supported in the CAIP namespace process. In the meanwhile, the JSON-RPC error code 9000 will be utilized for failed transaction submissions.

After approval of this HIP (or its replacement) there may be additional CAIP and/or pull requests within the Wallet Connect documentation repositories to further socialize and promote this protocol within the Wallet Connect community.

References

Copyright/license

This document is licensed under the Apache License, Version 2.0 – see LICENSE or (https://www.apache.org/licenses/LICENSE-2.0)

Citation

Please cite this document as: