"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CosmwasmTokenBridge = void 0;
const connect_sdk_1 = require("@wormhole-foundation/connect-sdk");
const connect_sdk_cosmwasm_1 = require("@wormhole-foundation/connect-sdk-cosmwasm");
require("@wormhole-foundation/connect-sdk-cosmwasm-core");
class CosmwasmTokenBridge {
    network;
    chain;
    rpc;
    contracts;
    tokenBridge;
    translator;
    constructor(network, chain, rpc, contracts) {
        this.network = network;
        this.chain = chain;
        this.rpc = rpc;
        this.contracts = contracts;
        const tokenBridgeAddress = this.contracts.tokenBridge;
        if (!tokenBridgeAddress)
            throw new Error(`Wormhole Token Bridge contract for domain ${chain} not found`);
        this.tokenBridge = tokenBridgeAddress;
        // May be undefined, thats ok
        this.translator = this.contracts.translator;
        // But it cannot be an empty string (misconfiguration)
        if (this.translator !== undefined && this.translator === "")
            throw new Error("Translator address may be undefined but not empty string");
    }
    static async fromRpc(rpc, config) {
        const [network, chain] = await connect_sdk_cosmwasm_1.CosmwasmPlatform.chainFromRpc(rpc);
        const conf = config[chain];
        if (conf.network !== network)
            throw new Error(`Network mismatch: ${conf.network} != ${network}`);
        return new CosmwasmTokenBridge(network, chain, rpc, config[chain].contracts);
    }
    async isWrappedAsset(token) {
        try {
            await this.getOriginalAsset(token);
            return true;
        }
        catch { }
        return false;
    }
    async hasWrappedAsset(token) {
        try {
            await this.getWrappedAsset(token);
            return true;
        }
        catch { }
        return false;
    }
    async getWrappedAsset(token) {
        if (token.chain === this.chain)
            throw new Error(`Expected foreign chain, got ${token.chain}`);
        if ((0, connect_sdk_1.isNative)(token.address))
            throw new Error("Native asset cannot be a wrapped asset");
        const base64Addr = connect_sdk_1.encoding.b64.encode(token.address.toUniversalAddress().toUint8Array());
        const { address } = await this.rpc.queryContractSmart(this.tokenBridge, {
            wrapped_registry: {
                chain: (0, connect_sdk_1.toChainId)(token.chain),
                address: base64Addr,
            },
        });
        return (0, connect_sdk_1.toNative)(this.chain, address);
    }
    async getOriginalAsset(token) {
        const wrappedAddress = new connect_sdk_cosmwasm_1.CosmwasmAddress(token).toString();
        const response = await this.rpc.queryContractSmart(wrappedAddress, {
            wrapped_asset_info: {},
        });
        const origChain = (0, connect_sdk_1.toChain)(response.asset_chain);
        const origAddress = connect_sdk_1.encoding.b64.decode(response.asset_address);
        return {
            chain: origChain,
            address: new connect_sdk_1.UniversalAddress(new Uint8Array(origAddress)),
        };
    }
    async isTransferCompleted(vaa) {
        const data = connect_sdk_1.encoding.b64.encode((0, connect_sdk_1.serialize)(vaa));
        const result = await this.rpc.queryContractSmart(this.tokenBridge, {
            is_vaa_redeemed: { vaa: data },
        });
        return result.is_redeemed;
    }
    async *createAttestation(token, payer) {
        if (!payer)
            throw new Error("Payer required to create attestation");
        const tokenStr = new connect_sdk_cosmwasm_1.CosmwasmAddress(token).toString();
        const payerStr = new connect_sdk_cosmwasm_1.CosmwasmAddress(payer).toString();
        // TODO nonce?
        const nonce = 0;
        const assetInfo = (0, connect_sdk_1.isNative)(token)
            ? {
                native_token: {
                    denom: connect_sdk_cosmwasm_1.CosmwasmPlatform.getNativeDenom(this.network, this.chain),
                },
            }
            : {
                token: { contract_addr: tokenStr },
            };
        yield this.createUnsignedTx({
            msgs: [
                (0, connect_sdk_cosmwasm_1.buildExecuteMsg)(payerStr, this.tokenBridge, {
                    create_asset_meta: { asset_info: assetInfo, nonce },
                }),
            ],
            fee: (0, connect_sdk_cosmwasm_1.computeFee)(this.network, this.chain),
            memo: "Wormhole - Create Attestation",
        }, "TokenBridge.createAttestation");
    }
    async *submitAttestation(vaa, payer) {
        if (!payer)
            throw new Error("Payer required to submit attestation");
        const payerStr = new connect_sdk_cosmwasm_1.CosmwasmAddress(payer).toString();
        yield this.createUnsignedTx({
            msgs: [
                (0, connect_sdk_cosmwasm_1.buildExecuteMsg)(payerStr, this.tokenBridge, {
                    submit_vaa: { data: (0, connect_sdk_1.serialize)(vaa) },
                }),
            ],
            fee: (0, connect_sdk_cosmwasm_1.computeFee)(this.network, this.chain),
            memo: "Wormhole - Submit Attestation",
        }, "TokenBridge.submitAttestation");
    }
    async *transfer(sender, recipient, token, amount, payload) {
        const nonce = Math.round(Math.random() * 100000);
        const relayerFee = "0";
        const recipientChainId = (0, connect_sdk_1.toChainId)(recipient.chain);
        // TODO: do we need to use the _native_ address for cosmos chains?
        const encodedRecipient = connect_sdk_1.encoding.b64.encode(recipient.address.toUniversalAddress().toUint8Array());
        const denom = connect_sdk_cosmwasm_1.CosmwasmPlatform.getNativeDenom(this.network, this.chain);
        const isNativeToken = (0, connect_sdk_1.isNative)(token);
        const tokenAddress = isNativeToken ? denom : token.toString();
        const senderAddress = new connect_sdk_cosmwasm_1.CosmwasmAddress(sender).toString();
        const mk_initiate_transfer = (info) => {
            const common = {
                asset: {
                    amount: amount.toString(),
                    info,
                },
                recipient_chain: recipientChainId,
                recipient: encodedRecipient,
                fee: relayerFee,
                nonce: nonce,
            };
            return payload
                ? {
                    initiate_transfer_with_payload: { ...common, payload: connect_sdk_1.encoding.b64.encode(payload) },
                }
                : {
                    initiate_transfer: common,
                };
        };
        if (isNativeToken) {
            const msgs = [
                (0, connect_sdk_cosmwasm_1.buildExecuteMsg)(senderAddress, this.tokenBridge, { deposit_tokens: {} }, [
                    { amount: amount.toString(), denom: tokenAddress },
                ]),
                (0, connect_sdk_cosmwasm_1.buildExecuteMsg)(senderAddress, this.tokenBridge, mk_initiate_transfer({
                    native_token: { denom: tokenAddress },
                })),
            ];
            yield this.createUnsignedTx({
                msgs,
                fee: (0, connect_sdk_cosmwasm_1.computeFee)(this.network, this.chain),
                memo: "Wormhole - Initiate Native Transfer",
            }, "TokenBridge.transferNative");
        }
        else {
            const msgs = [
                (0, connect_sdk_cosmwasm_1.buildExecuteMsg)(senderAddress, tokenAddress, {
                    increase_allowance: {
                        spender: this.tokenBridge,
                        amount: amount.toString(),
                        expires: { never: {} },
                    },
                }),
                (0, connect_sdk_cosmwasm_1.buildExecuteMsg)(senderAddress, this.tokenBridge, mk_initiate_transfer({
                    token: { contract_addr: tokenAddress },
                })),
            ];
            yield this.createUnsignedTx({
                msgs,
                fee: (0, connect_sdk_cosmwasm_1.computeFee)(this.network, this.chain),
                memo: "Wormhole - Initiate Transfer",
            }, "TokenBridge.transfer");
        }
    }
    async *redeem(sender, vaa, unwrapNative = true) {
        // TODO: unwrapNative
        const data = connect_sdk_1.encoding.b64.encode((0, connect_sdk_1.serialize)(vaa));
        const senderAddress = new connect_sdk_cosmwasm_1.CosmwasmAddress(sender).toString();
        const toTranslator = this.translator &&
            new connect_sdk_cosmwasm_1.CosmwasmAddress(this.translator).toUniversalAddress().equals(vaa.payload.to.address);
        const msg = toTranslator
            ? (0, connect_sdk_cosmwasm_1.buildExecuteMsg)(senderAddress, this.translator, {
                complete_transfer_and_convert: {
                    vaa: data,
                },
            })
            : (0, connect_sdk_cosmwasm_1.buildExecuteMsg)(senderAddress, this.tokenBridge, {
                submit_vaa: { data },
            });
        yield this.createUnsignedTx({
            msgs: [msg],
            fee: (0, connect_sdk_cosmwasm_1.computeFee)(this.network, this.chain),
            memo: "Wormhole - Complete Transfer",
        }, "TokenBridge.redeem");
        return;
    }
    async parseTransactionDetails(txid) {
        throw new Error("Not implemented");
    }
    async getWrappedNative() {
        return (0, connect_sdk_1.toNative)(this.chain, connect_sdk_cosmwasm_1.CosmwasmPlatform.getNativeDenom(this.network, this.chain));
    }
    createUnsignedTx(txReq, description, parallelizable = false) {
        return new connect_sdk_cosmwasm_1.CosmwasmUnsignedTransaction(txReq, this.network, this.chain, description, parallelizable);
    }
}
exports.CosmwasmTokenBridge = CosmwasmTokenBridge;
//# sourceMappingURL=tokenBridge.js.map