mirror of
https://github.com/tornadocash/tornado-pool-relayer
synced 2024-02-02 15:04:09 +01:00
fix: catch service errors
This commit is contained in:
parent
036fe4f8ea
commit
767c87b4d2
@ -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",
|
||||
|
@ -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.',
|
||||
};
|
||||
|
@ -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<Transaction> {
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user