import { BigNumber } from '@ethersproject/bignumber';
import { Decimal as RootDecimal } from 'decimal.js';
import type { Channel } from '../../channels';
import { Fee } from '../../services/types';
import type { UInt, UnionToIntersection } from '../../utils/types';
declare const Decimal: typeof RootDecimal;
declare type Decimal = RootDecimal;
declare type FeeFunc<BNIn extends Decimal | BigNumber, BNOut extends Decimal | BigNumber = BNIn> = (amount: BNIn) => BNOut;
/**
 * Defines the interface for a fee model, which receives and validates a given config,
 * and calculates the fees for given config, channel state and input transfer amount.
 * Generics in this type are important:
 * - Config declares the configuration type expected for this specific feeModel component
 * - Schedule declares the type for the output of [schedule] member function, which should be an
 *    object to be merged with all other models and used as PFSFeeUpdate['fee_schedule'] payload
 */
export interface FeeModel<Config, Schedule> {
    /** name of the fee model */
    readonly name: string;
    readonly emptySchedule: Schedule;
    /**
     * Validates and decodes the config; throws if expected config schema doesn't fit
     *
     * @param config - any object/value to validate as config
     * @returns Decoded config, to be used in the other functions
     */
    decodeConfig: (config: unknown, defaultConfig?: unknown) => Config;
    /**
     * Given (validated) config and a single channel, return a function to calculate this model's
     * fees for each incoming transfer amount
     *
     * @param config - Validated and decoded config by [decodeConfig]
     * @param channel - Channel state to calculate fee for
     * @returns Function which receives input amounts and returns fee
     */
    channelFee: (config: Config, channel: Channel) => FeeFunc<Decimal>;
    /**
     * Given (validated) config and pair of channels, return a function to calculate this model's
     * fees for each incoming transfer amount
     *
     * @param config - Validated and decoded config by [decodeConfig]
     * @param channelIn - Channel state where transfer got received
     * @param channelOut - Channel state where transfer is supposed to be forwarded through
     * @returns Function which receives input amounts and returns fee
     */
    fee: (config: Config, channelIn: Channel, channelOut: Channel) => FeeFunc<UInt<32>, Fee>;
    /**
     * Calculate this model's slice of the payload to PFSFeeUpdate messages
     *
     * @param config - Validated config
     * @param channel - Channel state to calculate FeeUpdate for
     * @returns A property of the fee_schedule member of [[PFSFeeUpdate]]
     */
    schedule: (config: Config, channel: Channel) => Schedule;
}
declare type ScheduleOf<M extends FeeModel<any, any>> = M['emptySchedule'];
export declare const flatFee: FeeModel<Fee, {
    flat: Fee;
}>;
export declare const proportionalFee: FeeModel<number, {
    proportional: Fee;
}>;
declare type Point<N = BigNumber> = readonly [N, N];
declare type DiscreteFunc<N = BigNumber> = readonly [Point<N>, ...Point<N>[], Point<N>];
export declare const imbalancePenaltyFee: FeeModel<number, {
    imbalance_penalty: DiscreteFunc<UInt<32>> | null;
}>;
/**
 * Returns a standard mediation FeeModel which translates a per-token mapping of feeModels to a
 * model which validates each per-key config and calculates the fees sum
 *
 * Config is expected and decoded as being a indexed mapping object where keys are token addresses,
 * and values are objects containing optional config properties where keys are the models keys
 * passed as parameter and values are each FeeModel expected and validated config.
 * e.g.:
 * - models={ flat: flatFee<number> };
 * - expectedConfig={ [token: Address]: { flat: number } }
 *
 * Additionally, if an [AddressZero] token config is present, it'll be used as fallback/default
 * config in case the requested token isn't set.
 *
 * @param models - Models dict where [key] is that model's config name on the per-token config obj
 * @returns Standard Fee calculator
 */
export declare function getStandardFeeCalculator<Models extends {
    [K: string]: FeeModel<any, Record<string, any>>;
}>(models: Models): FeeModel<{
    readonly [token: string]: Readonly<{
        cap: boolean;
    } & { [K in keyof Models]?: ReturnType<Models[K]["decodeConfig"]> | undefined; }>;
}, {
    cap_fees: boolean;
} & UnionToIntersection<ScheduleOf<Models[keyof Models]>>>;
export declare const standardCalculator: FeeModel<{
    readonly [token: string]: Readonly<{
        cap: boolean;
    } & {
        flat?: import("../../utils/types").Int<32> | undefined;
        proportional?: number | undefined;
        imbalance?: number | undefined;
    }>;
}, {
    cap_fees: boolean;
} & {
    flat: Fee;
} & {
    proportional: Fee;
} & {
    imbalance_penalty: DiscreteFunc<UInt<32>> | null;
}>;
export {};
