Skip to main content
Glama
droplet.ts3.23 kB
import { BSM, type PrivateKey } from "@bsv/sdk"; export interface DropletConfig { apiUrl: string; faucetName: string; authKey?: PrivateKey; // Optional auth key for API authentication } export interface FaucetStatus { faucet_name: string; balance_satoshis: number; unspent_utxo_count: number; fixed_drop_sats: number; spendable_utxo_count: number; consolidating_balance_satoshis: number; consolidating_utxo_count: number; } export interface TapResponse { txid: string; } export interface PushResponse { txid: string; message: string; } export class DropletClient { constructor(private config: DropletConfig) {} getConfig(): DropletConfig { return this.config; } async getFaucetStatus(): Promise<FaucetStatus> { const response = await fetch( `${this.config.apiUrl}/faucet/${this.config.faucetName}/status`, ); if (!response.ok) { const error = await response.json(); throw new Error(error.message || "Failed to get faucet status"); } return response.json(); } async tap(recipientAddress: string): Promise<TapResponse> { const response = await fetch( `${this.config.apiUrl}/faucet/${this.config.faucetName}/tap`, { method: "POST", headers: { "Content-Type": "application/json", ...(this.config.authKey ? await this.getAuthHeaders( "POST", `/faucet/${this.config.faucetName}/tap`, { recipient_address: recipientAddress }, ) : {}), }, body: JSON.stringify({ recipient_address: recipientAddress }), }, ); if (!response.ok) { const error = await response.json(); throw new Error(error.message || "Failed to tap faucet"); } return response.json(); } async push(data: string[], encoding = "hex"): Promise<PushResponse> { const response = await fetch( `${this.config.apiUrl}/faucet/${this.config.faucetName}/push`, { method: "POST", headers: { "Content-Type": "application/json", ...(this.config.authKey ? await this.getAuthHeaders( "POST", `/faucet/${this.config.faucetName}/push`, { data, encoding }, ) : {}), }, body: JSON.stringify({ data, encoding }), }, ); if (!response.ok) { const error = await response.json(); throw new Error(error.message || "Failed to push data"); } return response.json(); } async getAuthHeaders( method: string, path: string, body: unknown, ): Promise<Record<string, string>> { if (!this.config.authKey) { return {}; } // Generate timestamp const timestamp = Math.floor(Date.now() / 1000).toString(); // Create the message to sign (BSM format) // Format: requestPath + timestamp + body const bodyStr = JSON.stringify(body); const message = `${path}${timestamp}${bodyStr}`; // Sign the message using BSM const signature = BSM.sign( Buffer.from(message, "utf8"), this.config.authKey, ); // Create the auth token in the format expected by go-bitcoin-auth // Format: "BSM <pubkey> <signature> <timestamp> <path>" const pubkey = this.config.authKey.toPublicKey().toString(); const authToken = `BSM ${pubkey} ${signature.toString("base64")} ${timestamp} ${path}`; return { "X-Auth-Token": authToken, }; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/b-open-io/bsv-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server