"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChainContext = void 0;
const sdk_base_1 = require("@wormhole-foundation/sdk-base");
const address_1 = require("./address");
const protocol_1 = require("./protocol");
/**
 * A ChainContext provides a consistent interface for interacting with a chain.
 * It holds the configuration for the chain and cached RPC and protocol clients.
 *
 */
class ChainContext {
    network;
    chain;
    config;
    platform;
    // Cached Protocol clients
    rpc;
    coreBridge;
    tokenBridge;
    autoTokenBridge;
    circleBridge;
    autoCircleBridge;
    ibcBridge;
    porticoBridge;
    constructor(chain, platform, rpc) {
        this.config = platform.config[chain];
        this.platform = platform;
        this.chain = this.config.key;
        this.network = this.config.network;
        this.rpc = rpc;
    }
    /**
     * Get an RPC connection for this chain, uses the configuration passed in
     * the initial constructor
     *
     * @returns the RPC connection for this chain
     */
    getRpc() {
        this.rpc = this.rpc ? this.rpc : this.platform.getRpc(this.chain);
        return this.rpc;
    }
    /**
     *  Get the number of decimals for a token
     *
     *  @param token the token to get the decimals for
     *  @returns the number of decimals for the token
     */
    async getDecimals(token) {
        // try to find it in the token cache first
        if (this.config.tokenMap) {
            const found = sdk_base_1.tokens.getTokenByAddress(this.network, this.chain, token.toString());
            if (found)
                return found.decimals;
        }
        return this.platform.utils().getDecimals(this.chain, await this.getRpc(), token);
    }
    /**
     * Get the balance of a token for a given address
     *
     * @param walletAddr the address to get the balance for
     * @param token the token to get the balance for
     * @returns the balance of the token for the address
     *
     */
    async getBalance(walletAddr, token) {
        return this.platform.utils().getBalance(this.chain, await this.getRpc(), walletAddr, token);
    }
    /**
     * Get the latest block number seen by the chain according to the RPC
     *
     * @returns the latest block number
     */
    async getLatestBlock() {
        return this.platform.utils().getLatestBlock(await this.getRpc());
    }
    /**
     * Get the latest _finalized_ block number seen by the chain according to the RPC
     *
     * @returns the latest finalized block number
     */
    async getLatestFinalizedBlock() {
        return this.platform.utils().getLatestFinalizedBlock(await this.getRpc());
    }
    /**
     * Parse the Wormhole Core messages from a transaction
     *
     * @param txid the transaction to parse
     * @returns the Wormhole Core messages emitted by the transaction
     */
    async parseTransaction(txid) {
        return this.platform.parseWormholeMessages(this.chain, await this.getRpc(), txid);
    }
    /**
     *  Send a transaction and wait for it to be confirmed
     *
     * @param stxns the signed transaction to send
     * @returns the transaction hashes of the sent transactions
     */
    async sendWait(stxns) {
        return this.platform.utils().sendWait(this.chain, await this.getRpc(), stxns);
    }
    /**
     * Get the token data from the local cache if available
     * @param symbol the symbol of the token to get
     * @returns the token data if available
     */
    getToken(symbol) {
        if (!this.config.tokenMap)
            return;
        if (!(symbol in this.config.tokenMap))
            return;
        return this.config.tokenMap[symbol];
    }
    /**
     * Get the token id of the wrapped token for the native gas token
     *
     * @returns the wrapped token for the native gas token
     */
    async getNativeWrappedTokenId() {
        // see if we have it configured
        if (this.config.wrappedNative) {
            const { address } = this.config.wrappedNative;
            return { chain: this.chain, address: (0, address_1.toNative)(this.chain, address) };
        }
        // otherwise grab it from the token bridge fn
        const tb = await this.getTokenBridge();
        return { chain: this.chain, address: await tb.getWrappedNative() };
    }
    /**
     * Get the token account for a given address and token
     *
     * @remarks
     * This is really only useful in the context of Solana but in order
     * to provide a consistent interface, we provide it here.
     *
     * @param address the address to get the token account for
     * @param token the token to get the token account for
     * @returns the token account for the address and token
     */
    async getTokenAccount(address, token) {
        // Noop by default, override in implementation if necessary
        return { chain: this.chain, address };
    }
    /**
     * Check to see if a given protocol is supported by this chain
     * by checking if it is registered in the platform and the configuration
     * is available and correct
     *
     * @param protocolName the name of the Protocol to check for support
     * @returns a boolean indicating if this protocol is supported
     */
    supportsProtocol(protocolName) {
        return (0, protocol_1.protocolIsRegistered)(this.chain, protocolName);
    }
    /**
     * Check to see if the Wormhole Core protocol is supported by this chain
     * @returns a boolean indicating if this chain supports the Wormhole Core protocol
     */
    supportsWormholeCore = () => this.supportsProtocol("WormholeCore");
    /**
     * Get the Wormhole Core protocol client for this chain
     * @returns the Wormhole Core protocol client for this chain
     */
    async getWormholeCore() {
        this.coreBridge = this.coreBridge
            ? this.coreBridge
            : await this.platform.getProtocol("WormholeCore", await this.getRpc());
        return this.coreBridge;
    }
    /**
     * Check to see if the Token Bridge protocol is supported by this chain
     * @returns a boolean indicating if this chain supports the Token Bridge protocol
     */
    supportsTokenBridge = () => this.supportsProtocol("TokenBridge");
    /**
     * Get the Token Bridge protocol client for this chain
     * @returns the Token Bridge protocol client for this chain
     */
    async getTokenBridge() {
        this.tokenBridge = this.tokenBridge
            ? this.tokenBridge
            : await this.platform.getProtocol("TokenBridge", await this.getRpc());
        return this.tokenBridge;
    }
    /**
     * Check to see if the Automatic Token Bridge protocol is supported by this chain
     * @returns  a boolean indicating if this chain supports the Automatic Token Bridge protocol
     */
    supportsAutomaticTokenBridge = () => this.supportsProtocol("AutomaticTokenBridge");
    /**
     * Get the Automatic Token Bridge protocol client for this chain
     * @returns the Automatic Token Bridge protocol client for this chain
     */
    async getAutomaticTokenBridge() {
        this.autoTokenBridge = this.autoTokenBridge
            ? this.autoTokenBridge
            : await this.platform.getProtocol("AutomaticTokenBridge", await this.getRpc());
        return this.autoTokenBridge;
    }
    /**
     * Check to see if the Circle Bridge protocol is supported by this chain
     * @returns a boolean indicating if this chain supports the Circle Bridge protocol
     */
    supportsCircleBridge = () => this.supportsProtocol("CircleBridge");
    /**
     * Get the Circle Bridge protocol client for this chain
     * @returns the Circle Bridge protocol client for this chain
     */
    async getCircleBridge() {
        this.circleBridge = this.circleBridge
            ? this.circleBridge
            : await this.platform.getProtocol("CircleBridge", await this.getRpc());
        return this.circleBridge;
    }
    /**
     * Check to see if the Automatic Circle Bridge protocol is supported by this chain
     * @returns a boolean indicating if this chain supports the Automatic Circle Bridge protocol
     */
    supportsAutomaticCircleBridge = () => this.supportsProtocol("AutomaticCircleBridge");
    /**
     * Get the Automatic Circle Bridge protocol client for this chain
     * @returns the Automatic Circle Bridge protocol client for this chain
     */
    async getAutomaticCircleBridge() {
        this.autoCircleBridge = this.autoCircleBridge
            ? this.autoCircleBridge
            : await this.platform.getProtocol("AutomaticCircleBridge", await this.getRpc());
        return this.autoCircleBridge;
    }
    /**
     * Check to see if the IBC Bridge protocol is supported by this chain
     * @returns a boolean indicating if this chain supports the IBC Bridge protocol
     */
    supportsIbcBridge = () => this.supportsProtocol("IbcBridge");
    /**
     * Get the IBC Bridge protocol client for this chain
     * @returns the IBC Bridge protocol client for this chain
     */
    async getIbcBridge() {
        this.ibcBridge = this.ibcBridge
            ? this.ibcBridge
            : await this.platform.getProtocol("IbcBridge", await this.getRpc());
        return this.ibcBridge;
    }
    /**
     * Check to see if the Portico Bridge protocol is supported by this chain
     * @returns a boolean indicating if this chain supports the Portico Bridge protocol
     */
    supportsPorticoBridge = () => this.supportsProtocol("PorticoBridge");
    /**
     * Get the Portico Bridge protocol client for this chain
     * @returns the Portico Bridge protocol client for this chain
     */
    async getPorticoBridge() {
        this.porticoBridge = this.porticoBridge
            ? this.porticoBridge
            : await this.platform.getProtocol("PorticoBridge", await this.getRpc());
        return this.porticoBridge;
    }
}
exports.ChainContext = ChainContext;
//# sourceMappingURL=chain.js.map