Skip to content

Commit

Permalink
Upgrade nostr-tools
Browse files Browse the repository at this point in the history
  • Loading branch information
minibits-cash committed Oct 30, 2024
1 parent be0beb7 commit 215a895
Show file tree
Hide file tree
Showing 14 changed files with 227 additions and 215 deletions.
3 changes: 2 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import 'react-native-reanimated' // needed for qrcode reader
import { install } from 'react-native-quick-crypto' // needed for secp256k1, conf in babel.config
install()
import 'react-native-url-polyfill/auto' // URL.host etc
import 'text-encoding-polyfill' // needed in cashu-ts
import 'text-encoding-polyfill' // cashu-ts
import 'message-port-polyfill' // nostr-tools
import {AppRegistry} from 'react-native'
import messaging from '@react-native-firebase/messaging';
import App from './src/App'
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@
"js-lnurl": "^0.6.0",
"lodash.clonedeep": "^4.5.0",
"lodash.debounce": "4.0.8",
"message-port-polyfill": "^0.2.0",
"mobx": "^6.13.2",
"mobx-react-lite": "^4.0.7",
"mobx-state-tree": "^6.0.1",
"nostr-tools": "1.17.0",
"nostr-tools": "2.9.4",
"numbro": "^2.5.0",
"patch-package": "^8.0.0",
"postinstall-postinstall": "^2.1.0",
Expand Down
74 changes: 34 additions & 40 deletions src/models/NwcStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
isStateTreeNode,
detach,
} from 'mobx-state-tree'
import { kinds as NostrKinds } from 'nostr-tools'
import {withSetPropAction} from './helpers/withSetPropAction'
import {log} from '../services/logService'
import EventEmitter from '../utils/eventEmitter'
Expand Down Expand Up @@ -40,12 +41,6 @@ type NwcError = {
message: string
}
}

const NwcKind = {
info: 13194,
request: 23194,
response: 23195
}

