"use strict";
// Copyright 2017-2020 @polkadot/api authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
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());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const types_1 = require("../../types");
const util_1 = require("@polkadot/util");
const definitions_1 = __importDefault(require("../../types/interfaces/polymesh/definitions"));
const Init_1 = __importDefault(require("./Init"));
let pkgJson;
try {
    pkgJson = require('../package.json');
}
catch (error) {
    // development environment
    pkgJson = { name: '@polkadot/api', version: '-' };
}
function assertResult(value) {
    util_1.assert(!util_1.isUndefined(value), 'Api needs to be initialized before using, listen on \'ready\'');
    return value;
}
class ApiBase extends Init_1.default {
    /**
     * @description Create an instance of the class
     *
     * @param options Options object to create API instance or a Provider instance
     *
     * @example
     * <BR>
     *
     * ```javascript
     * import Api from '@polkadot/api/promise';
     *
     * const api = new Api().isReady();
     *
     * api.rpc.subscribeNewHeads((header) => {
     *   console.log(`new block #${header.number.toNumber()}`);
     * });
     * ```
     */
    constructor(options = {}, type, decorateMethod) {
        super(Object.assign(Object.assign({}, options), { types: Object.assign(Object.assign({}, options.types), definitions_1.default.types) }), type, decorateMethod);
        /**
         * @description Creates an instance of a type as registered
         */
        this.createType = (type, ...params) => {
            return types_1.createType(this.registry, type, ...params);
        };
    }
    /**
     * @description Contains the parameter types (constants) of all modules.
     *
     * The values are instances of the appropriate type and are accessible using `section`.`constantName`,
     *
     * @example
     * <BR>
     *
     * ```javascript
     * console.log(api.consts.democracy.enactmentPeriod.toString())
     * ```
     */
    get consts() {
        return assertResult(this._consts);
    }
    /**
     * @description Derived results that are injected into the API, allowing for combinations of various query results.
     *
     * @example
     * <BR>
     *
     * ```javascript
     * api.derive.chain.bestNumber((number) => {
     *   console.log('best number', number);
     * });
     * ```
     */
    get derive() {
        return assertResult(this._derive);
    }
    /**
     * @description  Returns the version of extrinsics in-use on this chain
     */
    get extrinsicVersion() {
        return this._extrinsicType;
    }
    /**
     * @description Contains the genesis Hash of the attached chain. Apart from being useful to determine the actual chain, it can also be used to sign immortal transactions.
     */
    get genesisHash() {
        return assertResult(this._genesisHash);
    }
    /**
     * @description `true` when subscriptions are supported
     */
    get hasSubscriptions() {
        return this._rpcCore.provider.hasSubscriptions;
    }
    /**
     * @description The library information name & version (from package.json)
     */
    get libraryInfo() {
        return `${pkgJson.name} v${pkgJson.version}`;
    }
    /**
     * @description Contains all the chain state modules and their subsequent methods in the API. These are attached dynamically from the runtime metadata.
     *
     * All calls inside the namespace, is denoted by `section`.`method` and may take an optional query parameter. As an example, `api.query.timestamp.now()` (current block timestamp) does not take parameters, while `api.query.system.accountNonce(<accountId>)` (retrieving the associated nonce for an account), takes the `AccountId` as a parameter.
     *
     * @example
     * <BR>
     *
     * ```javascript
     * api.query.balances.freeBalance(<accountId>, (balance) => {
     *   console.log('new balance', balance);
     * });
     * ```
     */
    get query() {
        return assertResult(this._query);
    }
    /**
     * @description Allows for the querying of multiple storage entries and the combination thereof into a single result. This is a very optimal way to make multiple queries since it only makes a single connection to the node and retrieves the data over one subscription.
     *
     * @example
     * <BR>
     *
     * ```javascript
     * const unsub = await api.queryMulti(
     *   [
     *     // you can include the storage without any parameters
     *     api.query.balances.totalIssuance,
     *     // or you can pass parameters to the storage query
     *     [api.query.balances.freeBalance, '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY']
     *   ],
     *   ([existential, balance]) => {
     *     console.log(`You have ${balance.sub(existential)} more than the existential deposit`);
     *
     *     unsub();
     *   }
     * );
     * ```
     */
    get queryMulti() {
        return assertResult(this._queryMulti);
    }
    /**
     * @description Contains all the raw rpc sections and their subsequent methods in the API as defined by the jsonrpc interface definitions. Unlike the dynamic `api.query` and `api.tx` sections, these methods are fixed (although extensible with node upgrades) and not determined by the runtime.
     *
     * RPC endpoints available here allow for the query of chain, node and system information, in addition to providing interfaces for the raw queries of state (using known keys) and the submission of transactions.
     *
     * @example
     * <BR>
     *
     * ```javascript
     * api.rpc.chain.subscribeNewHeads((header) => {
     *   console.log('new header', header);
     * });
     * ```
     */
    get rpc() {
        return assertResult(this._rpc);
    }
    /**
     * @description Yields the current attached runtime metadata. Generally this is only used to construct extrinsics & storage, but is useful for current runtime inspection.
     */
    get runtimeMetadata() {
        return assertResult(this._runtimeMetadata);
    }
    /**
     * @description Contains the version information for the current runtime.
     */
    get runtimeVersion() {
        return assertResult(this._runtimeVersion);
    }
    /**
     * @description The underlying Rx API interface
     */
    get rx() {
        return assertResult(this._rx);
    }
    /**
     * @description The type of this API instance, either 'rxjs' or 'promise'
     */
    get type() {
        return this._type;
    }
    /**
     * @description Contains all the extrinsic modules and their subsequent methods in the API. It allows for the construction of transactions and the submission thereof. These are attached dynamically from the runtime metadata.
     *
     * @example
     * <BR>
     *
     * ```javascript
     * api.tx.balances
     *   .transfer(<recipientId>, <balance>)
     *   .signAndSend(<keyPair>, ({status}) => {
     *     console.log('tx status', status.asFinalized.toHex());
     *   });
     * ```
     */
    get tx() {
        return assertResult(this._extrinsics);
    }
    /**
     * @description Disconnect from the underlying provider, halting all network traffic
     */
    disconnect() {
        this._rpcCore.disconnect();
    }
    /**
     * @description Finds the definition for a specific [[CallFunction]] based on the index supplied
     */
    findCall(callIndex) {
        return this.registry.findMetaCall(util_1.u8aToU8a(callIndex));
    }
    /**
     * @description Finds the definition for a specific [[RegistryError]] based on the index supplied
     */
    findError(errorIndex) {
        return this.registry.findMetaError(util_1.u8aToU8a(errorIndex));
    }
    /**
     * @description Register additional user-defined of chain-specific types in the type registry
     */
    registerTypes(types) {
        types && this.registry.register(types);
    }
    /**
     * @description Set an external signer which will be used to sign extrinsic when account passed in is not KeyringPair
     */
    setSigner(signer) {
        this._rx.signer = signer;
    }
    /**
     * @description Signs a raw signer payload, string or Uint8Array
     */
    sign(address, data, { signer } = {}) {
        var _a;
        return __awaiter(this, void 0, void 0, function* () {
            if (util_1.isString(address)) {
                const _signer = signer || this._rx.signer;
                util_1.assert((_a = _signer) === null || _a === void 0 ? void 0 : _a.signRaw, 'No signer exists with a signRaw interface');
                return (yield _signer.signRaw(Object.assign(Object.assign({ type: 'bytes' }, data), { address }))).signature;
            }
            return util_1.u8aToHex(address.sign(util_1.u8aToU8a(data.data)));
        });
    }
}
exports.default = ApiBase;
