Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MOB-1993 - Handle nonce fetch error #536

Merged
merged 6 commits into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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