Integrating decentralized applications (DApps) with blockchain wallets is a critical step in building seamless Web3 experiences. This guide walks you through the complete process of connecting your DApp to a wallet using WalletConnect 2.0, focusing on secure communication, transaction handling, and user authentication.
Whether you're a developer building on Bitcoin SV or creating multi-chain applications, understanding how to properly interface with wallets ensures better usability, security, and adoption.
Core Integration Requirements
To begin integrating your DApp with a wallet via WalletConnect 2.0, ensure the following prerequisites are met:
- Import the WalletConnect 2.0 SDK into your project.
- Use a compatible relay server (either self-hosted or the official WalletConnect relay).
- Follow standardized data structures for session initiation and transaction requests.
π Discover how easy it is to start building secure DApp connections today.
Initialization
Initialize the WalletConnect client with proper configuration options:
await WalletConnectClient.init(
Object.assign(
{
relayUrl: 'wss://your-relay-domain.com', // Replace with your relay server
} as ClientOptions,
opts ?? {}
)
);This sets up the secure bridge between your DApp and the userβs wallet using encrypted messaging over WebSockets.
Establishing Connection
Once initialized, initiate the connection request from the DApp side.
DApp Metadata Structure
Provide clear and concise metadata so users understand which application is requesting access:
| Field | Description |
|---|---|
name | Name of the DApp |
description | Brief functionality overview |
url | Official website URL |
icons | Array of icon URLs for display |
Use this structure when calling connect():
const wc = useWallet();
await wc.connect({
name: 'My DApp',
description: 'A decentralized marketplace',
url: 'https://mydapp.example.com',
icons: ['https://mydapp.example.com/icon.png']
});Session Response Structure
Upon successful connection, the wallet returns session data in the following format:
bsv:livenet:alias|domain|address|signatureBreakdown:
- Namespace & Network: Separated by
:(e.g.,bsv:livenet) Account Fields: Delimited by
|alias: Paymail handle (if available)domain: Wallet domainaddress: Bitcoin addresssignature: Signed public key for verification
Example:
bsv:livenet:test_account|chainbow.io|1BikvsWbVmLC9R9inrtRLQ7j2qBpMJVUfT|Hxj8kJ7ZdDC8zgtCAZopEQ01VUPI4Gl+L8L26IYKcsh/Mp1nhlxniTGFuPYTCPZMNA3ovlHdVED43r+QLiaYwmw=If no alias exists:
bsv:livenet:| |1BikvsWbVmLC9R9inrtRLQ7j2qBpMJVUfT|signatureSigning Messages for Authentication
Securely verify user ownership of an address using message signing.
Request Structure
| Field | Description |
|---|---|
address | Wallet address to sign |
message | Message to be signed |
await wc.signMessage({ address: data.address, message: data.message });Response
Returns a cryptographic signature:
| Field | Description |
|---|---|
signature | Hex-encoded signed message |
Verifying the Signature
Use standard libraries to validate authenticity:
const result = Message.verify(data.message, data.address, data.signature);
if (result) {
console.log("Signature verified");
}This confirms that the user controls the private key associated with the provided address.
Sending Transactions
Single Transaction: sendTransaction()
Send funds directly from the wallet using structured output parameters.
Input Structure
| Field | Description |
|---|---|
to | Recipient (address, Paymail, or script) |
format | Type: 'address', 'paymail', or 'script' |
amount | Amount in satoshis |
await wc.sendTransaction({
outputs: [
{
to: '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa',
format: 'address',
amount: '10000'
}
]
});Response
| Field | Description |
|---|---|
txId | Transaction ID |
time | Timestamp (ms) |
fee | Network fee (satoshi) |
amount | Sent amount (satoshi) |
Example:
{
"txId": "91256db99f8756d757fa72f2bf57b6c2bb45e9ce2d6e4a5d78ff70d89b6d53c9",
"time": 1645501589365,
"fee": 200,
"amount": 600
}π Learn how to streamline blockchain transactions in your DApp now.
Multiple Transactions: sendRawTransaction()
Broadcast pre-signed raw transactions to the network.
Input
| Field | Description |
|---|---|
rawHex | Full serialized transaction hex |
const res = await wc.sendRawTransaction([rawHex]);Response
Returns only:
txId: The blockchain transaction identifier
Ideal for batch operations or complex smart contract interactions where signing logic occurs off-wallet.
Signing Custom Transactions
For advanced use cases like multi-signature or conditional payments, request partial signatures.
Input: ITransaction & Sign Requests
Transaction Inputs
| Field | Description |
|---|---|
prevTxId | Previous transaction ID |
outputIndex | Output index |
satoshis | Value in satoshis |
lockingScript | ScriptPubKey as hex |
Transaction Outputs
| Field | Description |
|---|---|
to | Unlocking script (e.g., P2PKH script hex) |
format | Must be 'script' |
amount | Output value |
Sign Requests Array
| Field | Description |
|---|---|
inputIndex | Index of input to sign |
address | Associated Bitcoin address |
sigtype | Hash type flags (e.g., SIGHASH_ALL) |
const request = {
transaction: { inputs, outputs },
signRequests: [
{
inputIndex: 0,
address: '1BikvsWbVmLC9R9inrtRLQ7j2qBpMJVUfT',
sigtype: bsv.crypto.Signature.SIGHASH_ALL | bsv.crypto.Signature.SIGHASH_FORKID
}
]
};
await wc.signTransaction(request);Signature Response
Returns an array of signed inputs:
| Field | Description |
|---|---|
prevTxId | Reference transaction ID |
outputIndex | Output position |
satoshis | Amount |
sequenceNumber | Input sequence |
signature | DER-encoded signature |
pubkey | Public key used |
sigtype | Signature hash flag |
inputIndex | Index in transaction inputs |
Example:
"signatures": [
{
"prevTxId": "35a7c737b2e39b7b81219cc1628402a795e7e8a48b6e940207b912123f5e43c1",
"outputIndex": 0,
"satoshis": 1280900,
"sequenceNumber": 4294967295,
"signature": "304402206738aafa8df6179e2511a08b9646db1c6957d25a48f20134704ef7e84d7c25e1...",
"pubkey": "03753e4161e7dab8ca0de4350004af544ced8cdd17494df6597d4f7c12e3e0ed2a",
"sigtype": 65,
"inputIndex": 0
}
]Error Handling
Handle common errors gracefully to improve UX.
| Error Code | Meaning |
|---|---|
Error: User rejected the request | User denied authorization |
Error: UnknownAddress | Invalid Bitcoin address format |
Error: Session not approve | Session login rejected |
Error: JSON-RPC Request timeout... | No response within 300 seconds |
Implement retry logic and user prompts based on these codes.
Frequently Asked Questions (FAQ)
Q: Can I use WalletConnect 2.0 for non-BSV blockchains?
A: Yes. While this guide focuses on BSV integration, WalletConnect 2.0 supports multiple chains and namespaces, enabling cross-chain DApp development.
Q: Is user data exposed during connection?
A: No. All communication is end-to-end encrypted. The wallet only shares minimal required data like address and signed messages.
Q: What happens if the relay server goes down?
A: WalletConnect uses redundant relays and fallback mechanisms. Consider hosting your own relay for high availability.
Q: How do I test my integration before going live?
A: Use testnet networks and mock wallets. You can also clone example projects like DAppDemo for reference implementations.
Q: Are Paymail addresses mandatory?
A: No. They are optional but recommended for improved user experience and human-readable identifiers.
Q: Can I send tokens as well as satoshis?
A: Yes, provided the wallet and chain support token standards (e.g., BSV's Tokenized protocol). Adjust output formatting accordingly.
π Get started with secure, scalable DApp-wallet integration now.