diff --git a/Aux/Config/Common.xcconfig b/Aux/Config/Common.xcconfig index 6a48d0ac1b..390f3343aa 100644 --- a/Aux/Config/Common.xcconfig +++ b/Aux/Config/Common.xcconfig @@ -1,7 +1,7 @@ // MARK: - Custom flags /// Application version shared across all targets and flavours -APP_VERSION = 1.11.0 +APP_VERSION = 1.11.4 /// App Icon base name APP_ICON = AppIcon diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index e0b2df18cb..d2dffeebf1 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -828,6 +828,7 @@ 83377A052B9DDB5C00D8AA36 /* NPSSurveyClient+Live.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83377A042B9DDB5C00D8AA36 /* NPSSurveyClient+Live.swift */; }; 8338B9E52AFAB20700D1D8EA /* TransactionFee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8338B9E42AFAB20700D1D8EA /* TransactionFee.swift */; }; 834B651F2B972E5100B7E1E8 /* NPSSurvey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 834B651E2B972E5100B7E1E8 /* NPSSurvey.swift */; }; + 835DFF932D19855A00229DB0 /* Sargon in Frameworks */ = {isa = PBXBuildFile; productRef = 835DFF922D19855A00229DB0 /* Sargon */; }; 835F196D2B3581C300E0B71D /* UnknownDappComponents+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 835F196C2B3581C300E0B71D /* UnknownDappComponents+View.swift */; }; 8370FC5C2B99C780007AD882 /* NPSSurveyClient+Interface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8370FC5B2B99C780007AD882 /* NPSSurveyClient+Interface.swift */; }; 8381C8B02BBD2CD400A470B4 /* TokenPriceCientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8381C8AF2BBD2CD400A470B4 /* TokenPriceCientTests.swift */; }; @@ -843,6 +844,7 @@ 839B6C542B21D28400402651 /* ExpandableTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 839B6C532B21D28400402651 /* ExpandableTextView.swift */; }; 83AAAC6D2B483D1B00222B64 /* StakeSummaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83AAAC6B2B483D1B00222B64 /* StakeSummaryView.swift */; }; 83B783562C1764AE00AA7930 /* Sargon in Frameworks */ = {isa = PBXBuildFile; productRef = 83B783552C1764AE00AA7930 /* Sargon */; }; + 83D3F3C32D15C9CA00CA976D /* Sargon in Frameworks */ = {isa = PBXBuildFile; productRef = 83D3F3C22D15C9CA00CA976D /* Sargon */; }; 83D663B02B271D0100D1AB9E /* TruncationMask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83D663AF2B271D0100D1AB9E /* TruncationMask.swift */; }; 83D908AD2C931A7100822CC4 /* SargonSecureStorageDriver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83D908AC2C931A7100822CC4 /* SargonSecureStorageDriver.swift */; }; 83DFAF2E2B4E8A51008B70CE /* View+Extra.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83DFAF2D2B4E8A51008B70CE /* View+Extra.swift */; }; @@ -2568,6 +2570,7 @@ 48FFFAAB2ADC1FE900B2B213 /* DependenciesAdditions in Frameworks */, 48FFFAA22ADC1F5D00B2B213 /* Algorithms in Frameworks */, 48FFFAC12ADC20C400B2B213 /* JSONPreview in Frameworks */, + 83D3F3C32D15C9CA00CA976D /* Sargon in Frameworks */, 48FFFADB2ADC21E400B2B213 /* SwiftLogConsoleColors in Frameworks */, 48FFFADE2ADC21F500B2B213 /* FileLogging in Frameworks */, 48FFFACF2ADC216400B2B213 /* CollectionConcurrencyKit in Frameworks */, @@ -2585,6 +2588,7 @@ 5B1C4FD52BBB0B0C00B9436F /* AppsFlyerLib-Strict in Frameworks */, 48FFFB032ADC6F8100B2B213 /* Builders in Frameworks */, 48FFFAB72ADC207B00B2B213 /* NavigationTransitions in Frameworks */, + 835DFF932D19855A00229DB0 /* Sargon in Frameworks */, 5B634A942C91D2A0004B2FBC /* ScreenshotPreventing in Frameworks */, 48FFFA992ADC1EEC00B2B213 /* AsyncExtensions in Frameworks */, 83B783562C1764AE00AA7930 /* Sargon in Frameworks */, @@ -7107,6 +7111,8 @@ 5B634A932C91D2A0004B2FBC /* ScreenshotPreventing */, 5B447E0A2CAAFC2D0063AE39 /* Sargon */, 5B4E1D1E2CB7FE8E002FAC2E /* Sargon */, + 83D3F3C22D15C9CA00CA976D /* Sargon */, + 835DFF922D19855A00229DB0 /* Sargon */, ); productName = RadixWallet; productReference = 48CFBC4F2ADC106300E77A5C /* Radix Wallet Dev.app */; @@ -7177,7 +7183,7 @@ 8318BB172BC8403800057BCB /* XCRemoteSwiftPackageReference "swift-custom-dump" */, E6A0B0492BF23C7000617DAC /* XCRemoteSwiftPackageReference "swift-identified-collections" */, 5B634A922C91D2A0004B2FBC /* XCRemoteSwiftPackageReference "ScreenshotPreventing-iOS" */, - E775A1BC2CFA04B100E72DB9 /* XCRemoteSwiftPackageReference "sargon" */, + 835DFF912D19855A00229DB0 /* XCRemoteSwiftPackageReference "sargon" */, ); productRefGroup = 48CFBC502ADC106300E77A5C /* Products */; projectDirPath = ""; @@ -9266,6 +9272,14 @@ version = 1.3.0; }; }; + 835DFF912D19855A00229DB0 /* XCRemoteSwiftPackageReference "sargon" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/radixdlt/sargon"; + requirement = { + kind = exactVersion; + version = 1.1.96; + }; + }; A415574E2B757C5E0040AD4E /* XCRemoteSwiftPackageReference "swift-composable-architecture" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/pointfreeco/swift-composable-architecture"; @@ -9290,14 +9304,6 @@ version = 1.0.2; }; }; - E775A1BC2CFA04B100E72DB9 /* XCRemoteSwiftPackageReference "sargon" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/radixdlt/sargon"; - requirement = { - kind = exactVersion; - version = 1.1.71; - }; - }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -9506,10 +9512,19 @@ isa = XCSwiftPackageProductDependency; productName = Sargon; }; + 835DFF922D19855A00229DB0 /* Sargon */ = { + isa = XCSwiftPackageProductDependency; + package = 835DFF912D19855A00229DB0 /* XCRemoteSwiftPackageReference "sargon" */; + productName = Sargon; + }; 83B783552C1764AE00AA7930 /* Sargon */ = { isa = XCSwiftPackageProductDependency; productName = Sargon; }; + 83D3F3C22D15C9CA00CA976D /* Sargon */ = { + isa = XCSwiftPackageProductDependency; + productName = Sargon; + }; A415574F2B757C5E0040AD4E /* ComposableArchitecture */ = { isa = XCSwiftPackageProductDependency; package = A415574E2B757C5E0040AD4E /* XCRemoteSwiftPackageReference "swift-composable-architecture" */; diff --git a/RadixWallet.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/RadixWallet.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 89523bfc31..c18d9683e2 100644 --- a/RadixWallet.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/RadixWallet.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "7d3590b225945abb1bc0ab6c684b005c28c64bdc204afcc2d34c3e379ef8a3c8", + "originHash" : "4eb650ade57061cd1cf989ce8f615547774e9303f591ff57a76f3f2c04cdbd07", "pins" : [ { "identity" : "anycodable", @@ -114,8 +114,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/radixdlt/sargon", "state" : { - "revision" : "df3c55dc134a9f87848ef0470f1702b304739719", - "version" : "1.1.71" + "revision" : "2f610dafec01e66542d6902f02aeffda83dbc7cd", + "version" : "1.1.96" } }, { diff --git a/RadixWallet/Clients/AccountPortfoliosClient/AccountPortfoliosClient+State.swift b/RadixWallet/Clients/AccountPortfoliosClient/AccountPortfoliosClient+State.swift index d35d495a95..4e710baf96 100644 --- a/RadixWallet/Clients/AccountPortfoliosClient/AccountPortfoliosClient+State.swift +++ b/RadixWallet/Clients/AccountPortfoliosClient/AccountPortfoliosClient+State.swift @@ -51,6 +51,11 @@ extension AccountPortfoliosClient { return modified } + + /// Returns if the original account (which doesn't remove the hidden resources) contains any asset + var containsAnyAsset: Bool { + originalAccount.containsAnyAsset + } } /// Internal state that holds all loaded portfolios. @@ -266,9 +271,6 @@ extension ResourceAmount { case var .atLeast(exactAmount): exactAmount.fiatWorth = change(resourceAddress, exactAmount) self = .atLeast(exactAmount) - case var .atMost(exactAmount): - exactAmount.fiatWorth = change(resourceAddress, exactAmount) - self = .atMost(exactAmount) case var .between(minExactAmount, maxExactAmount): minExactAmount.fiatWorth = change(resourceAddress, minExactAmount) maxExactAmount.fiatWorth = change(resourceAddress, maxExactAmount) diff --git a/RadixWallet/Clients/CloudBackupClient/CloudBackupClient+Live.swift b/RadixWallet/Clients/CloudBackupClient/CloudBackupClient+Live.swift index 92e7c49301..a5d38d3f25 100644 --- a/RadixWallet/Clients/CloudBackupClient/CloudBackupClient+Live.swift +++ b/RadixWallet/Clients/CloudBackupClient/CloudBackupClient+Live.swift @@ -174,7 +174,7 @@ extension CloudBackupClient { guard shouldBackUp || timeToCheckIfClaimed else { return } let shouldReclaim: Bool - if let backedUpID = backedUpHeader?.lastUsedOnDevice.id, await !profileStore.isThisDevice(deviceID: backedUpID) { + if let backedUpID = backedUpHeader?.lastUsedOnDevice.id, SargonOS.shared.hostId().id != backedUpID { let action = await overlayWindowClient.scheduleFullScreen(.init(root: .claimWallet(.init()))) switch action { case .claimWallet(.transferBack): diff --git a/RadixWallet/Clients/DeviceFactorSourceClient/DeviceFactorSourceClient+Interface.swift b/RadixWallet/Clients/DeviceFactorSourceClient/DeviceFactorSourceClient+Interface.swift index 830a921e5b..758f4cadfa 100644 --- a/RadixWallet/Clients/DeviceFactorSourceClient/DeviceFactorSourceClient+Interface.swift +++ b/RadixWallet/Clients/DeviceFactorSourceClient/DeviceFactorSourceClient+Interface.swift @@ -128,12 +128,7 @@ extension DeviceFactorSourceClient { switch signerEntity.securityState { case let .unsecured(control): - let factorInstance = switch purpose { - case .signAuth: - control.authenticationSigning ?? control.transactionSigning - case .signTransaction, .signPreAuthorization: - control.transactionSigning - } + let factorInstance = control.transactionSigning guard let deviceFactorSource = try await factorSourcesClient.getDeviceFactorSource(of: factorInstance) @@ -180,12 +175,7 @@ extension DeviceFactorSourceClient { switch entity.securityState { case let .unsecured(unsecuredControl): - let factorInstance = switch purpose { - case .signAuth: - unsecuredControl.authenticationSigning ?? unsecuredControl.transactionSigning - case .signTransaction, .signPreAuthorization: - unsecuredControl.transactionSigning - } + let factorInstance = unsecuredControl.transactionSigning let derivationPath = factorInstance.derivationPath diff --git a/RadixWallet/Clients/FactorSourcesClient/FactorSourcesClient+Live.swift b/RadixWallet/Clients/FactorSourcesClient/FactorSourcesClient+Live.swift index 3207f1bba9..d0296e90b9 100644 --- a/RadixWallet/Clients/FactorSourcesClient/FactorSourcesClient+Live.swift +++ b/RadixWallet/Clients/FactorSourcesClient/FactorSourcesClient+Live.swift @@ -370,12 +370,7 @@ func signingFactors( switch entity.securityState { case let .unsecured(unsecuredEntityControl): - let factorInstance = switch signingPurpose { - case .signAuth: - unsecuredEntityControl.authenticationSigning ?? unsecuredEntityControl.transactionSigning - case .signTransaction, .signPreAuthorization: - unsecuredEntityControl.transactionSigning - } + let factorInstance = unsecuredEntityControl.transactionSigning let id = factorInstance.factorSourceID guard let factorSource = allFactorSources[id: id.asGeneral] else { diff --git a/RadixWallet/Clients/OnLedgerEntitiesClient/Helpers/OnLedgerEntitiesClient+CreateEntity.swift b/RadixWallet/Clients/OnLedgerEntitiesClient/Helpers/OnLedgerEntitiesClient+CreateEntity.swift index 95a36f7860..c67b8e76de 100644 --- a/RadixWallet/Clients/OnLedgerEntitiesClient/Helpers/OnLedgerEntitiesClient+CreateEntity.swift +++ b/RadixWallet/Clients/OnLedgerEntitiesClient/Helpers/OnLedgerEntitiesClient+CreateEntity.swift @@ -562,7 +562,7 @@ extension OnLedgerEntitiesClient { struct OwnedResourcePoolDetails: Hashable, Sendable { let address: PoolAddress let dAppName: String? - let poolUnitResource: ResourceWithVaultAmount + var poolUnitResource: ResourceWithVaultAmount var xrdResource: ResourceWithRedemptionValue? var nonXrdResources: [ResourceWithRedemptionValue] diff --git a/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Live.swift b/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Live.swift index 26695f55c6..b3e44d90fb 100644 --- a/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Live.swift +++ b/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Live.swift @@ -16,7 +16,7 @@ extension PreAuthorizationClient: DependencyKey { notaryPublicKey: Sargon.PublicKey.ed25519(request.notaryPublicKey.intoSargon()) ) } catch { - throw PreAuthorizationFailure.failedToGetPreview(.failedToAnalyse(error)) + throw TransactionFailure.fromCommonError(error as? CommonError) } } diff --git a/RadixWallet/Clients/ProfileStore/ProfileStore.swift b/RadixWallet/Clients/ProfileStore/ProfileStore.swift index 2c778f7b65..df12b5e130 100644 --- a/RadixWallet/Clients/ProfileStore/ProfileStore.swift +++ b/RadixWallet/Clients/ProfileStore/ProfileStore.swift @@ -60,16 +60,6 @@ extension ProfileStore { } } -extension ProfileStore { - func isThisDevice(deviceID: DeviceID) async -> Bool { - guard let hostId = try? await SargonOS.shared.resolveHostId().id else { - return false - } - - return hostId == deviceID - } -} - // MARK: Public extension ProfileStore { /// Mutates the in-memory copy of the Profile usung `transform`, and saves a diff --git a/RadixWallet/Clients/TransactionClient/TransactionClient+Live.swift b/RadixWallet/Clients/TransactionClient/TransactionClient+Live.swift index 74e83326e9..dbd737c9b3 100644 --- a/RadixWallet/Clients/TransactionClient/TransactionClient+Live.swift +++ b/RadixWallet/Clients/TransactionClient/TransactionClient+Live.swift @@ -368,12 +368,20 @@ extension TransactionFailure { case .FailedToExtractTransactionReceiptBytes: .failedToPrepareTXReview(.failedToExtractTXReceiptBytes) + case let .ExecutionSummaryFail(underlying): + .failedToPrepareTXReview(.failedTXPreview(underlying)) + + case let .FailedToGenerateManifestSummary(underlying): + .failedToPrepareTXReview(.failedTXPreview(underlying)) + + case let .InvalidInstructionsString(underlying): + .failedToPrepareTXReview(.failedTXPreview(underlying)) + + case let .some(err): + .failedToPrepareTXReview(.failedTXPreview(errorMessageFromError(error: err))) + default: - if let code = commonError?.errorCode { - .failedToPrepareTXReview(.failedTXPreview("Unknown reason, code: \(code)")) - } else { - .failedToPrepareTXReview(.failedTXPreview("Unknown reason")) - } + .failedToPrepareTXReview(.failedTXPreview("Unknown reason")) } } } diff --git a/RadixWallet/Clients/TransportProfileClient/TransportProfileClient+Live.swift b/RadixWallet/Clients/TransportProfileClient/TransportProfileClient+Live.swift index 4383b19933..d6e51e8d1a 100644 --- a/RadixWallet/Clients/TransportProfileClient/TransportProfileClient+Live.swift +++ b/RadixWallet/Clients/TransportProfileClient/TransportProfileClient+Live.swift @@ -12,10 +12,11 @@ extension TransportProfileClient: DependencyKey { return Self( importProfile: { profile, factorSourceIDs, skippedMainBdfs, containsP2PLinks in do { + try await profileStore.importProfile(profile, skippedMainBdfs: skippedMainBdfs) + let profile = await profileStore.profile() if profile.appPreferences.security.isCloudProfileSyncEnabled { try? await cloudBackupClient.claimProfileOnICloud(profile) } - try await profileStore.importProfile(profile, skippedMainBdfs: skippedMainBdfs) userDefaults.setShowRelinkConnectorsAfterProfileRestore(containsP2PLinks) } catch { // Revert the saved mnemonic diff --git a/RadixWallet/Core/SharedModels/Assets/ResourceAmount.swift b/RadixWallet/Core/SharedModels/Assets/ResourceAmount.swift index 00042e8146..28d7703bfc 100644 --- a/RadixWallet/Core/SharedModels/Assets/ResourceAmount.swift +++ b/RadixWallet/Core/SharedModels/Assets/ResourceAmount.swift @@ -4,7 +4,6 @@ import Sargon enum ResourceAmount: Sendable, Hashable, Codable { case exact(ExactResourceAmount) case atLeast(ExactResourceAmount) - case atMost(ExactResourceAmount) case between(minimum: ExactResourceAmount, maximum: ExactResourceAmount) case predicted(predicted: ExactResourceAmount, guaranteed: ExactResourceAmount) case unknown @@ -15,13 +14,14 @@ enum ResourceAmount: Sendable, Hashable, Codable { self = .exact(amount) case let .atLeast(amount): self = .atLeast(.init(nominalAmount: amount)) - case let .atMost(amount): - self = .atMost(.init(nominalAmount: amount)) case let .between(minAmount, maxAmount): self = .between( minimum: .init(nominalAmount: minAmount), maximum: .init(nominalAmount: maxAmount) ) + case .atMost: + // AtMost is considered unknown in the Wallet as per https://radixdlt.atlassian.net/browse/ABW-4040 + self = .unknown case .unknownAmount: self = .unknown } @@ -59,14 +59,21 @@ extension ResourceAmount { } } + var guaranteedAmount: ExactResourceAmount? { + switch self { + case let .predicted(_, amount): + amount + default: + nil + } + } + func adjustedNominalAmount(_ adjust: (Decimal192) -> Decimal192) -> Self { switch self { case let .exact(amount): return .exact(adjust(amount.nominalAmount)) case let .atLeast(amount): return .atLeast(.init(nominalAmount: adjust(amount.nominalAmount))) - case let .atMost(amount): - return .atMost(.init(nominalAmount: adjust(amount.nominalAmount))) case let .between(minAmount, maxAmount): let min = adjust(minAmount.nominalAmount) let max = adjust(maxAmount.nominalAmount) @@ -85,6 +92,14 @@ extension ResourceAmount { return .unknown } } + + mutating func setGuaranteedAmount(_ newGuaranteed: Decimal192) { + guard case let .predicted(predicted, _) = self else { + return + } + + self = .predicted(predicted: predicted, guaranteed: .init(nominalAmount: newGuaranteed)) + } } // MARK: CustomDebugStringConvertible @@ -95,8 +110,6 @@ extension ResourceAmount: CustomDebugStringConvertible { amount.nominalAmount.formatted() case let .atLeast(amount): "At least \(amount.nominalAmount.formatted())" - case let .atMost(amount): - "No more than \(amount.nominalAmount.formatted())" case let .between(minAmount, maxAmount): "Min: \(minAmount.nominalAmount.formatted()); Max: \(maxAmount.nominalAmount.formatted())" case let .predicted(predicted, guaranteed): diff --git a/RadixWallet/Features/AccountPreferencesFeature/Children/DeleteAccount/DeleteAccountConfirmation+Reducer.swift b/RadixWallet/Features/AccountPreferencesFeature/Children/DeleteAccount/DeleteAccountConfirmation+Reducer.swift index fed075409c..0c8746376a 100644 --- a/RadixWallet/Features/AccountPreferencesFeature/Children/DeleteAccount/DeleteAccountConfirmation+Reducer.swift +++ b/RadixWallet/Features/AccountPreferencesFeature/Children/DeleteAccount/DeleteAccountConfirmation+Reducer.swift @@ -16,7 +16,7 @@ struct DeleteAccountConfirmation: Sendable, FeatureReducer { @CasePathable enum InternalAction: Sendable, Equatable { - case fetchAccountPortfolioResult(TaskResult) + case fetchAccountPortfolioResult(TaskResult) case fetchReceivingAccounts case fetchReceivingAccountsResult(TaskResult<[State.ReceivingAccountCandidate]>) } @@ -44,7 +44,7 @@ struct DeleteAccountConfirmation: Sendable, FeatureReducer { state.footerButtonState = .loading(.local) return .run { [address = state.account.address] send in let result = await TaskResult { - try await accountPortfoliosClient.fetchAccountPortfolio(address, true).account + try await accountPortfoliosClient.fetchAccountPortfolio(address, true) } await send(.internal(.fetchAccountPortfolioResult(result))) } @@ -53,9 +53,9 @@ struct DeleteAccountConfirmation: Sendable, FeatureReducer { func reduce(into state: inout State, internalAction: InternalAction) -> Effect { switch internalAction { - case let .fetchAccountPortfolioResult(.success(account)): + case let .fetchAccountPortfolioResult(.success(portfolio)): state.footerButtonState = .enabled - return account.containsAnyAsset ? .send(.internal(.fetchReceivingAccounts)) : .send(.delegate(.deleteAccount)) + return portfolio.containsAnyAsset ? .send(.internal(.fetchReceivingAccounts)) : .send(.delegate(.deleteAccount)) case .fetchReceivingAccounts: return .run { send in diff --git a/RadixWallet/Features/AssetsFeature/Components/HelperViews/ResourceBalance/ResourceBalance.swift b/RadixWallet/Features/AssetsFeature/Components/HelperViews/ResourceBalance/ResourceBalance.swift index 14c322b7fd..434e19fa15 100644 --- a/RadixWallet/Features/AssetsFeature/Components/HelperViews/ResourceBalance/ResourceBalance.swift +++ b/RadixWallet/Features/AssetsFeature/Components/HelperViews/ResourceBalance/ResourceBalance.swift @@ -81,13 +81,13 @@ struct KnownResourceBalance: Sendable, Hashable { struct Fungible: Sendable, Hashable { let isXRD: Bool - let amount: ResourceAmount + var amount: ResourceAmount var guarantee: TransactionGuarantee? } struct LiquidStakeUnit: Sendable, Hashable { let resource: OnLedgerEntity.Resource - let amount: ResourceAmount + var amount: ResourceAmount let worth: ResourceAmount let validator: OnLedgerEntity.Validator var guarantee: TransactionGuarantee? @@ -109,7 +109,7 @@ struct KnownResourceBalance: Sendable, Hashable { } struct PoolUnit: Sendable, Hashable { - let details: OnLedgerEntitiesClient.OwnedResourcePoolDetails + var details: OnLedgerEntitiesClient.OwnedResourcePoolDetails var guarantee: TransactionGuarantee? } diff --git a/RadixWallet/Features/AssetsFeature/Components/HelperViews/ResourceBalance/ResourceBalanceView.swift b/RadixWallet/Features/AssetsFeature/Components/HelperViews/ResourceBalance/ResourceBalanceView.swift index d75992a88b..4eb5f131fb 100644 --- a/RadixWallet/Features/AssetsFeature/Components/HelperViews/ResourceBalance/ResourceBalanceView.swift +++ b/RadixWallet/Features/AssetsFeature/Components/HelperViews/ResourceBalance/ResourceBalanceView.swift @@ -517,12 +517,9 @@ extension ResourceBalanceView { } if case .unknown = amount { - StatusMessageView( - text: L10n.InteractionReview.Unknown.amount, - type: .warning, - useNarrowSpacing: true, - useSmallerFontSize: true - ) + Text(L10n.InteractionReview.Unknown.amount) + .textStyle(.body2HighImportance) + .foregroundStyle(.app.gray2) } } } @@ -566,12 +563,9 @@ extension ResourceBalanceView { } if case .unknown = amount { - StatusMessageView( - text: L10n.InteractionReview.Unknown.amount, - type: .warning, - useNarrowSpacing: true, - useSmallerFontSize: true - ) + Text(L10n.InteractionReview.Unknown.amount) + .textStyle(.body2HighImportance) + .foregroundStyle(.app.gray2) } } } @@ -653,13 +647,6 @@ extension ResourceBalanceView { appearance: appearance, symbol: symbol ) - case let .atMost(exactAmount): - SubAmountView( - title: L10n.InteractionReview.noMoreThan, - amount: exactAmount, - appearance: appearance, - symbol: symbol - ) case let .between(minAmount, maxAmount): VStack(alignment: alignment, spacing: .small3) { SubAmountView( diff --git a/RadixWallet/Features/ClaimWallet/ClaimWallet+Reducer.swift b/RadixWallet/Features/ClaimWallet/ClaimWallet+Reducer.swift index a865ee2c19..e14cabb5ea 100644 --- a/RadixWallet/Features/ClaimWallet/ClaimWallet+Reducer.swift +++ b/RadixWallet/Features/ClaimWallet/ClaimWallet+Reducer.swift @@ -1,6 +1,7 @@ import ComposableArchitecture import SwiftUI +// MARK: - ClaimWallet @Reducer struct ClaimWallet: Sendable, FeatureReducer { @ObservableState @@ -10,6 +11,9 @@ struct ClaimWallet: Sendable, FeatureReducer { isLoading ? .loading(.global(text: nil)) : .enabled } + @Presents + var destination: Destination.State? = nil + init() {} } @@ -26,24 +30,74 @@ struct ClaimWallet: Sendable, FeatureReducer { case transferBack } + struct Destination: DestinationReducer { + @CasePathable + enum State: Sendable, Hashable { + case confirmReset(AlertState) + } + + @CasePathable + enum Action: Sendable, Hashable { + case confirmReset(ConfirmReset) + + enum ConfirmReset: Sendable, Hashable { + case confirm + } + } + + var body: some Reducer { + EmptyReducer() + } + } + @Dependency(\.resetWalletClient) var resetWalletClient init() {} - var body: some ReducerOf { + var body: some ReducerOf { Reduce(core) + .ifLet(destinationPath, action: /Action.destination) { + Destination() + } } + private let destinationPath: WritableKeyPath> = \.$destination + func reduce(into state: inout State, viewAction: ViewAction) -> Effect { switch viewAction { case .clearWalletButtonTapped: + state.destination = Destination.confirmResetState + return .none + + case .transferBackButtonTapped: + return .send(.delegate(.transferBack)) + } + } + + func reduce(into state: inout State, presentedAction: Destination.Action) -> Effect { + switch presentedAction { + case .confirmReset(.confirm): state.isLoading = true return .run { send in await resetWalletClient.resetWallet() await send(.delegate(.didClearWallet)) } - case .transferBackButtonTapped: - return .send(.delegate(.transferBack)) } } } + +extension ClaimWallet.Destination { + static let confirmResetState: State = .confirmReset(.init( + title: { + TextState(L10n.FactoryReset.Dialog.title) + }, + actions: { + ButtonState(role: .destructive, action: .confirm) { + TextState(L10n.Common.confirm) + } + }, + message: { + TextState(L10n.FactoryReset.Dialog.message) + } + )) +} diff --git a/RadixWallet/Features/ClaimWallet/ClaimWallet+View.swift b/RadixWallet/Features/ClaimWallet/ClaimWallet+View.swift index d26e85bfd4..2a95a84db8 100644 --- a/RadixWallet/Features/ClaimWallet/ClaimWallet+View.swift +++ b/RadixWallet/Features/ClaimWallet/ClaimWallet+View.swift @@ -29,20 +29,20 @@ extension ClaimWallet { .foregroundColor(.app.gray2) .textStyle(.secondaryHeader) .multilineTextAlignment(.center) - .padding(.bottom, .medium1) + .padding(.bottom, .small1) Text(L10n.ConfigurationBackup.Automated.walletTransferredExplanation1 + "\n\n" + L10n.ConfigurationBackup.Automated.walletTransferredExplanation2) .textStyle(.body1Regular) .multilineTextAlignment(.center) + .padding(.bottom, .small1) Spacer() - VStack { - Button(L10n.ConfigurationBackup.Automated.walletTransferredClearButton) { + VStack(spacing: .medium1) { + Button(L10n.FactoryReset.resetWallet) { store.send(.view(.clearWalletButtonTapped)) } - .buttonStyle(.primaryRectangular) - .padding(.bottom, .small2) + .buttonStyle(.primaryRectangular(isDestructive: true)) Button(L10n.ConfigurationBackup.Automated.walletTransferredTransferBackButton) { store.send(.view(.transferBackButtonTapped)) @@ -50,10 +50,32 @@ extension ClaimWallet { .buttonStyle(.primaryText()) } } - .padding(.horizontal, .large1) + .padding(.horizontal, .medium3) .padding(.vertical, .medium3) .controlState(store.screenState) } + .destinations(with: store) + } + } +} + +private extension StoreOf { + var destination: PresentationStoreOf { + func scopeState(state: State) -> PresentationState { + state.$destination } + return scope(state: scopeState, action: Action.destination) + } +} + +@MainActor +private extension View { + func destinations(with store: StoreOf) -> some View { + let destination = store.destination + return confirmReset(with: destination) + } + + private func confirmReset(with destinationStore: PresentationStoreOf) -> some View { + alert(store: destinationStore.scope(state: \.confirmReset, action: \.confirmReset)) } } diff --git a/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift b/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift index 97907c07c0..499608077b 100644 --- a/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift +++ b/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift @@ -440,7 +440,7 @@ extension DappInteractionFlow { return continueEffect(for: &state) } - func handleSignAndSubmitTXFailed( + func handleTransactionFailure( _ error: TransactionFailure ) -> Effect { let (errorKind, message) = error.errorKindAndMessage @@ -520,13 +520,6 @@ extension DappInteractionFlow { return continueEffect(for: &state) } - func handlePreAuthorizationFailure( - _ error: PreAuthorizationFailure - ) -> Effect { - let (errorKind, message) = error.errorKindAndMessage - return dismissEffect(for: state, errorKind: errorKind, message: message) - } - let item = state.currentItem guard let action = childAction.action else { return .none } @@ -571,7 +564,7 @@ extension DappInteractionFlow { return .send(.delegate(.dismiss)) case let .reviewTransaction(.delegate(.failed(error))): - return handleSignAndSubmitTXFailed(error) + return handleTransactionFailure(error) case let .personaProofOfOwnership(.delegate(.provenPersonaOwnership(persona, challenge))): return handlePersonaProofOfOwnership(item, persona, challenge) @@ -591,7 +584,7 @@ extension DappInteractionFlow { return handlePreAuthorizationSignature(item, encoded) case let .preAuthorizationReview(.delegate(.failed(error))): - return handlePreAuthorizationFailure(error) + return handleTransactionFailure(error) default: return .none diff --git a/RadixWallet/Features/DebugInspectProfile/InspectProfile+View.swift b/RadixWallet/Features/DebugInspectProfile/InspectProfile+View.swift index a85414fa26..923de6c3ae 100644 --- a/RadixWallet/Features/DebugInspectProfile/InspectProfile+View.swift +++ b/RadixWallet/Features/DebugInspectProfile/InspectProfile+View.swift @@ -657,13 +657,6 @@ extension UnsecuredEntityControlView { factorInstance: unsecuredControl.transactionSigning, indentation: inOneLevel ) - if let authenticationSigning = unsecuredControl.authenticationSigning { - HierarchicalDeterministicFactorInstanceView( - description: "Auth Signing", - factorInstance: authenticationSigning, - indentation: inOneLevel - ) - } } } } diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections+ExecutionSummary.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+ExecutionSummary.swift index 49de0d814c..13841fc0d7 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections+ExecutionSummary.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections+ExecutionSummary.swift @@ -44,10 +44,6 @@ extension InteractionReview.Sections { return nil case .general, .transfer: - if summary.detailedManifestClass == .general { - guard !summary.deposits.isEmpty || !summary.withdrawals.isEmpty else { return nil } - } - let resourcesInfo = try await resourcesInfo(allAddresses.elements) let withdrawals = try await extractWithdrawals( accountWithdraws: summary.withdrawals, diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections+ManifestSummary.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+ManifestSummary.swift index 164e0ebb2d..6489f6a75c 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections+ManifestSummary.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections+ManifestSummary.swift @@ -2,6 +2,11 @@ import Sargon extension InteractionReview.Sections { func sections(for summary: ManifestSummary, networkID: NetworkID) async throws -> Common.SectionsData? { + /// Only GeneralSubintent classification is allowed for PreAuth transactions + guard summary.classification.first == .generalSubintent else { + return nil + } + let allWithdrawAddresses = summary.accountWithdrawals.values.flatMap { $0 }.map(\.resourceAddress) let allDepositAddresses = summary.accountDeposits.values.flatMap(\.specifiedResources).map(\.resourceAddress) diff --git a/RadixWallet/Features/OnboardingFeature/Coordinator/OnboardingCoordinator+Reducer.swift b/RadixWallet/Features/OnboardingFeature/Coordinator/OnboardingCoordinator+Reducer.swift index 17f2c9fd9c..f0217c40c4 100644 --- a/RadixWallet/Features/OnboardingFeature/Coordinator/OnboardingCoordinator+Reducer.swift +++ b/RadixWallet/Features/OnboardingFeature/Coordinator/OnboardingCoordinator+Reducer.swift @@ -111,6 +111,14 @@ struct OnboardingCoordinator: Sendable, FeatureReducer { _ = await radixConnectClient.loadP2PLinksAndConnectAll() } + case .createAccount(.delegate(.dismissed)): + return .run { _ in + // Clear out the ephemeral profile created on `setupNewUser` + try await SargonOS.shared.deleteWallet() + } catch: { error, _ in + errorQueue.schedule(error) + } + default: return .none } diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index 7edba2fef9..da5f73f011 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -45,7 +45,7 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { enum DelegateAction: Sendable, Equatable { case signedPreAuthorization(SignedSubintent) - case failed(PreAuthorizationFailure) + case failed(TransactionFailure) } struct Destination: DestinationReducer { @@ -117,12 +117,12 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { switch internalAction { case let .previewLoaded(.failure(error)): loggerGlobal.error("PreAuthroization preview failed, error: \(error)") - errorQueue.schedule(error) - guard let failure = error as? PreAuthorizationFailure else { - assertionFailure("Failed with unexpected error \(error)") - return .none + errorQueue.schedule(TransactionReviewFailure(underylying: error)) + if let txFailure = error as? TransactionFailure { + return .send(.delegate(.failed(txFailure))) + } else { + return .send(.delegate(.failed(TransactionFailure.failedToPrepareTXReview(.abortedTXReview(error))))) } - return .send(.delegate(.failed(failure))) case let .previewLoaded(.success(preview)): state.preview = preview diff --git a/RadixWallet/Features/SplashFeature/Splash.swift b/RadixWallet/Features/SplashFeature/Splash.swift index a9ed75041b..ba4fe2dab7 100644 --- a/RadixWallet/Features/SplashFeature/Splash.swift +++ b/RadixWallet/Features/SplashFeature/Splash.swift @@ -218,6 +218,7 @@ struct Splash: Sendable, FeatureReducer { drivers: .init( bundle: Bundle.main, userDefaultsSuite: UserDefaults.Dependency.radixSuiteName, + unsafeStorageKeyMapping: [:], secureStorageDriver: SargonSecureStorage() ) ) diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift index ce4076df6f..ce1f7e5d5c 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift @@ -599,21 +599,28 @@ extension ResourceBalance { } } set { + guard let newValue else { + return + } + switch self { case let .known(knownResourceBalance): switch knownResourceBalance.details { case var .fungible(fungible): fungible.guarantee = newValue + fungible.amount.setGuaranteedAmount(newValue.amount) var known = knownResourceBalance known.details = .fungible(fungible) self = .known(known) case var .liquidStakeUnit(liquidStakeUnit): liquidStakeUnit.guarantee = newValue + liquidStakeUnit.amount.setGuaranteedAmount(newValue.amount) var known = knownResourceBalance known.details = .liquidStakeUnit(liquidStakeUnit) self = .known(known) case var .poolUnit(poolUnit): poolUnit.guarantee = newValue + poolUnit.details.poolUnitResource.amount.setGuaranteedAmount(newValue.amount) var known = knownResourceBalance known.details = .poolUnit(poolUnit) self = .known(known) diff --git a/RadixWallet/SargonExtensions/SargonSecureStorageDriver.swift b/RadixWallet/SargonExtensions/SargonSecureStorageDriver.swift index f3064b96cd..3041abd894 100644 --- a/RadixWallet/SargonExtensions/SargonSecureStorageDriver.swift +++ b/RadixWallet/SargonExtensions/SargonSecureStorageDriver.swift @@ -61,6 +61,10 @@ final class SargonSecureStorage: SecureStorageDriver { } } + func containsDataForKey(key: SecureStorageKey) async throws -> Bool { + false + } + private func loadHostId() -> BagOfBytes? { let deviceInfo: DeviceInfo? = { if let existing = try? secureStorageClient.loadDeviceInfo() { diff --git a/RadixWalletTests/Clients/TransactionClientTests/TransactionClientTests.swift b/RadixWalletTests/Clients/TransactionClientTests/TransactionClientTests.swift index a39b88f16c..1395e4b66e 100644 --- a/RadixWalletTests/Clients/TransactionClientTests/TransactionClientTests.swift +++ b/RadixWalletTests/Clients/TransactionClientTests/TransactionClientTests.swift @@ -156,6 +156,8 @@ final class TransactionClientTests: TestCase { ) }))!] } + $0.secureStorageClient.saveDeviceInfo = { _ in } + $0.secureStorageClient.loadDeviceInfo = { nil } } operation: { try await TransactionClient.feePayerSelectionAmongstCandidates( request: .init( diff --git a/RadixWalletTests/Features/SplashFeatureTests/SplashFeatureTests.swift b/RadixWalletTests/Features/SplashFeatureTests/SplashFeatureTests.swift index c49119156d..74c304d615 100644 --- a/RadixWalletTests/Features/SplashFeatureTests/SplashFeatureTests.swift +++ b/RadixWalletTests/Features/SplashFeatureTests/SplashFeatureTests.swift @@ -30,6 +30,8 @@ final class SplashFeatureTests: TestCase { return .loaded(profile) } $0.userDefaults = userDefaults + $0.secureStorageClient.saveDeviceInfo = { _ in } + $0.secureStorageClient.loadDeviceInfo = { nil } } // when @@ -99,6 +101,9 @@ final class SplashFeatureTests: TestCase { $0.secureStorageClient.loadProfileSnapshotData = { _ in profile.jsonData() } + $0.secureStorageClient.saveDeviceInfo = { _ in } + $0.secureStorageClient.loadDeviceInfo = { nil } + $0.secureStorageClient.deprecatedLoadDeviceID = { nil } } // when diff --git a/RadixWalletTests/TestExtensions/TestUtils.swift b/RadixWalletTests/TestExtensions/TestUtils.swift index e565c65dbd..5c9cca2511 100644 --- a/RadixWalletTests/TestExtensions/TestUtils.swift +++ b/RadixWalletTests/TestExtensions/TestUtils.swift @@ -77,7 +77,7 @@ extension Profile { factorSourceId: privateHDFactorSource.factorSource.id, publicKey: .sample ), - authenticationSigning: nil + provisionalSecurifiedConfig: nil ) )