"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getOperatorContract = exports.transferTokens = exports.sponsor = exports.unstake = exports.stake = exports.undelegate = exports.delegate = exports.getTestAdminWallet = void 0;
exports.setupOperatorContract = setupOperatorContract;
exports.deployOperatorContract = deployOperatorContract;
exports.deploySponsorshipContract = deploySponsorshipContract;
exports.getProvider = getProvider;
exports.getTestTokenContract = getTestTokenContract;
const config_1 = require("@streamr/config");
const utils_1 = require("@streamr/utils");
const ethers_1 = require("ethers");
const lodash_1 = require("lodash");
const DATAv2Abi_json_1 = __importDefault(require("../ethereumArtifacts/DATAv2Abi.json"));
const OperatorAbi_json_1 = __importDefault(require("../ethereumArtifacts/OperatorAbi.json"));
const OperatorFactoryAbi_json_1 = __importDefault(require("../ethereumArtifacts/OperatorFactoryAbi.json"));
const SponsorshipAbi_json_1 = __importDefault(require("../ethereumArtifacts/SponsorshipAbi.json"));
const SponsorshipFactoryAbi_json_1 = __importDefault(require("../ethereumArtifacts/SponsorshipFactoryAbi.json"));
const TEST_CHAIN_CONFIG = config_1.config.dev2;
const FRACTION_MAX = (0, ethers_1.parseEther)('1');
const logger = new utils_1.Logger(module);
async function setupOperatorContract(opts) {
    const operatorWallet = await opts.createTestWallet({ gas: true, tokens: true });
    const operatorContract = await deployOperatorContract({
        deployer: operatorWallet,
        operatorsCutPercentage: opts?.operatorConfig?.operatorsCutPercentage,
        metadata: opts?.operatorConfig?.metadata
    });
    const nodeWallets = [];
    if ((opts?.nodeCount !== undefined) && (opts?.nodeCount > 0)) {
        for (const _ of (0, lodash_1.range)(opts.nodeCount)) {
            nodeWallets.push(await opts.createTestWallet({ gas: true, tokens: true }));
        }
        await (await operatorContract.setNodeAddresses(nodeWallets.map((w) => w.address))).wait();
    }
    return { operatorWallet, operatorContract, nodeWallets };
}
/**
 * @param opts.deployer should be the operator's Wallet
 * @returns Operator
 */
