Add support for .crypto (UnstoppableDomains) domain lookup #1931

pull/2250/head
Vladyslav shepitko 4 years ago committed by Hwee-Boon Yar
parent bafef32384
commit 74fe726b2f
  1. 12
      AlphaWallet.xcodeproj/project.pbxproj
  2. 117
      AlphaWallet/Core/DomainResolver.swift
  3. 24
      AlphaWallet/Core/Views/AddressOrEnsNameLabel.swift
  4. 2
      AlphaWallet/Tokens/Coordinators/GetENSOwnerCoordinator.swift
  5. 3
      Podfile
  6. 24
      Podfile.lock

@ -677,6 +677,7 @@
871E684B24E574F100F220A7 /* ActivityIndicatorControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 871E684824E574F000F220A7 /* ActivityIndicatorControl.swift */; };
8733474E24ED008A002D649D /* TransactionConfirmationRowInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8733474D24ED008A002D649D /* TransactionConfirmationRowInfoView.swift */; };
873F8063246E8E3E00EEE5EF /* SelectCurrencyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 873F8062246E8E3E00EEE5EF /* SelectCurrencyButton.swift */; };
8743CB50255059780039E469 /* DomainResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8743CB4F255059780039E469 /* DomainResolver.swift */; };
874DED0C24C05E88006C8FCE /* TransactionConfirmationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 874DED0A24C05E88006C8FCE /* TransactionConfirmationViewModel.swift */; };
874DED1524C1BAFF006C8FCE /* SelectAssetCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 874DED1424C1BAFF006C8FCE /* SelectAssetCoordinator.swift */; };
874DED1724C1BB0E006C8FCE /* SelectAssetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 874DED1624C1BB0E006C8FCE /* SelectAssetViewController.swift */; };
@ -1490,6 +1491,7 @@
871E684824E574F000F220A7 /* ActivityIndicatorControl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActivityIndicatorControl.swift; sourceTree = "<group>"; };
8733474D24ED008A002D649D /* TransactionConfirmationRowInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionConfirmationRowInfoView.swift; sourceTree = "<group>"; };
873F8062246E8E3E00EEE5EF /* SelectCurrencyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectCurrencyButton.swift; sourceTree = "<group>"; };
8743CB4F255059780039E469 /* DomainResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainResolver.swift; sourceTree = "<group>"; };
874DED0A24C05E88006C8FCE /* TransactionConfirmationViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionConfirmationViewModel.swift; sourceTree = "<group>"; };
874DED1424C1BAFF006C8FCE /* SelectAssetCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectAssetCoordinator.swift; sourceTree = "<group>"; };
874DED1624C1BB0E006C8FCE /* SelectAssetViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectAssetViewController.swift; sourceTree = "<group>"; };
@ -2694,6 +2696,7 @@
5E7C799E4784815CB0202820 /* Core.swift */,
5E7C7543079DF1C7CA998A2D /* Views */,
5E7C70526F00B835220DC0E2 /* Features.swift */,
8743CB4F255059780039E469 /* DomainResolver.swift */,
);
path = Core;
sourceTree = "<group>";
@ -4090,8 +4093,11 @@
"${BUILT_PRODUCTS_DIR}/AWSSNS/AWSSNS.framework",
"${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework",
"${BUILT_PRODUCTS_DIR}/Alamofire-Synchronous/Alamofire_Synchronous.framework",
"${BUILT_PRODUCTS_DIR}/Base58Swift/Base58Swift.framework",
"${BUILT_PRODUCTS_DIR}/BigInt/BigInt.framework",
"${BUILT_PRODUCTS_DIR}/CryptoSwift/CryptoSwift.framework",
"${BUILT_PRODUCTS_DIR}/EthereumABI/EthereumABI.framework",
"${BUILT_PRODUCTS_DIR}/EthereumAddress/EthereumAddress.framework",
"${BUILT_PRODUCTS_DIR}/Eureka/Eureka.framework",
"${BUILT_PRODUCTS_DIR}/JSONRPCKit/JSONRPCKit.framework",
"${BUILT_PRODUCTS_DIR}/JavaScriptKit/JavaScriptKit.framework",
@ -4119,6 +4125,7 @@
"${BUILT_PRODUCTS_DIR}/TrezorCrypto/TrezorCrypto.framework",
"${BUILT_PRODUCTS_DIR}/TrustKeystore/TrustKeystore.framework",
"${BUILT_PRODUCTS_DIR}/TrustWalletCore/WalletCore.framework",
"${BUILT_PRODUCTS_DIR}/UnstoppableDomainsResolution/UnstoppableDomainsResolution.framework",
"${BUILT_PRODUCTS_DIR}/libsodium/libsodium.framework",
"${BUILT_PRODUCTS_DIR}/secp256k1_ios/secp256k1_ios.framework",
"${BUILT_PRODUCTS_DIR}/web3swift/web3swift.framework",
@ -4130,8 +4137,11 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AWSSNS.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire_Synchronous.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Base58Swift.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BigInt.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CryptoSwift.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/EthereumABI.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/EthereumAddress.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Eureka.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/JSONRPCKit.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/JavaScriptKit.framework",
@ -4159,6 +4169,7 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/TrezorCrypto.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/TrustKeystore.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/WalletCore.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/UnstoppableDomainsResolution.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libsodium.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/secp256k1_ios.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/web3swift.framework",
@ -4431,6 +4442,7 @@
293112121FC4F48400966EEA /* ServiceProvider.swift in Sources */,
2912CD2F1F6A83A100C6CBE3 /* ImportWalletViewController.swift in Sources */,
874DED1724C1BB0E006C8FCE /* SelectAssetViewController.swift in Sources */,
8743CB50255059780039E469 /* DomainResolver.swift in Sources */,
2963B6AD1F981A96003063C1 /* TransactionAppearance.swift in Sources */,
29850D2B1F6B30FF00791A49 /* TransactionViewController.swift in Sources */,
296AF9AB1F7380920058AF78 /* GetTransactionCountRequest.swift in Sources */,

