Fixing my messed up merge 😢

pull/2/head
Michael Scoff 7 years ago
parent 7e37e291d4
commit cf0da3f3b0
  1. 48
      Trust.xcodeproj/project.pbxproj
  2. 28
      Trust/Accounts/Coordinators/AccountsCoordinator.swift
  3. 12
      Trust/Accounts/ViewModels/AccountViewModel.swift
  4. 36
      Trust/Accounts/ViewModels/AccountsViewController.swift
  5. 6
      Trust/Accounts/ViewModels/AccountsViewModel.swift
  6. 4
      Trust/Accounts/Views/AccountViewCell.swift
  7. 18
      Trust/AppCoordinator.swift
  8. 3
      Trust/AppDelegate.swift
  9. 21
      Trust/Assets.xcassets/mascot_happy.imageset/Contents.json
  10. BIN
      Trust/Assets.xcassets/mascot_happy.imageset/mascot_happy0.png
  11. 21
      Trust/Assets.xcassets/settings-share.imageset/Contents.json
  12. BIN
      Trust/Assets.xcassets/settings-share.imageset/settings-share.png
  13. 6
      Trust/Browser/Coordinators/BrowserCoordinator.swift
  14. 72
      Trust/Core/Coordinators/HelpUsCoordinator.swift
  15. 4
      Trust/Core/Initializers/MirgrationInitializer.swift
  16. 2
      Trust/Core/Initializers/TouchRegistrar.swift
  17. 54
      Trust/Core/Types/AppTracker.swift
  18. 2
      Trust/Core/Types/TrustRealmConfiguration.swift
  19. 65
      Trust/Core/ViewControllers/WellDoneViewController.swift
  20. 40
      Trust/Core/ViewModels/HelpUsViewModel.swift
  21. 4
      Trust/Deposit/Coordinators/DepositCoordinator.swift
  22. 4
      Trust/EtherClient/CoinMarket/Types/CoinTicker.swift
  23. 70
      Trust/EtherClient/EtherKeystore.swift
  24. 2
      Trust/EtherClient/ImportType.swift
  25. 12
      Trust/EtherClient/Keystore.swift
  26. 26
      Trust/EtherClient/TrustClient/TrustClient.swift
  27. 42
      Trust/EtherClient/Wallet.swift
  28. 69
      Trust/Exchange/Coordinators/ExchangeCoordinator.swift
  29. 27
      Trust/Export/Coordinators/BackupCoordinator.swift
  30. 79
      Trust/InCoordinator.swift
  31. 11
      Trust/Settings/Coordinators/ExchangeRateCoordinator.swift
  32. 10
      Trust/Settings/Coordinators/SettingsCoordinator.swift
  33. 1
      Trust/Settings/Types/Constants.swift
  34. 1
      Trust/Settings/Types/CurrencyRate.swift
  35. 2
      Trust/Settings/Types/RPCServers.swift
  36. 15
      Trust/Settings/ViewControllers/SettingsViewController.swift
  37. 28
      Trust/Tokens/Coordinators/TokensCoordinator.swift
  38. 18
      Trust/Tokens/Types/TokensDataStore.swift
  39. 4
      Trust/Tokens/ViewControllers/TokensViewController.swift
  40. 4
      Trust/Tokens/ViewModels/EditTokenTableCellViewModel.swift
  41. 2
      Trust/Tokens/ViewModels/TokensViewModel.swift
  42. 30
      Trust/Transactions/Coordinators/TransactionCoordinator.swift
  43. 4
      Trust/Transactions/Storage/Session.swift
  44. 11
      Trust/Transactions/ViewControllers/TransactionsViewController.swift
  45. 2
      Trust/Transactions/ViewModels/TransactionDetailsViewModel.swift
  46. 5
      Trust/Transfer/Controllers/TransactionConfigurator.swift
  47. 5
      Trust/Transfer/Coordinators/PaymentCoordinator.swift
  48. 6
      Trust/Transfer/Coordinators/SendCoordinator.swift
  49. 5
      Trust/Transfer/ViewControllers/SendViewController.swift
  50. 4
      Trust/Transfer/ViewModels/RequestViewModel.swift
  51. 4
      Trust/Wallet/Coordinators/InitialWalletCreationCoordinator.swift
  52. 146
      Trust/Wallet/Coordinators/OnePasswordCoordinator.swift
  53. 10
      Trust/Wallet/Coordinators/WalletCoordinator.swift
  54. 5
      Trust/Wallet/Types/ImportSelectionType.swift
  55. 55
      Trust/Wallet/ViewControllers/ImportWalletViewController.swift
  56. 15
      Trust/Wallet/ViewControllers/PassphraseViewController.swift
  57. 6
      TrustTests/Coordinators/AppCoordinatorTests.swift
  58. 48
      TrustTests/Coordinators/InCoordinatorTests.swift
  59. 2
      TrustTests/Coordinators/SendCoordinatorTests.swift
  60. 31
      TrustTests/Coordinators/TransactionCoordinatorTests.swift
  61. 5
      TrustTests/Coordinators/WalletCoordinatorTests.swift
  62. 22
      TrustTests/Core/Types/AppTrackerTests.swift
  63. 34
      TrustTests/EtherClient/EtherKeystoreTests.swift
  64. 30
      TrustTests/Factories/FakeKeystore.swift
  65. 14
      TrustTests/Factories/Wallet.swift
  66. 2
      TrustTests/Factories/WalletSession.swift
  67. 10
      TrustTests/Transfer/Controllers/TransactionConfiguratorTests.swift
  68. 4
      TrustTests/Transfer/ViewModels/RequestViewModelTests.swift
  69. 2
      TrustTests/ViewControllers/PaymentCoordinator.swift

