Skip to content

Commit

Permalink
feat: verify address
Browse files Browse the repository at this point in the history
  • Loading branch information
reez authored Nov 14, 2024
1 parent 121b6bb commit bb7df22
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 4 deletions.
6 changes: 6 additions & 0 deletions BDKSwiftExampleWallet.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@
AE4984882A1BBBD8009951E2 /* BDKSwiftExampleWalletTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BDKSwiftExampleWalletTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
AE49848C2A1BBBD8009951E2 /* BDKSwiftExampleWalletTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BDKSwiftExampleWalletTests.swift; sourceTree = "<group>"; };
AE4984A52A1BBCB8009951E2 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
AE6474732CE559E000A270C6 /* BDKSwiftExampleWallet.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = BDKSwiftExampleWallet.entitlements; sourceTree = "<group>"; };
AE6715F92A9A9220005C193F /* BDKSwiftExampleWalletPriceServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BDKSwiftExampleWalletPriceServiceTests.swift; sourceTree = "<group>"; };
AE6715FC2A9AC056005C193F /* PriceServiceError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceServiceError.swift; sourceTree = "<group>"; };
AE6715FE2A9AC066005C193F /* FeeServiceError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeeServiceError.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -387,6 +388,7 @@
AE49847A2A1BBBD6009951E2 /* BDKSwiftExampleWallet */ = {
isa = PBXGroup;
children = (
AE6474732CE559E000A270C6 /* BDKSwiftExampleWallet.entitlements */,
AE11D5EB2B784B2900D67366 /* Info.plist */,
AE1C34222A424440008F807A /* App */,
AE7F670A2A7451B600CED561 /* Model */,
Expand Down Expand Up @@ -854,6 +856,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = BDKSwiftExampleWallet/BDKSwiftExampleWallet.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"BDKSwiftExampleWallet/Preview Content\"";
Expand All @@ -862,6 +865,7 @@
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = BDKSwiftExampleWallet/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "BDK Wallet";
INFOPLIST_KEY_NFCReaderUsageDescription = "We need NFC access to verify addresses.";
INFOPLIST_KEY_NSCameraUsageDescription = "\"To scan QR codes\"";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
Expand All @@ -887,6 +891,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = BDKSwiftExampleWallet/BDKSwiftExampleWallet.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"BDKSwiftExampleWallet/Preview Content\"";
Expand All @@ -895,6 +900,7 @@
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = BDKSwiftExampleWallet/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "BDK Wallet";
INFOPLIST_KEY_NFCReaderUsageDescription = "We need NFC access to verify addresses.";
INFOPLIST_KEY_NSCameraUsageDescription = "\"To scan QR codes\"";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
Expand Down
10 changes: 10 additions & 0 deletions BDKSwiftExampleWallet/BDKSwiftExampleWallet.entitlements
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
<string>TAG</string>
</array>
</dict>
</plist>
4 changes: 1 addition & 3 deletions BDKSwiftExampleWallet/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>NSPasteboardUsageDescription</key>
<string>&quot;To allow users to copy and paste text between the app and other apps&quot;</string>
<key>NSCameraUsageDescription</key>
<string>&quot;To scan QR codes&quot;</string>
<string>"To allow users to copy and paste text between the app and other apps"</string>
</dict>
</plist>
85 changes: 84 additions & 1 deletion BDKSwiftExampleWallet/View Model/Receive/ReceiveViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@
//

import BitcoinDevKit
import CoreNFC
import Foundation
import Observation

@Observable
class ReceiveViewModel {
class ReceiveViewModel: NSObject, NFCNDEFReaderSessionDelegate {
let bdkClient: BDKClient

private var nfcSession: NFCNDEFReaderSession?

var address: String = ""
var receiveViewError: AppError?
var showingReceiveViewErrorAlert = false
Expand All @@ -35,3 +38,83 @@ class ReceiveViewModel {
}

}

extension ReceiveViewModel {
func startNFCSession() {
guard NFCNDEFReaderSession.readingAvailable else {
receiveViewError = .generic(message: "NFC not available on this device")
showingReceiveViewErrorAlert = true
return
}

nfcSession = NFCNDEFReaderSession(
delegate: self,
queue: nil,
invalidateAfterFirstRead: false
)
nfcSession?.alertMessage = "Hold your iPhone near the Coldcard to verify the address"
nfcSession?.begin()
}

// MARK: - NFCNDEFReaderSessionDelegate

func readerSession(_ session: NFCNDEFReaderSession, didDetect tags: [NFCNDEFTag]) {
guard let tag = tags.first else {
return
}

session.connect(to: tag) { error in
if let error = error {
session.invalidate(errorMessage: "Connection error: \(error.localizedDescription)")
return
}

let payload = NFCNDEFPayload(
format: .media,
type: "text/plain".data(using: .utf8)!,
identifier: Data(),
payload: self.address.data(using: .utf8)!
)

let message = NFCNDEFMessage(records: [payload])

tag.writeNDEF(message) { error in
if let error = error {
session.invalidate(errorMessage: "Write failed: \(error.localizedDescription)")
} else {
session.alertMessage = "Address passed to Coldcard successfully"
session.invalidate()
}
}

}
}

func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
if let nfcError = error as? NFCReaderError,
nfcError.code == .readerSessionInvalidationErrorUserCanceled
{
return
}

DispatchQueue.main.async {
self.receiveViewError = .generic(message: error.localizedDescription)
self.showingReceiveViewErrorAlert = true
}
}

func readerSessionDidBecomeActive(_ session: NFCNDEFReaderSession) {
// Required delegate method, but no action needed when session becomes active
}

func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
if let message = messages.first,
let record = message.records.first,
let payload = String(data: record.payload, encoding: .utf8)
{
// Handle response
}
session.invalidate()
}

}
8 changes: 8 additions & 0 deletions BDKSwiftExampleWallet/View/Receive/ReceiveView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

import BitcoinUI
import CoreNFC
import SwiftUI

struct ReceiveView: View {
Expand Down Expand Up @@ -51,6 +52,13 @@ struct ReceiveView: View {
)
.padding()

Button {
viewModel.startNFCSession()
} label: {
Image(systemName: "wave.3.right")
.foregroundColor(.primary)
}

HStack {
Button {
UIPasteboard.general.string = viewModel.address
Expand Down

0 comments on commit bb7df22

Please sign in to comment.