HashConnect v3 is public beta. API's may change or be unstable.
For v2 docs go here
Join the Hedera Developer Guild Discord
Hashconnect is a helper library around the Hedera WalletConnect standard, allowing dapps to easily integrate with a variety of wallets.
The provided demo demonstrates the pairing and signing functionality.
- HashConnect
Before doing anything you will need a WalletConnect project ID. You can get one by going to WalletConnect Cloud and setting up a project.
This is what you need to start using HashConnect, it will be explained in detail in the subsequent documentation.
import { HashConnect, HashConnectConnectionState, SessionData } from 'hashconnect';
import { LedgerId } from '@hashgraph/sdk';
const appMetadata = {
name: "<Your dapp name>",
description: "<Your dapp description>",
icons: ["<Image url>"],
url: "<Dapp url>"
}
let hashconnect: HashConnect;
let state: HashConnectConnectionState = HashConnectConnectionState.Disconnected;
let pairingData: SessionData;
async init() {
//create the hashconnect instance
hashconnect = new HashConnect(LedgerId.MAINNET, "<Your project ID>", appMetadata, true);
//register events
setUpHashConnectEvents();
//initialize
await hashconnect.init();
//open pairing modal
hashconnect.openPairingModal();
}
setUpHashConnectEvents() {
hashconnect.pairingEvent.on((newPairing) => {
pairingData = newPairing;
})
hashconnect.disconnectionEvent.on((data) => {
pairingData = null;
});
hashconnect.connectionStatusChangeEvent.on((connectionStatus) => {
state = connectionStatus;
})
}
sendTransaction(accountId: string, transaction: Transaction) {
hashconnect.sendTransaction(accountId, transaction).then(response => {
//handle success
}).catch(err => {
//handle error
})
}
The main functionality of Hashconnect is to send Hedera transactions to a wallet to be signed and executed by a user - we assume you are familiar with the Hedera API's and SDK's used to build these transactions.
HashConnect also providers other sorts of helpers, like user profile fetching and token gating.
npm i hashconnect --save
Import the library like you would any npm package
import { HashConnect } from 'hashconnect';
Create a metadata object that contains information about your dapp.
const appMetadata = {
name: "<Your dapp name>",
description: "<Your dapp description>",
icons: ["<Image url>"],
url: "<Dapp url>"
}
Create a variable to hold an instance of Hashconnect, and pass in the network, project id, metadata, and a boolean to enable debug mode.
let hashconnect = new HashConnect(LedgerId.MAINNET, "<Your project ID>", appMetadata, true);
Note: The LedgerId is from the HashGraph SDK, which you can import by doing this:
import { LedgerId } from '@hashgraph/sdk';
After creating the HashConnect object, set up events, and then call the init function with your parameters.
//register events
setUpHashConnectEvents();
//initialize and use returned data
let initData = await hashconnect.init();
Make sure you register your events before calling init - as some events will fire immediately after calling init.
Pass the accountId of a paired account to get a signer back, this allows you to interact with HashConnect using a simpler API.
signer = hashconnect.getSigner(AccountId.fromString('0.0.12345'));
const signer = hashconnect.getSigner(fromAccount);
let trans = await new TransferTransaction()
.addHbarTransfer(fromAccount, -1)
.addHbarTransfer(toAccount, 1)
.freezeWithSigner(signer);
let response = await trans.executeWithSigner(signer);
Events are emitted by HashConnect to let you know when a request has been fufilled.
The pairing event is triggered when a user accepts a pairing or an existing pairing is found.
hashconnect.pairingEvent.on((pairingData) => {
//do something
})
When a user disconnects this event will be triggered so you can update the state of your dapp.
hashconnect.disconnectionEvent.on((data) => {
//do something
});
This event is fired when the connection status changes. This returns a HashConnectConnectionState
(details)
hashconnect.connectionStatusChangeEvent.on((connectionStatus) => {
//do something with connection status
})
You can easily show a pairing popup containing the pairing code and a QR code by calling openPairingModal().
hashconnect.openPairingModal();
There are a variety of optional theme properties you can pass into openPairingModal() to customize it:
- themeMode - "dark" | "light"
- backgroundColor - string (hex color)
- accentColor - string (hex color)
- accentFillColor - string (hex color)
- borderRadius - string (css border radius)
If the HashPack extension is found during init, it will automatically pop it up and request pairing.
Call hashconnect.disconnect()
to disconnect.
This request takes two parameters, accountId and a Hedera Transaction, signs it with the specified account ID, and executes it.
let response = await hashconnect.sendTransaction(accountId, transaction);
With Signer:
let signer = hashconnect.getSigner(accountId);
let trans = await new TransferTransaction()
.addHbarTransfer(fromAccount, -1)
.addHbarTransfer(toAccount, 1)
.freezeWithSigner(signer);
let response = await trans.executeWithSigner(signer);
This request takes two parameters, accountId and a Hedera Transaction, signs it with the specified account ID, and returns a signed transaction that you can execute or send to other users for additional signatures.
let response = await hashconnect.signAndReturnTransaction(accountId, transaction);
With Signer:
let signer = hashconnect.getSigner(accountId);
let trans = await new TransferTransaction()
.addHbarTransfer(fromAccount, -1)
.addHbarTransfer(toAccount, 1)
.freezeWithSigner(signer);
let response = await trans.signTransaction(signer);
This request allows you to get a signature on a generic string, which can be used for things like authentication.
let signature = await hashconnect.signMessages(accountId, message);
With Signer:
let signer = hashconnect.getSigner(accountId);
let signature = await signer.sign(["Hello World!"]);
Once you've got the result you can call .verifyMessageSignature() to verify it was signed by the correct account. Please note - you will need to get the public key from a mirror node as you cannot trust the public key being returned by the user for verification purposes. You will also likely want to verify it server side.
This method will return a boolean if the signature matches the public key.
let verified = hashconnect.verifyMessageSignature("Hello World!", signMessageResponse, publicKey);
In order to prevent messages from secretly being transactions, there is a bit of manipulation happening to the messages. If you are attempting to verify a signature yourlsef, on the backend for example, you will need to run the message you are verifying through this function first and then verify the result against the signature:
prefixMessageToSign(message: string) {
return '\x19Hedera Signed Message:\n' + message.length + message
}
The HashConnect .sendTransaction() method will automatically retrieve and return a receipt, however when using the signer flow there is one extra step to getting a receipt:
With Signer:
let response = await trans.executeWithSigner(signer);
let receipt = await response.getReceiptWithSigner(signer);
export enum HashConnectConnectionState {
Connecting="Connecting",
Connected="Connected",
Disconnected="Disconnected",
Paired="Paired"
}
export interface SessionData {
metadata: {
name: string;
description: string;
url: string;
icons: string[];
};
accountIds: string[];
network: string;
}