This library is a work in progress and open for contribution. The final destination for the
community supported and governed helper library implementing WalletConnect will be
@hashgraph/walletconnect
.
This library was originally built utilizing the spec set out by the Hedera <> WalletConnect JSON-RPC spec.
There is an active discussion surrounding standardizing the "Integration of Wallet Connect 2.0 Protocol for Wallets and dApps on Hedera" via the HIP-820 discussion.
We will update this helper library as well as the WalletConnect Spec PR based on the results of HIP-820.
Please join the discussion!
This package managed by the Hedera community and is intended to be a standard for ecosystem
wallets and dApp providers utilizing WalletConnect as a their
communications protocol. It utilizes the
@hashgraph/sdk
and provides functions to
facilitate implementing the
Hedera <> WalletConnect JSON-RPC spec.
WalletConnect brings the ecosystem together by enabling wallets and apps to securely connect and interact.
This library facilitates the implementation of the Hedera <> WalletConnect Spec which allows
wallets and dApps to natively integrate with Hedera. It provides additional, out of network
functionality with the hedera_signMessage
function.
In short, it uses the Hedera javascript SDK to build transactions, serialize them, send "them over the wire" to wallets for processing and return responses back to dApps.
A message could be one of:
- a Hedera network response
- an error message
- signed transaction bytes
- signed arbitrary set of bytes
Please note, this is distinct from the Implementation of Ethereum JSON-RPC APIs for Hedera. At the time of this writing, "the Hedera JSON-RPC relay implementation is in beta, offers limited functionality today, and is only available to developers."
The relay and this library have different intentions and serve different purposes - namely native Hedera integration vs. Ethereum compatability layers to ease developer onboarding for those more familiar with the Ethereum ecosystem.
To start using WalletConnect, sign up for an account at https://cloud.walletconnect.com. You will use your project id when initializing client libraries.
It is important to understand core WalletConnect concepts when integrating this library. Please reference the WalletConnect documentation.
Upon successfully configuring your dApp and/or wallet to manage WalletConnect sessions, you can use this library’s functions to easily create and handle requests for the Hedera network.
- Initialize WalletConnect SignClient: Start by setting up a WalletConnect
SignClient
. This is your primary interface for establishing and managing sessions between a dApp and a wallet.
import SignClient from '@walletconnect/sign-client'
const signClient = await SignClient.init({ ...signClientProps })
// Ensure other initialization steps are followed as per the WalletConnect documentation.
- Construct a Hedera Transaction: Use the
@hashgraph/sdk
to build your desired Hedera transaction. When calling the.freeze()
method in preparation for serialization you must set aTransactionId
and aNodeAccountId
. Create an unsigned transaction.
import { AccountId, TransactionId, TopicMessageSubmitTransaction } from '@hashgraph/sdk'
const payerAccountId = new AccountId(userAccountId)
const nodeAccountIds = [new AccountId(3)]
const transactionId = TransactionId.generate(payerAccountId)
const transaction = new TopicMessageSubmitTransaction()
.setTransactionId(transactionId)
.setNodeAccountIds(nodeAccountIds)
.setTopicId(topicId)
.setMessage('Hello Future')
- Build the Session Request Payload: The
@hashgraph/walletconnect
library provides a seamless way to prepare the session request payload.
import { HederaSessionRequest, networkNameToCAIPChainId } from '@hashgraph/walletconnect'
const payload = HederaSessionRequest.create({
chainId: networkNameToCAIPChainId('testnet'), // CAIP-2 Chain ID for testnet
topic: 'abcdef123456',
}).buildSignAndExecuteTransactionRequest('0.0.1234', transaction)
- Send the Transaction to the Wallet: With the payload prepared, utilize the WalletConnect
signClient
to dispatch the transaction details to the user's wallet for approval. When the payload is received by the connected wallet, the wallet should prompt the account owner either sign or reject the transaction.
const result = await signClient.request(payload)
// do something with the result
console.log(result)
By following these steps, your dApp has access to the full set of Hedera network services. Be sure to refer to the linked documentation for in-depth details, best practices, and updates.
There are 2 core WalletConnect APIs to be implemented by a Wallet:
The Sign API
WalletConnect Sign is a remote signer protocol to communicate securely between web3 wallets and dapps. The protocol establishes a remote pairing between two apps and/or devices using a Relay server to relay payloads. These payloads are symmetrically encrypted through a shared key between the two peers. The pairing is initiated by one peer displaying a QR Code or deep link with a standard WalletConnect URI and is established when the counter-party approves this pairing request.
The Auth API
WalletConnect Auth is an authentication protocol that can be used to log-in blockchain wallets into apps. With a simple and lean interface, this API verifies wallet address ownership through a single signature request, realizing login in one action. It enables apps to set up a decentralized and passwordless onboarding flow.
The following instructions demonstrate implementation of the Sign API.
First, make sure you've installed the necessary npm packages:
npm install @walletconnect/sign-client @hashgraph/sdk @hashgraph/walletconnect
You'll need your WalletConnect Project ID for this step. If you haven't already, obtain a Project ID from WalletConnect Cloud.
import SignClient from '@walletconnect/sign-client'
const signClient = await SignClient.init({
projectId: 'YOUR_PROJECT_ID',
metadata: {
name: 'Your Wallet Name',
description: 'Description for your wallet',
url: 'https://your-wallet-url.com',
icons: ['https://your-wallet-url.com/icon.png'],
},
})
WalletConnect emits various events during a session. Listen to these events to synchronize the state of your application:
// Handle pairing proposals
signClient.on('session_proposal', (event) => {
// Display session proposal to the user and decide to approve or reject
})
// Handle session requests, like signing transactions or messages
signClient.on('session_request', (event) => {
// Process the session request
})
// Handle session deletions
signClient.on('session_delete', (event) => {
// React to session termination
})
For a complete list of events and their structure, refer to the provided WalletConnect documentation. WalletConnect Usage
Pairing establishes a connection between the wallet and a dApp. Once paired, the dApp can send session requests to the wallet.
If a dApp shares a URI for pairing:
await signClient.core.pairing.pair({ uri: 'RECEIVED_URI' })
Upon successful pairing, the session_proposal
event will be triggered.
For a better user experience, dApps often share QR codes that wallets can scan to establish a pairing. Use a QR code scanning library to scan and obtain the URI, then proceed with pairing:
const scannedUri = '...' // URI obtained from scanning the QR code
await signClient.core.pairing.pair({ uri: scannedUri })
Upon receiving a session_proposal
event, display the proposal details to the user. Allow them
to approve or reject the session:
// Approving a session proposal
const { topic, acknowledged } = await signClient.approve({
id: proposalId, // From the session_proposal event
namespaces: {
hedera: {
accounts: ['hedera:testnet:YOUR_HEDERA_ACCOUNT_ID'],
methods: ['hedera_signAndExecuteTransaction'],
},
},
})
// Rejecting a session proposal
await signClient.reject({
id: proposalId,
reason: {
code: 1,
message: 'User rejected the proposal',
},
})
Upon receiving a session_request
event, process the request. For instance, if the dApp
requests a transaction to be signed:
// Using the @hashgraph/sdk library
import { base64StringToTransaction, HederaWallet } from '@hashgraph/walletconnect'
const transaction = base64StringToTransaction(event.params.request.params)
// show the transaction details and prompt the user for confirmation or rejection
confirm('Would you like to complete this transaction?')
//sign on approval
const hederaWallet = await HederaWallet.init({
accountId: 'YOUR_HEDERA_ACCOUNT_ID',
privateKey: 'YOUR_HEDERA_PRIVATE_KEY',
network: 'testnet',
})
const response = await hederaWallet.signAndExecuteTransaction(transaction)
Return the network response to the dApp:
await signClient.send({ id: event.id, result: response })
Sessions can be deleted by either the dApp or the wallet. When the session_delete
event is
triggered, update your application's state to reflect the end of the session:
signClient.on('session_delete', (event) => {
// Update the UI to show the session has ended
})
Remember to always handle errors gracefully, informing users about any issues or required actions. Upon successful implementation by using the above steps and associated documentation, your wallet is ready to interact with dApps using WalletConnect.