Upgrade cashu-ts lib, improved zaps

This commit is contained in:
minibits-cash
2024-01-31 00:42:04 +01:00
parent b7d043e444
commit ad90bb3bb2
9 changed files with 126 additions and 121 deletions
+1 -1
View File
@@ -36,7 +36,7 @@
"mobx": "^6.9.0",
"mobx-react-lite": "^3.4.3",
"mobx-state-tree": "^5.1.8",
"nostr-tools": "^2.1.4",
"nostr-tools": "1.17.0",
"numbro": "^2.3.6",
"patch-package": "^7.0.0",
"postinstall-postinstall": "^2.1.0",
+25
View File
@@ -1,3 +1,28 @@
diff --git a/node_modules/@cashu/cashu-ts/package.json b/node_modules/@cashu/cashu-ts/package.json
index 78f8fc1..a392065 100644
--- a/node_modules/@cashu/cashu-ts/package.json
+++ b/node_modules/@cashu/cashu-ts/package.json
@@ -2,8 +2,7 @@
"name": "@cashu/cashu-ts",
"version": "0.9.0",
"description": "cashu library for communicating with a cashu mint",
- "main": "dist/lib/es5/index.js",
- "module": "dist/lib/es6/index.js",
+ "main": "src/index.ts",
"repository": {
"type": "git",
"url": "git+https://github.com/cashubtc/cashu-ts"
@@ -47,8 +46,8 @@
"dependencies": {
"@gandlaf21/bolt11-decode": "^3.0.6",
"@noble/curves": "^1.0.0",
- "@scure/bip32": "^1.3.2",
- "@scure/bip39": "^1.2.1",
+ "@scure/bip32": "^1.3.3",
+ "@scure/bip39": "^1.2.2",
"buffer": "^6.0.3"
}
}
diff --git a/node_modules/@cashu/cashu-ts/src/CashuMint.ts b/node_modules/@cashu/cashu-ts/src/CashuMint.ts
index f6bc3b1..3b1ca62 100644
--- a/node_modules/@cashu/cashu-ts/src/CashuMint.ts
+1 -2
View File
@@ -93,8 +93,7 @@ export const ProofsStoreModel = types
log.debug('[addProofs]', `Added new ${addedProofs.length}${isPending ? ' pending' : ''} proofs to the ProofsStore`,)
const rootStore = getRootStore(self)
const {userSettingsStore} = rootStore
const userSettingsStore = getRootStore(self).userSettingsStore
if (userSettingsStore.isLocalBackupOn === true && addedProofs.length > 0) {
Database.addOrUpdateProofs(addedProofs, isPending) // isSpent = false
+10 -2
View File
@@ -50,8 +50,8 @@ export const TransactionsStoreModel = types
const tx = self.transactions.find(tx => tx.id === id)
return tx || undefined
},
recentByHostname(mintHostname: string) {
return this.all.filter(t => t.mint?.includes(mintHostname)).slice(0, maxTransactionsByHostname)
recentByHostname(mintHostname: string) {
return this.all.filter(t => getHostname(t.mint as string) === mintHostname).slice(0, maxTransactionsByHostname)
},
getByMint(mintUrl: string) {
return this.all.filter(t => t.mint === mintUrl)
@@ -254,6 +254,14 @@ export const TransactionsStoreModel = types
},
}))
const getHostname = function (mintUrl: string) {
try {
return new URL(mintUrl).hostname
} catch (e) {
return false
}
}
// refresh
export interface TransactionsStore
extends Instance<typeof TransactionsStoreModel> {}
+8
View File
@@ -89,6 +89,14 @@ export const PictureScreen: FC<PictureScreenProps> = observer(function PictureSc
</Pressable>
)
})}
{pictures.length === 0 && (
<Card
ContentComponent={<ListItem
leftIcon='faXmark'
text='Could not retrieve pictures from the server, try again later.'
/>}
/>
)}
</View>
{selectedPicture && (
<View style={$buttonContainer}>
+1
View File
@@ -271,6 +271,7 @@ const checkDonationPaid = async function (paymentHash: string, pubkey: string) {
const fetchApi = async (url: string, options: any, timeout = 15000) => { //ms
log.trace('fetchApi', {url})
const controller = new AbortController()
+16 -9
View File
@@ -1,4 +1,3 @@
import { finalizeEvent, verifyEvent } from 'nostr-tools/pure'
import {
nip19,
getEventHash,
@@ -9,7 +8,7 @@ import {
validateEvent,
UnsignedEvent as NostrUnsignedEvent,
utils
} from 'nostr-tools/core'
} from 'nostr-tools'
import QuickCrypto from 'react-native-quick-crypto'
import {secp256k1} from '@noble/curves/secp256k1'
import {
@@ -21,6 +20,13 @@ import AppError, { Err } from '../utils/AppError'
import { MinibitsClient } from './minibitsService'
import { rootStoreInstance } from '../models'
export {
Event as NostrEvent,
Filter as NostrFilter,
Kind as NostrKind,
UnsignedEvent as NostrUnsignedEvent,
} from 'nostr-tools'
// refresh
export type NostrProfile = {
pubkey: string
@@ -167,24 +173,25 @@ const publish = async function (
relays: string[],
): Promise<Event | undefined> {
const keys: KeyPair = await getOrCreateKeyPair()
const keys: KeyPair = await getOrCreateKeyPair()
let signedEvent = finalizeEvent(event, Uint8Array.from(Buffer.from(keys.privateKey, 'hex')))
event.created_at = Math.floor(Date.now() / 1000)
event.id = getEventHash(event)
event.sig = getSignature(event, keys.privateKey)
if(!validateEvent(signedEvent)) {
if(!validateEvent(event)) {
throw new AppError(Err.VALIDATION_ERROR, 'Event is invalid and could not be published', event)
}
log.trace('Event to be published', signedEvent, 'publish')
log.trace('Event to be published', event, 'publish')
const pool = getRelayPool()
let pubs = pool.publish(relays, signedEvent)
let pubs = pool.publish(relays, event)
await delay(1000)
// await Promise.all(pubs)
const published: NostrEvent = await pool.get(relays, {
ids: [signedEvent.id]
ids: [event.id]
})
+52 -76
View File
@@ -1,8 +1,8 @@
import {deriveKeysetId, getEncodedToken} from '@cashu/cashu-ts'
import {addSeconds, isBefore} from 'date-fns'
import {isBefore} from 'date-fns'
import {getSnapshot, isStateTreeNode} from 'mobx-state-tree'
import {log} from './logService'
import {MintClient, MintKeys, MintKeySets} from './cashuMintClient'
import {MintClient, MintKeys} from './cashuMintClient'
import {Proof} from '../models/Proof'
import {
Transaction,
@@ -28,11 +28,9 @@ import { NostrClient, NostrEvent, NostrFilter } from './nostrService'
import { MINIBITS_NIP05_DOMAIN, MINIBITS_SERVER_API_HOST } from '@env'
import { PaymentRequest, PaymentRequestStatus, PaymentRequestType } from '../models/PaymentRequest'
import { IncomingDataType, IncomingParser } from './incomingParser'
import { Contact, ContactType } from '../models/Contact'
import { MinibitsClient } from './minibitsService'
import { Contact } from '../models/Contact'
import { getDefaultAmountPreference, isObj } from '@cashu/cashu-ts/src/utils'
import { KeyChain } from './keyChain'
import { delay } from '../utils/utils'
type WalletService = {
checkPendingSpent: () => Promise<void>
@@ -210,7 +208,9 @@ const checkPendingReceived = async function () {
if(contactsStore.eventAlreadyReceived(event.id)) {
log.error(Err.ALREADY_EXISTS_ERROR, 'Event has been processed in the past, skipping...', {id: event.id})
return
}
}
contactsStore.addReceivedEventId(event.id)
// decrypt message content
const decrypted = await NostrClient.decryptNip04(event.pubkey, event.content)
@@ -253,19 +253,35 @@ const checkPendingReceived = async function () {
log.trace('Incoming data', {incoming})
if(incoming.type === IncomingDataType.CASHU) {
const {
error,
receivedAmount,
const decoded: Token = CashuUtils.decodeToken(incoming.encoded)
const amountToReceive = CashuUtils.getTokenAmounts(decoded).totalAmount
const memo = decoded.memo || 'Received over Nostr'
const {transaction, receivedAmount} = await receive(
decoded as Token,
amountToReceive,
memo,
} = await receiveFromNostrEvent(incoming.encoded, event)
let picture: string | undefined = undefined
if(sentFrom && sentFrom.includes(MINIBITS_NIP05_DOMAIN)) {
picture = MINIBITS_SERVER_API_HOST + '/profile/avatar/' + sentFromPubkey
incoming.encoded as string,
)
if(transaction) {
await transactionsStore.updateSentFrom(
transaction.id as number,
sentFrom as string
)
}
//
// Send notification event
//
if(receivedAmount > 0) {
let picture: string | undefined = undefined
if(sentFrom && sentFrom.includes(MINIBITS_NIP05_DOMAIN)) {
picture = MINIBITS_SERVER_API_HOST + '/profile/avatar/' + sentFromPubkey
}
result = {
status: TransactionStatus.COMPLETED,
title: `⚡${receivedAmount} sats received!`,
@@ -277,10 +293,6 @@ const checkPendingReceived = async function () {
EventEmitter.emit('receiveTokenCompleted', result)
}
if(error) {
throw new AppError(Err.MINT_ERROR, `Error while receiving transaction: ${error.message}`)
}
return
}
@@ -393,55 +405,6 @@ const findMemo = function (message: string): string | undefined {
}
const receiveFromNostrEvent = async function (encoded: string, event: NostrEvent) {
try {
const decoded: Token = CashuUtils.decodeToken(encoded)
const sentFrom = getTagValue(event.tags, 'from')
const sentFromPubkey = event.pubkey
const tokenAmounts = CashuUtils.getTokenAmounts(decoded)
const amountToReceive = tokenAmounts.totalAmount
const memo = decoded.memo || ''
const {transaction, message, error, receivedAmount} =
await receive(
decoded as Token,
amountToReceive,
memo,
encoded as string,
)
if(transaction && transaction.status === TransactionStatus.COMPLETED) {
const updated = JSON.parse(transaction.data)
updated[2].receivedEvent = event
await transactionsStore.updateStatus(
transaction.id as number,
TransactionStatus.COMPLETED,
JSON.stringify(updated),
)
await transactionsStore.updateSentFrom(
transaction.id as number,
sentFrom as string
)
}
contactsStore.addReceivedEventId(event.id)
return {
error: null,
receivedAmount: receivedAmount,
memo,
sentFrom: sentFrom || '',
sentFromPubkey,
}
} catch (e: any) {
return {error: e, receivedAmount: 0}
}
}
/*
* Recover stuck wallet if tx error caused spent proof to remain in wallet.
@@ -733,7 +696,7 @@ const _checkInFlightByMint = async function (mint: Mint, seed: Uint8Array) {
log.error('[_checkInFlightByMint]', e.name, {message: e.message, mintUrl})
return {
mintUrl,
error: e,
error: {name: e.name, message: e.message}
}
}
}
@@ -855,6 +818,8 @@ const receive = async function (
transactionData.push({
status: TransactionStatus.PREPARED,
errorToken,
updatedToken,
errors,
createdAt: new Date(),
})
@@ -875,11 +840,12 @@ const receive = async function (
throw new AppError(
Err.VALIDATION_ERROR,
'Ecash could not be redeemed.',
{caller: 'receive', message: errors?.length ? errors[0]?.message : undefined, errorToken}
{caller: 'receive', errors}
)
}
let receivedAmount = 0
let addedProofsCount = 0
for (const entry of updatedToken.token) {
// create ProofModel instances and store them into the proofsStore
@@ -889,11 +855,21 @@ const receive = async function (
transactionId as number
)
receivedAmount += addedAmount
receivedAmount += addedAmount
addedProofsCount += addedProofs.length
}
// const receivedAmount = CashuUtils.getTokenAmounts(updatedToken as Token).totalAmount
log.debug('[receive]', `Received amount: ${receivedAmount}`)
// temporary dirty fix of zero value tx until I figure out how it happens
const receivedAmountCheck = CashuUtils.getTokenAmounts(updatedToken as Token).totalAmount
if (receivedAmount !== receivedAmountCheck) {
log.error('[receive]', `Received per proofStore: ${receivedAmount} Received check using tokenAmounts: ${receivedAmountCheck}`, updatedToken)
if(receivedAmount === 0 && addedProofsCount > 0) {
receivedAmount = receivedAmountCheck
}
}
// temp fix end
// Update tx amount if full amount was not received
if (receivedAmount !== amountToReceive) {
@@ -2179,7 +2155,7 @@ const _updateMintKeys = function (mintUrl: string, newKeys: MintKeys) {
const _formatError = function (e: AppError) {
return {
name: e.name,
message: e.message.slice(0, 300),
message: e.message.slice(0, 800),
params: e.params || {},
} as AppError
}
+12 -31
View File
@@ -1611,12 +1611,12 @@
resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-0.2.0.tgz#a12cda60f3cf1ab5d7c77068c3711d2366649ed7"
integrity sha512-6YBxJDAapHSdd3bLDv6x2wRPwq4QFMUaB3HvljNBUTThDd12eSm7/3F+2lnfzx2jvM+S6Nsy0jEt9QbPqSwqRw==
"@noble/curves@1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35"
integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==
"@noble/curves@1.1.0", "@noble/curves@~1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.1.0.tgz#f13fc667c89184bc04cccb9b11e8e7bae27d8c3d"
integrity sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==
dependencies:
"@noble/hashes" "1.3.2"
"@noble/hashes" "1.3.1"
"@noble/curves@^1.0.0", "@noble/curves@~1.3.0":
version "1.3.0"
@@ -1625,24 +1625,12 @@
dependencies:
"@noble/hashes" "1.3.3"
"@noble/curves@~1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.1.0.tgz#f13fc667c89184bc04cccb9b11e8e7bae27d8c3d"
integrity sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==
dependencies:
"@noble/hashes" "1.3.1"
"@noble/hashes@1.3.1", "@noble/hashes@~1.3.1":
"@noble/hashes@1.3.1":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9"
integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==
"@noble/hashes@1.3.2":
version "1.3.2"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39"
integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==
"@noble/hashes@1.3.3", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.2":
"@noble/hashes@1.3.3", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1", "@noble/hashes@~1.3.2":
version "1.3.3"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699"
integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==
@@ -6282,24 +6270,17 @@ normalize-path@^3.0.0:
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
nostr-tools@^2.1.4:
version "2.1.4"
resolved "https://registry.yarnpkg.com/nostr-tools/-/nostr-tools-2.1.4.tgz#7df43a5279eb86ce0530420183620dc2618adaa7"
integrity sha512-MX4gU1gJYP2PKdlLwveHhZIJi/k0qp+ZKwGB7gMFkUodJs4V1OX18Cteb+vxFngtD0B5LlCzLn+ml6tzwlKXFA==
nostr-tools@1.17.0:
version "1.17.0"
resolved "https://registry.yarnpkg.com/nostr-tools/-/nostr-tools-1.17.0.tgz#b6f62e32fedfd9e68ec0a7ce57f74c44fc768e8c"
integrity sha512-LZmR8GEWKZeElbFV5Xte75dOeE9EFUW/QLI1Ncn3JKn0kFddDKEfBbFN8Mu4TMs+L4HR/WTPha2l+PPuRnJcMw==
dependencies:
"@noble/ciphers" "0.2.0"
"@noble/curves" "1.2.0"
"@noble/curves" "1.1.0"
"@noble/hashes" "1.3.1"
"@scure/base" "1.1.1"
"@scure/bip32" "1.3.1"
"@scure/bip39" "1.2.1"
optionalDependencies:
nostr-wasm v0.1.0
nostr-wasm@v0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/nostr-wasm/-/nostr-wasm-0.1.0.tgz#17af486745feb2b7dd29503fdd81613a24058d94"
integrity sha512-78BTryCLcLYv96ONU8Ws3Q1JzjlAt+43pWQhIl86xZmWeegYCNLPml7yQ+gG3vR6V5h4XGj+TxO+SS5dsThQIA==
npm-run-path@^4.0.1:
version "4.0.1"