From 4f9f2f83706fa0b4b243f34b51e29f5fe3f0ec16 Mon Sep 17 00:00:00 2001 From: Daniel Gonzalez Date: Mon, 10 Nov 2025 18:45:37 -0400 Subject: [PATCH] feat(nostr): Added npub to order --- src/adapters/localdb/models/order.js | 1 + src/adapters/nostr.js | 28 ++++++++++++++++++++ src/controllers/timer-controllers.js | 2 +- src/use-cases/order.js | 3 +++ test/unit/adapters/nostr.adapter.unit.js | 29 +++++++++++++++++++++ test/unit/adapters/order-pagination.unit.js | 1 + test/unit/mocks/adapters/index.js | 3 ++- 7 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/adapters/localdb/models/order.js b/src/adapters/localdb/models/order.js index 0f38c1c..e6ee6b7 100644 --- a/src/adapters/localdb/models/order.js +++ b/src/adapters/localdb/models/order.js @@ -24,6 +24,7 @@ const Order = new mongoose.Schema({ p2wdbTxid: { type: String }, p2wdbHash: { type: String }, makerAddr: { type: String, required: true }, + makerNpub: { type: String, required: true }, // Authentication data signature: { type: String }, diff --git a/src/adapters/nostr.js b/src/adapters/nostr.js index b37b162..4bd2772 100644 --- a/src/adapters/nostr.js +++ b/src/adapters/nostr.js @@ -7,6 +7,8 @@ import BchNostr from 'bch-nostr' import { RelayPool } from 'nostr' import RetryQueue from '@chris.troutner/retry-queue' import * as nip19 from 'nostr-tools/nip19' +import { base58_to_binary as base58Tobinary } from 'base58-js' +import { getPublicKey } from 'nostr-tools/pure' class NostrAdapter { constructor (localConfig = { nostrRelay: '', nostrTopic: '' }) { @@ -44,6 +46,7 @@ class NostrAdapter { this.npub2pubkey = this.npub2pubkey.bind(this) this.readGlobalFeed = this.readGlobalFeed.bind(this) this.getFollowers = this.getFollowers.bind(this) + this.privKeyToNpub = this.privKeyToNpub.bind(this) } // Create nostr keys. @@ -247,6 +250,31 @@ class NostrAdapter { throw error } } + + // Convert a BCH private key (WIF) to a Nostr npub. + privKeyToNpub (privKey) { + try { + if (!privKey || typeof privKey !== 'string') { + throw new Error('privKey must be a string!') + } + // Extract the privaty key from the WIF, using this guide: + // https://learnmeabitcoin.com/technical/keys/private-key/wif/ + const wifBuf = base58Tobinary(privKey) + const privBuf = wifBuf.slice(1, 33) + // console.log('privBuf: ', privBuf) + + const nostrPubKey = getPublicKey(privBuf) + // console.log('nostrPubKey: ', nostrPubKey) + // Convert pubkey to npub + const nostrNpub = nip19.npubEncode(nostrPubKey) + // console.log('nostrNpub: ', nostrNpub) + + return nostrNpub + } catch (error) { + console.log(`Error in nostr.js/privKeyToNpub() ${error.message} `) + throw error + } + } } export default NostrAdapter diff --git a/src/controllers/timer-controllers.js b/src/controllers/timer-controllers.js index e242543..e541454 100644 --- a/src/controllers/timer-controllers.js +++ b/src/controllers/timer-controllers.js @@ -202,7 +202,7 @@ class TimerControllers { // Remove older deleted chats and posts. async removeOlderDeletedChatsAndPosts () { try { - //console.log('removeOlderDeletedChatsAndPosts() Timer Controller executing at ', new Date().toLocaleString()) + // console.log('removeOlderDeletedChatsAndPosts() Timer Controller executing at ', new Date().toLocaleString()) clearInterval(this.removeOlderDeletedChatsAndPostsInt) await this.useCases.nostr.removeOlderDeletedChats() await this.useCases.nostr.removeOlderDeletedPosts() diff --git a/src/use-cases/order.js b/src/use-cases/order.js index a75d0b1..9b003da 100644 --- a/src/use-cases/order.js +++ b/src/use-cases/order.js @@ -116,6 +116,9 @@ class OrderLib { orderEntity.operatorAddress = this.config.operatorAddress orderEntity.operatorPercentage = this.config.operatorPercentage + // Convert the Seller's BCH private key to a Nostr npub. This is used to identify the seller in Nostr. + orderEntity.makerNpub = this.adapters.nostr.privKeyToNpub(userWallet.walletInfo.privateKey) + // Post the new Order information to Nostr under the topic set in the // config file. const postObj = { diff --git a/test/unit/adapters/nostr.adapter.unit.js b/test/unit/adapters/nostr.adapter.unit.js index 9a0b5e0..f7ead56 100644 --- a/test/unit/adapters/nostr.adapter.unit.js +++ b/test/unit/adapters/nostr.adapter.unit.js @@ -224,4 +224,33 @@ describe('#nostr.js', () => { assert.isArray(result) }) }) + describe('#privKeyToNpub', () => { + it('should handle error if providedprivKey is not a string', async () => { + try { + uut.privKeyToNpub() + + assert.fail('Unexpected code path') + } catch (err) { + // console.log('err: ', err) + assert.include(err.message, 'privKey must be a string!') + } + }) + + it('should return npub if privKey is valid', async () => { + const result = uut.privKeyToNpub('L2kh34VinQNRq1ad8nnXnGoFrb9pT7j8GJXiT6Scsg18KMxsUVDr') + // console.log('result: ', result) + assert.isString(result) + assert.include(result, 'npub') + }) + it('should handle unexpected error', async () => { + try { + uut.privKeyToNpub('invalid format') + + assert.fail('Unexpected code path') + } catch (err) { + // console.log('err: ', err) + assert.include(err.message, 'Invalid base58 character') + } + }) + }) }) diff --git a/test/unit/adapters/order-pagination.unit.js b/test/unit/adapters/order-pagination.unit.js index 56849ec..270db04 100644 --- a/test/unit/adapters/order-pagination.unit.js +++ b/test/unit/adapters/order-pagination.unit.js @@ -52,6 +52,7 @@ describe('#OrderPagination', () => { nostrEventId: 'nostrEventId', dataType: 'dataType', makerAddr: 'makerAddr', + makerNpub: 'makerNpub', rateInBaseUnit: 'rateInBaseUnit', minUnitsToExchange: 'minUnitsToExchange', ticker: 'ticker', diff --git a/test/unit/mocks/adapters/index.js b/test/unit/mocks/adapters/index.js index d500699..9469c86 100644 --- a/test/unit/mocks/adapters/index.js +++ b/test/unit/mocks/adapters/index.js @@ -240,7 +240,8 @@ const nostr = { read: async () => { return true }, eventId2note: () => { return 'testNoteId' }, readGlobalFeed: async () => { return [] }, - getFollowers: async () => { return [] } + getFollowers: async () => { return [] }, + privKeyToNpub: async () => { return 'fakeNpub' } } export default { ipfs, localdb, bch, wallet, p2wdb, bchjs, nostr}