Refactor qr code detector

pull/5736/head
Krypto Pank 2 years ago
parent 4d15ce10ca
commit 468a33bef6
  1. 2
      AlphaWallet/Accounts/Coordinators/AccountsCoordinator.swift
  2. 51
      AlphaWallet/Browser/Coordinators/QRCodeResolutionCoordinator.swift
  3. 12
      AlphaWallet/Browser/Coordinators/ScanQRCodeCoordinator.swift
  4. 61
      AlphaWallet/Tokens/Coordinators/TokensCoordinator.swift
  5. 2
      AlphaWallet/Tokens/ViewControllers/NewTokenViewController.swift
  6. 2
      AlphaWallet/Transfer/Collectibles/ViewControllers/SendSemiFungibleTokenViewController.swift
  7. 60
      AlphaWallet/Wallet/Coordinators/WalletCoordinator.swift
  8. 8
      AlphaWallet/Wallet/Types/WalletEntryPoint.swift
  9. 2
      AlphaWalletTests/Coordinators/WalletCoordinatorTests.swift
  10. 40
      AlphaWalletTests/Foundation/QRCodeValueParserTests.swift
  11. 4
      modules/AlphaWalletFoundation/AlphaWalletFoundation/Analytics/AnalyticsTypes.swift
  12. 20
      modules/AlphaWalletFoundation/AlphaWalletFoundation/Browser/Models/ScanQRCodeResolution.swift
  13. 8
      modules/AlphaWalletFoundation/AlphaWalletFoundation/Foundation/QRCodeValueParser.swift
  14. 2
      modules/AlphaWalletFoundation/AlphaWalletFoundation/Tokens/Eip681UrlResolver.swift
  15. 6
      modules/AlphaWalletFoundation/AlphaWalletFoundation/Types/DeepLink.swift
  16. 4
      modules/AlphaWalletFoundation/AlphaWalletFoundation/WalletBalance/TokenBalanceFetcher.swift

