"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.fetchBrnBalance = fetchBrnBalance;
exports.fetchExplicitBRN = fetchExplicitBRN;
exports.fetchTotalBrn = fetchTotalBrn;
exports.fetchUserAndExecutorFlags = fetchUserAndExecutorFlags;
const tslib_1 = require("tslib");
const axios_1 = tslib_1.__importDefault(require("axios"));
const axios_retry_1 = tslib_1.__importDefault(require("axios-retry"));
const node_https_1 = tslib_1.__importDefault(require("node:https"));
const ethers_1 = require("ethers");
const logger_1 = require("./logger");
const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
const sync_1 = require("csv-parse/sync");
const node_path_1 = tslib_1.__importDefault(require("node:path"));
const BASE_URLS = {
    v1: 'https://brn.explorer.caldera.xyz/api/v2/addresses/',
    v2: 'https://b2n.explorer.caldera.xyz/api/v2/addresses/',
};
const client = axios_1.default.create({
    timeout: 10_000,
    httpsAgent: new node_https_1.default.Agent({ keepAlive: false }),
    headers: {
        accept: '*/*',
        'user-agent': 'Mozilla/5.0',
    },
});
(0, axios_retry_1.default)(client, {
    retries: 5,
    retryDelay: (...args) => axios_retry_1.default.exponentialDelay(...args),
    retryCondition: (error) => axios_retry_1.default.isNetworkOrIdempotentRequestError(error) ||
        (typeof error.response?.status === 'number' && [429, 500, 502, 503, 504].includes(error.response.status)),
    onRetry: (retryCount, error, reqConfig) => {
        console.warn(`axios-retry: retrying [${reqConfig.url}] (${retryCount}) due to: ${error.message}`);
    },
});
function isValidAddress(addr) {
    try {
        return ethers_1.ethers.utils.isAddress(addr);
    }
    catch {
        return false;
    }
}
function toEther(balance) {
    try {
        if (!balance || isNaN(balance))
            return '0';
        return ethers_1.ethers.utils.formatEther(balance.toString());
    }
    catch {
        return '0';
    }
}
async function fetchBrnBalance(address, version) {
    if (!isValidAddress(address))
        return '0';
    const url = BASE_URLS[version] + address;
    try {
        const { data } = await client.get(url);
        if (data && data.hash) {
            return toEther(data.coin_balance);
        }
        return '0';
    }
    catch (e) {
        if (e?.response?.status === 400 || e?.response?.status === 404)
            return '0';
        console.warn(`fetchBrnBalance error (${version}/${address}): ${e.message || e}`);
        return '0';
    }
}
async function fetchArbitrumSepoliaBRNBalance(address, config) {
    if (!ethers_1.ethers.utils.isAddress(address))
        return '0';
    const BRN_ARB_ADDRESS = '0x2e76CA39c9bd8d99B2681A60319fC0FE7C9d8336';
    const PUBLIC_RPC = 'https://arbitrum-sepolia-rpc.publicnode.com';
    try {
        const networkConfig = config.networks['arbitrum-sepolia'];
        if (!networkConfig) {
            logger_1.logger.warn({ address }, 'Network config arbitrum-sepolia for BRN balance could not be found');
            return '0';
        }
        let rpcUrl;
        if (!Array.isArray(networkConfig.rpcEndpoints) || !networkConfig.rpcEndpoints[0]) {
            (0, logger_1.batchLogger)({ source: networkConfig.id }, 'No valid rpcEndpoints for arbitrum-sepolia in config. Using public RPC');
            rpcUrl = PUBLIC_RPC;
        }
        else {
            rpcUrl = networkConfig.rpcEndpoints[0];
        }
        const provider = new ethers_1.ethers.providers.JsonRpcProvider(rpcUrl);
        const brnContract = new ethers_1.ethers.Contract(BRN_ARB_ADDRESS, ['function balanceOf(address owner) view returns (uint256)'], provider);
        const balance = await brnContract.balanceOf(address);
        return ethers_1.ethers.utils.formatEther(balance);
    }
    catch (e) {
        logger_1.logger.warn({ error: e.message, address }, 'Could not fetch Arbitrum Sepolia BRN balance');
        return '0';
    }
}
async function fetchExplicitBRN(address, config) {
    try {
        const [v1, v2, arb] = await Promise.allSettled([
            fetchBrnBalance(address, 'v1'),
            fetchBrnBalance(address, 'v2'),
            fetchArbitrumSepoliaBRNBalance(address, config),
        ]);
        const brnV1 = v1.status === 'fulfilled' ? parseFloat(v1.value) : 0;
        const brnV2 = v2.status === 'fulfilled' ? parseFloat(v2.value) : 0;
        const brnArb = arb.status === 'fulfilled' ? parseFloat(arb.value) : 0;
        const total = brnV1 + brnV2 + brnArb;
        return { total, v1: brnV1, v2: brnV2, arbt: brnArb };
    }
    catch {
        return { total: 0, v1: 0, v2: 0, arbt: 0 };
    }
}
async function fetchTotalBrn(address, config) {
    try {
        const [v1, v2, arb] = await Promise.allSettled([
            fetchBrnBalance(address, 'v1'),
            fetchBrnBalance(address, 'v2'),
            fetchArbitrumSepoliaBRNBalance(address, config),
        ]);
        const brnV1 = v1.status === 'fulfilled' ? parseFloat(v1.value) : 0;
        const brnV2 = v2.status === 'fulfilled' ? parseFloat(v2.value) : 0;
        const brnArb = arb.status === 'fulfilled' ? parseFloat(arb.value) : 0;
        return brnV1 + brnV2 + brnArb;
    }
    catch {
        return 0;
    }
}
function fetchUserAndExecutorFlags(address) {
    const csvPath = node_path_1.default.join(process.cwd(), 'src', 'sybils.csv');
    if (!node_fs_1.default.existsSync(csvPath)) {
        logger_1.logger.error('CSV file required but not found');
        return { v1User: false, v1Executor: false, v2User: false, v2Executor: false };
    }
    const csvContent = node_fs_1.default.readFileSync(csvPath, 'utf-8');
    const records = (0, sync_1.parse)(csvContent, { columns: true, trim: true });
    const normAddress = address.toLowerCase();
    for (const row of records) {
        const csvAddress = row.Address;
        if (csvAddress && ethers_1.ethers.utils.isAddress(csvAddress) && csvAddress.toLowerCase() === normAddress) {
            return {
                v1User: row.v1_user === '1',
                v1Executor: row.v1_executor === '1',
                v2User: row.v2_user === '1',
                v2Executor: row.v2_executor === '1',
            };
        }
    }
    return { v1User: false, v1Executor: false, v2User: false, v2Executor: false };
}
//# sourceMappingURL=sybils.js.map