[Refactoring] refactor Ramp and Oneinch

pull/6779/head
Krypto Pank 2 years ago
parent 7867ae9456
commit a36e724b9e
  1. 4
      AlphaWallet/Common/Services/TokenActionsService+Extensions.swift
  2. 4
      AlphaWalletTests/Coordinators/AppCoordinatorTests.swift
  3. 10
      AlphaWalletTests/modules/AlphaWalletFoundation/Oneinch/OneinchTests.swift
  4. 10
      AlphaWalletTests/modules/AlphaWalletFoundation/Ramp/RampTests.swift
  5. 29
      modules/AlphaWalletFoundation/AlphaWalletFoundation/BuyToken/Ramp/Ramp.swift
  6. 6
      modules/AlphaWalletFoundation/AlphaWalletFoundation/BuyToken/Ramp/RampNetworking.swift
  7. 28
      modules/AlphaWalletFoundation/AlphaWalletFoundation/SwapToken/Oneinch/Oneinch.swift
  8. 10
      modules/AlphaWalletFoundation/AlphaWalletFoundation/SwapToken/Oneinch/OneinchNetworking.swift

@ -14,7 +14,7 @@ extension TokenActionsService {
let traitCollection = UINavigationController().traitCollection
service.register(service: BuyTokenProvider(subProviders: [
Coinbase(action: R.string.localizable.aWalletTokenBuyOnCoinbaseTitle()),
Ramp(action: R.string.localizable.aWalletTokenBuyOnRampTitle(), networkProvider: RampNetworkProvider(networkService: networkService))
Ramp(action: R.string.localizable.aWalletTokenBuyOnRampTitle(), networking: BaseRampNetworking(networkService: networkService))
], action: R.string.localizable.aWalletTokenBuyTitle()))
let honeySwapService = HoneySwap(action: R.string.localizable.aWalletTokenErc20ExchangeHoneyswapButtonTitle())
@ -25,7 +25,7 @@ extension TokenActionsService {
var availableSwapProviders: [SupportedTokenActionsProvider & TokenActionProvider] = [
honeySwapService,
quickSwap,
Oneinch(action: R.string.localizable.aWalletTokenErc20ExchangeOn1inchButtonTitle(), networkProvider: OneinchNetworkProvider(networkService: networkService)),
Oneinch(action: R.string.localizable.aWalletTokenErc20ExchangeOn1inchButtonTitle(), networking: BaseOneinchNetworking(networkService: networkService)),
//uniswap
]
availableSwapProviders += Features.default.isAvailable(.isSwapEnabled) ? [SwapTokenNativeProvider(tokenSwapper: tokenSwapper)] : []

@ -47,7 +47,7 @@ class AppCoordinatorTests: XCTestCase {
coordinator.start()
XCTAssertEqual(3, coordinator.coordinators.count)
XCTAssertEqual(4, coordinator.coordinators.count)
XCTAssertTrue(coordinator.navigationController.viewControllers[0] is AccountsViewController)
XCTAssertTrue(coordinator.navigationController.viewControllers[1] is UITabBarController)
@ -112,7 +112,7 @@ class AppCoordinatorTests: XCTestCase {
coordinator.showActiveWallet(for: .make(), animated: true)
XCTAssertEqual(5, coordinator.coordinators.count)
XCTAssertEqual(6, coordinator.coordinators.count)
XCTAssertTrue(coordinator.navigationController.viewControllers[0] is AccountsViewController)
XCTAssertTrue(coordinator.navigationController.viewControllers[1] is UITabBarController)
}

@ -18,26 +18,26 @@ final class OneinchTests: XCTestCase {
func testOneinch() {
let reachability: ReachabilityManagerProtocol = FakeReachabilityManager(true)
let networkProvider = FakeOneinchNetworkProvider()
let networking = FakeBaseOneinchNetworking()
let retries: UInt = 3
let retryBehavior: RetryBehavior<RunLoop> = .randomDelayed(retries: retries, delayBeforeRetry: 1, delayUpperRangeValueFrom0To: 3)
let oneinch = Oneinch(action: "Buy with Oneinch", networkProvider: networkProvider, reachability: reachability, retryBehavior: retryBehavior)
let oneinch = Oneinch(action: "Buy with Oneinch", networking: networking, reachability: reachability, retryBehavior: retryBehavior)
infoLog("[Oneinch] Start")
oneinch.start()
let expectation = self.expectation(description: "Wait for failure")
oneinch.objectWillChange.sink { [weak oneinch, networkProvider] _ in
oneinch.objectWillChange.sink { [weak oneinch, networking] _ in
infoLog("[Oneinch] objectWillChange")
guard let oneinch = oneinch else { return XCTFail() }
guard case .failure = oneinch.assets else { return XCTFail() }
expectation.fulfill()
XCTAssertTrue(networkProvider.asyncAPICallCount == retries + 1)
XCTAssertTrue(networking.asyncAPICallCount == retries + 1)
}.store(in: &cancelable)
waitForExpectations(timeout: 60)
}
final class FakeOneinchNetworkProvider: OneinchNetworkProviderType {
final class FakeBaseOneinchNetworking: OneinchNetworking {
let msTimeFormatter: DateFormatter = {
let msTimeFormatter = DateFormatter()
msTimeFormatter.dateFormat = "[HH:mm:ss.SSSS] "

@ -18,26 +18,26 @@ final class RampTests: XCTestCase {
func testRamp() {
let reachability: ReachabilityManagerProtocol = FakeReachabilityManager(true)
let networkProvider = FakeRampNetworkProvider()
let networking = FakeRampNetworkProvider()
let retries: UInt = 3
let retryBehavior: RetryBehavior<RunLoop> = .randomDelayed(retries: retries, delayBeforeRetry: 1, delayUpperRangeValueFrom0To: 3)
let ramp = Ramp(action: "Buy with Ramp", networkProvider: networkProvider, reachability: reachability, retryBehavior: retryBehavior)
let ramp = Ramp(action: "Buy with Ramp", networking: networking, reachability: reachability, retryBehavior: retryBehavior)
infoLog("[Ramp] Start")
ramp.start()
let expectation = self.expectation(description: "Wait for failure")
ramp.objectWillChange.sink { [weak ramp, networkProvider] _ in
ramp.objectWillChange.sink { [weak ramp, networking] _ in
infoLog("[Ramp] objectWillChange")
guard let ramp = ramp else { return XCTFail() }
guard case .failure = ramp.assets else { return XCTFail() }
expectation.fulfill()
XCTAssertTrue(networkProvider.asyncAPICallCount == retries + 1)
XCTAssertTrue(networking.asyncAPICallCount == retries + 1)
}.store(in: &cancelable)
waitForExpectations(timeout: 60)
}
final class FakeRampNetworkProvider: RampNetworkProviderType {
final class FakeRampNetworkProvider: RampNetworking {
let msTimeFormatter: DateFormatter = {
let msTimeFormatter = DateFormatter()
msTimeFormatter.dateFormat = "[HH:mm:ss.SSSS] "

@ -12,11 +12,11 @@ import AlphaWalletLogger
public final class Ramp: SupportedTokenActionsProvider, BuyTokenURLProviderType {
private var objectWillChangeSubject = PassthroughSubject<Void, Never>()
private (set) public var assets: Swift.Result<[Asset], Error> = .failure(RampError())
private (set) public var assets: Loadable<[Asset], PromiseError> = .loading
private let queue: DispatchQueue = .init(label: "org.alphawallet.swift.Ramp")
private var cancelable = Set<AnyCancellable>()
private let reachability: ReachabilityManagerProtocol
private let networkProvider: RampNetworkProviderType
private let networking: RampNetworking
private let retryBehavior: RetryBehavior<RunLoop>
public var objectWillChange: AnyPublisher<Void, Never> {
@ -28,10 +28,14 @@ public final class Ramp: SupportedTokenActionsProvider, BuyTokenURLProviderType
public let analyticsName: String = "Ramp"
public let action: String
public init(action: String, networkProvider: RampNetworkProviderType, reachability: ReachabilityManagerProtocol = ReachabilityManager(), retryBehavior: RetryBehavior<RunLoop> = Oneinch.defaultRetryBehavior) {
public init(action: String,
networking: RampNetworking,
reachability: ReachabilityManagerProtocol = ReachabilityManager(),
retryBehavior: RetryBehavior<RunLoop> = Oneinch.defaultRetryBehavior) {
self.action = action
self.reachability = reachability
self.networkProvider = networkProvider
self.networking = networking
self.retryBehavior = retryBehavior
}
@ -62,21 +66,16 @@ public final class Ramp: SupportedTokenActionsProvider, BuyTokenURLProviderType
&& (asset.address == nil ? token.contractAddress == Constants.nativeCryptoAddressInDatabase : asset.address! == token.contractAddress)
}
guard !token.server.isTestnet else { return nil }
switch assets {
case .success(let assets):
return assets.first(where: { isAssetMatchesForToken(token: token, asset: $0) })
case .failure:
return nil
}
guard let assets = assets.value, !token.server.isTestnet else { return nil }
return assets.first(where: { isAssetMatchesForToken(token: token, asset: $0) })
}
public func start() {
reachability.networkBecomeReachablePublisher
.receive(on: queue)
.setFailureType(to: PromiseError.self)
.flatMapLatest { [networkProvider, retryBehavior] _ -> AnyPublisher<[Asset], PromiseError> in
networkProvider.retrieveAssets()
.flatMapLatest { [networking, retryBehavior] _ -> AnyPublisher<[Asset], PromiseError> in
networking.retrieveAssets()
.retry(retryBehavior, scheduler: RunLoop.main)
.eraseToAnyPublisher()
}.receive(on: queue)
@ -84,10 +83,10 @@ public final class Ramp: SupportedTokenActionsProvider, BuyTokenURLProviderType
objectWillChangeSubject.send(())
guard case .failure(let error) = result else { return }
let request = RampNetworkProvider.RampRequest()
let request = BaseRampNetworking.RampRequest()
RemoteLogger.instance.logRpcOrOtherWebError("Ramp error | \(error)", url: request.urlRequest?.url?.absoluteString ?? "")
} receiveValue: {
self.assets = .success($0)
self.assets = .done($0)
}.store(in: &cancelable)
}
}

@ -9,11 +9,11 @@ import Foundation
import AlphaWalletCore
import Combine
public protocol RampNetworkProviderType {
public protocol RampNetworking {
func retrieveAssets() -> AnyPublisher<[Asset], PromiseError>
}
public final class RampNetworkProvider: RampNetworkProviderType {
public final class BaseRampNetworking: RampNetworking {
private let decoder = JSONDecoder()
private let networkService: NetworkService
@ -31,7 +31,7 @@ public final class RampNetworkProvider: RampNetworkProviderType {
}
}
//NOTE: internal because we use it also for debugging
extension RampNetworkProvider {
extension BaseRampNetworking {
struct RampRequest: URLRequestConvertible {
func asURLRequest() throws -> URLRequest {

@ -10,7 +10,7 @@ import Combine
import AlphaWalletCore
public class Oneinch: SupportedTokenActionsProvider, SwapTokenViaUrlProvider {
private (set) public var assets: Swift.Result<[AlphaWallet.Address: Oneinch.Asset], Error> = .failure(OneinchError())
private (set) public var assets: Loadable<[AlphaWallet.Address: Oneinch.Asset], Error> = .loading
private let queue = DispatchQueue(label: "org.alphawallet.swift.Oneinch")
private var cancelable = Set<AnyCancellable>()
private var objectWillChangeSubject = PassthroughSubject<Void, Never>()
@ -23,7 +23,7 @@ public class Oneinch: SupportedTokenActionsProvider, SwapTokenViaUrlProvider {
private var predefinedAssets: [Oneinch.Asset] {
[.init(symbol: "ETH", name: "ETH", address: Constants.nativeCryptoAddressInDatabase, decimal: RPCServer.main.decimals)]
}
private let networkProvider: OneinchNetworkProviderType
private let networking: OneinchNetworking
private let reachability: ReachabilityManagerProtocol
private let retryBehavior: RetryBehavior<RunLoop>
public static let defaultRetryBehavior: RetryBehavior<RunLoop> = .randomDelayed(retries: 3, delayBeforeRetry: 5, delayUpperRangeValueFrom0To: 15)
@ -37,9 +37,13 @@ public class Oneinch: SupportedTokenActionsProvider, SwapTokenViaUrlProvider {
public let analyticsNavigation: Analytics.Navigation = .onOneinch
public let analyticsName: String = "Oneinch"
public init(action: String, networkProvider: OneinchNetworkProviderType, reachability: ReachabilityManagerProtocol = ReachabilityManager(), retryBehavior: RetryBehavior<RunLoop> = Oneinch.defaultRetryBehavior) {
public init(action: String,
networking: OneinchNetworking,
reachability: ReachabilityManagerProtocol = ReachabilityManager(),
retryBehavior: RetryBehavior<RunLoop> = Oneinch.defaultRetryBehavior) {
self.action = action
self.networkProvider = networkProvider
self.networking = networking
self.reachability = reachability
self.retryBehavior = retryBehavior
}
@ -48,8 +52,8 @@ public class Oneinch: SupportedTokenActionsProvider, SwapTokenViaUrlProvider {
reachability.networkBecomeReachablePublisher
.receive(on: queue)
.setFailureType(to: PromiseError.self)
.flatMapLatest { [networkProvider, retryBehavior] _ -> AnyPublisher<[Asset], PromiseError> in
networkProvider.retrieveAssets()
.flatMapLatest { [networking, retryBehavior] _ -> AnyPublisher<[Asset], PromiseError> in
networking.retrieveAssets()
.retry(retryBehavior, scheduler: RunLoop.main)
.eraseToAnyPublisher()
}.receive(on: queue)
@ -57,14 +61,14 @@ public class Oneinch: SupportedTokenActionsProvider, SwapTokenViaUrlProvider {
objectWillChangeSubject.send(())
guard case .failure(let error) = result else { return }
let request = RampNetworkProvider.RampRequest()
let request = BaseOneinchNetworking.OneInchAssetsRequest()
RemoteLogger.instance.logRpcOrOtherWebError("Oneinch error | \(error)", url: request.urlRequest?.url?.absoluteString ?? "")
} receiveValue: { assets in
var newAssets: [AlphaWallet.Address: Oneinch.Asset] = [:]
for asset in self.predefinedAssets + assets {
newAssets[asset.address] = asset
}
self.assets = .success(newAssets)
self.assets = .done(newAssets)
}.store(in: &cancelable)
}
@ -95,12 +99,8 @@ public class Oneinch: SupportedTokenActionsProvider, SwapTokenViaUrlProvider {
}
private func asset(for address: AlphaWallet.Address) -> Oneinch.Asset? {
switch assets {
case .success(let assets):
return assets[address]
case .failure:
return nil
}
guard let assets = assets.value else { return nil }
return assets[address]
}
private func subpath(inputAddress: AlphaWallet.Address) -> String {

@ -1,5 +1,5 @@
//
// OneinchNetworkProvider.swift
// BaseOneinchNetworking.swift
// AlphaWalletFoundation
//
// Created by Vladyslav Shepitko on 19.09.2022.
@ -9,11 +9,11 @@ import Foundation
import AlphaWalletCore
import Combine
public protocol OneinchNetworkProviderType {
public protocol OneinchNetworking {
func retrieveAssets() -> AnyPublisher<[Oneinch.Asset], PromiseError>
}
public final class OneinchNetworkProvider: OneinchNetworkProviderType {
public final class BaseOneinchNetworking: OneinchNetworking {
private let decoder = JSONDecoder()
private let networkService: NetworkService
@ -31,8 +31,8 @@ public final class OneinchNetworkProvider: OneinchNetworkProviderType {
}
}
fileprivate extension OneinchNetworkProvider {
private struct OneInchAssetsRequest: URLRequestConvertible {
extension BaseOneinchNetworking {
struct OneInchAssetsRequest: URLRequestConvertible {
func asURLRequest() throws -> URLRequest {
guard var components = URLComponents(url: Constants.OneInch.exchangeUrl, resolvingAgainstBaseURL: false) else { throw URLError(.badURL) }
components.path = "/v3.0/1/tokens"
Loading…
Cancel
Save