@ -216,7 +216,7 @@ class AccountsCoordinator: Coordinator {
}
private func showImportWallet() {
importOrCreateWallet(entryPoint: .importWallet)
importOrCreateWallet(entryPoint: .importWallet(params: nil))
}
private func showWatchWallet() {

@ -10,16 +10,19 @@ import BigInt
import PromiseKit
import AlphaWalletFoundation
protocol QRCodeResolutionCoordinatorDelegate: AnyObject {
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolveAddress address: AlphaWallet.Address, action: ScanQRCodeAction)
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolveTransactionType transactionType: TransactionType, token: Token)
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolveWalletConnectURL url: AlphaWallet.WalletConnect.ConnectionUrl)
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolveString value: String)
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolveURL url: URL)
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolveJSON json: String)
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolveSeedPhase seedPhase: [String])
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolvePrivateKey privateKey: String)
enum QrCodeResolution {
case address(address: AlphaWallet.Address, action: ScanQRCodeAction)
case transactionType(transactionType: TransactionType, token: Token)
case walletConnectUrl(url: AlphaWallet.WalletConnect.ConnectionUrl)
case string(value: String)
case url(url: URL)
case json(json: String)
case seedPhase(seedPhase: [String])
case privateKey(privateKey: String)
}
protocol QRCodeResolutionCoordinatorDelegate: AnyObject {
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolve qrCodeResolution: QrCodeResolution)
func didCancel(in coordinator: QRCodeResolutionCoordinator)
}
@ -82,21 +85,21 @@ extension QRCodeResolutionCoordinator: ScanQRCodeCoordinatorDelegate {
}
}
private func resolveScanResult(_ rawValue: String) {
private func resolveScanResult(_ string: String) {
guard let delegate = delegate else { return }
let resolved = ScanQRCodeResolution(rawValue: rawValue)
infoLog("[QR Code] resolved: \(resolved)")
let qrCodeValue = QrCodeValue(string: string)
infoLog("[QR Code] resolved: \(qrCodeValue)")
switch resolved {
case .value(let value):
switch qrCodeValue {
case .addressOrEip681(let value):
switch value {
case .address(let contract):
let actions = availableActions(forContract: contract)
if actions.count == 1 {
delegate.coordinator(self, didResolveAddress: contract, action: actions[0])
delegate.coordinator(self, didResolve: .address(address: contract, action: actions[0]))
} else {
showDidScanWalletAddress(for: actions, completion: { action in
delegate.coordinator(self, didResolveAddress: contract, action: action)
delegate.coordinator(self, didResolve: .address(address: contract, action: action))
}, cancelCompletion: {
self.skipResolvedCodes = false
})
@ -110,7 +113,7 @@ extension QRCodeResolutionCoordinator: ScanQRCodeCoordinatorDelegate {
}.done { result in
switch result {
case .transaction(let transactionType, let token):
delegate.coordinator(self, didResolveTransactionType: transactionType, token: token)
delegate.coordinator(self, didResolve: .transactionType(transactionType: transactionType, token: token))
case .address:
break // Not possible here
}
@ -119,23 +122,23 @@ extension QRCodeResolutionCoordinator: ScanQRCodeCoordinatorDelegate {
break
}
}
case .other(let value):
delegate.coordinator(self, didResolveString: value)
case .string(let value):
delegate.coordinator(self, didResolve: .string(value: value))
case .walletConnect(let url):
delegate.coordinator(self, didResolveWalletConnectURL: url)
delegate.coordinator(self, didResolve: .walletConnectUrl(url: url))
case .url(let url):
showOpenURL(completion: {
delegate.coordinator(self, didResolveURL: url)
delegate.coordinator(self, didResolve: .url(url: url))
}, cancelCompletion: {
//NOTE: we need to reset flag to false to make sure that next detected QR code will be handled
self.skipResolvedCodes = false
})
case .json(let value):
delegate.coordinator(self, didResolveJSON: value)
delegate.coordinator(self, didResolve: .json(json: value))
case .privateKey(let value):
delegate.coordinator(self, didResolvePrivateKey: value)
delegate.coordinator(self, didResolve: .privateKey(privateKey: value))
case .seedPhase(let value):
delegate.coordinator(self, didResolveSeedPhase: value)
delegate.coordinator(self, didResolve: .seedPhase(seedPhase: value))
}
}

@ -123,7 +123,7 @@ extension ScanQRCodeCoordinator {
}
private func convertToAnalyticsResultType(value: String!) -> Analytics.ScanQRCodeResultType {
if let resultType = QRCodeValueParser.from(string: value) {
if let resultType = AddressOrEip681Parser.from(string: value) {
switch resultType {
case .address:
return .address
@ -132,11 +132,11 @@ extension ScanQRCodeCoordinator {
}
}
switch ScanQRCodeResolution(rawValue: value) {
case .value:
return .value
case .other:
return .other
switch QrCodeValue(string: value) {
case .addressOrEip681:
return .addressOrEip681
case .string:
return .string
case .walletConnect:
return .walletConnect
case .url:

@ -318,42 +318,40 @@ extension TokensCoordinator: RenameWalletViewControllerDelegate {
}
extension TokensCoordinator: QRCodeResolutionCoordinatorDelegate {
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolveJSON json: String) {
removeCoordinator(coordinator)
}
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolveSeedPhase seedPhase: [String]) {
removeCoordinator(coordinator)
}
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolvePrivateKey privateKey: String) {
removeCoordinator(coordinator)
}
func didCancel(in coordinator: QRCodeResolutionCoordinator) {
removeCoordinator(coordinator)
}
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolveTransactionType transactionType: TransactionType, token: Token) {
removeCoordinator(coordinator)
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolve qrCodeResolution: QrCodeResolution) {
switch qrCodeResolution {
case .walletConnectUrl(let url):
walletConnectCoordinator.openSession(url: url)
case .transactionType(let transactionType, let token):
delegate?.didTap(suggestedPaymentFlow: .payment(type: .send(type: .transaction(transactionType)), server: token.server), viewController: .none, in: self)
}
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolveAddress address: AlphaWallet.Address, action: ScanQRCodeAction) {
removeCoordinator(coordinator)
case .address(let address, let action):
switch action {
case .addCustomToken:
handleAddCustomToken(address)
case .sendToAddress:
delegate?.didTap(suggestedPaymentFlow: .other(value: .sendToRecipient(recipient: .address(address))), viewController: .none, in: self)
case .watchWallet:
handleWatchWallet(address)
handleImportOrWatchWallet(.watchWallet(address: address))
case .openInEtherscan:
delegate?.didPressViewContractWebPage(forContract: address, server: config.anyEnabledServer(), in: tokensViewController)
}
case .url(let url):
delegate?.didPressOpenWebPage(url, in: tokensViewController)
case .string:
break
case .json(let json):
handleImportOrWatchWallet(.importWallet(params: .json(json: json)))
case .seedPhase(let seedPhase):
handleImportOrWatchWallet(.importWallet(params: .seedPhase(seedPhase: seedPhase)))
case .privateKey(let privateKey):
handleImportOrWatchWallet(.importWallet(params: .privateKey(privateKey: privateKey)))
}
removeCoordinator(coordinator)
}
private func handleAddCustomToken(_ address: AlphaWallet.Address) {
@ -370,32 +368,17 @@ extension TokensCoordinator: QRCodeResolutionCoordinatorDelegate {
coordinator.start()
}
private func handleWatchWallet(_ address: AlphaWallet.Address) {
private func handleImportOrWatchWallet(_ entryPoint: WalletEntryPoint) {
let walletCoordinator = WalletCoordinator(config: config, keystore: keystore, analytics: analytics, domainResolutionService: domainResolutionService)
walletCoordinator.delegate = self
addCoordinator(walletCoordinator)
walletCoordinator.start(.watchWallet(address: address))
walletCoordinator.start(entryPoint)
walletCoordinator.navigationController.makePresentationFullScreenForiOS13Migration()
navigationController.present(walletCoordinator.navigationController, animated: true)
}
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolveURL url: URL) {
removeCoordinator(coordinator)
delegate?.didPressOpenWebPage(url, in: tokensViewController)
}
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolveWalletConnectURL url: AlphaWallet.WalletConnect.ConnectionUrl) {
removeCoordinator(coordinator)
walletConnectCoordinator.openSession(url: url)
}
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolveString value: String) {
removeCoordinator(coordinator)
}
}
extension TokensCoordinator: NewTokenCoordinatorDelegate {

@ -434,7 +434,7 @@ extension NewTokenViewController: PopNotifiable {
extension NewTokenViewController: AddressTextFieldDelegate {
func didScanQRCode(_ result: String) {
switch QRCodeValueParser.from(string: result) {
switch AddressOrEip681Parser.from(string: result) {
case .address(let address):
updateContractValue(value: address.eip55String)
case .eip681, .none:

@ -216,7 +216,7 @@ extension SendSemiFungibleTokenViewController: VerifiableStatusViewController {
extension SendSemiFungibleTokenViewController: AddressTextFieldDelegate {
func didScanQRCode(_ result: String) {
switch QRCodeValueParser.from(string: result) {
switch AddressOrEip681Parser.from(string: result) {
case .address(let address):
targetAddressTextField.value = address.eip55String
case .eip681, .none:

@ -38,9 +38,22 @@ class WalletCoordinator: Coordinator {
///Return true if caller should proceed to show UI (`navigationController`)
@discardableResult func start(_ entryPoint: WalletEntryPoint) -> Bool {
switch entryPoint {
case .importWallet:
case .importWallet(let params):
let controller = ImportWalletViewController(keystore: keystore, analytics: analytics, domainResolutionService: domainResolutionService)
controller.delegate = self
switch params {
case .json(let json):
controller.set(tabSelection: .keystore)
controller.setValueForCurrentField(string: json)
case .seedPhase(let seedPhase):
controller.set(tabSelection: .mnemonic)
controller.setValueForCurrentField(string: seedPhase.joined(separator: " "))
case .privateKey(let privateKey):
controller.set(tabSelection: .privateKey)
controller.setValueForCurrentField(string: privateKey)
case .none:
break
}
controller.navigationItem.rightBarButtonItem = UIBarButtonItem.cancelBarButton(self, selector: #selector(dismiss))
navigationController.viewControllers = [controller]
importWalletViewController = controller
@ -146,48 +159,25 @@ extension WalletCoordinator: ImportWalletViewControllerDelegate {
extension WalletCoordinator: QRCodeResolutionCoordinatorDelegate {
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolveAddress address: AlphaWallet.Address, action: ScanQRCodeAction) {
removeCoordinator(coordinator)
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolve qrCodeResolution: QrCodeResolution) {
switch qrCodeResolution {
case .walletConnectUrl, .transactionType, .url, .string:
break
case .address(let address, _):
importWalletViewController?.set(tabSelection: .watch)
importWalletViewController?.setValueForCurrentField(string: address.eip55String)
}
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolveTransactionType transactionType: TransactionType, token: Token) {
removeCoordinator(coordinator)
}
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolveWalletConnectURL url: AlphaWallet.WalletConnect.ConnectionUrl) {
removeCoordinator(coordinator)
}
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolveString value: String) {
removeCoordinator(coordinator)
}
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolveURL url: URL) {
removeCoordinator(coordinator)
}
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolveJSON json: String) {
removeCoordinator(coordinator)
case .json(let json):
importWalletViewController?.set(tabSelection: .keystore)
importWalletViewController?.setValueForCurrentField(string: json)
}
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolveSeedPhase seedPhase: [String]) {
removeCoordinator(coordinator)
case .seedPhase(let seedPhase):
importWalletViewController?.set(tabSelection: .mnemonic)
importWalletViewController?.setValueForCurrentField(string: seedPhase.joined(separator: " "))
case .privateKey(let privateKey):
importWalletViewController?.set(tabSelection: .privateKey)
importWalletViewController?.setValueForCurrentField(string: privateKey)
}
func coordinator(_ coordinator: QRCodeResolutionCoordinator, didResolvePrivateKey privateKey: String) {
removeCoordinator(coordinator)
importWalletViewController?.set(tabSelection: .privateKey)
importWalletViewController?.setValueForCurrentField(string: privateKey)
}
func didCancel(in coordinator: QRCodeResolutionCoordinator) {
@ -209,7 +199,7 @@ extension WalletCoordinator: CreateInitialWalletViewControllerDelegate {
func didTapImportWallet(inViewController viewController: CreateInitialWalletViewController) {
logInitialAction(.import)
addWalletWith(entryPoint: .importWallet)
addWalletWith(entryPoint: .importWallet(params: nil))
}
}

@ -3,9 +3,15 @@
import Foundation
import AlphaWalletFoundation
enum ImportWalletParams {
case json(json: String)
case seedPhase(seedPhase: [String])
case privateKey(privateKey: String)
}
enum WalletEntryPoint {
case addInitialWallet
case createInstantWallet
case importWallet
case importWallet(params: ImportWalletParams?)
case watchWallet(address: AlphaWallet.Address?)
}

@ -15,7 +15,7 @@ class WalletCoordinatorTests: XCTestCase {
domainResolutionService: FakeDomainResolutionService()
)
coordinator.start(.importWallet)
coordinator.start(.importWallet(params: nil))
XCTAssertTrue(coordinator.navigationController.viewControllers[0] is ImportWalletViewController)
}

@ -6,14 +6,14 @@ import AlphaWalletFoundation
class QRCodeValueParserTests: XCTestCase {
func testEmptyString() {
let result = QRCodeValueParser.from(string: "")
let result = AddressOrEip681Parser.from(string: "")
XCTAssertNil(result)
}
func testJustAddressString() {
let input = "0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c"
guard let result = QRCodeValueParser.from(string: input) else { return XCTFail("Can't parse address-only") }
guard let result = AddressOrEip681Parser.from(string: input) else { return XCTFail("Can't parse address-only") }
switch result {
case .address(let address):
XCTAssertTrue(address.sameContract(as: input))
@ -24,12 +24,12 @@ class QRCodeValueParserTests: XCTestCase {
func testInvalidJustAddressStringWithEip681Prefix() {
let input = "pay-0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c"
XCTAssertNil(QRCodeValueParser.from(string: input))
XCTAssertNil(AddressOrEip681Parser.from(string: input))
}
func testJustAddressString2() {
let input = "0x6973dbabeb06dd60f1c50ed688fe11e742bc123e"
guard let result = QRCodeValueParser.from(string: input) else { return XCTFail("Can't parse address-only") }
guard let result = AddressOrEip681Parser.from(string: input) else { return XCTFail("Can't parse address-only") }
switch result {
case .address(let address):
XCTAssertTrue(address.sameContract(as: input))
@ -39,7 +39,7 @@ class QRCodeValueParserTests: XCTestCase {
}
func testProtocolAndAddress() {
guard let result = QRCodeValueParser.from(string: "ethereum:0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c") else { return XCTFail("Can't parse EIP 681") }
guard let result = AddressOrEip681Parser.from(string: "ethereum:0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c") else { return XCTFail("Can't parse EIP 681") }
switch result {
case .address:
XCTFail("Can't parse EIP 681")
@ -49,7 +49,7 @@ class QRCodeValueParserTests: XCTestCase {
}
func testEthereumAddress() {
guard let result = QRCodeValueParser.from(string: "ethereum:0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c") else { return XCTFail("Can't parse EIP 681") }
guard let result = AddressOrEip681Parser.from(string: "ethereum:0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c") else { return XCTFail("Can't parse EIP 681") }
switch result {
case .address:
XCTFail("Can't parse EIP 681")
@ -59,7 +59,7 @@ class QRCodeValueParserTests: XCTestCase {
}
func testEthereumAddressWithValue() {
guard let result = QRCodeValueParser.from(string: "ethereum:0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c?value=1") else { return XCTFail("Can't parse EIP 681") }
guard let result = AddressOrEip681Parser.from(string: "ethereum:0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c?value=1") else { return XCTFail("Can't parse EIP 681") }
switch result {
case .address:
XCTFail("Can't parse EIP 681")
@ -69,7 +69,7 @@ class QRCodeValueParserTests: XCTestCase {
}
func testExtractChain() {
guard let result = QRCodeValueParser.from(string: "ethereum:0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c@3?value=1") else { return XCTFail("Can't parse EIP 681") }
guard let result = AddressOrEip681Parser.from(string: "ethereum:0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c@3?value=1") else { return XCTFail("Can't parse EIP 681") }
switch result {
case .address:
XCTFail("Can't parse EIP 681")
@ -79,7 +79,7 @@ class QRCodeValueParserTests: XCTestCase {
}
func testOMGAddress() {
guard let result = QRCodeValueParser.from(string: "omg:0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c") else { return XCTFail("Can't parse EIP 681") }
guard let result = AddressOrEip681Parser.from(string: "omg:0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c") else { return XCTFail("Can't parse EIP 681") }
switch result {
case .address:
XCTFail("Can't parse EIP 681")
@ -90,7 +90,7 @@ class QRCodeValueParserTests: XCTestCase {
}
func testBancorAddress() {
guard let result = QRCodeValueParser.from(string: "bancor:0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c") else { return XCTFail("Can't parse EIP 681") }
guard let result = AddressOrEip681Parser.from(string: "bancor:0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c") else { return XCTFail("Can't parse EIP 681") }
switch result {
case .address:
XCTFail("Can't parse EIP 681")
@ -101,7 +101,7 @@ class QRCodeValueParserTests: XCTestCase {
}
func testParseData() {
guard let result = QRCodeValueParser.from(string: "ethereum:0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c?data=0x123") else { return XCTFail("Can't parse EIP 681") }
guard let result = AddressOrEip681Parser.from(string: "ethereum:0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c?data=0x123") else { return XCTFail("Can't parse EIP 681") }
switch result {
case .address:
XCTFail("Can't parse EIP 681")
@ -113,7 +113,7 @@ class QRCodeValueParserTests: XCTestCase {
}
func testParseMultipleValues() {
guard let result = QRCodeValueParser.from(string: "ethereum:0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c?data=0x123&amount=1.0") else { return XCTFail("Can't parse EIP 681") }
guard let result = AddressOrEip681Parser.from(string: "ethereum:0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c?data=0x123&amount=1.0") else { return XCTFail("Can't parse EIP 681") }
switch result {
case .address:
XCTFail("Can't parse EIP 681")
@ -126,7 +126,7 @@ class QRCodeValueParserTests: XCTestCase {
}
func testParseNativeCryptoSend() {
guard let qrCodeValue = QRCodeValueParser.from(string: "ethereum:0xfb6916095ca1df60bb79Ce92ce3ea74c37c5d359?value=2.014e18") else { return XCTFail("Can't parse EIP 681") }
guard let qrCodeValue = AddressOrEip681Parser.from(string: "ethereum:0xfb6916095ca1df60bb79Ce92ce3ea74c37c5d359?value=2.014e18") else { return XCTFail("Can't parse EIP 681") }
let expectation = self.expectation(description: "Promise resolves")
switch qrCodeValue {
case .address:
@ -148,7 +148,7 @@ class QRCodeValueParserTests: XCTestCase {
}
func testParseNativeCryptoSendWithScientificNotation() {
guard let qrCodeValue = QRCodeValueParser.from(string: "ethereum:0xfb6916095ca1df60bb79Ce92ce3ea74c37c5d359?value=2.014e18") else { return XCTFail("Can't parse EIP 681") }
guard let qrCodeValue = AddressOrEip681Parser.from(string: "ethereum:0xfb6916095ca1df60bb79Ce92ce3ea74c37c5d359?value=2.014e18") else { return XCTFail("Can't parse EIP 681") }
let expectation = self.expectation(description: "Promise resolves")
switch qrCodeValue {
case .address:
@ -170,7 +170,7 @@ class QRCodeValueParserTests: XCTestCase {
}
func testParseErc20Send() {
guard let qrCodeValue = QRCodeValueParser.from(string: "ethereum:0x744d70fdbe2ba4cf95131626614a1763df805b9e/transfer?address=0x3d597789ea16054a084ac84ce87f50df9198f415&uint256=314e17") else { return XCTFail("Can't parse EIP 681") }
guard let qrCodeValue = AddressOrEip681Parser.from(string: "ethereum:0x744d70fdbe2ba4cf95131626614a1763df805b9e/transfer?address=0x3d597789ea16054a084ac84ce87f50df9198f415&uint256=314e17") else { return XCTFail("Can't parse EIP 681") }
let expectation = self.expectation(description: "Promise resolves")
switch qrCodeValue {
case .address:
@ -193,7 +193,7 @@ class QRCodeValueParserTests: XCTestCase {
}
func testParseErc20SendWithoutRecipient() {
guard let qrCodeValue = QRCodeValueParser.from(string: "ethereum:0x60fa213f48cd0d83b54380108ccd03a6993247e0/transfer?uint256=1.5e18") else { return XCTFail("Can't parse EIP 681") }
guard let qrCodeValue = AddressOrEip681Parser.from(string: "ethereum:0x60fa213f48cd0d83b54380108ccd03a6993247e0/transfer?uint256=1.5e18") else { return XCTFail("Can't parse EIP 681") }
let expectation = self.expectation(description: "Promise resolves")
switch qrCodeValue {
case .address:
@ -216,7 +216,7 @@ class QRCodeValueParserTests: XCTestCase {
}
func testParseNativeCryptoSendWithoutValue() {
guard let qrCodeValue = QRCodeValueParser.from(string: "ethereum:0xfb6916095ca1df60bb79Ce92ce3ea74c37c5d359") else { return XCTFail("Can't parse EIP 681") }
guard let qrCodeValue = AddressOrEip681Parser.from(string: "ethereum:0xfb6916095ca1df60bb79Ce92ce3ea74c37c5d359") else { return XCTFail("Can't parse EIP 681") }
let expectation = self.expectation(description: "Promise resolves")
switch qrCodeValue {
case .address:
@ -238,7 +238,7 @@ class QRCodeValueParserTests: XCTestCase {
}
func testParseErc20SendWithoutAmount() {
guard let qrCodeValue = QRCodeValueParser.from(string: "ethereum:0x744d70fdbe2ba4cf95131626614a1763df805b9e/transfer?address=0x3d597789ea16054a084ac84ce87f50df9198f415") else { return XCTFail("Can't parse EIP 681") }
guard let qrCodeValue = AddressOrEip681Parser.from(string: "ethereum:0x744d70fdbe2ba4cf95131626614a1763df805b9e/transfer?address=0x3d597789ea16054a084ac84ce87f50df9198f415") else { return XCTFail("Can't parse EIP 681") }
let expectation = self.expectation(description: "Promise resolves")
switch qrCodeValue {
case .address:
@ -261,7 +261,7 @@ class QRCodeValueParserTests: XCTestCase {
}
func testParseInvalidNativeCryptoSend() {
guard let qrCodeValue = QRCodeValueParser.from(string: "ethereum:0xfb6916095ca1df60bb79Ce92ce3ea74c37c5d359/foo?value=2.014e18") else { return XCTFail("Can't parse EIP 681") }
guard let qrCodeValue = AddressOrEip681Parser.from(string: "ethereum:0xfb6916095ca1df60bb79Ce92ce3ea74c37c5d359/foo?value=2.014e18") else { return XCTFail("Can't parse EIP 681") }
let expectation = self.expectation(description: "Promise resolves")
switch qrCodeValue {
case .address:
@ -281,7 +281,7 @@ class QRCodeValueParserTests: XCTestCase {
}
func testParseNativeCryptoSendWithoutValueWithEnsName() {
guard let qrCodeValue = QRCodeValueParser.from(string: "ethereum:foo.eth") else { return XCTFail("Can't parse EIP 681") }
guard let qrCodeValue = AddressOrEip681Parser.from(string: "ethereum:foo.eth") else { return XCTFail("Can't parse EIP 681") }
let expectation = self.expectation(description: "Promise resolves")
switch qrCodeValue {
case .address:

@ -162,9 +162,9 @@ public enum Analytics {
}
public enum ScanQRCodeResultType: String {
case value
case addressOrEip681
case walletConnect
case other
case string
case url
case privateKey
case seedPhase

@ -1,5 +1,5 @@
//
// ScanQRCodeResolution.swift
// QrCodeValue.swift
// AlphaWallet
//
// Created by Vladyslav Shepitko on 30.08.2022.
@ -14,21 +14,21 @@ public enum ScanQRCodeAction: CaseIterable {
case openInEtherscan
}
public enum ScanQRCodeResolution {
case value(value: QRCodeValue)
public enum QrCodeValue {
case addressOrEip681(value: AddressOrEip681)
case walletConnect(AlphaWallet.WalletConnect.ConnectionUrl)
case other(String)
case string(String)
case url(URL)
case privateKey(String)
case seedPhase([String])
case json(String)
public init(rawValue: String) {
let trimmedValue = rawValue.trimmed
public init(string: String) {
let trimmedValue = string.trimmed
if let value = QRCodeValueParser.from(string: trimmedValue) {
self = .value(value: value)
} else if let url = AlphaWallet.WalletConnect.ConnectionUrl(rawValue) {
if let value = AddressOrEip681Parser.from(string: trimmedValue) {
self = .addressOrEip681(value: value)
} else if let url = AlphaWallet.WalletConnect.ConnectionUrl(string) {
self = .walletConnect(url)
} else if let url = URL(string: trimmedValue), trimmedValue.isValidURL {
self = .url(url)
@ -40,7 +40,7 @@ public enum ScanQRCodeResolution {
} else {
let components = trimmedValue.components(separatedBy: " ")
if components.isEmpty || components.count == 1 {
self = .other(trimmedValue)
self = .string(trimmedValue)
} else {
self = .seedPhase(components)
}

@ -2,7 +2,7 @@
import Foundation
public enum QRCodeValue {
public enum AddressOrEip681 {
case address(AlphaWallet.Address)
///Strictly speaking, EIP 681 should be like this:
/// ethereum:pay-0xfb6916095ca1df60bb79Ce92ce3ea74c37c5d359?value=2.014e18
@ -10,8 +10,8 @@ public enum QRCodeValue {
case eip681(protocolName: String, address: AddressOrEnsName, functionName: String?, params: [String: String])
}
public struct QRCodeValueParser {
public static func from(string: String) -> QRCodeValue? {
public struct AddressOrEip681Parser {
public static func from(string: String) -> AddressOrEip681? {
let string = string.trimmed
let parts = string.components(separatedBy: ":")
if parts.count == 1, let address = parts.first.flatMap({ AlphaWallet.Address(string: $0) }) {
@ -22,7 +22,7 @@ public struct QRCodeValueParser {
let secondHalf = parts[1]
let uncheckedParamParts = Array(secondHalf.components(separatedBy: "?")[1...])
let paramParts = uncheckedParamParts.isEmpty ? [] : Array(uncheckedParamParts[0].components(separatedBy: "&"))
var params = QRCodeValueParser.parseParamsFromParamParts(paramParts: paramParts)
var params = AddressOrEip681Parser.parseParamsFromParamParts(paramParts: paramParts)
if let chainId = secondHalf.slice(from: "@", to: "/") {
params["chainId"] = chainId
} else if let chainId = secondHalf.slice(from: "@", to: "?") {

@ -35,7 +35,7 @@ public final class Eip681UrlResolver {
}
@discardableResult public func resolve(url: URL) -> Promise<Eip681UrlResolver.Resolution> {
switch QRCodeValueParser.from(string: url.absoluteString) {
switch AddressOrEip681Parser.from(string: url.absoluteString) {
case .address(let address):
return .value(.address(address))
case .eip681(let protocolName, let address, let functionName, let params):

@ -163,8 +163,8 @@ extension DeepLink.functional {
//E.g. https://aw.app/ethereum:0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7/transfer?address=0x8e23ee67d1332ad560396262c48ffbb01f93d052&uint256=1
public static func extractEip681UrlMaybeEmbedded(in url: URL, supportedServers: [RPCServer]) -> URL? {
let rawEip681Url: URL? = {
guard let scheme = url.scheme, scheme == Eip681Parser.scheme, QRCodeValueParser.from(string: url.absoluteString) != nil else { return nil }
switch QRCodeValueParser.from(string: url.absoluteString) {
guard let scheme = url.scheme, scheme == Eip681Parser.scheme, AddressOrEip681Parser.from(string: url.absoluteString) != nil else { return nil }
switch AddressOrEip681Parser.from(string: url.absoluteString) {
case .none, .address:
return nil
case .eip681:
@ -177,7 +177,7 @@ extension DeepLink.functional {
return nil
}
let eip681Url = result.path
switch QRCodeValueParser.from(string: eip681Url) {
switch AddressOrEip681Parser.from(string: eip681Url) {
case .address, .none:
return nil
case .eip681:

@ -192,10 +192,10 @@ public class TokenBalanceFetcher: TokenBalanceFetcherType {
for (contract, nonFungibles) in contractToNonFungibles {
var listOfAssets = [NonFungibleBalance.NftAssetRawValue]()
var anyNonFungible: T?
var anyNonFungible: T? = nonFungibles.compactMap { $0.value }.first
for each in nonFungibles {
if let encodedJson = try? JSONEncoder().encode(each.value), let jsonString = String(data: encodedJson, encoding: .utf8) {
anyNonFungible = each.value
// anyNonFungible = each.value
listOfAssets.append(.init(json: jsonString, source: each.source))
} else {
//no op

Loading…
Cancel
Save