"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AutomaticTokenBridgeRoute = void 0;
const sdk_base_1 = require("@wormhole-foundation/sdk-base");
const sdk_definitions_1 = require("@wormhole-foundation/sdk-definitions");
const tokenTransfer_1 = require("../../protocols/tokenTransfer");
const types_1 = require("../../types");
const route_1 = require("../route");
class AutomaticTokenBridgeRoute extends route_1.AutomaticRoute {
    NATIVE_GAS_DROPOFF_SUPPORTED = true;
    static meta = {
        name: "AutomaticTokenBridge",
    };
    static supportedNetworks() {
        return ["Mainnet", "Testnet"];
    }
    // get the list of chains this route supports
    static supportedChains(network) {
        if (sdk_base_1.contracts.tokenBridgeRelayerChains.has(network)) {
            return sdk_base_1.contracts.tokenBridgeRelayerChains.get(network);
        }
        return [];
    }
    // get the list of source tokens that are possible to send
    static async supportedSourceTokens(fromChain) {
        const atb = await fromChain.getAutomaticTokenBridge();
        const registered = await atb.getRegisteredTokens();
        return [
            (0, sdk_definitions_1.nativeTokenId)(fromChain.chain),
            ...registered.map((v) => {
                return { chain: fromChain.chain, address: v };
            }),
        ];
    }
    // get the list of destination tokens that may be recieved on the destination chain
    static async supportedDestinationTokens(sourceToken, fromChain, toChain) {
        return [await tokenTransfer_1.TokenTransfer.lookupDestinationToken(fromChain, toChain, sourceToken)];
    }
    static isProtocolSupported(chain) {
        return chain.supportsAutomaticTokenBridge();
    }
    getDefaultOptions() {
        return { nativeGas: 0.0 };
    }
    async isAvailable() {
        const atb = await this.request.fromChain.getAutomaticTokenBridge();
        if ((0, sdk_definitions_1.isTokenId)(this.request.source.id)) {
            return await atb.isRegisteredToken(this.request.source.id.address);
        }
        return true;
    }
    async validate(params) {
        try {
            const options = params.options ?? this.getDefaultOptions();
            if (options.nativeGas && (options.nativeGas > 1.0 || options.nativeGas < 0.0))
                throw new Error("Native gas must be between 0.0 and 1.0 (0% and 100%)");
            // If destination is native, max out the nativeGas requested
            const { destination } = this.request;
            if ((0, sdk_definitions_1.isNative)(destination.id.address) && options.nativeGas === 0.0)
                options.nativeGas = 1.0;
            const updatedParams = { ...params, options };
            const validatedParams = {
                ...updatedParams,
                normalizedParams: await this.normalizeTransferParams(updatedParams),
            };
            return { valid: true, params: validatedParams };
        }
        catch (e) {
            return { valid: false, params, error: e };
        }
    }
    async normalizeTransferParams(params) {
        const amt = this.request.parseAmount(params.amount);
        const inputToken = (0, sdk_definitions_1.isNative)(this.request.source.id.address)
            ? await this.request.fromChain.getNativeWrappedTokenId()
            : this.request.source.id;
        const atb = await this.request.fromChain.getAutomaticTokenBridge();
        const fee = await atb.getRelayerFee(this.request.from.address, this.request.to, inputToken.address);
        // Min amount is fee + 5%
        const minAmount = (fee * 105n) / 100n;
        if (sdk_base_1.amount.units(amt) < minAmount) {
            throw new Error(`Minimum amount is ${sdk_base_1.amount.display({
                amount: minAmount.toString(),
                decimals: amt.decimals,
            })}`);
        }
        const redeemableAmount = sdk_base_1.amount.units(amt) - fee;
        // Determine nativeGas
        let nativeGasAmount = 0n;
        if (params.options && params.options.nativeGas > 0) {
            const scale = 10000;
            const scaledGas = BigInt(params.options.nativeGas * scale);
            nativeGasAmount = (redeemableAmount * scaledGas) / BigInt(scale);
        }
        return {
            fee: sdk_base_1.amount.fromBaseUnits(fee, this.request.source.decimals),
            amount: amt,
            nativeGasAmount: sdk_base_1.amount.fromBaseUnits(nativeGasAmount, this.request.source.decimals),
        };
    }
    async quote(params) {
        try {
            let quote = await tokenTransfer_1.TokenTransfer.quoteTransfer(this.request.fromChain, this.request.toChain, this.toTransferDetails(params));
            return this.request.displayQuote(quote, params);
        }
        catch (e) {
            return {
                success: false,
                error: e,
            };
        }
    }
    async initiate(signer, quote) {
        const { params } = quote;
        const transfer = this.toTransferDetails(params);
        const txids = await tokenTransfer_1.TokenTransfer.transfer(this.request.fromChain, transfer, signer);
        const msg = await tokenTransfer_1.TokenTransfer.getTransferMessage(this.request.fromChain, txids[txids.length - 1].txid);
        return {
            from: transfer.from.chain,
            to: transfer.to.chain,
            state: types_1.TransferState.SourceFinalized,
            originTxs: txids,
            attestation: { id: msg },
        };
    }
    async *track(receipt, timeout) {
        yield* tokenTransfer_1.TokenTransfer.track(this.wh, receipt, timeout, this.request.fromChain, this.request.toChain);
    }
    toTransferDetails(params) {
        const transfer = {
            automatic: true,
            from: this.request.from,
            to: this.request.to,
            amount: sdk_base_1.amount.units(params.normalizedParams.amount),
            token: this.request.source.id,
            nativeGas: sdk_base_1.amount.units(params.normalizedParams.nativeGasAmount),
        };
        return transfer;
    }
}
exports.AutomaticTokenBridgeRoute = AutomaticTokenBridgeRoute;
//# sourceMappingURL=automatic.js.map