import { PublicKey, AccountInfo, ParsedAccountData, VersionedTransaction, Lockup, TransactionInstruction, Signer, EpochInfo } from '@solana/web3.js';
import * as superstruct from 'superstruct';
import { Infer } from 'superstruct';
import BigNumber from 'bignumber.js';

/**
 * Copyright (c) 2025, Everstake.
 * Licensed under the BSD-3-Clause License. See LICENSE file for details.
 */
/**
 * `WalletSDKError` is a custom error class that extends the built-in `Error` class.
 * It provides additional properties for error handling within the Wallet SDK.
 *
 * @remarks
 * This class is needed to provide additional context for errors, such as a code
 * and the original error, if any.
 *
 * @public
 *
 * @param message - The error message.
 * @param code - A string representing the error code.
 * @param originalError - The original error that caused this error, if any.
 */
declare class WalletSDKError extends Error {
    code: string;
    originalError?: Error | undefined;
    constructor(message: string, code: string, originalError?: Error | undefined);
}
/**
 * `Blockchain` is an abstract class that provides a structure for blockchain-specific classes.
 * It includes methods for error handling and throwing errors.
 *
 * @remarks
 * This class should be extended by classes that implement blockchain-specific functionality.
 * The extending classes should provide their own `ERROR_MESSAGES` and `ORIGINAL_ERROR_MESSAGES`.
 *
 * @property ERROR_MESSAGES - An object that maps error codes to error messages.
 * @property ORIGINAL_ERROR_MESSAGES - An object that maps original error messages to user-friendly error messages.
 *
 *
 * **/
declare abstract class Blockchain {
    protected abstract ERROR_MESSAGES: {
        [key: string]: string;
    };
    protected abstract ORIGINAL_ERROR_MESSAGES: {
        [key: string]: string;
    };
    /**
     * Handles errors that occur within the Ethereum class.
     *
     * @param {keyof typeof ERROR_MESSAGES} code - The error code associated with the error.
     * @param {Error | WalletSDKError | unknown} originalError - The original error that was thrown.
     *
     * If the original error is an instance of WalletSDKError, it is thrown as is.
     * If the original error is an instance of the built-in Error class, a new WalletSDKError is thrown with the original error as the cause.
     * If the original error is not an instance of WalletSDKError or Error, a new WalletSDKError is thrown with a generic message and code.
     */
    handleError(code: keyof typeof this.ERROR_MESSAGES, originalError: Error | WalletSDKError | unknown): void;
    /**
     * Throws a WalletSDKError with a specified error code and message.
     *
     * @param {keyof typeof ERROR_MESSAGES} code - The error code associated with the error.
     * @param {...string[]} values - The values to be inserted into the error message.
     *
     * The method retrieves the error message template associated with the provided code from the ERROR_MESSAGES object.
     * It then replaces placeholders in the message template with provided values and throws a WalletSDKError with the final message and the provided code.
     */
    throwError(code: keyof typeof this.ERROR_MESSAGES, ...values: string[]): void;
    /**
     * Check if the URL is valid
     *
     * @param {string} url - URL
     * @returns a bool type result.
     *
     */
    isValidURL(url: string): boolean;
}

declare const SOL_CHAIN = "solana";
declare const SOL_MIN_AMOUNT = 10000000;
declare const SOL_MAINNET_VALIDATOR_ADDRESS: PublicKey;
declare const SOL_DEVNET_VALIDATOR_ADDRESS: PublicKey;
declare const FILTER_DATA_SIZE = 200;
declare const FILTER_OFFSET = 44;
declare enum SolNetwork {
    Mainnet = "mainnet-beta",
    Devnet = "devnet"
}
declare const StakeState: {
    inactive: string;
    activating: string;
    active: string;
    deactivating: string;
    deactivated: string;
};
declare const StakeAccountType: superstruct.Struct<"uninitialized" | "initialized" | "delegated" | "rewardsPool", {
    uninitialized: "uninitialized";
    initialized: "initialized";
    delegated: "delegated";
    rewardsPool: "rewardsPool";
}>;

