mirror of
https://github.com/minibits-cash/minibits_wallet.git
synced 2026-10-05 19:28:26 +00:00
Show payer of invoice in transaction detail, fixes
This commit is contained in:
@@ -18,9 +18,10 @@ export const ContactModel = types
|
||||
pubkey: types.string,
|
||||
name: types.maybe(types.string),
|
||||
about: types.maybe(types.string),
|
||||
displayName: types.maybe(types.string),
|
||||
display_name: types.maybe(types.string),
|
||||
picture: types.maybe(types.string),
|
||||
nip05: types.maybe(types.string),
|
||||
lud16: types.maybe(types.string),
|
||||
noteToSelf: types.maybe(types.string),
|
||||
data: types.maybe(types.string),
|
||||
isExternalDomain: types.optional(types.boolean, false),
|
||||
@@ -34,6 +35,9 @@ export const ContactModel = types
|
||||
setNoteToSelf(note: string) {
|
||||
self.noteToSelf = note
|
||||
},
|
||||
setLud16(lud16: string) {
|
||||
self.lud16 = lud16
|
||||
},
|
||||
}))
|
||||
.views(self => ({
|
||||
get nip05handle() {
|
||||
@@ -49,8 +53,9 @@ export type Contact = {
|
||||
npub: string
|
||||
pubkey: string
|
||||
name?: string
|
||||
nip05?: string
|
||||
picture?: string
|
||||
nip05?: string
|
||||
lud16?: string
|
||||
data?: string
|
||||
noteToSelf?: string
|
||||
} & Partial<Instance<typeof ContactModel>>
|
||||
|
||||
@@ -8,7 +8,7 @@ import {PaymentRequestsStoreModel} from './PaymentRequestsStore'
|
||||
import {ProofsStoreModel} from './ProofsStore'
|
||||
import {RelaysStoreModel} from './RelaysStore'
|
||||
|
||||
export const rootStoreModelVersion = 9 // Update this if model changes require migrations defined in setupRootStore.ts
|
||||
export const rootStoreModelVersion = 10 // Update this if model changes require migrations defined in setupRootStore.ts
|
||||
|
||||
/**
|
||||
* A RootStore model.
|
||||
|
||||
@@ -215,6 +215,19 @@ async function _runMigrations(rootStore: RootStore) {
|
||||
rootStore.setVersion(rootStoreModelVersion)
|
||||
}
|
||||
|
||||
if(currentVersion < 10) {
|
||||
log.trace(`Starting rootStore migrations from version v${currentVersion} -> v10`)
|
||||
|
||||
for (const contact of contactsStore.all) {
|
||||
if(contact.isExternalDomain === false) {
|
||||
contact.setLud16(contact.nip05)
|
||||
}
|
||||
}
|
||||
|
||||
log.info(`Completed rootStore migrations to the version v${rootStoreModelVersion}`)
|
||||
rootStore.setVersion(rootStoreModelVersion)
|
||||
}
|
||||
|
||||
} catch (e: any) {
|
||||
throw new AppError(
|
||||
Err.STORAGE_ERROR,
|
||||
|
||||
@@ -25,12 +25,21 @@ export const ContactListItem = observer(function (props: ContactListProps) {
|
||||
text={contact.name as string}
|
||||
textStyle={$mintText}
|
||||
subText={contact.noteToSelf || contact.nip05}
|
||||
LeftComponent={<Image style={[
|
||||
$iconContainer, {
|
||||
width: 40,
|
||||
height: contact.isExternalDomain ? 40 : 43,
|
||||
borderRadius: 20,
|
||||
}]} source={{uri: getImageSource(contact.picture as string)}} />}
|
||||
LeftComponent={
|
||||
<View style={{alignItems: 'center'}}>
|
||||
<Image
|
||||
style={[$iconContainer, {
|
||||
width: 40,
|
||||
height: contact.isExternalDomain ? 40 : 43,
|
||||
borderRadius: 20,
|
||||
}]}
|
||||
source={{uri: getImageSource(contact.picture as string)}}
|
||||
/>
|
||||
{contact.lud16 && (
|
||||
<Text text='⚡' size='xxs' style={{marginTop: -spacing.small}}/>
|
||||
)}
|
||||
</View>
|
||||
}
|
||||
RightComponent={
|
||||
<></>
|
||||
}
|
||||
|
||||
@@ -100,15 +100,16 @@ export const PrivateContacts = observer(function (props: {
|
||||
|
||||
log.trace('[saveNewContact]', 'Server profile', profile)
|
||||
|
||||
const {pubkey, npub, nip05, name, picture} = profile
|
||||
const {pubkey, npub, name, picture, nip05, lud16} = profile
|
||||
|
||||
newContact = {
|
||||
type: ContactType.PRIVATE,
|
||||
pubkey,
|
||||
npub,
|
||||
nip05,
|
||||
name,
|
||||
picture,
|
||||
nip05,
|
||||
lud16,
|
||||
isExternalDomain,
|
||||
} as Contact
|
||||
|
||||
@@ -130,6 +131,7 @@ export const PrivateContacts = observer(function (props: {
|
||||
pubkey,
|
||||
npub,
|
||||
nip05,
|
||||
lud16: nip05, // minibits addresses are both nostr and lightning addresses
|
||||
name,
|
||||
picture,
|
||||
isExternalDomain
|
||||
|
||||
@@ -367,14 +367,14 @@ export const TopupScreen: FC<WalletStackScreenProps<'Topup'>> = observer(
|
||||
const senderPubkey = walletProfileStore.pubkey
|
||||
const receiverPubkey = contactToSendTo?.pubkey
|
||||
|
||||
// log.trace('', {senderPrivkey, senderPubkey, receiverPubkey}, 'sendAsNostrDM')
|
||||
// redable message
|
||||
let message = `nostr:${walletProfileStore.npub} sent you Lightning invoice for ${amountToTopup} sats from Minibits wallet!`
|
||||
|
||||
// invoice
|
||||
let content = message + ' \n' + invoiceToPay + ' \n'
|
||||
// parsable memo that overrides static default mint invoice description
|
||||
if (memo) {
|
||||
message += ` Memo: ${memo}`
|
||||
}
|
||||
|
||||
const content = message + ' \n' + invoiceToPay
|
||||
content = content + `Memo: ${memo}`
|
||||
}
|
||||
|
||||
const encryptedContent = await NostrClient.encryptNip04(
|
||||
receiverPubkey as string,
|
||||
@@ -418,13 +418,6 @@ export const TopupScreen: FC<WalletStackScreenProps<'Topup'>> = observer(
|
||||
JSON.stringify(updated)
|
||||
)
|
||||
}
|
||||
|
||||
const txupdate = await transactionsStore.updateSentTo( // set contact to send to to the tx, could be elsewhere //
|
||||
transactionId as number,
|
||||
contactToSendTo?.nip05handle as string
|
||||
)
|
||||
|
||||
log.trace('sentTo tx', txupdate, 'sendAsNostrDM')
|
||||
} else {
|
||||
setInfo('Relay could not confirm that the message has been published.')
|
||||
}
|
||||
|
||||
@@ -908,6 +908,12 @@ const TopupInfoBlock = function (props: {
|
||||
label="tranDetailScreen.memoToReceiver"
|
||||
value={transaction.memo as string}
|
||||
/>
|
||||
{transaction.sentFrom && (
|
||||
<TranItem
|
||||
label="tranDetailScreen.sentFrom"
|
||||
value={transaction.sentFrom as string}
|
||||
/>
|
||||
)}
|
||||
<TranItem
|
||||
label="tranDetailScreen.type"
|
||||
value={transaction.type as string}
|
||||
|
||||
@@ -14,6 +14,15 @@ export type DecodedLightningInvoice = {
|
||||
readonly route_hints: any[]
|
||||
}
|
||||
|
||||
export type LightningInvoiceData = {
|
||||
amount: number;
|
||||
payment_hash: string,
|
||||
timestamp: number,
|
||||
expiry: number,
|
||||
description?: string;
|
||||
description_hash?: string,
|
||||
}
|
||||
|
||||
|
||||
const findEncodedLightningInvoice = function (content: string) {
|
||||
const words = content.split(/\s+|\n+/)
|
||||
@@ -80,7 +89,12 @@ const getInvoiceExpiresAt = function (timestamp: number, expiry: number): Date {
|
||||
|
||||
|
||||
const getInvoiceData = function (decoded: DecodedLightningInvoice) {
|
||||
let result: {amount?: number; description?: string; expiry?: number, payment_hash?: string, description_hash?: string, timestamp?: number} = {}
|
||||
const result: LightningInvoiceData = {
|
||||
amount: 0,
|
||||
payment_hash: '',
|
||||
expiry: 0,
|
||||
timestamp: 0
|
||||
}
|
||||
|
||||
// log.trace('decoded invoice', decoded)
|
||||
|
||||
@@ -93,7 +107,7 @@ const getInvoiceData = function (decoded: DecodedLightningInvoice) {
|
||||
result.description = (item.value as string) || ''
|
||||
break
|
||||
case 'payment_hash':
|
||||
result.payment_hash = (Buffer.from(item.value).toString('hex') as string) || ''
|
||||
result.payment_hash = (Buffer.from(item.value).toString('hex') as string)
|
||||
break
|
||||
case 'description_hash':
|
||||
result.description_hash = (Buffer.from(item.value).toString('hex') as string) || ''
|
||||
@@ -104,7 +118,7 @@ const getInvoiceData = function (decoded: DecodedLightningInvoice) {
|
||||
}
|
||||
}
|
||||
|
||||
result.expiry = decoded.expiry || 600
|
||||
result.expiry = decoded.expiry
|
||||
|
||||
log.trace('[getInvoiceData]', result)
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ export type NostrProfile = {
|
||||
about?: string
|
||||
picture?: string
|
||||
nip05?: string
|
||||
lud16?: string
|
||||
}
|
||||
|
||||
export type Nip05VerificationRecord = {
|
||||
|
||||
@@ -223,7 +223,7 @@ const checkPendingReceived = async function () {
|
||||
|
||||
// get sender profile and save it as a contact
|
||||
// this is not valid for events sent from LNURL bridge, that are sent and signed by a single server key
|
||||
// and do not contain sentFrom
|
||||
// and *** do not contain sentFrom ***
|
||||
let sentFromPubkey = event.pubkey
|
||||
let sentFrom = getFirstTagValue(event.tags, 'from')
|
||||
let sentFromNpub = NostrClient.getNpubkey(sentFromPubkey)
|
||||
@@ -238,12 +238,13 @@ const checkPendingReceived = async function () {
|
||||
}
|
||||
|
||||
// we skip retrieval of external nostr profiles to minimize failures
|
||||
// external contacts will thus miss image...
|
||||
// external contacts will thus miss image and lud16 address...
|
||||
|
||||
contactFrom = {
|
||||
pubkey: sentFromPubkey,
|
||||
npub: sentFromNpub,
|
||||
nip05: sentFrom,
|
||||
lud16: sentFrom.includes(MINIBITS_NIP05_DOMAIN) ? sentFrom : undefined,
|
||||
name: sentFromName || undefined,
|
||||
picture: sentFromPicture || undefined,
|
||||
isExternalDomain: sentFrom.includes(MINIBITS_NIP05_DOMAIN) ? false : true
|
||||
@@ -289,6 +290,12 @@ const checkPendingReceived = async function () {
|
||||
if(senderProfile) {
|
||||
sentFrom = senderProfile.nip05 || senderProfile.name
|
||||
sentFromPicture = senderProfile.picture
|
||||
|
||||
// if we have such contact, set or update its lightning address by the one from profile
|
||||
const contactInstance = contactsStore.findByPubkey(sentFromPubkey)
|
||||
if(contactInstance && senderProfile.lud16) {
|
||||
contactInstance.setLud16(senderProfile.lud16)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: any) {
|
||||
@@ -309,7 +316,6 @@ const checkPendingReceived = async function () {
|
||||
// Send notification event
|
||||
//
|
||||
if(receivedAmount > 0) {
|
||||
|
||||
result = {
|
||||
status: TransactionStatus.COMPLETED,
|
||||
title: `⚡${receivedAmount} sats received!`,
|
||||
@@ -360,10 +366,10 @@ const checkPendingReceived = async function () {
|
||||
encodedInvoice: incoming.encoded,
|
||||
amount: amount || 0,
|
||||
description: maybeMemo ? maybeMemo : description,
|
||||
paymentHash: paymentHash || '',
|
||||
paymentHash,
|
||||
contactFrom: contactFrom || {pubkey: sentFromPubkey, npub: sentFromNpub},
|
||||
contactTo,
|
||||
expiry: expiry || 600,
|
||||
expiry,
|
||||
createdAt: timestamp ? new Date(timestamp * 1000) : new Date()
|
||||
})
|
||||
|
||||
@@ -433,7 +439,7 @@ const getFirstTagValue = function (tagsArray: [string, string][], tagName: strin
|
||||
|
||||
const findMemo = function (message: string): string | undefined {
|
||||
// Find the last occurrence of "memo: "
|
||||
const lastIndex = message.lastIndexOf("memo: ")
|
||||
const lastIndex = message.lastIndexOf("Memo: ")
|
||||
|
||||
if (lastIndex !== -1) {
|
||||
const memoAfterLast = message.substring(lastIndex + 6) // skip "memo: " itself
|
||||
@@ -2345,12 +2351,16 @@ const checkPendingTopups = async function () {
|
||||
const {proofs, newKeys} = requestResult
|
||||
|
||||
if (!proofs || proofs.length === 0) {
|
||||
log.trace('[checkPendingTopups]', 'No proofs returned from mint')
|
||||
log.trace('[checkPendingTopups]', 'No proofs returned from mint')
|
||||
|
||||
// create copy of transactionId to avoid mobx error aftr pr is deleted
|
||||
const transactionId = {...pr}.transactionId
|
||||
|
||||
// remove already expired invoices only after check that they have not been paid
|
||||
if (isBefore(pr.expiresAt as Date, new Date())) {
|
||||
log.debug('[checkPendingTopups]', `Invoice expired, removing: ${pr.paymentHash}`)
|
||||
|
||||
const transactionId = pr.transactionId
|
||||
|
||||
paymentRequestsStore.removePaymentRequest(pr)
|
||||
|
||||
// expire related tx - but only if it has not been completed before this check
|
||||
@@ -2369,7 +2379,8 @@ const checkPendingTopups = async function () {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// release lock and move on
|
||||
mintInstance.resetInFlight(transactionId as number )
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -2402,7 +2413,12 @@ const checkPendingTopups = async function () {
|
||||
[pr.transactionId as number],
|
||||
TransactionStatus.COMPLETED,
|
||||
JSON.stringify(transactionDataUpdate),
|
||||
)
|
||||
)
|
||||
|
||||
transactionsStore.updateSentFrom(
|
||||
pr.transactionId as number,
|
||||
pr.contactTo?.nip05 as string // payemnt has been sent from payment request receiver
|
||||
)
|
||||
|
||||
// Fire event that the TopupScreen can listen to
|
||||
EventEmitter.emit('topupCompleted', {...pr})
|
||||
|
||||
Reference in New Issue
Block a user