From 767c87b4d25e49e8aa8b7516823564eb00fd82b2 Mon Sep 17 00:00:00 2001 From: Danil Kovtonyuk Date: Wed, 15 Dec 2021 20:24:09 +1000 Subject: [PATCH] fix: catch service errors --- package.json | 2 +- src/constants/variables.ts | 6 ++++ src/modules/queue/transaction.processor.ts | 36 ++++++++++++++-------- src/services/gas-price.service.ts | 28 ++++++++++------- src/services/offchain-price.service.ts | 22 +++++++------ 5 files changed, 60 insertions(+), 34 deletions(-) diff --git a/package.json b/package.json index 45b3a03..60c3584 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pool-relayer", - "version": "0.0.1", + "version": "0.0.2", "description": "Relayer for Tornado.cash Nova privacy solution. https://tornado.cash", "author": "tornado.cash", "license": "MIT", diff --git a/src/constants/variables.ts b/src/constants/variables.ts index b9d263b..3e4b562 100644 --- a/src/constants/variables.ts +++ b/src/constants/variables.ts @@ -47,3 +47,9 @@ export const CONTRACT_ERRORS = [ 'Invalid transaction proof', "Can't withdraw to zero address", ]; + +export const SERVICE_ERRORS = { + GAS_PRICE: 'Could not get gas price', + TOKEN_RATES: 'Could not get token rates', + GAS_SPIKE: 'Provided fee is not enough. Probably it is a Gas Price spike, try to resubmit.', +}; diff --git a/src/modules/queue/transaction.processor.ts b/src/modules/queue/transaction.processor.ts index f4375ba..b18f4ef 100644 --- a/src/modules/queue/transaction.processor.ts +++ b/src/modules/queue/transaction.processor.ts @@ -7,8 +7,8 @@ import { ConfigService } from '@nestjs/config'; import { InjectQueue, Process, Processor, OnQueueActive, OnQueueCompleted, OnQueueFailed } from '@nestjs/bull'; import { Transaction } from '@/types'; -import { CONTRACT_ERRORS, jobStatus } from '@/constants'; import { getToIntegerMultiplier, toWei } from '@/utilities'; +import { CONTRACT_ERRORS, SERVICE_ERRORS, jobStatus } from '@/constants'; import { GasPriceService, ProviderService, OffchainPriceService } from '@/services'; import txMangerConfig from '@/config/txManager.config'; @@ -131,28 +131,38 @@ export class TransactionProcessor extends BaseProcessor { } async checkFee({ fee, externalAmount }) { - const { gasLimit } = this.configService.get('base'); - const { fast } = await this.gasPriceService.getGasPrice(); + try { + const { gasLimit } = this.configService.get('base'); + const { fast } = await this.gasPriceService.getGasPrice(); - const operationFee = BigNumber.from(fast).mul(gasLimit); + const operationFee = BigNumber.from(fast).mul(gasLimit); - const feePercent = this.getServiceFee(externalAmount); + const feePercent = this.getServiceFee(externalAmount); - const ethPrice = await this.offChainPriceService.getDaiEthPrice(); + const ethPrice = await this.offChainPriceService.getDaiEthPrice(); - const expense = operationFee.mul(ethPrice).div(toWei('1')); - const desiredFee = expense.add(feePercent); + const expense = operationFee.mul(ethPrice).div(toWei('1')); + const desiredFee = expense.add(feePercent); - if (BigNumber.from(fee).lt(desiredFee)) { - throw new Error('Provided fee is not enough. Probably it is a Gas Price spike, try to resubmit.'); + if (BigNumber.from(fee).lt(desiredFee)) { + throw new Error(SERVICE_ERRORS.GAS_SPIKE); + } + } catch (err) { + this.handleError(err); } } handleError({ message }: Error) { - const error = CONTRACT_ERRORS.find((knownError) => message.includes(knownError)); + const contractError = CONTRACT_ERRORS.find((knownError) => message.includes(knownError)); - if (error) { - throw new Error(`Revert by smart contract: ${error}`); + if (contractError) { + throw new Error(`Revert by smart contract: ${contractError}`); + } + + const serviceError = Object.values(SERVICE_ERRORS).find((knownError) => message.includes(knownError)); + + if (serviceError) { + throw new Error(`Relayer internal error: ${serviceError}`); } console.log('handleError:', message); diff --git a/src/services/gas-price.service.ts b/src/services/gas-price.service.ts index a7aa397..1400bfa 100644 --- a/src/services/gas-price.service.ts +++ b/src/services/gas-price.service.ts @@ -5,6 +5,7 @@ import { BigNumber } from 'ethers'; import { GasPriceOracle } from 'gas-price-oracle'; import { toWei } from '@/utilities'; +import { SERVICE_ERRORS } from '@/constants'; const bump = (gas: BigNumber, percent: number) => gas.mul(percent).div(100).toHexString(); const gweiToWei = (value: number) => toWei(String(value), 'gwei'); @@ -27,18 +28,23 @@ export class GasPriceService { } async getGasPrice() { - const instance = new GasPriceOracle({ - chainId: this.chainId, - defaultRpc: this.rpcUrl, - }); + try { + const instance = new GasPriceOracle({ + chainId: this.chainId, + defaultRpc: this.rpcUrl, + }); - const result = await instance.gasPrices(); + const result = await instance.gasPrices(); - return { - instant: bump(gweiToWei(result.instant), percentBump.INSTANT), - fast: bump(gweiToWei(result.instant), percentBump.FAST), - standard: bump(gweiToWei(result.standard), percentBump.STANDARD), - low: bump(gweiToWei(result.low), percentBump.LOW), - }; + return { + instant: bump(gweiToWei(result.instant), percentBump.INSTANT), + fast: bump(gweiToWei(result.instant), percentBump.FAST), + standard: bump(gweiToWei(result.standard), percentBump.STANDARD), + low: bump(gweiToWei(result.low), percentBump.LOW), + }; + } catch (err) { + console.log('getGasPrice has error:', err.message); + throw new Error(SERVICE_ERRORS.GAS_PRICE); + } } } diff --git a/src/services/offchain-price.service.ts b/src/services/offchain-price.service.ts index 44554bc..3734da3 100644 --- a/src/services/offchain-price.service.ts +++ b/src/services/offchain-price.service.ts @@ -4,10 +4,9 @@ import { ConfigService } from '@nestjs/config'; import { BigNumber } from 'ethers'; import { ChainId } from '@/types'; -import { DAI_ADDRESS } from '@/constants'; -import { ProviderService } from '@/services'; import { toWei } from '@/utilities'; - +import { ProviderService } from '@/services'; +import { DAI_ADDRESS, SERVICE_ERRORS } from '@/constants'; @Injectable() export class OffchainPriceService { private readonly chainId: number; @@ -19,14 +18,19 @@ export class OffchainPriceService { } async getDaiEthPrice() { - const contract = this.providerService.getOffChainOracle(); + try { + const contract = this.providerService.getOffChainOracle(); - const rate = await contract.callStatic.getRateToEth(DAI_ADDRESS, false); + const rate = await contract.callStatic.getRateToEth(DAI_ADDRESS, false); - const numerator = BigNumber.from(toWei('1')); - const denominator = BigNumber.from(toWei('1')); + const numerator = BigNumber.from(toWei('1')); + const denominator = BigNumber.from(toWei('1')); - // price = rate * "token decimals" / "eth decimals" (dai = eth decimals) - return BigNumber.from(rate).mul(numerator).div(denominator); + // price = rate * "token decimals" / "eth decimals" (dai = eth decimals) + return BigNumber.from(rate).mul(numerator).div(denominator); + } catch (err) { + console.log('getDaiEthPrice has error:', err.message); + throw new Error(SERVICE_ERRORS.TOKEN_RATES); + } } }