From 47bb74cce7130aade358f5fae3bf1cdb1fb45faf Mon Sep 17 00:00:00 2001 From: minibits-cash Date: Fri, 25 Apr 2025 14:20:33 +0200 Subject: [PATCH] Implement scanning of pubkey to lock to --- package.json | 2 +- src/screens/LightningPayScreen.tsx | 2 ++ src/screens/MintsScreen.tsx | 5 +++- src/screens/ScanScreen.tsx | 12 +++++++++- src/screens/SendScreen.tsx | 38 ++++++++++++++++++++++++++---- src/services/incomingParser.ts | 28 +++++++++++++++++++++- 6 files changed, 78 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 148e28d..376ae58 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minibits_wallet", - "version": "0.2.2-beta.10", + "version": "0.2.2-beta.11", "private": true, "scripts": { "android:clean": "cd android && ./gradlew clean", diff --git a/src/screens/LightningPayScreen.tsx b/src/screens/LightningPayScreen.tsx index 01cbcab..c1a48c1 100644 --- a/src/screens/LightningPayScreen.tsx +++ b/src/screens/LightningPayScreen.tsx @@ -98,6 +98,7 @@ export const LightningPayScreen = function LightningPayScreen({ route }: Props) const gotoScan = async function () { lightningInputRef.current?.blur() + //@ts-ignore navigation.navigate('Scan', { mintUrl: mint?.mintUrl, unit }) @@ -147,6 +148,7 @@ export const LightningPayScreen = function LightningPayScreen({ route }: Props) const gotoSend = async function () { + //@ts-ignore navigation.navigate('Send', { unit, mintUrl: mint?.mintUrl diff --git a/src/screens/MintsScreen.tsx b/src/screens/MintsScreen.tsx index f14b858..42fe090 100644 --- a/src/screens/MintsScreen.tsx +++ b/src/screens/MintsScreen.tsx @@ -87,7 +87,10 @@ export const MintsScreen = observer(function MintsScreen({ route }: Props) { const gotoScan = function () { toggleAddMintModal() // @ts-ignore - navigation.navigate('Scan', {unit: userSettingsStore.preferredUnit}) + navigation.navigate('WalletNavigator', { + screen: 'Scan', + params: {unit: userSettingsStore.preferredUnit} + }) } diff --git a/src/screens/ScanScreen.tsx b/src/screens/ScanScreen.tsx index 768a37a..93c2c6a 100644 --- a/src/screens/ScanScreen.tsx +++ b/src/screens/ScanScreen.tsx @@ -162,7 +162,17 @@ export const ScanScreen = function ScanScreen({ route }: Props) { e.message = translate("scanReceiveExtractFail") handleError(e) break - } + } + case 'Send': + try { + const pubkey = IncomingParser.findAndExtract(incoming, IncomingDataType.NPUB_OR_HEX) // throws + return IncomingParser.navigateWithIncomingData(pubkey, navigation, unit, mint && mint.mintUrl) + + } catch (e: any) { + e.params = incoming + handleError(e) + break + } case 'LightningPay': try { const invoiceResult = IncomingParser.findAndExtract(incoming, IncomingDataType.INVOICE) diff --git a/src/screens/SendScreen.tsx b/src/screens/SendScreen.tsx index 4a9818c..b71042c 100644 --- a/src/screens/SendScreen.tsx +++ b/src/screens/SendScreen.tsx @@ -81,7 +81,8 @@ type Props = StaticScreenProps<{ paymentOption?: SendOption, encodedCashuPaymentRequest?: string, contact?: Contact, - mintUrl?: string, + mintUrl?: string, + scannedPubkey?: string }> export const SendScreen = observer(function SendScreen({ route }: Props) { @@ -225,6 +226,7 @@ const pubkeyInputRef = useRef(null) // Initialize pubkeyInputRef } //reset + //@ts-ignore navigation.setParams({ paymentOption: undefined, contact: undefined @@ -375,6 +377,7 @@ const pubkeyInputRef = useRef(null) // Initialize pubkeyInputRef setIsMintSelectorVisible(true) //reset + //@ts-ignore navigation.setParams({ paymentOption: undefined, encodedCashuPaymentRequest: undefined @@ -396,6 +399,22 @@ const pubkeyInputRef = useRef(null) // Initialize pubkeyInputRef }, [route.params?.paymentOption]) ) + // Scan pubkey to lock to + useEffect(() => { + const {scannedPubkey} = route.params + log.trace('[useEffect]', scannedPubkey) + + const handleScannedPubkey = () => { + setLockedPubkey(scannedPubkey) + setIsPubkeySelectorModalVisible(true) + } + + if(scannedPubkey) { + handleScannedPubkey() + } + }, [route.params?.scannedPubkey]) + + // Offline send useEffect(() => { @@ -532,7 +551,7 @@ const pubkeyInputRef = useRef(null) // Initialize pubkeyInputRef const toggleProofSelectorModal = () => setIsProofSelectorModalVisible(previousState => !previousState) const toggleResultModal = () => setIsResultModalVisible(previousState => !previousState) const toggleIsLockedToPubkey = () => setIsLockedToPubkey(previousState => !previousState) -const togglePubkeySelectorModal = () => setIsPubkeySelectorModalVisible(previousState => !previousState) + const togglePubkeySelectorModal = () => setIsPubkeySelectorModalVisible(previousState => !previousState) const onAmountEndEditing = function () { try { @@ -660,6 +679,7 @@ const togglePubkeySelectorModal = () => setIsPubkeySelectorModalVisible(previous setIsLoading(true) const amountToSendInt = round(toNumber(amountToSend) * getCurrency(unitRef.current).precision, 0) + //@ts-ignore const p2pk: { pubkey: string; locktime?: number; @@ -933,8 +953,16 @@ const togglePubkeySelectorModal = () => setIsPubkeySelectorModalVisible(previous } } - const onScanLockedPubkey = async function () { -// TODO + const gotoScan = async function () { + log.trace('[onScanLockedPubkey]') + + togglePubkeySelectorModal() + //@ts-ignore + navigation.navigate('Scan', { + unit: unitRef.current, + mintUrl: mintBalanceToSendFrom.mintUrl + }) + } return ( @@ -1138,7 +1166,7 @@ const togglePubkeySelectorModal = () => setIsPubkeySelectorModalVisible(previous borderBottomLeftRadius: 0, marginHorizontal: 1, }} - onPress={onScanLockedPubkey} + onPress={gotoScan} /> {contactsStore.contacts.length > 0 && ( diff --git a/src/services/incomingParser.ts b/src/services/incomingParser.ts index 1c4d9ba..b86834a 100644 --- a/src/services/incomingParser.ts +++ b/src/services/incomingParser.ts @@ -9,6 +9,7 @@ import { LNURLPayParams, LnurlClient } from './lnurlService' import { MintUnit } from './wallet/currency' import { RootNavigation } from '../navigation' import { NavigationProp } from '@react-navigation/native' +import { NostrClient } from './nostrService' export enum IncomingDataType { CASHU = 'CASHU', @@ -17,6 +18,7 @@ export enum IncomingDataType { LNURL = 'LNURL', LNURL_ADDRESS = 'LNURL_ADDRESS', MINT_URL = 'MINT_URL', + NPUB_OR_HEX = 'NPUB_OR_HEX', } const findAndExtract = function ( @@ -66,7 +68,24 @@ const findAndExtract = function ( return { type: expectedType, encoded: incomingData - } + } + case IncomingDataType.NPUB_OR_HEX: + if(incomingData.startsWith('npub')) { + encoded = '02' + NostrClient.getHexkey(incomingData) + } else { + if(incomingData.length === 64) { + encoded = '02' + incomingData + } else if(incomingData.length === 66) { + encoded = incomingData + } else { + throw new AppError(Err.VALIDATION_ERROR, 'Invalid key. Please provide public key in NPUB or HEX format.') + } + } + + return { + type: expectedType, + encoded + } default: throw new AppError(Err.NOTFOUND_ERROR, 'Unknown expectedType', {expectedType}) } @@ -268,6 +287,13 @@ const navigateWithIncomingData = async function ( } }) + case IncomingDataType.NPUB_OR_HEX: + // popTo used to goBack with params within the same navigator + //@ts-ignore + return navigation.popTo('Send', { + scannedPubkey: incoming.encoded, + }) + default: throw new AppError(Err.NOTFOUND_ERROR, 'Scanned data is neither ecash token, lightning invoice, lnurl or mint URL.') }