mirror of
https://github.com/minibits-cash/minibits_wallet.git
synced 2026-10-06 03:38:24 +00:00
Upgrade cashu-ts lib, improved zaps
This commit is contained in:
+1
-1
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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> {}
|
||||
|
||||
@@ -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}>
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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]
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user