HIP-1190: Improvements to the Wallet Connect implementation for dApps on Hedera
| Author | Greg Scullard |
|---|---|
| Working Group | Tyler McDonald, Jason Fabritz, Adrian Marin, Michael Garber |
| Requested By | Community Stakeholders |
| Discussions-To | https://github.com/hiero-ledger/hiero-improvement-proposals/pull/1190 |
| Status | Active ⓘ |
| Needs Hedera Review | No ⓘ |
| Needs Hiero Approval | No ⓘ |
| Last Call Period Ends ⓘ | Tue, 28 Oct 2025 07:00:00 +0000 |
| Type | Standards Track ⓘ |
| Category | Application ⓘ |
| Created | 2025-05-07 |
| Updated | 2025-11-13 |
| Replaces | 820 |
Table of Contents
Abstract
This HIP proposes changes to the specification introduced in HIP-820 for wallets and dApps on the Hedera platform to connect using the Wallet Connect 2.0 protocol.
It introduces improved methods to facilitate native Hedera network operations such that the SDK’s capabilities for handling nodes that are temporarily unavailable are used to their full extent.
Motivation
Wallet connect enables dApps to work with a number of different wallets without implementing specific integration to each wallet they wish to support.
The first implementation however sometimes enforced that a dApp submits a TransactionBody and not a full SDK Transaction, resulting in unnecessary failures to submit transactions to the network and degrading user experience.
Rationale
Hedera doesn’t operate a mem pool, instead, applications are able to submit their transactions to a node of their choice. If the selected node is temporarily unavailable, the application will have to select a different node and prompt the user to approve the same transaction again.
The SDKs implement strategies that enable the user to approve a transaction once, however behind the scenes, the SDK will prepare a number of transactions (say 10 for example) targeted at different nodes, a single user signature operation essentially signs several (10 for example) transactions. The SDK will attempt to submit the first transaction to the node identified in the Transaction’s TransactionBody, if unsuccessful, it will automatically attempt another node with the next Transaction it prepared.
Indeed an SDK Transaction is a complex object which contains an array of TransactionBody, a TransactionBody includes a node_account_id which is the AccountId of the node the transaction is meant to be sent to.
A small portion of transaction fees are paid to the node handling receiving and checking the transaction prior to submitting to consensus, it is necessary to ensure that the signature for the transaction includes the node_account_id in order to approve this payment.
Sending a transaction which TransactionBody specifies node_account_id 0.0.3 to node 0.0.4 will result in an INVALID_NODE_ACCOUNT_ID failure given node 0.0.4 will not be paid for handling this transaction.
This HIP aims to correct the first implementation to more faithfully adhere to the SDK’s network handling capabilities.
Note that if an application wishes to enforce a specific node_account_id is used, it is free to do so by overriding the SDK’s default behaviour, however, if the selected node is temporarily unavailable, the application user will have to approve another transaction to another node, or wait until the node is available again.
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 including ip addresses. 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_signmethod 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.
- As a dApp developer, I want to be able to leverage the SDK’s capabilities for handling unavailable nodes.
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
hederanamespace will be used for CAIP blockchain identifiers. There will be 4 distinct references:mainnet,testnet,previewnet, anddevnet….hedera:devnetrefers 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
No changes from Hip-820
hedera_signTransactions
When a dApp requires only the signature from the controller (wallet), it can use the hedera_signTransactions method which contrary to the hedera_signTransaction method will accept a list of transactions with unique node account ids.
This method accepts a base64 encoded protobuf representation of a TransactionList message which is obtained by using the toBytes() method of an sdk Transaction.
The controller decodes and interprets the contents, and if valid and approved, returns signature maps:
Note: In the event this feature is used to collect signatures in a multi-sig scenario, it is essential that the Transaction sent for signatures includes one or more node account ids, else the wallet may allocate them and different wallets may generate a different list which will result in errors.
Parameters
transactionList – a base64 encoding of the Hedera SDK’s Transaction bytes transaction.toBytes().
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 identified account or omission of this property, or provide additional signatures beyond the request if the controller deems it necessary or proper.
Returns
signatureMaps: a base64 encoding of a list of protobuf SignatureMap messages, one for each transaction in the TransactionList sent for signing. Each SignatureMap contains the signatures for the corresponding transaction.
Important Security Note: This method returns only signature maps, not full signed transactions. This design intentionally forces the dApp to add the returned signatures to its original transaction object, ensuring the transaction body bytes cannot be modified by a malicious actor. Returning full Transaction objects (which include SignedTransaction with body bytes) could enable lazy implementations that re-hydrate returned bytes without verification, creating opportunities for man-in-the-middle attacks.
Example
The application having created and submitted a transaction object receives only the signature maps as a response. The application must add these signatures to its original transaction:
// Create a transaction with the SDK
const transaction = new TransferTransaction()
.addHbarTransfer(senderAccountId, -10)
.addHbarTransfer(recipientAccountId, 10);
// Serialize and send via wallet connect for signing
const transactionBytes = transaction.toBytes();
// Request signatures from wallet (returns only signature maps)
const result = await walletConnect.request({
method: 'hedera_signTransactions',
params: {
transactionList: base64Encode(transactionBytes),
signerAccountId: 'hedera:testnet:0.0.12345'
}
});
// Decode signature maps
const signatureMaps = base64Decode(result.signatureMaps);
// Add signatures to the ORIGINAL transaction object
// This ensures body bytes have not been tampered with
transaction.addSignatures(signatureMaps);
// Now the transaction is ready to submit
const response = await transaction.execute(client);
hedera_signAndExecuteTransaction
No changes from Hip-820
hedera_executeTransaction
No changes from Hip-820
hedera_signAndExecuteQuery
No changes from Hip-820
hedera_signMessage
No changes from Hip-820
hedera_getNodeAddresses
No changes from Hip-820
Backwards Compatibility
There are changes to the existing protocol for Hedera’s implementation of wallet connect.
Old applications will continue to work with newer wallets.
Applications using hedera_signTransactions introduced in this improvement proposal will not work with wallets that have not yet implemented support for this feature.
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.
Transaction Body Integrity
The hedera_signTransactions method is designed to prevent man-in-the-middle attacks by returning only signature maps rather than full signed transactions. This design choice forces dApp implementations to add the returned signatures to their original transaction object, ensuring that:
- The transaction body bytes cannot be modified in transit
- Lazy implementations that blindly re-hydrate returned bytes without verification are prevented
- The dApp must perform due diligence by maintaining its original transaction object
Returning full Transaction objects (which include SignedTransaction containing body bytes) would create opportunities for implementations that fail to verify the returned body bytes match the originally sent bytes, potentially enabling malicious actors to substitute transaction contents.
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
The hedera-wallet-connect repository contains sample code and demos that serves as a reference implementation.
Rejected Ideas
Open Issues
SDK helpers may be useful to more easily generate and consume the data required in the messages in this specification.
References
- HIP-820
- HIP-30: CAIP Identifiers for the Hedera Network
- HIP-179: External Transaction Signing for SDK and other clients
- HAPI: Hedera API Protobuf Specification
- CAIP-2: Blockchain ID Specification
- CAIP-10: Account ID Specification
- CAIP-19: Asset Type and Asset ID Specification
- CAIP-25: JSON-RPC Provider Authorization
- CAIP-27: JSON-RPC Provider Request
- CAIP-217: Authorization Scopes
- Wallet Connect Documentation
- Wallet Connect Specifications
- JSON-RPC 2.0 Specification
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: