"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MockSvmCpiEventsClient = void 0;
const tslib_1 = require("tslib");
const assert_1 = tslib_1.__importDefault(require("assert"));
const ethers_1 = require("ethers");
const crypto_1 = require("crypto");
const utils_1 = require("ethers/lib/utils");
const lodash_1 = require("lodash");
const kit_1 = require("@solana/kit");
const contracts_1 = require("@across-protocol/contracts");
const constants_1 = require("@across-protocol/constants");
const mocks_1 = require("../../providers/mocks");
const svm_1 = require("../../arch/svm");
const utils_2 = require("../../utils");
const interfaces_1 = require("../../interfaces");
const randomBytes = (n) => ethers_1.utils.hexlify(ethers_1.utils.randomBytes(n));
class MockSvmCpiEventsClient extends svm_1.SvmCpiEventsClient {
    events = {};
    slotHeight = BigInt(0);
    chainId;
    minBlockRange = 10;
    numberOfDeposits = utils_2.bnZero;
    constructor(programId = contracts_1.SvmSpokeClient.SVM_SPOKE_PROGRAM_ADDRESS, chainId = constants_1.CHAIN_IDs.SOLANA) {
        super(null, programId, null, null);
        this.chainId = chainId;
    }
    setSlotHeight(slotHeight) {
        this.slotHeight = slotHeight;
    }
    setEvents(events) {
        for (const event of events) {
            this.events[event.name] ??= [];
            this.events[event.name].push(event);
        }
        const maxSlot = Math.max(...events.map((event) => Number(event.slot)));
        this.setSlotHeight(BigInt(maxSlot) + BigInt(1));
    }
    clearEvents(name) {
        if (name) {
            this.events[name] = [];
        }
        else {
            this.events = {};
        }
    }
    queryEvents(eventName, fromSlot, toSlot) {
        return Promise.resolve(this.events[eventName]?.filter((event) => (!fromSlot || event.slot >= fromSlot) && (!toSlot || event.slot <= toSlot)) ?? []);
    }
    getRpc() {
        const client = new mocks_1.MockSolanaRpcFactory("https://test.com", 1234567890);
        client.setResult("getSlot", [], this.slotHeight);
        return client.createRpcClient();
    }
    deposit(deposit) {
        const { slot } = deposit;
        let { depositId, destinationChainId, inputAmount, outputAmount } = deposit;
        depositId ??= (0, utils_1.arrayify)((0, utils_1.hexZeroPad)((0, utils_1.hexlify)((0, lodash_1.random)(1, 100_000, false)), 32));
        this.numberOfDeposits = this.numberOfDeposits.add(utils_2.bnOne);
        destinationChainId ??= BigInt((0, lodash_1.random)(1, 42161, false));
        const depositor = deposit.depositor ?? (0, svm_1.getRandomSvmAddress)();
        const recipient = deposit.recipient ?? utils_2.SvmAddress.from(randomBytes(32)).toBase58();
        const inputToken = deposit.inputToken ?? (0, svm_1.getRandomSvmAddress)();
        const outputToken = deposit.outputToken ?? utils_2.SvmAddress.from(randomBytes(32)).toBase58();
        inputAmount ??= BigInt((0, lodash_1.random)(1, 1000, false));
        outputAmount ??= (0, svm_1.bigToU8a32)((inputAmount * BigInt(95)) / BigInt(100));
        const message = deposit.message ?? new Uint8Array(32);
        const quoteTimestamp = deposit.quoteTimestamp ?? (0, utils_2.getCurrentTime)();
        const args = {
            depositId,
            destinationChainId,
            depositor,
            recipient,
            inputToken,
            inputAmount,
            outputToken,
            outputAmount,
            quoteTimestamp,
            fillDeadline: deposit.fillDeadline ?? quoteTimestamp + 3600,
            exclusiveRelayer: deposit.exclusiveRelayer ?? svm_1.SVM_DEFAULT_ADDRESS,
            exclusivityDeadline: deposit.exclusivityDeadline ?? quoteTimestamp + 600,
            message,
        };
        return this.generateEvent({
            event: svm_1.SVMEventNames.FundsDeposited,
            address: this.getProgramAddress(),
            args,
            slot,
        });
    }
    fillRelay(fill) {
        const { slot } = fill;
        let { depositId, inputAmount, outputAmount, fillDeadline } = fill;
        depositId ??= (0, utils_1.arrayify)((0, utils_1.hexZeroPad)((0, utils_1.hexlify)((0, lodash_1.random)(1, 100_000, false)), 32));
        const inputAmountBigInt = BigInt((0, lodash_1.random)(1, 1000, false));
        inputAmount ??= (0, svm_1.bigToU8a32)(inputAmountBigInt);
        outputAmount ??= (inputAmountBigInt * BigInt(95)) / BigInt(100);
        fillDeadline ??= (0, utils_2.getCurrentTime)() + 60;
        const depositor = fill.depositor ?? utils_2.EvmAddress.from((0, utils_2.randomAddress)()).toBase58();
        const recipient = fill.recipient ?? (0, svm_1.getRandomSvmAddress)();
        const inputToken = fill.inputToken ?? utils_2.EvmAddress.from((0, utils_2.randomAddress)()).toBase58();
        const outputToken = fill.outputToken ?? (0, svm_1.getRandomSvmAddress)();
        const messageHash = fill.messageHash ?? new Uint8Array(32);
        const relayExecutionInfo = {
            updatedRecipient: fill.relayExecutionInfo?.updatedRecipient ?? recipient,
            updatedOutputAmount: fill.relayExecutionInfo?.updatedOutputAmount ?? outputAmount,
            fillType: fill.relayExecutionInfo?.fillType ?? interfaces_1.FillType.FastFill,
            updatedMessageHash: fill.relayExecutionInfo?.updatedMessageHash ?? messageHash,
        };
        const args = {
            depositId,
            originChainId: fill.originChainId ?? BigInt((0, lodash_1.random)(1, 42161, false)),
            depositor,
            recipient,
            inputToken,
            inputAmount,
            outputToken,
            outputAmount,
            fillDeadline,
            exclusiveRelayer: fill.exclusiveRelayer ?? svm_1.SVM_DEFAULT_ADDRESS,
            exclusivityDeadline: fill.exclusivityDeadline ?? fillDeadline,
            relayer: fill.relayer ?? (0, svm_1.getRandomSvmAddress)(),
            messageHash,
            relayExecutionInfo,
        };
        return this.generateEvent({
            event: svm_1.SVMEventNames.FilledRelay,
            address: this.getProgramAddress(),
            args,
            slot,
        });
    }
    requestSlowFill(slowFillRequest) {
        const { slot } = slowFillRequest;
        let { depositId, originChainId } = slowFillRequest;
        depositId ??= Uint8Array.from([(0, lodash_1.random)(1, 100_000, false)]);
        originChainId ??= BigInt((0, lodash_1.random)(1, 42161, false));
        const depositor = slowFillRequest.depositor ?? utils_2.SvmAddress.from(randomBytes(32)).toBase58();
        const recipient = slowFillRequest.recipient ?? (0, svm_1.getRandomSvmAddress)();
        const inputToken = slowFillRequest.inputToken ?? utils_2.SvmAddress.from(randomBytes(32)).toBase58();
        const outputToken = slowFillRequest.outputToken ?? (0, svm_1.getRandomSvmAddress)();
        const args = {
            ...slowFillRequest,
            depositId,
            originChainId,
            depositor,
            recipient,
            inputToken,
            outputToken,
            inputAmount: slowFillRequest.inputAmount ?? BigInt((0, lodash_1.random)(1, 1000, false)),
            outputAmount: slowFillRequest.outputAmount ?? slowFillRequest.inputAmount ?? BigInt((0, lodash_1.random)(1, 1000, false)),
            exclusiveRelayer: slowFillRequest.exclusiveRelayer ?? svm_1.SVM_DEFAULT_ADDRESS,
        };
        return this.generateEvent({
            event: svm_1.SVMEventNames.RequestedSlowFill,
            address: this.getProgramAddress(),
            args,
            slot,
        });
    }
    generateEvent(inputs) {
        const { address, event, args } = inputs;
        let { slot } = inputs;
        const randomSlotWithinRange = () => (0, lodash_1.random)(Number(this.slotHeight) + 1, Number(this.slotHeight) + this.minBlockRange, false);
        slot ??= BigInt(randomSlotWithinRange());
        (0, assert_1.default)(slot >= this.slotHeight, `${slot} < ${this.slotHeight}`);
        this.slotHeight = slot;
        const generatedEvent = {
            name: event,
            slot,
            signature: (0, kit_1.signature)(utils_2.bs58.encode(Uint8Array.from((0, crypto_1.createHash)("sha512")
                .update(`Across-${event}-${slot}-${(0, lodash_1.random)(1, 100_000)}`)
                .digest()))),
            program: address,
            data: args,
            confirmationStatus: "finalized",
            blockTime: BigInt(new Date().getTime()),
        };
        this.setEvents([generatedEvent]);
        return generatedEvent;
    }
}
exports.MockSvmCpiEventsClient = MockSvmCpiEventsClient;
//# sourceMappingURL=MockSvmCpiEventsClient.js.map