@ -0,0 +1,117 @@
//
// DomainResolver.swift
// AlphaWallet
//
// Created by Vladyslav Shepitko on 02.11.2020.
//
import Foundation
import UnstoppableDomainsResolution
import PromiseKit
import web3swift
extension Resolution {
convenience init?(server: RPCServer) {
guard let networkName = server.unstoppableDomainLookupName else { return nil }
try? self.init(providerUrl: server.rpcURL.absoluteString, network: networkName)
}
}
class DomainResolver {
private struct ENSLookupKey: Hashable {
let name: String
let server: RPCServer
}
private enum AnyError: Error {
case failureToResolve
case invalidAddress
case invalidInput
}
private let server: RPCServer
private static var cache: [ENSLookupKey: AlphaWallet.Address] = [:]
private var resolution: Resolution?
private let ticker: String = "eth" //Not sure what `ticker` do we need to use here
init(server: RPCServer) {
self.server = server
self.resolution = Resolution(server: server)
}
func resolveAddress(_ input: String) -> Promise<AlphaWallet.Address> {
//if already an address, send back the address
if let value = AlphaWallet.Address(string: input) {
return .value(value)
}
let node = input.lowercased().nameHash
if let value = cachedResult(forNode: node) {
return .value(value)
}
guard let resolution = resolution else { return .init(error: AnyError.invalidAddress) }
return Promise { seal in
resolution.addr(domain: input, ticker: self.ticker) { result in
switch result {
case .success(let value):
if let address = AlphaWallet.Address(string: value), CryptoAddressValidator.isValidAddress(value) {
self.cache(forNode: node, result: address)
seal.fulfill(address)
} else {
seal.reject(AnyError.invalidAddress)
}
case .failure(let error):
seal.reject(error)
}
}
}
}
private func cachedResult(forNode node: String) -> AlphaWallet.Address? {
return DomainResolver.cache[ENSLookupKey(name: node, server: server)]
}
private func cache(forNode node: String, result: AlphaWallet.Address) {
DomainResolver.cache[ENSLookupKey(name: node, server: server)] = result
}
}
extension GetENSAddressCoordinator {
func getENSAddressFromResolverPromise(value: String) -> Promise<EthereumAddress> {
enum AnyError: Error {
case addressNotFound
}
return Promise { seal in
GetENSAddressCoordinator(server: server).getENSAddressFromResolver(for: value) { result in
if let address = result.value, CryptoAddressValidator.isValidAddress(address.address) {
seal.fulfill(address)
} else {
seal.reject(AnyError.addressNotFound)
}
}
}
}
}
fileprivate extension RPCServer {
//These strings need to match what is used by UnstoppableDomains's code (look up where it's used)
var unstoppableDomainLookupName: String? {
switch self {
case .main: return "mainnet"
case .kovan: return "kovan"
case .ropsten: return "ropsten"
case .rinkeby: return "rinkeby"
case .poa, .sokol, .classic, .callisto, .xDai, .goerli, .artis_sigma1, .artis_tau1, .binance_smart_chain, .binance_smart_chain_testnet:
return nil
case .custom:
return nil
}
}
}

