Skip to content

Commit

Permalink
MOB-1993 - Handle nonce fetch error (#536)
Browse files Browse the repository at this point in the history
* Handling of a new error

.failedFetchNonce

* handling fetch nonce error -- double attempt

* refactoring

* extracting doubleAttempt() method

* fixed error

* merged error types
  • Loading branch information
rommex authored May 6, 2024
1 parent 0ab8ef5 commit 5f1d911
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 51 deletions.
17 changes: 12 additions & 5 deletions unstoppable-ios-app/domains-manager-ios/Extensions/Error.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,18 @@ extension Error {
case .notConnectedToInternet = networkError {
title = String.Constants.connectionLost.localized()
message = String.Constants.pleaseCheckInternetConnection.localized()
} else if let jrpcError = self as? NetworkService.JRPCError,
case .failedFetchInfuraGasPrices = jrpcError {
title = String.Constants.gasFeeFailed.localized()
message = String.Constants.pleaseTryAgain.localized()
} else{
} else if let jrpcError = self as? NetworkService.JRPCError {
switch jrpcError {
case .failedFetchInfuraGasPrices:
title = String.Constants.gasFeeFailed.localized()
message = String.Constants.pleaseTryAgain.localized()
case .failedFetchNonce:
title = String.Constants.nonceFailed.localized()
message = String.Constants.pleaseTryAgain.localized()
default: title = String.Constants.somethingWentWrong.localized()
message = String.Constants.pleaseTryAgain.localized()
}
} else {
title = String.Constants.somethingWentWrong.localized()
message = String.Constants.pleaseTryAgain.localized()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ extension String {
static let transactionFailed = "TRANSACTION_FAILED"
static let connectionLost = "CONNECTION_LOST"
static let gasFeeFailed = "GAS_FEE_FETCH_FAILED"
static let nonceFailed = "NONCE_FETCH_FAILED"
static let pleaseCheckInternetConnection = "PLEASE_CHECK_INTERNET_CONNECTION"
static let failedToPickImageFromPhotoLibraryErrorMessage = "FAILED_TO_PICK_IMAGE_FROM_PHOTO_LIBRARY_ERROR_MESSAGE"
static let unableToCreateAccount = "UNABLE_TO_CREATE_ACCOUNT"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,9 @@ extension EVMCryptoSender {

private func fetchGasPrices(chainId: Int) async throws -> EstimatedGasPrices {
// here routes to Status or Infura source

let prices: EstimatedGasPrices
do {
prices = try await NetworkService().fetchInfuraGasPrices(chainId: chainId)
} catch {
try await Task.sleep(nanoseconds: 500_000_000)
return try await NetworkService().fetchInfuraGasPrices(chainId: chainId)
try await NetworkService().doubleAttempt {
try await NetworkService().fetchInfuraGasPrices(chainId: chainId)
}
return prices
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,40 +12,27 @@ struct JRPC_Client {
static let instance = JRPC_Client()
private init() { }

enum Error: Swift.Error {
case failedFetchGas
case lowAllowance
case failedFetchGasLimit
}

func fetchNonce(address: HexAddress, chainId: Int) async throws -> EthereumQuantity {
guard let nonce = await fetchNonce(address: address, chainId: chainId),
let nonceBig = BigUInt(nonce.droppedHexPrefix, radix: 16) else {
throw WalletConnectRequestError.failedFetchNonce
let nonceString = try await NetworkService().doubleAttempt {
try await NetworkService().getTransactionCount(address: address,
chainId: chainId)
}
return EthereumQuantity(quantity: nonceBig)
}

func fetchNonce(address: HexAddress, chainId: Int) async -> String? {
guard let nonceString = try? await NetworkService().getTransactionCount(address: address,
chainId: chainId) else {
Debugger.printFailure("Failed to fetch nonce for address: \(address)", critical: true)
return nil
guard let nonceBig = BigUInt(nonceString.droppedHexPrefix, radix: 16) else {
throw NetworkService.JRPCError.failedFetchNonce
}
Debugger.printInfo(topic: .WalletConnect, "Fetched nonce successfully: \(nonceString)")
return nonceString
return EthereumQuantity(quantity: nonceBig)
}

func fetchGasPrice(chainId: Int) async throws -> EthereumQuantity {
guard let gasPrice = try? await NetworkService().getGasPrice(chainId: chainId) else {
Debugger.printFailure("Failed to fetch gasPrice", critical: false)
throw Self.Error.failedFetchGas
throw NetworkService.JRPCError.failedFetchGas
}
Debugger.printInfo(topic: .WalletConnect, "Fetched gasPrice successfully: \(gasPrice)")
let gasPriceBigUInt = BigUInt(gasPrice.droppedHexPrefix, radix: 16)

guard let gasPriceBigUInt else {
throw Self.Error.failedFetchGas
throw NetworkService.JRPCError.failedFetchGas
}
return EthereumQuantity(quantity: gasPriceBigUInt)
}
Expand All @@ -56,7 +43,7 @@ struct JRPC_Client {
chainId: chainId)
guard let result = BigUInt(gasPriceString.droppedHexPrefix, radix: 16) else {
Debugger.printFailure("Failed to parse gas Estimate from: \(gasPriceString)", critical: true)
throw Self.Error.failedFetchGasLimit
throw NetworkService.JRPCError.failedFetchGasLimit
}
Debugger.printInfo(topic: .WalletConnect, "Fetched gas Estimate successfully: \(gasPriceString)")
return EthereumQuantity(quantity: result)
Expand All @@ -65,10 +52,10 @@ struct JRPC_Client {
switch jrpcError {
case .genericError(let message):
Debugger.printFailure("Failed to fetch gas Estimate, message: \(message)", critical: false)
throw JRPC_Client.Error.failedFetchGas
throw NetworkService.JRPCError.failedFetchGas
case .gasRequiredExceedsAllowance:
Debugger.printFailure("Failed to fetch gas Estimate because of Low Allowance Error", critical: false)
throw JRPC_Client.Error.lowAllowance
throw NetworkService.JRPCError.lowAllowance
default: throw WalletConnectRequestError.failedFetchGas
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,8 +320,12 @@ extension NetworkService {
case failedGetStatus
case failedParseStatusPrices
case failedFetchInfuraGasPrices
case failedFetchNonce
case failedParseInfuraPrices
case failedEncodeTxParameters
case failedFetchGas
case lowAllowance
case failedFetchGasLimit
case unknownChain

init(message: String) {
Expand All @@ -333,6 +337,17 @@ extension NetworkService {
}
}

func doubleAttempt<T>(fetchingAction: (() async throws -> T) ) async throws -> T {
let fetched: T
do {
fetched = try await fetchingAction()
} catch {
try await Task.sleep(nanoseconds: 500_000_000)
fetched = try await fetchingAction()
}
return fetched
}

func getJRPCRequest(chainId: Int,
requestInfo: JRPCRequestInfo) async throws -> String {

Expand All @@ -356,10 +371,15 @@ extension NetworkService {

func getTransactionCount(address: HexAddress,
chainId: Int) async throws -> String {

try await getJRPCRequest(chainId: chainId,
requestInfo: JRPCRequestInfo(name: "eth_getTransactionCount",
paramsBuilder: { "[\"\(address)\", \"latest\"]"} ))
let countString: String
do {
countString = try await getJRPCRequest(chainId: chainId,
requestInfo: JRPCRequestInfo(name: "eth_getTransactionCount",
paramsBuilder: { "[\"\(address)\", \"latest\"]"} ))
} catch {
throw JRPCError.failedFetchNonce
}
return countString
}

func getGasEstimation(tx: EthereumTransaction,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -856,19 +856,14 @@ extension WalletConnectServiceV2: WalletConnectV2RequestHandlingServiceProtocol
guard transaction.nonce == nil else {
return transaction
}

guard let nonce = await fetchNonce(transaction: transaction, chainId: chainId),
let nonceBig = BigUInt(nonce.droppedHexPrefix, radix: 16) else {
throw WalletConnectRequestError.failedFetchNonce
}
var newTx = transaction
newTx.nonce = EthereumQuantity(quantity: nonceBig)
newTx.nonce = try await fetchNonce(transaction: transaction, chainId: chainId)
return newTx
}

private func fetchNonce(transaction: EthereumTransaction, chainId: Int) async -> String? {
guard let addressString = transaction.from?.hex() else { return nil }
return await JRPC_Client.instance.fetchNonce(address: addressString, chainId: chainId)
private func fetchNonce(transaction: EthereumTransaction, chainId: Int) async throws -> EthereumQuantity {
guard let addressString = transaction.from?.hex() else { throw WalletConnectRequestError.failedFetchNonce }
return try await JRPC_Client.instance.fetchNonce(address: addressString, chainId: chainId)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"TRANSACTION_FAILED" = "Transaction Failed";
"CONNECTION_LOST" = "Connection lost";
"GAS_FEE_FETCH_FAILED" = "Failed to obtain current gas fees";
"NONCE_FETCH_FAILED" = "Failed to obtain current nonce for the wallet address";
"PLEASE_CHECK_INTERNET_CONNECTION" = "Please check your connection and try again.";
"FAILED_TO_PICK_IMAGE_FROM_PHOTO_LIBRARY_ERROR_MESSAGE" = "Unexpected error occurred when tried to use selected image";
"UNABLE_TO_CREATE_ACCOUNT" = "Unable to create account";
Expand Down

0 comments on commit 5f1d911

Please sign in to comment.