import { ccc } from "@ckb-ccc/core"; import { Connection, ConnectionsRepo, ConnectionsRepoLocalStorage, } from "./connectionsStorage/index.js"; import { Provider } from "./nip07.advanced.js"; /** * Error thrown when the wallet signs with a different account than the restored * NIP-07 connection. * @public */ export class NostrAccountChangedError extends Error { constructor() { super("The active Nostr account has changed. Please reconnect the wallet."); this.name = "NostrAccountChangedError"; } } /** * @public */ export class Signer extends ccc.SignerNostr { private connection?: Connection; constructor( client: ccc.Client, public readonly provider: Provider, private readonly connectionsRepo: ConnectionsRepo = new ConnectionsRepoLocalStorage(), ) { super(client); } private async assertConnection(): Promise { if (!(await this.isConnected()) || !this.connection) { throw new Error("Not connected"); } return this.connection; } private async saveConnection(): Promise { await this.connectionsRepo.set(this.connection); } private async restoreConnection(): Promise { this.connection = await this.connectionsRepo.get(); } async getNostrPublicKey(): Promise { return (await this.assertConnection()).publicKey; } async signNostrEvent( event: ccc.NostrEvent, ): Promise> { const expectedPublicKey = await this.getNostrPublicKey(); const signedEvent = await this.provider.signEvent({ ...event, pubkey: expectedPublicKey.slice(2), }); try { if (ccc.hexFrom(signedEvent.pubkey) !== expectedPublicKey) { throw new Error("Public key mismatch"); } } catch { this.connection = undefined; await this.saveConnection(); throw new NostrAccountChangedError(); } return signedEvent; } async connect(): Promise { try { this.connection = { publicKey: ccc.hexFrom(await this.provider.getPublicKey()), }; await this.saveConnection(); } catch (error) { this.connection = undefined; await this.saveConnection(); throw error; } } async disconnect(): Promise { await super.disconnect(); this.connection = undefined; await this.saveConnection(); } async isConnected(): Promise { if (this.connection) { return true; } await this.restoreConnection(); return this.connection !== undefined; } }