"use strict";
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());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createWrappedOnSui = exports.createWrappedOnSuiPrepare = exports.createWrappedOnAptos = exports.createWrappedTypeOnAptos = exports.createWrappedOnNear = exports.createWrappedOnAlgorand = exports.createWrappedOnSolana = exports.createWrappedOnXpla = exports.createWrappedOnTerra = exports.createWrappedOnEth = void 0;
const sui_js_1 = require("@mysten/sui.js");
const web3_js_1 = require("@solana/web3.js");
const terra_js_1 = require("@terra-money/terra.js");
const xpla_js_1 = require("@xpla/xpla.js");
const bn_js_1 = __importDefault(require("bn.js"));
const js_base64_1 = require("js-base64");
const algorand_1 = require("../algorand");
const aptos_1 = require("../aptos");
const ethers_contracts_1 = require("../ethers-contracts");
const tokenBridge_1 = require("../solana/tokenBridge");
const sui_1 = require("../sui");
const utils_1 = require("../utils");
function createWrappedOnEth(tokenBridgeAddress, signer, signedVAA, overrides = {}) {
    return __awaiter(this, void 0, void 0, function* () {
        const bridge = ethers_contracts_1.Bridge__factory.connect(tokenBridgeAddress, signer);
        const v = yield bridge.createWrapped(signedVAA, overrides);
        const receipt = yield v.wait();
        return receipt;
    });
}
exports.createWrappedOnEth = createWrappedOnEth;
function createWrappedOnTerra(tokenBridgeAddress, walletAddress, signedVAA) {
    return __awaiter(this, void 0, void 0, function* () {
        return new terra_js_1.MsgExecuteContract(walletAddress, tokenBridgeAddress, {
            submit_vaa: {
                data: js_base64_1.fromUint8Array(signedVAA),
            },
        });
    });
}
exports.createWrappedOnTerra = createWrappedOnTerra;
function createWrappedOnXpla(tokenBridgeAddress, walletAddress, signedVAA) {
    return new xpla_js_1.MsgExecuteContract(walletAddress, tokenBridgeAddress, {
        submit_vaa: {
            data: js_base64_1.fromUint8Array(signedVAA),
        },
    });
}
exports.createWrappedOnXpla = createWrappedOnXpla;
function createWrappedOnSolana(connection, bridgeAddress, tokenBridgeAddress, payerAddress, signedVaa, commitment) {
    return __awaiter(this, void 0, void 0, function* () {
        const transaction = new web3_js_1.Transaction().add(tokenBridge_1.createCreateWrappedInstruction(tokenBridgeAddress, bridgeAddress, payerAddress, signedVaa));
        const { blockhash } = yield connection.getLatestBlockhash(commitment);
        transaction.recentBlockhash = blockhash;
        transaction.feePayer = new web3_js_1.PublicKey(payerAddress);
        return transaction;
    });
}
exports.createWrappedOnSolana = createWrappedOnSolana;
function createWrappedOnAlgorand(client, tokenBridgeId, bridgeId, senderAddr, attestVAA) {
    return __awaiter(this, void 0, void 0, function* () {
        return yield algorand_1._submitVAAAlgorand(client, tokenBridgeId, bridgeId, attestVAA, senderAddr);
    });
}
exports.createWrappedOnAlgorand = createWrappedOnAlgorand;
function createWrappedOnNear(provider, tokenBridge, attestVAA) {
    return __awaiter(this, void 0, void 0, function* () {
        const vaa = Buffer.from(attestVAA).toString("hex");
        const res = yield utils_1.callFunctionNear(provider, tokenBridge, "deposit_estimates");
        const msgs = [
            {
                contractId: tokenBridge,
                methodName: "submit_vaa",
                args: { vaa },
                attachedDeposit: new bn_js_1.default(res[1]),
                gas: new bn_js_1.default("150000000000000"),
            },
        ];
        msgs.push(Object.assign({}, msgs[0]));
        return msgs;
    });
}
exports.createWrappedOnNear = createWrappedOnNear;
/**
 * 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
 */
