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 { TxnBuilderTypes } from "aptos";
import { _parseVAAAlgorand } from "../../algorand";
import { assertChain, CHAIN_ID_APTOS, coalesceChainId, getAssetFullyQualifiedType, getTypeFromExternalAddress, hexToUint8Array, isValidAptosType, } from "../../utils";
// Attest token
export const attestToken = (tokenBridgeAddress, tokenChain, tokenAddress) => {
    if (!tokenBridgeAddress)
        throw new Error("Need token bridge address.");
    const assetType = getAssetFullyQualifiedType(tokenBridgeAddress, coalesceChainId(tokenChain), tokenAddress);
    if (!assetType)
        throw new Error("Invalid asset address.");
    return {
        function: `${tokenBridgeAddress}::attest_token::attest_token_entry`,
        type_arguments: [assetType],
        arguments: [],
    };
};
// Complete transfer
export const completeTransfer = (client, tokenBridgeAddress, transferVAA, feeRecipient) => __awaiter(void 0, void 0, void 0, function* () {
    if (!tokenBridgeAddress)
        throw new Error("Need token bridge address.");
    const parsedVAA = _parseVAAAlgorand(transferVAA);
    if (!parsedVAA.FromChain || !parsedVAA.Contract || !parsedVAA.ToChain) {
        throw new Error("VAA does not contain required information");
    }
    if (parsedVAA.ToChain !== CHAIN_ID_APTOS) {
        throw new Error("Transfer is not destined for Aptos");
    }
    assertChain(parsedVAA.FromChain);
    const assetType = parsedVAA.FromChain === CHAIN_ID_APTOS
        ? yield getTypeFromExternalAddress(client, tokenBridgeAddress, parsedVAA.Contract)
        : getAssetFullyQualifiedType(tokenBridgeAddress, coalesceChainId(parsedVAA.FromChain), parsedVAA.Contract);
    if (!assetType)
        throw new Error("Invalid asset address.");
    return {
        function: `${tokenBridgeAddress}::complete_transfer::submit_vaa_entry`,
        type_arguments: [assetType],
        arguments: [transferVAA, feeRecipient],
    };
});
export const completeTransferAndRegister = (client, tokenBridgeAddress, transferVAA) => __awaiter(void 0, void 0, void 0, function* () {
    if (!tokenBridgeAddress)
        throw new Error("Need token bridge address.");
    const parsedVAA = _parseVAAAlgorand(transferVAA);
    if (!parsedVAA.FromChain || !parsedVAA.Contract || !parsedVAA.ToChain) {
        throw new Error("VAA does not contain required information");
    }
    if (parsedVAA.ToChain !== CHAIN_ID_APTOS) {
        throw new Error("Transfer is not destined for Aptos");
    }
    assertChain(parsedVAA.FromChain);
    const assetType = parsedVAA.FromChain === CHAIN_ID_APTOS
        ? yield getTypeFromExternalAddress(client, tokenBridgeAddress, parsedVAA.Contract)
        : getAssetFullyQualifiedType(tokenBridgeAddress, coalesceChainId(parsedVAA.FromChain), parsedVAA.Contract);
    if (!assetType)
        throw new Error("Invalid asset address.");
    return {
        function: `${tokenBridgeAddress}::complete_transfer::submit_vaa_and_register_entry`,
        type_arguments: [assetType],
        arguments: [transferVAA],
    };
});
export const completeTransferWithPayload = (_tokenBridgeAddress, _tokenChain, _tokenAddress, _vaa) => {
    throw new Error("Completing transfers with payload is not yet supported in the sdk");
};
/**
 * Construct a payload for a transaction that registers a coin defined by the given origin chain
 * ID and address to the sender's account.
 *
 * The bytecode was compiled from the following Move code:
 * ```move
 * script {
 *   use aptos_framework::coin;
 *   use aptos_framework::signer;
 *
 *   fun main<CoinType>(user: &signer) {
 *     if (!coin::is_account_registered<CoinType>(signer::address_of(user))) {
 *       coin::register<CoinType>(user);
 *     };
 *   }
 * }
 * ```
 * @param tokenBridgeAddress Address of token bridge
 * @param originChain Origin chain ID of asset
 * @param originAddress Asset address on origin chain
 * @returns Transaction payload
 */
