var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { IWormholeRelayer__factory } from "../../ethers-contracts";
import { toChainName } from "../../utils";
import { parseVaa } from "../../vaa";
import { getWormholeRelayerAddress } from "../consts";
import { RelayerPayloadId, packOverrides, parseEVMExecutionInfoV1, parseWormholeRelayerPayloadType, parseWormholeRelayerSend, } from "../structs";
import { getSignedVAAWithRetry } from "../../rpc";
export function deliver(deliveryVaa, signer, wormholeRPCs, environment = "MAINNET", overrides) {
    return __awaiter(this, void 0, void 0, function* () {
        const { budget, deliveryInstruction, deliveryHash } = extractDeliveryArguments(deliveryVaa, overrides);
        const additionalVaas = yield fetchAdditionalVaas(wormholeRPCs, deliveryInstruction.vaaKeys);
        const wormholeRelayerAddress = getWormholeRelayerAddress(toChainName(deliveryInstruction.targetChainId), environment);
        const wormholeRelayer = IWormholeRelayer__factory.connect(wormholeRelayerAddress, signer);
        const gasEstimate = yield wormholeRelayer.estimateGas.deliver(additionalVaas, deliveryVaa, signer.getAddress(), overrides ? packOverrides(overrides) : new Uint8Array(), { value: budget });
        const tx = yield wormholeRelayer.deliver(additionalVaas, deliveryVaa, signer.getAddress(), overrides ? packOverrides(overrides) : new Uint8Array(), { value: budget, gasLimit: gasEstimate.mul(2) });
        const rx = yield tx.wait();
        console.log(`Delivered ${deliveryHash} on ${rx.blockNumber}`);
        return rx;
    });
}
export function deliveryBudget(delivery, overrides) {
    const receiverValue = (overrides === null || overrides === void 0 ? void 0 : overrides.newReceiverValue)
        ? overrides.newReceiverValue
        : delivery.requestedReceiverValue.add(delivery.extraReceiverValue);
    const getMaxRefund = (encodedDeliveryInfo) => {
        const [deliveryInfo] = parseEVMExecutionInfoV1(encodedDeliveryInfo, 0);
        return deliveryInfo.targetChainRefundPerGasUnused.mul(deliveryInfo.gasLimit);
    };
    const maxRefund = getMaxRefund((overrides === null || overrides === void 0 ? void 0 : overrides.newExecutionInfo)
        ? overrides.newExecutionInfo
        : delivery.encodedExecutionInfo);
    return receiverValue.add(maxRefund);
}
export function extractDeliveryArguments(vaa, overrides) {
    const parsedVaa = parseVaa(vaa);
    const payloadType = parseWormholeRelayerPayloadType(parsedVaa.payload);
    if (payloadType !== RelayerPayloadId.Delivery) {
        throw new Error(`Expected delivery payload type, got ${RelayerPayloadId[payloadType]}`);
    }
    const deliveryInstruction = parseWormholeRelayerSend(parsedVaa.payload);
    const budget = deliveryBudget(deliveryInstruction, overrides);
    return {
        budget,
        deliveryInstruction: deliveryInstruction,
        deliveryHash: parsedVaa.hash.toString("hex"),
    };
}
export function fetchAdditionalVaas(wormholeRPCs, additionalVaaKeys) {
    return __awaiter(this, void 0, void 0, function* () {
        const rpcs = typeof wormholeRPCs === "string" ? [wormholeRPCs] : wormholeRPCs;
        const vaas = yield Promise.all(additionalVaaKeys.map((vaaKey) => __awaiter(this, void 0, void 0, function* () {
            return getSignedVAAWithRetry(rpcs, vaaKey.chainId, vaaKey.emitterAddress.toString("hex"), vaaKey.sequence.toBigInt().toString());
        })));
        return vaas.map((vaa) => vaa.vaaBytes);
    });
}