@ -6,6 +6,7 @@
//
import UIKit
import PromiseKit
class AddressOrEnsNameLabel: UILabel {
@ -103,10 +104,11 @@ class AddressOrEnsNameLabel: UILabel {
func resolve(_ value: String, completion: @escaping ((AddressOrEnsResolution) -> Void)) {
clear()
let server = serverToResolveEns
if let address = AlphaWallet.Address(string: value) {
inResolvingState = true
ENSReverseLookupCoordinator(server: serverToResolveEns).getENSNameFromResolver(forAddress: address) { [weak self] result in
ENSReverseLookupCoordinator(server: server).getENSNameFromResolver(forAddress: address) { [weak self] result in
guard let strongSelf = self else { return }
strongSelf.inResolvingState = false
@ -119,18 +121,20 @@ class AddressOrEnsNameLabel: UILabel {
} else if value.contains(".") {
inResolvingState = true
GetENSAddressCoordinator(server: serverToResolveEns).getENSAddressFromResolver(for: value) { [weak self] result in
guard let strongSelf = self else { return }
strongSelf.inResolvingState = false
if let address = result.value, CryptoAddressValidator.isValidAddress(address.address) {
completion(.resolved(.address(AlphaWallet.Address(address: address))))
} else {
completion(.resolved(.none))
DomainResolver(server: server).resolveAddress(value).recover { _ -> Promise<AlphaWallet.Address> in
return GetENSAddressCoordinator(server: server).getENSAddressFromResolverPromise(value: value).map { address in
AlphaWallet.Address(address: address)
}
}.done { address in
completion(.resolved(.address(address)))
}.catch { _ in
completion(.resolved(.none))
}.finally {
self.inResolvingState = false
}
} else {
completion(.invalidInput)
}
}
}

@ -30,7 +30,7 @@ class GetENSAddressCoordinator {
private static let DELAY_AFTER_STOP_TYPING_TO_START_RESOLVING_ENS_NAME = TimeInterval(0.5)
private var toStartResolvingEnsNameTimer: Timer?
private let server: RPCServer
private (set) var server: RPCServer
init(server: RPCServer) {
self.server = server

@ -4,7 +4,7 @@ source 'https://cdn.cocoapods.org/'
target 'AlphaWallet' do
use_frameworks!
pod 'BigInt', '~> 3.0'
pod 'BigInt', '~> 3.1'
pod 'R.swift'
pod 'JSONRPCKit', '~> 2.0.0'
pod 'APIKit'
@ -37,6 +37,7 @@ target 'AlphaWallet' do
pod 'TrustWalletCore'
pod 'AWSSNS'
pod 'Mixpanel-swift'
pod 'UnstoppableDomainsResolution', '0.1.6'
# pod 'AWSCognito'
target 'AlphaWalletTests' do
inherit! :search_paths

@ -7,9 +7,17 @@ PODS:
- AWSCore (2.18.0)
- AWSSNS (2.18.0):
- AWSCore (= 2.18.0)
- Base58Swift (2.1.7):
- BigInt (~> 3.1)
- BigInt (3.1.0):
- SipHash (~> 1.2)
- CryptoSwift (1.3.2)
- EthereumABI (1.3.0):
- BigInt (~> 3.1)
- CryptoSwift (~> 1.0)
- EthereumAddress (~> 1.3)
- EthereumAddress (1.3.0):
- CryptoSwift (~> 1.0)
- Eureka (5.2.1)
- iOSSnapshotTestCase (6.2.0):
- iOSSnapshotTestCase/SwiftSupport (= 6.2.0)
@ -79,6 +87,9 @@ PODS:
- TrustWalletCore/Types
- TrustWalletCore/Types (2.3.3):
- SwiftProtobuf
- UnstoppableDomainsResolution (0.1.6):
- Base58Swift (~> 2.1)
- EthereumABI (~> 1.3)
- web3swift (0.9.0):
- Alamofire (~> 4.7)
- Alamofire-Synchronous (~> 4.0)
@ -93,7 +104,7 @@ DEPENDENCIES:
- AlphaWalletWeb3Provider (from `https://github.com/AlphaWallet/AlphaWallet-web3-provider`, commit `1c1aafb566361e7067e69f6e38b0fdc30b801429`)
- APIKit
- AWSSNS
- BigInt (~> 3.0)
- BigInt (~> 3.1)
- CryptoSwift (~> 1.0)
- Eureka (from `https://github.com/xmartlabs/Eureka.git`, commit `5c54e2607632ce586010e50e91d9adcb6bb3909e`)
- iOSSnapshotTestCase
@ -121,6 +132,7 @@ DEPENDENCIES:
- TrezorCrypto (from `https://github.com/AlphaWallet/trezor-crypto-ios.git`, commit `50c16ba5527e269bbc838e80aee5bac0fe304cc7`)
- TrustKeystore (from `https://github.com/alpha-wallet/trust-keystore.git`, commit `c0bdc4f6ffc117b103e19d17b83109d4f5a0e764`)
- TrustWalletCore
- UnstoppableDomainsResolution (= 0.1.6)
- web3swift (from `https://github.com/AlphaWallet/web3swift.git`, commit `169e50e29b60df72351c689a002005d2e2bc7559`)
SPEC REPOS:
@ -130,8 +142,11 @@ SPEC REPOS:
- APIKit
- AWSCore
- AWSSNS
- Base58Swift
- BigInt
- CryptoSwift
- EthereumABI
- EthereumAddress
- iOSSnapshotTestCase
- JavaScriptKit
- JSONRPCKit
@ -156,6 +171,7 @@ SPEC REPOS:
- SwiftyJSON
- SWXMLHash
- TrustWalletCore
- UnstoppableDomainsResolution
EXTERNAL SOURCES:
AlphaWalletWeb3Provider:
@ -227,8 +243,11 @@ SPEC CHECKSUMS:
APIKit: 9e1a4069608bf0ae5238811e6cfc26928ad4d01e
AWSCore: e8cc7fd06efa211328942cc7c9f6dddbe889a115
AWSSNS: d3ed65985986d5393de2793259e457e466997b55
Base58Swift: 149c9dd95d8712f00e4695b36baafb3031927256
BigInt: 76b5dfdfa3e2e478d4ffdf161aeede5502e2742f
CryptoSwift: 093499be1a94b0cae36e6c26b70870668cb56060
EthereumABI: c021720744d260b87def6aa45d94554d260cb5a9
EthereumAddress: 39fe8e11cf04e4e9902b55ae653dbc4e0aee5f30
Eureka: c883105488e05bc65539f583246ecf9657cabbfe
iOSSnapshotTestCase: 9ab44cb5aa62b84d31847f40680112e15ec579a6
JavaScriptKit: 33a7abbd6e03bf12e3f19f0f8ee753e748a361c1
@ -261,8 +280,9 @@ SPEC CHECKSUMS:
TrezorCrypto: bfeea47a052dca2c77d4a39e1e183865e52de14d
TrustKeystore: 3d8b4571c66648fb985015c96b3185440bb837fe
TrustWalletCore: 84a87886e55b4efa875b452926d3ba58a32359c8
UnstoppableDomainsResolution: dc89a8d9e51f3786b46274b457875a231d5bdbb8
web3swift: 06118d4c4edc801444aaa995bbbddeda176b97ef
PODFILE CHECKSUM: d284670f6269632d01f9c22fd6699ba293e4f2e6
PODFILE CHECKSUM: 9b09ec864c2168207fdd3d0a3cbaddbbf0f696e8
COCOAPODS: 1.10.0

Loading…
Cancel
Save