diff --git a/Kukai Mobile.xcodeproj/project.pbxproj b/Kukai Mobile.xcodeproj/project.pbxproj index b3f4768e..387e26cc 100644 --- a/Kukai Mobile.xcodeproj/project.pbxproj +++ b/Kukai Mobile.xcodeproj/project.pbxproj @@ -174,6 +174,7 @@ C050365D271ED8E600E7A664 /* Onboarding.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C050365F271ED8E600E7A664 /* Onboarding.storyboard */; }; C0503660271ED8F300E7A664 /* Home.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C0503662271ED8F300E7A664 /* Home.storyboard */; }; C0503663271ED8FD00E7A664 /* Send.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C0503665271ED8FD00E7A664 /* Send.storyboard */; }; + C051E2DE2D09B1E200DCA32E /* KukaiCoreSwift in Frameworks */ = {isa = PBXBuildFile; productRef = C051E2DD2D09B1E200DCA32E /* KukaiCoreSwift */; }; C05240A72770D6DA0031B5D1 /* KukaiCoreSwift in Frameworks */ = {isa = PBXBuildFile; productRef = C05240A62770D6DA0031B5D1 /* KukaiCoreSwift */; }; C05361BD277490FA002B51A4 /* UIApplication+extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C05361BC277490FA002B51A4 /* UIApplication+extensions.swift */; }; C053A57729EFFBA800FE1EC0 /* TitleSubtitleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C053A57629EFFBA800FE1EC0 /* TitleSubtitleCell.swift */; }; @@ -904,6 +905,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + C051E2DE2D09B1E200DCA32E /* KukaiCoreSwift in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2929,6 +2931,11 @@ package = C044B14D2CC7A4F100132B7F /* XCRemoteSwiftPackageReference "reown-swift" */; productName = ReownWalletKit; }; + C051E2DD2D09B1E200DCA32E /* KukaiCoreSwift */ = { + isa = XCSwiftPackageProductDependency; + package = C00B8B272770C874008E3878 /* XCRemoteSwiftPackageReference "kukai-core-swift" */; + productName = KukaiCoreSwift; + }; C05240A62770D6DA0031B5D1 /* KukaiCoreSwift */ = { isa = XCSwiftPackageProductDependency; package = C00B8B272770C874008E3878 /* XCRemoteSwiftPackageReference "kukai-core-swift" */; diff --git a/Kukai Mobile/Modules/Account/AccountViewModel.swift b/Kukai Mobile/Modules/Account/AccountViewModel.swift index 1812bd7b..5a2223cd 100644 --- a/Kukai Mobile/Modules/Account/AccountViewModel.swift +++ b/Kukai Mobile/Modules/Account/AccountViewModel.swift @@ -389,7 +389,7 @@ class AccountViewModel: ViewModel, UITableViewDiffableDataSourceHandler { /** 2. Suggested action, staking. Staking is important in order to secure the network and promote bakers who actively help the network */ - if currentAccount.availableBalance > XTZAmount(fromNormalisedAmount: 3) && (currentAccount.delegate == nil || currentAccount.xtzStakedBalance == .zero()) && DependencyManager.shared.selectedWalletMetadata?.isWatchOnly != true { + if currentAccount.availableBalance >= XTZAmount(fromNormalisedAmount: 3) && (currentAccount.delegate == nil || currentAccount.xtzStakedBalance == .zero()) && DependencyManager.shared.selectedWalletMetadata?.isWatchOnly != true { return .init(SuggestedActionData(image: UIImage(named: "Lock"), title: "Suggested Action", description: "Start staking to earn passive income, and participate in on-chain governance", segue: "stake-onboarding")) } diff --git a/Kukai Mobile/Modules/Stake/ChooseBakerConfirmViewController.swift b/Kukai Mobile/Modules/Stake/ChooseBakerConfirmViewController.swift index 5c6a0247..bec8c9de 100644 --- a/Kukai Mobile/Modules/Stake/ChooseBakerConfirmViewController.swift +++ b/Kukai Mobile/Modules/Stake/ChooseBakerConfirmViewController.swift @@ -218,10 +218,15 @@ class ChooseBakerConfirmViewController: SendAbstractConfirmViewController, Slide switch sendResult { case .success(let opHash): Logger.app.info("Sent: \(opHash)") + + let backupBakerInfoForStakeFlow = TransactionService.shared.delegateData.chosenBaker + self?.didSend = true self?.addPendingTransaction(opHash: opHash) self?.handleApproval(opHash: opHash, slideButton: self?.slideButton) + TransactionService.shared.stakeData.chosenBaker = backupBakerInfoForStakeFlow + case .failure(let sendError): self?.unblockInteraction() self?.slideButton?.resetSlider() diff --git a/Kukai MobileUITests/Tests/Test_04_Account.swift b/Kukai MobileUITests/Tests/Test_04_Account.swift index 46f2e0f0..2724ce7c 100644 --- a/Kukai MobileUITests/Tests/Test_04_Account.swift +++ b/Kukai MobileUITests/Tests/Test_04_Account.swift @@ -6,6 +6,7 @@ // import XCTest +import KukaiCryptoSwift final class Test_04_Account: XCTestCase { @@ -463,80 +464,67 @@ final class Test_04_Account: XCTestCase { let newPendingUnstakeCount = app.tables.cells.containing(.staticText, identifier: "pending-unstake-amount-label").count XCTAssert(newPendingUnstakeCount > initialPendingUnstakeCount, "\(newPendingUnstakeCount) > \(initialPendingUnstakeCount)") - - - - - - - - - /* + } + + public func testStakeOnboarding() { let app = XCUIApplication() Test_03_Home.handleLoginIfNeeded(app: app) + Test_04_Account.waitForInitalLoad(app: app) + Test_04_Account.createNewHDWalletAndSeedWithXTZ(app: app) - // Change baker - let tablesQuery = app.tables - tablesQuery.staticTexts["XTZ"].tap() - - let bakerButton = tablesQuery.buttons["token-detials-baker-button"] - let currentBakerName = bakerButton.label - - bakerButton.tap() sleep(2) + app.tables.staticTexts["Suggested Action"].tap() - app.tables.cells.containing(.staticText, identifier: "baker-list-name").element(boundBy: 2).tap() - sleep(2) + // Section 1 Start + SharedHelpers.shared.tapPrimaryButton(app: app) + sleep(1) + // Delegation info SharedHelpers.shared.tapPrimaryButton(app: app) - sleep(4) + sleep(1) + SharedHelpers.shared.tapPrimaryButton(app: app) + sleep(1) + SharedHelpers.shared.tapPrimaryButton(app: app) + sleep(1) + SharedHelpers.shared.tapPrimaryButton(app: app) + sleep(1) + // Choose Baker + SharedHelpers.shared.tapPrimaryButton(app: app) + sleep(1) + app.tables.staticTexts["Baking Benjamins"].tap() + app.buttons["Delegate"].tap() + SharedHelpers.shared.waitForStaticText("Confirm Delegate", exists: true, inElement: app, delay: 30) Test_04_Account.slideButtonToComplete(inApp: app) - sleep(2) - - Test_03_Home.waitForActivityAnimationTo(start: false, app: app, delay: 60) - sleep(2) - - // Check baker no longer matches - tablesQuery.staticTexts["XTZ"].tap() - XCTAssert(bakerButton.label != currentBakerName, bakerButton.label) - - - // Switch back to bestie, baking benjamins - bakerButton.tap() - sleep(2) + SharedHelpers.shared.waitForStaticText("Learn about staking", exists: true, inElement: app, delay: 60) - let name = "Baking Benjamins" - if app.tables.staticTexts[name].exists { - app.tables.staticTexts["Baking Benjamins"].tap() - } else { - app.tables.staticTexts["tz1YgDU...4jnD"].tap() - } - sleep(2) + // Section 2 start + SharedHelpers.shared.tapPrimaryButton(app: app) + sleep(1) + // Staking Info SharedHelpers.shared.tapPrimaryButton(app: app) - sleep(4) + sleep(1) + SharedHelpers.shared.tapPrimaryButton(app: app) + sleep(1) + // Stake + SharedHelpers.shared.tapPrimaryButton(app: app) + sleep(1) + app.textFields.firstMatch.tap() + SharedHelpers.shared.type(app: app, text: "1.5") + app.buttons["Review"].tap() + SharedHelpers.shared.waitForStaticText("Confirm Stake", exists: true, inElement: app, delay: 30) Test_04_Account.slideButtonToComplete(inApp: app) - sleep(2) + SharedHelpers.shared.waitForStaticText("Congratulations", exists: true, inElement: app, delay: 60) + SharedHelpers.shared.tapPrimaryButton(app: app) - Test_03_Home.waitForActivityAnimationTo(start: false, app: app, delay: 60) - sleep(2) - */ - } - - /* - public func testStakeOnboarding() { - // Go to sub account - // undelegate if delegated - // tap on "Suggested action" - // navigate through screens, complete baker selection - // complete stake - // unstake - - // ... how to deal with need to finalise? + // Confirm back home and values are correct + Test_04_Account.check(app: app, xtzBalanceIsNotZero: true) + Test_04_Account.check(app: app, xtzStakingBalanceIsNotZero: true) + + Test_05_WalletManagement.handleSwitchingTo(app: app, address: testConfig.walletAddress_HD.truncateTezosAddress()) } - */ // MARK: - Helpers @@ -597,6 +585,43 @@ final class Test_04_Account: XCTestCase { Test_03_Home.waitForActivityAnimationTo(start: false, app: app, delay: 60) } + public static func createNewHDWalletAndSeedWithXTZ(app: XCUIApplication) { + // Instead of creating a new HD wallet, which will cover the suggested action with backup warnings + // we can skip this step by instead importing a newly created Mnemonic instead + Test_03_Home.handleOpenWalletManagement(app: app) + Test_05_WalletManagement.addMore(app: app) + + let mnemonic = try? Mnemonic(numberOfWords: .twelve, in: .english) + let phrase = mnemonic?.words.joined(separator: " ") ?? "" + let currentWallet = Test_05_WalletManagement.addExisting(app: app, withMnemonic: phrase) + let addressOfNewWallet = app.tables.cells.containing(.staticText, identifier: "accounts-item-title").element(boundBy: 2).staticTexts["accounts-item-title"].label + + app.tables.staticTexts[currentWallet].tap() + + Test_04_Account.sendXTZ(app: app, amount: 3, to: addressOfNewWallet) + Test_05_WalletManagement.handleSwitchingTo(app: app, address: addressOfNewWallet) + } + + public static func sendXTZ(app: XCUIApplication, amount: Decimal, to: String) { + let testConfig: TestConfig = EnvironmentVariables.shared.config() + + let tablesQuery = app.tables + tablesQuery.staticTexts["XTZ"].tap() + tablesQuery.buttons["primary-button"].tap() + tablesQuery.staticTexts[to].tap() + + SharedHelpers.shared.type(app: app, text: amount.description) + + app.buttons["primary-button"].tap() + sleep(4) + + let feeAmount = SharedHelpers.getSanitizedDecimal(fromStaticText: "fee-amount", in: app) + Test_04_Account.slideButtonToComplete(inApp: app) + + sleep(2) + Test_03_Home.waitForActivityAnimationTo(start: false, app: app, delay: 60) + } + public static func check(app: XCUIApplication, estimatedTotalIs: String, fiatIs: String) { let estimatedXTZ = app.tables.staticTexts["account-total-xtz"].label let estimatedFiat = app.tables.staticTexts["account-total-fiat"].label @@ -635,6 +660,26 @@ final class Test_04_Account: XCTestCase { } } + public static func check(app: XCUIApplication, xtzStakingBalanceIsNotZero: Bool) { + let xtz = app.tables.staticTexts.matching(identifier: "account-token-balance").element(boundBy: 1).label + let fiat = app.staticTexts["account-token-fiat"].firstMatch.label + + let sanatisedXTZ = xtz.replacingOccurrences(of: ",", with: "") + var sanatisedFiat = fiat.replacingOccurrences(of: ",", with: "") + sanatisedFiat = String(sanatisedFiat.dropFirst()) + + let xtzDecimal = Decimal(string: sanatisedXTZ) ?? 0 + let fiatDecimal = Decimal(string: sanatisedFiat) ?? 0 + + if xtzStakingBalanceIsNotZero { + XCTAssert(xtzDecimal > 0, xtzDecimal.description) + XCTAssert(fiatDecimal > 0, fiatDecimal.description) + } else { + XCTAssert(xtzDecimal == 0) + XCTAssert(fiatDecimal == 0) + } + } + public static func check(app: XCUIApplication, estimatedTotalExists: Bool) { SharedHelpers.shared.waitForStaticText("account-total-xtz", exists: estimatedTotalExists, inElement: app.tables, delay: 2) } diff --git a/Kukai MobileUITests/Tests/Test_05_WalletManagement.swift b/Kukai MobileUITests/Tests/Test_05_WalletManagement.swift index 255e5320..af2bd768 100644 --- a/Kukai MobileUITests/Tests/Test_05_WalletManagement.swift +++ b/Kukai MobileUITests/Tests/Test_05_WalletManagement.swift @@ -35,7 +35,7 @@ final class Test_05_WalletManagement: XCTestCase { Test_03_Home.handleOpenWalletManagement(app: app) sleep(2) - app.tables.buttons["accounts-section-header-more"].tap() + app.tables.buttons["accounts-section-header-more"].firstMatch.tap() app.popovers.tables.staticTexts["Add Account"].tap() sleep(2) @@ -69,7 +69,7 @@ final class Test_05_WalletManagement: XCTestCase { } private func changeGroupName(to: String, inApp app: XCUIApplication) { - app.tables.buttons["accounts-section-header-more"].tap() + app.tables.buttons["accounts-section-header-more"].firstMatch.tap() app.popovers.tables.staticTexts["Edit Name"].tap() sleep(2) @@ -133,7 +133,7 @@ final class Test_05_WalletManagement: XCTestCase { let newExists = app.tables.staticTexts["NEW!"].exists let countOfNew = app.tables.staticTexts.matching(identifier: "NEW!").count - XCTAssert(count == 3) + XCTAssert(count == 4) XCTAssert(newExists) XCTAssert(countOfNew == 1) } @@ -246,6 +246,23 @@ final class Test_05_WalletManagement: XCTestCase { app.navigationBars.buttons["accounts-nav-add"].tap() } + public static func addExisting(app: XCUIApplication, withMnemonic: String) -> String { + app.tables.staticTexts["Add Existing Wallet"].tap() + app.tables.staticTexts["Restore with Recovery Phrase"].tap() + + sleep(2) + app.scrollViews.children(matching: .textView).element.tap() + sleep(2) + app.typeText(withMnemonic) + + SharedHelpers.shared.tapPrimaryButton(app: app) + + let mainWallet = EnvironmentVariables.shared.config().walletAddress_HD.truncateTezosAddress() + SharedHelpers.shared.waitForStaticText(mainWallet, exists: true, inElement: app.tables, delay: 30) + + return mainWallet + } + public static func handleSwitchingTo(app: XCUIApplication, address: String) { Test_03_Home.handleOpenWalletManagement(app: app) sleep(2)