function createWrappedTypeOnAptos(tokenBridgeAddress, attestVAA) {
    return aptos_1.createWrappedCoinType(tokenBridgeAddress, attestVAA);
}
exports.createWrappedTypeOnAptos = createWrappedTypeOnAptos;
/**
 * 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
 */
function createWrappedOnAptos(tokenBridgeAddress, attestVAA) {
    return aptos_1.createWrappedCoin(tokenBridgeAddress, attestVAA);
}
exports.createWrappedOnAptos = createWrappedOnAptos;
function createWrappedOnSuiPrepare(provider, coreBridgeStateObjectId, tokenBridgeStateObjectId, decimals, signerAddress) {
    return __awaiter(this, void 0, void 0, function* () {
        return sui_1.publishCoin(provider, coreBridgeStateObjectId, tokenBridgeStateObjectId, decimals, signerAddress);
    });
}
exports.createWrappedOnSuiPrepare = createWrappedOnSuiPrepare;
function createWrappedOnSui(provider, coreBridgeStateObjectId, tokenBridgeStateObjectId, signerAddress, coinPackageId, wrappedAssetSetupType, attestVAA) {
    var _a;
    return __awaiter(this, void 0, void 0, function* () {
        const [coreBridgePackageId, tokenBridgePackageId] = yield Promise.all([
            sui_1.getPackageId(provider, coreBridgeStateObjectId),
            sui_1.getPackageId(provider, tokenBridgeStateObjectId),
        ]);
        // Get coin metadata
        const coinType = sui_1.getWrappedCoinType(coinPackageId);
        const coinMetadataObjectId = (_a = (yield provider.getCoinMetadata({ coinType }))) === null || _a === void 0 ? void 0 : _a.id;
        if (!coinMetadataObjectId) {
            throw new Error(`Coin metadata object not found for coin type ${coinType}.`);
        }
        // WrappedAssetSetup looks like
        // 0x92d81f28c167d90f84638c654b412fe7fa8e55bdfac7f638bdcf70306289be86::create_wrapped::WrappedAssetSetup<0xa40e0511f7d6531dd2dfac0512c7fd4a874b76f5994985fb17ee04501a2bb050::coin::COIN, 0x4eb7c5bca3759ab3064b46044edb5668c9066be8a543b28b58375f041f876a80::version_control::V__0_1_1>
        const wrappedAssetSetupObjectId = yield sui_1.getOwnedObjectId(provider, signerAddress, wrappedAssetSetupType);
        if (!wrappedAssetSetupObjectId) {
            throw new Error(`WrappedAssetSetup not found`);
        }
        // Get coin upgrade capability
        const coinUpgradeCapObjectId = yield sui_1.getUpgradeCapObjectId(provider, signerAddress, coinPackageId);
        if (!coinUpgradeCapObjectId) {
            throw new Error(`Coin upgrade cap not found for ${coinType} under owner ${signerAddress}. You must call 'createWrappedOnSuiPrepare' first.`);
        }
        // Get TokenBridgeMessage
        const tx = new sui_js_1.TransactionBlock();
        const [vaa] = tx.moveCall({
            target: `${coreBridgePackageId}::vaa::parse_and_verify`,
            arguments: [
                tx.object(coreBridgeStateObjectId),
                tx.pure(sui_1.uint8ArrayToBCS(attestVAA)),
                tx.object(sui_js_1.SUI_CLOCK_OBJECT_ID),
            ],
        });
        const [message] = tx.moveCall({
            target: `${tokenBridgePackageId}::vaa::verify_only_once`,
            arguments: [tx.object(tokenBridgeStateObjectId), vaa],
        });
        // Construct complete registration payload
        const versionType = wrappedAssetSetupType.split(", ")[1].replace(">", ""); // ugh
        tx.moveCall({
            target: `${tokenBridgePackageId}::create_wrapped::complete_registration`,
            arguments: [
                tx.object(tokenBridgeStateObjectId),
                tx.object(coinMetadataObjectId),
                tx.object(wrappedAssetSetupObjectId),
                tx.object(coinUpgradeCapObjectId),
                message,
            ],
            typeArguments: [coinType, versionType],
        });
        return tx;
    });
}
exports.createWrappedOnSui = createWrappedOnSui;
