/// <reference types="node" />
declare class BaseRewardsReporter {
    reportSuccess(_: {
        userId: number;
        challengeId: string;
        amount: number;
        specifier: string;
    }): Promise<void>;
    reportRetry(_: {
        userId: number;
        challengeId: string;
        amount: number;
        error: string;
        phase: string;
    }): Promise<void>;
    reportFailure(_: {
        userId: number;
        challengeId: string;
        amount: number;
        error: string;
        phase: string;
    }): Promise<void>;
    reportAAORejection(_: {
        userId: number;
        challengeId: string;
        amount: number;
        error: string;
        reason: string;
    }): Promise<void>;
}
declare type ATTESTER_PHASE = 'HALTED' | 'SELECTING_NODES' | 'REFILLING_QUEUE' | 'ATTESTING' | 'SLEEPING' | 'RETRY_BACKOFF';
/**
 * Class to encapsulate logic for calculating disbursement delay thresholds.
 * Periodically polls Solana to get slot production rate.
 * Caches old values (`allowedStalenessSec`) for current POA block & Solana slot to reduce RPC
 * overhead.
 *
 * Exposes `getPOABlockThreshold` and `getSolanaSlotThreshold`
 *
 * @class ThresholdCalculator
 */
export declare class AttestationDelayCalculator {
    libs: any;
    solanaSecPerSlot: number;
    runBehindSec: number;
    lastSolanaThreshold: {
        threshold: number;
        time: number;
    } | null;
    lastPOAThreshold: {
        threshold: number;
        time: number;
    } | null;
    allowedStalenessSec: number;
    solanaPollingInterval: number;
    logger: any;
    intervalHandle: NodeJS.Timeout | null;
    private readonly blockOffset;
    constructor({ libs, runBehindSec, allowedStalenessSec, blockOffset, solanaPollingInterval, logger }: {
        libs: any;
        runBehindSec: number;
        allowedStalenessSec: number;
        solanaPollingInterval?: number;
        logger: any;
        blockOffset: number;
    });
    start(): Promise<void>;
    stop(): void;
    getPOABlockThreshold(): Promise<number>;
    getSolanaSlotThreshold(): Promise<number>;
}
declare type ConstructorArgs = {
    libs: any;
    startingBlock: number;
    offset: number;
    parallelization: number;
    logger?: any;
    quorumSize: number;
    aaoEndpoint: string;
    aaoAddress: string;
    updateValues: ({ startingBlock, offset, successCount }: {
        startingBlock: number;
        offset: number;
        successCount: number;
    }) => void;
    getStartingBlockOverride: () => Promise<number | null> | number | null;
    maxRetries: number;
    reporter?: BaseRewardsReporter;
    challengeIdsDenyList: string[];
    endpoints?: string[];
    runBehindSec?: number;
    isSolanaChallenge?: (challenge: string) => boolean;
    feePayerOverride: string | null;
    maxAggregationAttempts?: number;
    updateStateCallback?: (state: AttesterState) => Promise<void>;
    maxCooldownMsec?: number;
    blockOffset: number;
};
declare type Challenge = {
    challengeId: string;
    userId: string;
    specifier: string;
    amount: number;
    handle: string;
    wallet: string;
    completedBlocknumber: number;
};
declare type AttestationResult = Challenge & {
    error?: string | null;
    phase?: string | null;
    aaoErrorCode?: number | null;
    nodesToReselect?: string[] | null;
};
declare type AttesterState = {
    phase: ATTESTER_PHASE;
    lastSuccessChallengeTime: number | null;
    lastChallengeTime: number | null;
    lastActionTime: number;
};
/**
 * `RewardsAttester` is responsible for repeatedly attesting for completed rewards.
 *
 * **Implementation**
 *
 * `RewardsAttester` attempts to attest for `parallelization` rewards in parallel.
 * It won't move onto the next batch of rewards until every reward in that batch has
 * either succeeded or failed attestation. It retries errors that might be due to DN
 * timing issues, and skips AAO errors and some Solana program errors.
 *
 * Internally, state is tracked with two variables: `offset` and `startingBlock`.
 * `startingBlock` represents which block it start requesting attestations from, while `offset` determines
 * where within those results we offset. AAO rejected rewards
 * are never cleared from the DN rewards queue, so we have to move past them either with `offset` or `startingBlock`.
 * `RewardsAttester` accepts callbacks (`updateValues`) for a client to persist these values periodically.
 *
 * RewardsAttester will fetch a single large list of undisbursed rewards (`undisbursedQueue`), and
 * process that entire list before fetching new undisbursed rewards. It also maintains a list of
 * recently processed rewards, and filters those out when re-fetching new undisbursed rewards.
 */
