WalletConnect Class
The WalletConnect
class provides a client-side implementation for connecting to NIP-47 wallet services. It handles all communication with wallet services, including request encryption, response decryption, and notification handling.
Overview
WalletConnect
is designed to be a complete client for interacting with Nostr Wallet Connect services. It provides:
- Reactive Architecture: Built on RxJS for efficient event handling
- Encryption Support: Automatic handling of NIP-04 and NIP-44 encryption
- Request Management: Built-in timeout handling and error management
- Notification Support: Real-time wallet notifications
- Type Safety: Full TypeScript support with typed responses
Relay Connections
The WalletConnect
requires two methods for communicating with relays: a subscription method for receiving events and a publish method for sending events.
These methods can be set either through the constructor or globally on the class. At least one of these approaches must be used before creating a WalletConnect
instance.
import { Observable } from "rxjs";
function subscriptionMethod(relays, filters) {
return new Observable((observer) => {
// Create subscription to relays
const cleanup = subscribeToRelays(relays, filters, (event) => {
observer.next(event);
});
return () => cleanup();
});
}
async function publishMethod(relays, event) {
for (const relay of relays) {
await publishToRelay(relay, event);
}
}
// Set methods globally once at app initialization
WalletConnect.subscriptionMethod = subscriptionMethod;
WalletConnect.publishMethod = publishMethod;
// Or pass them as options when creating a signer
const signer = new WalletConnect({
relays: ["wss://relay.example.com"],
subscriptionMethod,
publishMethod,
// ... other options
});
Using the relay pool
The simplest way to set these methods is to use the RelayPool
from the applesauce-relay
package.
import { RelayPool } from "applesauce-relay";
const pool = new RelayPool();
// Set the pool globally
WalletConnect.pool = pool;
// Or pass the pool as an option when creating a client
const client = new WalletConnect({
relays: ["wss://relay.example.com"],
pool,
// ... other options
});
Using a nostr+walletconnect://
URI
The most common way to create a client is using a connection string:
import { WalletConnect } from "applesauce-wallet-connect";
// Create a new client from a connection string
const wallet = WalletConnect.fromConnectionString(
"nostr+walletconnect://relay.example.com?secret=abc123&pubkey=def456",
);
// Start using the wallet
await wallet.getInfo();
await wallet.payInvoice("lnbc1...");
Using a nostr+walletauth://
URI
Some wallets support a nostr+walletauth://
URI for the client app to request a connection from the wallet service.
import { WalletConnect } from "applesauce-wallet-connect";
// Create a new client with a random secret key
const secret = generateSecretKey();
const wallet = new WalletConnect(
secret,
relays: ["wss://relay.wallet.com"],
);
// Get the auth URI and show it to the user as a QR code
const authUri = wallet.getAuthURI();
// Wait for the service to respond
await wallet.waitForService();
console.log("Connected to wallet service!");
// Start using the wallet
await wallet.getInfo();
Checking Wallet Capabilities
Before using specific methods, it's good practice to check what the wallet supports:
// Get the wallet's supported methods and capabilities
const support = await wallet.getSupport();
if (support) {
console.log("Supported methods:", support.methods);
console.log("Encryption methods:", support.encryption);
console.log("Notification types:", support.notifications);
}
// Check specific method support
if (await wallet.supportsMethod("pay_invoice")) {
console.log("Wallet supports invoice payments");
}
if (await wallet.supportsNotifications()) {
console.log("Wallet supports notifications");
}
Basic Wallet Operations
Getting Wallet Information
// Get basic wallet info
const info = await wallet.getInfo();
console.log("Wallet alias:", info.alias);
console.log("Network:", info.network);
// Get current balance
const balance = await wallet.getBalance();
console.log("Balance:", balance.balance, "msats");
Transaction History
// Get recent transactions
const transactions = await wallet.listTransactions({
limit: 10,
type: "incoming",
});
transactions.transactions.forEach((tx) => {
console.log(`${tx.type}: ${tx.amount} msats`);
});
Payment Operations
Invoice Payments
// Pay a Lightning invoice
const result = await wallet.payInvoice("lnbc1...");
console.log("Payment successful:", result.preimage);
// Pay multiple invoices at once
const results = await wallet.payMultipleInvoices([{ invoice: "lnbc1..." }, { invoice: "lnbc2..." }]);
Keysend Payments
// Send a keysend payment
const result = await wallet.payKeysend(
"pubkey123...",
100000, // 100 sats in msats
undefined, // preimage (optional)
[{ type: 696969, value: "Hello from Nostr!" }], // TLV records
);
Creating Invoices
// Create a new invoice
const invoice = await wallet.makeInvoice(50000, {
description: "Coffee payment",
expiry: 3600, // 1 hour
});
console.log("Invoice created:", invoice.payment_request);
Notifications
Using the notification Method
The notification
method allows you to listen for specific types of notifications:
// Listen for payment received notifications
const subscription = wallet.notification("payment_received", (notification) => {
const { payment_hash, amount, fee } = notification;
console.log(`Payment received: ${amount} msats`);
});
// Listen for payment sent notifications
const sentSubscription = wallet.notification("payment_sent", (notification) => {
console.log("Payment sent successfully");
});
// Clean up when done
subscription.unsubscribe();
sentSubscription.unsubscribe();
Using Observables
For more advanced usage, you can subscribe to the observables directly:
import { filter, map } from "rxjs";
// Subscribe to all notifications
wallet.notifications$.subscribe((notification) => {
console.log("Notification:", notification);
});
// Filter notifications by type
wallet.notifications$
.pipe(
filter((n) => n.notification_type === "payment_received"),
map((n) => n.notification),
)
.subscribe((notification) => {
console.log("Payment received:", notification);
});
Available Observables
support$
Emits wallet support information when it changes:
wallet.support$.subscribe((support) => {
if (support) {
console.log("Wallet supports:", support.methods);
}
});
notifications$
Emits all wallet notifications:
wallet.notifications$.subscribe((notification) => {
console.log("Notification:", notification);
});
encryption$
Emits the preferred encryption method:
wallet.encryption$.subscribe((method) => {
console.log("Using encryption:", method);
});
Error Handling
WalletConnect provides comprehensive error handling with typed errors:
try {
const result = await wallet.payInvoice("lnbc1...");
console.log("Payment successful:", result.preimage);
} catch (error) {
if (error instanceof InsufficientBalanceError) {
console.log("Not enough balance:", error.message);
} else if (error instanceof InvalidInvoiceError) {
console.log("Invalid invoice:", error.message);
} else {
console.log("Unexpected error:", error.message);
}
}
Common Error Types
InsufficientBalanceError
: When the wallet doesn't have enough balanceInvalidInvoiceError
: When an invoice is malformedRateLimitedError
: When too many requests are madeUserRejectedError
: When the user rejects the operation
For a complete list of error types and their meanings, see the typedocs.