From f86a73027cb983b8df9d8dffe4e65bc6be3d8875 Mon Sep 17 00:00:00 2001 From: Michael Scoff Date: Sat, 28 Oct 2017 00:37:06 -0700 Subject: [PATCH] Support for ERC20 sending! Yaaaaa --- Trust.xcodeproj/project.pbxproj | 12 ++++ Trust/Models/Token.swift | 2 +- .../Coordinator/TokensCoordinator.swift | 56 +++++++++++++++++++ .../TokensViewController.swift | 10 +++- .../Coordinators/TransactionCoordinator.swift | 20 ++++++- .../ConfirmPaymentViewController.swift | 49 +++++++++++----- .../Controllers/PaymentCoordinator.swift | 33 ++++++++--- .../Controllers/RequestViewController.swift | 2 +- .../Controllers/SendViewController.swift | 8 +-- .../SendTransactionCoordinator.swift | 7 +-- Trust/Transfer/Types/PaymentFlow.swift | 2 +- Trust/Transfer/Types/TransferType.swift | 2 +- 12 files changed, 165 insertions(+), 38 deletions(-) create mode 100644 Trust/Tokens/Coordinator/TokensCoordinator.swift diff --git a/Trust.xcodeproj/project.pbxproj b/Trust.xcodeproj/project.pbxproj index ecf2d1533..672050acc 100644 --- a/Trust.xcodeproj/project.pbxproj +++ b/Trust.xcodeproj/project.pbxproj @@ -173,6 +173,7 @@ 29E2E3411F7B1585000CF94A /* ActionButtonRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29E2E3401F7B1585000CF94A /* ActionButtonRow.swift */; }; 29EB102A1F6CBD23000907A4 /* UIAlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29EB10291F6CBD23000907A4 /* UIAlertController.swift */; }; 29F114E91FA3EC9E00114A29 /* InCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29F114E81FA3EC9E00114A29 /* InCoordinatorTests.swift */; }; + 29F114EC1FA448F400114A29 /* TokensCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29F114EB1FA448F400114A29 /* TokensCoordinator.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 */; }; @@ -382,6 +383,7 @@ 29E2E3401F7B1585000CF94A /* ActionButtonRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionButtonRow.swift; sourceTree = ""; }; 29EB10291F6CBD23000907A4 /* UIAlertController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIAlertController.swift; sourceTree = ""; }; 29F114E81FA3EC9E00114A29 /* InCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InCoordinatorTests.swift; sourceTree = ""; }; + 29F114EB1FA448F400114A29 /* TokensCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokensCoordinator.swift; sourceTree = ""; }; 29FC0CB51F8298820036089F /* TransactionCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionCoordinator.swift; sourceTree = ""; }; 29FC0CB71F8299510036089F /* Coordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = ""; }; 29FC9BC51F830880000209CD /* MirgrationInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MirgrationInitializer.swift; sourceTree = ""; }; @@ -784,6 +786,7 @@ 296106C01F7640240006164B /* Tokens */ = { isa = PBXGroup; children = ( + 29F114EA1FA448DE00114A29 /* Coordinator */, 2977CAF31F7E0C5D009682A0 /* Types */, 2977CAF21F7E0C3A009682A0 /* ViewModels */, 2977CAF11F7E0C33009682A0 /* ViewControllers */, @@ -1172,6 +1175,14 @@ path = Storage; sourceTree = ""; }; + 29F114EA1FA448DE00114A29 /* Coordinator */ = { + isa = PBXGroup; + children = ( + 29F114EB1FA448F400114A29 /* TokensCoordinator.swift */, + ); + path = Coordinator; + sourceTree = ""; + }; 29FC9BC31F830880000209CD /* Core */ = { isa = PBXGroup; children = ( @@ -1692,6 +1703,7 @@ 290B2B5B1F8F551E0053C83E /* LokaliseInitializer.swift in Sources */, 29B6AECB1F7C5FA900EC6DE3 /* PaymentCoordinator.swift in Sources */, 2963B6B91F9A7EEA003063C1 /* CoinTicker.swift in Sources */, + 29F114EC1FA448F400114A29 /* TokensCoordinator.swift in Sources */, 2996F14A1F6C9D10005C33AE /* ExportCoordinator.swift in Sources */, 2932488E1F88E69F008A9818 /* OnePasswordError.swift in Sources */, 293E62711FA2F63500CB0A66 /* InitialWalletCreationCoordinator.swift in Sources */, diff --git a/Trust/Models/Token.swift b/Trust/Models/Token.swift index 18005ca60..86106b4a5 100644 --- a/Trust/Models/Token.swift +++ b/Trust/Models/Token.swift @@ -15,7 +15,7 @@ extension Token { static func from(address: String, json: [String: AnyObject]) -> Token { let tokenInfo = json["tokenInfo"] as? [String: AnyObject] ?? [:] return Token( - address: Address(address: address), + address: Address(address: tokenInfo["address"] as? String ?? ""), name: tokenInfo["name"] as? String ?? "", symbol: tokenInfo["symbol"] as? String ?? "", totalSupply: tokenInfo["symbol"] as? String ?? "", diff --git a/Trust/Tokens/Coordinator/TokensCoordinator.swift b/Trust/Tokens/Coordinator/TokensCoordinator.swift new file mode 100644 index 000000000..370b322f8 --- /dev/null +++ b/Trust/Tokens/Coordinator/TokensCoordinator.swift @@ -0,0 +1,56 @@ +// Copyright SIX DAY LLC. All rights reserved. + +import Foundation +import UIKit + +protocol TokensCoordinatorDelegate: class { + func didCancel(in coordinator: TokensCoordinator) +} + +class TokensCoordinator: Coordinator { + + let navigationController: UINavigationController + let account: Account + var coordinators: [Coordinator] = [] + weak var delegate: TokensCoordinatorDelegate? + + init( + navigationController: UINavigationController, + account: Account + ) { + self.navigationController = navigationController + self.account = account + } + + func start() { + showTokens() + } + + func showTokens() { + let controller = TokensViewController(account: account) + controller.delegate = self + if UIDevice.current.userInterfaceIdiom == .pad { + let nav = UINavigationController(rootViewController: controller) + nav.modalPresentationStyle = .formSheet + controller.navigationItem.leftBarButtonItem = UIBarButtonItem( + barButtonSystemItem: .cancel, + target: self, + action: #selector(dismiss) + ) + navigationController.present(nav, animated: true, completion: nil) + } else { + navigationController.pushViewController(controller, animated: true) + } + } + + @objc func dismiss() { + navigationController.dismiss(animated: true, completion: nil) + delegate?.didCancel(in: self) + } +} + +extension TokensCoordinator: TokensViewControllerDelegate { + func didSelect(token: Token, in viewController: UIViewController) { + // + } +} diff --git a/Trust/Tokens/ViewControllers/TokensViewController.swift b/Trust/Tokens/ViewControllers/TokensViewController.swift index 635d3c453..c231e2493 100644 --- a/Trust/Tokens/ViewControllers/TokensViewController.swift +++ b/Trust/Tokens/ViewControllers/TokensViewController.swift @@ -5,6 +5,10 @@ import UIKit import StatefulViewController import Result +protocol TokensViewControllerDelegate: class { + func didSelect(token: Token, in viewController: UIViewController) +} + class TokensViewController: UIViewController { private lazy var dataStore: TokensDataStore = { @@ -15,6 +19,7 @@ class TokensViewController: UIViewController { let account: Account let tableView: UITableView let refreshControl = UIRefreshControl() + weak var delegate: TokensViewControllerDelegate? init( account: Account @@ -84,7 +89,10 @@ extension TokensViewController: StatefulViewController { extension TokensViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - tableView.deselectRow(at: indexPath, animated: true ) + tableView.deselectRow(at: indexPath, animated: true) + + let token = viewModel.item(for: indexPath.row, section: indexPath.section) + delegate?.didSelect(token: token, in: self) } } diff --git a/Trust/Transactions/Coordinators/TransactionCoordinator.swift b/Trust/Transactions/Coordinators/TransactionCoordinator.swift index d44db4762..10139bfca 100644 --- a/Trust/Transactions/Coordinators/TransactionCoordinator.swift +++ b/Trust/Transactions/Coordinators/TransactionCoordinator.swift @@ -69,10 +69,15 @@ class TransactionCoordinator: Coordinator { func showTokens(for account: Account) { let controller = TokensViewController(account: account) + controller.delegate = self if UIDevice.current.userInterfaceIdiom == .pad { let nav = UINavigationController(rootViewController: controller) nav.modalPresentationStyle = .formSheet - controller.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(dismiss)) + controller.navigationItem.leftBarButtonItem = UIBarButtonItem( + barButtonSystemItem: .cancel, + target: self, + action: #selector(dismiss) + ) navigationController.present(nav, animated: true, completion: nil) } else { navigationController.pushViewController(controller, animated: true) @@ -143,7 +148,7 @@ extension TransactionCoordinator: SettingsCoordinatorDelegate { break case .donate(let address): coordinator.navigationController.dismiss(animated: true) { - self.showPaymentFlow(for: .send(destination: address), session: self.session) + self.showPaymentFlow(for: .send(type: .ether(destination: address)), session: self.session) } } } @@ -155,7 +160,7 @@ extension TransactionCoordinator: SettingsCoordinatorDelegate { extension TransactionCoordinator: TransactionsViewControllerDelegate { func didPressSend(in viewController: TransactionsViewController) { - showPaymentFlow(for: .send(destination: .none), session: session) + showPaymentFlow(for: .send(type: .ether(destination: .none)), session: session) } func didPressRequest(in viewController: TransactionsViewController) { @@ -210,3 +215,12 @@ extension TransactionCoordinator: AccountsCoordinatorDelegate { delegate?.didRestart(with: account, in: self) } } + +extension TransactionCoordinator: TokensViewControllerDelegate { + func didSelect(token: Token, in viewController: UIViewController) { + showPaymentFlow(for: .send( + type: .token(token)), + session: session + ) + } +} diff --git a/Trust/Transfer/Controllers/ConfirmPaymentViewController.swift b/Trust/Transfer/Controllers/ConfirmPaymentViewController.swift index f04f42705..181a6f34d 100644 --- a/Trust/Transfer/Controllers/ConfirmPaymentViewController.swift +++ b/Trust/Transfer/Controllers/ConfirmPaymentViewController.swift @@ -12,6 +12,7 @@ class ConfirmPaymentViewController: UIViewController { let transaction: UnconfirmedTransaction let session: WalletSession + let transferType: TransferType let stackViewController = StackViewController() lazy var sendTransactionCoordinator = { return SendTransactionCoordinator(session: self.session) @@ -28,10 +29,12 @@ class ConfirmPaymentViewController: UIViewController { init( session: WalletSession, - transaction: UnconfirmedTransaction + transaction: UnconfirmedTransaction, + transferType: TransferType ) { self.session = session self.transaction = transaction + self.transferType = transferType super.init(nibName: nil, bundle: nil) @@ -80,19 +83,39 @@ class ConfirmPaymentViewController: UIViewController { func send() { self.displayLoading() - self.sendTransactionCoordinator.send( - address: transaction.address, - value: transaction.amount, - configuration: self.configuration - ) { [weak self] result in - guard let `self` = self else { return } - switch result { - case .success(let transaction): - self.delegate?.didCompleted(transaction: transaction, in: self) - case .failure(let error): - self.displayError(error: error) + + switch transferType { + case .ether: + self.sendTransactionCoordinator.send( + address: transaction.address, + value: transaction.amount, + configuration: self.configuration + ) { [weak self] result in + guard let `self` = self else { return } + switch result { + case .success(let transaction): + self.delegate?.didCompleted(transaction: transaction, in: self) + case .failure(let error): + self.displayError(error: error) + } + self.hideLoading() + } + case .token(let token): + self.sendTransactionCoordinator.send( + contract: token.address, + to: transaction.address, + amount: transaction.amount, + decimals: token.decimals + ) { [weak self] result in + guard let `self` = self else { return } + switch result { + case .success(let transaction): + self.delegate?.didCompleted(transaction: transaction, in: self) + case .failure(let error): + self.displayError(error: error) + } + self.hideLoading() } - self.hideLoading() } } } diff --git a/Trust/Transfer/Controllers/PaymentCoordinator.swift b/Trust/Transfer/Controllers/PaymentCoordinator.swift index ad6d49e10..c24c73931 100644 --- a/Trust/Transfer/Controllers/PaymentCoordinator.swift +++ b/Trust/Transfer/Controllers/PaymentCoordinator.swift @@ -33,11 +33,20 @@ class PaymentCoordinator: Coordinator { switch self.flow { case .request: return self.requestViewController - case .send(let destination): + case .send(let type): return self.sendViewController } }() + lazy var transferType: TransferType = { + switch self.flow { + case .send(let type): + return type + case .request: + return .ether(destination: .none) + } + }() + init( navigationController: UINavigationController = UINavigationController(), flow: PaymentFlow, @@ -52,7 +61,10 @@ class PaymentCoordinator: Coordinator { } func makeSendViewController() -> SendViewController { - let controller = SendViewController(account: self.session.account) + let controller = SendViewController( + account: session.account, + transferType: transferType + ) controller.navigationItem.titleView = titleView controller.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(dismiss)) controller.navigationItem.rightBarButtonItem = UIBarButtonItem( @@ -61,10 +73,16 @@ class PaymentCoordinator: Coordinator { target: controller, action: #selector(SendViewController.send) ) - if case .send(let destination) = flow { - controller.addressRow?.value = destination?.address - controller.addressRow?.cell.row.updateCell() + if case .send(let type) = flow { + switch type { + case .ether(let destination): + controller.addressRow?.value = destination?.address + controller.addressRow?.cell.row.updateCell() + case .token: + break + } } + controller.delegate = self return controller } @@ -103,10 +121,11 @@ extension PaymentCoordinator: SendViewControllerDelegate { delegate?.didCreatePendingTransaction(transaction, in: self) } - func didPressConfirm(transaction: UnconfirmedTransaction, in viewController: SendViewController) { + func didPressConfirm(transaction: UnconfirmedTransaction, transferType: TransferType, in viewController: SendViewController) { let controller = ConfirmPaymentViewController( session: session, - transaction: transaction + transaction: transaction, + transferType: transferType ) controller.delegate = self navigationController.pushViewController(controller, animated: true) diff --git a/Trust/Transfer/Controllers/RequestViewController.swift b/Trust/Transfer/Controllers/RequestViewController.swift index 7b02d7d61..3bcb0d86b 100644 --- a/Trust/Transfer/Controllers/RequestViewController.swift +++ b/Trust/Transfer/Controllers/RequestViewController.swift @@ -59,7 +59,7 @@ class RequestViewController: UIViewController { let transferType: TransferType - init(account: Account, transferType: TransferType = .ether) { + init(account: Account, transferType: TransferType = .ether(destination: .none)) { self.account = account self.transferType = transferType diff --git a/Trust/Transfer/Controllers/SendViewController.swift b/Trust/Transfer/Controllers/SendViewController.swift index c96ecf17c..6a367a7e4 100644 --- a/Trust/Transfer/Controllers/SendViewController.swift +++ b/Trust/Transfer/Controllers/SendViewController.swift @@ -9,7 +9,7 @@ import APIKit import QRCodeReaderViewController protocol SendViewControllerDelegate: class { - func didPressConfirm(transaction: UnconfirmedTransaction, in viewController: SendViewController) + func didPressConfirm(transaction: UnconfirmedTransaction, transferType: TransferType, in viewController: SendViewController) func didCreatePendingTransaction(_ transaction: SentTransaction, in viewController: SendViewController) } @@ -36,7 +36,7 @@ class SendViewController: FormViewController { return form.rowBy(tag: Values.amount) as? TextFloatLabelRow } - init(account: Account, transferType: TransferType = .ether) { + init(account: Account, transferType: TransferType = .ether(destination: .none)) { self.account = account self.transferType = transferType @@ -58,7 +58,7 @@ class SendViewController: FormViewController { button.addTarget(self, action: #selector(self.openReader), for: .touchUpInside) cell.textField.textAlignment = .left - cell.textField.placeholder = "\(self.viewModel.symbol) " + NSLocalizedString("Send.AddressPlaceholder", value: "Address", comment: "") + cell.textField.placeholder = "Ethereum " + NSLocalizedString("Send.AddressPlaceholder", value: "Address", comment: "") cell.textField.rightView = button cell.textField.rightViewMode = .always } @@ -102,7 +102,7 @@ class SendViewController: FormViewController { amount: amount, address: address ) - self.delegate?.didPressConfirm(transaction: transaction, in: self) + self.delegate?.didPressConfirm(transaction: transaction, transferType: transferType, in: self) } @objc func openReader() { diff --git a/Trust/Transfer/Coordinators/SendTransactionCoordinator.swift b/Trust/Transfer/Coordinators/SendTransactionCoordinator.swift index b50a89d21..a66914b43 100644 --- a/Trust/Transfer/Coordinators/SendTransactionCoordinator.swift +++ b/Trust/Transfer/Coordinators/SendTransactionCoordinator.swift @@ -51,22 +51,17 @@ class SendTransactionCoordinator { decimals: Int64, completion: @escaping (Result) -> Void ) { - //let contract = "0x47c5a08256065306216b3e7cd82b599937540d1f" - //let to = "0x0039f22efb07a647557c7c5d17854cfd6d489ef3" - session.web3.request(request: ContractERC20Transfer(amount: amount, decimals: decimals, address: to.address)) { result in switch result { case .success(let res): - NSLog("result \(res)") - self.send( address: contract, value: 0, data: Data(hex: res.drop0x), configuration: TransactionConfiguration( speed: TransactionSpeed.custom( - gasPrice: TransactionSpeed.regular.gasPrice, + gasPrice: TransactionSpeed.cheap.gasPrice, gasLimit: GethNewBigInt(2900000) ) ), diff --git a/Trust/Transfer/Types/PaymentFlow.swift b/Trust/Transfer/Types/PaymentFlow.swift index aef61fe79..5c6bfb363 100644 --- a/Trust/Transfer/Types/PaymentFlow.swift +++ b/Trust/Transfer/Types/PaymentFlow.swift @@ -3,6 +3,6 @@ import Foundation enum PaymentFlow { - case send(destination: Address?) + case send(type: TransferType) case request } diff --git a/Trust/Transfer/Types/TransferType.swift b/Trust/Transfer/Types/TransferType.swift index 491ed9ab9..06e90991c 100644 --- a/Trust/Transfer/Types/TransferType.swift +++ b/Trust/Transfer/Types/TransferType.swift @@ -3,7 +3,7 @@ import Foundation enum TransferType { - case ether + case ether(destination: Address?) case token(Token) }