export declare class RewardsAttester {
    private startingBlock;
    private offset;
    private recentlyDisbursedQueue;
    private _shouldStop;
    private endpoints;
    private undisbursedQueue;
    private attesterState;
    private parallelization;
    private aaoEndpoint;
    private aaoAddress;
    private endpointPool;
    private challengeIdsDenyList;
    private discoveryNodeBlocklist;
    private readonly libs;
    private readonly logger;
    private readonly quorumSize;
    private readonly reporter;
    private readonly maxRetries;
    private readonly maxAggregationAttempts;
    private readonly updateValues;
    private readonly cooldownMsec;
    private readonly backoffExponent;
    private readonly maxCooldownMsec;
    private readonly getStartingBlockOverride;
    private readonly feePayerOverride;
    private readonly delayCalculator;
    private readonly isSolanaChallenge;
    private readonly _updateStateCallback;
    /**
     * Creates an instance of RewardsAttester.
     * @memberof RewardsAttester
     */
    constructor({ libs, startingBlock, offset, parallelization, logger, quorumSize, aaoEndpoint, aaoAddress, updateValues, getStartingBlockOverride, maxRetries, reporter, challengeIdsDenyList, endpoints, runBehindSec, isSolanaChallenge, feePayerOverride, maxAggregationAttempts, updateStateCallback, maxCooldownMsec, blockOffset }: ConstructorArgs);
    /**
     * Begin attestation loop. Entry point for identity attestations
     *
     * @memberof RewardsAttester
     */
    start(): Promise<void>;
    stop(): Promise<void>;
    /**
     * Called from the client to attest challenges
     */
    processChallenges(challenges: Challenge[]): Promise<{
        errors: AttestationResult[];
    } | {
        errors?: undefined;
    }>;
    /**
     * Updates attester config
     *
     * @memberof RewardsAttester
     */
    updateConfig({ aaoEndpoint, aaoAddress, endpoints, challengeIdsDenyList, parallelization }: {
        aaoEndpoint: string;
        aaoAddress: string;
        endpoints: string[];
        challengeIdsDenyList: string[];
        parallelization: number;
    }): void;
    /**
     * Sleeps until the feePayer has a usable Sol balance.
     *
     * @memberof RewardsAttester
     */
    _awaitFeePayerBalance(): Promise<void>;
    /**
     * Returns the override feePayer if set, otherwise a random fee payer from among the list of existing fee payers.
     *
     * @memberof RewardsAttester
     */
    _getFeePayer(): string | null;
    /**
     * Escape hatch for manually setting starting block.
     *
     * @memberof RewardsAttester
     */
    _checkForStartingBlockOverride(): Promise<void>;
    /**
     * Main method to attest for a bucket of challenges in parallel.
     *
     * Algorithm:
     * - Gets `this.parallelization` undisbursed challenges from the queue, refilling it from DN if necessary.
     * - Call `_performSingleAttestation` on those in parallel.
     * - For challenges that failed, either keep retrying or discard them, depending on the error.
     * - Set offset and startingBlock
     *
     * @memberof RewardsAttester
     */
    _attestInParallel(toAttest: Challenge[]): Promise<{
        accumulatedErrors: AttestationResult[];
        highestBlock: number | null;
        offset: number;
        successCount: number;
    }>;
    /**
     * Attempts to attest for a single challenge.
     *
     * @memberof RewardsAttester
     */
    _performSingleAttestation({ challengeId, userId, specifier, amount, handle, wallet, completedBlocknumber }: Challenge): Promise<AttestationResult>;
    _selectDiscoveryNodes(): Promise<void>;
    /**
     * Fetches new undisbursed rewards and inserts them into the undisbursedQueue
     * if the queue is currently empty.
     *
     * @memberof RewardsAttester
     */
    _refillQueueIfNecessary(): Promise<{
        error?: undefined;
    } | {
        error: string;
    }>;
    /**
     * Processes responses from `_performSingleAttestation`,
     * bucketing errors into those that need retry and those that should be skipped.
     *
     * @memberof RewardsAttester
     */
    _processResponses(responses: AttestationResult[], isFinalAttempt: boolean): Promise<{
        successful: AttestationResult[];
        noRetry: AttestationResult[];
        needsRetry: AttestationResult[];
        shouldReselect: boolean;
        failingNodes: string[];
    }>;
    _disbursementToKey({ challengeId, userId, specifier }: Challenge): string;
    _backoff(retryCount: number): Promise<void>;
    _delay(waitTime: number): Promise<void>;
    _addRecentlyDisbursed(challenges: Challenge[]): void;
    _filterRecentlyCompleted(challenges: Challenge[]): Promise<Challenge[]>;
    _updateState(newState: Partial<AttesterState>): Promise<void>;
    _updatePhase(phase: ATTESTER_PHASE): Promise<void>;
}
export {};
