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",
|
"name": "pool-relayer",
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"description": "Relayer for Tornado.cash Nova privacy solution. https://tornado.cash",
|
"description": "Relayer for Tornado.cash Nova privacy solution. https://tornado.cash",
|
||||||
"author": "tornado.cash",
|
"author": "tornado.cash",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
@ -47,3 +47,9 @@ export const CONTRACT_ERRORS = [
|
|||||||
'Invalid transaction proof',
|
'Invalid transaction proof',
|
||||||
"Can't withdraw to zero address",
|
"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 { InjectQueue, Process, Processor, OnQueueActive, OnQueueCompleted, OnQueueFailed } from '@nestjs/bull';
|
||||||
|
|
||||||
import { Transaction } from '@/types';
|
import { Transaction } from '@/types';
|
||||||
import { CONTRACT_ERRORS, jobStatus } from '@/constants';
|
|
||||||
import { getToIntegerMultiplier, toWei } from '@/utilities';
|
import { getToIntegerMultiplier, toWei } from '@/utilities';
|
||||||
|
import { CONTRACT_ERRORS, SERVICE_ERRORS, jobStatus } from '@/constants';
|
||||||
import { GasPriceService, ProviderService, OffchainPriceService } from '@/services';
|
import { GasPriceService, ProviderService, OffchainPriceService } from '@/services';
|
||||||
|
|
||||||
import txMangerConfig from '@/config/txManager.config';
|
import txMangerConfig from '@/config/txManager.config';
|
||||||
@ -131,28 +131,38 @@ export class TransactionProcessor extends BaseProcessor<Transaction> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async checkFee({ fee, externalAmount }) {
|
async checkFee({ fee, externalAmount }) {
|
||||||
const { gasLimit } = this.configService.get('base');
|
try {
|
||||||
const { fast } = await this.gasPriceService.getGasPrice();
|
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 expense = operationFee.mul(ethPrice).div(toWei('1'));
|
||||||
const desiredFee = expense.add(feePercent);
|
const desiredFee = expense.add(feePercent);
|
||||||
|
|
||||||
if (BigNumber.from(fee).lt(desiredFee)) {
|
if (BigNumber.from(fee).lt(desiredFee)) {
|
||||||
throw new Error('Provided fee is not enough. Probably it is a Gas Price spike, try to resubmit.');
|
throw new Error(SERVICE_ERRORS.GAS_SPIKE);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
this.handleError(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleError({ message }: Error) {
|
handleError({ message }: Error) {
|
||||||
const error = CONTRACT_ERRORS.find((knownError) => message.includes(knownError));
|
const contractError = CONTRACT_ERRORS.find((knownError) => message.includes(knownError));
|
||||||
|
|
||||||
if (error) {
|
if (contractError) {
|
||||||
throw new Error(`Revert by smart contract: ${error}`);
|
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);
|
console.log('handleError:', message);
|
||||||
|
@ -5,6 +5,7 @@ import { BigNumber } from 'ethers';
|
|||||||
import { GasPriceOracle } from 'gas-price-oracle';
|
import { GasPriceOracle } from 'gas-price-oracle';
|
||||||
|
|
||||||
import { toWei } from '@/utilities';
|
import { toWei } from '@/utilities';
|
||||||
|
import { SERVICE_ERRORS } from '@/constants';
|
||||||
|
|
||||||
const bump = (gas: BigNumber, percent: number) => gas.mul(percent).div(100).toHexString();
|
const bump = (gas: BigNumber, percent: number) => gas.mul(percent).div(100).toHexString();
|
||||||
const gweiToWei = (value: number) => toWei(String(value), 'gwei');
|
const gweiToWei = (value: number) => toWei(String(value), 'gwei');
|
||||||
@ -27,18 +28,23 @@ export class GasPriceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getGasPrice() {
|
async getGasPrice() {
|
||||||
const instance = new GasPriceOracle({
|
try {
|
||||||
chainId: this.chainId,
|
const instance = new GasPriceOracle({
|
||||||
defaultRpc: this.rpcUrl,
|
chainId: this.chainId,
|
||||||
});
|
defaultRpc: this.rpcUrl,
|
||||||
|
});
|
||||||
|
|
||||||
const result = await instance.gasPrices();
|
const result = await instance.gasPrices();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
instant: bump(gweiToWei(result.instant), percentBump.INSTANT),
|
instant: bump(gweiToWei(result.instant), percentBump.INSTANT),
|
||||||
fast: bump(gweiToWei(result.instant), percentBump.FAST),
|
fast: bump(gweiToWei(result.instant), percentBump.FAST),
|
||||||
standard: bump(gweiToWei(result.standard), percentBump.STANDARD),
|
standard: bump(gweiToWei(result.standard), percentBump.STANDARD),
|
||||||
low: bump(gweiToWei(result.low), percentBump.LOW),
|
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 { BigNumber } from 'ethers';
|
||||||
|
|
||||||
import { ChainId } from '@/types';
|
import { ChainId } from '@/types';
|
||||||
import { DAI_ADDRESS } from '@/constants';
|
|
||||||
import { ProviderService } from '@/services';
|
|
||||||
import { toWei } from '@/utilities';
|
import { toWei } from '@/utilities';
|
||||||
|
import { ProviderService } from '@/services';
|
||||||
|
import { DAI_ADDRESS, SERVICE_ERRORS } from '@/constants';
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class OffchainPriceService {
|
export class OffchainPriceService {
|
||||||
private readonly chainId: number;
|
private readonly chainId: number;
|
||||||
@ -19,14 +18,19 @@ export class OffchainPriceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getDaiEthPrice() {
|
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 numerator = BigNumber.from(toWei('1'));
|
||||||
const denominator = BigNumber.from(toWei('1'));
|
const denominator = BigNumber.from(toWei('1'));
|
||||||
|
|
||||||
// price = rate * "token decimals" / "eth decimals" (dai = eth decimals)
|
// price = rate * "token decimals" / "eth decimals" (dai = eth decimals)
|
||||||
return BigNumber.from(rate).mul(numerator).div(denominator);
|
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