export const registerCoin = (tokenBridgeAddress, originChain, originAddress) => {
    const bytecode = hexToUint8Array("a11ceb0b050000000601000403041104150405190b072436085a200000000101020002000003020401000004000101000103020301060c000105010900010104636f696e067369676e65720a616464726573735f6f661569735f6163636f756e745f726567697374657265640872656769737465720000000000000000000000000000000000000000000000000000000000000001010000010c0a001100380020030605090b003801050b0b000102");
    const assetType = getAssetFullyQualifiedType(tokenBridgeAddress, coalesceChainId(originChain), originAddress);
    if (!assetType)
        throw new Error("Asset type is null");
    const typeTag = new TxnBuilderTypes.TypeTagStruct(TxnBuilderTypes.StructTag.fromString(assetType));
    return new TxnBuilderTypes.TransactionPayloadScript(new TxnBuilderTypes.Script(bytecode, [typeTag], []));
};
// Deploy coin
// don't need `signer` and `&signer` in argument list because the Move VM will inject them
export const deployCoin = (tokenBridgeAddress) => {
    if (!tokenBridgeAddress)
        throw new Error("Need token bridge address.");
    return {
        function: `${tokenBridgeAddress}::deploy_coin::deploy_coin`,
        type_arguments: [],
        arguments: [],
    };
};
// Register chain
export const registerChain = (tokenBridgeAddress, vaa) => {
    if (!tokenBridgeAddress)
        throw new Error("Need token bridge address.");
    return {
        function: `${tokenBridgeAddress}::register_chain::submit_vaa_entry`,
        type_arguments: [],
        arguments: [vaa],
    };
};
// Transfer tokens
export const transferTokens = (tokenBridgeAddress, fullyQualifiedType, amount, recipientChain, recipient, relayerFee, nonce) => {
    if (!tokenBridgeAddress)
        throw new Error("Need token bridge address.");
    if (!isValidAptosType(fullyQualifiedType)) {
        throw new Error("Invalid qualified type");
    }
    const recipientChainId = coalesceChainId(recipientChain);
    return {
        function: `${tokenBridgeAddress}::transfer_tokens::transfer_tokens_entry`,
        type_arguments: [fullyQualifiedType],
        arguments: [amount, recipientChainId, recipient, relayerFee, nonce],
    };
};
export const transferTokensWithPayload = (tokenBridgeAddress, fullyQualifiedType, amount, recipientChain, recipient, relayerFee, nonce, payload) => {
    throw new Error("Transfer with payload are not yet supported in the sdk");
};
// Created wrapped coin
export const createWrappedCoinType = (tokenBridgeAddress, vaa) => {
    if (!tokenBridgeAddress)
        throw new Error("Need token bridge address.");
    return {
        function: `${tokenBridgeAddress}::wrapped::create_wrapped_coin_type`,
        type_arguments: [],
        arguments: [vaa],
    };
};
export const createWrappedCoin = (tokenBridgeAddress, attestVAA) => {
    if (!tokenBridgeAddress)
        throw new Error("Need token bridge address.");
    const parsedVAA = _parseVAAAlgorand(attestVAA);
    if (!parsedVAA.FromChain || !parsedVAA.Contract) {
        throw new Error("VAA does not contain required information");
    }
    assertChain(parsedVAA.FromChain);
    const assetType = getAssetFullyQualifiedType(tokenBridgeAddress, coalesceChainId(parsedVAA.FromChain), parsedVAA.Contract);
    if (!assetType)
        throw new Error("Invalid asset address.");
    return {
        function: `${tokenBridgeAddress}::wrapped::create_wrapped_coin`,
        type_arguments: [assetType],
        arguments: [attestVAA],
    };
};
