import { BigNumber } from 'ethers'; import { KycParams } from '../facade/types'; import { Flow } from './flow'; import { WaitableTransaction } from './observable'; /** * The withdrawal pipeline, headless — the small sibling of `DepositFlow`. * * Much less happens here, and that is the point of it being separate: no loan * agreement, no approval (the lender is handing tranche shares back, not * granting a spend), no on-chain KYC payload. What survives is the shape both * applications need — an observable phase, one `'max'`-aware submission, and * the same `cancelled` / `failed` split, so a lender who pressed Reject is * never told something broke. * * The run lifecycle — the re-entrancy guard, `state`, `isRunning`, * `subscribe`, `reset` — is `Flow`'s, shared with the deposit pipeline. It was * a second copy here until 2.7.0, which is two places for one guard to be * wrong. * * Same house rules as the deposit flow: no React, no copy, no I/O of its own. * `state` carries codes; the consumer owns every word a lender reads. * * ```ts * const flow = new WithdrawFlow(ports); * flow.subscribe(render); * await flow.start({ poolId, trancheId, amount: 'max', userAddress }); * ``` */ export type WithdrawPhase = 'idle' | 'checking-kyc' | 'request-sign' | 'request-confirm' | 'success' | 'error'; /** * `kyc` only exists when the consumer supplies `getKycSignature`. kasu-mobile * does, to fail early and legibly when a lender's KYC has lapsed rather than * let the on-chain call revert; kasu-ui does not. */ export type WithdrawStep = 'kyc' | 'request'; export type WithdrawFailure = { step: WithdrawStep; reason: 'cancelled'; } | { step: WithdrawStep; reason: 'failed'; error: unknown; }; export interface WithdrawPorts { /** * Build the Nexera KYC params for the pre-check. Defaults to * `kasu.deposits.buildKycParams`, exactly as the deposit flow's does. */ buildKycParams?(userAddress: `0x${string}`): KycParams | Promise; /** * Exchange those params for a signature at the consumer's own backend, and * so verify the lender's KYC BEFORE the wallet is opened — a lapsed one * surfaces as `{ step: 'kyc' }` instead of an opaque revert. The * withdrawal call itself does not carry the signature. * * Supplying this port is what turns the pre-check on; there is no default, * because the SDK does not know the application's backend. This is the * same pair the deposit flow uses, rather than the opaque `ensureKyc` of * earlier drafts, so one KYC pre-check exists across both money paths. */ getKycSignature?(params: KycParams): Promise; /** `requestWithdrawalInAsset`. Defaults to `kasu.deposits.withdraw`. */ withdraw(params: { poolId: string; trancheId: string; amount: BigNumber; }): Promise; /** `requestWithdrawalMax`. Defaults to `kasu.deposits.withdrawMax`. */ withdrawMax(poolId: string, trancheId: string, userAddress: string): Promise; } export interface WithdrawFlowInput { poolId: string; trancheId: string; /** * The amount in BASE units, or the literal `'max'`. * * `'max'` is not "the balance as I last read it": it routes to the * all-shares contract call, which resolves the balance on chain at * execution. Deciding max-ness from a number the consumer read a moment ago * is how dust gets stranded in a tranche, so the decision is a code, made * by the consumer, and carried here intact. */ amount: BigNumber | 'max'; userAddress: `0x${string}`; } export interface WithdrawState { phase: WithdrawPhase; step: WithdrawStep | null; /** True when this run routed through the all-shares call. */ isMax: boolean; failure: WithdrawFailure | null; } /** What a KYC pre-check with no `buildKycParams` to call fails with. */ export declare const NO_KYC_PARAMS_MESSAGE = "WithdrawFlow: getKycSignature was supplied without buildKycParams; build the flow with kasu.flows.withdraw() or pass both"; export declare class WithdrawFlow extends Flow { private readonly _ports; constructor(_ports: WithdrawPorts); protected _run(input: WithdrawFlowInput, token: number): Promise; }