diff --git a/BDKSwiftExampleWallet.xcodeproj/project.pbxproj b/BDKSwiftExampleWallet.xcodeproj/project.pbxproj index f2eb2a19..baf80dec 100644 --- a/BDKSwiftExampleWallet.xcodeproj/project.pbxproj +++ b/BDKSwiftExampleWallet.xcodeproj/project.pbxproj @@ -34,15 +34,18 @@ AE2B8C1D2A9678C900815B2F /* FeeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE2B8C1C2A9678C900815B2F /* FeeService.swift */; }; AE2B8C1F2A96797300815B2F /* RecommendedFees.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE2B8C1E2A96797300815B2F /* RecommendedFees.swift */; }; AE2F255D2BED0BFB002A9AC6 /* AppError.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE2F255C2BED0BFB002A9AC6 /* AppError.swift */; }; + AE32D7622D0C9146006A8788 /* BitcoinDevKit in Frameworks */ = {isa = PBXBuildFile; productRef = AE32D7612D0C9146006A8788 /* BitcoinDevKit */; }; AE34DDAC2B6B31ED00F04AD4 /* WalletRecoveryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE34DDAB2B6B31ED00F04AD4 /* WalletRecoveryView.swift */; }; AE34DDAE2B6B320F00F04AD4 /* WalletRecoveryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE34DDAD2B6B320F00F04AD4 /* WalletRecoveryViewModel.swift */; }; AE3646262BEDB01200B04E25 /* FileManager+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE3646252BEDB01200B04E25 /* FileManager+Extensions.swift */; }; AE3902A42A3B4CD900BEC318 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE3902A32A3B4CD900BEC318 /* HomeView.swift */; }; + AE4135652D0CC1AD00605103 /* BitcoinDevKit in Frameworks */ = {isa = PBXBuildFile; productRef = AE4135642D0CC1AD00605103 /* BitcoinDevKit */; }; AE49847C2A1BBBD6009951E2 /* BDKSwiftExampleWalletApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE49847B2A1BBBD6009951E2 /* BDKSwiftExampleWalletApp.swift */; }; AE4984802A1BBBD7009951E2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AE49847F2A1BBBD7009951E2 /* Assets.xcassets */; }; AE4984832A1BBBD7009951E2 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AE4984822A1BBBD7009951E2 /* Preview Assets.xcassets */; }; AE49848D2A1BBBD8009951E2 /* BDKSwiftExampleWalletTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE49848C2A1BBBD8009951E2 /* BDKSwiftExampleWalletTests.swift */; }; AE4984A62A1BBCB8009951E2 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = AE4984A52A1BBCB8009951E2 /* README.md */; }; + AE52D68F2D1367C80042119D /* BitcoinDevKit in Frameworks */ = {isa = PBXBuildFile; productRef = AE52D68E2D1367C80042119D /* BitcoinDevKit */; }; AE6715FA2A9A9220005C193F /* BDKSwiftExampleWalletPriceServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE6715F92A9A9220005C193F /* BDKSwiftExampleWalletPriceServiceTests.swift */; }; AE6715FD2A9AC056005C193F /* PriceServiceError.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE6715FC2A9AC056005C193F /* PriceServiceError.swift */; }; AE6715FF2A9AC066005C193F /* FeeServiceError.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE6715FE2A9AC066005C193F /* FeeServiceError.swift */; }; @@ -74,7 +77,6 @@ AEB735D32B2CC4B900F99DBB /* BitcoinUI in Frameworks */ = {isa = PBXBuildFile; productRef = AEB735D22B2CC4B900F99DBB /* BitcoinUI */; }; AEB905C32A7EEBF000CD0337 /* BackupInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEB905C22A7EEBF000CD0337 /* BackupInfo.swift */; }; AEC2CF5A2ABFBA19008065E4 /* BuildTransactionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEC2CF592ABFBA19008065E4 /* BuildTransactionViewModel.swift */; }; - AED02B912C9D0B44006DAAAF /* BitcoinDevKit in Frameworks */ = {isa = PBXBuildFile; productRef = AED02B902C9D0B44006DAAAF /* BitcoinDevKit */; }; AED062712A9BB1D6001DC6BD /* BDKSwiftExampleWalletFeeServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AED062702A9BB1D6001DC6BD /* BDKSwiftExampleWalletFeeServiceTests.swift */; }; AED062732A9BD698001DC6BD /* BDKSwiftExampleWalletKeyServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AED062722A9BD698001DC6BD /* BDKSwiftExampleWalletKeyServiceTests.swift */; }; AED062752A9BD7FA001DC6BD /* BDKSwiftExampleWalletBDKServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AED062742A9BD7FA001DC6BD /* BDKSwiftExampleWalletBDKServiceTests.swift */; }; @@ -187,7 +189,9 @@ AE187D782C9BB3B50081D0C3 /* BitcoinDevKit in Frameworks */, AE29ED0F2BBE2E7100EB9C4F /* BitcoinDevKit in Frameworks */, AEAF83B62B7BD4D10019B23B /* CodeScanner in Frameworks */, - AED02B912C9D0B44006DAAAF /* BitcoinDevKit in Frameworks */, + AE52D68F2D1367C80042119D /* BitcoinDevKit in Frameworks */, + AE32D7622D0C9146006A8788 /* BitcoinDevKit in Frameworks */, + AE4135652D0CC1AD00605103 /* BitcoinDevKit in Frameworks */, AEB735D32B2CC4B900F99DBB /* BitcoinUI in Frameworks */, AEE83A492C07F54B00834468 /* BitcoinDevKit in Frameworks */, AE7D5A0E2A7EE62200EAC8CE /* KeychainAccess in Frameworks */, @@ -542,7 +546,9 @@ AE29ED0E2BBE2E7100EB9C4F /* BitcoinDevKit */, AEE83A482C07F54B00834468 /* BitcoinDevKit */, AE187D772C9BB3B50081D0C3 /* BitcoinDevKit */, - AED02B902C9D0B44006DAAAF /* BitcoinDevKit */, + AE32D7612D0C9146006A8788 /* BitcoinDevKit */, + AE4135642D0CC1AD00605103 /* BitcoinDevKit */, + AE52D68E2D1367C80042119D /* BitcoinDevKit */, ); productName = BDKSwiftExampleWallet; productReference = AE4984782A1BBBD6009951E2 /* BDKSwiftExampleWallet.app */; @@ -599,7 +605,7 @@ AE7D5A0C2A7EE62200EAC8CE /* XCRemoteSwiftPackageReference "KeychainAccess" */, AEB735D12B2CC4B900F99DBB /* XCRemoteSwiftPackageReference "BitcoinUI" */, AEAF83B42B7BD4D10019B23B /* XCRemoteSwiftPackageReference "CodeScanner" */, - AED02B8F2C9D0B44006DAAAF /* XCRemoteSwiftPackageReference "bdk-swift" */, + AE52D68D2D1367C80042119D /* XCRemoteSwiftPackageReference "bdk-swift" */, ); productRefGroup = AE4984792A1BBBD6009951E2 /* Products */; projectDirPath = ""; @@ -994,6 +1000,14 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ + AE52D68D2D1367C80042119D /* XCRemoteSwiftPackageReference "bdk-swift" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/bitcoindevkit/bdk-swift.git"; + requirement = { + kind = exactVersion; + version = "1.0.0-beta.6"; + }; + }; AE7D5A0C2A7EE62200EAC8CE /* XCRemoteSwiftPackageReference "KeychainAccess" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/kishikawakatsumi/KeychainAccess.git"; @@ -1018,14 +1032,6 @@ kind = branch; }; }; - AED02B8F2C9D0B44006DAAAF /* XCRemoteSwiftPackageReference "bdk-swift" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/bitcoindevkit/bdk-swift.git"; - requirement = { - kind = exactVersion; - version = "1.0.0-beta.5"; - }; - }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -1037,6 +1043,19 @@ isa = XCSwiftPackageProductDependency; productName = BitcoinDevKit; }; + AE32D7612D0C9146006A8788 /* BitcoinDevKit */ = { + isa = XCSwiftPackageProductDependency; + productName = BitcoinDevKit; + }; + AE4135642D0CC1AD00605103 /* BitcoinDevKit */ = { + isa = XCSwiftPackageProductDependency; + productName = BitcoinDevKit; + }; + AE52D68E2D1367C80042119D /* BitcoinDevKit */ = { + isa = XCSwiftPackageProductDependency; + package = AE52D68D2D1367C80042119D /* XCRemoteSwiftPackageReference "bdk-swift" */; + productName = BitcoinDevKit; + }; AE7D5A0D2A7EE62200EAC8CE /* KeychainAccess */ = { isa = XCSwiftPackageProductDependency; package = AE7D5A0C2A7EE62200EAC8CE /* XCRemoteSwiftPackageReference "KeychainAccess" */; @@ -1052,11 +1071,6 @@ package = AEB735D12B2CC4B900F99DBB /* XCRemoteSwiftPackageReference "BitcoinUI" */; productName = BitcoinUI; }; - AED02B902C9D0B44006DAAAF /* BitcoinDevKit */ = { - isa = XCSwiftPackageProductDependency; - package = AED02B8F2C9D0B44006DAAAF /* XCRemoteSwiftPackageReference "bdk-swift" */; - productName = BitcoinDevKit; - }; AEE83A482C07F54B00834468 /* BitcoinDevKit */ = { isa = XCSwiftPackageProductDependency; productName = BitcoinDevKit; diff --git a/BDKSwiftExampleWallet/Extensions/BDK+Extensions/CanonicalTx+Extensions.swift b/BDKSwiftExampleWallet/Extensions/BDK+Extensions/CanonicalTx+Extensions.swift index 05dbd672..384e0122 100644 --- a/BDKSwiftExampleWallet/Extensions/BDK+Extensions/CanonicalTx+Extensions.swift +++ b/BDKSwiftExampleWallet/Extensions/BDK+Extensions/CanonicalTx+Extensions.swift @@ -19,7 +19,8 @@ extension CanonicalTx { hash: "hash" ), confirmationTime: UInt64(21) - ) + ), + transitively: "c1f9fe0d7f97c6490f8360cf71bbef151f2e73302bd06f1690d640b96fb94457" ) ) } diff --git a/BDKSwiftExampleWallet/Extensions/BDK+Extensions/ChainPosition+Extensions.swift b/BDKSwiftExampleWallet/Extensions/BDK+Extensions/ChainPosition+Extensions.swift index 0d4ad43b..a863a03e 100644 --- a/BDKSwiftExampleWallet/Extensions/BDK+Extensions/ChainPosition+Extensions.swift +++ b/BDKSwiftExampleWallet/Extensions/BDK+Extensions/ChainPosition+Extensions.swift @@ -19,10 +19,16 @@ extension ChainPosition { return false case (.unconfirmed(let timestamp1), .unconfirmed(let timestamp2)): // If both are unconfirmed, compare by timestamp (optional). - return timestamp1 < timestamp2 - case (.confirmed(let blockTime1), .confirmed(let blockTime2)): - // If both are confirmed, compare by block height descending. - return blockTime1.blockId.height > blockTime2.blockId.height + return (timestamp1 ?? 0) < (timestamp2 ?? 0) + case ( + .confirmed(let blockTime1, let transitively1), + .confirmed(let blockTime2, let transitively2) + ): + // Sort by height descending, but note that if transitively is Some, + // this block height might not be the "original" confirmation block + return blockTime1.blockId.height != blockTime2.blockId.height + ? blockTime1.blockId.height > blockTime2.blockId.height + : (transitively1 != nil) && (transitively2 == nil) } } } diff --git a/BDKSwiftExampleWallet/Resources/Localizable.xcstrings b/BDKSwiftExampleWallet/Resources/Localizable.xcstrings index c9588b85..97539308 100644 --- a/BDKSwiftExampleWallet/Resources/Localizable.xcstrings +++ b/BDKSwiftExampleWallet/Resources/Localizable.xcstrings @@ -532,6 +532,9 @@ } } } + }, + "Pending" : { + }, "Please make sure to write it down and store it securely." : { diff --git a/BDKSwiftExampleWallet/View/Activity/TransactionDetailView.swift b/BDKSwiftExampleWallet/View/Activity/TransactionDetailView.swift index ad6d7d59..b9970e23 100644 --- a/BDKSwiftExampleWallet/View/Activity/TransactionDetailView.swift +++ b/BDKSwiftExampleWallet/View/Activity/TransactionDetailView.swift @@ -50,7 +50,7 @@ struct TransactionDetailView: View { .fontWeight(.semibold) switch canonicalTx.chainPosition { - case .confirmed(let confirmationBlockTime): + case .confirmed(let confirmationBlockTime, _): Text("Block \(confirmationBlockTime.blockId.height.delimiter)") .foregroundStyle(.secondary) case .unconfirmed(_): @@ -76,7 +76,7 @@ struct TransactionDetailView: View { .fontDesign(.rounded) VStack(spacing: 4) { switch canonicalTx.chainPosition { - case .confirmed(let confirmationBlockTime): + case .confirmed(let confirmationBlockTime, _): Text( confirmationBlockTime.confirmationTime.toDate().formatted( date: .abbreviated, @@ -84,12 +84,16 @@ struct TransactionDetailView: View { ) ) case .unconfirmed(let timestamp): - Text( - timestamp.toDate().formatted( - date: .abbreviated, - time: Date.FormatStyle.TimeStyle.shortened + if let timestamp { + Text( + timestamp.toDate().formatted( + date: .abbreviated, + time: Date.FormatStyle.TimeStyle.shortened + ) ) - ) + } else { + Text("Pending") + } } if let fee = viewModel.calculateFee { Text("\(fee.formattedWithSeparator) sats fee") diff --git a/BDKSwiftExampleWallet/View/Activity/TransactionItemView.swift b/BDKSwiftExampleWallet/View/Activity/TransactionItemView.swift index 2bfad83e..27dcb3b1 100644 --- a/BDKSwiftExampleWallet/View/Activity/TransactionItemView.swift +++ b/BDKSwiftExampleWallet/View/Activity/TransactionItemView.swift @@ -44,7 +44,7 @@ struct TransactionItemView: View { .foregroundStyle( { switch canonicalTx.chainPosition { - case .confirmed(_): + case .confirmed(_, _): Color.bitcoinOrange case .unconfirmed(_): Color.gray.opacity(0.5) @@ -63,7 +63,7 @@ struct TransactionItemView: View { .font(.title) .foregroundStyle(.primary) switch canonicalTx.chainPosition { - case .confirmed(let confirmationBlockTime): + case .confirmed(let confirmationBlockTime, _): Text( confirmationBlockTime.confirmationTime.toDate().formatted( date: .abbreviated, @@ -74,15 +74,22 @@ struct TransactionItemView: View { .font(.caption2) .fontWidth(.condensed) case .unconfirmed(let timestamp): - Text( - timestamp.toDate().formatted( - date: .abbreviated, - time: .shortened + if let timestamp { + Text( + timestamp.toDate().formatted( + date: .abbreviated, + time: .shortened + ) ) - ) - .lineLimit(dynamicTypeSize.isAccessibilitySize ? 2 : 1) - .font(.caption2) - .fontWidth(.condensed) + .lineLimit(dynamicTypeSize.isAccessibilitySize ? 2 : 1) + .font(.caption2) + .fontWidth(.condensed) + } else { + Text("Pending") + .lineLimit(dynamicTypeSize.isAccessibilitySize ? 2 : 1) + .font(.caption2) + .fontWidth(.condensed) + } } } .foregroundStyle(.secondary)