mirror of
https://github.com/tornadocash/tornado-pool-relayer
synced 2024-02-02 15:04:09 +01:00
fix: update relayer
-add unique job id -handle contract errors -fix queue management
This commit is contained in:
parent
bb9d6de05f
commit
bd8f40881c
@ -33,3 +33,14 @@ const FIELD_SIZE = BigNumber.from('218882428718392752222464057452572750885483644
|
||||
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
||||
|
||||
export { numbers, NETWORKS_INFO, FIELD_SIZE, BG_ZERO, ZERO_ADDRESS };
|
||||
|
||||
export const CONTRACT_ERRORS = [
|
||||
'Invalid merkle root',
|
||||
'Input is already spent',
|
||||
'Incorrect external data hash',
|
||||
'Invalid fee',
|
||||
'Invalid ext amount',
|
||||
'Invalid public amount',
|
||||
'Invalid transaction proof',
|
||||
"Can't withdraw to zero address",
|
||||
];
|
||||
|
@ -1,10 +1,12 @@
|
||||
import { Queue, Job } from 'bull';
|
||||
import { Queue } from 'bull';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { InjectQueue } from '@nestjs/bull';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { ProviderService } from '@/services';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
import { Transaction } from '@/types';
|
||||
@Injectable()
|
||||
class ApiService {
|
||||
constructor(
|
||||
@ -32,13 +34,24 @@ class ApiService {
|
||||
}
|
||||
|
||||
async transaction(data: any): Promise<string> {
|
||||
const job = await this.transactionQueue.add(data);
|
||||
const jobId = uuid();
|
||||
|
||||
return String(job.id);
|
||||
await this.transactionQueue.add({ ...data, status: 'QUEUED' }, { jobId });
|
||||
|
||||
return jobId;
|
||||
}
|
||||
|
||||
async getJob(id: string): Promise<Job | null> {
|
||||
return await this.transactionQueue.getJob(id);
|
||||
async getJob(id: string): Promise<Transaction | null> {
|
||||
const job = await this.transactionQueue.getJob(id);
|
||||
|
||||
if (!job) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
...job.data,
|
||||
failedReason: job.failedReason,
|
||||
};
|
||||
}
|
||||
|
||||
private async healthCheck(): Promise<Health> {
|
||||
|
@ -1,48 +1,18 @@
|
||||
import { Job, Queue } from 'bull';
|
||||
import { BigNumber, BigNumberish } from 'ethers';
|
||||
import { BytesLike } from '@ethersproject/bytes';
|
||||
import { BigNumber } from 'ethers';
|
||||
import { TxManager } from 'tx-manager';
|
||||
import { Job, Queue, DoneCallback } from 'bull';
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { InjectQueue, Process, Processor } from '@nestjs/bull';
|
||||
import { InjectQueue, Process, Processor, OnQueueActive, OnQueueCompleted, OnQueueFailed } from '@nestjs/bull';
|
||||
|
||||
import { numbers } from '@/constants';
|
||||
import { numbers, CONTRACT_ERRORS } from '@/constants';
|
||||
import { toWei, getToIntegerMultiplier } from '@/utilities';
|
||||
import { GasPriceService, ProviderService } from '@/services';
|
||||
import txMangerConfig from '@/config/txManager.config';
|
||||
|
||||
import { BaseProcessor } from './base.processor';
|
||||
import { ChainId } from '@/types';
|
||||
|
||||
export type ExtData = {
|
||||
recipient: string;
|
||||
relayer: string;
|
||||
fee: BigNumberish;
|
||||
extAmount: BigNumberish;
|
||||
encryptedOutput1: BytesLike;
|
||||
encryptedOutput2: BytesLike;
|
||||
};
|
||||
|
||||
export type ArgsProof = {
|
||||
proof: BytesLike;
|
||||
root: BytesLike;
|
||||
newRoot: BytesLike;
|
||||
inputNullifiers: string[];
|
||||
outputCommitments: BytesLike[];
|
||||
outPathIndices: string;
|
||||
publicAmount: string;
|
||||
extDataHash: string;
|
||||
};
|
||||
|
||||
export interface Transaction {
|
||||
extData: ExtData;
|
||||
args: ArgsProof;
|
||||
txHash: string;
|
||||
status: string;
|
||||
confirmations: number;
|
||||
}
|
||||
|
||||
import { ChainId, Transaction } from '@/types';
|
||||
@Injectable()
|
||||
@Processor('transaction')
|
||||
export class TransactionProcessor extends BaseProcessor<Transaction> {
|
||||
@ -58,19 +28,40 @@ export class TransactionProcessor extends BaseProcessor<Transaction> {
|
||||
}
|
||||
|
||||
@Process()
|
||||
async processTransactions(job: Job<Transaction>) {
|
||||
async processTransactions(job: Job<Transaction>, cb: DoneCallback) {
|
||||
try {
|
||||
await job.isActive();
|
||||
|
||||
const { extData } = job.data;
|
||||
|
||||
await this.checkFee({ fee: extData.fee, externalAmount: extData.extAmount });
|
||||
await this.submitTx(job);
|
||||
|
||||
cb(null);
|
||||
} catch (err) {
|
||||
await job.moveToFailed(err, true);
|
||||
cb(err);
|
||||
}
|
||||
}
|
||||
|
||||
@OnQueueActive()
|
||||
async onActive(job: Job) {
|
||||
job.data.status = 'ACCEPTED';
|
||||
|
||||
await job.update(job.data);
|
||||
}
|
||||
|
||||
@OnQueueCompleted()
|
||||
async onCompleted(job: Job) {
|
||||
job.data.status = 'CONFIRMED';
|
||||
|
||||
await job.update(job.data);
|
||||
}
|
||||
|
||||
@OnQueueFailed()
|
||||
async onFailed(job: Job) {
|
||||
job.data.status = 'FAILED';
|
||||
|
||||
await job.update(job.data);
|
||||
}
|
||||
|
||||
async submitTx(job: Job<Transaction>) {
|
||||
try {
|
||||
const txManager = new TxManager(txMangerConfig());
|
||||
@ -97,17 +88,11 @@ export class TransactionProcessor extends BaseProcessor<Transaction> {
|
||||
await job.update(job.data);
|
||||
});
|
||||
|
||||
if (receipt.status === 1) {
|
||||
await job.isCompleted();
|
||||
|
||||
job.data.status = 'SENT';
|
||||
|
||||
await job.update(job.data);
|
||||
} else {
|
||||
if (receipt.status !== 1) {
|
||||
throw new Error('Submitted transaction failed');
|
||||
}
|
||||
} catch (e) {
|
||||
throw new Error(`Revert by smart contract ${e.message}`);
|
||||
} catch (err) {
|
||||
return this.handleError(err);
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,4 +155,21 @@ export class TransactionProcessor extends BaseProcessor<Transaction> {
|
||||
throw new Error('Provided fee is not enough. Probably it is a Gas Price spike, try to resubmit.');
|
||||
}
|
||||
}
|
||||
|
||||
handleError(e) {
|
||||
// Sometimes ethers wraps known errors, unwrap it in this case
|
||||
if (e?.error?.error) {
|
||||
e = e.error;
|
||||
}
|
||||
|
||||
const message = e?.error ? e.error.message : e.message;
|
||||
|
||||
const error = CONTRACT_ERRORS.find((e) => (typeof e === 'string' ? e === message : message.match(e)));
|
||||
|
||||
if (error) {
|
||||
throw new Error(`Revert by smart contract: ${error}`);
|
||||
}
|
||||
|
||||
throw new Error('Relayer did not send your transaction. Please choose a different relayer.');
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,39 @@
|
||||
const MAINNET_CHAIN_ID = 1
|
||||
const GOERLI_CHAIN_ID = 5
|
||||
const OPTIMISM_CHAIN_ID = 69
|
||||
import { BigNumberish } from 'ethers';
|
||||
import { BytesLike } from '@ethersproject/bytes';
|
||||
|
||||
const MAINNET_CHAIN_ID = 1;
|
||||
const GOERLI_CHAIN_ID = 5;
|
||||
const OPTIMISM_CHAIN_ID = 69;
|
||||
|
||||
export enum ChainId {
|
||||
MAINNET = MAINNET_CHAIN_ID,
|
||||
GOERLI = GOERLI_CHAIN_ID,
|
||||
OPTIMISM = OPTIMISM_CHAIN_ID,
|
||||
}
|
||||
|
||||
export type ExtData = {
|
||||
recipient: string;
|
||||
relayer: string;
|
||||
fee: BigNumberish;
|
||||
extAmount: BigNumberish;
|
||||
encryptedOutput1: BytesLike;
|
||||
encryptedOutput2: BytesLike;
|
||||
};
|
||||
|
||||
export type ArgsProof = {
|
||||
proof: BytesLike;
|
||||
root: BytesLike;
|
||||
inputNullifiers: string[];
|
||||
outputCommitments: BytesLike[];
|
||||
publicAmount: string;
|
||||
extDataHash: string;
|
||||
};
|
||||
|
||||
export interface Transaction {
|
||||
extData: ExtData;
|
||||
args: ArgsProof;
|
||||
status: string;
|
||||
txHash?: string;
|
||||
confirmations?: number;
|
||||
failedReason?: string;
|
||||
}
|
||||
|
@ -5871,11 +5871,16 @@ utils-merge@1.0.1:
|
||||
resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
||||
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
|
||||
|
||||
uuid@8.3.2, uuid@^8.3.0, uuid@^8.3.2:
|
||||
uuid@8.3.2, uuid@^8.3.0:
|
||||
version "8.3.2"
|
||||
resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
|
||||
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
||||
|
||||
uuid@^8.3.2:
|
||||
version "8.3.2"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
|
||||
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
||||
|
||||
v8-compile-cache@^2.0.3:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
|
||||
|
Loading…
Reference in New Issue
Block a user