"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RateLimitedProvider = void 0;
const tslib_1 = require("tslib");
const async_1 = require("async");
const ethers_1 = require("ethers");
const NetworkUtils_1 = require("../utils/NetworkUtils");
const winston_1 = tslib_1.__importDefault(require("winston"));
class RateLimitedProvider extends ethers_1.ethers.providers.StaticJsonRpcProvider {
    pctRpcCallsLogged;
    logger;
    queue;
    constructor(maxConcurrency, pctRpcCallsLogged, logger = winston_1.default.createLogger({
        transports: [new winston_1.default.transports.Console()],
    }), ...cacheConstructorParams) {
        super(...cacheConstructorParams);
        this.pctRpcCallsLogged = pctRpcCallsLogged;
        this.logger = logger;
        this.queue = (0, async_1.queue)(async ({ sendArgs, resolve, reject }, callback) => {
            await this.wrapSendWithLog(...sendArgs)
                .then(resolve)
                .catch(reject);
            callback();
        }, maxConcurrency);
    }
    async wrapSendWithLog(method, params) {
        if (this.pctRpcCallsLogged <= 0 || Math.random() > this.pctRpcCallsLogged / 100) {
            return super.send(method, params);
        }
        else {
            const loggerArgs = {
                at: "ProviderUtils",
                message: "Provider response sample",
                provider: (0, NetworkUtils_1.getOriginFromURL)(this.connection.url),
                method,
                params,
                chainId: this.network.chainId,
                datadog: true,
            };
            const startTime = performance.now();
            try {
                const result = await super.send(method, params);
                const elapsedTimeS = (performance.now() - startTime) / 1000;
                this.logger.debug({
                    ...loggerArgs,
                    success: true,
                    timeElapsed: elapsedTimeS,
                });
                return result;
            }
            catch (error) {
                const elapsedTimeS = (performance.now() - startTime) / 1000;
                this.logger.debug({
                    ...loggerArgs,
                    success: false,
                    timeElapsed: elapsedTimeS,
                });
                throw error;
            }
        }
    }
    send(method, params) {
        return new Promise((resolve, reject) => {
            const task = {
                sendArgs: [method, params],
                resolve,
                reject,
            };
            void this.queue.push(task);
        });
    }
}
exports.RateLimitedProvider = RateLimitedProvider;
//# sourceMappingURL=rateLimitedProvider.js.map