From 00af3903034db6a508ee626092bc7532c0918a39 Mon Sep 17 00:00:00 2001 From: Dong-Ha Kim Date: Mon, 12 Dec 2022 19:44:07 +0100 Subject: [PATCH 01/17] test(e2e): try to fix caching in tests --- src/modules/referral/services/service.ts | 2 ++ test/referrals.e2e-spec.ts | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/modules/referral/services/service.ts b/src/modules/referral/services/service.ts index 57a8c5b9..f8499d65 100644 --- a/src/modules/referral/services/service.ts +++ b/src/modules/referral/services/service.ts @@ -43,6 +43,8 @@ export class ReferralService { public async getReferralSummary(address: string) { let data = await this.cacheManager.get(getReferralsSummaryCacheKey(address)); + console.log("CACHE", data); + if (data) return data; const referreeWalletsQuery = getReferreeWalletsQuery(); diff --git a/test/referrals.e2e-spec.ts b/test/referrals.e2e-spec.ts index 7db843e7..83f4ad46 100644 --- a/test/referrals.e2e-spec.ts +++ b/test/referrals.e2e-spec.ts @@ -25,6 +25,7 @@ const usdc = { const tier5DepositAmount = utils.parseUnits("500000", usdc.decimals).toString(); const tier4DepositAmount = utils.parseUnits("250000", usdc.decimals).toString(); const dayInMS = 24 * 60 * 60 * 1000; +const acxUsdPrice = utils.parseEther("0.1").toString(); let app: INestApplication; let depositFixture: DepositFixture; @@ -92,6 +93,7 @@ describe("POST /referrals/merkle-distribution", () => { amount: tier5DepositAmount, depositDate: new Date(), bridgeFeePct: ethers.utils.parseEther("0.01").toString(), // 1% + acxUsdPrice, }), ]); await referralService.cumputeReferralStats(); @@ -208,6 +210,7 @@ describe("GET /referrals/summary", () => { tokenId: token.id, priceId: price.id, depositorAddr: `0x${i}`, + acxUsdPrice, }), ), ); @@ -232,6 +235,7 @@ describe("GET /referrals/summary", () => { depositorAddr: `0x1`, depositDate: new Date(Date.now() - dayInMS), rewardsWindowIndex: 1, + acxUsdPrice, }), ]); await referralService.cumputeReferralStats(); @@ -260,6 +264,7 @@ describe("GET /referrals/summary", () => { amount: tier5DepositAmount, tokenId: token.id, priceId: price.id, + acxUsdPrice, }; await depositFixture.insertManyDeposits([ From c70cae4a94baa72a7ad93e136d9e27916413a983 Mon Sep 17 00:00:00 2001 From: Dong-Ha Kim Date: Tue, 13 Dec 2022 09:40:46 +0100 Subject: [PATCH 02/17] fix: only set cache value if ttl > 0 --- src/modules/referral/services/service.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/modules/referral/services/service.ts b/src/modules/referral/services/service.ts index f8499d65..57a8c5b9 100644 --- a/src/modules/referral/services/service.ts +++ b/src/modules/referral/services/service.ts @@ -43,8 +43,6 @@ export class ReferralService { public async getReferralSummary(address: string) { let data = await this.cacheManager.get(getReferralsSummaryCacheKey(address)); - console.log("CACHE", data); - if (data) return data; const referreeWalletsQuery = getReferreeWalletsQuery(); From f84157b2001646accd76bbd36d05b74eea36296b Mon Sep 17 00:00:00 2001 From: amateima Date: Tue, 13 Dec 2022 13:27:31 +0200 Subject: [PATCH 03/17] Fix materialized view --- test/referrals.e2e-spec.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/referrals.e2e-spec.ts b/test/referrals.e2e-spec.ts index 83f4ad46..7db843e7 100644 --- a/test/referrals.e2e-spec.ts +++ b/test/referrals.e2e-spec.ts @@ -25,7 +25,6 @@ const usdc = { const tier5DepositAmount = utils.parseUnits("500000", usdc.decimals).toString(); const tier4DepositAmount = utils.parseUnits("250000", usdc.decimals).toString(); const dayInMS = 24 * 60 * 60 * 1000; -const acxUsdPrice = utils.parseEther("0.1").toString(); let app: INestApplication; let depositFixture: DepositFixture; @@ -93,7 +92,6 @@ describe("POST /referrals/merkle-distribution", () => { amount: tier5DepositAmount, depositDate: new Date(), bridgeFeePct: ethers.utils.parseEther("0.01").toString(), // 1% - acxUsdPrice, }), ]); await referralService.cumputeReferralStats(); @@ -210,7 +208,6 @@ describe("GET /referrals/summary", () => { tokenId: token.id, priceId: price.id, depositorAddr: `0x${i}`, - acxUsdPrice, }), ), ); @@ -235,7 +232,6 @@ describe("GET /referrals/summary", () => { depositorAddr: `0x1`, depositDate: new Date(Date.now() - dayInMS), rewardsWindowIndex: 1, - acxUsdPrice, }), ]); await referralService.cumputeReferralStats(); @@ -264,7 +260,6 @@ describe("GET /referrals/summary", () => { amount: tier5DepositAmount, tokenId: token.id, priceId: price.id, - acxUsdPrice, }; await depositFixture.insertManyDeposits([ From 712d63c5477f90ee0b24b657c8f1d2754f41f2f0 Mon Sep 17 00:00:00 2001 From: Dong-Ha Kim Date: Wed, 14 Dec 2022 11:50:48 +0100 Subject: [PATCH 04/17] feat: handle speed up events (#179) * feat: extend deposit entity to cover speed ups * fix: make default suggested fees threshold shorter * feat: add `SpeedUpEventsConsumer` * fix: nullable initial relayer fee cpt * refactor: use update instead of save * fixup --- migrations/1670925750747-Deposit.ts | 15 ++++ src/modules/configuration/index.ts | 2 +- .../adapter/messaging/BlocksEventsConsumer.ts | 35 +++++++++- .../messaging/SpeedUpEventsConsumer.ts | 69 +++++++++++++++++++ .../scraper/adapter/messaging/index.ts | 11 +++ src/modules/scraper/model/deposit.entity.ts | 12 ++++ src/modules/scraper/module.ts | 11 +++ .../scraper/service/ScraperQueuesService.ts | 8 +++ .../web3/services/SpokePoolEventsQuerier.ts | 15 ++++ 9 files changed, 175 insertions(+), 3 deletions(-) create mode 100644 migrations/1670925750747-Deposit.ts create mode 100644 src/modules/scraper/adapter/messaging/SpeedUpEventsConsumer.ts diff --git a/migrations/1670925750747-Deposit.ts b/migrations/1670925750747-Deposit.ts new file mode 100644 index 00000000..40f1dd97 --- /dev/null +++ b/migrations/1670925750747-Deposit.ts @@ -0,0 +1,15 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class Deposit1670925750747 implements MigrationInterface { + name = "Deposit1670925750747"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "deposit" ADD "initialRelayerFeePct" numeric`); + await queryRunner.query(`ALTER TABLE "deposit" ADD "speedUps" jsonb NOT NULL DEFAULT '[]'`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "deposit" DROP COLUMN "speedUps"`); + await queryRunner.query(`ALTER TABLE "deposit" DROP COLUMN "initialRelayerFeePct"`); + } +} diff --git a/src/modules/configuration/index.ts b/src/modules/configuration/index.ts index d60f0315..5277183e 100644 --- a/src/modules/configuration/index.ts +++ b/src/modules/configuration/index.ts @@ -99,7 +99,7 @@ export const configValues = () => ({ }, suggestedFees: { apiUrl: process.env.SUGGESTED_FEES_API_URL || "https://across.to/api/suggested-fees", - fallbackThresholdHours: Number(process.env.SUGGESTED_FEES_FALLBACK_THRESHOLD_HOURS || "24"), + fallbackThresholdHours: Number(process.env.SUGGESTED_FEES_FALLBACK_THRESHOLD_HOURS || "4"), }, }); diff --git a/src/modules/scraper/adapter/messaging/BlocksEventsConsumer.ts b/src/modules/scraper/adapter/messaging/BlocksEventsConsumer.ts index 4d88559f..2e4ef951 100644 --- a/src/modules/scraper/adapter/messaging/BlocksEventsConsumer.ts +++ b/src/modules/scraper/adapter/messaging/BlocksEventsConsumer.ts @@ -5,8 +5,18 @@ import { InjectRepository } from "@nestjs/typeorm"; import { Repository, QueryFailedError } from "typeorm"; import { EthProvidersService } from "../../../web3/services/EthProvidersService"; -import { BlockNumberQueueMessage, BlocksEventsQueueMessage, FillEventsQueueMessage, ScraperQueue } from "."; -import { FundsDepositedEvent, FilledRelayEvent } from "@across-protocol/contracts-v2/dist/typechain/SpokePool"; +import { + BlockNumberQueueMessage, + BlocksEventsQueueMessage, + FillEventsQueueMessage, + ScraperQueue, + SpeedUpEventsQueueMessage, +} from "."; +import { + FundsDepositedEvent, + FilledRelayEvent, + RequestedSpeedUpDepositEvent, +} from "@across-protocol/contracts-v2/dist/typechain/SpokePool"; import { Deposit } from "../../model/deposit.entity"; import { ScraperQueuesService } from "../../service/ScraperQueuesService"; @@ -31,6 +41,12 @@ export class BlocksEventsConsumer { .getSpokePoolEventQuerier(chainId) .getFilledRelayEvents(from, to); this.logger.log(`(${from}, ${to}) - chainId ${chainId} - found ${fillEvents.length} FilledRelayEvent`); + const speedUpEvents: RequestedSpeedUpDepositEvent[] = await this.providers + .getSpokePoolEventQuerier(chainId) + .getRequestedSpeedUpDepositEvents(from, to); + this.logger.log( + `(${from}, ${to}) - chainId ${chainId} - found ${speedUpEvents.length} RequestedSpeedUpDepositEvent`, + ); for (const event of depositEvents) { try { @@ -59,6 +75,20 @@ export class BlocksEventsConsumer { appliedRelayerFeePct: e.args.appliedRelayerFeePct.toString(), })); await this.scraperQueuesService.publishMessagesBulk(ScraperQueue.FillEvents, fillMessages); + + const speedUpMessages: SpeedUpEventsQueueMessage[] = speedUpEvents.map((e) => ({ + depositSourceChainId: chainId, + depositId: e.args.depositId, + depositor: e.args.depositor, + depositorSignature: e.args.depositorSignature, + transactionHash: e.transactionHash, + blockNumber: e.blockNumber, + newRelayerFeePct: e.args.newRelayerFeePct.toString(), + })); + await this.scraperQueuesService.publishMessagesBulk( + ScraperQueue.SpeedUpEvents, + speedUpMessages, + ); } private async fromFundsDepositedEventToDeposit(event: FundsDepositedEvent) { @@ -78,6 +108,7 @@ export class BlocksEventsConsumer { blockNumber, depositorAddr: depositor, depositRelayerFeePct: relayerFeePct.toString(), + initialRelayerFeePct: relayerFeePct.toString(), }); } diff --git a/src/modules/scraper/adapter/messaging/SpeedUpEventsConsumer.ts b/src/modules/scraper/adapter/messaging/SpeedUpEventsConsumer.ts new file mode 100644 index 00000000..3ee48321 --- /dev/null +++ b/src/modules/scraper/adapter/messaging/SpeedUpEventsConsumer.ts @@ -0,0 +1,69 @@ +import { OnQueueFailed, Process, Processor } from "@nestjs/bull"; +import { Logger } from "@nestjs/common"; +import { Job } from "bull"; +import { DepositFilledDateQueueMessage, ScraperQueue, SpeedUpEventsQueueMessage } from "."; +import { InjectRepository } from "@nestjs/typeorm"; +import { Deposit } from "../../model/deposit.entity"; +import { Repository } from "typeorm"; +import { ScraperQueuesService } from "../../service/ScraperQueuesService"; + +@Processor(ScraperQueue.SpeedUpEvents) +export class SpeedUpEventsConsumer { + private logger = new Logger(SpeedUpEventsConsumer.name); + + constructor( + @InjectRepository(Deposit) private depositRepository: Repository, + private scraperQueuesService: ScraperQueuesService, + ) {} + + @Process() + private async process(job: Job) { + const { depositId, depositSourceChainId } = job.data; + const deposit = await this.depositRepository.findOne({ where: { sourceChainId: depositSourceChainId, depositId } }); + + if (!deposit) { + throw new Error( + `RequestedSpeedUpDeposit event for deposit with depositId '${depositId}' and sourceChainId '${depositSourceChainId}' could not be processed: deposit not found in db`, + ); + } + + if (this.isSpeedUpAlreadyProcessed(deposit, job.data)) { + this.logger.warn("RequestedSpeedUpDeposit event already processed"); + return; + } + + await this.processSpeedUpEventQueueMessage(deposit, job.data); + + this.scraperQueuesService.publishMessage(ScraperQueue.DepositFilledDate, { + depositId: deposit.id, + }); + } + + public async processSpeedUpEventQueueMessage(deposit: Deposit, data: SpeedUpEventsQueueMessage) { + const { transactionHash, newRelayerFeePct, blockNumber, depositSourceChainId } = data; + + const sortedSpeedUps = [ + ...deposit.speedUps, + { hash: transactionHash, newRelayerFeePct, blockNumber, depositSourceChainId }, + ].sort((a, b) => b.blockNumber - a.blockNumber); + + return this.depositRepository.update( + { id: deposit.id }, + { + speedUps: sortedSpeedUps, + depositRelayerFeePct: sortedSpeedUps[0].newRelayerFeePct, + }, + ); + } + + public isSpeedUpAlreadyProcessed(deposit: Deposit, speedUp: SpeedUpEventsQueueMessage) { + const { transactionHash } = speedUp; + const speedUpTxIndex = deposit.speedUps.findIndex((speedUpTx) => speedUpTx.hash === transactionHash); + return speedUpTxIndex !== -1; + } + + @OnQueueFailed() + private onQueueFailed(job: Job, error: Error) { + this.logger.error(`${ScraperQueue.SpeedUpEvents} ${JSON.stringify(job.data)} failed: ${error}`); + } +} diff --git a/src/modules/scraper/adapter/messaging/index.ts b/src/modules/scraper/adapter/messaging/index.ts index 2c5a9174..3193a82b 100644 --- a/src/modules/scraper/adapter/messaging/index.ts +++ b/src/modules/scraper/adapter/messaging/index.ts @@ -1,6 +1,7 @@ export enum ScraperQueue { BlocksEvents = "BlocksEvents", FillEvents = "FillEvents", + SpeedUpEvents = "SpeedUpEvents", BlockNumber = "BlockNumber", TokenDetails = "TokenDetails", DepositReferral = "DepositReferral", @@ -33,6 +34,16 @@ export type FillEventsQueueMessage = { appliedRelayerFeePct: string; }; +export type SpeedUpEventsQueueMessage = { + depositSourceChainId: number; + depositId: number; + depositor: string; + depositorSignature: string; + transactionHash: string; + blockNumber: number; + newRelayerFeePct: string; +}; + export type BlockNumberQueueMessage = { depositId: number; }; diff --git a/src/modules/scraper/model/deposit.entity.ts b/src/modules/scraper/model/deposit.entity.ts index d4a07e3e..898123f9 100644 --- a/src/modules/scraper/model/deposit.entity.ts +++ b/src/modules/scraper/model/deposit.entity.ts @@ -21,6 +21,12 @@ export type DepositFillTx = { appliedRelayerFeePct: string; date?: string; }; +export type RequestedSpeedUpDepositTx = { + hash: string; + blockNumber: number; + newRelayerFeePct: string; + depositSourceChainId: number; +}; @Entity() @Unique("UK_deposit_depositId_sourceChainId", ["depositId", "sourceChainId"]) @@ -62,6 +68,9 @@ export class Deposit { @Column({ type: "decimal" }) depositRelayerFeePct?: string; + @Column({ type: "decimal", nullable: true }) + initialRelayerFeePct?: string; + @Column({ type: "decimal", nullable: true }) suggestedRelayerFeePct?: string; @@ -94,6 +103,9 @@ export class Deposit { @Column({ type: "jsonb", default: [] }) fillTxs: DepositFillTx[]; + @Column({ type: "jsonb", default: [] }) + speedUps: RequestedSpeedUpDepositTx[]; + @Column() blockNumber: number; diff --git a/src/modules/scraper/module.ts b/src/modules/scraper/module.ts index 755e8043..0dfe0f15 100644 --- a/src/modules/scraper/module.ts +++ b/src/modules/scraper/module.ts @@ -17,6 +17,7 @@ import { MerkleDistributorBlocksEventsConsumer } from "./adapter/messaging/Merkl import { DepositFilledDateConsumer } from "./adapter/messaging/DepositFilledDateConsumer"; import { DepositReferralConsumer } from "./adapter/messaging/DepositReferralConsumer"; import { FillEventsConsumer } from "./adapter/messaging/FillEventsConsumer"; +import { SpeedUpEventsConsumer } from "./adapter/messaging/SpeedUpEventsConsumer"; import { TokenDetailsConsumer } from "./adapter/messaging/TokenDetailsConsumer"; import { TokenPriceConsumer } from "./adapter/messaging/TokenPriceConsumer"; import { ScraperController } from "./entry-point/http/controller"; @@ -38,6 +39,7 @@ import { SuggestedFeesService } from "./adapter/across-serverless-api/suggested- BlocksEventsConsumer, MerkleDistributorBlocksEventsConsumer, FillEventsConsumer, + SpeedUpEventsConsumer, BlockNumberConsumer, TokenDetailsConsumer, DepositReferralConsumer, @@ -85,6 +87,15 @@ import { SuggestedFeesService } from "./adapter/across-serverless-api/suggested- removeOnFail: true, }, }), + BullModule.registerQueue({ + name: ScraperQueue.SpeedUpEvents, + defaultJobOptions: { + backoff: 120 * 1000, + attempts: Number.MAX_SAFE_INTEGER, + removeOnComplete: true, + removeOnFail: true, + }, + }), BullModule.registerQueue({ name: ScraperQueue.DepositFilledDate, }), diff --git a/src/modules/scraper/service/ScraperQueuesService.ts b/src/modules/scraper/service/ScraperQueuesService.ts index 1d4a81ca..9b880787 100644 --- a/src/modules/scraper/service/ScraperQueuesService.ts +++ b/src/modules/scraper/service/ScraperQueuesService.ts @@ -11,6 +11,7 @@ export class ScraperQueuesService { @InjectQueue(ScraperQueue.BlocksEvents) private blocksEventsQueue: Queue, @InjectQueue(ScraperQueue.MerkleDistributorBlocksEvents) private merkleDistributorBlocksEventsQueue: Queue, @InjectQueue(ScraperQueue.FillEvents) private fillEventsQueue: Queue, + @InjectQueue(ScraperQueue.SpeedUpEvents) private speedUpEventsQueue: Queue, @InjectQueue(ScraperQueue.BlockNumber) private blockNumberQueue: Queue, @InjectQueue(ScraperQueue.TokenDetails) private tokenDetailsQueue: Queue, @InjectQueue(ScraperQueue.DepositReferral) private depositReferralQueue: Queue, @@ -29,6 +30,9 @@ export class ScraperQueuesService { this.fillEventsQueue .getJobCounts() .then((data) => this.logger.log(`${ScraperQueue.FillEvents} ${JSON.stringify(data)}`)); + this.speedUpEventsQueue + .getJobCounts() + .then((data) => this.logger.log(`${ScraperQueue.SpeedUpEvents} ${JSON.stringify(data)}`)); this.blockNumberQueue .getJobCounts() .then((data) => this.logger.log(`${ScraperQueue.BlockNumber} ${JSON.stringify(data)}`)); @@ -58,6 +62,8 @@ export class ScraperQueuesService { await this.blocksEventsQueue.add(message); } else if (queue === ScraperQueue.FillEvents) { await this.fillEventsQueue.add(message); + } else if (queue === ScraperQueue.SpeedUpEvents) { + await this.speedUpEventsQueue.add(message); } else if (queue === ScraperQueue.BlockNumber) { await this.blockNumberQueue.add(message); } else if (queue === ScraperQueue.TokenDetails) { @@ -82,6 +88,8 @@ export class ScraperQueuesService { await this.blocksEventsQueue.addBulk(messages.map((m) => ({ data: m }))); } else if (queue === ScraperQueue.FillEvents) { await this.fillEventsQueue.addBulk(messages.map((m) => ({ data: m }))); + } else if (queue === ScraperQueue.SpeedUpEvents) { + await this.speedUpEventsQueue.addBulk(messages.map((m) => ({ data: m }))); } else if (queue === ScraperQueue.BlockNumber) { await this.blockNumberQueue.addBulk(messages.map((m) => ({ data: m }))); } else if (queue === ScraperQueue.TokenDetails) { diff --git a/src/modules/web3/services/SpokePoolEventsQuerier.ts b/src/modules/web3/services/SpokePoolEventsQuerier.ts index 280b692b..23894355 100644 --- a/src/modules/web3/services/SpokePoolEventsQuerier.ts +++ b/src/modules/web3/services/SpokePoolEventsQuerier.ts @@ -16,6 +16,14 @@ export class SpokePoolEventsQuerier extends EventsQuerier { return this.getEvents(from, to, this.getFilledRelayEventsFilter(depositorAddr)); } + public async getRequestedSpeedUpDepositEvents( + from: number, + to: number, + depositorAddr?: string, + ): Promise[]> { + return this.getEvents(from, to, this.getRequestedSpeedUpDepositEventsFilters(depositorAddr)); + } + private getFilledRelayEventsFilter(depositorAddr?: string) { if (depositorAddr) { return this.spokePool.filters.FilledRelay( @@ -55,4 +63,11 @@ export class SpokePoolEventsQuerier extends EventsQuerier { } return this.spokePool.filters.FundsDeposited(); } + + private getRequestedSpeedUpDepositEventsFilters(depositorAddr?: string) { + if (depositorAddr) { + return this.spokePool.filters.RequestedSpeedUpDeposit(undefined, undefined, depositorAddr.toLowerCase()); + } + return this.spokePool.filters.RequestedSpeedUpDeposit(); + } } From 3b1bcd20151e5aaef85331fd6c623cacaacd7b15 Mon Sep 17 00:00:00 2001 From: Dong-Ha Kim Date: Wed, 14 Dec 2022 17:48:17 +0100 Subject: [PATCH 05/17] feat: use `suggestedRelayerFeePct` in `GET /deposits` endpoint (#181) * feat: use `suggestedRelayerFeePct` in `GET /deposits` endpoint * refactor: improve query and remove spread * fixup * refactor: make deviation buffer configurable --- migrations/1670942459408-Deposit.ts | 17 +++++++++++++++++ src/modules/configuration/index.ts | 1 + src/modules/deposit/service.ts | 6 +++++- src/modules/scraper/model/deposit.entity.ts | 4 ++-- 4 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 migrations/1670942459408-Deposit.ts diff --git a/migrations/1670942459408-Deposit.ts b/migrations/1670942459408-Deposit.ts new file mode 100644 index 00000000..f7fd88a9 --- /dev/null +++ b/migrations/1670942459408-Deposit.ts @@ -0,0 +1,17 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class Deposit1670942459408 implements MigrationInterface { + name = "Deposit1670942459408"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "deposit" ALTER COLUMN "suggestedRelayerFeePct" SET NOT NULL`); + await queryRunner.query( + `ALTER TABLE "deposit" ALTER COLUMN "suggestedRelayerFeePct" SET DEFAULT '100000000000000'`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "deposit" ALTER COLUMN "suggestedRelayerFeePct" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "deposit" ALTER COLUMN "suggestedRelayerFeePct" DROP NOT NULL`); + } +} diff --git a/src/modules/configuration/index.ts b/src/modules/configuration/index.ts index 5277183e..ab73435d 100644 --- a/src/modules/configuration/index.ts +++ b/src/modules/configuration/index.ts @@ -100,6 +100,7 @@ export const configValues = () => ({ suggestedFees: { apiUrl: process.env.SUGGESTED_FEES_API_URL || "https://across.to/api/suggested-fees", fallbackThresholdHours: Number(process.env.SUGGESTED_FEES_FALLBACK_THRESHOLD_HOURS || "4"), + deviationBufferMultiplier: Number(process.env.SUGGESTED_FEES_DEVIATION_BUFFER_MULTIPLIER || "1.25"), }, }); diff --git a/src/modules/deposit/service.ts b/src/modules/deposit/service.ts index 28124e7b..254dd58d 100644 --- a/src/modules/deposit/service.ts +++ b/src/modules/deposit/service.ts @@ -5,12 +5,14 @@ import { Repository } from "typeorm"; import { Cache } from "cache-manager"; import { Deposit } from "../scraper/model/deposit.entity"; import { getAvgFillTimeQuery, getTotalDepositsQuery, getTotalVolumeQuery } from "./adapter/db/queries"; +import { AppConfig } from "../configuration/configuration.service"; export const DEPOSITS_STATS_CACHE_KEY = "deposits:stats"; @Injectable() export class DepositService { constructor( + private appConfig: AppConfig, @InjectRepository(Deposit) private depositRepository: Repository, @Inject(CACHE_MANAGER) private cacheManager: Cache, ) {} @@ -53,7 +55,9 @@ export class DepositService { .createQueryBuilder("d") .where("d.status = :status", { status }) .andWhere("d.depositDate > NOW() - INTERVAL '1 days'") - .andWhere("d.depositRelayerFeePct / power(10, 18) >= 0.0001") + .andWhere(`d.depositRelayerFeePct * :multiplier >= d.suggestedRelayerFeePct`, { + multiplier: this.appConfig.values.suggestedFees.deviationBufferMultiplier, + }) .orderBy("d.depositDate", "DESC") .take(limit) .skip(offset) diff --git a/src/modules/scraper/model/deposit.entity.ts b/src/modules/scraper/model/deposit.entity.ts index 898123f9..679186d0 100644 --- a/src/modules/scraper/model/deposit.entity.ts +++ b/src/modules/scraper/model/deposit.entity.ts @@ -71,8 +71,8 @@ export class Deposit { @Column({ type: "decimal", nullable: true }) initialRelayerFeePct?: string; - @Column({ type: "decimal", nullable: true }) - suggestedRelayerFeePct?: string; + @Column({ type: "decimal", default: 100000000000000 }) // default 1bp = 0.01% + suggestedRelayerFeePct: string; @Column({ type: "decimal", default: 0 }) realizedLpFeePctCapped: string; From 0c2e3ac9e9ab319be071c468b57e7cabd84de5ab Mon Sep 17 00:00:00 2001 From: Dong-Ha Kim Date: Thu, 15 Dec 2022 14:54:04 +0100 Subject: [PATCH 06/17] feat: endpoint to get user deposits (#182) * feat: endpoint to get user deposits * refactor: remove unused ethers import * feat: expose speed ups and initial relayer fee pct * feat: expose suggested relayer fee pct * fixup * refactor: review requests - try/catch and address to checksum - re-use controller and address as query param - adjust tests * fix: query user deposits if status not set * fixup --- src/modules/deposit/controller.ts | 5 ++++ src/modules/deposit/dto.ts | 7 ++++- src/modules/deposit/exceptions.ts | 13 +++++++++ src/modules/deposit/service.ts | 47 +++++++++++++++++++++++++++++++ test/deposit.e2e-spec.ts | 30 +++++++++++++++++--- 5 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 src/modules/deposit/exceptions.ts diff --git a/src/modules/deposit/controller.ts b/src/modules/deposit/controller.ts index d1a1d2ce..bb964a9e 100644 --- a/src/modules/deposit/controller.ts +++ b/src/modules/deposit/controller.ts @@ -12,6 +12,11 @@ export class DepositController { getDeposits(@Query() query: GetDepositsQuery) { const limit = parseInt(query.limit ?? "10"); const offset = parseInt(query.offset ?? "0"); + + if (query.address) { + return this.depositService.getUserDeposits(query.address, query.status, limit, offset); + } + return this.depositService.getDeposits(query.status, limit, offset); } diff --git a/src/modules/deposit/dto.ts b/src/modules/deposit/dto.ts index c5315769..a5944e7a 100644 --- a/src/modules/deposit/dto.ts +++ b/src/modules/deposit/dto.ts @@ -1,5 +1,5 @@ import { ApiProperty } from "@nestjs/swagger"; -import { IsEnum, IsNumberString, IsOptional } from "class-validator"; +import { IsEnum, IsNumberString, IsOptional, IsString } from "class-validator"; export class GetDepositsQuery { @IsOptional() @@ -24,6 +24,11 @@ export class GetDepositsQuery { @IsNumberString({ no_symbols: true }) @ApiProperty({ example: "0", required: false }) offset: string; + + @IsOptional() + @IsString() + @ApiProperty({ required: false }) + address: string; } export class GetDepositsStatsResponse { diff --git a/src/modules/deposit/exceptions.ts b/src/modules/deposit/exceptions.ts new file mode 100644 index 00000000..a187ddfe --- /dev/null +++ b/src/modules/deposit/exceptions.ts @@ -0,0 +1,13 @@ +import { HttpException, HttpStatus } from "@nestjs/common"; + +export class InvalidAddressException extends HttpException { + constructor() { + super( + { + error: InvalidAddressException.name, + message: "Invalid address", + }, + HttpStatus.BAD_REQUEST, + ); + } +} diff --git a/src/modules/deposit/service.ts b/src/modules/deposit/service.ts index 254dd58d..8a9e66e0 100644 --- a/src/modules/deposit/service.ts +++ b/src/modules/deposit/service.ts @@ -2,10 +2,12 @@ import { DateTime } from "luxon"; import { CACHE_MANAGER, Inject, Injectable } from "@nestjs/common"; import { InjectRepository } from "@nestjs/typeorm"; import { Repository } from "typeorm"; +import { utils } from "ethers"; import { Cache } from "cache-manager"; import { Deposit } from "../scraper/model/deposit.entity"; import { getAvgFillTimeQuery, getTotalDepositsQuery, getTotalVolumeQuery } from "./adapter/db/queries"; import { AppConfig } from "../configuration/configuration.service"; +import { InvalidAddressException } from "./exceptions"; export const DEPOSITS_STATS_CACHE_KEY = "deposits:stats"; @@ -36,6 +38,47 @@ export class DepositService { return data; } + public async getUserDeposits(userAddress: string, status?: "filled" | "pending", limit = 10, offset = 0) { + let userDeposits: Deposit[] = []; + let total = 0; + + try { + userAddress = utils.getAddress(userAddress); + } catch (error) { + throw new InvalidAddressException(); + } + + if (status) { + [userDeposits, total] = await this.depositRepository + .createQueryBuilder("d") + .where("d.status = :status", { status }) + .andWhere("d.depositDate is not null") + .andWhere("d.depositorAddr = :userAddress", { userAddress }) + .orderBy("d.depositDate", "DESC") + .take(limit) + .skip(offset) + .getManyAndCount(); + } else { + [userDeposits, total] = await this.depositRepository + .createQueryBuilder("d") + .andWhere("d.depositDate is not null") + .andWhere("d.depositorAddr = :userAddress", { userAddress }) + .orderBy("d.depositDate", "DESC") + .take(limit) + .skip(offset) + .getManyAndCount(); + } + + return { + deposits: userDeposits.map(formatDeposit), + pagination: { + limit, + offset, + total, + }, + }; + } + public async getDeposits(status: "filled" | "pending", limit = 10, offset = 0) { let deposits: Deposit[] = []; let total = 0; @@ -97,9 +140,13 @@ export function formatDeposit(deposit: Deposit) { sourceChainId: deposit.sourceChainId, destinationChainId: deposit.destinationChainId, assetAddr: deposit.tokenAddr, + depositorAddr: deposit.depositorAddr, amount: deposit.amount, depositTxHash: deposit.depositTxHash, fillTxs: deposit.fillTxs.map(({ hash }) => hash), + speedUps: deposit.speedUps, depositRelayerFeePct: deposit.depositRelayerFeePct, + initialRelayerFeePct: deposit.initialRelayerFeePct, + suggestedRelayerFeePct: deposit.suggestedRelayerFeePct, }; } diff --git a/test/deposit.e2e-spec.ts b/test/deposit.e2e-spec.ts index ad4b4b39..05d7b825 100644 --- a/test/deposit.e2e-spec.ts +++ b/test/deposit.e2e-spec.ts @@ -1,6 +1,8 @@ import request from "supertest"; import { INestApplication } from "@nestjs/common"; import { Test } from "@nestjs/testing"; +import { constants } from "ethers"; + import { DepositFixture, mockManyDepositEntities } from "../src/modules/scraper/adapter/db/deposit-fixture"; import { ValidationPipe } from "../src/validation.pipe"; import { AppModule } from "../src/app.module"; @@ -18,10 +20,17 @@ beforeAll(async () => { }); describe("GET /deposits", () => { + const depositorAddress = "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D"; // filled deposits with depositIds 10 - 19 and ascending depositDate - const FILLED_DEPOSITS = mockManyDepositEntities(10, { depositIdStartIndex: 10, overrides: { status: "filled" } }); + const FILLED_DEPOSITS = mockManyDepositEntities(10, { + depositIdStartIndex: 10, + overrides: { status: "filled", depositorAddr: depositorAddress }, + }); // pending deposits with depositIds 20 - 29 and ascending depositDate - const PENDING_DEPOSITS = mockManyDepositEntities(10, { depositIdStartIndex: 20, overrides: { status: "pending" } }); + const PENDING_DEPOSITS = mockManyDepositEntities(10, { + depositIdStartIndex: 20, + overrides: { status: "pending", depositorAddr: depositorAddress }, + }); beforeAll(async () => { await app.get(DepositFixture).insertManyDeposits([...FILLED_DEPOSITS, ...PENDING_DEPOSITS]); @@ -34,8 +43,10 @@ describe("GET /deposits", () => { expect(response.body.pagination).toMatchObject({ limit: 10, offset: 0 }); }); - it("200 with status=filled & limit=5 ", async () => { - const response = await request(app.getHttpServer()).get("/deposits?status=filled&limit=5"); + it("200 with status=filled & limit=5 & address=depositorAddress", async () => { + const response = await request(app.getHttpServer()).get( + `/deposits?status=filled&limit=5&address=${depositorAddress}`, + ); expect(response.status).toBe(200); expect(response.body.deposits).toHaveLength(5); expect(response.body.pagination).toMatchObject({ limit: 5, offset: 0, total: FILLED_DEPOSITS.length }); @@ -50,6 +61,12 @@ describe("GET /deposits", () => { expect(response.body.deposits[0].depositId).toBe(14); }); + it("200 with empty array", async () => { + const response = await request(app.getHttpServer()).get(`/deposits?address=${constants.AddressZero}`); + expect(response.status).toBe(200); + expect(response.body.deposits).toHaveLength(0); + }); + it("400 for invalid status", async () => { const response = await request(app.getHttpServer()).get("/deposits?status=invalid"); expect(response.status).toBe(400); @@ -60,6 +77,11 @@ describe("GET /deposits", () => { expect(response.status).toBe(400); }); + it("400 for invalid address", async () => { + const response = await request(app.getHttpServer()).get(`/deposits?address=invalid`); + expect(response.status).toBe(400); + }); + it("400 for negative offset", async () => { const response = await request(app.getHttpServer()).get("/deposits?offset=-10"); expect(response.status).toBe(400); From 47fd1ec4b76fc4c5920eab470a6fea7c662fe01d Mon Sep 17 00:00:00 2001 From: Dong-Ha Kim Date: Tue, 20 Dec 2022 15:17:45 +0100 Subject: [PATCH 07/17] fix: migrations suggested relayer fees (#184) --- migrations/1670942459408-Deposit.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/migrations/1670942459408-Deposit.ts b/migrations/1670942459408-Deposit.ts index f7fd88a9..90b91aef 100644 --- a/migrations/1670942459408-Deposit.ts +++ b/migrations/1670942459408-Deposit.ts @@ -4,6 +4,9 @@ export class Deposit1670942459408 implements MigrationInterface { name = "Deposit1670942459408"; public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `UPDATE "deposit" SET "suggestedRelayerFeePct" = '100000000000000' WHERE "suggestedRelayerFeePct" IS NULL`, + ); await queryRunner.query(`ALTER TABLE "deposit" ALTER COLUMN "suggestedRelayerFeePct" SET NOT NULL`); await queryRunner.query( `ALTER TABLE "deposit" ALTER COLUMN "suggestedRelayerFeePct" SET DEFAULT '100000000000000'`, From 7ddbe488d4a09dffbff9e2acdaeb20f3b9d3f69c Mon Sep 17 00:00:00 2001 From: amateima <89395931+amateima@users.noreply.github.com> Date: Tue, 20 Dec 2022 16:35:37 +0200 Subject: [PATCH 08/17] feat: reset referral rewards after claim (#183) --- migrations/1671299400000-Deposit.ts | 16 +++++ src/modules/referral/services/service.ts | 77 +++++++++++++-------- src/modules/scraper/model/deposit.entity.ts | 7 ++ 3 files changed, 73 insertions(+), 27 deletions(-) create mode 100644 migrations/1671299400000-Deposit.ts diff --git a/migrations/1671299400000-Deposit.ts b/migrations/1671299400000-Deposit.ts new file mode 100644 index 00000000..88d4fd51 --- /dev/null +++ b/migrations/1671299400000-Deposit.ts @@ -0,0 +1,16 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class Deposit1671299400000 implements MigrationInterface { + name = "Deposit1671299400000"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(` + create index "IX_deposit_srAddress_depositDate_pId_tId_status" + on deposit ("stickyReferralAddress", "depositDate", "priceId", "tokenId", status) + `); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`drop index if exists "IX_deposit_srAddress_depositDate_pId_tId_status"`); + } +} diff --git a/src/modules/referral/services/service.ts b/src/modules/referral/services/service.ts index 57a8c5b9..0db3140b 100644 --- a/src/modules/referral/services/service.ts +++ b/src/modules/referral/services/service.ts @@ -24,6 +24,7 @@ import { WindowAlreadySetException } from "./exceptions"; import { DepositsFilteredReferrals } from "../model/DepositsFilteredReferrals.entity"; import { DepositReferralStat } from "../../deposit/model/deposit-referral-stat.entity"; import { splitArrayInChunks } from "../../../utils"; +import { Claim } from "../../scraper/model/claim.entity"; const REFERRAL_ADDRESS_DELIMITER = "d00dfeeddeadbeef"; const getReferralsSummaryCacheKey = (address: string) => `referrals:summary:${address}`; @@ -127,7 +128,6 @@ export class ReferralService { .where("deposit.rewardsWindowIndex IS NULL") .andWhere("deposit.depositDate <= :maxDepositDate", { maxDepositDate }) .getMany(); - console.log(`found ${deposits.length} deposits`); const { recipients, rewardsToDeposit } = this.calculateReferralRewards(deposits); for (const depositsChunk of splitArrayInChunks(deposits, 100)) { @@ -274,11 +274,9 @@ export class ReferralService { this.logger.log(`start cumputeReferralStats()`); const t1 = performance.now(); const window = -1; - const deposits = await entityManager .createQueryBuilder(DepositsFilteredReferrals, "d") .select("d.stickyReferralAddress") - .where("d.referralClaimedWindowIndex = :claimedWindowIndex", { claimedWindowIndex: window }) .groupBy("d.stickyReferralAddress") .getMany(); const referralAddresses = deposits.map((deposit) => deposit.stickyReferralAddress); @@ -286,7 +284,7 @@ export class ReferralService { await Bluebird.Promise.map( referralAddresses, (address) => { - return this.computeStatsForReferralAddress(entityManager, window, address); + return this.computeStatsForReferralAddress(entityManager, address); }, { concurrency: 10 }, ); @@ -296,21 +294,33 @@ export class ReferralService { }); } - private async computeStatsForReferralAddress(entityManager: EntityManager, window: number, referralAddress: string) { - const depositsResult = await entityManager + private async computeStatsForReferralAddress(entityManager: EntityManager, referralAddress: string) { + const claims = await entityManager + .createQueryBuilder(Claim, "c") + .where("c.account = :account", { account: referralAddress }) + .orderBy("c.claimedAt", "ASC") + .getMany(); + const deposits = await entityManager .createQueryBuilder(DepositsFilteredReferrals, "d") - .where("d.referralClaimedWindowIndex = :claimedWindowIndex", { claimedWindowIndex: window }) .andWhere("d.stickyReferralAddress = :referralAddress", { referralAddress }) .getMany(); + const sortedDeposits = deposits.sort((d1, d2) => (d1.depositDate.getTime() < d2.depositDate.getTime() ? -1 : 0)); + const sortedClaims = claims.sort((c1, c2) => (c1.claimedAt.getTime() < c2.claimedAt.getTime() ? -1 : 0)); + const groupedDeposits = this.groupDepositsByClaimDate(sortedDeposits, sortedClaims); + + for (const deposits of Object.values(groupedDeposits)) { + await this.computeReferralStatsForDeposits(deposits, entityManager); + } + } + + private async computeReferralStatsForDeposits(deposits: DepositsFilteredReferrals[], entityManager: EntityManager) { const depositorAddrCounts = {}; const depositCounts = {}; const depositVolume = {}; let totalVolume = new BigNumber(0); - let currentCount = 0; - const sortedDeposits = depositsResult.sort((d1, d2) => (d1.depositDate < d2.depositDate ? -1 : 0)); - for (const deposit of sortedDeposits) { + for (const deposit of deposits) { const prevCount = depositorAddrCounts[deposit.depositorAddr]; if (!prevCount) { @@ -327,22 +337,35 @@ export class ReferralService { depositVolume[deposit.id] = totalVolume; } - for (const depositsChunk of splitArrayInChunks(sortedDeposits, 100)) { - const values: Partial[] = depositsChunk.map((d) => ({ - depositId: d.id, - referralCount: depositCounts[d.id], - referralVolume: depositVolume[d.id].toFixed(), - referralClaimedWindowIndex: d.referralClaimedWindowIndex, - })); - await entityManager - .createQueryBuilder(DepositReferralStat, "d") - .insert() - .values(values) - .orUpdate({ - conflict_target: ["depositId"], - overwrite: ["referralCount", "referralVolume", "referralClaimedWindowIndex"], - }) - .execute(); - } + await Promise.all( + splitArrayInChunks(deposits, 100).map((depositsChunk) => { + const values: Partial[] = depositsChunk.map((d) => ({ + depositId: d.id, + referralCount: depositCounts[d.id], + referralVolume: depositVolume[d.id].toFixed(), + referralClaimedWindowIndex: d.referralClaimedWindowIndex, + })); + return entityManager + .createQueryBuilder(DepositReferralStat, "d") + .insert() + .values(values) + .orUpdate({ + conflict_target: ["depositId"], + overwrite: ["referralCount", "referralVolume", "referralClaimedWindowIndex"], + }) + .execute(); + }), + ); + } + + private groupDepositsByClaimDate(deposits: DepositsFilteredReferrals[], claims: Claim[]) { + return deposits.reduce((acc, deposit) => { + const claim = claims.filter((claim) => claim.claimedAt.getTime() >= deposit.depositDate.getTime())[0]; + const windowIndex = claim?.windowIndex || -1; + return { + ...acc, + [windowIndex]: [...(acc[windowIndex] || []), deposit], + }; + }, {} as Record); } } diff --git a/src/modules/scraper/model/deposit.entity.ts b/src/modules/scraper/model/deposit.entity.ts index 679186d0..8a540fd2 100644 --- a/src/modules/scraper/model/deposit.entity.ts +++ b/src/modules/scraper/model/deposit.entity.ts @@ -31,6 +31,13 @@ export type RequestedSpeedUpDepositTx = { @Entity() @Unique("UK_deposit_depositId_sourceChainId", ["depositId", "sourceChainId"]) @Index("IX_deposit_depositorAddr", ["depositorAddr"]) +@Index("IX_deposit_srAddress_depositDate_pId_tId_status", [ + "stickyReferralAddress", + "depositDate", + "priceId", + "tokenId", + "status", +]) export class Deposit { @PrimaryGeneratedColumn() id: number; From 12e211e331c010022960ca1a497f71bf8bddf86b Mon Sep 17 00:00:00 2001 From: Dong-Ha Kim Date: Thu, 29 Dec 2022 13:40:31 +0100 Subject: [PATCH 09/17] feat: track fill event amplitude (#186) * feat: add ampli packages and pull code * feat: wip add consumer to track fill events * feat: add new deposit column `recipientAddr` * feat: refine track fill event consumer * test: fix imports for e2e tests * test: fix missing destinationToken in mock * fixup * feat: add fillAmount and totalFilledAmount to tracker * feat: derive capital + relayer gas fee values * refactor: add fallback if src or dst chains unknown --- .env.sample | 1 + .gitignore | 5 +- migrations/1672153290341-Deposit.ts | 15 + package.json | 5 +- src/modules/ampli/index.ts | 435 +++++++ src/modules/configuration/index.ts | 3 + .../market-price/adapters/coingecko/index.ts | 2 + .../adapter/amplitude/track-service.ts | 30 + .../scraper/adapter/amplitude/utils.ts | 49 + .../scraper/adapter/db/deposit-fixture.ts | 1 + .../adapter/messaging/BlocksEventsConsumer.ts | 5 +- .../adapter/messaging/FillEventsConsumer.ts | 15 +- .../messaging/TrackFillEventConsumer.ts | 183 +++ .../scraper/adapter/messaging/index.ts | 8 + src/modules/scraper/model/deposit.entity.ts | 3 + src/modules/scraper/module.ts | 7 + .../scraper/service/ScraperQueuesService.ts | 8 + src/modules/web3/model/ChainId.ts | 8 + src/utils.ts | 29 + test/scraper.e2e-spec.ts | 1 + yarn.lock | 1086 ++++++++++++++++- 21 files changed, 1866 insertions(+), 33 deletions(-) create mode 100644 migrations/1672153290341-Deposit.ts create mode 100644 src/modules/ampli/index.ts create mode 100644 src/modules/scraper/adapter/amplitude/track-service.ts create mode 100644 src/modules/scraper/adapter/amplitude/utils.ts create mode 100644 src/modules/scraper/adapter/messaging/TrackFillEventConsumer.ts diff --git a/.env.sample b/.env.sample index cc94364a..e0bc4b4d 100644 --- a/.env.sample +++ b/.env.sample @@ -36,3 +36,4 @@ ENABLE_MERKLE_DISTRIBUTOR_EVENTS_PROCESSING=false DISTRIBUTOR_PROOFS_CACHE_SECONDS_DURATION=0 REFERRALS_SUMMARY_CACHE_SECONDS_DURATION=0 +AMPLITUDE_API_KEY= diff --git a/.gitignore b/.gitignore index f7d6d874..dc77177d 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,7 @@ lerna-debug.log* !.vscode/launch.json !.vscode/extensions.json -uploads \ No newline at end of file +uploads + +# Amplitude +ampli.json diff --git a/migrations/1672153290341-Deposit.ts b/migrations/1672153290341-Deposit.ts new file mode 100644 index 00000000..4ec78868 --- /dev/null +++ b/migrations/1672153290341-Deposit.ts @@ -0,0 +1,15 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class Deposit1672153290341 implements MigrationInterface { + name = "Deposit1672153290341"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "deposit" ADD "recipientAddr" character varying`); + await queryRunner.query(`UPDATE "deposit" SET "recipientAddr" = "depositorAddr" WHERE "recipientAddr" IS NULL`); + await queryRunner.query(`ALTER TABLE "deposit" ALTER COLUMN "recipientAddr" SET NOT NULL`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "deposit" DROP COLUMN "recipientAddr"`); + } +} diff --git a/package.json b/package.json index 5af30aec..9c19abaa 100644 --- a/package.json +++ b/package.json @@ -23,10 +23,12 @@ "test:e2e:docker:prune": "docker-compose -f docker-compose.e2e.yml down -v", "typeorm": "node --require ts-node/register ./node_modules/typeorm/cli.js", "db:migration:generate": "yarn typeorm -- migration:generate -d ormconfig.ts", - "db:migration:run": "yarn typeorm -- migration:run -d ormconfig.ts" + "db:migration:run": "yarn typeorm -- migration:run -d ormconfig.ts", + "ampli:pull": "ampli pull --path=./src/modules/ampli --omit-api-keys scraper && prettier -w ./src/modules/ampli/*.ts" }, "dependencies": { "@across-protocol/contracts-v2": "^1.0.7", + "@amplitude/analytics-node": "^1.0.1", "@nestjs/axios": "^0.0.8", "@nestjs/bull": "^0.5.5", "@nestjs/cli": "^8.2.4", @@ -75,6 +77,7 @@ "uuid": "^9.0.0" }, "devDependencies": { + "@amplitude/ampli": "^1.28.0", "@types/async": "^3.2.13", "@types/bignumber.js": "^5.0.0", "@types/bluebird": "^3.5.37", diff --git a/src/modules/ampli/index.ts b/src/modules/ampli/index.ts new file mode 100644 index 00000000..db756607 --- /dev/null +++ b/src/modules/ampli/index.ts @@ -0,0 +1,435 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Ampli - A strong typed wrapper for your Analytics + * + * This file is generated by Amplitude. + * To update run 'ampli pull scraper' + * + * Required dependencies: @amplitude/analytics-node@^0.5.0 + * Tracking Plan Version: 30 + * Build: 1.0.0 + * Runtime: node.js:typescript-ampli-v2 + * + * [View Tracking Plan](https://data.amplitude.com/risklabs/Risk%20Labs/events/main/latest) + * + * [Full Setup Instructions](https://data.amplitude.com/risklabs/Risk%20Labs/implementation/scraper) + */ + +import * as amplitude from "@amplitude/analytics-node"; + +export type NodeClient = amplitude.Types.NodeClient; +export type BaseEvent = amplitude.Types.BaseEvent; +export type Event = amplitude.Types.Event; +export type EventOptions = amplitude.Types.EventOptions; +export type Result = amplitude.Types.Result; +export type NodeOptions = amplitude.Types.NodeOptions; + +export type Environment = "production" | "development"; + +export const ApiKey: Record = { + production: "", + development: "", +}; + +/** + * Default Amplitude configuration options. Contains tracking plan information. + */ +export const DefaultConfiguration: NodeOptions = { + plan: { + version: "30", + branch: "main", + source: "scraper", + versionId: "0b21d764-e05a-48ac-9da6-95b3efc901dd", + }, + ...{ + ingestionMetadata: { + sourceName: "node.js-typescript-ampli", + sourceVersion: "2.0.0", + }, + }, +}; + +export interface LoadOptionsBase { + disabled?: boolean; +} + +export type LoadOptionsWithEnvironment = LoadOptionsBase & { + environment: Environment; + client?: { configuration?: NodeOptions }; +}; +export type LoadOptionsWithApiKey = LoadOptionsBase & { client: { apiKey: string; configuration?: NodeOptions } }; +export type LoadOptionsWithClientInstance = LoadOptionsBase & { client: { instance: NodeClient } }; + +export type LoadOptions = LoadOptionsWithEnvironment | LoadOptionsWithApiKey | LoadOptionsWithClientInstance; + +export interface IdentifyProperties { + /** + * List of wallet addresses connected during Wallet Connect Transaction Completed event. + * + * | Rule | Value | + * |---|---| + * | Unique Items | true | + * | Item Type | string | + */ + allWalletAddressesConnected?: string[]; + /** + * Chain ids of wallet addresses connected + * + * | Rule | Value | + * |---|---| + * | Unique Items | true | + * | Item Type | string | + */ + allWalletChainIds?: string[]; + initial_dclid?: any; + initial_fbclid?: any; + initial_gbraid?: any; + initial_gclid?: any; + initial_ko_click_id?: any; + initial_msclkid?: any; + initial_referrer?: any; + initial_referring_domain?: any; + initial_ttclid?: any; + initial_twclid?: any; + initial_utm_campaign?: any; + initial_utm_content?: any; + initial_utm_id?: any; + initial_utm_medium?: any; + initial_utm_source?: any; + initial_utm_term?: any; + initial_wbraid?: any; + /** + * Total volume of bridge transfers (since event tracking was implemented). Updated on each new transfer the user completes. + * + * | Rule | Value | + * |---|---| + * | Type | integer | + */ + totalVolumeUsd: number; + /** + * Currently connected wallet address + */ + walletAddress?: string; + /** + * Type of wallet connected + */ + walletType?: string; +} + +export interface TransferTransactionConfirmedProperties { + /** + * Capital fee percent, in decimals + */ + capitalFeePct: string; + /** + * Capital fee in the bridge token, in decimals + */ + capitalFeeTotal: string; + /** + * Capital fee in USD + */ + capitalFeeTotalUsd: string; + fillAmount: string; + fillAmountUsd: string; + /** + * From amount in the bridge token, in decimals + */ + fromAmount: string; + /** + * From amount in USD + */ + fromAmountUsd: string; + /** + * From chain id + */ + fromChainId: string; + /** + * From chain name + */ + fromChainName: string; + /** + * Token address of bridge token on from chain + */ + fromTokenAddress: string; + isAmountTooLow: boolean; + /** + * Lp fee percent, in decimals + */ + lpFeePct: string; + /** + * Lp fee in the bridge token, in decimals + */ + lpFeeTotal: string; + /** + * Lp fee in USD + */ + lpFeeTotalUsd: string; + /** + * Gas fee in network token + */ + NetworkFeeNative: string; + /** + * Network native token + */ + NetworkFeeNativeToken: string; + /** + * Gas fee in USD + */ + NetworkFeeUsd: string; + /** + * Recipient wallet address + */ + recipient: string; + /** + * Address of referee, null if no referral used + */ + referralProgramAddress: string; + /** + * Relay fee percent, in decimals + */ + relayFeePct: string; + /** + * Relay fee in the gas token, in decimals + */ + relayFeeTotal: string; + /** + * Relay fee in USD + */ + relayFeeTotalUsd: string; + /** + * Relayer gas fee percent, in decimals + */ + relayGasFeePct: string; + /** + * Relayer gas fee in the gas token, in decimals + */ + relayGasFeeTotal: string; + /** + * Relayer fee in USD + */ + relayGasFeeTotalUsd: string; + /** + * Route "{fromChainId}-{toChainId}" + */ + routeChainIdFromTo: string; + /** + * Route "{fromChainName}-{toChainName}" + */ + routeChainNameFromTo: string; + /** + * Sender wallet address + */ + sender: string; + /** + * Result of user signing or rejecting wallet connection + */ + succeeded: boolean; + /** + * Duration in milliseconds between TransferSigned event to the TransferTransactionCompleted event + */ + timeFromTransferSignedToTransferCompleteInMilliseconds: string; + /** + * To amount of bridge token, in decimals + */ + toAmount: string; + /** + * To amount in USD + */ + toAmountUsd: string; + /** + * Id of the toChain + */ + toChainId: string; + /** + * Name of the toChain + */ + toChainName: string; + /** + * Symbol of bridge token + */ + tokenSymbol: string; + /** + * Total bridge fee in the bridge token, in decimals + */ + totalBridgeFee: string; + /** + * Total bridge fee percent, in decimals + */ + totalBridgeFeePct: string; + /** + * Total bridge fee in USD + */ + totalBridgeFeeUsd: string; + totalFilledAmount: string; + totalFilledAmountUsd: string; + /** + * Token address of bridge token on to chain + */ + toTokenAddress: string; + /** + * Resulting transaction hash of transaction, null if "result" if TransferTransactionCompleted = failed + */ + transactionHash: string; + /** + * Timestamp transfer completed + */ + transferCompleteTimestamp: string; + transferQuoteBlockNumber: string; +} + +export class Identify implements BaseEvent { + event_type = "Identify"; + + constructor(public event_properties: IdentifyProperties) { + this.event_properties = event_properties; + } +} + +export class TransferTransactionConfirmed implements BaseEvent { + event_type = "TransferTransactionConfirmed"; + + constructor(public event_properties: TransferTransactionConfirmedProperties) { + this.event_properties = event_properties; + } +} + +export type PromiseResult = { promise: Promise }; + +const getVoidPromiseResult = () => ({ promise: Promise.resolve() }); + +// prettier-ignore +export class Ampli { + private disabled: boolean = false; + private amplitude?: NodeClient; + + get client(): NodeClient { + this.isInitializedAndEnabled(); + return this.amplitude!; + } + + get isLoaded(): boolean { + return this.amplitude != null; + } + + private isInitializedAndEnabled(): boolean { + if (!this.amplitude) { + console.error('ERROR: Ampli is not yet initialized. Have you called ampli.load() on app start?'); + return false; + } + return !this.disabled; + } + + /** + * Initialize the Ampli SDK. Call once when your application starts. + * + * @param options Configuration options to initialize the Ampli SDK with. + */ + load(options: LoadOptions): PromiseResult { + this.disabled = options.disabled ?? false; + + if (this.amplitude) { + console.warn('WARNING: Ampli is already initialized. Ampli.load() should be called once at application startup.'); + return getVoidPromiseResult(); + } + + let apiKey: string | null = null; + if (options.client && 'apiKey' in options.client) { + apiKey = options.client.apiKey; + } else if ('environment' in options) { + apiKey = ApiKey[options.environment]; + } + + if (options.client && 'instance' in options.client) { + this.amplitude = options.client.instance; + } else if (apiKey) { + this.amplitude = amplitude.createInstance(); + return this.amplitude.init(apiKey, { ...DefaultConfiguration, ...(options.client as any)?.configuration }); + } else { + console.error("ERROR: ampli.load() requires 'environment', 'client.apiKey', or 'client.instance'"); + } + + return getVoidPromiseResult(); + } + + /** + * Identify a user and set user properties. + * + * @param userId The user's id. + * @param properties The user properties. + * @param options Optional event options. + */ + identify( + userId: string | undefined, + properties: IdentifyProperties, + options?: EventOptions, + ): PromiseResult { + if (!this.isInitializedAndEnabled()) { + return getVoidPromiseResult(); + } + + if (userId) { + options = {...options, user_id: userId}; + } + + const amplitudeIdentify = new amplitude.Identify(); + const eventProperties = properties; + if (eventProperties != null) { + for (const [key, value] of Object.entries(eventProperties)) { + amplitudeIdentify.set(key, value); + } + } + + return this.amplitude!.identify(amplitudeIdentify, options); + } + + /** + * Track event + * + * @param userId The user's id. + * @param event The event to track. + * @param options Optional event options. + */ + track(userId: string | undefined, event: Event, options?: EventOptions): PromiseResult { + if (!this.isInitializedAndEnabled()) { + return getVoidPromiseResult(); + } + + if (userId) { + options = {...options, user_id: userId}; + } + + return this.amplitude!.track(event, undefined, options); + } + + flush(): PromiseResult { + if (!this.isInitializedAndEnabled()) { + return getVoidPromiseResult(); + } + + return this.amplitude!.flush(); + } + + /** + * TransferTransactionConfirmed + * + * [View in Tracking Plan](https://data.amplitude.com/risklabs/Risk%20Labs/events/main/latest/TransferTransactionConfirmed) + * + * On-chain transfer completed + * + * Owner: James Morris + * + * @param userId The user's ID. + * @param properties The event's properties (e.g. capitalFeePct) + * @param options Amplitude event options. + */ + transferTransactionConfirmed( + userId: string | undefined, + properties: TransferTransactionConfirmedProperties, + options?: EventOptions, + ) { + return this.track(userId, new TransferTransactionConfirmed(properties), options); + } +} + +export const ampli = new Ampli(); diff --git a/src/modules/configuration/index.ts b/src/modules/configuration/index.ts index ab73435d..52e861c2 100644 --- a/src/modules/configuration/index.ts +++ b/src/modules/configuration/index.ts @@ -102,6 +102,9 @@ export const configValues = () => ({ fallbackThresholdHours: Number(process.env.SUGGESTED_FEES_FALLBACK_THRESHOLD_HOURS || "4"), deviationBufferMultiplier: Number(process.env.SUGGESTED_FEES_DEVIATION_BUFFER_MULTIPLIER || "1.25"), }, + amplitude: { + apiKey: process.env.AMPLITUDE_API_KEY, + }, }); export default registerAs("config", () => configValues()); diff --git a/src/modules/market-price/adapters/coingecko/index.ts b/src/modules/market-price/adapters/coingecko/index.ts index 4bc6b412..435d98e6 100644 --- a/src/modules/market-price/adapters/coingecko/index.ts +++ b/src/modules/market-price/adapters/coingecko/index.ts @@ -3,6 +3,8 @@ import { Injectable } from "@nestjs/common"; import { CGHistoricPrice } from "./model"; const symbolIdMap = { + eth: "ethereum", + matic: "matic-network", wbtc: "wrapped-bitcoin", usdc: "usd-coin", uma: "uma", diff --git a/src/modules/scraper/adapter/amplitude/track-service.ts b/src/modules/scraper/adapter/amplitude/track-service.ts new file mode 100644 index 00000000..8814b177 --- /dev/null +++ b/src/modules/scraper/adapter/amplitude/track-service.ts @@ -0,0 +1,30 @@ +import { HttpService } from "@nestjs/axios"; +import { Injectable } from "@nestjs/common"; + +import { EventOptions, TransferTransactionConfirmedProperties, ampli } from "../../../ampli"; +import { AppConfig } from "../../../configuration/configuration.service"; + +@Injectable() +export class TrackService { + constructor(private appConfig: AppConfig, private httpService: HttpService) { + if (appConfig.values.amplitude.apiKey) { + ampli.load({ + client: { + apiKey: appConfig.values.amplitude.apiKey, + }, + }); + } + } + + public isEnabled() { + return Boolean(this.appConfig.values.amplitude.apiKey); + } + + public async trackDepositFilledEvent( + userId: string, + eventProperties: TransferTransactionConfirmedProperties, + eventOptions?: EventOptions, + ) { + return ampli.transferTransactionConfirmed(userId, eventProperties, eventOptions); + } +} diff --git a/src/modules/scraper/adapter/amplitude/utils.ts b/src/modules/scraper/adapter/amplitude/utils.ts new file mode 100644 index 00000000..b69c25a0 --- /dev/null +++ b/src/modules/scraper/adapter/amplitude/utils.ts @@ -0,0 +1,49 @@ +import BigNumber from "bignumber.js"; +import { utils } from "ethers"; + +export const fixedPointAdjustment = new BigNumber(10).pow(18); + +export function formatWeiPct(weiPct: string, decimals?: number) { + return new BigNumber(weiPct).dividedBy(fixedPointAdjustment).multipliedBy(100).toFixed(decimals); +} + +export function formatWeiPctOfTotal(weiPct: string, total: string, decimals?: number) { + return new BigNumber(total).multipliedBy(weiPct).dividedBy(fixedPointAdjustment).toFixed(decimals); +} + +export function getFormattedWeiPctValues(weiPct: string, totalAmount: string, usdPrice: string) { + const weiPctTotal = formatWeiPctOfTotal(weiPct, totalAmount); + return { + pct: formatWeiPct(weiPct, 3), + total: weiPctTotal, + totalUsd: new BigNumber(weiPctTotal).multipliedBy(usdPrice).toFixed(), + }; +} + +export function makeWeiPctValuesFormatter(totalAmount: string, usdPrice: string) { + return (weiPct: string) => getFormattedWeiPctValues(weiPct, totalAmount, usdPrice); +} + +export function getFormattedAmountValues(amount: string, decimals: number, usdPrice: string) { + const formattedAmount = utils.formatUnits(amount, decimals); + return { + formattedAmount, + formattedAmountUsd: new BigNumber(formattedAmount).multipliedBy(usdPrice).toFixed(), + }; +} + +export function makeAmountValuesFormatter(decimals: number, usdPrice: string) { + return (amount: string) => getFormattedAmountValues(amount, decimals, usdPrice); +} + +export function deriveRelayerFeeComponents(gasFeeUsd: string, relayerFeeUsd: string, relayerFeePct: string) { + const gasFeePct = new BigNumber(gasFeeUsd).dividedBy(relayerFeeUsd).multipliedBy(relayerFeePct); + const capitalFeeUsd = new BigNumber(relayerFeeUsd).minus(gasFeeUsd); + const capitalFeePct = new BigNumber(relayerFeePct).minus(gasFeePct); + return { + gasFeeUsd, + gasFeePct: gasFeePct.toFixed(), + capitalFeeUsd: capitalFeeUsd.toFixed(), + capitalFeePct: capitalFeePct.toFixed(), + }; +} diff --git a/src/modules/scraper/adapter/db/deposit-fixture.ts b/src/modules/scraper/adapter/db/deposit-fixture.ts index c14c561d..6cd6e761 100644 --- a/src/modules/scraper/adapter/db/deposit-fixture.ts +++ b/src/modules/scraper/adapter/db/deposit-fixture.ts @@ -31,6 +31,7 @@ export function mockDepositEntity(overrides: Partial) { destinationChainId: 1, depositDate: new Date(), depositorAddr: "0x", + recipientAddr: "0x", status: "pending" as TransferStatus, amount: "0", filled: "0", diff --git a/src/modules/scraper/adapter/messaging/BlocksEventsConsumer.ts b/src/modules/scraper/adapter/messaging/BlocksEventsConsumer.ts index 2e4ef951..c144148f 100644 --- a/src/modules/scraper/adapter/messaging/BlocksEventsConsumer.ts +++ b/src/modules/scraper/adapter/messaging/BlocksEventsConsumer.ts @@ -73,6 +73,7 @@ export class BlocksEventsConsumer { fillAmount: e.args.fillAmount.toString(), transactionHash: e.transactionHash, appliedRelayerFeePct: e.args.appliedRelayerFeePct.toString(), + destinationToken: e.args.destinationToken, })); await this.scraperQueuesService.publishMessagesBulk(ScraperQueue.FillEvents, fillMessages); @@ -93,7 +94,8 @@ export class BlocksEventsConsumer { private async fromFundsDepositedEventToDeposit(event: FundsDepositedEvent) { const { transactionHash, blockNumber } = event; - const { depositId, originChainId, destinationChainId, amount, originToken, depositor, relayerFeePct } = event.args; + const { depositId, originChainId, destinationChainId, amount, originToken, depositor, relayerFeePct, recipient } = + event.args; return this.depositRepository.create({ depositId, @@ -107,6 +109,7 @@ export class BlocksEventsConsumer { fillTxs: [], blockNumber, depositorAddr: depositor, + recipientAddr: recipient, depositRelayerFeePct: relayerFeePct.toString(), initialRelayerFeePct: relayerFeePct.toString(), }); diff --git a/src/modules/scraper/adapter/messaging/FillEventsConsumer.ts b/src/modules/scraper/adapter/messaging/FillEventsConsumer.ts index c5f24d9c..4bbca40b 100644 --- a/src/modules/scraper/adapter/messaging/FillEventsConsumer.ts +++ b/src/modules/scraper/adapter/messaging/FillEventsConsumer.ts @@ -1,7 +1,13 @@ import { OnQueueFailed, Process, Processor } from "@nestjs/bull"; import { Logger } from "@nestjs/common"; import { Job } from "bull"; -import { BlocksEventsQueueMessage, DepositFilledDateQueueMessage, FillEventsQueueMessage, ScraperQueue } from "."; +import { + BlocksEventsQueueMessage, + DepositFilledDateQueueMessage, + FillEventsQueueMessage, + ScraperQueue, + TrackFillEventQueueMessage, +} from "."; import { InjectRepository } from "@nestjs/typeorm"; import { Deposit } from "../../model/deposit.entity"; import { LessThan, MoreThan, Repository } from "typeorm"; @@ -19,7 +25,7 @@ export class FillEventsConsumer { @Process() private async process(job: Job) { - const { depositId, originChainId } = job.data; + const { depositId, originChainId, destinationToken, transactionHash } = job.data; const deposit = await this.depositRepository.findOne({ where: { sourceChainId: originChainId, depositId } }); if (!deposit) { @@ -37,6 +43,11 @@ export class FillEventsConsumer { this.scraperQueuesService.publishMessage(ScraperQueue.DepositFilledDate, { depositId: deposit.id, }); + this.scraperQueuesService.publishMessage(ScraperQueue.TrackFillEvent, { + depositId: deposit.id, + destinationToken, + fillTxHash: transactionHash, + }); } public async processFillEventQueueMessage(deposit: Deposit, data: FillEventsQueueMessage) { diff --git a/src/modules/scraper/adapter/messaging/TrackFillEventConsumer.ts b/src/modules/scraper/adapter/messaging/TrackFillEventConsumer.ts new file mode 100644 index 00000000..5b059480 --- /dev/null +++ b/src/modules/scraper/adapter/messaging/TrackFillEventConsumer.ts @@ -0,0 +1,183 @@ +import { OnQueueFailed, Process, Processor } from "@nestjs/bull"; +import { Logger } from "@nestjs/common"; +import { Job } from "bull"; +import { InjectRepository } from "@nestjs/typeorm"; +import { Repository } from "typeorm"; +import { utils } from "ethers"; +import BigNumber from "bignumber.js"; +import { DateTime } from "luxon"; + +import { TrackFillEventQueueMessage, ScraperQueue } from "."; +import { Deposit } from "../../model/deposit.entity"; +import { TrackService } from "../amplitude/track-service"; +import { + deriveRelayerFeeComponents, + fixedPointAdjustment, + makeAmountValuesFormatter, + makeWeiPctValuesFormatter, +} from "../amplitude/utils"; +import { EthProvidersService } from "../../../web3/services/EthProvidersService"; +import { chainIdToInfo } from "../../../../utils"; +import { MarketPriceService } from "../../../market-price/services/service"; + +@Processor(ScraperQueue.TrackFillEvent) +export class TrackFillEventConsumer { + private logger = new Logger(TrackFillEventConsumer.name); + + constructor( + private providers: EthProvidersService, + private marketPriceService: MarketPriceService, + private trackService: TrackService, + @InjectRepository(Deposit) private depositRepository: Repository, + ) {} + + @Process() + private async process(job: Job) { + if (!this.trackService.isEnabled()) { + this.logger.verbose("Amplitude tracking is disabled"); + return; + } + + const { depositId, fillTxHash, destinationToken } = job.data; + const deposit = await this.depositRepository.findOne({ where: { id: depositId }, relations: ["token", "price"] }); + + if (!deposit) { + this.logger.verbose("Deposit not found in db"); + return; + } + + if (!deposit.token || !deposit.price || !deposit.depositDate) { + throw new Error("Can not track fill event without token, price or deposit date"); + } + + const fillTx = deposit.fillTxs.find((tx) => tx.hash === fillTxHash); + + if (!fillTx) { + throw new Error("Fill tx does not exist on deposit"); + } + + if (!fillTx.date) { + throw new Error("Fill tx does not have a date"); + } + + const destinationChainInfo = chainIdToInfo[deposit.destinationChainId] || { + name: "unknown", + chainId: deposit.destinationChainId, + nativeSymbol: "unknown", + }; + const sourceChainInfo = chainIdToInfo[deposit.sourceChainId] || { + name: "unknown", + chainId: deposit.sourceChainId, + nativeSymbol: "unknown", + }; + const depositTokenPriceUsd = deposit.price.usd; + + const { fee, feeUsd, fillTxBlockNumber } = await this.getFillTxNetworkFee(deposit.destinationChainId, fillTx.hash); + + const formatAmountValues = makeAmountValuesFormatter(deposit.token.decimals, depositTokenPriceUsd); + const fromAmounts = formatAmountValues(deposit.amount); + + const fillAmounts = formatAmountValues(fillTx.fillAmount); + const totalFilledAmounts = formatAmountValues(fillTx.totalFilledAmount); + + const formatWeiPctValues = makeWeiPctValuesFormatter(fromAmounts.formattedAmount, deposit.price.usd); + const formattedLpFeeValues = formatWeiPctValues(fillTx.realizedLpFeePct); + const formattedRelayFeeValues = formatWeiPctValues(fillTx.appliedRelayerFeePct); + const formattedBridgeFeeValues = formatWeiPctValues( + new BigNumber(fillTx.realizedLpFeePct).plus(fillTx.appliedRelayerFeePct).toString(), + ); + + const { gasFeePct, capitalFeeUsd, capitalFeePct } = deriveRelayerFeeComponents( + feeUsd, + formattedRelayFeeValues.totalUsd, + formattedRelayFeeValues.pct, + ); + + this.trackService.trackDepositFilledEvent(deposit.depositorAddr, { + capitalFeePct, + capitalFeeTotal: new BigNumber(capitalFeePct).dividedBy(100).multipliedBy(fromAmounts.formattedAmount).toFixed(), + capitalFeeTotalUsd: capitalFeeUsd, + fillAmount: fillAmounts.formattedAmount, + fillAmountUsd: fillAmounts.formattedAmountUsd, + fromAmount: fromAmounts.formattedAmount, + fromAmountUsd: fromAmounts.formattedAmountUsd, + fromChainId: String(deposit.sourceChainId), + fromChainName: sourceChainInfo.name, + fromTokenAddress: deposit.tokenAddr, + isAmountTooLow: false, + lpFeePct: formattedLpFeeValues.pct, + lpFeeTotal: formattedLpFeeValues.total, + lpFeeTotalUsd: formattedLpFeeValues.totalUsd, + NetworkFeeNative: fee, + NetworkFeeNativeToken: destinationChainInfo.nativeSymbol, + NetworkFeeUsd: feeUsd, + recipient: deposit.recipientAddr, + referralProgramAddress: deposit.referralAddress || "-", + relayFeePct: formattedRelayFeeValues.pct, + relayFeeTotal: formattedRelayFeeValues.total, + relayFeeTotalUsd: formattedRelayFeeValues.totalUsd, + relayGasFeePct: gasFeePct, + relayGasFeeTotal: new BigNumber(gasFeePct).dividedBy(100).multipliedBy(fromAmounts.formattedAmount).toFixed(), + relayGasFeeTotalUsd: feeUsd, + routeChainIdFromTo: `${deposit.sourceChainId}-${deposit.destinationChainId}`, + routeChainNameFromTo: `${sourceChainInfo.name}-${destinationChainInfo.name}`, + sender: deposit.depositorAddr, + succeeded: true, + timeFromTransferSignedToTransferCompleteInMilliseconds: String( + DateTime.fromISO(fillTx.date).diff(DateTime.fromJSDate(deposit.depositDate)).as("milliseconds"), + ), + toAmount: new BigNumber(fromAmounts.formattedAmount).minus(formattedBridgeFeeValues.total).toFixed(), + toAmountUsd: new BigNumber(fromAmounts.formattedAmountUsd) + .minus(formattedBridgeFeeValues.totalUsd) + .multipliedBy(depositTokenPriceUsd) + .toFixed(), + toChainId: String(deposit.destinationChainId), + toChainName: destinationChainInfo.name, + tokenSymbol: deposit.token.symbol, + totalBridgeFee: formattedBridgeFeeValues.total, + totalBridgeFeePct: formattedBridgeFeeValues.pct, + totalBridgeFeeUsd: formattedBridgeFeeValues.totalUsd, + totalFilledAmount: totalFilledAmounts.formattedAmount, + totalFilledAmountUsd: totalFilledAmounts.formattedAmountUsd, + toTokenAddress: utils.getAddress(destinationToken), + transactionHash: fillTx.hash, + transferCompleteTimestamp: String(DateTime.fromISO(fillTx.date).toMillis()), + transferQuoteBlockNumber: String(fillTxBlockNumber), + }); + } + + private async getFillTxNetworkFee(destinationChainId: number, fillTxHash: string) { + const destinationChainProvider = this.providers.getProvider(destinationChainId); + const destinationChainInfo = chainIdToInfo[destinationChainId]; + + if (!destinationChainProvider || !destinationChainInfo) { + return { + fillTxBlockNumber: 0, + fee: "0", + feeUsd: "0", + }; + } + + const fillTxReceipt = await destinationChainProvider.getTransactionReceipt(fillTxHash); + // Some chains, e.g. Optimism, do not return the effective gas price in the receipt. We need to fetch it separately. + const gasPrice = fillTxReceipt.effectiveGasPrice || (await destinationChainProvider.getGasPrice()); + const fillTxGasCostsWei = gasPrice.mul(fillTxReceipt.gasUsed).toString(); + const fillTxBlock = await this.providers.getCachedBlock(destinationChainId, fillTxReceipt.blockNumber); + const nativeTokenPriceUsd = await this.marketPriceService.getCachedHistoricMarketPrice( + fillTxBlock.date, + destinationChainInfo.nativeSymbol.toLowerCase(), + ); + const fee = new BigNumber(fillTxGasCostsWei).dividedBy(fixedPointAdjustment); + + return { + fillTxBlockNumber: fillTxBlock.blockNumber, + fee: fee.toFixed(), + feeUsd: fee.multipliedBy(nativeTokenPriceUsd.usd).toFixed(), + }; + } + + @OnQueueFailed() + private onQueueFailed(job: Job, error: Error) { + this.logger.error(`${ScraperQueue.TrackFillEvent} ${JSON.stringify(job.data)} failed: ${error}`); + } +} diff --git a/src/modules/scraper/adapter/messaging/index.ts b/src/modules/scraper/adapter/messaging/index.ts index 3193a82b..8d229156 100644 --- a/src/modules/scraper/adapter/messaging/index.ts +++ b/src/modules/scraper/adapter/messaging/index.ts @@ -10,6 +10,7 @@ export enum ScraperQueue { MerkleDistributorBlocksEvents = "MerkleDistributorBlocksEvents", DepositAcxPrice = "DepositAcxPrice", SuggestedFees = "SuggestedFees", + TrackFillEvent = "TrackFillEvent", } export type BlocksEventsQueueMessage = { @@ -32,6 +33,7 @@ export type FillEventsQueueMessage = { fillAmount: string; transactionHash: string; appliedRelayerFeePct: string; + destinationToken: string; }; export type SpeedUpEventsQueueMessage = { @@ -71,3 +73,9 @@ export type DepositAcxPriceQueueMessage = { export type SuggestedFeesQueueMessage = { depositId: number; }; + +export type TrackFillEventQueueMessage = { + depositId: number; + fillTxHash: string; + destinationToken: string; +}; diff --git a/src/modules/scraper/model/deposit.entity.ts b/src/modules/scraper/model/deposit.entity.ts index 8a540fd2..fa171c56 100644 --- a/src/modules/scraper/model/deposit.entity.ts +++ b/src/modules/scraper/model/deposit.entity.ts @@ -60,6 +60,9 @@ export class Deposit { @Column() depositorAddr: string; + @Column() + recipientAddr: string; + @Column({ default: "pending" }) status: TransferStatus; diff --git a/src/modules/scraper/module.ts b/src/modules/scraper/module.ts index 0dfe0f15..23614b4e 100644 --- a/src/modules/scraper/module.ts +++ b/src/modules/scraper/module.ts @@ -30,12 +30,15 @@ import { ScraperQueuesService } from "./service/ScraperQueuesService"; import { DepositAcxPriceConsumer } from "./adapter/messaging/DepositAcxPriceConsumer"; import { SuggestedFeesConsumer } from "./adapter/messaging/SuggestedFeesConsumer"; import { SuggestedFeesService } from "./adapter/across-serverless-api/suggested-fees-service"; +import { TrackFillEventConsumer } from "./adapter/messaging/TrackFillEventConsumer"; +import { TrackService } from "./adapter/amplitude/track-service"; @Module({ providers: [ ScraperService, ScraperQueuesService, SuggestedFeesService, + TrackService, BlocksEventsConsumer, MerkleDistributorBlocksEventsConsumer, FillEventsConsumer, @@ -47,6 +50,7 @@ import { SuggestedFeesService } from "./adapter/across-serverless-api/suggested- DepositFilledDateConsumer, DepositAcxPriceConsumer, SuggestedFeesConsumer, + TrackFillEventConsumer, DepositFixture, ClaimFixture, ], @@ -102,6 +106,9 @@ import { SuggestedFeesService } from "./adapter/across-serverless-api/suggested- BullModule.registerQueue({ name: ScraperQueue.SuggestedFees, }), + BullModule.registerQueue({ + name: ScraperQueue.TrackFillEvent, + }), ], exports: [ScraperQueuesService], controllers: [ScraperController], diff --git a/src/modules/scraper/service/ScraperQueuesService.ts b/src/modules/scraper/service/ScraperQueuesService.ts index 9b880787..19dea829 100644 --- a/src/modules/scraper/service/ScraperQueuesService.ts +++ b/src/modules/scraper/service/ScraperQueuesService.ts @@ -19,6 +19,7 @@ export class ScraperQueuesService { @InjectQueue(ScraperQueue.DepositFilledDate) private depositFilledDateQueue: Queue, @InjectQueue(ScraperQueue.DepositAcxPrice) private depositAcxPriceQueue: Queue, @InjectQueue(ScraperQueue.SuggestedFees) private suggestedFeesQueue: Queue, + @InjectQueue(ScraperQueue.TrackFillEvent) private trackFillEventsQueue: Queue, ) { setInterval(() => { this.blocksEventsQueue @@ -54,6 +55,9 @@ export class ScraperQueuesService { this.suggestedFeesQueue .getJobCounts() .then((data) => this.logger.log(`${ScraperQueue.SuggestedFees} ${JSON.stringify(data)}`)); + this.trackFillEventsQueue + .getJobCounts() + .then((data) => this.logger.log(`${ScraperQueue.TrackFillEvent} ${JSON.stringify(data)}`)); }, 1000 * 60); } @@ -80,6 +84,8 @@ export class ScraperQueuesService { await this.depositAcxPriceQueue.add(message); } else if (queue === ScraperQueue.SuggestedFees) { await this.suggestedFeesQueue.add(message); + } else if (queue === ScraperQueue.TrackFillEvent) { + await this.trackFillEventsQueue.add(message); } } @@ -106,6 +112,8 @@ export class ScraperQueuesService { await this.depositAcxPriceQueue.addBulk(messages.map((m) => ({ data: m }))); } else if (queue === ScraperQueue.SuggestedFees) { await this.suggestedFeesQueue.addBulk(messages.map((m) => ({ data: m }))); + } else if (queue === ScraperQueue.TrackFillEvent) { + await this.trackFillEventsQueue.addBulk(messages.map((m) => ({ data: m }))); } } } diff --git a/src/modules/web3/model/ChainId.ts b/src/modules/web3/model/ChainId.ts index 41e65b20..2d8ca3ee 100644 --- a/src/modules/web3/model/ChainId.ts +++ b/src/modules/web3/model/ChainId.ts @@ -14,6 +14,14 @@ export const ChainIds = { polygonMumbai: 80001, }; +export const ChainIdToName = Object.entries(ChainIds).reduce((idToName, entry) => { + const [name, id] = entry; + return { + ...idToName, + [id]: name, + }; +}, {} as Record); + export type Web3Error = { error: { code: Web3ErrorCode; diff --git a/src/utils.ts b/src/utils.ts index 652601c8..6483013b 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,5 +1,34 @@ import { applyDecorators } from "@nestjs/common"; import { Cron } from "@nestjs/schedule"; +import { ChainIds } from "./modules/web3/model/ChainId"; + +export const chainIdToInfo = { + [ChainIds.mainnet]: { + name: "Ethereum", + chainId: ChainIds.mainnet, + nativeSymbol: "eth", + }, + [ChainIds.arbitrum]: { + name: "Arbitrum", + chainId: ChainIds.arbitrum, + nativeSymbol: "eth", + }, + [ChainIds.boba]: { + name: "Boba", + chainId: ChainIds.boba, + nativeSymbol: "eth", + }, + [ChainIds.optimism]: { + name: "Optimism", + chainId: ChainIds.optimism, + nativeSymbol: "eth", + }, + [ChainIds.polygon]: { + name: "Polygon", + chainId: ChainIds.polygon, + nativeSymbol: "matic", + }, +}; export const wait = (seconds = 1) => new Promise((res) => { diff --git a/test/scraper.e2e-spec.ts b/test/scraper.e2e-spec.ts index 93d163ad..0717f37e 100644 --- a/test/scraper.e2e-spec.ts +++ b/test/scraper.e2e-spec.ts @@ -37,6 +37,7 @@ describe("Scraper module", () => { realizedLpFeePct: "0", totalFilledAmount: "0", transactionHash: "0x", + destinationToken: "0x", }; deposit = await app.get(FillEventsConsumer).processFillEventQueueMessage(deposit, fillEventMessage); const isFillTxAlreadyProcessed = app.get(FillEventsConsumer).fillTxAlreadyProcessed(deposit, fillEventMessage); diff --git a/yarn.lock b/yarn.lock index b517853f..25990b8a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -26,6 +26,117 @@ "@openzeppelin/contracts" "4.1.0" "@uma/core" "^2.18.0" +"@amplitude/ampli@^1.28.0": + version "1.28.0" + resolved "https://registry.yarnpkg.com/@amplitude/ampli/-/ampli-1.28.0.tgz#df068e5815e4fbfa622b43833b1c7ee67bf9d24e" + integrity sha512-b83aRm/vtcJu9v2gGzCpv5K+DlKUHaGUCYSObnku3VVnGy79aCFVeiVziQ0iF5eR0Xp9FUFAZ+ldrX8dDlC0Hg== + dependencies: + "@amplitude/identify" "^1.10.0" + "@amplitude/node" "^1.10.0" + "@amplitude/types" "^1.10.0" + "@babel/parser" "^7.12.11" + "@babel/traverse" "^7.12.12" + "@oclif/command" "^1.6.1" + "@oclif/config" "^1.15.1" + "@oclif/errors" "^1.2.2" + "@oclif/parser" "^3.8.3" + "@oclif/plugin-autocomplete" "^0.3.0" + "@oclif/plugin-help" "^3.2.2" + "@oclif/plugin-update" "^1.3.10" + "@oclif/plugin-warn-if-update-available" "^1.7.0" + "@phenomnomnominal/tsquery" "^3.0.0" + "@sentry/node" "^6.2.5" + "@sentry/types" "^6.2.5" + "@types/debug" "^4.1.5" + "@types/inquirer" "^8.2.4" + ansi-regex "^5.0.1" + antlr4ts "^0.5.0-alpha.4" + chalk "^2.4.2" + client-oauth2 "^4.3.3" + conf "^6.2.0" + debug "^4.1.1" + dotenv "^8.2.0" + fs-extra "^8.1.0" + get-port "^5.0.0" + globby "^10.0.1" + graphql "^15.4.0" + graphql-request "^3.3.0" + graphql-tag "^2.11.0" + https-proxy-agent "^5.0.1" + ignore-walk "^3.0.3" + inquirer "^8.2.4" + inquirer-autocomplete-prompt "^2.0.0" + json5 "^2.1.1" + lodash "^4.17.21" + minimatch "^3.0.4" + node-fetch "^2.6.1" + open "^7.3.1" + ora "^4.1.1" + php-parser "^3.0.0-prerelease.8" + pkce-challenge "^2.2.0" + randomstring "^1.1.5" + rimraf "^3.0.2" + stoppable "^1.1.0" + tmp "^0.2.1" + tslib "^1.14.1" + typescript "^3.9.7" + uuid "^9.0.0" + vue-parser "^1.1.6" + +"@amplitude/analytics-core@^0.11.1": + version "0.11.1" + resolved "https://registry.yarnpkg.com/@amplitude/analytics-core/-/analytics-core-0.11.1.tgz#faa801c1566dff9136091d6c9171b23ce4e18ef9" + integrity sha512-G+GgYFwxhD5DjYDKuC6jRcsO/kqJw4hLTlJ0x2mwppxVuMqQ44wRvdQ1hhzMRY02AGnmr0OR1xDtft8CabiIag== + dependencies: + "@amplitude/analytics-types" "^0.14.0" + tslib "^2.4.1" + +"@amplitude/analytics-node@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@amplitude/analytics-node/-/analytics-node-1.0.1.tgz#1e80222173ef36eb989f98f5c757dc599dc9091f" + integrity sha512-NrimUadF3+0P0MedkRzmu7bXi8cECnLIRWiO561jWndwL3RE/yDSJVN2W+wAVHJk7VyHfMS4ty/R0s71otIBzQ== + dependencies: + "@amplitude/analytics-core" "^0.11.1" + "@amplitude/analytics-types" "^0.14.0" + tslib "^2.4.1" + +"@amplitude/analytics-types@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@amplitude/analytics-types/-/analytics-types-0.14.0.tgz#06848235e52fe1d46a6e04bbc5d14090bdde15e3" + integrity sha512-O3E/KHyWCb4HAlYevqgCzqQdS+0LhbJV2IeVGox2eyCge+/lGwtGdJV2rJNWcoGf3p+BhnbqJBlhkPMs12iniA== + +"@amplitude/identify@^1.10.0", "@amplitude/identify@^1.10.2": + version "1.10.2" + resolved "https://registry.yarnpkg.com/@amplitude/identify/-/identify-1.10.2.tgz#25d88f9e3bedd99701c777b9e44408ac69179aa1" + integrity sha512-ywxeabS8ukMdJWNwx3rG/EBngXFg/4NsPhlyAxbBUcI7HzBXEJUKepiZfkz8K6Y7f0mpc23Qz1aBf48ZJDZmkQ== + dependencies: + "@amplitude/types" "^1.10.2" + "@amplitude/utils" "^1.10.2" + tslib "^2.0.0" + +"@amplitude/node@^1.10.0": + version "1.10.2" + resolved "https://registry.yarnpkg.com/@amplitude/node/-/node-1.10.2.tgz#79fb80e7228486521156eae510de998264e6620c" + integrity sha512-E3xp8DOpkF5ThjrRlAmSocnrEYsTPpd3Zg4WdBLms0ackQSgQpw6z84+YMcoPerZHJJ/LEqdo4Cg4Z5Za3D+3Q== + dependencies: + "@amplitude/identify" "^1.10.2" + "@amplitude/types" "^1.10.2" + "@amplitude/utils" "^1.10.2" + tslib "^2.0.0" + +"@amplitude/types@^1.10.0", "@amplitude/types@^1.10.2": + version "1.10.2" + resolved "https://registry.yarnpkg.com/@amplitude/types/-/types-1.10.2.tgz#8f3c6c3c9ee24f401ee037b351c3c67eb945eefc" + integrity sha512-I8qenRI7uU6wKNb9LiZrAosSHVoNHziXouKY81CrqxH9xhVTEIJFXeuCV0hbtBr0Al/8ejnGjQRx+S2SvU/pPg== + +"@amplitude/utils@^1.10.2": + version "1.10.2" + resolved "https://registry.yarnpkg.com/@amplitude/utils/-/utils-1.10.2.tgz#ce77dc8a54fcd3843511531cc7d56363247c7ad8" + integrity sha512-tVsHXu61jITEtRjB7NugQ5cVDd4QDzne8T3ifmZye7TiJeUfVRvqe44gDtf55A+7VqhDhyEIIXTA1iVcDGqlEw== + dependencies: + "@amplitude/types" "^1.10.2" + tslib "^2.0.0" + "@ampproject/remapping@^2.1.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" @@ -99,6 +210,13 @@ dependencies: "@babel/highlight" "^7.16.7" +"@babel/code-frame@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== + dependencies: + "@babel/highlight" "^7.18.6" + "@babel/compat-data@^7.13.11", "@babel/compat-data@^7.17.10": version "7.18.5" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.5.tgz#acac0c839e317038c73137fbb6ef71a1d6238471" @@ -134,6 +252,15 @@ "@jridgewell/gen-mapping" "^0.3.0" jsesc "^2.5.1" +"@babel/generator@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.7.tgz#f8ef57c8242665c5929fe2e8d82ba75460187b4a" + integrity sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw== + dependencies: + "@babel/types" "^7.20.7" + "@jridgewell/gen-mapping" "^0.3.2" + jsesc "^2.5.1" + "@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.18.2": version "7.18.2" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz#67a85a10cbd5fc7f1457fec2e7f45441dc6c754b" @@ -163,6 +290,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz#8a6d2dedb53f6bf248e31b4baf38739ee4a637bd" integrity sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ== +"@babel/helper-environment-visitor@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" + integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== + "@babel/helper-function-name@^7.17.9": version "7.17.9" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz#136fcd54bc1da82fcb47565cf16fd8e444b1ff12" @@ -171,6 +303,14 @@ "@babel/template" "^7.16.7" "@babel/types" "^7.17.0" +"@babel/helper-function-name@^7.19.0": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz#941574ed5390682e872e52d3f38ce9d1bef4648c" + integrity sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w== + dependencies: + "@babel/template" "^7.18.10" + "@babel/types" "^7.19.0" + "@babel/helper-hoist-variables@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" @@ -178,6 +318,13 @@ dependencies: "@babel/types" "^7.16.7" +"@babel/helper-hoist-variables@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== + dependencies: + "@babel/types" "^7.18.6" + "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" @@ -218,11 +365,28 @@ dependencies: "@babel/types" "^7.16.7" +"@babel/helper-split-export-declaration@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-string-parser@^7.19.4": + version "7.19.4" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63" + integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== + "@babel/helper-validator-identifier@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== +"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" + integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== + "@babel/helper-validator-option@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" @@ -246,11 +410,25 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + chalk "^2.0.0" + js-tokens "^4.0.0" + "@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.18.5": version "7.18.5" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.5.tgz#337062363436a893a2d22faa60be5bb37091c83c" integrity sha512-YZWVaglMiplo7v8f1oMQ5ZPQr0vn7HPeZXxXWsxXJRjGVrzUFn9OxFQl1sb5wzfootjA/yChhW84BV+383FSOw== +"@babel/parser@^7.12.11", "@babel/parser@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.7.tgz#66fe23b3c8569220817d5feb8b9dcdc95bb4f71b" + integrity sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg== + "@babel/parser@^7.9.4": version "7.20.0" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.0.tgz#b26133c888da4d79b0d3edcf42677bcadc783046" @@ -383,6 +561,31 @@ "@babel/parser" "^7.16.7" "@babel/types" "^7.16.7" +"@babel/template@^7.18.10": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8" + integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + +"@babel/traverse@^7.12.12": + version "7.20.10" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.10.tgz#2bf98239597fcec12f842756f186a9dde6d09230" + integrity sha512-oSf1juCgymrSez8NI4A2sr4+uB/mFd9MXplYGPEBnfAuWmmyeVcHa6xLPiaRBcXkcb/28bgxmQLTVwFKE1yfsg== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.20.7" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.19.0" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + debug "^4.1.0" + globals "^11.1.0" + "@babel/traverse@^7.13.0", "@babel/traverse@^7.18.0", "@babel/traverse@^7.18.2", "@babel/traverse@^7.18.5", "@babel/traverse@^7.7.2": version "7.18.5" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.5.tgz#94a8195ad9642801837988ab77f36e992d9a20cd" @@ -407,6 +610,15 @@ "@babel/helper-validator-identifier" "^7.16.7" to-fast-properties "^2.0.0" +"@babel/types@^7.18.6", "@babel/types@^7.19.0", "@babel/types@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.7.tgz#54ec75e252318423fc07fb644dc6a58a64c09b7f" + integrity sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg== + dependencies: + "@babel/helper-string-parser" "^7.19.4" + "@babel/helper-validator-identifier" "^7.19.1" + to-fast-properties "^2.0.0" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -2007,6 +2219,15 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" +"@jridgewell/gen-mapping@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + "@jridgewell/resolve-uri@^3.0.3": version "3.0.7" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz#30cd49820a962aff48c8fffc5cd760151fca61fe" @@ -2017,6 +2238,11 @@ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.1.tgz#36a6acc93987adcf0ba50c66908bd0b70de8afea" integrity sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ== +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + "@jridgewell/source-map@^0.3.2": version "0.3.2" resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" @@ -2418,6 +2644,176 @@ consola "^2.15.0" node-fetch "^2.6.1" +"@oclif/color@^0.1.0": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@oclif/color/-/color-0.1.2.tgz#28b07e2850d9ce814d0b587ce3403b7ad8f7d987" + integrity sha512-M9o+DOrb8l603qvgz1FogJBUGLqcMFL1aFg2ZEL0FbXJofiNTLOWIeB4faeZTLwE6dt0xH9GpCVpzksMMzGbmA== + dependencies: + ansi-styles "^3.2.1" + chalk "^3.0.0" + strip-ansi "^5.2.0" + supports-color "^5.4.0" + tslib "^1" + +"@oclif/command@^1.5.13", "@oclif/command@^1.6.1", "@oclif/command@^1.7.0", "@oclif/command@^1.8.15", "@oclif/command@^1.8.6": + version "1.8.20" + resolved "https://registry.yarnpkg.com/@oclif/command/-/command-1.8.20.tgz#7e28387be8744145e1b2ee7db89275bc7f708f2f" + integrity sha512-BHM9byujY0kf0PiRorIyp99K50cA3i6Hyro0+TPpFFx+4QM+PyQ5vMHO/TG5wkEP8tIivNRs24bF8QVyJru25g== + dependencies: + "@oclif/config" "^1.18.2" + "@oclif/errors" "^1.3.6" + "@oclif/help" "^1.0.1" + "@oclif/parser" "^3.8.9" + debug "^4.1.1" + semver "^7.3.8" + +"@oclif/config@1.18.2": + version "1.18.2" + resolved "https://registry.yarnpkg.com/@oclif/config/-/config-1.18.2.tgz#5bfe74a9ba6a8ca3dceb314a81bd9ce2e15ebbfe" + integrity sha512-cE3qfHWv8hGRCP31j7fIS7BfCflm/BNZ2HNqHexH+fDrdF2f1D5S8VmXWLC77ffv3oDvWyvE9AZeR0RfmHCCaA== + dependencies: + "@oclif/errors" "^1.3.3" + "@oclif/parser" "^3.8.0" + debug "^4.1.1" + globby "^11.0.1" + is-wsl "^2.1.1" + tslib "^2.0.0" + +"@oclif/config@1.18.6", "@oclif/config@^1.13.0", "@oclif/config@^1.15.1", "@oclif/config@^1.16.0", "@oclif/config@^1.17.1", "@oclif/config@^1.18.2": + version "1.18.6" + resolved "https://registry.yarnpkg.com/@oclif/config/-/config-1.18.6.tgz#37367026b3110a2f04875509b1920a8ee4489f21" + integrity sha512-OWhCpdu4QqggOPX1YPZ4XVmLLRX+lhGjXV6RNA7sogOwLqlEmSslnN/lhR5dkhcWZbKWBQH29YCrB3LDPRu/IA== + dependencies: + "@oclif/errors" "^1.3.6" + "@oclif/parser" "^3.8.9" + debug "^4.3.4" + globby "^11.1.0" + is-wsl "^2.1.1" + tslib "^2.3.1" + +"@oclif/errors@1.3.5": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@oclif/errors/-/errors-1.3.5.tgz#a1e9694dbeccab10fe2fe15acb7113991bed636c" + integrity sha512-OivucXPH/eLLlOT7FkCMoZXiaVYf8I/w1eTAM1+gKzfhALwWTusxEx7wBmW0uzvkSg/9ovWLycPaBgJbM3LOCQ== + dependencies: + clean-stack "^3.0.0" + fs-extra "^8.1" + indent-string "^4.0.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +"@oclif/errors@1.3.6", "@oclif/errors@^1.2.2", "@oclif/errors@^1.3.3", "@oclif/errors@^1.3.4", "@oclif/errors@^1.3.5", "@oclif/errors@^1.3.6": + version "1.3.6" + resolved "https://registry.yarnpkg.com/@oclif/errors/-/errors-1.3.6.tgz#e8fe1fc12346cb77c4f274e26891964f5175f75d" + integrity sha512-fYaU4aDceETd89KXP+3cLyg9EHZsLD3RxF2IU9yxahhBpspWjkWi3Dy3bTgcwZ3V47BgxQaGapzJWDM33XIVDQ== + dependencies: + clean-stack "^3.0.0" + fs-extra "^8.1" + indent-string "^4.0.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +"@oclif/help@^1.0.1": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@oclif/help/-/help-1.0.4.tgz#0c7cfd776e3cbe033cab023486ed929be0cd1c77" + integrity sha512-w3xsdZj1af/dFN7oCmvAHbHRj6L0SOO5uGXEve0LLroAJSM3DeEpzgNMjxS5RTV2gVC4RmJ/rTqmp0SRaXGiTA== + dependencies: + "@oclif/config" "1.18.6" + "@oclif/errors" "1.3.6" + chalk "^4.1.2" + indent-string "^4.0.0" + lodash "^4.17.21" + string-width "^4.2.0" + strip-ansi "^6.0.0" + widest-line "^3.1.0" + wrap-ansi "^6.2.0" + +"@oclif/linewrap@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@oclif/linewrap/-/linewrap-1.0.0.tgz#aedcb64b479d4db7be24196384897b5000901d91" + integrity sha512-Ups2dShK52xXa8w6iBWLgcjPJWjais6KPJQq3gQ/88AY6BXoTX+MIGFPrWQO1KLMiQfoTpcLnUwloN4brrVUHw== + +"@oclif/parser@^3.8.0", "@oclif/parser@^3.8.3", "@oclif/parser@^3.8.9": + version "3.8.9" + resolved "https://registry.yarnpkg.com/@oclif/parser/-/parser-3.8.9.tgz#9399041ada7e465043f34b24f4d82a8beb68a023" + integrity sha512-1j/kThdse7yHQz6+c3v8RA1I3gD6+SGt2O7IAb/MAMoxqyBrFQDabQHH2UU4eVFGMLN7U91AiYJp11zJ9LcQAg== + dependencies: + "@oclif/errors" "^1.3.6" + "@oclif/linewrap" "^1.0.0" + chalk "^4.1.0" + tslib "^2.4.1" + +"@oclif/plugin-autocomplete@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@oclif/plugin-autocomplete/-/plugin-autocomplete-0.3.0.tgz#eec788596a88a4ca5170a9103b6c2835119a8fbd" + integrity sha512-gCuIUCswvoU1BxDDvHSUGxW8rFagiacle8jHqE49+WnuniXD/N8NmJvnzmlNyc8qLE192CnKK+qYyAF+vaFQBg== + dependencies: + "@oclif/command" "^1.5.13" + "@oclif/config" "^1.13.0" + chalk "^4.1.0" + cli-ux "^5.2.1" + debug "^4.0.0" + fs-extra "^9.0.1" + moment "^2.22.1" + +"@oclif/plugin-help@^3.2.2": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@oclif/plugin-help/-/plugin-help-3.3.1.tgz#36adb4e0173f741df409bb4b69036d24a53bfb24" + integrity sha512-QuSiseNRJygaqAdABYFWn/H1CwIZCp9zp/PLid6yXvy6VcQV7OenEFF5XuYaCvSARe2Tg9r8Jqls5+fw1A9CbQ== + dependencies: + "@oclif/command" "^1.8.15" + "@oclif/config" "1.18.2" + "@oclif/errors" "1.3.5" + "@oclif/help" "^1.0.1" + chalk "^4.1.2" + indent-string "^4.0.0" + lodash "^4.17.21" + string-width "^4.2.0" + strip-ansi "^6.0.0" + widest-line "^3.1.0" + wrap-ansi "^6.2.0" + +"@oclif/plugin-update@^1.3.10": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@oclif/plugin-update/-/plugin-update-1.5.0.tgz#a9e0092a9b7ae01e54708938e2a424903f5079ef" + integrity sha512-GsWK1CMeBBO8YknThoOZulj3xE+ZgZAXW1ouNJALXcs3mbROzszLDGjXV3RM6ffbJpnWLiMIqSFNOE8d+vGcgQ== + dependencies: + "@oclif/color" "^0.1.0" + "@oclif/command" "^1.7.0" + "@oclif/config" "^1.16.0" + "@oclif/errors" "^1.3.4" + "@types/semver" "^7.3.4" + cli-ux "^5.5.1" + cross-spawn "^7.0.3" + debug "^4.3.1" + filesize "^6.1.0" + fs-extra "^9.0.1" + http-call "^5.3.0" + lodash "^4.17.21" + log-chopper "^1.0.2" + semver "^7.3.5" + tar-fs "^2.1.1" + +"@oclif/plugin-warn-if-update-available@^1.7.0": + version "1.7.3" + resolved "https://registry.yarnpkg.com/@oclif/plugin-warn-if-update-available/-/plugin-warn-if-update-available-1.7.3.tgz#efe6676655fabbed2e90cc9e646e9da4c99bc8ae" + integrity sha512-q8q0NIneVCwIAJzglUMsl3EbXR/H5aPDk6g+qs7uF0tToxe07SWSONoNaKPzViwRWvYChMPjL77/rXyW1HVn4A== + dependencies: + "@oclif/command" "^1.8.6" + "@oclif/config" "^1.17.1" + "@oclif/errors" "^1.3.5" + chalk "^4.1.0" + debug "^4.1.0" + fs-extra "^9.0.1" + http-call "^5.2.2" + lodash "^4.17.21" + semver "^7.3.2" + +"@oclif/screen@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@oclif/screen/-/screen-1.0.4.tgz#b740f68609dfae8aa71c3a6cab15d816407ba493" + integrity sha512-60CHpq+eqnTxLZQ4PGHYNwUX572hgpMHGPtTWMjdTMsAvlm69lZV/4ly6O3sAYkomo4NggGcomrDpBe34rxUqw== + "@openzeppelin/contracts-0.8@npm:@openzeppelin/contracts@^4.3.2", "@openzeppelin/contracts@^4.2.0", "@openzeppelin/contracts@^4.3.2": name "@openzeppelin/contracts-0.8" version "4.6.0" @@ -2473,6 +2869,13 @@ proper-lockfile "^4.1.1" solidity-ast "^0.4.15" +"@phenomnomnominal/tsquery@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@phenomnomnominal/tsquery/-/tsquery-3.0.0.tgz#6f2f4dbf6304ff52b12cc7a5b979f20c3794a22a" + integrity sha512-SW8lKitBHWJ9fAYkJ9kJivuctwNYCh3BUxLdH0+XiR1GPBiu+7qiZzh8p8jqlj1LgVC1TbvfNFroaEsmYlL8Iw== + dependencies: + esquery "^1.0.1" + "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" @@ -2559,6 +2962,17 @@ "@sentry/utils" "5.30.0" tslib "^1.9.3" +"@sentry/core@6.19.7": + version "6.19.7" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.19.7.tgz#156aaa56dd7fad8c89c145be6ad7a4f7209f9785" + integrity sha512-tOfZ/umqB2AcHPGbIrsFLcvApdTm9ggpi/kQZFkej7kMphjT+SGBiQfYtjyg9jcRW+ilAR4JXC9BGKsdEQ+8Vw== + dependencies: + "@sentry/hub" "6.19.7" + "@sentry/minimal" "6.19.7" + "@sentry/types" "6.19.7" + "@sentry/utils" "6.19.7" + tslib "^1.9.3" + "@sentry/hub@5.30.0": version "5.30.0" resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.30.0.tgz#2453be9b9cb903404366e198bd30c7ca74cdc100" @@ -2568,6 +2982,15 @@ "@sentry/utils" "5.30.0" tslib "^1.9.3" +"@sentry/hub@6.19.7": + version "6.19.7" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.19.7.tgz#58ad7776bbd31e9596a8ec46365b45cd8b9cfd11" + integrity sha512-y3OtbYFAqKHCWezF0EGGr5lcyI2KbaXW2Ik7Xp8Mu9TxbSTuwTe4rTntwg8ngPjUQU3SUHzgjqVB8qjiGqFXCA== + dependencies: + "@sentry/types" "6.19.7" + "@sentry/utils" "6.19.7" + tslib "^1.9.3" + "@sentry/minimal@5.30.0": version "5.30.0" resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.30.0.tgz#ce3d3a6a273428e0084adcb800bc12e72d34637b" @@ -2577,6 +3000,15 @@ "@sentry/types" "5.30.0" tslib "^1.9.3" +"@sentry/minimal@6.19.7": + version "6.19.7" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.19.7.tgz#b3ee46d6abef9ef3dd4837ebcb6bdfd01b9aa7b4" + integrity sha512-wcYmSJOdvk6VAPx8IcmZgN08XTXRwRtB1aOLZm+MVHjIZIhHoBGZJYTVQS/BWjldsamj2cX3YGbGXNunaCfYJQ== + dependencies: + "@sentry/hub" "6.19.7" + "@sentry/types" "6.19.7" + tslib "^1.9.3" + "@sentry/node@^5.18.1": version "5.30.0" resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.30.0.tgz#4ca479e799b1021285d7fe12ac0858951c11cd48" @@ -2592,6 +3024,20 @@ lru_map "^0.3.3" tslib "^1.9.3" +"@sentry/node@^6.2.5": + version "6.19.7" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.19.7.tgz#32963b36b48daebbd559e6f13b1deb2415448592" + integrity sha512-gtmRC4dAXKODMpHXKfrkfvyBL3cI8y64vEi3fDD046uqYcrWdgoQsffuBbxMAizc6Ez1ia+f0Flue6p15Qaltg== + dependencies: + "@sentry/core" "6.19.7" + "@sentry/hub" "6.19.7" + "@sentry/types" "6.19.7" + "@sentry/utils" "6.19.7" + cookie "^0.4.1" + https-proxy-agent "^5.0.0" + lru_map "^0.3.3" + tslib "^1.9.3" + "@sentry/tracing@5.30.0": version "5.30.0" resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-5.30.0.tgz#501d21f00c3f3be7f7635d8710da70d9419d4e1f" @@ -2608,6 +3054,11 @@ resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.30.0.tgz#19709bbe12a1a0115bc790b8942917da5636f402" integrity sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw== +"@sentry/types@6.19.7", "@sentry/types@^6.2.5": + version "6.19.7" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.19.7.tgz#c6b337912e588083fc2896eb012526cf7cfec7c7" + integrity sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg== + "@sentry/utils@5.30.0": version "5.30.0" resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.30.0.tgz#9a5bd7ccff85ccfe7856d493bffa64cabc41e980" @@ -2616,6 +3067,19 @@ "@sentry/types" "5.30.0" tslib "^1.9.3" +"@sentry/utils@6.19.7": + version "6.19.7" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.19.7.tgz#6edd739f8185fd71afe49cbe351c1bbf5e7b7c79" + integrity sha512-z95ECmE3i9pbWoXQrD/7PgkBAzJYR+iXtPuTkpBjDKs86O3mT+PXOT3BAn79w2wkn7/i3vOGD2xVr1uiMl26dA== + dependencies: + "@sentry/types" "6.19.7" + tslib "^1.9.3" + +"@servie/events@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@servie/events/-/events-1.0.0.tgz#8258684b52d418ab7b86533e861186638ecc5dc1" + integrity sha512-sBSO19KzdrJCM3gdx6eIxV8M9Gxfgg6iDQmH5TIAGaUu+X9VDdsINXJOnoiZ1Kx3TrHdH4bt5UVglkjsEGBcvw== + "@sindresorhus/is@^0.14.0": version "0.14.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" @@ -3015,6 +3479,13 @@ "@types/luxon" "*" "@types/node" "*" +"@types/debug@^4.1.5": + version "4.1.7" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.7.tgz#7cc0ea761509124709b8b2d1090d8f6c17aadb82" + integrity sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg== + dependencies: + "@types/ms" "*" + "@types/eslint-scope@^3.7.3": version "3.7.3" resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.3.tgz#125b88504b61e3c8bc6f870882003253005c3224" @@ -3094,6 +3565,13 @@ dependencies: "@types/node" "*" +"@types/inquirer@^8.2.4": + version "8.2.5" + resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-8.2.5.tgz#c508423bcc11126db278170ab07347783ac2300c" + integrity sha512-QXlzybid60YtAwfgG3cpykptRYUx2KomzNutMlWsQC64J/WG/gQSl+P4w7A21sGN0VIxRVava4rgnT7FQmFCdg== + dependencies: + "@types/through" "*" + "@types/ioredis@*": version "4.28.10" resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.28.10.tgz#40ceb157a4141088d1394bb87c98ed09a75a06ff" @@ -3214,6 +3692,11 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== +"@types/ms@*": + version "0.7.31" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" + integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== + "@types/multer@^1.4.7": version "1.4.7" resolved "https://registry.yarnpkg.com/@types/multer/-/multer-1.4.7.tgz#89cf03547c28c7bbcc726f029e2a76a7232cc79e" @@ -3339,6 +3822,11 @@ dependencies: "@types/node" "*" +"@types/semver@^7.3.4": + version "7.3.13" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" + integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== + "@types/serve-static@*": version "1.13.10" resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9" @@ -3367,6 +3855,18 @@ dependencies: "@types/superagent" "*" +"@types/through@*": + version "0.0.30" + resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.30.tgz#e0e42ce77e897bd6aead6f6ea62aeb135b8a3895" + integrity sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg== + dependencies: + "@types/node" "*" + +"@types/tough-cookie@^2.3.5": + version "2.3.8" + resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-2.3.8.tgz#511fc1569cc32b0cf50941fe9f00bf70f94116bb" + integrity sha512-7axfYN8SW9pWg78NgenHasSproWQee5rzyPVLC9HpaQSDgNArsnKJD88EaMfi4Pl48AyciO3agYCFqpHS1gLpg== + "@types/uuid@^8.3.4": version "8.3.4" resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" @@ -4015,7 +4515,7 @@ ajv@8.9.0: require-from-string "^2.0.2" uri-js "^4.2.2" -ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: +ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -4055,7 +4555,12 @@ ansi-colors@^4.1.1: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== -ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: +ansi-escapes@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== + +ansi-escapes@^4.2.1, ansi-escapes@^4.3.0, ansi-escapes@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== @@ -4094,7 +4599,7 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.0.0, ansi-styles@^4.1.0: +ansi-styles@^4.0.0, ansi-styles@^4.1.0, ansi-styles@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== @@ -4106,6 +4611,11 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== +ansicolors@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" + integrity sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg== + antlr4ts@^0.5.0-alpha.4: version "0.5.0-alpha.4" resolved "https://registry.yarnpkg.com/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz#71702865a87478ed0b40c0709f422cf14d51652a" @@ -4228,6 +4738,11 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== +array-uniq@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.2.tgz#5fcc373920775723cfd64d65c64bef53bf9eba6d" + integrity sha512-GVYjmpL05al4dNlKJm53mKE4w9OOLiuVHWorsIA3YVz+Hu0hcn6PtE3Ydl0EqU7v+7ABC4mjjWsnLUxbpno+CA== + array-uniq@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" @@ -4342,6 +4857,11 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + available-typed-arrays@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" @@ -5379,6 +5899,16 @@ busboy@^1.0.0: dependencies: streamsearch "^1.1.0" +byline@5.x: + version "5.0.0" + resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" + integrity sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q== + +byte-length@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/byte-length/-/byte-length-1.0.2.tgz#ba5a5909240b0121c079b7f7b15248d6f08223cc" + integrity sha512-ovBpjmsgd/teRmgcPh23d4gJvxDoXtAzEL9xTfMU8Yc2kqCDb7L9jAG0XHl1nzuGl+h3ebCIF1i62UFyA9V/2Q== + bytes@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" @@ -5452,6 +5982,14 @@ caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30001358: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001359.tgz#a1c1cbe1c2da9e689638813618b4219acbd4925e" integrity sha512-Xln/BAsPzEuiVLgJ2/45IaqD9jShtk3Y33anKb4+yLwQzws3+v6odKfpgES/cDEaZMLzSChpIGdbOYtH9MyuHw== +cardinal@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-2.1.1.tgz#7cc1055d822d212954d07b085dea251cc7bc5505" + integrity sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw== + dependencies: + ansicolors "~0.3.2" + redeyed "~2.1.0" + caseless@^0.12.0, caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" @@ -5735,6 +6273,13 @@ clean-stack@^2.0.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== +clean-stack@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-3.0.1.tgz#155bf0b2221bf5f4fba89528d24c5953f17fe3a8" + integrity sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg== + dependencies: + escape-string-regexp "4.0.0" + cli-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" @@ -5754,6 +6299,18 @@ cli-highlight@^2.1.11: parse5-htmlparser2-tree-adapter "^6.0.0" yargs "^16.0.0" +cli-progress@^3.4.0: + version "3.11.2" + resolved "https://registry.yarnpkg.com/cli-progress/-/cli-progress-3.11.2.tgz#f8c89bd157e74f3f2c43bcfb3505670b4d48fc77" + integrity sha512-lCPoS6ncgX4+rJu5bS3F/iCz17kZ9MPZ6dpuTtI0KXKABkhyXIdYB3Inby1OpaGti3YlI3EeEkM9AuWpelJrVA== + dependencies: + string-width "^4.2.3" + +cli-spinners@^2.2.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.7.0.tgz#f815fd30b5f9eaac02db604c7a231ed7cb2f797a" + integrity sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw== + cli-spinners@^2.5.0: version "2.6.1" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" @@ -5778,11 +6335,51 @@ cli-table3@^0.5.0: optionalDependencies: colors "^1.1.2" +cli-ux@^5.2.1, cli-ux@^5.5.1: + version "5.6.7" + resolved "https://registry.yarnpkg.com/cli-ux/-/cli-ux-5.6.7.tgz#32ef9e6cb2b457be834280cc799028a11c8235a8" + integrity sha512-dsKAurMNyFDnO6X1TiiRNiVbL90XReLKcvIq4H777NMqXGBxBws23ag8ubCJE97vVZEgWG2eSUhsyLf63Jv8+g== + dependencies: + "@oclif/command" "^1.8.15" + "@oclif/errors" "^1.3.5" + "@oclif/linewrap" "^1.0.0" + "@oclif/screen" "^1.0.4" + ansi-escapes "^4.3.0" + ansi-styles "^4.2.0" + cardinal "^2.1.1" + chalk "^4.1.0" + clean-stack "^3.0.0" + cli-progress "^3.4.0" + extract-stack "^2.0.0" + fs-extra "^8.1" + hyperlinker "^1.0.0" + indent-string "^4.0.0" + is-wsl "^2.2.0" + js-yaml "^3.13.1" + lodash "^4.17.21" + natural-orderby "^2.0.1" + object-treeify "^1.1.4" + password-prompt "^1.1.2" + semver "^7.3.2" + string-width "^4.2.0" + strip-ansi "^6.0.0" + supports-color "^8.1.0" + supports-hyperlinks "^2.1.0" + tslib "^2.0.0" + cli-width@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== +client-oauth2@^4.3.3: + version "4.3.3" + resolved "https://registry.yarnpkg.com/client-oauth2/-/client-oauth2-4.3.3.tgz#7a700e6f4bf412c1f96da0d6b50e07676561e086" + integrity sha512-k8AvUYJon0vv75ufoVo4nALYb/qwFFicO3I0+39C6xEdflqVtr+f9cy+0ZxAduoVSTfhP5DX2tY2XICAd5hy6Q== + dependencies: + popsicle "^12.0.5" + safe-buffer "^5.2.0" + cliui@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" @@ -5969,6 +6566,22 @@ concat-stream@^1.5.1, concat-stream@^1.5.2, concat-stream@^1.6.0, concat-stream@ readable-stream "^2.2.2" typedarray "^0.0.6" +conf@^6.2.0: + version "6.2.4" + resolved "https://registry.yarnpkg.com/conf/-/conf-6.2.4.tgz#49d23c4e21ef2ac2860f7b5ed25b7b7e484f769f" + integrity sha512-GjgyPRLo1qK1LR9RWAdUagqo+DP18f5HWCFk4va7GS+wpxQTOzfuKTwKOvGW2c01/YXNicAyyoyuSddmdkBzZQ== + dependencies: + ajv "^6.10.2" + debounce-fn "^3.0.1" + dot-prop "^5.0.0" + env-paths "^2.2.0" + json-schema-typed "^7.0.1" + make-dir "^3.0.0" + onetime "^5.1.0" + pkg-up "^3.0.1" + semver "^6.2.0" + write-file-atomic "^3.0.0" + configstore@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" @@ -6015,7 +6628,7 @@ content-hash@^2.5.2: multicodec "^0.5.5" multihashes "^0.4.15" -content-type@~1.0.4: +content-type@^1.0.4, content-type@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== @@ -6157,6 +6770,24 @@ cross-fetch@^2.1.0, cross-fetch@^2.1.1: node-fetch "^2.6.7" whatwg-fetch "^2.0.4" +cross-fetch@^3.0.6: + version "3.1.5" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" + integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== + dependencies: + node-fetch "2.6.7" + +cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -6278,6 +6909,13 @@ death@^1.1.0: resolved "https://registry.yarnpkg.com/death/-/death-1.1.0.tgz#01aa9c401edd92750514470b8266390c66c67318" integrity sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w== +debounce-fn@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/debounce-fn/-/debounce-fn-3.0.1.tgz#034afe8b904d985d1ec1aa589cd15f388741d680" + integrity sha512-aBoJh5AhpqlRoHZjHmOzZlRx+wz2xVwGL9rjs+Kj0EWUrL4/h4K7OD176thl2Tdoqui/AaA4xhHrNArGLAaI3Q== + dependencies: + mimic-fn "^2.1.0" + debug@2.6.9, debug@^2.2.0, debug@^2.6.0, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -6292,7 +6930,7 @@ debug@3.2.6: dependencies: ms "^2.1.1" -debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: +debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -6635,7 +7273,7 @@ dot-case@^2.1.0: dependencies: no-case "^2.2.0" -dot-prop@^5.2.0: +dot-prop@^5.0.0, dot-prop@^5.2.0: version "5.3.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== @@ -6652,7 +7290,7 @@ dotenv@16.0.1, dotenv@^16.0.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.1.tgz#8f8f9d94876c35dac989876a5d3a82a267fdce1d" integrity sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ== -dotenv@^8.0.0: +dotenv@^8.0.0, dotenv@^8.2.0: version "8.6.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== @@ -7165,12 +7803,12 @@ esprima@2.7.x, esprima@^2.7.1: resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" integrity sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A== -esprima@^4.0.0, esprima@^4.0.1: +esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.4.0: +esquery@^1.0.1, esquery@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== @@ -7910,6 +8548,16 @@ external-editor@^3.0.3: iconv-lite "^0.4.24" tmp "^0.0.33" +extract-files@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-9.0.0.tgz#8a7744f2437f81f5ed3250ed9f1550de902fe54a" + integrity sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ== + +extract-stack@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/extract-stack/-/extract-stack-2.0.0.tgz#11367bc865bfcd9bc0db3123e5edb57786f11f9b" + integrity sha512-AEo4zm+TenK7zQorGK1f9mJ8L14hnTDi2ZQPR+Mub1NX8zimka1mXpV5LpH8x9HoUmFSHZCfLHqWvp0Y4FxxzQ== + extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" @@ -8011,7 +8659,7 @@ fetch-ponyfill@^4.0.0: dependencies: node-fetch "~1.7.1" -figures@^3.0.0: +figures@^3.0.0, figures@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== @@ -8030,6 +8678,11 @@ file-uri-to-path@1.0.0: resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== +filesize@^6.1.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-6.4.0.tgz#914f50471dd66fdca3cefe628bd0cde4ef769bcd" + integrity sha512-mjFIpOHC4jbfcTfoh4rkWpI31mF7viw9ikj/JyLoKzqlwG/YsefKfvYlYhdYdg/9mtK2z1AzgN/0LvVQ3zdlSQ== + fill-range@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" @@ -8273,7 +8926,7 @@ fs-extra@^7.0.1: jsonfile "^4.0.0" universalify "^0.1.0" -fs-extra@^8.1.0: +fs-extra@^8.1, fs-extra@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== @@ -8282,6 +8935,16 @@ fs-extra@^8.1.0: jsonfile "^4.0.0" universalify "^0.1.0" +fs-extra@^9.0.1: + version "9.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + fs-minipass@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" @@ -8434,7 +9097,7 @@ get-port@^3.1.0: resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc" integrity sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg== -get-port@^5.1.1: +get-port@^5.0.0, get-port@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== @@ -8635,7 +9298,7 @@ globby@^10.0.1: merge2 "^1.2.3" slash "^3.0.0" -globby@^11.1.0: +globby@^11.0.1, globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -8772,6 +9435,27 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== +graphql-request@^3.3.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-3.7.0.tgz#c7406e537084f8b9788541e3e6704340ca13055b" + integrity sha512-dw5PxHCgBneN2DDNqpWu8QkbbJ07oOziy8z+bK/TAXufsOLaETuVO4GkXrbs0WjhdKhBMN3BkpN/RIvUHkmNUQ== + dependencies: + cross-fetch "^3.0.6" + extract-files "^9.0.0" + form-data "^3.0.0" + +graphql-tag@^2.11.0: + version "2.12.6" + resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.6.tgz#d441a569c1d2537ef10ca3d1633b48725329b5f1" + integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg== + dependencies: + tslib "^2.1.0" + +graphql@^15.4.0: + version "15.8.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.8.0.tgz#33410e96b012fa3bdb1091cc99a94769db212b38" + integrity sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw== + growl@1.10.5: version "1.10.5" resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" @@ -9114,6 +9798,18 @@ http-cache-semantics@^4.0.0: resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== +http-call@^5.2.2, http-call@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/http-call/-/http-call-5.3.0.tgz#4ded815b13f423de176eb0942d69c43b25b148db" + integrity sha512-ahwimsC23ICE4kPl9xTBjKB4inbRaeLyZeRunC/1Jy/Z6X8tv22MEAjK+KBOMSVLaqXPTTmd8638waVIKLGx2w== + dependencies: + content-type "^1.0.4" + debug "^4.1.1" + is-retry-allowed "^1.1.0" + is-stream "^2.0.0" + parse-json "^4.0.0" + tunnel-agent "^0.6.0" + http-errors@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" @@ -9164,7 +9860,7 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" -https-proxy-agent@^5.0.0: +https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== @@ -9182,6 +9878,11 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== +hyperlinker@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hyperlinker/-/hyperlinker-1.0.0.tgz#23dc9e38a206b208ee49bc2d6c8ef47027df0c0e" + integrity sha512-Ty8UblRWFEcfSuIaajM34LdPXIhbs1ajEX/BBPv24J+enSVaEVY63xQ6lTO9VRYS5LAoghIG0IDJ+p+IPzKUQQ== + iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -9208,6 +9909,13 @@ ieee754@^1.1.13, ieee754@^1.2.1: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== +ignore-walk@^3.0.3: + version "3.0.4" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.4.tgz#c9a09f69b7c7b479a5d74ac1a3c0d4236d2a6335" + integrity sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ== + dependencies: + minimatch "^3.0.4" + ignore@^5.1.1, ignore@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" @@ -9277,6 +9985,17 @@ ini@^1.3.5, ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== +inquirer-autocomplete-prompt@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/inquirer-autocomplete-prompt/-/inquirer-autocomplete-prompt-2.0.0.tgz#28d742e5bc411ce52c8ce21509279e12b21a76f3" + integrity sha512-c2LljLP3ewVJe4AUZzKdA6oWjqhpy5pfsisHAjh7mP3WUQ/O02x5OLMMqcLOYuRHx6i2hlVSIhUv0xYGyFxFYA== + dependencies: + ansi-escapes "^4.3.2" + figures "^3.2.0" + picocolors "^1.0.0" + run-async "^2.4.1" + rxjs "^7.5.4" + inquirer@7.3.3: version "7.3.3" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" @@ -9316,6 +10035,27 @@ inquirer@8.2.0: strip-ansi "^6.0.0" through "^2.3.6" +inquirer@^8.2.4: + version "8.2.5" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.5.tgz#d8654a7542c35a9b9e069d27e2df4858784d54f8" + integrity sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.1" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.21" + mute-stream "0.0.8" + ora "^5.4.1" + run-async "^2.4.0" + rxjs "^7.5.5" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + wrap-ansi "^7.0.0" + internal-slot@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" @@ -9366,6 +10106,11 @@ ioredis@^4.28.5: redis-parser "^3.0.0" standard-as-callback "^2.1.0" +ip-regex@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + integrity sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw== + ip-regex@^4.0.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5" @@ -9572,6 +10317,11 @@ is-date-object@^1.0.1: dependencies: has-tostringtag "^1.0.0" +is-docker@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + is-electron@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/is-electron/-/is-electron-2.2.1.tgz#751b1dd8a74907422faa5c35aaa0cf66d98086e9" @@ -9707,7 +10457,7 @@ is-regex@^1.0.4, is-regex@^1.1.4, is-regex@~1.1.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-retry-allowed@^1.0.0: +is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== @@ -9788,6 +10538,13 @@ is-weakref@^1.0.2: dependencies: call-bind "^1.0.2" +is-wsl@^2.1.1, is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" @@ -10512,6 +11269,11 @@ json-buffer@3.0.0: resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" integrity sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ== +json-parse-better-errors@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" @@ -10559,6 +11321,11 @@ json-schema-traverse@^1.0.0: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== +json-schema-typed@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/json-schema-typed/-/json-schema-typed-7.0.3.tgz#23ff481b8b4eebcd2ca123b4fa0409e66469a2d9" + integrity sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A== + json-schema@0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" @@ -10605,6 +11372,11 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" +json5@^2.1.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.2.tgz#64471c5bdcc564c18f7c1d4df2e2297f2457c5ab" + integrity sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ== + jsonc-parser@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.0.0.tgz#abdd785701c7e7eaca8a9ec8cf070ca51a745a22" @@ -11136,7 +11908,14 @@ lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17. resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -log-symbols@3.0.0: +log-chopper@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/log-chopper/-/log-chopper-1.0.2.tgz#a88da7a47a9f0e511eda4d5e1dc840e0eaf4547a" + integrity sha512-tEWS6Fb+Xv0yLChJ6saA1DP3H1yPL0PfiIN7SDJ+U/CyP+fD4G/dhKfow+P5UuJWi6BdE4mUcPkJclGXCWxDrg== + dependencies: + byline "5.x" + +log-symbols@3.0.0, log-symbols@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" integrity sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ== @@ -11273,7 +12052,14 @@ make-dir@^3.0.0: dependencies: semver "^6.0.0" -make-error@1.x, make-error@^1.1.1: +make-error-cause@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/make-error-cause/-/make-error-cause-2.3.0.tgz#ecd11875971e506d510e93d37796e5b83f46d6f9" + integrity sha512-etgt+n4LlOkGSJbBTV9VROHA5R7ekIPS4vfh+bCAoJgRrJWdqJCBbpS3osRJ/HrT7R68MzMiY3L3sDJ/Fd8aBg== + dependencies: + make-error "^1.3.5" + +make-error@1.x, make-error@^1.1.1, make-error@^1.3.5: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== @@ -11711,7 +12497,7 @@ mock-fs@^4.1.0: resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" integrity sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw== -moment@^2.24.0: +moment@^2.22.1, moment@^2.24.0: version "2.29.4" resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== @@ -11981,6 +12767,11 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== +natural-orderby@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/natural-orderby/-/natural-orderby-2.0.3.tgz#8623bc518ba162f8ff1cdb8941d74deb0fdcc016" + integrity sha512-p7KTHxU0CUrcOXe62Zfrb5Z13nLvPhSWR/so3kFulUQU0sgUll2Z0LwpsLN351eOOD+hRGu/F1g+6xDfPeD++Q== + negotiator@0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" @@ -11996,6 +12787,11 @@ next-tick@^1.1.0: resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + no-case@^2.2.0, no-case@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" @@ -12042,7 +12838,7 @@ node-environment-flags@1.0.6: object.getownpropertydescriptors "^2.0.3" semver "^5.7.0" -node-fetch@^2.6.1, node-fetch@^2.6.7: +node-fetch@2.6.7, node-fetch@^2.6.1, node-fetch@^2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== @@ -12230,6 +13026,11 @@ object-keys@~0.4.0: resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" integrity sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw== +object-treeify@^1.1.4: + version "1.1.33" + resolved "https://registry.yarnpkg.com/object-treeify/-/object-treeify-1.1.33.tgz#f06fece986830a3cba78ddd32d4c11d1f76cdf40" + integrity sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A== + object.assign@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" @@ -12309,6 +13110,14 @@ onetime@^5.1.0, onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" +open@^7.3.1: + version "7.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" + integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== + dependencies: + is-docker "^2.0.0" + is-wsl "^2.1.1" + optionator@^0.8.1: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" @@ -12348,6 +13157,20 @@ ora@5.4.1, ora@^5.4.1: strip-ansi "^6.0.0" wcwidth "^1.0.1" +ora@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ora/-/ora-4.1.1.tgz#566cc0348a15c36f5f0e979612842e02ba9dddbc" + integrity sha512-sjYP8QyVWBpBZWD6Vr1M/KwknSw6kJOz41tvGMlwWeClHBtYKTbHMki1PsLZnxKpXMPbTKv9b3pjQu3REib96A== + dependencies: + chalk "^3.0.0" + cli-cursor "^3.1.0" + cli-spinners "^2.2.0" + is-interactive "^1.0.0" + log-symbols "^3.0.0" + mute-stream "0.0.8" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" @@ -12538,6 +13361,14 @@ parse-json@^2.2.0: dependencies: error-ex "^1.2.0" +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw== + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + parse-json@^5.0.0, parse-json@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" @@ -12568,6 +13399,13 @@ parse5@6.0.1, parse5@^6.0.1: resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== +parse5@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c" + integrity sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA== + dependencies: + "@types/node" "*" + parse5@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" @@ -12626,6 +13464,14 @@ passport@^0.6.0: pause "0.0.1" utils-merge "^1.0.1" +password-prompt@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/password-prompt/-/password-prompt-1.1.2.tgz#85b2f93896c5bd9e9f2d6ff0627fa5af3dc00923" + integrity sha512-bpuBhROdrhuN3E7G/koAju0WjVw9/uQOG5Co5mokNj0MiOSBVZS1JTwM4zl55hu0WFmIEFvO9cU9sJQiBIYeIA== + dependencies: + ansi-escapes "^3.1.0" + cross-spawn "^6.0.5" + path-case@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/path-case/-/path-case-2.1.1.tgz#94b8037c372d3fe2906e465bb45e25d226e8eea5" @@ -12655,6 +13501,11 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== +path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== + path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" @@ -12786,6 +13637,11 @@ pgpass@1.x: dependencies: split2 "^4.1.0" +php-parser@^3.0.0-prerelease.8: + version "3.1.2" + resolved "https://registry.yarnpkg.com/php-parser/-/php-parser-3.1.2.tgz#db704c584ea4085142fc5d3c33218b207d5f9a09" + integrity sha512-RRCMK/bCKYPLRhlpfMlVVVsaIesuW+X6UxRqWjm7dTAmTZk8PvD6hCmG/RVeDzse7iqYWJwLJeqEbaGLC+aHeQ== + picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" @@ -12828,6 +13684,11 @@ pirates@^4.0.4: resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== +pkce-challenge@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/pkce-challenge/-/pkce-challenge-2.2.0.tgz#02622e0498b82aab248c8c7dbf6507e8bbe20abf" + integrity sha512-Ly0Y0OwhtG2N1ynk5ruqoyJxkrWhAPmvdRk0teiLh9Dp2+J4URKpv1JSKWD0j1Sd+QCeiwO9lTl0EjmrB2jWeA== + pkg-dir@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" @@ -12835,11 +13696,67 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +pkg-up@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" + integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== + dependencies: + find-up "^3.0.0" + pluralize@8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== +popsicle-content-encoding@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/popsicle-content-encoding/-/popsicle-content-encoding-1.0.0.tgz#2ab419083fee0387bf6e64d21b1a9af560795adb" + integrity sha512-4Df+vTfM8wCCJVTzPujiI6eOl3SiWQkcZg0AMrOkD1enMXsF3glIkFUZGvour1Sj7jOWCsNSEhBxpbbhclHhzw== + +popsicle-cookie-jar@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/popsicle-cookie-jar/-/popsicle-cookie-jar-1.0.0.tgz#9e8c89be7182b31f7ce0e66dad465ae475d8f47c" + integrity sha512-vrlOGvNVELko0+J8NpGC5lHWDGrk8LQJq9nwAMIVEVBfN1Lib3BLxAaLRGDTuUnvl45j5N9dT2H85PULz6IjjQ== + dependencies: + "@types/tough-cookie" "^2.3.5" + tough-cookie "^3.0.1" + +popsicle-redirects@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/popsicle-redirects/-/popsicle-redirects-1.1.1.tgz#da0936ed97f0ea22b16daa028bc624cb5b6ce05d" + integrity sha512-mC2HrKjdTAWDalOjGxlXw9j6Qxrz/Yd2ui6bPxpi2IQDYWpF4gUAMxbA8EpSWJhLi0PuWKDwTHHPrUPGutAoIA== + +popsicle-transport-http@^1.0.8: + version "1.2.1" + resolved "https://registry.yarnpkg.com/popsicle-transport-http/-/popsicle-transport-http-1.2.1.tgz#35fdf4a59f429470b13b62f4223ec0249e3a163b" + integrity sha512-i5r3IGHkGiBDm1oPFvOfEeSGWR0lQJcsdTqwvvDjXqcTHYJJi4iSi3ecXIttDiTBoBtRAFAE9nF91fspQr63FQ== + dependencies: + make-error-cause "^2.2.0" + +popsicle-transport-xhr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/popsicle-transport-xhr/-/popsicle-transport-xhr-2.0.0.tgz#23d5fabb0e50e321d50219860825c27cd827ddd9" + integrity sha512-5Sbud4Widngf1dodJE5cjEYXkzEUIl8CzyYRYR57t6vpy9a9KPGQX6KBKdPjmBZlR5A06pOBXuJnVr23l27rtA== + +popsicle-user-agent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/popsicle-user-agent/-/popsicle-user-agent-1.0.0.tgz#976af355b605966168733c4e03ad1e4f783f5d48" + integrity sha512-epKaq3TTfTzXcxBxjpoKYMcTTcAX8Rykus6QZu77XNhJuRHSRxMd+JJrbX/3PFI0opFGSN0BabbAYCbGxbu0mA== + +popsicle@^12.0.5: + version "12.1.0" + resolved "https://registry.yarnpkg.com/popsicle/-/popsicle-12.1.0.tgz#80ba6ea75818d30658263329f1d8985751ecac02" + integrity sha512-muNC/cIrWhfR6HqqhHazkxjob3eyECBe8uZYSQ/N5vixNAgssacVleerXnE8Are5fspR0a+d2qWaBR1g7RYlmw== + dependencies: + popsicle-content-encoding "^1.0.0" + popsicle-cookie-jar "^1.0.0" + popsicle-redirects "^1.1.0" + popsicle-transport-http "^1.0.8" + popsicle-transport-xhr "^2.0.0" + popsicle-user-agent "^1.0.0" + servie "^4.3.3" + throwback "^4.1.0" + postgres-array@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" @@ -13165,6 +14082,11 @@ queue@^6.0.2: dependencies: inherits "~2.0.3" +randombytes@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.3.tgz#674c99760901c3c4112771a31e521dc349cc09ec" + integrity sha512-lDVjxQQFoCG1jcrP06LNo2lbWp4QTShEXnhActFBwYuHprllQV6VUpwreApsYqCgD+N1mHoqJ/BI/4eV4R2GYg== + randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.0.6, randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -13180,6 +14102,14 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" +randomstring@^1.1.5: + version "1.2.3" + resolved "https://registry.yarnpkg.com/randomstring/-/randomstring-1.2.3.tgz#49d2bc34ff6bc2bd0f6bb8e7d876e1d4433564c8" + integrity sha512-3dEFySepTzp2CvH6W/ASYGguPPveBuz5MpZ7MuoUkoVehmyNl9+F9c9GFVrz2QPbM9NXTIHGcmJDY/3j4677kQ== + dependencies: + array-uniq "1.0.2" + randombytes "2.0.3" + range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" @@ -13311,6 +14241,13 @@ recursive-readdir@^2.2.2: dependencies: minimatch "3.0.4" +redeyed@~2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-2.1.1.tgz#8984b5815d99cb220469c99eeeffe38913e6cc0b" + integrity sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ== + dependencies: + esprima "~4.0.0" + redis-commands@1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89" @@ -13639,7 +14576,7 @@ rlp@^2.0.0, rlp@^2.2.1, rlp@^2.2.2, rlp@^2.2.3, rlp@^2.2.4: dependencies: bn.js "^5.2.0" -run-async@^2.4.0: +run-async@^2.4.0, run-async@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== @@ -13677,6 +14614,13 @@ rxjs@^7.2.0, rxjs@^7.5.5: dependencies: tslib "^2.1.0" +rxjs@^7.5.4: + version "7.8.0" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.0.tgz#90a938862a82888ff4c7359811a595e14e1e09a4" + integrity sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg== + dependencies: + tslib "^2.1.0" + safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -13821,12 +14765,12 @@ semver@7.x, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7: dependencies: lru-cache "^6.0.0" -semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: +semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.1.2: +semver@^7.1.2, semver@^7.3.8: version "7.3.8" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== @@ -13889,6 +14833,15 @@ serve-static@1.15.0: parseurl "~1.3.3" send "0.18.0" +servie@^4.3.3: + version "4.3.3" + resolved "https://registry.yarnpkg.com/servie/-/servie-4.3.3.tgz#4a9ffed6842cd0523003ad0ae9c0c8079f37718f" + integrity sha512-b0IrY3b1gVMsWvJppCf19g1p3JSnS0hQi6xu4Hi40CIhf0Lx8pQHcvBL+xunShpmOiQzg1NOia812NAWdSaShw== + dependencies: + "@servie/events" "^1.0.0" + byte-length "^1.0.2" + ts-expect "^1.1.0" + servify@^0.1.12: version "0.1.12" resolved "https://registry.yarnpkg.com/servify/-/servify-0.1.12.tgz#142ab7bee1f1d033b66d0707086085b17c06db95" @@ -13948,6 +14901,13 @@ sha3@^2.1.1: dependencies: buffer "6.0.3" +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== + dependencies: + shebang-regex "^1.0.0" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -13955,6 +14915,11 @@ shebang-command@^2.0.0: dependencies: shebang-regex "^3.0.0" +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== + shebang-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" @@ -14256,6 +15221,11 @@ stealthy-require@^1.1.1: resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" integrity sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g== +stoppable@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/stoppable/-/stoppable-1.1.0.tgz#32da568e83ea488b08e4d7ea2c3bcc9d75015d5b" + integrity sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw== + stream-events@^1.0.4, stream-events@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/stream-events/-/stream-events-1.0.5.tgz#bbc898ec4df33a4902d892333d47da9bf1c406d5" @@ -14310,7 +15280,7 @@ string-width@^1.0.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -14483,7 +15453,7 @@ supports-color@6.0.0: dependencies: has-flag "^3.0.0" -supports-color@8.1.1, supports-color@^8.0.0: +supports-color@8.1.1, supports-color@^8.0.0, supports-color@^8.1.0: version "8.1.1" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== @@ -14502,7 +15472,7 @@ supports-color@^3.1.0: dependencies: has-flag "^1.0.0" -supports-color@^5.3.0: +supports-color@^5.3.0, supports-color@^5.4.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== @@ -14524,6 +15494,14 @@ supports-hyperlinks@^2.0.0: has-flag "^4.0.0" supports-color "^7.0.0" +supports-hyperlinks@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624" + integrity sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" @@ -14634,7 +15612,7 @@ tape@^4.4.0, tape@^4.6.3: string.prototype.trim "~1.2.5" through "~2.3.8" -tar-fs@^2.0.0: +tar-fs@^2.0.0, tar-fs@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== @@ -14792,6 +15770,11 @@ through@^2.3.6, through@~2.3.4, through@~2.3.8: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== +throwback@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/throwback/-/throwback-4.1.0.tgz#421aac7ba9eff473105385ac4a2b0130d4b0a59c" + integrity sha512-dLFe8bU8SeH0xeqeKL7BNo8XoPC/o91nz9/ooeplZPiso+DZukhoyZcSz9TFnUNScm+cA9qjU1m1853M6sPOng== + timed-out@^4.0.0, timed-out@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" @@ -14867,6 +15850,15 @@ tough-cookie@^2.3.3, tough-cookie@~2.5.0: psl "^1.1.28" punycode "^2.1.1" +tough-cookie@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2" + integrity sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg== + dependencies: + ip-regex "^2.1.0" + psl "^1.1.28" + punycode "^2.1.1" + tough-cookie@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" @@ -14918,6 +15910,11 @@ truffle-deploy-registry@^0.5.1: mkdirp "^0.5.1" rimraf "^2.6.3" +ts-expect@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-expect/-/ts-expect-1.3.0.tgz#3f8d3966e0e22b5e2bb88337eb99db6816a4c1cf" + integrity sha512-e4g0EJtAjk64xgnFPD6kTBUtpnMVzDrMb12N1YZV0VvSlhnVT3SGxiYTLdGy8Q5cYHOIC/FAHmZ10eGrAguicQ== + ts-jest@^27.1.4: version "27.1.5" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-27.1.5.tgz#0ddf1b163fbaae3d5b7504a1e65c914a95cff297" @@ -14990,11 +15987,16 @@ tslib@2.4.0, tslib@^2.1.0, tslib@^2.3.1, tslib@^2.4.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== -tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: +tslib@^1, tslib@^1.14.1, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslib@^2.0.0, tslib@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" + integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== + tsort@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/tsort/-/tsort-0.0.1.tgz#e2280f5e817f8bf4275657fd0f9aebd44f5a2786" @@ -15121,6 +16123,11 @@ typescript@4.7.4, typescript@^4.6.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== +typescript@^3.9.7: + version "3.9.10" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8" + integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q== + u2f-api@0.2.7: version "0.2.7" resolved "https://registry.yarnpkg.com/u2f-api/-/u2f-api-0.2.7.tgz#17bf196b242f6bf72353d9858e6a7566cc192720" @@ -15419,6 +16426,13 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +vue-parser@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/vue-parser/-/vue-parser-1.1.6.tgz#3063c8431795664ebe429c23b5506899706e6355" + integrity sha512-v3/R7PLbaFVF/c8IIzWs1HgRpT2gN0dLRkaLIT5q+zJGVgmhN4VuZJF4Y9N4hFtFjS4B1EHxAOP6/tzqM4Ug2g== + dependencies: + parse5 "^3.0.3" + w3c-hr-time@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" @@ -16060,7 +17074,7 @@ which-typed-array@^1.1.2: has-tostringtag "^1.0.0" is-typed-array "^1.1.9" -which@1.3.1, which@^1.1.1, which@^1.3.1: +which@1.3.1, which@^1.1.1, which@^1.2.9, which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== @@ -16088,6 +17102,13 @@ wide-align@^1.1.0: dependencies: string-width "^1.0.2 || 2 || 3 || 4" +widest-line@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" + integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== + dependencies: + string-width "^4.0.0" + window-size@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" @@ -16162,6 +17183,15 @@ wrap-ansi@^5.1.0: string-width "^3.0.0" strip-ansi "^5.0.0" +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" From 996467adb8e4ce9e236c7375b4114c034eb44b30 Mon Sep 17 00:00:00 2001 From: amateima <89395931+amateima@users.noreply.github.com> Date: Thu, 29 Dec 2022 16:31:57 +0200 Subject: [PATCH 10/17] fix: retry failed jobs (#187) --- .../scraper/service/ScraperQueuesService.ts | 111 ++++++++++++------ 1 file changed, 73 insertions(+), 38 deletions(-) diff --git a/src/modules/scraper/service/ScraperQueuesService.ts b/src/modules/scraper/service/ScraperQueuesService.ts index 19dea829..67f6cf3f 100644 --- a/src/modules/scraper/service/ScraperQueuesService.ts +++ b/src/modules/scraper/service/ScraperQueuesService.ts @@ -21,44 +21,8 @@ export class ScraperQueuesService { @InjectQueue(ScraperQueue.SuggestedFees) private suggestedFeesQueue: Queue, @InjectQueue(ScraperQueue.TrackFillEvent) private trackFillEventsQueue: Queue, ) { - setInterval(() => { - this.blocksEventsQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.BlocksEvents} ${JSON.stringify(data)}`)); - this.merkleDistributorBlocksEventsQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.MerkleDistributorBlocksEvents} ${JSON.stringify(data)}`)); - this.fillEventsQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.FillEvents} ${JSON.stringify(data)}`)); - this.speedUpEventsQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.SpeedUpEvents} ${JSON.stringify(data)}`)); - this.blockNumberQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.BlockNumber} ${JSON.stringify(data)}`)); - this.tokenDetailsQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.TokenDetails} ${JSON.stringify(data)}`)); - this.depositReferralQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.DepositReferral} ${JSON.stringify(data)}`)); - this.tokenPriceQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.TokenPrice} ${JSON.stringify(data)}`)); - this.depositFilledDateQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.DepositFilledDate} ${JSON.stringify(data)}`)); - this.depositAcxPriceQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.DepositAcxPrice} ${JSON.stringify(data)}`)); - this.suggestedFeesQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.SuggestedFees} ${JSON.stringify(data)}`)); - this.trackFillEventsQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.TrackFillEvent} ${JSON.stringify(data)}`)); - }, 1000 * 60); + this.initLogs(); + this.retryFailedJobs(); } public async publishMessage(queue: ScraperQueue, message: T) { @@ -116,4 +80,75 @@ export class ScraperQueuesService { await this.trackFillEventsQueue.addBulk(messages.map((m) => ({ data: m }))); } } + + public getAllQueues() { + return [ + this.blocksEventsQueue, + this.merkleDistributorBlocksEventsQueue, + this.fillEventsQueue, + this.speedUpEventsQueue, + this.blockNumberQueue, + this.tokenDetailsQueue, + this.depositReferralQueue, + this.tokenPriceQueue, + this.depositFilledDateQueue, + this.depositAcxPriceQueue, + this.suggestedFeesQueue, + this.trackFillEventsQueue, + ]; + } + + private async retryFailedJobs() { + try { + for (const queue of this.getAllQueues()) { + const failedJobs = await queue.getFailed(); + for (const failedJob of failedJobs) { + await failedJob.retry(); + } + } + } catch (error) { + this.logger.error(error); + } + } + + private initLogs() { + setInterval(() => { + this.blocksEventsQueue + .getJobCounts() + .then((data) => this.logger.log(`${ScraperQueue.BlocksEvents} ${JSON.stringify(data)}`)); + this.merkleDistributorBlocksEventsQueue + .getJobCounts() + .then((data) => this.logger.log(`${ScraperQueue.MerkleDistributorBlocksEvents} ${JSON.stringify(data)}`)); + this.fillEventsQueue + .getJobCounts() + .then((data) => this.logger.log(`${ScraperQueue.FillEvents} ${JSON.stringify(data)}`)); + this.speedUpEventsQueue + .getJobCounts() + .then((data) => this.logger.log(`${ScraperQueue.SpeedUpEvents} ${JSON.stringify(data)}`)); + this.blockNumberQueue + .getJobCounts() + .then((data) => this.logger.log(`${ScraperQueue.BlockNumber} ${JSON.stringify(data)}`)); + this.tokenDetailsQueue + .getJobCounts() + .then((data) => this.logger.log(`${ScraperQueue.TokenDetails} ${JSON.stringify(data)}`)); + this.depositReferralQueue + .getJobCounts() + .then((data) => this.logger.log(`${ScraperQueue.DepositReferral} ${JSON.stringify(data)}`)); + this.tokenPriceQueue + .getJobCounts() + .then((data) => this.logger.log(`${ScraperQueue.TokenPrice} ${JSON.stringify(data)}`)); + this.depositFilledDateQueue + .getJobCounts() + .then((data) => this.logger.log(`${ScraperQueue.DepositFilledDate} ${JSON.stringify(data)}`)); + this.depositAcxPriceQueue + .getJobCounts() + .then((data) => this.logger.log(`${ScraperQueue.DepositAcxPrice} ${JSON.stringify(data)}`)); + this.suggestedFeesQueue + .getJobCounts() + .then((data) => this.logger.log(`${ScraperQueue.SuggestedFees} ${JSON.stringify(data)}`)); + this.trackFillEventsQueue + .getJobCounts() + .then((data) => this.logger.log(`${ScraperQueue.TrackFillEvent} ${JSON.stringify(data)}`)); + }, 1000 * 60); + } } From 8760bd761566dd02425b3a20327a1815760c6886 Mon Sep 17 00:00:00 2001 From: Dong-Ha Kim Date: Thu, 29 Dec 2022 16:27:42 +0100 Subject: [PATCH 11/17] fix: default to zero address for old queued up redis jobs (#188) --- .../scraper/adapter/messaging/TrackFillEventConsumer.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/modules/scraper/adapter/messaging/TrackFillEventConsumer.ts b/src/modules/scraper/adapter/messaging/TrackFillEventConsumer.ts index 5b059480..fc260e28 100644 --- a/src/modules/scraper/adapter/messaging/TrackFillEventConsumer.ts +++ b/src/modules/scraper/adapter/messaging/TrackFillEventConsumer.ts @@ -3,7 +3,7 @@ import { Logger } from "@nestjs/common"; import { Job } from "bull"; import { InjectRepository } from "@nestjs/typeorm"; import { Repository } from "typeorm"; -import { utils } from "ethers"; +import { utils, constants } from "ethers"; import BigNumber from "bignumber.js"; import { DateTime } from "luxon"; @@ -139,7 +139,9 @@ export class TrackFillEventConsumer { totalBridgeFeeUsd: formattedBridgeFeeValues.totalUsd, totalFilledAmount: totalFilledAmounts.formattedAmount, totalFilledAmountUsd: totalFilledAmounts.formattedAmountUsd, - toTokenAddress: utils.getAddress(destinationToken), + // Old queued up redis jobs might not have the `destinationToken` field, + // so we default to `0x0000000000000000000000000000000000000000` + toTokenAddress: utils.getAddress(destinationToken || constants.AddressZero), transactionHash: fillTx.hash, transferCompleteTimestamp: String(DateTime.fromISO(fillTx.date).toMillis()), transferQuoteBlockNumber: String(fillTxBlockNumber), From 07c8eaba49f913ea7be4755974336308bc97f6ba Mon Sep 17 00:00:00 2001 From: amateima <89395931+amateima@users.noreply.github.com> Date: Mon, 2 Jan 2023 17:03:04 +0200 Subject: [PATCH 12/17] fix: fix grouping deposits by claimed window (#191) --- src/modules/referral/services/service.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/referral/services/service.ts b/src/modules/referral/services/service.ts index 0db3140b..536897f9 100644 --- a/src/modules/referral/services/service.ts +++ b/src/modules/referral/services/service.ts @@ -298,6 +298,7 @@ export class ReferralService { const claims = await entityManager .createQueryBuilder(Claim, "c") .where("c.account = :account", { account: referralAddress }) + .andWhere("c.windowIndex > 0") .orderBy("c.claimedAt", "ASC") .getMany(); const deposits = await entityManager From 436b7bebfedba58a65fe9deeef1fedeb88e5bd52 Mon Sep 17 00:00:00 2001 From: amateima <89395931+amateima@users.noreply.github.com> Date: Tue, 3 Jan 2023 16:36:12 +0200 Subject: [PATCH 13/17] fix: fix cache default values (#193) --- src/modules/configuration/index.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/modules/configuration/index.ts b/src/modules/configuration/index.ts index 52e861c2..2473bcb5 100644 --- a/src/modules/configuration/index.ts +++ b/src/modules/configuration/index.ts @@ -27,8 +27,12 @@ export const configValues = () => ({ : undefined, disableCrons: process.env.DISABLE_CRONS === "true" || false, cacheDuration: { - distributorProofs: parseInt(process.env.DISTRIBUTOR_PROOFS_CACHE_SECONDS_DURATION) ?? 300, - referralsSummary: parseInt(process.env.REFERRALS_SUMMARY_CACHE_SECONDS_DURATION) ?? 120, + distributorProofs: isNaN(parseInt(process.env.DISTRIBUTOR_PROOFS_CACHE_SECONDS_DURATION)) + ? 300 + : parseInt(process.env.DISTRIBUTOR_PROOFS_CACHE_SECONDS_DURATION), + referralsSummary: isNaN(parseInt(process.env.REFERRALS_SUMMARY_CACHE_SECONDS_DURATION)) + ? 120 + : parseInt(process.env.REFERRALS_SUMMARY_CACHE_SECONDS_DURATION), }, }, web3: { From 88cbcdd97a88777b7445be1cb81892b0256fb89d Mon Sep 17 00:00:00 2001 From: amateima Date: Thu, 5 Jan 2023 15:28:57 +0200 Subject: [PATCH 14/17] fix: disable unnecesary line --- src/modules/scraper/adapter/messaging/FillEventsConsumer.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/scraper/adapter/messaging/FillEventsConsumer.ts b/src/modules/scraper/adapter/messaging/FillEventsConsumer.ts index 4bbca40b..df5370af 100644 --- a/src/modules/scraper/adapter/messaging/FillEventsConsumer.ts +++ b/src/modules/scraper/adapter/messaging/FillEventsConsumer.ts @@ -29,7 +29,8 @@ export class FillEventsConsumer { const deposit = await this.depositRepository.findOne({ where: { sourceChainId: originChainId, depositId } }); if (!deposit) { - await this.tryToRefetchDepositEvents(job.data); + // this is not needed anymore. At least for now + // await this.tryToRefetchDepositEvents(job.data); throw new Error("Deposit not found in db"); } From dae2a278d410a134ea28af55b265c50e3555bb60 Mon Sep 17 00:00:00 2001 From: amateima <89395931+amateima@users.noreply.github.com> Date: Mon, 9 Jan 2023 13:02:57 +0200 Subject: [PATCH 15/17] fix: add endpoint to retry failed jobs (#197) --- .../scraper/entry-point/http/controller.ts | 11 ++ src/modules/scraper/entry-point/http/dto.ts | 10 +- .../scraper/service/ScraperQueuesService.ts | 149 +++++------------- 3 files changed, 58 insertions(+), 112 deletions(-) diff --git a/src/modules/scraper/entry-point/http/controller.ts b/src/modules/scraper/entry-point/http/controller.ts index fe5de215..4aee6d24 100644 --- a/src/modules/scraper/entry-point/http/controller.ts +++ b/src/modules/scraper/entry-point/http/controller.ts @@ -25,6 +25,7 @@ import { ProcessBlockNumberBody, SubmitDepositAcxPriceBody, SubmitSuggestedFeesBody, + RetryFailedJobsBody, } from "./dto"; @Controller() @@ -163,4 +164,14 @@ export class ScraperController { }); } } + + @Post("scraper/failed-jobs/retry") + @ApiTags("scraper") + @Roles(Role.Admin) + @UseGuards(JwtAuthGuard, RolesGuard) + @ApiBearerAuth() + async retryFailedJobs(@Body() body: RetryFailedJobsBody) { + const { queue } = body; + this.scraperQueuesService.retryFailedJobs(queue); + } } diff --git a/src/modules/scraper/entry-point/http/dto.ts b/src/modules/scraper/entry-point/http/dto.ts index fa717d3c..07a1fdd4 100644 --- a/src/modules/scraper/entry-point/http/dto.ts +++ b/src/modules/scraper/entry-point/http/dto.ts @@ -1,5 +1,6 @@ import { ApiProperty } from "@nestjs/swagger"; -import { IsInt } from "class-validator"; +import { IsIn, IsInt, IsString } from "class-validator"; +import { ScraperQueue } from "../../adapter/messaging"; export class ProcessBlocksBody { @IsInt() @@ -74,3 +75,10 @@ export class SubmitSuggestedFeesBody { @ApiProperty({ example: 2 }) toDepositId: number; } + +export class RetryFailedJobsBody { + @IsString() + @IsIn(Object.values(ScraperQueue)) + @ApiProperty({ enum: ScraperQueue, isArray: false }) + queue: ScraperQueue; +} diff --git a/src/modules/scraper/service/ScraperQueuesService.ts b/src/modules/scraper/service/ScraperQueuesService.ts index 67f6cf3f..8ec9c95c 100644 --- a/src/modules/scraper/service/ScraperQueuesService.ts +++ b/src/modules/scraper/service/ScraperQueuesService.ts @@ -6,6 +6,7 @@ import { ScraperQueue } from "../adapter/messaging"; @Injectable() export class ScraperQueuesService { private logger = new Logger(ScraperQueuesService.name); + private queuesMap: Record; public constructor( @InjectQueue(ScraperQueue.BlocksEvents) private blocksEventsQueue: Queue, @@ -21,134 +22,60 @@ export class ScraperQueuesService { @InjectQueue(ScraperQueue.SuggestedFees) private suggestedFeesQueue: Queue, @InjectQueue(ScraperQueue.TrackFillEvent) private trackFillEventsQueue: Queue, ) { + this.queuesMap = { + [ScraperQueue.BlocksEvents]: this.blocksEventsQueue, + [ScraperQueue.MerkleDistributorBlocksEvents]: this.merkleDistributorBlocksEventsQueue, + [ScraperQueue.FillEvents]: this.fillEventsQueue, + [ScraperQueue.SpeedUpEvents]: this.speedUpEventsQueue, + [ScraperQueue.BlockNumber]: this.blockNumberQueue, + [ScraperQueue.TokenDetails]: this.tokenDetailsQueue, + [ScraperQueue.DepositReferral]: this.depositReferralQueue, + [ScraperQueue.TokenPrice]: this.tokenPriceQueue, + [ScraperQueue.DepositFilledDate]: this.depositFilledDateQueue, + [ScraperQueue.DepositAcxPrice]: this.depositAcxPriceQueue, + [ScraperQueue.SuggestedFees]: this.suggestedFeesQueue, + [ScraperQueue.TrackFillEvent]: this.trackFillEventsQueue, + }; this.initLogs(); - this.retryFailedJobs(); } public async publishMessage(queue: ScraperQueue, message: T) { - if (queue === ScraperQueue.BlocksEvents) { - await this.blocksEventsQueue.add(message); - } else if (queue === ScraperQueue.FillEvents) { - await this.fillEventsQueue.add(message); - } else if (queue === ScraperQueue.SpeedUpEvents) { - await this.speedUpEventsQueue.add(message); - } else if (queue === ScraperQueue.BlockNumber) { - await this.blockNumberQueue.add(message); - } else if (queue === ScraperQueue.TokenDetails) { - await this.tokenDetailsQueue.add(message); - } else if (queue === ScraperQueue.DepositReferral) { - await this.depositReferralQueue.add(message); - } else if (queue === ScraperQueue.TokenPrice) { - await this.tokenPriceQueue.add(message); - } else if (queue === ScraperQueue.DepositFilledDate) { - await this.depositFilledDateQueue.add(message); - } else if (queue === ScraperQueue.MerkleDistributorBlocksEvents) { - await this.merkleDistributorBlocksEventsQueue.add(message); - } else if (queue === ScraperQueue.DepositAcxPrice) { - await this.depositAcxPriceQueue.add(message); - } else if (queue === ScraperQueue.SuggestedFees) { - await this.suggestedFeesQueue.add(message); - } else if (queue === ScraperQueue.TrackFillEvent) { - await this.trackFillEventsQueue.add(message); + const q = this.queuesMap[queue]; + + if (q) { + await q.add(message); } } public async publishMessagesBulk(queue: ScraperQueue, messages: T[]) { - if (queue === ScraperQueue.BlocksEvents) { - await this.blocksEventsQueue.addBulk(messages.map((m) => ({ data: m }))); - } else if (queue === ScraperQueue.FillEvents) { - await this.fillEventsQueue.addBulk(messages.map((m) => ({ data: m }))); - } else if (queue === ScraperQueue.SpeedUpEvents) { - await this.speedUpEventsQueue.addBulk(messages.map((m) => ({ data: m }))); - } else if (queue === ScraperQueue.BlockNumber) { - await this.blockNumberQueue.addBulk(messages.map((m) => ({ data: m }))); - } else if (queue === ScraperQueue.TokenDetails) { - await this.tokenDetailsQueue.addBulk(messages.map((m) => ({ data: m }))); - } else if (queue === ScraperQueue.DepositReferral) { - await this.depositReferralQueue.addBulk(messages.map((m) => ({ data: m }))); - } else if (queue === ScraperQueue.TokenPrice) { - await this.tokenPriceQueue.addBulk(messages.map((m) => ({ data: m }))); - } else if (queue === ScraperQueue.DepositFilledDate) { - await this.depositFilledDateQueue.addBulk(messages.map((m) => ({ data: m }))); - } else if (queue === ScraperQueue.MerkleDistributorBlocksEvents) { - await this.merkleDistributorBlocksEventsQueue.addBulk(messages.map((m) => ({ data: m }))); - } else if (queue === ScraperQueue.DepositAcxPrice) { - await this.depositAcxPriceQueue.addBulk(messages.map((m) => ({ data: m }))); - } else if (queue === ScraperQueue.SuggestedFees) { - await this.suggestedFeesQueue.addBulk(messages.map((m) => ({ data: m }))); - } else if (queue === ScraperQueue.TrackFillEvent) { - await this.trackFillEventsQueue.addBulk(messages.map((m) => ({ data: m }))); + const q = this.queuesMap[queue]; + + if (q) { + await q.addBulk(messages.map((m) => ({ data: m }))); } } - public getAllQueues() { - return [ - this.blocksEventsQueue, - this.merkleDistributorBlocksEventsQueue, - this.fillEventsQueue, - this.speedUpEventsQueue, - this.blockNumberQueue, - this.tokenDetailsQueue, - this.depositReferralQueue, - this.tokenPriceQueue, - this.depositFilledDateQueue, - this.depositAcxPriceQueue, - this.suggestedFeesQueue, - this.trackFillEventsQueue, - ]; + private initLogs() { + setInterval(() => { + for (const queueName of Object.keys(this.queuesMap)) { + const queue = this.queuesMap[queueName] as Queue; + queue.getJobCounts().then((data) => this.logger.log(`${queueName} ${JSON.stringify(data)}`)); + } + }, 1000 * 60); } - private async retryFailedJobs() { + public async retryFailedJobs(queue: ScraperQueue) { + const q = this.queuesMap[queue]; + + if (!q) return; + try { - for (const queue of this.getAllQueues()) { - const failedJobs = await queue.getFailed(); - for (const failedJob of failedJobs) { - await failedJob.retry(); - } + const failedJobs = await q.getFailed(); + for (const failedJob of failedJobs) { + await failedJob.retry(); } } catch (error) { this.logger.error(error); } } - - private initLogs() { - setInterval(() => { - this.blocksEventsQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.BlocksEvents} ${JSON.stringify(data)}`)); - this.merkleDistributorBlocksEventsQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.MerkleDistributorBlocksEvents} ${JSON.stringify(data)}`)); - this.fillEventsQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.FillEvents} ${JSON.stringify(data)}`)); - this.speedUpEventsQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.SpeedUpEvents} ${JSON.stringify(data)}`)); - this.blockNumberQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.BlockNumber} ${JSON.stringify(data)}`)); - this.tokenDetailsQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.TokenDetails} ${JSON.stringify(data)}`)); - this.depositReferralQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.DepositReferral} ${JSON.stringify(data)}`)); - this.tokenPriceQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.TokenPrice} ${JSON.stringify(data)}`)); - this.depositFilledDateQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.DepositFilledDate} ${JSON.stringify(data)}`)); - this.depositAcxPriceQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.DepositAcxPrice} ${JSON.stringify(data)}`)); - this.suggestedFeesQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.SuggestedFees} ${JSON.stringify(data)}`)); - this.trackFillEventsQueue - .getJobCounts() - .then((data) => this.logger.log(`${ScraperQueue.TrackFillEvent} ${JSON.stringify(data)}`)); - }, 1000 * 60); - } } From 6d27e8e18e9a6430343093041eda1f30f4b1aa9a Mon Sep 17 00:00:00 2001 From: Dong-Ha Kim Date: Mon, 9 Jan 2023 12:15:13 +0100 Subject: [PATCH 16/17] refactor: rename ampli events and prop adjustments (#196) --- src/modules/ampli/index.ts | 44 ++++++++----------- .../adapter/amplitude/track-service.ts | 6 +-- .../messaging/TrackFillEventConsumer.ts | 12 +++-- 3 files changed, 26 insertions(+), 36 deletions(-) diff --git a/src/modules/ampli/index.ts b/src/modules/ampli/index.ts index db756607..df74225f 100644 --- a/src/modules/ampli/index.ts +++ b/src/modules/ampli/index.ts @@ -7,7 +7,7 @@ * To update run 'ampli pull scraper' * * Required dependencies: @amplitude/analytics-node@^0.5.0 - * Tracking Plan Version: 30 + * Tracking Plan Version: 32 * Build: 1.0.0 * Runtime: node.js:typescript-ampli-v2 * @@ -37,10 +37,10 @@ export const ApiKey: Record = { */ export const DefaultConfiguration: NodeOptions = { plan: { - version: "30", + version: "32", branch: "main", source: "scraper", - versionId: "0b21d764-e05a-48ac-9da6-95b3efc901dd", + versionId: "e6298d8b-58e2-45e6-a09d-0f244c0489ab", }, ...{ ingestionMetadata: { @@ -117,7 +117,7 @@ export interface IdentifyProperties { walletType?: string; } -export interface TransferTransactionConfirmedProperties { +export interface FillTransactionCompletedProperties { /** * Capital fee percent, in decimals */ @@ -130,8 +130,11 @@ export interface TransferTransactionConfirmedProperties { * Capital fee in USD */ capitalFeeTotalUsd: string; + depositCompleteTimestamp: string; fillAmount: string; fillAmountUsd: string; + fillCompleteTimestamp: string; + fillTime: string; /** * From amount in the bridge token, in decimals */ @@ -141,7 +144,7 @@ export interface TransferTransactionConfirmedProperties { */ fromAmountUsd: string; /** - * From chain id + * Id of the fromChain */ fromChainId: string; /** @@ -225,10 +228,6 @@ export interface TransferTransactionConfirmedProperties { * Result of user signing or rejecting wallet connection */ succeeded: boolean; - /** - * Duration in milliseconds between TransferSigned event to the TransferTransactionCompleted event - */ - timeFromTransferSignedToTransferCompleteInMilliseconds: string; /** * To amount of bridge token, in decimals */ @@ -268,14 +267,9 @@ export interface TransferTransactionConfirmedProperties { */ toTokenAddress: string; /** - * Resulting transaction hash of transaction, null if "result" if TransferTransactionCompleted = failed + * Resulting transaction hash of transaction, null if "result" if SwapSigned event = failed */ transactionHash: string; - /** - * Timestamp transfer completed - */ - transferCompleteTimestamp: string; - transferQuoteBlockNumber: string; } export class Identify implements BaseEvent { @@ -286,10 +280,10 @@ export class Identify implements BaseEvent { } } -export class TransferTransactionConfirmed implements BaseEvent { - event_type = "TransferTransactionConfirmed"; +export class FillTransactionCompleted implements BaseEvent { + event_type = "FillTransactionCompleted"; - constructor(public event_properties: TransferTransactionConfirmedProperties) { + constructor(public event_properties: FillTransactionCompletedProperties) { this.event_properties = event_properties; } } @@ -411,24 +405,22 @@ export class Ampli { } /** - * TransferTransactionConfirmed - * - * [View in Tracking Plan](https://data.amplitude.com/risklabs/Risk%20Labs/events/main/latest/TransferTransactionConfirmed) + * FillTransactionCompleted * - * On-chain transfer completed + * [View in Tracking Plan](https://data.amplitude.com/risklabs/Risk%20Labs/events/main/latest/FillTransactionCompleted) * - * Owner: James Morris + * Owner: Dong-Ha Kim * * @param userId The user's ID. * @param properties The event's properties (e.g. capitalFeePct) * @param options Amplitude event options. */ - transferTransactionConfirmed( + fillTransactionCompleted( userId: string | undefined, - properties: TransferTransactionConfirmedProperties, + properties: FillTransactionCompletedProperties, options?: EventOptions, ) { - return this.track(userId, new TransferTransactionConfirmed(properties), options); + return this.track(userId, new FillTransactionCompleted(properties), options); } } diff --git a/src/modules/scraper/adapter/amplitude/track-service.ts b/src/modules/scraper/adapter/amplitude/track-service.ts index 8814b177..ecb74b66 100644 --- a/src/modules/scraper/adapter/amplitude/track-service.ts +++ b/src/modules/scraper/adapter/amplitude/track-service.ts @@ -1,7 +1,7 @@ import { HttpService } from "@nestjs/axios"; import { Injectable } from "@nestjs/common"; -import { EventOptions, TransferTransactionConfirmedProperties, ampli } from "../../../ampli"; +import { EventOptions, FillTransactionCompletedProperties, ampli } from "../../../ampli"; import { AppConfig } from "../../../configuration/configuration.service"; @Injectable() @@ -22,9 +22,9 @@ export class TrackService { public async trackDepositFilledEvent( userId: string, - eventProperties: TransferTransactionConfirmedProperties, + eventProperties: FillTransactionCompletedProperties, eventOptions?: EventOptions, ) { - return ampli.transferTransactionConfirmed(userId, eventProperties, eventOptions); + return ampli.fillTransactionCompleted(userId, eventProperties, eventOptions); } } diff --git a/src/modules/scraper/adapter/messaging/TrackFillEventConsumer.ts b/src/modules/scraper/adapter/messaging/TrackFillEventConsumer.ts index fc260e28..8df6a058 100644 --- a/src/modules/scraper/adapter/messaging/TrackFillEventConsumer.ts +++ b/src/modules/scraper/adapter/messaging/TrackFillEventConsumer.ts @@ -97,8 +97,11 @@ export class TrackFillEventConsumer { capitalFeePct, capitalFeeTotal: new BigNumber(capitalFeePct).dividedBy(100).multipliedBy(fromAmounts.formattedAmount).toFixed(), capitalFeeTotalUsd: capitalFeeUsd, + depositCompleteTimestamp: String(DateTime.fromJSDate(deposit.depositDate).toMillis()), fillAmount: fillAmounts.formattedAmount, fillAmountUsd: fillAmounts.formattedAmountUsd, + fillCompleteTimestamp: String(DateTime.fromISO(fillTx.date).toMillis()), + fillTime: String(DateTime.fromISO(fillTx.date).diff(DateTime.fromJSDate(deposit.depositDate)).as("milliseconds")), fromAmount: fromAmounts.formattedAmount, fromAmountUsd: fromAmounts.formattedAmountUsd, fromChainId: String(deposit.sourceChainId), @@ -109,7 +112,7 @@ export class TrackFillEventConsumer { lpFeeTotal: formattedLpFeeValues.total, lpFeeTotalUsd: formattedLpFeeValues.totalUsd, NetworkFeeNative: fee, - NetworkFeeNativeToken: destinationChainInfo.nativeSymbol, + NetworkFeeNativeToken: destinationChainInfo.nativeSymbol.toUpperCase(), NetworkFeeUsd: feeUsd, recipient: deposit.recipientAddr, referralProgramAddress: deposit.referralAddress || "-", @@ -123,9 +126,6 @@ export class TrackFillEventConsumer { routeChainNameFromTo: `${sourceChainInfo.name}-${destinationChainInfo.name}`, sender: deposit.depositorAddr, succeeded: true, - timeFromTransferSignedToTransferCompleteInMilliseconds: String( - DateTime.fromISO(fillTx.date).diff(DateTime.fromJSDate(deposit.depositDate)).as("milliseconds"), - ), toAmount: new BigNumber(fromAmounts.formattedAmount).minus(formattedBridgeFeeValues.total).toFixed(), toAmountUsd: new BigNumber(fromAmounts.formattedAmountUsd) .minus(formattedBridgeFeeValues.totalUsd) @@ -133,7 +133,7 @@ export class TrackFillEventConsumer { .toFixed(), toChainId: String(deposit.destinationChainId), toChainName: destinationChainInfo.name, - tokenSymbol: deposit.token.symbol, + tokenSymbol: deposit.token.symbol.toUpperCase(), totalBridgeFee: formattedBridgeFeeValues.total, totalBridgeFeePct: formattedBridgeFeeValues.pct, totalBridgeFeeUsd: formattedBridgeFeeValues.totalUsd, @@ -143,8 +143,6 @@ export class TrackFillEventConsumer { // so we default to `0x0000000000000000000000000000000000000000` toTokenAddress: utils.getAddress(destinationToken || constants.AddressZero), transactionHash: fillTx.hash, - transferCompleteTimestamp: String(DateTime.fromISO(fillTx.date).toMillis()), - transferQuoteBlockNumber: String(fillTxBlockNumber), }); } From 9075a81966bc394c7b776f31bf4fc34901cd1fbb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Jan 2023 23:48:02 +0000 Subject: [PATCH 17/17] build(deps): bump class-validator from 0.13.2 to 0.14.0 Bumps [class-validator](https://github.com/typestack/class-validator) from 0.13.2 to 0.14.0. - [Release notes](https://github.com/typestack/class-validator/releases) - [Changelog](https://github.com/typestack/class-validator/blob/develop/CHANGELOG.md) - [Commits](https://github.com/typestack/class-validator/compare/v0.13.2...v0.14.0) --- updated-dependencies: - dependency-name: class-validator dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 9c19abaa..27b2ea69 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "bull": "^4.8.4", "cache-manager": "^4.0.0", "class-transformer": "^0.5.1", - "class-validator": "^0.13.2", + "class-validator": "^0.14.0", "dotenv": "^16.0.0", "ethers": "^5.6.8", "helmet": "^5.0.2", diff --git a/yarn.lock b/yarn.lock index 25990b8a..6f64d7af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3872,6 +3872,11 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== +"@types/validator@^13.7.10": + version "13.7.10" + resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.7.10.tgz#f9763dc0933f8324920afa9c0790308eedf55ca7" + integrity sha512-t1yxFAR2n0+VO6hd/FJ9F2uezAZVWHLmpmlJzm1eX03+H7+HsuTAp7L8QJs+2pQCfWkP1+EXsGK9Z9v7o/qPVQ== + "@types/yargs-parser@*": version "21.0.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" @@ -6260,12 +6265,13 @@ class-transformer@^0.5.1: resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336" integrity sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw== -class-validator@^0.13.2: - version "0.13.2" - resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.13.2.tgz#64b031e9f3f81a1e1dcd04a5d604734608b24143" - integrity sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw== +class-validator@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.14.0.tgz#40ed0ecf3c83b2a8a6a320f4edb607be0f0df159" + integrity sha512-ct3ltplN8I9fOwUd8GrP8UQixwff129BkEtuWDKL5W45cQuLd19xqmTLu5ge78YDm/fdje6FMt0hGOhl0lii3A== dependencies: - libphonenumber-js "^1.9.43" + "@types/validator" "^13.7.10" + libphonenumber-js "^1.10.14" validator "^13.7.0" clean-stack@^2.0.0: @@ -11735,10 +11741,10 @@ libp2p-crypto@^0.19.0: uint8arrays "^3.0.0" ursa-optional "^0.10.1" -libphonenumber-js@^1.9.43: - version "1.10.7" - resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.7.tgz#4c010b7b57e824c571ea4cdbf7aea6f3c408878c" - integrity sha512-jZXLCCWMe1b/HXkjiLeYt2JsytZMcqH26jLFIdzFDFF0xvSUWrYKyvPlyPG+XJzEyKUFbcZxLdWGMwQsWaHDxQ== +libphonenumber-js@^1.10.14: + version "1.10.18" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.18.tgz#657c419071c8a02c638c0e80d9ee1232f152f280" + integrity sha512-NS4ZEgNhwbcPz1gfSXCGFnQm0xEiyTSPRthIuWytDzOiEG9xnZ2FbLyfJC4tI2BMAAXpoWbNxHYH75pa3Dq9og== lines-and-columns@^1.1.6: version "1.2.4"