lint
This commit is contained in:
parent
bd0f8d2a2e
commit
e997d4d07e
@ -1,10 +1,26 @@
|
||||
[
|
||||
{
|
||||
"inputs": [
|
||||
{ "internalType": "contract MultiWrapper", "name": "_multiWrapper", "type": "address" },
|
||||
{ "internalType": "contract IOracle[]", "name": "existingOracles", "type": "address[]" },
|
||||
{ "internalType": "enum OffchainOracle.OracleType[]", "name": "oracleTypes", "type": "uint8[]" },
|
||||
{ "internalType": "contract IERC20[]", "name": "existingConnectors", "type": "address[]" },
|
||||
{
|
||||
"internalType": "contract MultiWrapper",
|
||||
"name": "_multiWrapper",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "contract IOracle[]",
|
||||
"name": "existingOracles",
|
||||
"type": "address[]"
|
||||
},
|
||||
{
|
||||
"internalType": "enum OffchainOracle.OracleType[]",
|
||||
"name": "oracleTypes",
|
||||
"type": "uint8[]"
|
||||
},
|
||||
{
|
||||
"internalType": "contract IERC20[]",
|
||||
"name": "existingConnectors",
|
||||
"type": "address[]"
|
||||
},
|
||||
{ "internalType": "contract IERC20", "name": "wBase", "type": "address" }
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
@ -13,7 +29,12 @@
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{ "indexed": false, "internalType": "contract IERC20", "name": "connector", "type": "address" }
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "contract IERC20",
|
||||
"name": "connector",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "ConnectorAdded",
|
||||
"type": "event"
|
||||
@ -21,7 +42,12 @@
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{ "indexed": false, "internalType": "contract IERC20", "name": "connector", "type": "address" }
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "contract IERC20",
|
||||
"name": "connector",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "ConnectorRemoved",
|
||||
"type": "event"
|
||||
@ -29,7 +55,12 @@
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{ "indexed": false, "internalType": "contract MultiWrapper", "name": "multiWrapper", "type": "address" }
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "contract MultiWrapper",
|
||||
"name": "multiWrapper",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "MultiWrapperUpdated",
|
||||
"type": "event"
|
||||
@ -37,7 +68,12 @@
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{ "indexed": false, "internalType": "contract IOracle", "name": "oracle", "type": "address" },
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "contract IOracle",
|
||||
"name": "oracle",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "enum OffchainOracle.OracleType",
|
||||
@ -51,7 +87,12 @@
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{ "indexed": false, "internalType": "contract IOracle", "name": "oracle", "type": "address" },
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "contract IOracle",
|
||||
"name": "oracle",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "enum OffchainOracle.OracleType",
|
||||
@ -65,14 +106,30 @@
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{ "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" },
|
||||
{ "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" }
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "previousOwner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "newOwner",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "OwnershipTransferred",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"inputs": [{ "internalType": "contract IERC20", "name": "connector", "type": "address" }],
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "contract IERC20",
|
||||
"name": "connector",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "addConnector",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
@ -80,8 +137,16 @@
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{ "internalType": "contract IOracle", "name": "oracle", "type": "address" },
|
||||
{ "internalType": "enum OffchainOracle.OracleType", "name": "oracleKind", "type": "uint8" }
|
||||
{
|
||||
"internalType": "contract IOracle",
|
||||
"name": "oracle",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "enum OffchainOracle.OracleType",
|
||||
"name": "oracleKind",
|
||||
"type": "uint8"
|
||||
}
|
||||
],
|
||||
"name": "addOracle",
|
||||
"outputs": [],
|
||||
@ -91,14 +156,28 @@
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "connectors",
|
||||
"outputs": [{ "internalType": "contract IERC20[]", "name": "allConnectors", "type": "address[]" }],
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "contract IERC20[]",
|
||||
"name": "allConnectors",
|
||||
"type": "address[]"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{ "internalType": "contract IERC20", "name": "srcToken", "type": "address" },
|
||||
{ "internalType": "contract IERC20", "name": "dstToken", "type": "address" },
|
||||
{
|
||||
"internalType": "contract IERC20",
|
||||
"name": "srcToken",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "contract IERC20",
|
||||
"name": "dstToken",
|
||||
"type": "address"
|
||||
},
|
||||
{ "internalType": "bool", "name": "useWrappers", "type": "bool" }
|
||||
],
|
||||
"name": "getRate",
|
||||
@ -108,7 +187,11 @@
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{ "internalType": "contract IERC20", "name": "srcToken", "type": "address" },
|
||||
{
|
||||
"internalType": "contract IERC20",
|
||||
"name": "srcToken",
|
||||
"type": "address"
|
||||
},
|
||||
{ "internalType": "bool", "name": "useSrcWrappers", "type": "bool" }
|
||||
],
|
||||
"name": "getRateToEth",
|
||||
@ -127,8 +210,16 @@
|
||||
"inputs": [],
|
||||
"name": "oracles",
|
||||
"outputs": [
|
||||
{ "internalType": "contract IOracle[]", "name": "allOracles", "type": "address[]" },
|
||||
{ "internalType": "enum OffchainOracle.OracleType[]", "name": "oracleTypes", "type": "uint8[]" }
|
||||
{
|
||||
"internalType": "contract IOracle[]",
|
||||
"name": "allOracles",
|
||||
"type": "address[]"
|
||||
},
|
||||
{
|
||||
"internalType": "enum OffchainOracle.OracleType[]",
|
||||
"name": "oracleTypes",
|
||||
"type": "uint8[]"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
@ -141,7 +232,13 @@
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [{ "internalType": "contract IERC20", "name": "connector", "type": "address" }],
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "contract IERC20",
|
||||
"name": "connector",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "removeConnector",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
@ -149,8 +246,16 @@
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{ "internalType": "contract IOracle", "name": "oracle", "type": "address" },
|
||||
{ "internalType": "enum OffchainOracle.OracleType", "name": "oracleKind", "type": "uint8" }
|
||||
{
|
||||
"internalType": "contract IOracle",
|
||||
"name": "oracle",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "enum OffchainOracle.OracleType",
|
||||
"name": "oracleKind",
|
||||
"type": "uint8"
|
||||
}
|
||||
],
|
||||
"name": "removeOracle",
|
||||
"outputs": [],
|
||||
@ -165,7 +270,13 @@
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [{ "internalType": "contract MultiWrapper", "name": "_multiWrapper", "type": "address" }],
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "contract MultiWrapper",
|
||||
"name": "_multiWrapper",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "setMultiWrapper",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
|
@ -9,7 +9,7 @@ services:
|
||||
environment:
|
||||
REDIS_URL: redis://redis/0
|
||||
nginx_proxy_read_timeout: 600
|
||||
depends_on: [ redis ]
|
||||
depends_on: [redis]
|
||||
|
||||
worker1:
|
||||
image: tornadocash/relayer
|
||||
@ -18,7 +18,7 @@ services:
|
||||
env_file: .env
|
||||
environment:
|
||||
REDIS_URL: redis://redis/0
|
||||
depends_on: [ redis ]
|
||||
depends_on: [redis]
|
||||
|
||||
# worker2:
|
||||
# image: tornadocash/relayer:mining
|
||||
@ -65,12 +65,10 @@ services:
|
||||
# TELEGRAM_NOTIFIER_BOT_TOKEN: ...
|
||||
# TELEGRAM_NOTIFIER_CHAT_ID: ...
|
||||
|
||||
|
||||
|
||||
redis:
|
||||
image: redis
|
||||
restart: always
|
||||
command: [ redis-server, '/usr/local/etc/redis/redis.conf', --appendonly, 'yes', ]
|
||||
command: [redis-server, '/usr/local/etc/redis/redis.conf', --appendonly, 'yes']
|
||||
ports:
|
||||
- '6379:6379'
|
||||
volumes:
|
||||
|
@ -13,4 +13,3 @@ export const healthProcessor: Processor = async () => {
|
||||
await healthService.setStatus({ status: false, error: e.message });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Processor, Queue, QueueScheduler, Worker } from 'bullmq';
|
||||
import { TransactionReceipt } from '@ethersproject/abstract-provider';
|
||||
import { JobStatus, RelayerJobType, Token } from '../types';
|
||||
import { WithdrawalData } from '../services/tx.service';
|
||||
import { priceProcessor } from './price.processor';
|
||||
@ -8,19 +9,23 @@ import { ConfigService } from '../services/config.service';
|
||||
import { relayerProcessor } from './relayer.processor';
|
||||
import { healthProcessor } from './health.processor';
|
||||
|
||||
type PriceJobData = Token[]
|
||||
type PriceJobReturn = number
|
||||
type PriceJobData = Token[];
|
||||
type PriceJobReturn = number;
|
||||
|
||||
type HealthJobReturn = void
|
||||
type HealthJobData = null
|
||||
type HealthJobReturn = void;
|
||||
type HealthJobData = null;
|
||||
|
||||
export type RelayerJobData =
|
||||
WithdrawalData
|
||||
& { id: string, status: JobStatus, type: RelayerJobType, txHash?: string, confirmations?: number }
|
||||
export type RelayerJobReturn = any
|
||||
export type RelayerJobData = WithdrawalData & {
|
||||
id: string;
|
||||
status: JobStatus;
|
||||
type: RelayerJobType;
|
||||
txHash?: string;
|
||||
confirmations?: number;
|
||||
};
|
||||
export type RelayerJobReturn = TransactionReceipt;
|
||||
|
||||
export type RelayerProcessor = Processor<RelayerJobData, RelayerJobReturn, RelayerJobType>
|
||||
export type PriceProcessor = Processor<PriceJobData, PriceJobReturn, 'updatePrice'>
|
||||
export type RelayerProcessor = Processor<RelayerJobData, RelayerJobReturn, RelayerJobType>;
|
||||
export type PriceProcessor = Processor<PriceJobData, PriceJobReturn, 'updatePrice'>;
|
||||
|
||||
@autoInjectable()
|
||||
export class PriceQueueHelper {
|
||||
@ -28,8 +33,7 @@ export class PriceQueueHelper {
|
||||
_worker: Worker<PriceJobData, PriceJobReturn, 'updatePrice'>;
|
||||
_scheduler: QueueScheduler;
|
||||
|
||||
constructor(private store?: RedisStore) {
|
||||
}
|
||||
constructor(private store?: RedisStore) {}
|
||||
|
||||
get queue() {
|
||||
if (!this._queue) {
|
||||
@ -56,7 +60,9 @@ export class PriceQueueHelper {
|
||||
|
||||
get scheduler() {
|
||||
if (!this._scheduler) {
|
||||
this._scheduler = new QueueScheduler('price', { connection: this.store.client });
|
||||
this._scheduler = new QueueScheduler('price', {
|
||||
connection: this.store.client,
|
||||
});
|
||||
}
|
||||
return this._scheduler;
|
||||
}
|
||||
@ -71,15 +77,13 @@ export class PriceQueueHelper {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@autoInjectable()
|
||||
export class RelayerQueueHelper {
|
||||
private _queue: Queue<RelayerJobData, RelayerJobReturn, RelayerJobType>;
|
||||
private _worker: Worker<RelayerJobData, RelayerJobReturn, RelayerJobType>;
|
||||
private _scheduler: QueueScheduler;
|
||||
|
||||
constructor(private store?: RedisStore, private config?: ConfigService) {
|
||||
}
|
||||
constructor(private store?: RedisStore, private config?: ConfigService) {}
|
||||
|
||||
get queue() {
|
||||
if (!this._queue) {
|
||||
@ -103,27 +107,27 @@ export class RelayerQueueHelper {
|
||||
|
||||
get scheduler() {
|
||||
if (!this._scheduler) {
|
||||
this._scheduler = new QueueScheduler(this.config.queueName, { connection: this.store.client });
|
||||
this._scheduler = new QueueScheduler(this.config.queueName, {
|
||||
connection: this.store.client,
|
||||
});
|
||||
}
|
||||
return this._scheduler;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@autoInjectable()
|
||||
export class HealthQueueHelper {
|
||||
|
||||
private _queue: Queue<HealthJobData, HealthJobReturn, 'checkHealth'>;
|
||||
private _worker: Worker<HealthJobData, HealthJobReturn, 'checkHealth'>;
|
||||
private _scheduler: QueueScheduler;
|
||||
|
||||
constructor(private store?: RedisStore, private config?: ConfigService) {
|
||||
}
|
||||
constructor(private store?: RedisStore, private config?: ConfigService) {}
|
||||
|
||||
get scheduler(): QueueScheduler {
|
||||
if (!this._scheduler) {
|
||||
this._scheduler = new QueueScheduler('health', { connection: this.store.client });
|
||||
this._scheduler = new QueueScheduler('health', {
|
||||
connection: this.store.client,
|
||||
});
|
||||
}
|
||||
return this._scheduler;
|
||||
}
|
||||
@ -156,6 +160,4 @@ export class HealthQueueHelper {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -7,4 +7,3 @@ export const priceProcessor: PriceProcessor = async (job) => {
|
||||
if (result) return await priceService.savePrices(result);
|
||||
return null;
|
||||
};
|
||||
|
||||
|
@ -15,19 +15,23 @@ class RelayerError extends Error {
|
||||
|
||||
@autoInjectable()
|
||||
export class HealthService {
|
||||
|
||||
constructor(private config: ConfigService, private store: RedisStore) {
|
||||
}
|
||||
constructor(private config: ConfigService, private store: RedisStore) {}
|
||||
|
||||
async clearErrorCodes() {
|
||||
await this.store.client.del('errors:code');
|
||||
}
|
||||
|
||||
private async _getErrors(): Promise<{ errorsLog: { message: string, score: number }[], errorsCode: Record<string, number> }> {
|
||||
private async _getErrors(): Promise<{
|
||||
errorsLog: { message: string; score: number }[];
|
||||
errorsCode: Record<string, number>;
|
||||
}> {
|
||||
const logSet = await this.store.client.zrevrange('errors:log', 0, -1, 'WITHSCORES');
|
||||
const codeSet = await this.store.client.zrevrange('errors:code', 0, -1, 'WITHSCORES');
|
||||
|
||||
return { errorsLog: HealthService._parseSet(logSet), errorsCode: HealthService._parseSet(codeSet, 'object') };
|
||||
return {
|
||||
errorsLog: HealthService._parseSet(logSet),
|
||||
errorsCode: HealthService._parseSet(codeSet, 'object'),
|
||||
};
|
||||
}
|
||||
|
||||
private async _getStatus() {
|
||||
@ -53,7 +57,7 @@ export class HealthService {
|
||||
return out;
|
||||
}
|
||||
|
||||
async setStatus(status: { status: boolean; error: string; }) {
|
||||
async setStatus(status: { status: boolean; error: string }) {
|
||||
await this.store.client.hset('health:status', status);
|
||||
}
|
||||
|
||||
@ -115,8 +119,6 @@ export class HealthService {
|
||||
await this.config.checkNetwork();
|
||||
const mainBalance = await this.config.wallet.getBalance();
|
||||
const tornBalance = await this.config.tokenContract.balanceOf(this.config.wallet.address);
|
||||
// const mainBalance = BigNumber.from(`${1e18}`).add(1);
|
||||
// const tornBalance = BigNumber.from(`${60e18}`);
|
||||
const mainStatus = await this._checkBalance(mainBalance, 'MAIN');
|
||||
const tornStatus = await this._checkBalance(tornBalance, 'TORN');
|
||||
if (mainStatus.level === 'CRITICAL') {
|
||||
@ -128,15 +130,10 @@ export class HealthService {
|
||||
}
|
||||
}
|
||||
|
||||
type HealthData = {
|
||||
status: boolean,
|
||||
error: string,
|
||||
errorsLog: { message: string, score: number }[]
|
||||
}
|
||||
type Alert = {
|
||||
type: string,
|
||||
message: string,
|
||||
level: Levels,
|
||||
time?: number,
|
||||
}
|
||||
type: string;
|
||||
message: string;
|
||||
level: Levels;
|
||||
time?: number;
|
||||
};
|
||||
export default () => container.resolve(HealthService);
|
||||
|
@ -4,4 +4,3 @@ export { default as getJobService } from './job.service';
|
||||
export { default as getTxService } from './tx.service';
|
||||
export { default as getNotifierService } from './notifier.service';
|
||||
export { default as getHealthService } from './health.service';
|
||||
|
||||
|
@ -7,11 +7,12 @@ import { ConfigService } from './config.service';
|
||||
|
||||
@injectable()
|
||||
export class JobService {
|
||||
constructor(private price?: PriceQueueHelper,
|
||||
constructor(
|
||||
private price?: PriceQueueHelper,
|
||||
private relayer?: RelayerQueueHelper,
|
||||
private health?: HealthQueueHelper,
|
||||
public config?: ConfigService) {
|
||||
}
|
||||
public config?: ConfigService,
|
||||
) {}
|
||||
|
||||
async postJob(type: RelayerJobType, data: WithdrawalData) {
|
||||
const id = v4();
|
||||
@ -39,10 +40,8 @@ export class JobService {
|
||||
|
||||
private async _clearSchedulerJobs() {
|
||||
try {
|
||||
|
||||
|
||||
const jobs = await Promise.all([this.price.queue.getJobs(), this.health.queue.getJobs()]);
|
||||
await Promise.all(jobs.flat().map(job => job?.remove()));
|
||||
await Promise.all(jobs.flat().map((job) => job?.remove()));
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
@ -2,21 +2,20 @@ import { Telegram } from 'telegraf';
|
||||
import { autoInjectable, container } from 'tsyringe';
|
||||
import { RedisStore } from '../modules/redis';
|
||||
|
||||
export type Levels = keyof typeof AlertLevel
|
||||
export type Levels = keyof typeof AlertLevel;
|
||||
|
||||
export enum AlertLevel {
|
||||
'INFO' = 'ℹ️️',
|
||||
'WARN' = '⚠️',
|
||||
'CRITICAL' = '‼️',
|
||||
'ERROR' = '💩',
|
||||
'OK' = '✅'
|
||||
'OK' = '✅',
|
||||
}
|
||||
|
||||
export enum AlertType {
|
||||
'INSUFFICIENT_BALANCE',
|
||||
'INSUFFICIENT_TORN_BALANCE',
|
||||
'RPC'
|
||||
|
||||
'RPC',
|
||||
}
|
||||
|
||||
class MockTelegram {
|
||||
@ -43,7 +42,6 @@ export class NotifierService {
|
||||
this.token = process.env.TELEGRAM_NOTIFIER_BOT_TOKEN;
|
||||
this.chatId = process.env.TELEGRAM_NOTIFIER_CHAT_ID;
|
||||
this.telegram = this.token ? new Telegram(this.token) : new MockTelegram();
|
||||
|
||||
}
|
||||
|
||||
async processAlert(message: string) {
|
||||
@ -52,7 +50,7 @@ export class NotifierService {
|
||||
const isSent = await this.store.client.sismember('alerts:sent', `${a}_${b}_${c}`);
|
||||
if (!isSent) {
|
||||
if (alert.level === 'OK') {
|
||||
this.store.client.srem('alerts:sent', ...['WARN', 'CRITICAL'].map(c => `${a}_${b}_${c}`));
|
||||
this.store.client.srem('alerts:sent', ...['WARN', 'CRITICAL'].map((c) => `${a}_${b}_${c}`));
|
||||
} else {
|
||||
await this.send(alert.message, alert.level);
|
||||
this.store.client.sadd('alerts:sent', alert.type);
|
||||
@ -64,26 +62,16 @@ export class NotifierService {
|
||||
this.store.subscriber.subscribe('user-notify');
|
||||
this.store.subscriber.on('message', async (channel, message) => {
|
||||
await this.processAlert(<string>message);
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
send(message: string, level: Levels) {
|
||||
const text = `${AlertLevel[level]} ${message}`;
|
||||
return this.telegram.sendMessage(
|
||||
this.chatId,
|
||||
text,
|
||||
{ parse_mode: 'HTML' },
|
||||
);
|
||||
return this.telegram.sendMessage(this.chatId, text, { parse_mode: 'HTML' });
|
||||
}
|
||||
|
||||
sendError(e: any) {
|
||||
return this.telegram.sendMessage(
|
||||
this.chatId,
|
||||
`Error: ${e}`,
|
||||
);
|
||||
return this.telegram.sendMessage(this.chatId, `Error: ${e}`);
|
||||
}
|
||||
|
||||
check() {
|
||||
|
Loading…
Reference in New Issue
Block a user