@ -266,6 +266,14 @@
29F1C84A1FEB6D6B003780D8 /* EditTokenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29F1C8491FEB6D6B003780D8 /* EditTokenViewModel.swift */; };
29F1C84C1FEC4F6F003780D8 /* TokensFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29F1C84B1FEC4F6F003780D8 /* TokensFooterView.swift */; };
29F1C85120032688003780D8 /* Address.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29F1C85020032688003780D8 /* Address.swift */; };
29F1C853200363B2003780D8 /* PassphraseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29F1C852200363B2003780D8 /* PassphraseViewController.swift */; };
29F1C85620036887003780D8 /* AppTrackerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29F1C85520036887003780D8 /* AppTrackerTests.swift */; };
29F1C85820036926003780D8 /* AppTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29F1C85720036926003780D8 /* AppTracker.swift */; };
29F1C85A20036968003780D8 /* HelpUsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29F1C85920036968003780D8 /* HelpUsCoordinator.swift */; };
29F1C85D2003698A003780D8 /* WellDoneViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29F1C85C2003698A003780D8 /* WellDoneViewController.swift */; };
29F1C85F200369BA003780D8 /* HelpUsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29F1C85E200369BA003780D8 /* HelpUsViewModel.swift */; };
29F1C863200375D2003780D8 /* Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29F1C862200375D2003780D8 /* Wallet.swift */; };
29F1C865200384FE003780D8 /* Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29F1C864200384FE003780D8 /* Wallet.swift */; };
29FC0CB61F8298820036089F /* TransactionCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29FC0CB51F8298820036089F /* TransactionCoordinator.swift */; };
29FC0CB81F8299510036089F /* Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29FC0CB71F8299510036089F /* Coordinator.swift */; };
29FC9BC61F830899000209CD /* MirgrationInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29FC9BC51F830880000209CD /* MirgrationInitializer.swift */; };
@ -590,6 +598,14 @@
29F1C8491FEB6D6B003780D8 /* EditTokenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditTokenViewModel.swift; sourceTree = "<group>"; };
29F1C84B1FEC4F6F003780D8 /* TokensFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokensFooterView.swift; sourceTree = "<group>"; };
29F1C85020032688003780D8 /* Address.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Address.swift; sourceTree = "<group>"; };
29F1C852200363B2003780D8 /* PassphraseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PassphraseViewController.swift; sourceTree = "<group>"; };
29F1C85520036887003780D8 /* AppTrackerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppTrackerTests.swift; sourceTree = "<group>"; };
29F1C85720036926003780D8 /* AppTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppTracker.swift; sourceTree = "<group>"; };
29F1C85920036968003780D8 /* HelpUsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelpUsCoordinator.swift; sourceTree = "<group>"; };
29F1C85C2003698A003780D8 /* WellDoneViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WellDoneViewController.swift; sourceTree = "<group>"; };
29F1C85E200369BA003780D8 /* HelpUsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelpUsViewModel.swift; sourceTree = "<group>"; };
29F1C862200375D2003780D8 /* Wallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wallet.swift; sourceTree = "<group>"; };
29F1C864200384FE003780D8 /* Wallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wallet.swift; sourceTree = "<group>"; };
29FC0CB51F8298820036089F /* TransactionCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionCoordinator.swift; sourceTree = "<group>"; };
29FC0CB71F8299510036089F /* Coordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = "<group>"; };
29FC9BC51F830880000209CD /* MirgrationInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MirgrationInitializer.swift; sourceTree = "<group>"; };
@ -918,6 +934,7 @@
2923D9B41FDA4E07000CF3F8 /* PasswordGenerator.swift */,
61DCE17A2001A6BE0053939F /* RLP.swift */,
61C359DF2002AA590097B04D /* TransactionSigning.swift */,
29F1C862200375D2003780D8 /* Wallet.swift */,
);
path = EtherClient;
sourceTree = "<group>";
@ -988,6 +1005,7 @@
isa = PBXGroup;
children = (
2931120F1FC4ADCB00966EEA /* InCoordinatorViewModel.swift */,
29F1C85E200369BA003780D8 /* HelpUsViewModel.swift */,
);
path = ViewModels;
sourceTree = "<group>";
@ -1221,6 +1239,7 @@
isa = PBXGroup;
children = (
2912CD2E1F6A83A100C6CBE3 /* ImportWalletViewController.swift */,
29F1C852200363B2003780D8 /* PassphraseViewController.swift */,
);
path = ViewControllers;
sourceTree = "<group>";
@ -1639,6 +1658,7 @@
isa = PBXGroup;
children = (
29E9CFD11FE737FE00017744 /* TrustRealmConfiguration.swift */,
29F1C85720036926003780D8 /* AppTracker.swift */,
);
path = Types;
sourceTree = "<group>";
@ -1663,9 +1683,26 @@
path = Coordinators;
sourceTree = "<group>";
};
29F1C85420036879003780D8 /* Types */ = {
isa = PBXGroup;
children = (
29F1C85520036887003780D8 /* AppTrackerTests.swift */,
);
path = Types;
sourceTree = "<group>";
};
29F1C85B2003697E003780D8 /* ViewControllers */ = {
isa = PBXGroup;
children = (
29F1C85C2003698A003780D8 /* WellDoneViewController.swift */,
);
path = ViewControllers;
sourceTree = "<group>";
};
29FC9BC31F830880000209CD /* Core */ = {
isa = PBXGroup;
children = (
29F1C85B2003697E003780D8 /* ViewControllers */,
295B61D21FE7D5AB00642E60 /* Formatters */,
29E9CFD01FE737EE00017744 /* Types */,
CCA4FE341FD427CA00749AE4 /* Helpers */,
@ -1757,6 +1794,7 @@
CCA4FE391FD42B4100749AE4 /* FakeJailbreakChecker.swift */,
295B61D51FE7FC8300642E60 /* FakeTokensDataStore.swift */,
29BDF1951FEE43F40023A45F /* UnconfirmedTransaction.swift */,
29F1C864200384FE003780D8 /* Wallet.swift */,
);
path = Factories;
sourceTree = "<group>";
@ -1819,6 +1857,7 @@
CCA4FE301FD3652100749AE4 /* Core */ = {
isa = PBXGroup;
children = (
29F1C85420036879003780D8 /* Types */,
CCA4FE311FD3653300749AE4 /* Coordinators */,
);
path = Core;
@ -1845,6 +1884,7 @@
isa = PBXGroup;
children = (
CCCD74FC1FD2D38D004A087D /* CheckDeviceCoordinator.swift */,
29F1C85920036968003780D8 /* HelpUsCoordinator.swift */,
);
path = Coordinators;
sourceTree = "<group>";
@ -2272,6 +2312,7 @@
2963B6B11F9891F5003063C1 /* UIButton.swift in Sources */,
29F114F21FA7966300114A29 /* PrivateKeyRule.swift in Sources */,
296106C41F7640C50006164B /* TokenViewCellViewModel.swift in Sources */,
29F1C853200363B2003780D8 /* PassphraseViewController.swift in Sources */,
29B9345D1F88459C009FCABB /* SplashViewController.swift in Sources */,
29E2E33A1F7A008C000CF94A /* UIView.swift in Sources */,
299B5E491FD2C8900051361C /* ConfigureTransaction.swift in Sources */,
@ -2308,6 +2349,7 @@
615F10561FCBEF2E008A45AF /* OnboardingPageViewModel.swift in Sources */,
29E2E3411F7B1585000CF94A /* ActionButtonRow.swift in Sources */,
29FC0CB61F8298820036089F /* TransactionCoordinator.swift in Sources */,
29F1C85F200369BA003780D8 /* HelpUsViewModel.swift in Sources */,
290B2B5B1F8F551E0053C83E /* LokaliseInitializer.swift in Sources */,
293112371FC9A24600966EEA /* UIGestureRecognizer+Closure.swift in Sources */,
29B6AECB1F7C5FA900EC6DE3 /* PaymentCoordinator.swift in Sources */,
@ -2316,6 +2358,7 @@
2963B6B91F9A7EEA003063C1 /* CoinTicker.swift in Sources */,
29F114EC1FA448F400114A29 /* TokensCoordinator.swift in Sources */,
2932488E1F88E69F008A9818 /* OnePasswordError.swift in Sources */,
29F1C85820036926003780D8 /* AppTracker.swift in Sources */,
293E62711FA2F63500CB0A66 /* InitialWalletCreationCoordinator.swift in Sources */,
291D73C61F7F500D00A8AB56 /* TransactionItemState.swift in Sources */,
29BE3FD21F707DC300F6BFC2 /* TransactionDataCoordinator.swift in Sources */,
@ -2337,6 +2380,7 @@
29FC0CB81F8299510036089F /* Coordinator.swift in Sources */,
296106C61F7645CC0006164B /* TokensViewController.swift in Sources */,
29282B531F7630970067F88D /* Token.swift in Sources */,
29F1C85D2003698A003780D8 /* WellDoneViewController.swift in Sources */,
29E9CFCF1FE7347200017744 /* ERC20Token.swift in Sources */,
29C9F5FB1F720C050025C494 /* FloatLabelTextField.swift in Sources */,
293248861F88CCE6008A9818 /* SplashError.swift in Sources */,
@ -2392,6 +2436,7 @@
29CA4B791F6FBFD50032313D /* Balance.swift in Sources */,
291F52A71F6B766100B369AB /* BalanceRequest.swift in Sources */,
2932488A1F88D593008A9818 /* OnePasswordConfig.swift in Sources */,
29F1C85A20036968003780D8 /* HelpUsCoordinator.swift in Sources */,
29D72A2A1F6A8D1500CE9209 /* AppCoordinator.swift in Sources */,
290B2B671F9266630053C83E /* SettingsAction.swift in Sources */,
293E626F1FA2ED1400CB0A66 /* InCoordinator.swift in Sources */,
@ -2428,6 +2473,7 @@
2932488C1F88E689008A9818 /* OnePasswordConverter.swift in Sources */,
295996161FADAFE500DB66A8 /* TransactionAction.swift in Sources */,
299B5E291FCA8F040051361C /* GetERC20Balance.swift in Sources */,
29F1C863200375D2003780D8 /* Wallet.swift in Sources */,
29E6E06E1FE897EE0079265A /* BrowserViewController.swift in Sources */,
2912CCF91F6A830700C6CBE3 /* AppDelegate.swift in Sources */,
615F105D1FCBF55E008A45AF /* OnboardingCollectionViewController.swift in Sources */,
@ -2506,6 +2552,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
29F1C85620036887003780D8 /* AppTrackerTests.swift in Sources */,
29BDF19F1FEE51650023A45F /* GasLimitConfigurationTests.swift in Sources */,
290B2B6C1F92C35B0053C83E /* RPCServerTests.swift in Sources */,
29FF13031F75EB7500AFD326 /* Account.swift in Sources */,
@ -2513,6 +2560,7 @@
29BDF1941FEE43AA0023A45F /* TransactionConfiguratorTests.swift in Sources */,
29FF13081F75F0AE00AFD326 /* AppCoordinatorTests.swift in Sources */,
2923D9B71FDA5E51000CF3F8 /* PasswordGeneratorTests.swift in Sources */,
29F1C865200384FE003780D8 /* Wallet.swift in Sources */,
2912CD101F6A830700C6CBE3 /* TrustTests.swift in Sources */,
29FF130D1F7626E800AFD326 /* FakeNavigationController.swift in Sources */,
293112311FC971B600966EEA /* ExchangeTokensCoordinatorTests.swift in Sources */,

@ -6,9 +6,9 @@ import UIKit
protocol AccountsCoordinatorDelegate: class {
func didCancel(in coordinator: AccountsCoordinator)
func didSelectAccount(account: Account, in coordinator: AccountsCoordinator)
func didAddAccount(account: Account, in coordinator: AccountsCoordinator)
func didDeleteAccount(account: Account, in coordinator: AccountsCoordinator)
func didSelectAccount(account: Wallet, in coordinator: AccountsCoordinator)
func didAddAccount(account: Wallet, in coordinator: AccountsCoordinator)
func didDeleteAccount(account: Wallet, in coordinator: AccountsCoordinator)
}
class AccountsCoordinator: Coordinator {
@ -57,12 +57,15 @@ class AccountsCoordinator: Coordinator {
navigationController.present(coordinator.navigationController, animated: true, completion: nil)
}
func showInfoSheet(for account: Account, sender: UIView) {
func showInfoSheet(for account: Wallet, sender: UIView) {
let controller = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
controller.popoverPresentationController?.sourceView = sender
controller.popoverPresentationController?.sourceRect = sender.centerRect
let actionTitle = NSLocalizedString("wallets.backup.alertSheet.title", value: "Backup Keystore", comment: "The title of the backup button in the wallet's action sheet")
let action = UIAlertAction(title: actionTitle, style: .default) { _ in
switch account.type {
case .real(let account):
let backupKeystoreAction = UIAlertAction(title: actionTitle, style: .default) { _ in
let coordinator = BackupCoordinator(
navigationController: self.navigationController,
keystore: self.keystore,
@ -72,6 +75,11 @@ class AccountsCoordinator: Coordinator {
coordinator.start()
self.addCoordinator(coordinator)
}
controller.addAction(backupKeystoreAction)
case .watch:
break
}
let copyAction = UIAlertAction(
title: NSLocalizedString("Copy Address", value: "Copy Address", comment: ""),
style: .default
@ -79,7 +87,7 @@ class AccountsCoordinator: Coordinator {
UIPasteboard.general.string = account.address.address
}
let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel", value: "Cancel", comment: ""), style: .cancel) { _ in }
controller.addAction(action)
controller.addAction(copyAction)
controller.addAction(cancelAction)
navigationController.present(controller, animated: true, completion: nil)
@ -87,21 +95,21 @@ class AccountsCoordinator: Coordinator {
}
extension AccountsCoordinator: AccountsViewControllerDelegate {
func didSelectAccount(account: Account, in viewController: AccountsViewController) {
func didSelectAccount(account: Wallet, in viewController: AccountsViewController) {
delegate?.didSelectAccount(account: account, in: self)
}
func didDeleteAccount(account: Account, in viewController: AccountsViewController) {
func didDeleteAccount(account: Wallet, in viewController: AccountsViewController) {
delegate?.didDeleteAccount(account: account, in: self)
}
func didSelectInfoForAccount(account: Account, sender: UIView, in viewController: AccountsViewController) {
func didSelectInfoForAccount(account: Wallet, sender: UIView, in viewController: AccountsViewController) {
showInfoSheet(for: account, sender: sender)
}
}
extension AccountsCoordinator: WalletCoordinatorDelegate {
func didFinish(with account: Account, in coordinator: WalletCoordinator) {
func didFinish(with account: Wallet, in coordinator: WalletCoordinator) {
delegate?.didAddAccount(account: account, in: self)
accountsViewController.fetch()
coordinator.navigationController.dismiss(animated: true, completion: nil)

@ -6,16 +6,16 @@ import UIKit
struct AccountViewModel {
let account: Account
let current: Account?
let wallet: Wallet
let current: Wallet?
init(account: Account, current: Account?) {
self.account = account
init(wallet: Wallet, current: Wallet?) {
self.wallet = wallet
self.current = current
}
var title: String {
return account.address.address
return wallet.address.address
}
var image: UIImage? {
@ -26,6 +26,6 @@ struct AccountViewModel {
}
var isActive: Bool {
return account == current
return wallet == current
}
}

@ -4,9 +4,9 @@ import TrustKeystore
import UIKit
protocol AccountsViewControllerDelegate: class {
func didSelectAccount(account: Account, in viewController: AccountsViewController)
func didDeleteAccount(account: Account, in viewController: AccountsViewController)
func didSelectInfoForAccount(account: Account, sender: UIView, in viewController: AccountsViewController)
func didSelectAccount(account: Wallet, in viewController: AccountsViewController)
func didDeleteAccount(account: Wallet, in viewController: AccountsViewController)
func didSelectInfoForAccount(account: Wallet, sender: UIView, in viewController: AccountsViewController)
}
class AccountsViewController: UITableViewController {
@ -18,15 +18,15 @@ class AccountsViewController: UITableViewController {
var viewModel: AccountsViewModel {
return AccountsViewModel(
accounts: accounts
wallets: wallets
)
}
var hasAccounts: Bool {
return !accounts.isEmpty
var hasWallets: Bool {
return !keystore.wallets.isEmpty
}
var accounts: [Account] = [] {
var wallets: [Wallet] = [] {
didSet {
tableView.reloadData()
configure(viewModel: viewModel)
@ -50,17 +50,15 @@ class AccountsViewController: UITableViewController {
}
func fetch() {
accounts = keystore.accounts.map {
Account(address: $0.address)
}
wallets = keystore.wallets
}
func configure(viewModel: AccountsViewModel) {
title = headerTitle ?? viewModel.title
}
func account(for indexPath: IndexPath) -> Account {
return viewModel.accounts[indexPath.row]
func account(for indexPath: IndexPath) -> Wallet {
return viewModel.wallets[indexPath.row]
}
override func numberOfSections(in tableView: UITableView) -> Int {
@ -68,19 +66,19 @@ class AccountsViewController: UITableViewController {
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.accounts.count
return viewModel.wallets.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let account = self.account(for: indexPath)
let cell = AccountViewCell(style: .default, reuseIdentifier: AccountViewCell.identifier)
cell.viewModel = AccountViewModel(account: account, current: EtherKeystore.current)
cell.viewModel = AccountViewModel(wallet: account, current: EtherKeystore.current)
cell.delegate = self
return cell
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return allowsAccountDeletion && (EtherKeystore.current != viewModel.accounts[indexPath.row] || viewModel.accounts.count == 1)
return allowsAccountDeletion && (EtherKeystore.current != viewModel.wallets[indexPath.row] || viewModel.wallets.count == 1)
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
@ -97,7 +95,7 @@ class AccountsViewController: UITableViewController {
delegate?.didSelectAccount(account: account, in: self)
}
func confirmDelete(account: Account) {
func confirmDelete(account: Wallet) {
confirm(
title: "Are you sure you would like to delete this wallet?",
message: "Make sure you have backup of your wallet",
@ -112,8 +110,8 @@ class AccountsViewController: UITableViewController {
}
}
func delete(account: Account) {
let result = self.keystore.delete(account: account)
func delete(account: Wallet) {
let result = self.keystore.delete(wallet: account)
switch result {
case .success:
self.fetch()
@ -129,7 +127,7 @@ class AccountsViewController: UITableViewController {
}
extension AccountsViewController: AccountViewCellDelegate {
func accountViewCell(_ cell: AccountViewCell, didTapInfoViewForAccount account: Account) {
func accountViewCell(_ cell: AccountViewCell, didTapInfoViewForAccount account: Wallet) {
self.delegate?.didSelectInfoForAccount(account: account, sender: cell.infoButton, in: self)
}
}

@ -5,10 +5,10 @@ import TrustKeystore
struct AccountsViewModel {
let accounts: [Account]
let wallets: [Wallet]
init(accounts: [Account]) {
self.accounts = accounts
init(wallets: [Wallet]) {
self.wallets = wallets
}
var title: String {

@ -4,7 +4,7 @@ import TrustKeystore
import UIKit
protocol AccountViewCellDelegate: class {
func accountViewCell(_ cell: AccountViewCell, didTapInfoViewForAccount _: Account)
func accountViewCell(_ cell: AccountViewCell, didTapInfoViewForAccount _: Wallet)
}
class AccountViewCell: UITableViewCell {
@ -70,7 +70,7 @@ class AccountViewCell: UITableViewCell {
}
@objc private func didTapInfoButton(sender: UIButton) {
guard let account = viewModel?.account else {
guard let account = viewModel?.wallet else {
return
}
delegate?.accountViewCell(self, didTapInfoViewForAccount: account)

@ -21,6 +21,7 @@ class AppCoordinator: NSObject, Coordinator {
let pushNotificationRegistrar = PushNotificationsRegistrar()
private var keystore: Keystore
private var appTracker = AppTracker()
var coordinators: [Coordinator] = []
@ -38,24 +39,25 @@ class AppCoordinator: NSObject, Coordinator {
func start() {
inializers()
appTracker.start()
handleNotifications()
applyStyle()
resetToWelcomeScreen()
if keystore.hasAccounts {
showTransactions(for: keystore.recentlyUsedAccount ?? keystore.accounts.first!)
if keystore.hasWallets {
showTransactions(for: keystore.recentlyUsedWallet ?? keystore.wallets.first!)
} else {
resetToWelcomeScreen()
}
pushNotificationRegistrar.reRegister()
}
func showTransactions(for account: Account) {
func showTransactions(for wallet: Wallet) {
let coordinator = InCoordinator(
navigationController: navigationController,
account: account,
keystore: keystore
wallet: wallet,
keystore: keystore,
appTracker: appTracker
)
coordinator.delegate = self
coordinator.start()
@ -93,7 +95,7 @@ class AppCoordinator: NSObject, Coordinator {
func didRegisterForRemoteNotificationsWithDeviceToken(deviceToken: Data) {
pushNotificationRegistrar.didRegister(
with: deviceToken,
addresses: keystore.accounts.map { $0.address }
addresses: keystore.wallets.map { $0.address }
)
}
@ -125,7 +127,7 @@ extension AppCoordinator: InitialWalletCreationCoordinatorDelegate {
removeCoordinator(coordinator)
}
func didAddAccount(_ account: Account, in coordinator: InitialWalletCreationCoordinator) {
func didAddAccount(_ account: Wallet, in coordinator: InitialWalletCreationCoordinator) {
coordinator.navigationController.dismiss(animated: true, completion: nil)
removeCoordinator(coordinator)
showTransactions(for: account)

@ -6,9 +6,10 @@ import Lokalise
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDelegate {
private let window: UIWindow? = UIWindow()
var window: UIWindow?
var coordinator: AppCoordinator!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
do {
let keystore = try EtherKeystore()
coordinator = AppCoordinator(window: window!, keystore: keystore)

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "mascot_happy0.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "settings-share.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -36,10 +36,13 @@ class BrowserCoordinator: Coordinator {
extension BrowserCoordinator: BrowserViewControllerDelegate {
func didCall(action: DappAction) {
switch session.account.type {
case .real(let account):
switch action {
case .signTransaction(let unconfirmedTransaction):
let configurator = TransactionConfigurator(
session: session,
account: account,
transaction: unconfirmedTransaction,
gasPrice: .none
)
@ -57,6 +60,9 @@ extension BrowserCoordinator: BrowserViewControllerDelegate {
case .sign, .unknown:
break
}
case .watch: break
}
}
}

@ -0,0 +1,72 @@
// Copyright SIX DAY LLC. All rights reserved.
import Foundation
import UIKit
import StoreKit
class HelpUsCoordinator: Coordinator {
let navigationController: UINavigationController
let appTracker: AppTracker
var coordinators: [Coordinator] = []
private let viewModel = HelpUsViewModel()
init(
navigationController: UINavigationController = NavigationController(),
appTracker: AppTracker = AppTracker()
) {
self.navigationController = navigationController
self.navigationController.modalPresentationStyle = .formSheet
self.appTracker = appTracker
}
func start() {
switch appTracker.launchCountForCurrentBuild {
case 5 where !appTracker.completedRating:
rateUs()
case 10 where !appTracker.completedSharing:
wellDone()
default: break
}
}
func rateUs() {
if #available(iOS 10.3, *) { SKStoreReviewController.requestReview() } else {
UIApplication.shared.openURL(URL(string: "itms-apps://itunes.apple.com/app/id1288339409")!)
}
appTracker.completedRating = true
}
private func wellDone() {
let controller = WellDoneViewController()
controller.navigationItem.title = viewModel.title
controller.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(dismiss))
controller.delegate = self
let nav = NavigationController(rootViewController: controller)
navigationController.present(nav, animated: true, completion: nil)
}
@objc private func dismiss() {
navigationController.dismiss(animated: true, completion: nil)
}
func presentSharing(in viewController: UIViewController, from sender: UIView) {
let activityViewController = UIActivityViewController(
activityItems: viewModel.activityItems,
applicationActivities: nil
)
activityViewController.popoverPresentationController?.sourceView = sender
activityViewController.popoverPresentationController?.sourceRect = sender.centerRect
viewController.present(activityViewController, animated: true, completion: nil)
}
}
extension HelpUsCoordinator: WellDoneViewControllerDelegate {
func didPress(action: WellDoneAction, sender: UIView, in viewController: WellDoneViewController) {
switch action {
case .other:
presentSharing(in: viewController, from: sender)
}
appTracker.completedSharing = true
}
}

@ -6,11 +6,11 @@ import TrustKeystore
class MigrationInitializer: Initializer {
let account: Account
let account: Wallet
let chainID: Int
init(
account: Account, chainID: Int
account: Wallet, chainID: Int
) {
self.account = account
self.chainID = chainID

@ -19,7 +19,7 @@ class TouchRegistrar {
}
func register() {
if !keystore.hasAccounts {
if !keystore.hasWallets {
unregister()
}

@ -0,0 +1,54 @@
// Copyright SIX DAY LLC. All rights reserved.
import Foundation
class AppTracker {
struct Keys {
static let launchCountTotal = "launchCountTotal"
static let launchCountForCurrentBuild = "launchCountForCurrentBuild-" + String(Bundle.main.buildNumberInt)
static let completedSharing = "completedSharing"
static let completedRating = "completedRating"
}
let defaults: UserDefaults
var launchCountTotal: Int {
get { return defaults.integer(forKey: Keys.launchCountTotal) }
set { return defaults.set(newValue, forKey: Keys.launchCountTotal) }
}
var launchCountForCurrentBuild: Int {
get { return defaults.integer(forKey: Keys.launchCountForCurrentBuild) }
set { return defaults.set(newValue, forKey: Keys.launchCountForCurrentBuild) }
}
var completedRating: Bool {
get { return defaults.bool(forKey: Keys.completedRating) }
set { return defaults.set(newValue, forKey: Keys.completedRating) }
}
var completedSharing: Bool {
get { return defaults.bool(forKey: Keys.completedSharing) }
set { return defaults.set(newValue, forKey: Keys.completedSharing) }
}
init(
defaults: UserDefaults = .standard
) {
self.defaults = defaults
}
func start() {
launchCountTotal += launchCountTotal
launchCountForCurrentBuild += 1
}
var description: String {
return """
launchCountTotal: \(launchCountTotal)
launchCountForCurrentBuild: \(launchCountForCurrentBuild)
completedRating: \(completedRating)
completedSharing: \(completedSharing)
"""
}
}

@ -6,7 +6,7 @@ import TrustKeystore
struct RealmConfiguration {
static func configuration(for account: Account, chainID: Int) -> Realm.Configuration {
static func configuration(for account: Wallet, chainID: Int) -> Realm.Configuration {
var config = Realm.Configuration()
config.fileURL = config.fileURL!.deletingLastPathComponent().appendingPathComponent("\(account.address.address)-\(chainID).realm")
return config

@ -0,0 +1,65 @@
// Copyright SIX DAY LLC. All rights reserved.
import UIKit
enum WellDoneAction {
case other
}
protocol WellDoneViewControllerDelegate: class {
func didPress(action: WellDoneAction, sender: UIView, in viewController: WellDoneViewController)
}
class WellDoneViewController: UIViewController {
weak var delegate: WellDoneViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
let imageView = UIImageView(image: R.image.mascot_happy())
imageView.translatesAutoresizingMaskIntoConstraints = false
let descriptionLabel = UILabel()
descriptionLabel.translatesAutoresizingMaskIntoConstraints = false
descriptionLabel.text = NSLocalizedString("welldone.description.label.text", value: "Help us grow by sharing this app with your friends!", comment: "")
descriptionLabel.font = UIFont.systemFont(ofSize: 16, weight: .regular)
descriptionLabel.textColor = Colors.blue
descriptionLabel.numberOfLines = 0
descriptionLabel.textAlignment = .center
let otherButton = Button(size: .normal, style: .solid)
otherButton.translatesAutoresizingMaskIntoConstraints = false
otherButton.setTitle(NSLocalizedString("welldone.share.label.text", value: "Share", comment: ""), for: .normal)
otherButton.addTarget(self, action: #selector(other(_:)), for: .touchUpInside)
let stackView = UIStackView(arrangedSubviews: [
imageView,
//titleLabel,
descriptionLabel,
.spacer(height: 10),
.spacer(),
otherButton,
])
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.alignment = .center
stackView.axis = .vertical
stackView.spacing = 10
view.backgroundColor = .white
view.addSubview(stackView)
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(greaterThanOrEqualTo: view.topAnchor),
stackView.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: view.readableContentGuide.trailingAnchor),
stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
stackView.bottomAnchor.constraint(lessThanOrEqualTo: view.bottomAnchor),
otherButton.widthAnchor.constraint(equalToConstant: 240),
])
}
@objc private func other(_ sender: UIView) {
delegate?.didPress(action: .other, sender: sender, in: self)
}
}

@ -0,0 +1,40 @@
// Copyright SIX DAY LLC. All rights reserved.
import Foundation
import UIKit
struct HelpUsViewModel {
var title: String {
return NSLocalizedString("welldone.navigation.title", value: "Thank you!", comment: "")
}
private let sharingText: [String] = [
NSLocalizedString(
"welldone.viewmodel.sharing.text1",
value: "Here is the app I use to store my ETH and ERC20 tokens.",
comment: ""
),
NSLocalizedString(
"welldone.viewmodel.sharing.text2",
value: "Check out Trust - the wallet that lets me securely store my Ethereum and ERC20 tokens.",
comment: ""
),
NSLocalizedString(
"welldone.viewmodel.sharing.text3",
value: "I securely store Ethereum and ERC20 tokens in the Trust wallet",
comment: ""
),
NSLocalizedString(
"welldone.viewmodel.sharing.text4",
value: "I secure my Ethereum and ERC20 tokens in the Trust wallet.",
comment: ""
),
]
var activityItems: [Any] {
return [
sharingText[Int(arc4random_uniform(UInt32(sharingText.count)))],
URL(string: Constants.website)!,
]
}
}

@ -7,12 +7,12 @@ import UIKit
class DepositCoordinator: Coordinator {
let navigationController: UINavigationController
let account: Account
let account: Wallet
var coordinators: [Coordinator] = []
init(
navigationController: UINavigationController,
account: Account
account: Wallet
) {
self.navigationController = navigationController
self.account = account

@ -4,16 +4,18 @@ import Foundation
import RealmSwift
struct CoinTicker: Codable {
let id: String
let name: String
let symbol: String
let price: String
let percent_change_24h: String
let contract: String
static let tokenLogoPath = "https://files.coinmarketcap.com/static/img/coins/128x128/"
}
extension CoinTicker {
var imageURL: URL? {
return URL(string: CoinTicker.tokenLogoPath + name.lowercased() + ".png")
return URL(string: CoinTicker.tokenLogoPath + id + ".png")
}
}

@ -15,6 +15,7 @@ open class EtherKeystore: Keystore {
struct Keys {
static let recentlyUsedAddress: String = "recentlyUsedAddress"
static let watchAddresses = "watchAddresses"
}
private let keychain: KeychainSwift
@ -36,23 +37,34 @@ open class EtherKeystore: Keystore {
self.keyStore = try KeyStore(keydir: URL(fileURLWithPath: keydir))
}
var hasAccounts: Bool {
return !accounts.isEmpty
var hasWallets: Bool {
return !wallets.isEmpty
}
var recentlyUsedAccount: Account? {
var watchAddresses: [String] {
set {
let data = NSKeyedArchiver.archivedData(withRootObject: newValue)
keychain.set(data, forKey: Keys.watchAddresses)
}
get {
guard let data = keychain.getData(Keys.watchAddresses) else { return [] }
return NSKeyedUnarchiver.unarchiveObject(with: data) as? [String] ?? []
}
}
var recentlyUsedWallet: Wallet? {
set {
keychain.set(newValue?.address.address ?? "", forKey: Keys.recentlyUsedAddress, withAccess: defaultKeychainAccess)
}
get {
let address = keychain.get(Keys.recentlyUsedAddress)
return accounts.filter { $0.address.address == address }.first
return wallets.filter { $0.address.address == address }.first
}
}
static var current: Account? {
static var current: Wallet? {
do {
return try EtherKeystore().recentlyUsedAccount
return try EtherKeystore().recentlyUsedWallet
} catch {
return .none
}
@ -69,30 +81,45 @@ open class EtherKeystore: Keystore {
}
}
func importWallet(type: ImportType, completion: @escaping (Result<Account, KeystoreError>) -> Void) {
func importWallet(type: ImportType, completion: @escaping (Result<Wallet, KeystoreError>) -> Void) {
let newPassword = PasswordGenerator.generateRandom()
switch type {
case .keystore(let string, let password):
importKeystore(
value: string,
password: password,
newPassword: newPassword,
completion: completion
)
newPassword: newPassword
) { result in
switch result {
case .success(let account):
completion(.success(Wallet(type: .real(account))))
case .failure(let error):
completion(.failure(error))
}
}
case .privateKey(let privateKey):
self.keystore(for: privateKey, password: newPassword) { result in
keystore(for: privateKey, password: newPassword) { result in
switch result {
case .success(let value):
self.importKeystore(
value: value,
password: newPassword,
newPassword: newPassword,
completion: completion
)
newPassword: newPassword
) { result in
switch result {
case .success(let account):
completion(.success(Wallet(type: .real(account))))
case .failure(let error):
completion(.failure(error))
}
}
case .failure(let error):
completion(.failure(error))
}
}
case .watch(let address):
self.watchAddresses = [watchAddresses, [address.address]].flatMap { $0 }
completion(.success(Wallet(type: .watch(address))))
}
}
@ -150,8 +177,11 @@ open class EtherKeystore: Keystore {
}
}
var accounts: [Account] {
return keyStore.accounts
var wallets: [Wallet] {
return [
keyStore.accounts.map { Wallet(type: .real($0)) },
watchAddresses.map { Wallet(type: .watch(Address(string: $0))) },
].flatMap { $0 }
}
func export(account: Account, password: String, newPassword: String) -> Result<String, KeystoreError> {
@ -178,7 +208,9 @@ open class EtherKeystore: Keystore {
}
}
func delete(account: Account) -> Result<Void, KeystoreError> {
func delete(wallet: Wallet) -> Result<Void, KeystoreError> {
switch wallet.type {
case .real(let account):
guard let account = getAccount(for: account.address) else {
return .failure(.accountNotFound)
}
@ -193,6 +225,10 @@ open class EtherKeystore: Keystore {
} catch {
return .failure(.failedToDeleteAccount)
}
case .watch(let address):
watchAddresses = watchAddresses.filter { $0 != address.address }
return .success(())
}
}
func updateAccount(account: Account, password: String, newPassword: String) -> Result<Void, KeystoreError> {

@ -1,8 +1,10 @@
// Copyright SIX DAY LLC. All rights reserved.
import Foundation
import TrustKeystore
enum ImportType {
case keystore(string: String, password: String)
case privateKey(privateKey: String)
case watch(address: Address)
}

@ -5,20 +5,20 @@ import Result
import TrustKeystore
protocol Keystore {
var hasAccounts: Bool { get }
var accounts: [Account] { get }
var recentlyUsedAccount: Account? { get set }
static var current: Account? { get }
var hasWallets: Bool { get }
var wallets: [Wallet] { get }
var recentlyUsedWallet: Wallet? { get set }
static var current: Wallet? { get }
@available(iOS 10.0, *)
func createAccount(with password: String, completion: @escaping (Result<Account, KeystoreError>) -> Void)
func importWallet(type: ImportType, completion: @escaping (Result<Account, KeystoreError>) -> Void)
func importWallet(type: ImportType, completion: @escaping (Result<Wallet, KeystoreError>) -> Void)
func keystore(for privateKey: String, password: String, completion: @escaping (Result<String, KeystoreError>) -> Void)
func importKeystore(value: String, password: String, newPassword: String, completion: @escaping (Result<Account, KeystoreError>) -> Void)
func createAccout(password: String) -> Account
func importKeystore(value: String, password: String, newPassword: String) -> Result<Account, KeystoreError>
func export(account: Account, password: String, newPassword: String) -> Result<String, KeystoreError>
func exportData(account: Account, password: String, newPassword: String) -> Result<Data, KeystoreError>
func delete(account: Account) -> Result<Void, KeystoreError>
func delete(wallet: Wallet) -> Result<Void, KeystoreError>
func updateAccount(account: Account, password: String, newPassword: String) -> Result<Void, KeystoreError>
func signTransaction(_ signTransaction: SignTransaction) -> Result<Data, KeystoreError>
func getPassword(for account: Account) -> String?

@ -4,13 +4,23 @@ import Foundation
import Moya
enum TrustService {
case prices(currency: Currency, symbols: [String])
case prices(TokensPrice)
case getTransactions(address: String, startBlock: Int)
case getTransaction(ID: String)
case register(device: PushDevice)
case unregister(device: PushDevice)
}
struct TokensPrice: Encodable {
let currency: String
let tokens: [TokenPrice]
}
struct TokenPrice: Encodable {
let contract: String
let symbol: String
}
extension TrustService: TargetType {
var baseURL: URL { return Config().remoteURL }
@ -26,7 +36,7 @@ extension TrustService: TargetType {
case .unregister:
return "/push/unregister"
case .prices:
return "/prices"
return "/tokenPrices"
}
}
@ -36,7 +46,7 @@ extension TrustService: TargetType {
case .getTransaction: return .get
case .register: return .post
case .unregister: return .delete
case .prices: return .get
case .prices: return .post
}
}
@ -50,14 +60,8 @@ extension TrustService: TargetType {
return .requestJSONEncodable(device)
case .unregister(let device):
return .requestJSONEncodable(device)
case .prices(let currency, let symbols):
return .requestParameters(
parameters: [
"currency": currency.rawValue,
"symbols": symbols.joined(separator: ","),
],
encoding:URLEncoding.queryString
)
case .prices(let tokensPrice):
return .requestJSONEncodable(tokensPrice)
}
}

@ -0,0 +1,42 @@
// Copyright SIX DAY LLC. All rights reserved.
import Foundation
import TrustKeystore
enum WalletType {
case real(Account)
case watch(Address)
}
extension WalletType: Equatable {
static func == (lhs: WalletType, rhs: WalletType) -> Bool {
switch (lhs, rhs) {
case (let .real(lhs), let .real(rhs)):
return lhs == rhs
case (let .watch(lhs), let .watch(rhs)):
return lhs == rhs
case (.real, .watch),
(.watch, .real):
return false
}
}
}
struct Wallet {
let type: WalletType
var address: Address {
switch type {
case .real(let account):
return account.address
case .watch(let address):
return address
}
}
}
extension Wallet: Equatable {
static func == (lhs: Wallet, rhs: Wallet) -> Bool {
return lhs.type == rhs.type
}
}

@ -13,7 +13,7 @@ class ExchangeCoordinator: Coordinator {
let controller = ExchangeViewController(
session: self.session
)
controller.delegate = self
//controller.delegate = self
return controller
}()
var coordinators: [Coordinator] = []
@ -35,37 +35,38 @@ class ExchangeCoordinator: Coordinator {
}
}
extension ExchangeCoordinator: ExchangeViewControllerDelegate {
func didPress(from: SubmitExchangeToken, to: SubmitExchangeToken, in viewController: ExchangeViewController) {
//extension ExchangeCoordinator: ExchangeViewControllerDelegate {
// func didPress(from: SubmitExchangeToken, to: SubmitExchangeToken, in viewController: ExchangeViewController) {
//
// let transaction = UnconfirmedTransaction(
// transferType: .exchange(from: from, to: to),
// value: from.amount,
// address: to.token.address,
// account: session.account,
// chainID: session.config.chainID,
// data: Data()
// )
//
// let configurator = TransactionConfigurator(
// session: session,
// transaction: transaction,
// gasPrice: .none
// )
//
// let controller = ConfirmPaymentViewController(
// session: session,
// keystore: keystore,
// configurator: configurator
// )
// controller.delegate = self
// navigationController.pushViewController(controller, animated: true)
// }
//}
//
//extension ExchangeCoordinator: ConfirmPaymentViewControllerDelegate {
// func didCompleted(transaction: SentTransaction, in viewController: ConfirmPaymentViewController) {
// navigationController.popViewController(animated: true)
// navigationController.displaySuccess(title: "Exchanged completed. Transaction ID: (\(transaction.id)")
// }
//}
let transaction = UnconfirmedTransaction(
transferType: .exchange(from: from, to: to),
value: from.amount,
address: to.token.address,
account: session.account,
chainID: session.config.chainID,
data: Data()
)
let configurator = TransactionConfigurator(
session: session,
transaction: transaction,
gasPrice: .none
)
let controller = ConfirmPaymentViewController(
session: session,
keystore: keystore,
configurator: configurator
)
controller.delegate = self
navigationController.pushViewController(controller, animated: true)
}
}
extension ExchangeCoordinator: ConfirmPaymentViewControllerDelegate {
func didCompleted(transaction: SentTransaction, in viewController: ConfirmPaymentViewController) {
navigationController.popViewController(animated: true)
navigationController.displaySuccess(title: "Exchanged completed. Transaction ID: (\(transaction.id)")
}
}

@ -4,6 +4,7 @@ import Foundation
import UIKit
import Result
import TrustKeystore
import Result
protocol BackupCoordinatorDelegate: class {
func didCancel(coordinator: BackupCoordinator)
@ -32,15 +33,16 @@ class BackupCoordinator: Coordinator {
export(for: account)
}
func finish(completed: Bool) {
if completed {
func finish(result: Result<Bool, AnyError>) {
switch result {
case .success:
delegate?.didFinish(account: account, in: self)
} else {
case .failure:
delegate?.didCancel(coordinator: self)
}
}
func presentActivityViewController(for account: Account, password: String, newPassword: String, completion: @escaping (Bool) -> Void) {
func presentActivityViewController(for account: Account, password: String, newPassword: String, completion: @escaping (Result<Bool, AnyError>) -> Void) {
let result = keystore.export(account: account, password: password, newPassword: newPassword)
navigationController.displayLoading(
@ -49,12 +51,21 @@ class BackupCoordinator: Coordinator {
switch result {
case .success(let value):
let url = URL(fileURLWithPath: NSTemporaryDirectory().appending("trust_wallet_\(account.address.address).json"))
do {
try value.data(using: .utf8)!.write(to: url)
} catch {
return completion(.failure(AnyError(error)))
}
let activityViewController = UIActivityViewController(
activityItems: [value],
activityItems: [url],
applicationActivities: nil
)
activityViewController.completionWithItemsHandler = { _, result, _, _ in
completion(result)
do { try FileManager.default.removeItem(at: url)
} catch { }
completion(.success(result))
}
activityViewController.popoverPresentationController?.sourceView = navigationController.view
activityViewController.popoverPresentationController?.sourceRect = navigationController.view.centerRect
@ -68,8 +79,8 @@ class BackupCoordinator: Coordinator {
}
func presentShareActivity(for account: Account, password: String, newPassword: String) {
self.presentActivityViewController(for: account, password: password, newPassword: newPassword) { completed in
self.finish(completed: completed)
self.presentActivityViewController(for: account, password: password, newPassword: newPassword) { result in
self.finish(result: result)
}
}

@ -9,36 +9,60 @@ protocol InCoordinatorDelegate: class {
func didUpdateAccounts(in coordinator: InCoordinator)
}
enum InCoordinatorError: LocalizedError {
case onlyWatchAccount
var errorDescription: String? {
return NSLocalizedString(
"InCoordinatorError.onlyWatchAccount",
value: "This wallet could be only used for watching. Import Private Key/Keystore to sign transactions",
comment: ""
)
}
}
class InCoordinator: Coordinator {
let navigationController: UINavigationController
var coordinators: [Coordinator] = []
let initialAccount: Account
let initialWallet: Wallet
var keystore: Keystore
var config: Config
let appTracker: AppTracker
weak var delegate: InCoordinatorDelegate?
var transactionCoordinator: TransactionCoordinator? {
return self.coordinators.flatMap { $0 as? TransactionCoordinator }.first
}
lazy var helpUsCoordinator: HelpUsCoordinator = {
return HelpUsCoordinator(
navigationController: navigationController,
appTracker: appTracker
)
}()
init(
navigationController: UINavigationController = NavigationController(),
account: Account,
wallet: Wallet,
keystore: Keystore,
config: Config = Config()
config: Config = Config(),
appTracker: AppTracker = AppTracker()
) {
self.navigationController = navigationController
self.initialAccount = account
self.initialWallet = wallet
self.keystore = keystore
self.config = config
self.appTracker = appTracker
}
func start() {
showTabBar(for: initialAccount)
showTabBar(for: initialWallet)
checkDevice()
helpUsCoordinator.start()
addCoordinator(helpUsCoordinator)
}
func showTabBar(for account: Account) {
func showTabBar(for account: Wallet) {
let session = WalletSession(
account: account,
config: config
@ -128,7 +152,7 @@ class InCoordinator: Coordinator {
navigationController.setNavigationBarHidden(true, animated: false)
addCoordinator(transactionCoordinator)
keystore.recentlyUsedAccount = account
keystore.recentlyUsedWallet = account
}
@objc func activateDebug() {
@ -138,7 +162,7 @@ class InCoordinator: Coordinator {
restart(for: transactionCoordinator.session.account, in: transactionCoordinator)
}
func restart(for account: Account, in coordinator: TransactionCoordinator) {
func restart(for account: Wallet, in coordinator: TransactionCoordinator) {
coordinator.navigationController.dismiss(animated: true, completion: nil)
coordinator.stop()
removeAllCoordinators()
@ -155,9 +179,33 @@ class InCoordinator: Coordinator {
addCoordinator(deviceChecker)
}
func showPaymentFlow(for type: PaymentFlow) {
guard let transactionCoordinator = transactionCoordinator else { return }
let session = transactionCoordinator.session
switch session.account.type {
case .real(let account):
let coordinator = PaymentCoordinator(
flow: type,
session: session,
account: account,
keystore: keystore
)
coordinator.delegate = self
navigationController.present(coordinator.navigationController, animated: true, completion: nil)
coordinator.start()
addCoordinator(coordinator)
case .watch: break
}
}
}
extension InCoordinator: TransactionCoordinatorDelegate {
func didPress(for type: PaymentFlow, in coordinator: TransactionCoordinator) {
showPaymentFlow(for: type)
}
func didCancel(in coordinator: TransactionCoordinator) {
delegate?.didCancel(in: self)
coordinator.navigationController.dismiss(animated: true, completion: nil)
@ -185,7 +233,7 @@ extension InCoordinator: SettingsCoordinatorDelegate {
delegate?.didCancel(in: self)
}
func didRestart(with account: Account, in coordinator: SettingsCoordinator) {
func didRestart(with account: Wallet, in coordinator: SettingsCoordinator) {
guard let transactionCoordinator = transactionCoordinator else { return }
restart(for: account, in: transactionCoordinator)
}
@ -194,3 +242,16 @@ extension InCoordinator: SettingsCoordinatorDelegate {
delegate?.didUpdateAccounts(in: self)
}
}
extension InCoordinator: TokensCoordinatorDelegate {
func didPress(for type: PaymentFlow, in coordinator: TokensCoordinator) {
showPaymentFlow(for: type)
}
}
extension InCoordinator: PaymentCoordinatorDelegate {
func didCancel(in coordinator: PaymentCoordinator) {
coordinator.navigationController.dismiss(animated: true, completion: nil)
removeCoordinator(coordinator)
}
}

@ -26,7 +26,13 @@ class ExchangeRateCoordinator: NSObject {
}
func fetch() {
provider.request(.prices(currency: Config().currency, symbols:[config.server.symbol])) { result in
let tokens = [TokenPrice(contract: "0x", symbol: config.server.symbol)]
let tokensPrice = TokensPrice(
currency: config.currency.rawValue,
tokens: tokens
)
provider.request(.prices(tokensPrice)) { [weak self] result in
guard let `self` = self else { return }
guard case .success(let response) = result else { return }
do {
guard let ticker = try response.map([CoinTicker].self, atKeyPath: "response", using: JSONDecoder()).first else { return }
@ -41,7 +47,8 @@ class ExchangeRateCoordinator: NSObject {
rates: [
Rate(
code: ticker.symbol,
price: Double(ticker.price) ?? 0
price: Double(ticker.price) ?? 0,
contract: ticker.contract
),
]
)

@ -6,7 +6,7 @@ import UIKit
protocol SettingsCoordinatorDelegate: class {
func didUpdate(action: SettingsAction, in coordinator: SettingsCoordinator)
func didRestart(with account: Account, in coordinator: SettingsCoordinator)
func didRestart(with account: Wallet, in coordinator: SettingsCoordinator)
func didUpdateAccounts(in coordinator: SettingsCoordinator)
func didCancel(in coordinator: SettingsCoordinator)
}
@ -78,14 +78,14 @@ extension SettingsCoordinator: SettingsViewControllerDelegate {
}
extension SettingsCoordinator: AccountsCoordinatorDelegate {
func didAddAccount(account: Account, in coordinator: AccountsCoordinator) {
func didAddAccount(account: Wallet, in coordinator: AccountsCoordinator) {
delegate?.didUpdateAccounts(in: self)
}
func didDeleteAccount(account: Account, in coordinator: AccountsCoordinator) {
func didDeleteAccount(account: Wallet, in coordinator: AccountsCoordinator) {
storage.deleteAll()
delegate?.didUpdateAccounts(in: self)
guard !coordinator.accountsViewController.hasAccounts else { return }
guard !coordinator.accountsViewController.hasWallets else { return }
coordinator.navigationController.dismiss(animated: true, completion: nil)
delegate?.didCancel(in: self)
}
@ -95,7 +95,7 @@ extension SettingsCoordinator: AccountsCoordinatorDelegate {
removeCoordinator(coordinator)
}
func didSelectAccount(account: Account, in coordinator: AccountsCoordinator) {
func didSelectAccount(account: Wallet, in coordinator: AccountsCoordinator) {
coordinator.navigationController.dismiss(animated: true, completion: nil)
removeCoordinator(coordinator)
delegate?.didRestart(with: account, in: self)

@ -10,6 +10,7 @@ public struct Constants {
public static let keychainKeyPrefix = "trustwallet"
// social
public static let website = "https://trustwalletapp.com"
public static let twitterUsername = "trustwalletapp"
public static let telegramUsername = "trustwallet"
public static let facebookUsername = "trustwalletapp"

@ -5,6 +5,7 @@ import Foundation
struct Rate {
let code: String
let price: Double
let contract: String
}
struct CurrencyRate {

@ -15,7 +15,7 @@ enum RPCServer: String {
case .kovan: return 42
case .ropsten: return 3
case .poa: return 99
case .classic: return 66
case .classic: return 61
}
}

@ -18,7 +18,7 @@ class SettingsViewController: FormViewController {
}
private var config = Config()
private let helpUsCoordinator = HelpUsCoordinator()
weak var delegate: SettingsViewControllerDelegate?
var isPasscodeEnabled: Bool {
@ -183,12 +183,17 @@ class SettingsViewController: FormViewController {
+++ Section(NSLocalizedString("settings.support.label.title", value: "Support", comment: ""))
<<< AppFormAppearance.button { button in
button.title = NSLocalizedString("settings.shareWithFriends.button.title", value: "Share With Friends", comment: "")
button.cell.imageView?.image = R.image.settingsShare()
}.onCellSelection { [unowned self] cell, _ in
self.helpUsCoordinator.presentSharing(in: self, from: cell.contentView)
}
<<< AppFormAppearance.button { button in
button.title = NSLocalizedString("settings.rateUsAppStore.button.title", value: "Rate Us on App Store", comment: "")
}.onCellSelection { _, _ in
if #available(iOS 10.3, *) { SKStoreReviewController.requestReview() } else {
UIApplication.shared.openURL(URL(string: "itms-apps://itunes.apple.com/app/id1288339409")!)
}
self.helpUsCoordinator.rateUs()
}.cellSetup { cell, _ in
cell.imageView?.image = R.image.settings_rating()
}
@ -197,7 +202,7 @@ class SettingsViewController: FormViewController {
button.title = NSLocalizedString("settings.emailUs.button.title", value: "Email Us", comment: "")
}.onCellSelection { _, _ in
self.sendUsEmail()
}.cellSetup { cell, _ in
}.cellSetup { [unowned self] cell, _ in
cell.imageView?.image = R.image.settings_email()
}

@ -3,6 +3,10 @@
import Foundation
import UIKit
protocol TokensCoordinatorDelegate: class {
func didPress(for type: PaymentFlow, in coordinator: TokensCoordinator)
}
class TokensCoordinator: Coordinator {
let navigationController: UINavigationController
@ -21,6 +25,7 @@ class TokensCoordinator: Coordinator {
controller.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addToken))
return controller
}()
weak var delegate: TokensCoordinatorDelegate?
lazy var rootViewController: TokensViewController = {
return self.tokensViewController
@ -47,18 +52,6 @@ class TokensCoordinator: Coordinator {
navigationController.viewControllers = [rootViewController]
}
func showPaymentFlow(for type: PaymentFlow) {
let coordinator = PaymentCoordinator(
flow: type,
session: session,
keystore: keystore
)
coordinator.delegate = self
coordinator.start()
navigationController.present(coordinator.navigationController, animated: true, completion: nil)
addCoordinator(coordinator)
}
func newTokenViewController() -> NewTokenViewController {
let controller = NewTokenViewController()
controller.delegate = self
@ -90,9 +83,9 @@ extension TokensCoordinator: TokensViewControllerDelegate {
func didSelect(token: TokenObject, in viewController: UIViewController) {
switch token.type {
case .ether:
showPaymentFlow(for: .send(type: .ether(destination: .none)))
delegate?.didPress(for: .send(type: .ether(destination: .none)), in: self)
case .token:
showPaymentFlow(for: .send(type: .token(token)))
delegate?.didPress(for: .send(type: .token(token)), in: self)
}
}
@ -106,13 +99,6 @@ extension TokensCoordinator: TokensViewControllerDelegate {
}
}
extension TokensCoordinator: PaymentCoordinatorDelegate {
func didCancel(in coordinator: PaymentCoordinator) {
coordinator.navigationController.dismiss(animated: true, completion: nil)
removeCoordinator(coordinator)
}
}
extension TokensCoordinator: NewTokenViewControllerDelegate {
func didAddToken(token: ERC20Token, in viewController: NewTokenViewController) {
storage.addCustom(token: token)

@ -96,9 +96,9 @@ class TokensDataStore {
updateDelegate()
return
}
let updateTokens = objects
let updateTokens = enabledObject
var count = 0
for tokenObject in objects {
for tokenObject in updateTokens {
getBalanceCoordinator.getBalance(for: session.account.address, contract: Address(string: tokenObject.contract)) { [weak self] result in
guard let `self` = self else { return }
switch result {
@ -137,7 +137,7 @@ class TokensDataStore {
}
func coinTicker(for token: TokenObject) -> CoinTicker? {
return tickers?[token.symbol]
return tickers?[token.contract]
}
func handleError(error: Error) {
@ -156,16 +156,20 @@ class TokensDataStore {
}
func updatePrices() {
var symbols = objects.map { $0.symbol }
symbols.append(Config().server.symbol)
provider.request(.prices(currency: Config().currency, symbols: symbols)) { [weak self] result in
var tokens = objects.map { TokenPrice(contract: $0.contract, symbol: $0.symbol) }
tokens.append(TokenPrice(contract: "0x", symbol: session.config.server.symbol))
let tokensPrice = TokensPrice(
currency: session.config.currency.rawValue,
tokens: tokens
)
provider.request(.prices(tokensPrice)) { [weak self] result in
guard let `self` = self else { return }
guard case .success(let response) = result else { return }
do {
let tickers = try response.map([CoinTicker].self, atKeyPath: "response", using: JSONDecoder())
self.tickers = tickers.reduce([String: CoinTicker]()) { (dict, ticker) -> [String: CoinTicker] in
var dict = dict
dict[ticker.symbol] = ticker
dict[ticker.contract] = ticker
return dict
}
self.updateDelegate()

@ -21,13 +21,13 @@ class TokensViewController: UIViewController {
refreshView(viewModel: viewModel)
}
}
let account: Account
let account: Wallet
let tableView: UITableView
let refreshControl = UIRefreshControl()
weak var delegate: TokensViewControllerDelegate?
init(
account: Account,
account: Wallet,
dataStore: TokensDataStore
) {
self.account = account

@ -39,4 +39,8 @@ struct EditTokenTableCellViewModel {
var isEnabled: Bool {
return !token.isDisabled
}
var contractText: String {
return token.contract
}
}

@ -27,7 +27,7 @@ struct TokensViewModel {
private func amount(for token: TokenObject) -> Double {
guard let tickers = tickers else { return 0 }
guard !token.valueBigInt.isZero, let tickersSymbol = tickers[token.symbol] else { return 0 }
guard !token.valueBigInt.isZero, let tickersSymbol = tickers[token.contract] else { return 0 }
let tokenValue = CurrencyFormatter.plainFormatter.string(from: token.valueBigInt, decimals: token.decimals).doubleValue
let price = Double(tickersSymbol.price) ?? 0
return tokenValue * price

@ -6,6 +6,7 @@ import Result
import TrustKeystore
protocol TransactionCoordinatorDelegate: class {
func didPress(for type: PaymentFlow, in coordinator: TransactionCoordinator)
func didCancel(in coordinator: TransactionCoordinator)
}
@ -49,7 +50,7 @@ class TransactionCoordinator: Coordinator {
navigationController.viewControllers = [rootViewController]
}
private func makeTransactionsController(with account: Account) -> TransactionsViewController {
private func makeTransactionsController(with account: Wallet) -> TransactionsViewController {
let viewModel = TransactionsViewModel()
let controller = TransactionsViewController(
account: account,
@ -87,18 +88,6 @@ class TransactionCoordinator: Coordinator {
}
}
func showPaymentFlow(for type: PaymentFlow) {
let coordinator = PaymentCoordinator(
flow: type,
session: session,
keystore: keystore
)
coordinator.delegate = self
navigationController.present(coordinator.navigationController, animated: true, completion: nil)
coordinator.start()
addCoordinator(coordinator)
}
@objc func didEnterForeground() {
rootViewController.fetch()
}
@ -120,7 +109,7 @@ class TransactionCoordinator: Coordinator {
showDeposit(for: session.account, from: sender)
}
func showDeposit(for account: Account, from barButtonItem: UIBarButtonItem? = .none) {
func showDeposit(for account: Wallet, from barButtonItem: UIBarButtonItem? = .none) {
let coordinator = DepositCoordinator(
navigationController: navigationController,
account: account
@ -131,18 +120,18 @@ class TransactionCoordinator: Coordinator {
extension TransactionCoordinator: TransactionsViewControllerDelegate {
func didPressSend(in viewController: TransactionsViewController) {
showPaymentFlow(for: .send(type: .ether(destination: .none)))
delegate?.didPress(for: .send(type: .ether(destination: .none)), in: self)
}
func didPressRequest(in viewController: TransactionsViewController) {
showPaymentFlow(for: .request)
delegate?.didPress(for: .request, in: self)
}
func didPressTransaction(transaction: Transaction, in viewController: TransactionsViewController) {
showTransaction(transaction)
}
func didPressDeposit(for account: Account, sender: UIView, in viewController: TransactionsViewController) {
func didPressDeposit(for account: Wallet, sender: UIView, in viewController: TransactionsViewController) {
let coordinator = DepositCoordinator(
navigationController: navigationController,
account: account
@ -154,10 +143,3 @@ extension TransactionCoordinator: TransactionsViewControllerDelegate {
delegate?.didCancel(in: self)
}
}
extension TransactionCoordinator: PaymentCoordinatorDelegate {
func didCancel(in coordinator: PaymentCoordinator) {
coordinator.navigationController.dismiss(animated: true, completion: nil)
removeCoordinator(coordinator)
}
}

@ -8,7 +8,7 @@ enum RefreshType {
}
class WalletSession {
let account: Account
let account: Wallet
let web3: Web3Swift
let config: Config
let chainState: ChainState
@ -23,7 +23,7 @@ class WalletSession {
var balanceViewModel: Subscribable<BalanceBaseViewModel> = Subscribable(nil)
init(
account: Account,
account: Wallet,
config: Config
) {
self.account = account

@ -11,14 +11,14 @@ protocol TransactionsViewControllerDelegate: class {
func didPressSend(in viewController: TransactionsViewController)
func didPressRequest(in viewController: TransactionsViewController)
func didPressTransaction(transaction: Transaction, in viewController: TransactionsViewController)
func didPressDeposit(for account: Account, sender: UIView, in viewController: TransactionsViewController)
func didPressDeposit(for account: Wallet, sender: UIView, in viewController: TransactionsViewController)
}
class TransactionsViewController: UIViewController {
var viewModel: TransactionsViewModel
let account: Account
let account: Wallet
let tableView = UITableView(frame: .zero, style: .plain)
let refreshControl = UIRefreshControl()
@ -38,8 +38,10 @@ class TransactionsViewController: UIViewController {
return footerView
}()
let insets = UIEdgeInsets(top: 130, left: 0, bottom: ButtonSize.extraLarge.height + 84, right: 0)
init(
account: Account,
account: Wallet,
dataCoordinator: TransactionDataCoordinator,
session: WalletSession,
viewModel: TransactionsViewModel = TransactionsViewModel(transactions: [])
@ -78,9 +80,6 @@ class TransactionsViewController: UIViewController {
refreshControl.addTarget(self, action: #selector(pullToRefresh), for: .valueChanged)
tableView.addSubview(refreshControl)
//TODO: Find a way to fix hardcoded 32px value. Use bottom safe inset instead.
let insets = UIEdgeInsets(top: 130, left: 0, bottom: ButtonSize.extraLarge.height + 84, right: 0)
errorView = ErrorView(insets: insets, onRetry: fetch)
loadingView = LoadingView(insets: insets)
emptyView = {

@ -82,7 +82,7 @@ struct TransactionDetailsViewModel {
var gasFee: String {
let gasUsed = BigInt(transaction.gasUsed) ?? BigInt()
let gasPrice = BigInt(transaction.gasPrice) ?? BigInt()
return fullFormatter.string(from: gasPrice * gasUsed)
return fullFormatter.string(from: gasPrice * gasUsed) + " " + config.server.symbol
}
var confirmation: String {

@ -21,16 +21,19 @@ public struct PreviewTransaction {
class TransactionConfigurator {
let session: WalletSession
let account: Account
let transaction: UnconfirmedTransaction
private let gasPrice: BigInt?
var configuration: TransactionConfiguration
init(
session: WalletSession,
account: Account,
transaction: UnconfirmedTransaction,
gasPrice: BigInt?
) {
self.session = session
self.account = account
self.transaction = transaction
self.gasPrice = gasPrice
@ -107,7 +110,7 @@ class TransactionConfigurator {
}()
let signTransaction = SignTransaction(
value: value,
account: transaction.account,
account: account,
address: address,
nonce: 0,
data: configuration.data,

@ -2,6 +2,7 @@
import Foundation
import UIKit
import TrustKeystore
protocol PaymentCoordinatorDelegate: class {
func didCancel(in coordinator: PaymentCoordinator)
@ -16,6 +17,7 @@ class PaymentCoordinator: Coordinator {
var coordinators: [Coordinator] = []
let navigationController: UINavigationController
let keystore: Keystore
let account: Account
lazy var transferType: TransferType = {
switch self.flow {
@ -30,11 +32,13 @@ class PaymentCoordinator: Coordinator {
navigationController: UINavigationController = UINavigationController(),
flow: PaymentFlow,
session: WalletSession,
account: Account,
keystore: Keystore
) {
self.navigationController = navigationController
self.navigationController.modalPresentationStyle = .formSheet
self.session = session
self.account = account
self.flow = flow
self.keystore = keystore
}
@ -46,6 +50,7 @@ class PaymentCoordinator: Coordinator {
transferType: type,
navigationController: navigationController,
session: session,
account: account,
keystore: keystore
)
coordinator.delegate = self

@ -3,6 +3,7 @@
import Foundation
import UIKit
import BigInt
import TrustKeystore
protocol SendCoordinatorDelegate: class {
func didCancel(in coordinator: SendCoordinator)
@ -12,6 +13,7 @@ class SendCoordinator: Coordinator {
let transferType: TransferType
let session: WalletSession
let account: Account
let navigationController: UINavigationController
let keystore: Keystore
var coordinators: [Coordinator] = []
@ -24,12 +26,14 @@ class SendCoordinator: Coordinator {
transferType: TransferType,
navigationController: UINavigationController = UINavigationController(),
session: WalletSession,
account: Account,
keystore: Keystore
) {
self.transferType = transferType
self.navigationController = navigationController
self.navigationController.modalPresentationStyle = .formSheet
self.session = session
self.account = account
self.keystore = keystore
}
@ -40,6 +44,7 @@ class SendCoordinator: Coordinator {
func makeSendViewController() -> SendViewController {
let controller = SendViewController(
session: session,
account: account,
transferType: transferType
)
controller.navigationItem.titleView = BalanceTitleView.make(from: self.session, transferType)
@ -70,6 +75,7 @@ extension SendCoordinator: SendViewControllerDelegate {
let configurator = TransactionConfigurator(
session: session,
account: account,
transaction: transaction,
gasPrice: gasPrice
)

@ -32,6 +32,7 @@ class SendViewController: FormViewController {
}
let session: WalletSession
let account: Account
let transferType: TransferType
var addressRow: TextFloatLabelRow? {
@ -44,9 +45,11 @@ class SendViewController: FormViewController {
init(
session: WalletSession,
account: Account,
transferType: TransferType = .ether(destination: .none)
) {
self.session = session
self.account = account
self.transferType = transferType
super.init(nibName: nil, bundle: nil)
@ -167,7 +170,7 @@ class SendViewController: FormViewController {
transferType: transferType,
value: value,
address: address,
account: session.account,
account: account,
chainID: session.config.chainID,
data: Data()
)

@ -6,11 +6,11 @@ import UIKit
struct RequestViewModel {
let account: Account
let account: Wallet
let config: Config
init(
account: Account,
account: Wallet,
config: Config
) {
self.account = account

@ -6,7 +6,7 @@ import UIKit
protocol InitialWalletCreationCoordinatorDelegate: class {
func didCancel(in coordinator: InitialWalletCreationCoordinator)
func didAddAccount(_ account: Account, in coordinator: InitialWalletCreationCoordinator)
func didAddAccount(_ account: Wallet, in coordinator: InitialWalletCreationCoordinator)
}
class InitialWalletCreationCoordinator: Coordinator {
@ -53,7 +53,7 @@ class InitialWalletCreationCoordinator: Coordinator {
}
extension InitialWalletCreationCoordinator: WalletCoordinatorDelegate {
func didFinish(with account: Account, in coordinator: WalletCoordinator) {
func didFinish(with account: Wallet, in coordinator: WalletCoordinator) {
delegate?.didAddAccount(account, in: self)
removeCoordinator(coordinator)
}

@ -14,77 +14,77 @@ class OnePasswordCoordinator {
self.keystore = keystore
}
func createWallet(in viewController: UIViewController, completion: @escaping (Result<Account, AnyError>) -> Void) {
let newPasssword = PasswordGenerator.generateRandom()
let account = keystore.createAccout(password: newPasssword)
let keystoreString: String = {
let value = keystore.export(account: account, password: newPasssword, newPassword: newPasssword)
switch value {
case .success(let string):
return string
case .failure: return ""
}
}()
let formattedPassword = OnePasswordConverter.toPassword(password: newPasssword, keystore: keystoreString)
OnePasswordExtension().storeLogin(
forURLString: OnePasswordConfig.url,
loginDetails: [
AppExtensionUsernameKey: account.address.address,
AppExtensionPasswordKey: formattedPassword,
AppExtensionNotesKey: "Ethereum wallet has been stored here. Format: password-trust-keystore. -trust- - is a divider between password and keystore",
],
passwordGenerationOptions: [:],
for: viewController,
sender: nil
) { results, error in
let results = results ?? [:]
if error != nil {
let _ = self.keystore.delete(account: account)
} else {
let updatedPassword = results[AppExtensionPasswordKey] as? String ?? ""
let result = OnePasswordConverter.fromPassword(password: updatedPassword)
switch result {
case .success(let password, _):
if password == newPasssword {
completion(.success(account))
} else {
let result = self.keystore.updateAccount(account: account, password: password, newPassword: updatedPassword)
switch result {
case .success:
completion(.success(account))
case .failure(let error):
completion(.failure(AnyError(error)))
}
}
case .failure(let error):
completion(.failure(AnyError(error)))
}
}
}
}
func importWallet(in viewController: UIViewController, completion: @escaping (Result<(password: String, keystore: String), AnyError>) -> Void) {
OnePasswordExtension().findLogin(
forURLString: OnePasswordConfig.url,
for: viewController,
sender: nil
) { results, error in
if let error = error {
return completion(.failure(AnyError(error)))
}
guard let password = results?[AppExtensionPasswordKey] as? String else { return }
let result = OnePasswordConverter.fromPassword(password: password)
switch result {
case .success(let password, let keystore):
completion(.success((password: password, keystore: keystore)))
case .failure(let error):
completion(.failure(AnyError(error)))
}
}
}
// func createWallet(in viewController: UIViewController, completion: @escaping (Result<Account, AnyError>) -> Void) {
//
// let newPasssword = PasswordGenerator.generateRandom()
// let account = keystore.createAccout(password: newPasssword)
// let keystoreString: String = {
// let value = keystore.export(account: account, password: newPasssword, newPassword: newPasssword)
// switch value {
// case .success(let string):
// return string
// case .failure: return ""
// }
// }()
//
// let formattedPassword = OnePasswordConverter.toPassword(password: newPasssword, keystore: keystoreString)
//
// OnePasswordExtension().storeLogin(
// forURLString: OnePasswordConfig.url,
// loginDetails: [
// AppExtensionUsernameKey: account.address.address,
// AppExtensionPasswordKey: formattedPassword,
// AppExtensionNotesKey: "Ethereum wallet has been stored here. Format: password-trust-keystore. -trust- - is a divider between password and keystore",
// ],
// passwordGenerationOptions: [:],
// for: viewController,
// sender: nil
// ) { results, error in
// let results = results ?? [:]
// if error != nil {
// let _ = self.keystore.delete(account: account)
// } else {
// let updatedPassword = results[AppExtensionPasswordKey] as? String ?? ""
// let result = OnePasswordConverter.fromPassword(password: updatedPassword)
// switch result {
// case .success(let password, _):
// if password == newPasssword {
// completion(.success(account))
// } else {
// let result = self.keystore.updateAccount(account: account, password: password, newPassword: updatedPassword)
// switch result {
// case .success:
// completion(.success(account))
// case .failure(let error):
// completion(.failure(AnyError(error)))
// }
// }
// case .failure(let error):
// completion(.failure(AnyError(error)))
// }
// }
// }
// }
//
// func importWallet(in viewController: UIViewController, completion: @escaping (Result<(password: String, keystore: String), AnyError>) -> Void) {
// OnePasswordExtension().findLogin(
// forURLString: OnePasswordConfig.url,
// for: viewController,
// sender: nil
// ) { results, error in
// if let error = error {
// return completion(.failure(AnyError(error)))
// }
// guard let password = results?[AppExtensionPasswordKey] as? String else { return }
//
// let result = OnePasswordConverter.fromPassword(password: password)
//
// switch result {
// case .success(let password, let keystore):
// completion(.success((password: password, keystore: keystore)))
// case .failure(let error):
// completion(.failure(AnyError(error)))
// }
// }
// }
}

@ -5,7 +5,7 @@ import TrustKeystore
import UIKit
protocol WalletCoordinatorDelegate: class {
func didFinish(with account: Account, in coordinator: WalletCoordinator)
func didFinish(with account: Wallet, in coordinator: WalletCoordinator)
func didCancel(in coordinator: WalletCoordinator)
}
@ -77,7 +77,7 @@ class WalletCoordinator: Coordinator {
delegate?.didCancel(in: self)
}
func didCreateAccount(account: Account) {
func didCreateAccount(account: Wallet) {
delegate?.didFinish(with: account, in: self)
}
@ -104,7 +104,7 @@ extension WalletCoordinator: WelcomeViewControllerDelegate {
}
extension WalletCoordinator: ImportWalletViewControllerDelegate {
func didImportAccount(account: Account, in viewController: ImportWalletViewController) {
func didImportAccount(account: Wallet, in viewController: ImportWalletViewController) {
didCreateAccount(account: account)
}
}
@ -123,7 +123,7 @@ extension WalletCoordinator: BackupViewControllerDelegate {
) { result in
switch result {
case .success:
self.delegate?.didFinish(with: account, in: self)
self.delegate?.didFinish(with: Wallet(type: .real(account)), in: self)
case .failure:
break
}
@ -138,6 +138,6 @@ extension WalletCoordinator: BackupCoordinatorDelegate {
func didFinish(account: Account, in coordinator: BackupCoordinator) {
removeCoordinator(coordinator)
didCreateAccount(account: account)
didCreateAccount(account: Wallet(type: .real(account)))
}
}

@ -5,6 +5,7 @@ import Foundation
enum ImportSelectionType {
case keystore
case privateKey
case watch
var title: String {
switch self {
@ -12,6 +13,8 @@ enum ImportSelectionType {
return "Keystore"
case .privateKey:
return "Private Key"
case .watch:
return "Watch"
}
}
@ -19,6 +22,8 @@ enum ImportSelectionType {
switch title {
case ImportSelectionType.privateKey.title?:
self = .privateKey
case ImportSelectionType.watch.title?:
self = .watch
default:
self = .keystore
}

@ -7,7 +7,7 @@ import BonMot
import TrustKeystore
protocol ImportWalletViewControllerDelegate: class {
func didImportAccount(account: Account, in viewController: ImportWalletViewController)
func didImportAccount(account: Wallet, in viewController: ImportWalletViewController)
}
class ImportWalletViewController: FormViewController {
@ -20,6 +20,7 @@ class ImportWalletViewController: FormViewController {
static let keystore = "keystore"
static let privateKey = "privateKey"
static let password = "password"
static let watch = "watch"
}
var segmentRow: SegmentedRow<String>? {
@ -38,6 +39,10 @@ class ImportWalletViewController: FormViewController {
return form.rowBy(tag: Values.password)
}
var watchRow: TextFloatLabelRow? {
return form.rowBy(tag: Values.watch)
}
lazy var onePasswordCoordinator: OnePasswordCoordinator = {
return OnePasswordCoordinator(keystore: self.keystore)
}()
@ -92,6 +97,7 @@ class ImportWalletViewController: FormViewController {
$0.options = [
ImportSelectionType.keystore.title,
ImportSelectionType.privateKey.title,
ImportSelectionType.watch.title,
]
$0.value = ImportSelectionType.keystore.title
}
@ -116,6 +122,16 @@ class ImportWalletViewController: FormViewController {
})
}
<<< AppFormAppearance.textFieldFloat(tag: Values.watch) {
$0.add(rule: RuleRequired())
$0.add(rule: EthereumAddressRule())
$0.hidden = Eureka.Condition.function([Values.segment], { _ in
return self.segmentRow?.value != ImportSelectionType.watch.title
})
}.cellUpdate { cell, _ in
cell.textField.placeholder = NSLocalizedString("Ethereum Address", value: "Ethereum Address", comment: "")
}
<<< AppFormAppearance.textFieldFloat(tag: Values.password) {
$0.validationOptions = .validatesOnDemand
$0.hidden = Eureka.Condition.function([Values.segment], { _ in
@ -136,7 +152,7 @@ class ImportWalletViewController: FormViewController {
}
}
func didImport(account: Account) {
func didImport(account: Wallet) {
delegate?.didImportAccount(account: account, in: self)
}
@ -147,6 +163,7 @@ class ImportWalletViewController: FormViewController {
let keystoreInput = keystoreRow?.value?.trimmed ?? ""
let privateKeyInput = privateKeyRow?.value?.trimmed ?? ""
let password = passwordRow?.value ?? ""
let watchInput = watchRow?.value?.trimmed ?? ""
displayLoading(text: NSLocalizedString("importWallet.importingIndicator.label.title", value: "Importing wallet...", comment: ""), animated: false)
@ -157,6 +174,8 @@ class ImportWalletViewController: FormViewController {
return .keystore(string: keystoreInput, password: password)
case .privateKey:
return .privateKey(privateKey: privateKeyInput)
case .watch:
return .watch(address: Address(string: watchInput))
}
}()
@ -172,27 +191,25 @@ class ImportWalletViewController: FormViewController {
}
func onePasswordImport() {
onePasswordCoordinator.importWallet(in: self) { [weak self] result in
guard let `self` = self else { return }
switch result {
case .success(let password, let keystore):
self.keystoreRow?.value = keystore
self.keystoreRow?.reload()
self.passwordRow?.value = password
self.passwordRow?.reload()
self.importWallet()
case .failure(let error):
self.displayError(error: error)
}
}
// onePasswordCoordinator.importWallet(in: self) { [weak self] result in
// guard let `self` = self else { return }
// switch result {
// case .success(let password, let keystore):
// self.keystoreRow?.value = keystore
// self.keystoreRow?.reload()
// self.passwordRow?.value = password
// self.passwordRow?.reload()
// self.importWallet()
// case .failure(let error):
// self.displayError(error: error)
// }
// }
}
@objc func demo() {
//Used for taking screenshots to the App Store by snapshot
let demoAccount = Account(
address: Address(string: "0xD663bE6b87A992C5245F054D32C7f5e99f5aCc47")
)
delegate?.didImportAccount(account: demoAccount, in: self)
let demoWallet = Wallet(type: .watch(Address(string: "0xD663bE6b87A992C5245F054D32C7f5e99f5aCc47")))
delegate?.didImportAccount(account: demoWallet, in: self)
}
@objc func importOptions(sender: UIBarButtonItem) {

@ -0,0 +1,15 @@
// Copyright SIX DAY LLC. All rights reserved.
import Foundation
import UIKit
class PassphraseViewController: UIViewController {
init() {
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

@ -20,7 +20,7 @@ class AppCoordinatorTests: XCTestCase {
let coordinator = AppCoordinator(
window: UIWindow(),
keystore: FakeKeystore(
accounts: [.make()]
wallets: [.make()]
)
)
@ -34,7 +34,7 @@ class AppCoordinatorTests: XCTestCase {
let coordinator = AppCoordinator(
window: UIWindow(),
keystore: FakeKeystore(
accounts: [.make()]
wallets: [.make()]
)
)
coordinator.start()
@ -61,7 +61,7 @@ class AppCoordinatorTests: XCTestCase {
let coordinator = AppCoordinator(
window: UIWindow(),
keystore: FakeKeystore(
accounts: [.make()]
wallets: [.make()]
),
navigationController: FakeNavigationController()
)

@ -9,7 +9,7 @@ class InCoordinatorTests: XCTestCase {
func testShowTabBar() {
let coordinator = InCoordinator(
navigationController: FakeNavigationController(),
account: .make(),
wallet: .make(),
keystore: FakeEtherKeystore(),
config: .make()
)
@ -33,28 +33,62 @@ class InCoordinatorTests: XCTestCase {
}
func testChangeRecentlyUsedAccount() {
let account1: Account = .make(address: .make(address: "0x1000000000000000000000000000000000000000"))
let account2: Account = .make(address: .make(address: "0x2000000000000000000000000000000000000000"))
let account1: Wallet = .make(type: .watch(Address(string: "0x1000000000000000000000000000000000000000")))
let account2: Wallet = .make(type: .watch(Address(string: "0x2000000000000000000000000000000000000000")))
let keystore = FakeKeystore(
accounts: [
wallets: [
account1,
account2
]
)
let coordinator = InCoordinator(
navigationController: FakeNavigationController(),
account: .make(),
wallet: .make(),
keystore: keystore,
config: .make()
)
coordinator.showTabBar(for: account1)
XCTAssertEqual(coordinator.keystore.recentlyUsedAccount, account1)
XCTAssertEqual(coordinator.keystore.recentlyUsedWallet, account1)
coordinator.showTabBar(for: account2)
XCTAssertEqual(coordinator.keystore.recentlyUsedAccount, account2)
XCTAssertEqual(coordinator.keystore.recentlyUsedWallet, account2)
}
func testShowSendFlow() {
let coordinator = InCoordinator(
navigationController: FakeNavigationController(),
wallet: .make(),
keystore: FakeEtherKeystore(),
config: .make()
)
coordinator.showTabBar(for: .make())
coordinator.showPaymentFlow(for: .send(type: .ether(destination: .none)))
let controller = (coordinator.navigationController.presentedViewController as? UINavigationController)?.viewControllers[0]
XCTAssertTrue(coordinator.coordinators.last is PaymentCoordinator)
XCTAssertTrue(controller is SendViewController)
}
func testShowRequstFlow() {
let coordinator = InCoordinator(
navigationController: FakeNavigationController(),
wallet: .make(),
keystore: FakeEtherKeystore(),
config: .make()
)
coordinator.showTabBar(for: .make())
coordinator.showPaymentFlow(for: .request)
let controller = (coordinator.navigationController.presentedViewController as? UINavigationController)?.viewControllers[0]
XCTAssertTrue(coordinator.coordinators.last is PaymentCoordinator)
XCTAssertTrue(controller is RequestViewController)
}
}

@ -11,6 +11,7 @@ class SendCoordinatorTests: XCTestCase {
transferType: .ether(destination: .none),
navigationController: FakeNavigationController(),
session: .make(),
account: .make(),
keystore: FakeKeystore()
)
@ -25,6 +26,7 @@ class SendCoordinatorTests: XCTestCase {
transferType: .ether(destination: address),
navigationController: FakeNavigationController(),
session: .make(),
account: .make(),
keystore: FakeKeystore()
)
coordinator.start()

@ -5,35 +5,4 @@ import XCTest
class TransactionCoordinatorTests: XCTestCase {
func testShowSendFlow() {
let coordinator = TransactionCoordinator(
session: .make(),
navigationController: FakeNavigationController(),
storage: FakeTransactionsStorage(),
keystore: FakeEtherKeystore()
)
coordinator.showPaymentFlow(for: .send(type: .ether(destination: .none)))
let controller = (coordinator.navigationController.presentedViewController as? UINavigationController)?.viewControllers[0]
XCTAssertTrue(coordinator.coordinators.first is PaymentCoordinator)
XCTAssertTrue(controller is SendViewController)
}
func testShowRequstFlow() {
let coordinator = TransactionCoordinator(
session: .make(),
navigationController: FakeNavigationController(),
storage: FakeTransactionsStorage(),
keystore: FakeEtherKeystore()
)
coordinator.showPaymentFlow(for: .request)
let controller = (coordinator.navigationController.presentedViewController as? UINavigationController)?.viewControllers[0]
XCTAssertTrue(coordinator.coordinators.first is PaymentCoordinator)
XCTAssertTrue(controller is RequestViewController)
}
}

@ -56,16 +56,15 @@ class WalletCoordinatorTests: XCTestCase {
}
class FakeWalletCoordinatorDelegate: WalletCoordinatorDelegate {
var didFail: Error? = .none
var didFinishAccount: Account? = .none
var didFinishAccount: Wallet? = .none
var didCancel: Bool = false
func didCancel(in coordinator: WalletCoordinator) {
didCancel = true
}
func didFinish(with account: Account, in coordinator: WalletCoordinator) {
func didFinish(with account: Wallet, in coordinator: WalletCoordinator) {
didFinishAccount = account
}

@ -0,0 +1,22 @@
// Copyright SIX DAY LLC. All rights reserved.
import XCTest
@testable import Trust
class AppTrackerTests: XCTestCase {
func testLaunchCountForCurrentBuild() {
let tracker = AppTracker(defaults: .test)
XCTAssertEqual(0, tracker.launchCountForCurrentBuild)
tracker.start()
XCTAssertEqual(1, tracker.launchCountForCurrentBuild)
tracker.start()
XCTAssertEqual(2, tracker.launchCountForCurrentBuild)
}
}

@ -12,7 +12,7 @@ class EtherKeystoreTests: XCTestCase {
let keystore = FakeEtherKeystore()
XCTAssertNotNil(keystore)
XCTAssertEqual(false, keystore.hasAccounts)
XCTAssertEqual(false, keystore.hasWallets)
}
func testCreateWallet() {
@ -23,7 +23,7 @@ class EtherKeystoreTests: XCTestCase {
let retrivedPassword = keystore.getPassword(for: account)
XCTAssertEqual(password, retrivedPassword)
XCTAssertEqual(1, keystore.accounts.count)
XCTAssertEqual(1, keystore.wallets.count)
}
func testSetAndGetPasswordForAccount() {
@ -60,7 +60,7 @@ class EtherKeystoreTests: XCTestCase {
}
XCTAssertEqual("5e9c27156a612a2d516c74c7a80af107856f8539", account.address.description)
XCTAssertEqual(1, keystore.accounts.count)
XCTAssertEqual(1, keystore.wallets.count)
}
func testImportDuplicate() {
@ -87,7 +87,7 @@ class EtherKeystoreTests: XCTestCase {
}
XCTAssertEqual("5e9c27156a612a2d516c74c7a80af107856f8539", account.address.description)
XCTAssertEqual(1, keystore.accounts.count)
XCTAssertEqual(1, keystore.wallets.count)
}
func testImportFailInvalidPassword() {
@ -103,7 +103,7 @@ class EtherKeystoreTests: XCTestCase {
return XCTFail()
}
XCTAssertEqual(0, keystore.accounts.count)
XCTAssertEqual(0, keystore.wallets.count)
}
func testImportUsesNewPasswordForEncryption() {
@ -125,7 +125,7 @@ class EtherKeystoreTests: XCTestCase {
XCTAssertEqual(newPassword, retreivePassword)
XCTAssertEqual("5e9c27156a612a2d516c74c7a80af107856f8539", account.address.description)
XCTAssertEqual(1, keystore.accounts.count)
XCTAssertEqual(1, keystore.wallets.count)
let exportResult = keystore.export(account: account, password: newPassword, newPassword: "test2")
@ -153,33 +153,33 @@ class EtherKeystoreTests: XCTestCase {
let keystore = FakeEtherKeystore()
let password = "test"
XCTAssertNil(keystore.recentlyUsedAccount)
XCTAssertNil(keystore.recentlyUsedWallet)
let account = keystore.createAccout(password: password)
let account = Wallet(type: .real(keystore.createAccout(password: password)))
keystore.recentlyUsedAccount = account
keystore.recentlyUsedWallet = account
XCTAssertEqual(account, keystore.recentlyUsedAccount)
XCTAssertEqual(account, keystore.recentlyUsedWallet)
keystore.recentlyUsedAccount = nil
keystore.recentlyUsedWallet = nil
XCTAssertNil(keystore.recentlyUsedAccount)
XCTAssertNil(keystore.recentlyUsedWallet)
}
func testDeleteAccount() {
let keystore = FakeEtherKeystore()
let password = "test"
let account = keystore.createAccout(password: password)
let wallet = Wallet(type: .real(keystore.createAccout(password: password)))
XCTAssertEqual(1, keystore.accounts.count)
XCTAssertEqual(1, keystore.wallets.count)
let result = keystore.delete(account: account)
let result = keystore.delete(wallet: wallet)
guard case .success = result else {
return XCTFail()
}
XCTAssertEqual(0, keystore.accounts.count)
XCTAssertEqual(0, keystore.wallets.count)
}
func testConvertPrivateKeyToKeyStore() {
@ -201,6 +201,6 @@ class EtherKeystoreTests: XCTestCase {
return XCTFail()
}
XCTAssertEqual(1, keystore.accounts.count)
XCTAssertEqual(1, keystore.wallets.count)
}
}

@ -6,26 +6,26 @@ import TrustKeystore
import Result
struct FakeKeystore: Keystore {
static var current: Account?
var hasAccounts: Bool {
return accounts.count > 0
static var current: Wallet?
var hasWallets: Bool {
return wallets.count > 0
}
var accounts: [Account]
var recentlyUsedAccount: Account?
var wallets: [Wallet]
var recentlyUsedWallet: Wallet?
init(
accounts: [Account] = [],
recentlyUsedAccount: Account? = .none
wallets: [Wallet] = [],
recentlyUsedWallet: Wallet? = .none
) {
self.accounts = accounts
self.recentlyUsedAccount = recentlyUsedAccount
self.wallets = wallets
self.recentlyUsedWallet = recentlyUsedWallet
}
func createAccount(with password: String, completion: @escaping (Result<Account, KeystoreError>) -> Void) {
completion(.success(.make()))
}
func importWallet(type: ImportType, completion: @escaping (Result<Account, KeystoreError>) -> Void) {
func importWallet(type: ImportType, completion: @escaping (Result<Wallet, KeystoreError>) -> Void) {
//TODO: Implement
}
@ -57,7 +57,7 @@ struct FakeKeystore: Keystore {
return .failure(KeystoreError.failedToSignTransaction)
}
func delete(account: Account) -> Result<Void, KeystoreError> {
func delete(wallet wallet: Wallet) -> Result<Void, KeystoreError> {
//TODO: Implement
return .failure(KeystoreError.failedToSignTransaction)
}
@ -85,12 +85,12 @@ struct FakeKeystore: Keystore {
extension FakeKeystore {
static func make(
accounts: [Account] = [],
recentlyUsedAccount: Account? = .none
wallets: [Wallet] = [],
recentlyUsedWallet: Wallet? = .none
) -> FakeKeystore {
return FakeKeystore(
accounts: accounts,
recentlyUsedAccount: recentlyUsedAccount
wallets: wallets,
recentlyUsedWallet: recentlyUsedWallet
)
}
}

@ -0,0 +1,14 @@
// Copyright SIX DAY LLC. All rights reserved.
import Foundation
@testable import Trust
extension Wallet {
static func make(
type: WalletType = .real(.make())
) -> Wallet {
return Wallet(
type: type
)
}
}

@ -6,7 +6,7 @@ import TrustKeystore
extension WalletSession {
static func make(
account: Account = .make(),
account: Wallet = .make(),
config: Config = .make()
) -> WalletSession {
return WalletSession(

@ -7,7 +7,7 @@ import BigInt
class TransactionConfiguratorTests: XCTestCase {
func testDefault() {
let configurator = TransactionConfigurator(session: .make(), transaction: .make(), gasPrice: .none)
let configurator = TransactionConfigurator(session: .make(), account: .make(), transaction: .make(), gasPrice: .none)
XCTAssertEqual(GasPriceConfiguration.default, configurator.configuration.gasPrice)
XCTAssertEqual(GasLimitConfiguration.default, configurator.configuration.gasLimit)
@ -15,25 +15,25 @@ class TransactionConfiguratorTests: XCTestCase {
func testAdjustGasPrice() {
let desiderGasPrice = BigInt(2000000000)
let configurator = TransactionConfigurator(session: .make(), transaction: .make(), gasPrice: desiderGasPrice)
let configurator = TransactionConfigurator(session: .make(), account: .make(), transaction: .make(), gasPrice: desiderGasPrice)
XCTAssertEqual(desiderGasPrice, configurator.configuration.gasPrice)
}
func testMinGasPrice() {
let configurator = TransactionConfigurator(session: .make(), transaction: .make(), gasPrice: BigInt(1))
let configurator = TransactionConfigurator(session: .make(), account: .make(), transaction: .make(), gasPrice: BigInt(1))
XCTAssertEqual(GasPriceConfiguration.min, configurator.configuration.gasPrice)
}
func testMaxGasPrice() {
let configurator = TransactionConfigurator(session: .make(), transaction: .make(), gasPrice: BigInt(990000000000))
let configurator = TransactionConfigurator(session: .make(), account: .make(), transaction: .make(), gasPrice: BigInt(990000000000))
XCTAssertEqual(GasPriceConfiguration.max, configurator.configuration.gasPrice)
}
func testLoadEtherConfiguration() {
let configurator = TransactionConfigurator(session: .make(), transaction: .make(), gasPrice: .none)
let configurator = TransactionConfigurator(session: .make(), account: .make(), transaction: .make(), gasPrice: .none)
configurator.load { _ in }

@ -7,14 +7,14 @@ import TrustKeystore
class RequestViewModelTests: XCTestCase {
func testMyAddressText() {
let account: Account = .make()
let account: Wallet = .make()
let viewModel = RequestViewModel(account: account, config: .make())
XCTAssertEqual(account.address.address, viewModel.myAddressText)
}
func testShareMyAddressText() {
let account: Account = .make()
let account: Wallet = .make()
let config: Config = .make()
let viewModel = RequestViewModel(account: account, config: .make())

@ -12,6 +12,7 @@ class PaymentCoordinatorTests: XCTestCase {
navigationController: FakeNavigationController(),
flow: .send(type: .ether(destination: address)),
session: .make(),
account: .make(),
keystore: FakeKeystore()
)
coordinator.start()
@ -25,6 +26,7 @@ class PaymentCoordinatorTests: XCTestCase {
navigationController: FakeNavigationController(),
flow: .request,
session: .make(),
account: .make(),
keystore: FakeKeystore()
)

Loading…
Cancel
Save