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 { SUI_CLOCK_OBJECT_ID, TransactionBlock, } from "@mysten/sui.js";
import { PublicKey, Transaction, } from "@solana/web3.js";
import { MsgExecuteContract } from "@terra-money/terra.js";
import { MsgExecuteContract as XplaMsgExecuteContract } from "@xpla/xpla.js";
import BN from "bn.js";
import { fromUint8Array } from "js-base64";
import { _submitVAAAlgorand } from "../algorand";
import { createWrappedCoin as createWrappedCoinAptos, createWrappedCoinType as createWrappedCoinTypeAptos, } from "../aptos";
import { Bridge__factory } from "../ethers-contracts";
import { createCreateWrappedInstruction } from "../solana/tokenBridge";
import { getWrappedCoinType, publishCoin } from "../sui";
import { callFunctionNear, uint8ArrayToHex } from "../utils";
import { submitVAAOnInjective } from "./redeem";
export function createWrappedOnEth(tokenBridgeAddress, signer, signedVAA, overrides = {}) {
    return __awaiter(this, void 0, void 0, function* () {
        const bridge = Bridge__factory.connect(tokenBridgeAddress, signer);
        const v = yield bridge.createWrapped(signedVAA, overrides);
        const receipt = yield v.wait();
        return receipt;
    });
}
export function createWrappedOnTerra(tokenBridgeAddress, walletAddress, signedVAA) {
    return __awaiter(this, void 0, void 0, function* () {
        return new MsgExecuteContract(walletAddress, tokenBridgeAddress, {
            submit_vaa: {
                data: fromUint8Array(signedVAA),
            },
        });
    });
}
export const createWrappedOnInjective = submitVAAOnInjective;
export function createWrappedOnXpla(tokenBridgeAddress, walletAddress, signedVAA) {
    return new XplaMsgExecuteContract(walletAddress, tokenBridgeAddress, {
        submit_vaa: {
            data: fromUint8Array(signedVAA),
        },
    });
}
export function createWrappedOnSolana(connection, bridgeAddress, tokenBridgeAddress, payerAddress, signedVaa, commitment) {
    return __awaiter(this, void 0, void 0, function* () {
        const transaction = new Transaction().add(createCreateWrappedInstruction(tokenBridgeAddress, bridgeAddress, payerAddress, signedVaa));
        const { blockhash } = yield connection.getLatestBlockhash(commitment);
        transaction.recentBlockhash = blockhash;
        transaction.feePayer = new PublicKey(payerAddress);
        return transaction;
    });
}
export function createWrappedOnAlgorand(client, tokenBridgeId, bridgeId, senderAddr, attestVAA) {
    return __awaiter(this, void 0, void 0, function* () {
        return yield _submitVAAAlgorand(client, tokenBridgeId, bridgeId, attestVAA, senderAddr);
    });
}
export function createWrappedOnNear(provider, tokenBridge, attestVAA) {
    return __awaiter(this, void 0, void 0, function* () {
        const vaa = Buffer.from(attestVAA).toString("hex");
        const res = yield callFunctionNear(provider, tokenBridge, "deposit_estimates");
        const msgs = [
            {
                contractId: tokenBridge,
                methodName: "submit_vaa",
                args: { vaa },
                attachedDeposit: new BN(res[1]),
                gas: new BN("150000000000000"),
            },
        ];
        msgs.push(Object.assign({}, msgs[0]));
        return msgs;
    });
}
/**
 * Constructs payload to create wrapped asset type. The type is of form `{{address}}::coin::T`,
 * where address is `sha256_hash(tokenBridgeAddress | chainID | "::" | originAddress | 0xFF)`.
 *
 * Note that the typical createWrapped call is broken into two parts on Aptos because we must first
 * create the CoinType that is used by `create_wrapped_coin<CoinType>`. Since it's not possible to
 * create a resource and use it in the same transaction, this is broken into separate transactions.
 * @param tokenBridgeAddress Address of token bridge
 * @param attestVAA Bytes of attest VAA
 * @returns Transaction payload
 */
export function createWrappedTypeOnAptos(tokenBridgeAddress, attestVAA) {
    return createWrappedCoinTypeAptos(tokenBridgeAddress, attestVAA);
}
/**
 * Constructs payload to create wrapped asset.
 *
 * Note that this function is typically called in tandem with `createWrappedTypeOnAptos` because
 * we must first create the CoinType that is used by `create_wrapped_coin<CoinType>`. Since it's
 * not possible to create a resource and use it in the same transaction, this is broken into
 * separate transactions.
 * @param tokenBridgeAddress Address of token bridge
 * @param attestVAA Bytes of attest VAA
 * @returns Transaction payload
 */
export function createWrappedOnAptos(tokenBridgeAddress, attestVAA) {
    return createWrappedCoinAptos(tokenBridgeAddress, attestVAA);
}
export function createWrappedOnSuiPrepare(coreBridgePackageId, tokenBridgePackageId, attestVAA, signerAddress) {
    return __awaiter(this, void 0, void 0, function* () {
        return publishCoin(coreBridgePackageId, tokenBridgePackageId, uint8ArrayToHex(attestVAA), signerAddress);
    });
}
export function createWrappedOnSui(provider, tokenBridgePackageId, coreBridgeStateObjectId, tokenBridgeStateObjectId, signerAddress, coinPackageId) {
    var _a;
    return __awaiter(this, void 0, void 0, function* () {
        // Get WrappedAssetSetup object ID
        const coinType = getWrappedCoinType(coinPackageId);
        const type = `${tokenBridgePackageId}::create_wrapped::WrappedAssetSetup<${coinType}>`;
        const res = yield provider.getOwnedObjects({
            owner: signerAddress,
            filter: { StructType: type },
        });
        if (!res || !res.data || res.data.length === 0) {
            throw new Error(`No WrappedAssetSetup object found for ${coinType} under owner ${signerAddress}. You must call 'createWrappedOnSuiPrepare' first.`);
        }
        const wrappedAssetSetupObjectId = (_a = res.data[0].data) === null || _a === void 0 ? void 0 : _a.objectId;
        if (!wrappedAssetSetupObjectId) {
            throw new Error(`WrappedAssetSetup object is invalid`);
        }
        // Construct complete registration payload
        const tx = new TransactionBlock();
        tx.moveCall({
            target: `${tokenBridgePackageId}::create_wrapped::complete_registration`,
            arguments: [
                tx.object(tokenBridgeStateObjectId),
                tx.object(coreBridgeStateObjectId),
                tx.object(wrappedAssetSetupObjectId),
                tx.object(SUI_CLOCK_OBJECT_ID),
            ],
            typeArguments: [coinType],
        });
        return tx;
    });
}