type StakeAccount$1 = Infer<typeof StakeAccount$1>;
declare const StakeAccount$1: superstruct.Struct<{
    type: "uninitialized" | "initialized" | "delegated" | "rewardsPool";
    info: {
        meta: {
            rentExemptReserve: BigNumber;
            authorized: {
                staker: PublicKey;
                withdrawer: PublicKey;
            };
            lockup: {
                unixTimestamp: number;
                epoch: number;
                custodian: PublicKey;
            };
        };
        stake: {
            delegation: {
                stake: BigNumber;
                voter: PublicKey;
                activationEpoch: BigNumber;
                deactivationEpoch: BigNumber;
                warmupCooldownRate: number;
            };
            creditsObserved: number;
        } | null;
    };
}, {
    type: superstruct.Struct<"uninitialized" | "initialized" | "delegated" | "rewardsPool", {
        uninitialized: "uninitialized";
        initialized: "initialized";
        delegated: "delegated";
        rewardsPool: "rewardsPool";
    }>;
    info: superstruct.Struct<{
        meta: {
            rentExemptReserve: BigNumber;
            authorized: {
                staker: PublicKey;
                withdrawer: PublicKey;
            };
            lockup: {
                unixTimestamp: number;
                epoch: number;
                custodian: PublicKey;
            };
        };
        stake: {
            delegation: {
                stake: BigNumber;
                voter: PublicKey;
                activationEpoch: BigNumber;
                deactivationEpoch: BigNumber;
                warmupCooldownRate: number;
            };
            creditsObserved: number;
        } | null;
    }, {
        meta: superstruct.Struct<{
            rentExemptReserve: BigNumber;
            authorized: {
                staker: PublicKey;
                withdrawer: PublicKey;
            };
            lockup: {
                unixTimestamp: number;
                epoch: number;
                custodian: PublicKey;
            };
        }, {
            rentExemptReserve: superstruct.Struct<BigNumber, null>;
            authorized: superstruct.Struct<{
                staker: PublicKey;
                withdrawer: PublicKey;
            }, {
                staker: superstruct.Struct<PublicKey, null>;
                withdrawer: superstruct.Struct<PublicKey, null>;
            }>;
            lockup: superstruct.Struct<{
                unixTimestamp: number;
                epoch: number;
                custodian: PublicKey;
            }, {
                unixTimestamp: superstruct.Struct<number, null>;
                epoch: superstruct.Struct<number, null>;
                custodian: superstruct.Struct<PublicKey, null>;
            }>;
        }>;
        stake: superstruct.Struct<{
            delegation: {
                stake: BigNumber;
                voter: PublicKey;
                activationEpoch: BigNumber;
                deactivationEpoch: BigNumber;
                warmupCooldownRate: number;
            };
            creditsObserved: number;
        } | null, {
            delegation: superstruct.Struct<{
                stake: BigNumber;
                voter: PublicKey;
                activationEpoch: BigNumber;
                deactivationEpoch: BigNumber;
                warmupCooldownRate: number;
            }, {
                voter: superstruct.Struct<PublicKey, null>;
                stake: superstruct.Struct<BigNumber, null>;
                activationEpoch: superstruct.Struct<BigNumber, null>;
                deactivationEpoch: superstruct.Struct<BigNumber, null>;
                warmupCooldownRate: superstruct.Struct<number, null>;
            }>;
            creditsObserved: superstruct.Struct<number, null>;
        }>;
    }>;
}>;

declare class ParseStakeAccountError extends Error {
}
/**
 * The `StakeAccount` provides methods for interacting with the parsed Solana stake account.
 *
 * @property account - Parser account infop AccountInfo<Account>.
 * @throws ParseStakeAccountError if `account` is AccountInfo<Buffer> or if unable to parse account data
 */
declare class StakeAccount {
    account: AccountInfo<StakeAccount$1>;
    constructor({ executable, owner, lamports, data, rentEpoch, }: AccountInfo<Buffer | ParsedAccountData>);
    /**
     * Check if lockup is in force
     * @param currEpoch current epoch.
     * @param currUnixTimestamp current unix timetamp.
     * @returns a bool type result.
     */
    isLockupInForce(currEpoch: number, currUnixTimestamp: number): boolean;
    /**
     * Determins the current state of a stake account given the current epoch
     * @param currentEpoch
     * @returns `stakeAccount`'s stake state`string`
     */
    stakeAccountState(currentEpoch: number): string;
}

/**
 * Copyright (c) 2025, Everstake.
 * Licensed under the BSD-3-Clause License. See LICENSE file for details.
 */

