From 5bd15e0bab4cebd0e3e7b106e0e541d2507cd692 Mon Sep 17 00:00:00 2001 From: Vladyslav Shepitko Date: Fri, 8 Oct 2021 14:08:24 +0300 Subject: [PATCH] Add DAS name lookup #3284 --- AlphaWallet.xcodeproj/project.pbxproj | 8 ++ AlphaWallet/Core/DomainResolver.swift | 13 +++- .../Requests/DASLookupRequest.swift | 78 +++++++++++++++++++ AlphaWallet/Settings/Types/Constants.swift | 8 ++ .../DASNameLookupCoordinator.swift | 37 +++++++++ 5 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 AlphaWallet/EtherClient/Requests/DASLookupRequest.swift create mode 100644 AlphaWallet/Tokens/Coordinators/DASNameLookupCoordinator.swift diff --git a/AlphaWallet.xcodeproj/project.pbxproj b/AlphaWallet.xcodeproj/project.pbxproj index 67b48938a..a53b1c3ab 100644 --- a/AlphaWallet.xcodeproj/project.pbxproj +++ b/AlphaWallet.xcodeproj/project.pbxproj @@ -895,6 +895,8 @@ 87D175ED24AF1565002130D2 /* KeyboardChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D175EC24AF1565002130D2 /* KeyboardChecker.swift */; }; 87D457F526677CBF00BA1442 /* ERC20BalanceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D457F426677CBE00BA1442 /* ERC20BalanceViewModel.swift */; }; 87D457F726677CD300BA1442 /* NativecryptoBalanceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D457F626677CD300BA1442 /* NativecryptoBalanceViewModel.swift */; }; + 87D949BB2710553000A96A85 /* DASLookupRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D949BA2710553000A96A85 /* DASLookupRequest.swift */; }; + 87D949BD2710559700A96A85 /* DASNameLookupCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87D949BC2710559700A96A85 /* DASNameLookupCoordinator.swift */; }; 87DB61C1264A94CD009FBDDE /* ABI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87DB61C0264A94CD009FBDDE /* ABI.swift */; }; 87DB61C3264A9611009FBDDE /* ERC20.json in Resources */ = {isa = PBXBuildFile; fileRef = 87DB61C2264A9611009FBDDE /* ERC20.json */; }; 87DCCB51266F655D003E8EA0 /* WalletSummaryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87DCCB50266F655D003E8EA0 /* WalletSummaryViewModel.swift */; }; @@ -1897,6 +1899,8 @@ 87D175EC24AF1565002130D2 /* KeyboardChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardChecker.swift; sourceTree = ""; }; 87D457F426677CBE00BA1442 /* ERC20BalanceViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ERC20BalanceViewModel.swift; sourceTree = ""; }; 87D457F626677CD300BA1442 /* NativecryptoBalanceViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativecryptoBalanceViewModel.swift; sourceTree = ""; }; + 87D949BA2710553000A96A85 /* DASLookupRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DASLookupRequest.swift; sourceTree = ""; }; + 87D949BC2710559700A96A85 /* DASNameLookupCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DASNameLookupCoordinator.swift; sourceTree = ""; }; 87DB61C0264A94CD009FBDDE /* ABI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ABI.swift; sourceTree = ""; }; 87DB61C2264A9611009FBDDE /* ERC20.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = ERC20.json; sourceTree = ""; }; 87DCCB50266F655D003E8EA0 /* WalletSummaryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletSummaryViewModel.swift; sourceTree = ""; }; @@ -2280,6 +2284,7 @@ 664D11A02007D59F0041A0B0 /* EstimateGasRequest.swift */, 5E7C7ADC229B4038964F417C /* EthCalllRequest.swift */, 5E7C7DA5F3C065F96CCB34B4 /* EthChainIdRequest.swift */, + 87D949BA2710553000A96A85 /* DASLookupRequest.swift */, ); path = Requests; sourceTree = ""; @@ -3117,6 +3122,7 @@ 5E7C769E7A78811BDF9463A3 /* GetWalletNameCoordinator.swift */, 5E7C777C420B7E1C1E6FCF00 /* GetIsERC1155ContractCoordinator.swift */, 87A97D7626FE01B7000C2F38 /* GetENSTextRecordsCoordinator.swift */, + 87D949BC2710559700A96A85 /* DASNameLookupCoordinator.swift */, ); path = Coordinators; sourceTree = ""; @@ -5427,6 +5433,7 @@ 29BB94951F6FC54C009B09CC /* EthereumUnit.swift in Sources */, 29C70C712016C7780072E454 /* SentTransaction.swift in Sources */, 87ED8F99248541380005C69B /* AdvancedSettingsViewModel.swift in Sources */, + 87D949BB2710553000A96A85 /* DASLookupRequest.swift in Sources */, AAEF2CAB2050A68A0038BE0D /* SignatureHelper.swift in Sources */, 29E9CFD21FE737FE00017744 /* TrustRealmConfiguration.swift in Sources */, 2959961C1FAE3EDF00DB66A8 /* AlphaWalletService.swift in Sources */, @@ -5783,6 +5790,7 @@ 5E7C749615D227B91E40B274 /* TokenViewControllerHeaderView.swift in Sources */, 5E7C72EECA8154CEB7D9F46C /* ContainerViewWithShadow.swift in Sources */, 5E7C7A9628548EB8AB8B7A26 /* TokenCollection.swift in Sources */, + 87D949BD2710559700A96A85 /* DASNameLookupCoordinator.swift in Sources */, 878EE951255BEC20000210DE /* ItemType.swift in Sources */, 5E7C75862ABD367EF101DF9C /* SingleChainTokenCoordinator.swift in Sources */, 5E7C70F550D982833859D8B4 /* MigrationInitializer.swift in Sources */, diff --git a/AlphaWallet/Core/DomainResolver.swift b/AlphaWallet/Core/DomainResolver.swift index 79045bc09..91891afac 100644 --- a/AlphaWallet/Core/DomainResolver.swift +++ b/AlphaWallet/Core/DomainResolver.swift @@ -51,14 +51,23 @@ class DomainResolver { return .value(value) } + return DASNameLookupCoordinator() + .resolve(rpcURL: .forResolvingDAS, value: input) + .recover { _ -> Promise in + self.domainResolvation(domain: input) + }.get { address in + self.cache(forNode: node, result: address) + } + } + + private func domainResolvation(domain: String) -> Promise { guard let resolution = resolution else { return .init(error: AnyError.invalidAddress) } return Promise { seal in - resolution.addr(domain: input, ticker: self.ticker) { result in + resolution.addr(domain: domain, ticker: self.ticker) { result in switch result { case .success(let value): if let address = AlphaWallet.Address(string: value) { - self.cache(forNode: node, result: address) seal.fulfill(address) } else { diff --git a/AlphaWallet/EtherClient/Requests/DASLookupRequest.swift b/AlphaWallet/EtherClient/Requests/DASLookupRequest.swift new file mode 100644 index 000000000..ede698892 --- /dev/null +++ b/AlphaWallet/EtherClient/Requests/DASLookupRequest.swift @@ -0,0 +1,78 @@ +// +// DASLookupRequest.swift +// AlphaWallet +// +// Created by Vladyslav Shepitko on 08.10.2021. +// + +import JSONRPCKit +import Foundation + +struct DASLookupRequest: JSONRPCKit.Request { + typealias Response = DASLookupResponse + + let value: String + + var method: String { + return "das_searchAccount" + } + + var parameters: Any? { + return [value] + } + + func response(from resultObject: Any) throws -> Response { + guard let data = try? JSONSerialization.data(withJSONObject: resultObject, options: []) else { + throw CastError(actualValue: resultObject, expectedType: Response.self) + } + if let data = try? JSONDecoder().decode(DASLookupResponse.self, from: data) { + return data + } else { + throw CastError(actualValue: resultObject, expectedType: Response.self) + } + } +} + +struct DASLookupResponse: Decodable { + enum CodingKeys: String, CodingKey { + case errno, errmsg, data + } + let errno: Int + let errmsg: String + let records: [Record] + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + errno = try container.decode(Int.self, forKey: .errno) + errmsg = try container.decode(String.self, forKey: .errmsg) + if let value = try? container.decodeIfPresent(DataClass.self, forKey: .data) { + records = value?.accountData.records ?? [] + } else { + records = [] + } + } + + struct DataClass: Decodable { + let accountData: AccountData + enum CodingKeys: String, CodingKey { + case accountData = "account_data" + } + } + + struct AccountData: Decodable { + enum CodingKeys: String, CodingKey { + case records + } + let records: [Record] + } + + struct Record: Decodable { + enum CodingKeys: String, CodingKey { + case key, label, value, ttl + } + let key: String + let label: String + let value: String + let ttl: String + } +} diff --git a/AlphaWallet/Settings/Types/Constants.swift b/AlphaWallet/Settings/Types/Constants.swift index 63be46ae8..8f6f34d54 100644 --- a/AlphaWallet/Settings/Types/Constants.swift +++ b/AlphaWallet/Settings/Types/Constants.swift @@ -103,6 +103,8 @@ public struct Constants { static let gasNowEndpointBaseUrl = "https://www.gasnow.org" static let highStandardGasThresholdGwei = BigInt(55) + //DAS + static let dasLookupURL = URL(string: "https://indexer.da.systems/")! //Misc public static let etherReceivedNotificationIdentifier = "etherReceivedNotificationIdentifier" @@ -199,3 +201,9 @@ public struct UnitConfiguration { public static let gasFeeUnit: EthereumUnit = .ether public static let finneyUnit: EthereumUnit = .finney } + +extension URL { + static var forResolvingDAS: URL { + return Constants.dasLookupURL + } +} diff --git a/AlphaWallet/Tokens/Coordinators/DASNameLookupCoordinator.swift b/AlphaWallet/Tokens/Coordinators/DASNameLookupCoordinator.swift new file mode 100644 index 000000000..3fc3ef4ee --- /dev/null +++ b/AlphaWallet/Tokens/Coordinators/DASNameLookupCoordinator.swift @@ -0,0 +1,37 @@ +// +// DASNameLookupCoordinator.swift +// AlphaWallet +// +// Created by Vladyslav Shepitko on 08.10.2021. +// + +import JSONRPCKit +import APIKit +import PromiseKit + +public final class DASNameLookupCoordinator { + enum DASNameLookupError: Error { + case ethRecordNotFound + case invalidInput + } + + private static let ethAddressKey = "address.eth" + + static func isValid(value: String) -> Bool { + return value.trimmed.hasSuffix(".bit") + } + + func resolve(rpcURL: URL, value: String) -> Promise { + guard DASNameLookupCoordinator.isValid(value: value) else { + return .init(error: DASNameLookupError.invalidInput) + } + + let request = EtherServiceRequest(rpcURL: rpcURL, batch: BatchFactory().create(DASLookupRequest(value: value))) + return Session.send(request).map { response -> AlphaWallet.Address in + if let record = response.records.first(where: { $0.key == DASNameLookupCoordinator.ethAddressKey }), let address = AlphaWallet.Address(string: record.value) { + return address + } + throw DASNameLookupError.ethRecordNotFound + } + } +}