Show payer of invoice in transaction detail, fixes

This commit is contained in:
minibits-cash
2024-02-22 17:25:44 +01:00
parent 4d3d8f3fe9
commit da95740447
10 changed files with 96 additions and 37 deletions
+7 -2
View File
@@ -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>>
+1 -1
View File
@@ -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.
+13
View File
@@ -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,
+15 -6
View File
@@ -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={
<></>
}
+4 -2
View File
@@ -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
+6 -13
View File
@@ -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.')
}
+6
View File
@@ -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}
+17 -3
View File
@@ -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)
+1
View File
@@ -39,6 +39,7 @@ export type NostrProfile = {
about?: string
picture?: string
nip05?: string
lud16?: string
}
export type Nip05VerificationRecord = {
+26 -10
View File
@@ -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})