import { Address } from 'viem';
import { ChainId } from '../../api/vault-config.mjs';
import { AtomicQueueAbi } from '../../contracts/atomic-queue-abi.mjs';
import { BoringVaultAbi } from '../../contracts/boring-vault-abi.mjs';
import { BridgeTransactionData } from '../bridge.mjs';
import { VaultKey } from '../config.mjs';
import { TokenKey } from '../tokens.mjs';
import 'viem/chains';
import '../../contracts/cross-chain-teller-base-abi.mjs';

/**
 * @file Withdraw functionality for Nucleus vaults
 * @module vaults/withdraw
 */

/**
 * Arguments for an atomic request to the AtomicQueue contract
 * @typedef {Object} AtomicRequestArgs
 * @property {Address} offer - Address of the token being offered (shares token address)
 * @property {Address} want - Address of the token being requested (want token address)
 * @property {UserRequest} userRequest - User request details
 */
type AtomicRequestArgs = {
    offer: Address;
    want: Address;
    userRequest: UserRequest;
};
/**
 * Options for an atomic request
 * @typedef {Object} AtomicRequestOptions
 * @property {Address} atomicQueueContractAddress - Address of the AtomicQueue contract
 * @property {number} chainId - ID of the destination chain
 */
type AtomicRequestOptions = {
    atomicQueueContractAddress: Address;
    chainId: ChainId;
};
/**
 * User request details for an atomic swap
 * @typedef {Object} UserRequest
 * @property {number} deadline - Unix timestamp when the request expires
 * @property {bigint} atomicPrice - Rate in quote with fee applied
 * @property {bigint} offerAmount - Amount of shares token to redeem
 * @property {boolean} inSolve - Whether the request is in solve mode (always false for new requests)
 */
type UserRequest = {
    deadline: bigint;
    atomicPrice: bigint;
    offerAmount: bigint;
    inSolve: boolean;
};
/**
 * Parameters for preparing a withdrawal transaction from a vault
 * @interface PrepareWithdrawTransactionDataParams
 * @property {ChainId} chainId - ID of the chain where the withdrawal will occur
 * @property {number} [deadline] - Unix timestamp when the request expires (optional)
 * @property {number} offerAmount - Amount of vault shares to withdraw
 * @property {number} [slippage] - Maximum acceptable slippage percentage (optional)
 * @property {Address} userAddress - Ethereum address of the user making the withdrawal
 * @property {VaultKey} vaultKey - Unique identifier for the vault
 * @property {TokenKey} wantTokenSymbol - Symbol of the token the user wants to receive
 */
interface PrepareWithdrawTransactionDataParams {
    chainId: ChainId;
    deadline?: number;
    offerAmount: string;
    slippage?: number;
    userAddress: Address;
    vaultKey: VaultKey;
    wantTokenSymbol: TokenKey;
}
/**
 * Result object containing transaction data for a withdrawal operation
 * @interface WithdrawTransactionData
 * @property {typeof AtomicQueueAbi} abi - ABI for the AtomicQueue contract
 * @property {Address} address - Address of the AtomicQueue contract
 * @property {'updateAtomicRequest'} functionName - Name of the function to call
 * @property {[Address, Address, UserRequest]} args - Arguments for the updateAtomicRequest function:
 *   [offer, want, userRequest]
 * @property {number} chainId - ID of the chain where the transaction should be executed
 */
interface WithdrawTransactionData {
    abi: typeof AtomicQueueAbi;
    address: Address;
    functionName: "updateAtomicRequest";
    args: [offer: Address, want: Address, userRequest: UserRequest];
    chainId: number;
}
/**
 * Prepares the transaction data needed to withdraw assets from a vault
 *
 * This function calculates the appropriate exchange rate with slippage protection
 * and prepares a user request for the AtomicQueue contract. It returns a transaction
 * object that can be used with viem or ethers.js to execute the withdrawal.
 *
 * @example
 * ```typescript
 * const withdrawData = await prepareWithdrawData({
 *   vaultKey: 'bobaeth',
 *   chainId: 1, // Ethereum mainnet
 *   userAddress: '0x1234...',
 *   wantAsset: TokenKey.WETH,
 *   redeemAmount: BigInt('1000000000000000000'), // 1 token
 *   deadline: Math.floor(Date.now() / 1000) + 3600, // 1 hour from now
 *   slippage: 0.01, // 1% slippage
 * });
 * ```
 *
 * @param {PrepareWithdrawTransactionParams} params - Parameters for the withdraw operation
 * @param {VaultKey} params.vaultKey - Unique identifier for the vault
 * @param {ChainId} params.chainId - ID of the chain where the withdrawal will occur
 * @param {Address} params.userAddress - Ethereum address of the user making the withdrawal
 * @param {TokenKey} params.wantAsset - Key of the asset the user wants to receive
 * @param {bigint} params.offerAmount - Amount of vault tokens to redeem (in base units)
 * @param {number} [params.deadline] - Unix timestamp when the request expires
 * @param {number} [params.slippage] - Maximum acceptable slippage in basis points (bps).
 *                                     e.g., 20 for 0.2%, 50 for 0.5%
 *
 * @returns {Promise<WithdrawTransactionData>} Promise resolving to the prepared transaction data
 * @throws {Error} If the vault key is invalid, if contracts are not properly configured,
 *                 or if the specified chain or token is not supported
 */
