import { CosmWasmClient } from "@cosmjs/cosmwasm-stargate";
import { QueryClient, setupBankExtension, setupIbcExtension, } from "@cosmjs/stargate";
import { PlatformContext, Wormhole, decimals, isNative, nativeChainIds, networkPlatformConfigs, } from "@wormhole-foundation/connect-sdk";
import { CosmwasmChain } from "./chain";
import { chainToNativeDenoms, networkChainToChannels } from "./constants";
import { _platform } from "./types";
import { chainToPlatform } from "@wormhole-foundation/connect-sdk";
import { CosmwasmAddress } from "./address";
import { IBC_TRANSFER_PORT } from "./constants";
/**
 * @category Cosmwasm
 */
export class CosmwasmPlatform extends PlatformContext {
    static _platform = _platform;
    constructor(network, _config) {
        super(network, _config ?? networkPlatformConfigs(network, CosmwasmPlatform._platform));
    }
    async getRpc(chain) {
        if (chain in this.config && this.config[chain].rpc)
            return await CosmWasmClient.connect(this.config[chain].rpc);
        throw new Error("No configuration available for chain: " + chain);
    }
    getChain(chain, rpc) {
        if (chain in this.config)
            return new CosmwasmChain(chain, this, rpc);
        throw new Error("No configuration available for chain: " + chain);
    }
    static getQueryClient = (rpc) => {
        return QueryClient.withExtensions(rpc["cometClient"], setupBankExtension, setupIbcExtension);
    };
    // cached channels from config if available
    static getIbcChannels(network, chain) {
        return networkChainToChannels.has(network, chain)
            ? networkChainToChannels.get(network, chain)
            : null;
    }
    static nativeTokenId(network, chain) {
        if (!this.isSupportedChain(chain))
            throw new Error(`invalid chain for CosmWasm: ${chain}`);
        return Wormhole.chainAddress(chain, this.getNativeDenom(network, chain));
    }
    static isSupportedChain(chain) {
        const platform = chainToPlatform(chain);
        return platform === CosmwasmPlatform._platform;
    }
    static isNativeTokenId(network, chain, tokenId) {
        if (!this.isSupportedChain(chain))
            return false;
        if (tokenId.chain !== chain)
            return false;
        const native = this.nativeTokenId(network, chain);
        return native == tokenId;
    }
    static async getDecimals(chain, rpc, token) {
        if (isNative(token))
            return decimals.nativeDecimals(CosmwasmPlatform._platform);
        const addrStr = new CosmwasmAddress(token).toString();
        const { decimals: numDecimals } = await rpc.queryContractSmart(addrStr, {
            token_info: {},
        });
        return numDecimals;
    }
    static async getBalance(chain, rpc, walletAddress, token) {
        if (isNative(token)) {
            const [network, _] = await CosmwasmPlatform.chainFromRpc(rpc);
            const { amount } = await rpc.getBalance(walletAddress, this.getNativeDenom(network, chain));
            return BigInt(amount);
        }
        const addrStr = new CosmwasmAddress(token).toString();
        const { amount } = await rpc.getBalance(walletAddress, addrStr);
        return BigInt(amount);
    }
    static async getBalances(chain, rpc, walletAddress, tokens) {
        const client = CosmwasmPlatform.getQueryClient(rpc);
        const allBalances = await client.bank.allBalances(walletAddress);
        const [network, _] = await CosmwasmPlatform.chainFromRpc(rpc);
        const balancesArr = tokens.map((token) => {
            const address = isNative(token)
                ? this.getNativeDenom(network, chain)
                : new CosmwasmAddress(token).toString();
            const balance = allBalances.find((balance) => balance.denom === address);
            const balanceBigInt = balance ? BigInt(balance.amount) : null;
            return { [address]: balanceBigInt };
        });
        return balancesArr.reduce((obj, item) => Object.assign(obj, item), {});
    }
    static getNativeDenom(network, chain) {
        return chainToNativeDenoms.get(network, chain);
    }
    static async sendWait(chain, rpc, stxns) {
        const txhashes = [];
        for (const stxn of stxns) {
            const result = await rpc.broadcastTx(stxn);
            if (result.code !== 0)
                throw new Error(`Error sending transaction (${result.transactionHash}): ${result.rawLog}`);
            txhashes.push(result.transactionHash);
        }
        return txhashes;
    }
    static async getLatestBlock(rpc) {
        return await rpc.getHeight();
    }
    static async getLatestFinalizedBlock(rpc) {
        throw new Error("not implemented");
    }
    static chainFromChainId(chainMoniker) {
        const networkChainPair = nativeChainIds.platformNativeChainIdToNetworkChain(CosmwasmPlatform._platform, chainMoniker);
        if (networkChainPair === undefined)
            throw new Error(`Unknown Cosmwasm chainId ${chainMoniker}`);
        const [network, chain] = networkChainPair;
        return [network, chain];
    }
    static async chainFromRpc(rpc) {
        const chainId = await rpc.getChainId();
        return this.chainFromChainId(chainId);
    }
    static async getCounterpartyChannel(sourceChannel, rpc) {
        const queryClient = CosmwasmPlatform.getQueryClient(rpc);
        const conn = await queryClient.ibc.channel.channel(IBC_TRANSFER_PORT, sourceChannel);
        return conn.channel?.counterparty?.channelId ?? null;
    }
}
//# sourceMappingURL=platform.js.map