type NwcRequest = {
method: string,
Expand Down Expand Up @@ -162,7 +157,7 @@ export const NwcConnectionModel = types.model('NwcConnection', {

const responseEvent: NostrUnsignedEvent = {
pubkey: self.walletPubkey,
kind: NwcKind.response,
kind: NostrKinds.NWCWalletResponse,
tags: [["p", requestEvent.pubkey], ["e", requestEvent.id]],
content: encryptedContent,
created_at: Math.floor(Date.now() / 1000)
Expand Down Expand Up @@ -684,18 +679,18 @@ export const NwcStoreModel = types

self.nwcConnections.push(newConnection)

const filters = [{
kinds: [NwcKind.info],
const filter = {
kinds: [NostrKinds.NWCWalletInfo],
authors: [newConnection.walletPubkey],
}]
}

// Not sure we should publish that as we are not always on, TBD
const existingInfoEvent = yield NostrClient.getEvent(newConnection.connectionRelays, filters)
const existingInfoEvent = yield NostrClient.getEvent(newConnection.connectionRelays, filter)

if(!existingInfoEvent) {
// publish info replacable event // seems to be a relict replaced by get_info request?
const infoEvent: NostrUnsignedEvent = {
kind: NwcKind.info,
kind: NostrKinds.NWCWalletInfo,
pubkey: newConnection.walletPubkey,
tags: [],
content: self.supportedMethods.join(' '),
Expand Down Expand Up @@ -738,42 +733,41 @@ export const NwcStoreModel = types

try {
const since = Math.floor(Date.now() / 1000)
const connectionsPubkeys = self.nwcConnections.map(c => c.connectionPubkey)
const connectionsPubkeys = self.nwcConnections.map(c => c.connectionPubkey)
let eventsBatch: NostrEvent[] = []

const filters = [{
kinds: [NwcKind.request],
const filter = [{
kinds: [NostrKinds.NWCWalletRequest],
authors: connectionsPubkeys,
"#p": [self.walletPubkey],
since
}]

const pool = NostrClient.getRelayPool()
const sub = pool.sub(self.connectionRelays , filters)

let eventsBatch: NostrEvent[] = []
const pool = NostrClient.getRelayPool()

sub.on('event', async (event: NostrEvent) => {
if (event.kind != NwcKind.request) {
return
}

eventsBatch.push(event)

// find connection the nwc request is sent to
const targetConnection = self.nwcConnections.find(c =>
c.connectionPubkey === event.pubkey
)

if(!targetConnection) {
throw new AppError(Err.VALIDATION_ERROR, 'Missing connection matching event pubkey', {pubkey: event.pubkey})
const sub = pool.subscribeMany(self.connectionRelays , filter, {
onevent(event) {
if (event.kind != NostrKinds.NWCWalletRequest) {
return
}

eventsBatch.push(event)

// find connection the nwc request is sent to
const targetConnection = self.nwcConnections.find(c =>
c.connectionPubkey === event.pubkey
)

if(!targetConnection) {
throw new AppError(Err.VALIDATION_ERROR, 'Missing connection matching event pubkey', {pubkey: event.pubkey})
}
// dispatch to correct connection
targetConnection.handleRequest(event)
},
oneose() {
log.trace('[receiveNwcEvents]', `Eose: Got ${eventsBatch.length} NWC events`)
eventsBatch = []
}
// dispatch to correct connection
await targetConnection.handleRequest(event)
})

sub.on('eose', async () => {
log.trace('[receiveNwcEvents]', `Eose: Got ${eventsBatch.length} NWC events`)
eventsBatch = []
})

EventEmitter.on('ev_transferTask_result', self.handleTransferResult)
Expand Down
5 changes: 3 additions & 2 deletions src/models/WalletProfileStore.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {Instance, SnapshotOut, types, flow} from 'mobx-state-tree'
import { kinds as NostrKinds } from 'nostr-tools'
import {KeyChain, MinibitsClient, NostrClient, NostrUnsignedEvent, WalletTask} from '../services'
import {log} from '../services/logService'
import { Err } from '../utils/AppError'
Expand Down Expand Up @@ -50,7 +51,7 @@ export const WalletProfileStoreModel = types

// announce to minibits relay + default public relays with replaceable event
const profileEvent: NostrUnsignedEvent = {
kind: 0,
kind: NostrKinds.Metadata,
pubkey,
tags: [],
content: JSON.stringify({
Expand Down Expand Up @@ -93,7 +94,7 @@ export const WalletProfileStoreModel = types

// announce to new minibits relay
const profileEvent: NostrUnsignedEvent = {
kind: 0,
kind: NostrKinds.Metadata,
pubkey,
tags: [],
content: JSON.stringify({
Expand Down
23 changes: 12 additions & 11 deletions src/screens/Contacts/PublicContacts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import {observer} from 'mobx-react-lite'
import React, {useEffect, useRef, useState} from 'react'
import {FlatList, Image, InteractionManager, LayoutAnimation, Platform, TextInput, TextStyle, UIManager, View, ViewStyle} from 'react-native'
import {verticalScale} from '@gocodingnow/rn-size-matters'
import { kinds as NostrKinds } from 'nostr-tools'
import Clipboard from '@react-native-clipboard/clipboard'
import {colors, spacing, typography, useThemeColor} from '../../theme'
import {colors, spacing, useThemeColor} from '../../theme'
import {BottomModal, Button, Card, ErrorModal, Icon, InfoModal, ListItem, Loading, Screen, Text} from '../../components'
import {useStores} from '../../models'
import {NostrClient, NostrEvent, NostrFilter, NostrProfile} from '../../services'
Expand Down Expand Up @@ -122,21 +123,21 @@ export const PublicContacts = observer(function (props: {
return
}

const filters: NostrFilter[] = [{
const filter: NostrFilter = {
authors: [contactsStore.publicPubkey],
kinds: [0, 3],
}]
kinds: [NostrKinds.Metadata, NostrKinds.Contacts],
}

log.trace('[subscribeToOwnProfileAndPubkeys] getEvents')
const events: NostrEvent[] = await NostrClient.getEvents(relaysStore.allPublicUrls, filters)
const events: NostrEvent[] = await NostrClient.getEvents(relaysStore.allPublicUrls, filter)
log.trace(events)

for (const event of events) {
if(ownProfile && ownProfile.name && followingPubkeys && followingPubkeys.length > 0) {
continue
}

if(event.kind === 0) {
if(event.kind === NostrKinds.Metadata) {
try {
const profile: NostrProfile = JSON.parse(event.content)
profile.pubkey = contactsStore.publicPubkey as string // pubkey might not be in ev.content
Expand All @@ -148,7 +149,7 @@ export const PublicContacts = observer(function (props: {
}
}

if(event.kind === 3) {
if(event.kind === NostrKinds.Contacts) {
const pubkeys = event.tags
.filter((item) => item[0] === "p")
.map((item) => item[1])
Expand All @@ -166,17 +167,17 @@ export const PublicContacts = observer(function (props: {
return
}

const filters: NostrFilter[] = [{
const filter: NostrFilter = {
authors: followingPubkeys,
kinds: [0],
kinds: [NostrKinds.Metadata],
limit: maxContactsToLoad,
}]
}

log.trace('[loadProfiles] Starting following profiles subscription...')

setIsLoading(true)

const events: NostrEvent[] = await NostrClient.getEvents(relaysStore.allPublicUrls, filters)
const events: NostrEvent[] = await NostrClient.getEvents(relaysStore.allPublicUrls, filter)

let following: NostrProfile[] = []

Expand Down
2 changes: 1 addition & 1 deletion src/screens/NwcScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export const NwcScreen: FC<NwcScreenProps> = observer(
}

const onConnect = async function () {
log.trace('onConnect')
log.trace('[onConnect]')

if(!isRemoteDataPushEnabled) {
setSelectedConnection(undefined)
Expand Down
2 changes: 1 addition & 1 deletion src/screens/RelaysScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export const RelaysScreen: FC<SettingsScreenProps> = observer(
}

const onConnect = async function () {
log.trace('onConnect')
log.trace('[onConnect]')

// Full force re-subscription, not just reconnect
WalletTask.receiveEventsFromRelays().catch(e => false)
Expand Down
3 changes: 2 additions & 1 deletion src/screens/SendScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
ImageStyle,
Image,
} from 'react-native'
import { kinds as NostrKinds } from 'nostr-tools'
import {spacing, typography, useThemeColor, colors} from '../theme'
import {WalletStackScreenProps} from '../navigation'
import {
Expand Down Expand Up @@ -511,7 +512,7 @@ export const SendScreen: FC<WalletStackScreenProps<'Send'>> = observer(
// log.trace('Relays', relaysToShareTo)

const dmEvent: NostrUnsignedEvent = {
kind: 4,
kind: NostrKinds.EncryptedDirectMessage,
pubkey: senderPubkey,
tags: [['p', receiverPubkey as string], ['from', walletProfileStore.nip05]],
content: encryptedContent,
Expand Down
3 changes: 2 additions & 1 deletion src/screens/TopupScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
Image,
ImageStyle,
} from 'react-native'
import { kinds as NostrKinds } from 'nostr-tools'
import {spacing, useThemeColor, colors, typography} from '../theme'
import {WalletStackScreenProps} from '../navigation'
import {
Expand Down Expand Up @@ -514,7 +515,7 @@ export const TopupScreen: FC<WalletStackScreenProps<'Topup'>> = observer(
// log.trace('Relays', relaysToShareTo)

const dmEvent: NostrUnsignedEvent = {
kind: 4,
kind: NostrKinds.EncryptedDirectMessage,
pubkey: senderPubkey,
tags: [
['p', receiverPubkey as string],
Expand Down
5 changes: 3 additions & 2 deletions src/screens/WalletScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import {
import codePush, { RemotePackage } from 'react-native-code-push'
import {moderateScale, verticalScale} from '@gocodingnow/rn-size-matters'
import { SvgXml } from 'react-native-svg'
import { debounce } from "lodash"
import {useThemeColor, spacing, colors, typography} from '../theme'
import {
Button,
Expand Down Expand Up @@ -70,6 +69,7 @@ interface WalletScreenProps extends WalletStackScreenProps<'Wallet'> {}
export const WalletScreen: FC<WalletScreenProps> = observer(
function WalletScreen({route, navigation}) {
const {
relaysStore,
mintsStore,
proofsStore,
transactionsStore,
Expand Down Expand Up @@ -298,6 +298,7 @@ export const WalletScreen: FC<WalletScreenProps> = observer(
const handleAppStateChange = (nextAppState: AppStateStatus) => {
if (appState.current.match(/inactive|background/) && nextAppState === 'active') {
if (!isInternetReachable) {
relaysStore.resetStatuses()
return
}

Expand Down Expand Up @@ -473,7 +474,7 @@ export const WalletScreen: FC<WalletScreenProps> = observer(
}
]}>
<UnitBalanceBlock
unitBalance={balances.unitBalances.find(balance => balance.unit === unitMints.unit)!}
unitBalance={balances.unitBalances.find((balance) => balance.unit === unitMints.unit)!}
/>
<Pressable
onPress={toggleMintsModal}
Expand Down
10 changes: 6 additions & 4 deletions src/services/keyChain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import * as _Keychain from 'react-native-keychain'
import AppError, {Err} from '../utils/AppError'
import QuickCrypto from 'react-native-quick-crypto'
import { generateNewMnemonic } from '@cashu/cashu-ts'
import { generatePrivateKey, getPublicKey } from 'nostr-tools'
import { bytesToHex } from '@noble/hashes/utils'
import { generateSecretKey, getPublicKey } from 'nostr-tools'
import {btoa, fromByteArray} from 'react-native-quick-base64'
import {log} from './logService'

Expand Down Expand Up @@ -345,8 +346,9 @@ async function updateAuthSettings(isAuthOn: boolean) {

const generateNostrKeyPair = function () {
try {
const privateKey = generatePrivateKey() // hex string
const publicKey = getPublicKey(privateKey)
const privateKeyBytes = generateSecretKey() // Uint8Array
const privateKey = bytesToHex(privateKeyBytes)
const publicKey = getPublicKey(privateKeyBytes)

log.trace('New HEX Nostr keypair created:', publicKey, privateKey)

Expand Down Expand Up @@ -392,7 +394,7 @@ const loadNostrKeyPair = async function (): Promise<KeyPair | undefined> {
})

if (result) {
const keyPair = JSON.parse(result.password)
const keyPair: KeyPair = JSON.parse(result.password)
return keyPair
}
log.trace('[loadNostrKeyPair]', 'Did not find existing keyPair in the KeyChain')
Expand Down
Loading

0 comments on commit 215a895

Please sign in to comment.