async function deployOperatorContract(opts) {
    logger.debug('Deploying OperatorContract');
    const abi = OperatorFactoryAbi_json_1.default;
    const operatorFactory = new ethers_1.Contract(TEST_CHAIN_CONFIG.contracts.OperatorFactory, abi, opts.deployer);
    const contractAddress = await operatorFactory.operators(opts.deployer.address);
    if (contractAddress !== ethers_1.ZeroAddress) {
        throw new Error('Operator already has a contract');
    }
    const operatorReceipt = await (await operatorFactory.deployOperator((0, utils_1.multiplyWeiAmount)(FRACTION_MAX, ((opts.operatorsCutPercentage ?? 0) / 100)), opts.operatorTokenName ?? `OperatorToken-${Date.now()}`, opts.metadata ?? '', [
        TEST_CHAIN_CONFIG.contracts.OperatorDefaultDelegationPolicy,
        TEST_CHAIN_CONFIG.contracts.OperatorDefaultExchangeRatePolicy,
        TEST_CHAIN_CONFIG.contracts.OperatorDefaultUndelegationPolicy,
    ], [
        0,
        0,
        0,
    ])).wait();
    const newSponsorshipEvent = operatorReceipt.logs.find((l) => l.fragment?.name === 'NewOperator');
    const newOperatorAddress = newSponsorshipEvent.args.operatorContractAddress;
    const newOperator = new ethers_1.Contract(newOperatorAddress, OperatorAbi_json_1.default, opts.deployer);
    logger.debug('Deployed OperatorContract', { address: newOperatorAddress });
    return newOperator;
}
async function deploySponsorshipContract(opts) {
    logger.debug('Deploying SponsorshipContract');
    const sponsorshipFactory = new ethers_1.Contract(TEST_CHAIN_CONFIG.contracts.SponsorshipFactory, SponsorshipFactoryAbi_json_1.default, opts.deployer);
    const sponsorshipDeployTx = await sponsorshipFactory.deploySponsorship((opts.minOperatorCount ?? 1).toString(), opts.streamId, opts.metadata ?? '{}', [
        TEST_CHAIN_CONFIG.contracts.SponsorshipStakeWeightedAllocationPolicy,
        TEST_CHAIN_CONFIG.contracts.SponsorshipDefaultLeavePolicy,
        TEST_CHAIN_CONFIG.contracts.SponsorshipVoteKickPolicy,
    ], [
        opts.earningsPerSecond ?? (0, ethers_1.parseEther)('1'),
        '0',
        '0',
    ]);
    const sponsorshipDeployReceipt = await sponsorshipDeployTx.wait();
    const newSponsorshipEvent = sponsorshipDeployReceipt.logs.find((l) => l.fragment?.name === 'NewSponsorship');
    const newSponsorshipAddress = newSponsorshipEvent.args.sponsorshipContract;
    const newSponsorship = new ethers_1.Contract(newSponsorshipAddress, SponsorshipAbi_json_1.default, opts.deployer);
    logger.debug('Deployed SponsorshipContract', { address: newSponsorshipAddress });
    return newSponsorship;
}
function getProvider() {
    return new ethers_1.JsonRpcProvider(TEST_CHAIN_CONFIG.rpcEndpoints[0].url, undefined, {
        batchStallTime: 0, // Don't batch requests, send them immediately
        cacheTimeout: -1 // Do not employ result caching
    });
}
function getTestTokenContract() {
    return new ethers_1.Contract(TEST_CHAIN_CONFIG.contracts.DATA, DATAv2Abi_json_1.default);
}
const getTestAdminWallet = (adminKey, provider) => {
    return new ethers_1.Wallet(adminKey ?? TEST_CHAIN_CONFIG.adminPrivateKey).connect(provider ?? getProvider());
};
exports.getTestAdminWallet = getTestAdminWallet;
const delegate = async (delegator, operatorContractAddress, amount, token) => {
    logger.debug('Delegate', { amount: amount.toString() });
    // onTokenTransfer: the tokens are delegated on behalf of the given data address
    // eslint-disable-next-line max-len
    // https://github.com/streamr-dev/network-contracts/blob/01ec980cfe576e25e8c9acc08a57e1e4769f3e10/packages/network-contracts/contracts/OperatorTokenomics/Operator.sol#L233
    await (0, exports.transferTokens)(delegator, operatorContractAddress, amount, await delegator.getAddress(), token);
};
exports.delegate = delegate;
const undelegate = async (delegator, operatorContract, amount) => {
    await (await operatorContract.connect(delegator).undelegate(amount)).wait();
};
exports.undelegate = undelegate;
const stake = async (operatorContract, sponsorshipContractAddress, amount) => {
    logger.debug('Stake', { amount: amount.toString() });
    await (await operatorContract.stake(sponsorshipContractAddress, amount)).wait();
};
exports.stake = stake;
const unstake = async (operatorContract, sponsorshipContractAddress) => {
    logger.debug('Unstake');
    await (await operatorContract.unstake(sponsorshipContractAddress)).wait();
};
exports.unstake = unstake;
const sponsor = async (sponsorer, sponsorshipContractAddress, amount, token) => {
    logger.debug('Sponsor', { amount: amount.toString() });
    // eslint-disable-next-line max-len
    // https://github.com/streamr-dev/network-contracts/blob/01ec980cfe576e25e8c9acc08a57e1e4769f3e10/packages/network-contracts/contracts/OperatorTokenomics/Sponsorship.sol#L139
    await (0, exports.transferTokens)(sponsorer, sponsorshipContractAddress, amount, undefined, token);
};
exports.sponsor = sponsor;
const transferTokens = async (from, to, amount, data, token) => {
    const tx = await ((token ?? getTestTokenContract()).connect(from).transferAndCall(to, amount, data ?? '0x'));
    await tx.wait();
};
exports.transferTokens = transferTokens;
const getOperatorContract = (operatorAddress) => {
    return new ethers_1.Contract(operatorAddress, OperatorAbi_json_1.default);
};
exports.getOperatorContract = getOperatorContract;
//# sourceMappingURL=operatorContractUtils.js.map