"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AlgorandPlatform = void 0;
const connect_sdk_1 = require("@wormhole-foundation/connect-sdk");
const algosdk_1 = require("algosdk");
const address_1 = require("./address");
const chain_1 = require("./chain");
const types_1 = require("./types");
/**
 * @category Algorand
 */
class AlgorandPlatform extends connect_sdk_1.PlatformContext {
    static _platform = types_1._platform;
    constructor(network, _config) {
        super(network, _config ?? (0, connect_sdk_1.networkPlatformConfigs)(network, AlgorandPlatform._platform));
    }
    getRpc(chain) {
        if (chain in this.config)
            return new algosdk_1.Algodv2("", this.config[chain].rpc);
        throw new Error("No configuration available for chain: " + chain);
    }
    getChain(chain) {
        if (chain in this.config)
            return new chain_1.AlgorandChain(chain, this);
        throw new Error("No configuration available for chain: " + chain);
    }
    static nativeTokenId(network, chain) {
        if (!AlgorandPlatform.isSupportedChain(chain))
            throw new Error(`invalid chain for Algorand: ${chain}`);
        return connect_sdk_1.Wormhole.chainAddress(chain, address_1.AlgorandZeroAddress);
    }
    static isNativeTokenId(network, chain, tokenId) {
        if (!AlgorandPlatform.isSupportedChain(chain))
            return false;
        if (tokenId.chain !== chain)
            return false;
        const native = this.nativeTokenId(network, chain);
        return native == tokenId;
    }
    static isSupportedChain(chain) {
        const platform = (0, connect_sdk_1.chainToPlatform)(chain);
        return platform === AlgorandPlatform._platform;
    }
    static async getDecimals(chain, rpc, token) {
        // It may come in as a universal address
        const assetId = (0, connect_sdk_1.isNative)(token) ? 0 : new address_1.AlgorandAddress(token).toInt();
        if (assetId === 0)
            return connect_sdk_1.decimals.nativeDecimals(AlgorandPlatform._platform);
        const assetResp = await rpc.getAssetByID(assetId).do();
        const asset = algosdk_1.modelsv2.Asset.from_obj_for_encoding(assetResp);
        if (!asset.params || !asset.params.decimals)
            throw new Error("Could not fetch token details");
        return Number(asset.params.decimals);
    }
    static async getBalance(chain, rpc, walletAddr, token) {
        const assetId = (0, connect_sdk_1.isNative)(token) ? 0 : new address_1.AlgorandAddress(token).toInt();
        if (assetId === 0) {
            const resp = await rpc.accountInformation(walletAddr).do();
            const accountInfo = algosdk_1.modelsv2.Account.from_obj_for_encoding(resp);
            return BigInt(accountInfo.amount);
        }
        const acctAssetInfoResp = await rpc.accountAssetInformation(walletAddr, assetId).do();
        const accountAssetInfo = algosdk_1.modelsv2.AssetHolding.from_obj_for_encoding(acctAssetInfoResp);
        return BigInt(accountAssetInfo.amount);
    }
    static async getBalances(chain, rpc, walletAddr, tokens) {
        let native;
        if (tokens.includes("native")) {
            const acctInfoResp = await rpc.accountInformation(walletAddr).do();
            const accountInfo = algosdk_1.modelsv2.Account.from_obj_for_encoding(acctInfoResp);
            native = BigInt(accountInfo.amount);
        }
        const balancesArr = tokens.map(async (token) => {
            if ((0, connect_sdk_1.isNative)(token)) {
                return { ["native"]: native };
            }
            const asaId = new address_1.AlgorandAddress(token).toInt();
            const acctAssetInfoResp = await rpc.accountAssetInformation(walletAddr, asaId).do();
            const accountAssetInfo = algosdk_1.modelsv2.AssetHolding.from_obj_for_encoding(acctAssetInfoResp);
            return BigInt(accountAssetInfo.amount);
        });
        return balancesArr.reduce((obj, item) => Object.assign(obj, item), {});
    }
    static async sendWait(chain, rpc, stxns) {
        const rounds = 4;
        const decodedStxns = stxns.map((val, idx) => {
            const decodedStxn = (0, algosdk_1.decodeSignedTransaction)(val);
            return decodedStxn;
        });
        const txIds = decodedStxns.map((val, idx) => {
            const id = val.txn.txID();
            return id;
        });
        const { txId } = await rpc.sendRawTransaction(stxns).do();
        if (!txId) {
            throw new Error("Transaction(s) failed to send");
        }
        const confirmResp = await (0, algosdk_1.waitForConfirmation)(rpc, txId, rounds);
        const ptr = algosdk_1.modelsv2.PendingTransactionResponse.from_obj_for_encoding(confirmResp);
        if (!ptr.confirmedRound) {
            throw new Error(`Transaction(s) could not be confirmed in ${rounds} rounds`);
        }
        return txIds;
    }
    static async getLatestBlock(rpc) {
        const statusResp = await rpc.status().do();
        const status = algosdk_1.modelsv2.NodeStatusResponse.from_obj_for_encoding(statusResp);
        if (!status.lastRound) {
            throw new Error("Error getting status from node");
        }
        return Number(status.lastRound);
    }
    static async getLatestFinalizedBlock(rpc) {
        const statusResp = await rpc.status().do();
        const status = algosdk_1.modelsv2.NodeStatusResponse.from_obj_for_encoding(statusResp);
        if (!status.lastRound) {
            throw new Error("Error getting status from node");
        }
        return Number(status.lastRound);
    }
    static chainFromChainId(genesisId) {
        const networkChainPair = connect_sdk_1.nativeChainIds.platformNativeChainIdToNetworkChain(AlgorandPlatform._platform, genesisId);
        if (networkChainPair === undefined)
            throw new Error(`Unknown native chain id ${genesisId}`);
        const [network, chain] = networkChainPair;
        return [network, chain];
    }
    static async chainFromRpc(rpc) {
        const versionResp = await rpc.versionsCheck().do();
        const version = algosdk_1.modelsv2.Version.from_obj_for_encoding(versionResp);
        return this.chainFromChainId(version.genesisId);
    }
}
exports.AlgorandPlatform = AlgorandPlatform;
//# sourceMappingURL=platform.js.map