interface ApiResponse<T> {
    result: T;
}
type SolDelegation = {
    pubkey: PublicKey;
    account: AccountInfo<Buffer | ParsedAccountData>;
};
type SolCreateAccountResponse = {
    createStakeAccountVerTx: VersionedTransaction;
    stakeAccount: PublicKey;
};
type SolAccount = {
    pubkey: PublicKey;
    account: StakeAccount;
};
type SolAccountToSplit = {
    account: SolAccount;
    lamports: number;
};

/**
 * Copyright (c) 2025, Everstake.
 * Licensed under the BSD-3-Clause License. See LICENSE file for details.
 */

/**
 * The `Solana` class extends the `Blockchain` class and provides methods for interacting with the Solana blockchain.
 *
 * @property connection - The connection to the Solana blockchain.
 * @property ERROR_MESSAGES - The error messages for the Solana class.
 * @property ORIGINAL_ERROR_MESSAGES - The original error messages for the Solana class.

 * @throws Throws an error if there's an issue establishing the connection.
 */
declare class Solana extends Blockchain {
    private connection;
    private validator;
    protected ERROR_MESSAGES: {
        CONNECTION_ERROR: string;
        MIN_AMOUNT_ERROR: string;
        CREATE_ACCOUNT_ERROR: string;
        DELEGATE_ERROR: string;
        DEACTIVATE_ERROR: string;
        WITHDRAW_ERROR: string;
        GET_DELEGATIONS_ERROR: string;
        STAKE_ERROR: string;
        INVALID_RPC_ERROR: string;
        UNSUPPORTED_NETWORK_ERROR: string;
        CLAIM_ERROR: string;
        UNSTAKE_ERROR: string;
        NOTHING_TO_CLAIM_ERROR: string;
        NOT_ENOUGH_ACTIVE_STAKE_ERROR: string;
        GET_EPOCH_INFO_ERROR: string;
    };
    protected ORIGINAL_ERROR_MESSAGES: {};
    constructor(network?: SolNetwork, rpc?: string | null);
    /**
     * Creates a new stake account.
     *
     * @param address - The public key of the account as PublicKey.
     * @param lamports  - The amount to stake in lamports.
     * @param source  - stake source
     * @param lockup - stake account lockup
     *
     * @throws  Throws an error if the lamports is less than the minimum amount.
     * @throws  Throws an error if there's an issue creating the stake account.
     *
     * @returns Returns a promise that resolves with the versioned transaction of the stake account creation and the public key of the stake account.
     *
     */
    createAccount(address: PublicKey, lamports: number, source: string | null, lockup?: Lockup | null): Promise<ApiResponse<SolCreateAccountResponse>>;
    /**
     * Prepares a transaction with the given instructions and payer.
     *
     * @param instructions - An array of TransactionInstruction objects.
     * @param payer - The public key of the payer.
     * @param externalSigners - an array of external signers.
     * @returns A promise that resolves to a VersionedTransaction object.
     */
    prepareTransaction(instructions: TransactionInstruction[], payer: PublicKey, externalSigners: Signer[]): Promise<VersionedTransaction>;
    /**
     * Retrieves the latest blockhash.
     *
     * @returns A promise that resolves to a string representing the blockhash.
     */
    getBlockhash(): Promise<string>;
    /**
     * Delegates a specified amount from a stake account to a validator.
     *
     * @param address - The public key of the account.
     * @param lamports - The amount in lamports to be delegated.
     * @param stakeAccount - The public key of the stake account.
     *
     * @throws Throws an error if the amount is less than the minimum amount, or if there's an issue during the delegation process.
     *
     * @returns Returns a promise that resolves with the delegation transaction.
     *
     */
    delegate(address: string, lamports: number, stakeAccount: string): Promise<ApiResponse<VersionedTransaction>>;
    /**
     * Deactivates a stake account.
     *
     * @param address - The public key of the account.
     * @param stakeAccountPublicKey - The public key of the stake account.
     * @throws Throws an error if there's an issue during the deactivation process.
     * @returns Returns a promise that resolves with the deactivation transaction.
     *
     */
    deactivate(address: string, stakeAccountPublicKey: string): Promise<ApiResponse<VersionedTransaction>>;
    /**
     * Withdraws a specified amount from a stake account.
     *
     * @param address - The public key of the account.
     * @param stakeAccountPublicKey - The public key of the stake account.
     * @param stakeBalance - The amount in lamports to be withdrawn from the stake account.
     *
     * @throws Throws an error if there's an issue during the withdrawal process.
     *
     * @returns Returns a promise that resolves with the withdrawal transaction.
     *
     */
    withdraw(address: string, stakeAccountPublicKey: PublicKey, stakeBalance: number): Promise<ApiResponse<VersionedTransaction>>;
    /**
     * Fetches the delegations of a given account.
     *
     * @param address - The public key of the account.
     *
     * @throws Throws an error if there's an issue fetching the delegations.
     *
     * @returns Returns a promise that resolves with the delegations of the account.
     *
     */
    getDelegations(address: string): Promise<ApiResponse<Array<SolDelegation>>>;
    /**
     * Stakes a certain amount of lamports.
     *
     * @param sender - The public key of the sender.
     * @param lamports - The number of lamports to stake.
     * @param source  - stake source
     * @param lockup - stake account lockup
     * @returns A promise that resolves to a VersionedTransaction object.
     */
    stake(sender: string, lamports: number, source: string | null, lockup?: Lockup | null): Promise<ApiResponse<VersionedTransaction>>;
    /**
     * Create account Tx, public key and array of keypair.
     *
     * @param address - The public key of the account.
     * @param lamports - The number of lamports to stake.
     * @param lockup - The stake account lockup
     *
     * @throws Throws an error if there's an issue creating an account.
     *
     * @returns Returns a promise that resolves with the Transaction, PublicKey and array of Keypair.
     *
     */
    private createAccountTx;
    /**
     * Create account Tx, public key and array of keypair using seed.
     *
     * @param authorityPublicKey - The public key of the account.
     * @param lamports - The number of lamports to stake.
     * @param source - The stake source
     * @param lockup - The stake account lockup
     *
     * @throws Throws an error if there's an issue creating an account.
     *
     * @returns Returns a promise that resolves with the Transaction, PublicKey and array of Keypair.
     *
     */
    private createAccountWithSeedTx;
    /** unstake - unstake
     * @param {string} sender - account blockchain address (staker)
     * @param {number} lamports - lamport amount
     * @param {string} source - stake source
     * @returns {Promise<object>} Promise object with Versioned Tx
     */
    unstake(sender: string, lamports: number, source: string): Promise<ApiResponse<VersionedTransaction>>;
    /**
     * Split existing account to create a new one
     *
     * @param authorityPublicKey - The public key of the account.
     * @param lamports - The number of lamports to stake.
     * @param oldStakeAccountPubkey -The public key of the old account.
     * @param source - The stake source
     *
     * @throws Throws an error if there's an issue splitting an account.
     *
     * @returns Returns a promise that resolves with the Transaction, PublicKey and array of Keypair.
     *
     */
    private split;
    /**
     * Claim makes withdrawal from all sender's deactivated accounts.
     *
     * @param sender - The sender solana address.
     *
     * @throws Throws an error if there's an issue while claiming a stake.
     *
     * @returns Returns a promise that resolves with a Versioned Transaction.
     *
     */
    claim(sender: string): Promise<ApiResponse<VersionedTransaction>>;
    getEpochInfo(): Promise<ApiResponse<EpochInfo>>;
    /**
     * Merge two accounts into a new one
     *
     * @param authorityPublicKey - The public key of the account.
     * @param stakeAccount1 - The public key of the first account.
     * @param stakeAccount2 - The public key of the second account.
     *
     * @throws Throws an error if there's an issue while merging an account.
     *
     * @returns Returns a promise that resolves with the Transaction, PublicKey and array of Keypair.
     *
     */
    private merge;
    /**
     * Generate a unique source for crating an account.
     *
     * @param source - source ID.
     *
     * @returns Returns a unique source for an account.
     *
     */
    private formatSource;
    /**
     * Generate timestamp in seconds.
     *
     * @returns Returns a timestamp in seconds.
     *
     */
    private timestampInSec;
}

export { type ApiResponse, FILTER_DATA_SIZE, FILTER_OFFSET, ParseStakeAccountError, SOL_CHAIN, SOL_DEVNET_VALIDATOR_ADDRESS, SOL_MAINNET_VALIDATOR_ADDRESS, SOL_MIN_AMOUNT, type SolAccount, type SolAccountToSplit, type SolCreateAccountResponse, type SolDelegation, SolNetwork, Solana, StakeAccount, StakeAccountType, StakeState };