declare const prepareWithdrawTransactionData: ({ vaultKey, chainId, wantTokenSymbol, offerAmount, deadline, slippage, }: PrepareWithdrawTransactionDataParams) => Promise<WithdrawTransactionData>;
/**
 * Parameters for preparing a cross-chain bridge and withdrawal transaction
 * @interface PrepareBridgeAndWithdrawTransactionDataParams
 * @extends {Omit<PrepareWithdrawTransactionDataParams, 'chainId'>}
 * @property {ChainId} sourceChainId - Chain ID where shares currently exist
 * @property {ChainId} destinationChainId - Chain ID where assets will be withdrawn
 * @property {number} offerAmount - Amount of vault shares to withdraw
 * @property {number} [deadline] - Unix timestamp when the request expires (optional)
 * @property {number} [slippage] - Maximum acceptable slippage percentage (optional)
 * @property {Address} userAddress - Ethereum address of the user making the withdrawal
 * @property {VaultKey} vaultKey - Unique identifier for the vault
 * @property {TokenKey} wantTokenSymbol - Symbol of the token the user wants to receive
 */
interface PrepareBridgeAndWithdrawTransactionDataParams extends Omit<PrepareWithdrawTransactionDataParams, "chainId"> {
    sourceChainId: ChainId;
    destinationChainId: ChainId;
}
/**
 * Combined result containing both bridge and withdrawal transaction data
 * @interface BridgeAndWithdrawResult
 */
interface BridgeAndWithdrawTransactionData {
    bridgeTransactionData: BridgeTransactionData;
    withdrawTransactionData: WithdrawTransactionData;
}
/**
 * Prepares transaction data for cross-chain withdrawals from a vault
 *
 * This function handles both:
 * 1. Bridging vault shares from source chain to destination chain
 * 2. Creating a withdraw request on the destination chain
 *
 * The withdraw request can be submitted before the bridge completes - the solver
 * will wait for bridged shares to arrive before processing the request.
 *
 * @example
 * ```typescript
 * const result = await prepareBridgeAndWithdrawData({
 *   vaultKey: 'bobaeth',
 *   sourceChainId: 42161, // Arbitrum
 *   destinationChainId: 1, // Ethereum
 *   userAddress: '0x1234...',
 *   wantTokenSymbol: TokenKey.ETH,
 *   offerAmount: 1.5, // 1.5 shares
 *   deadline: Math.floor(Date.now() / 1000) + 3600, // 1 hour
 *   slippage: 0.005 // 0.5%
 * });
 * ```
 *
 * @param {PrepareBridgeAndWithdrawParams} params - Parameters for the cross-chain withdraw
 * @returns {Promise<BridgeAndWithdrawResult>} Transaction data for both bridge and withdraw operations
 * @throws {Error} If vault configuration is invalid or if preparing either transaction fails
 */
declare const prepareBridgeAndWithdrawTransactionData: ({ deadline, destinationChainId, offerAmount, slippage, sourceChainId, userAddress, vaultKey, wantTokenSymbol, }: PrepareBridgeAndWithdrawTransactionDataParams) => Promise<BridgeAndWithdrawTransactionData>;
interface PrepareApproveWithdrawTokenParams {
    vaultKey: VaultKey;
    withdrawAmount?: string;
    chainId: ChainId;
}
interface ApproveWithdrawTokenTransactionData {
    abi: typeof BoringVaultAbi;
    address: Address;
    functionName: "approve";
    args: [Address, bigint];
}
declare const prepareApproveWithdrawToken: ({ vaultKey, withdrawAmount, chainId, }: PrepareApproveWithdrawTokenParams) => Promise<ApproveWithdrawTokenTransactionData>;

export { type ApproveWithdrawTokenTransactionData, type AtomicRequestArgs, type AtomicRequestOptions, type BridgeAndWithdrawTransactionData, type PrepareBridgeAndWithdrawTransactionDataParams, type PrepareWithdrawTransactionDataParams, type UserRequest, type WithdrawTransactionData, prepareApproveWithdrawToken, prepareBridgeAndWithdrawTransactionData, prepareWithdrawTransactionData };
