@funkit/connect
Version:
Funkit Connect SDK elevates DeFi apps via web2 sign-ins and one-click checkouts.
183 lines (182 loc) • 8.09 kB
TypeScript
/**
* Lighter.xyz withdrawal.
*
* Lighter supports two withdrawal types — the SDK exposes them as a
* multi-method config so the user is shown a selection screen first:
*
* 1. **Fast** — routed through Fun + Relay. USDC Perps only. Multiple
* destination chains/tokens supported. Completes in seconds.
* 2. **Secure** — Lighter's native bridge to Ethereum mainnet. Supports all
* Lighter assets. Destination chain is locked to Ethereum and the
* destination token matches the source. Completion ~60+ minutes.
*
* Both callbacks conform to CustomWithdrawalConfig.withdrawCallback; the
* caller provides the actual on-chain implementation.
*/
import { type Address } from 'viem';
import type { CustomWithdrawalConfig, LighterRouteType, MultiMethodWithdrawalConfig } from '../providers/FunkitCheckoutContext/types';
export { LIGHTER_ROUTE_TYPE } from '../modals/WithdrawalModal/LighterWithdrawal';
export type { LighterRouteType } from '../providers/FunkitCheckoutContext/types';
export type LighterTransferParams = {
toAccountIndex: number;
assetIndex: number;
fromRouteType: number;
toRouteType: number;
amount: number;
usdcFee: number;
memo: string;
ethSigner?: {
signMessage: (message: string) => Promise<string>;
};
nonce?: number;
};
export type LighterTransaction = {
hash: string;
status: number | 'pending' | 'confirmed' | 'failed';
block_height?: number;
message?: string;
};
export type LighterSigner = {
transfer: (params: LighterTransferParams) => Promise<[unknown, string, string | null]>;
};
export interface LighterWithdrawalConfig {
/**
* The connected user's L1 address. The hook resolves the Lighter account
* index from this internally — get it from `useFunkitUserInfo` (or your
* own wallet hook) in the caller and pass it through.
*/
l1Address: Address;
/** Title shown on the selection screen. Defaults to "Withdraw". */
modalTitle?: string;
disableConnectedWallet?: boolean;
fastIconSrc?: string;
secureIconSrc?: string;
/** Pre-built Lighter signer. */
signerClient: LighterSigner;
sendLighterSecureWithdrawal: LighterSecureWithdrawalExec;
/**
* Returns the minimum Secure withdrawal amount in token units for the given symbol.
* Spot USDC is passed as `USDC (Spot)` (perps collateral is plain `USDC`);
* return `undefined` to fall back to the per-base-symbol defaults.
*
* ```ts
* getSecureMinWithdrawalAmount: (symbol) => ({ USDC: 1, ETH: 0.001 }[symbol] ?? 0)
* ```
*/
getSecureMinWithdrawalAmount?: (symbol: string) => number | undefined;
/**
* Awaited hook fired after the user taps "Withdraw" but before either method
* (Fast or Secure) fetches a nonce, prompts the wallet, or submits the L2 tx.
*
* Lighter strategies and withdrawals share the same L2 signing account, so a
* strategy that's still placing/cancelling orders will bump the nonce out
* from under the withdrawal and the signed tx is rejected. Cancel in-flight
* strategies here (awaited) so the withdrawal signs against a stable nonce.
*
* Throw to abort the withdrawal — the message is shown to the user verbatim
* and no nonce is consumed. Applies to both Fast and Secure.
*/
onBeforeSign?: () => Promise<void> | void;
}
/**
* Default minimum Secure-withdrawal amounts (token units) for known Lighter
* assets. Used as a fallback when `LighterWithdrawalConfig.getSecureMinWithdrawalAmount`
* is omitted or returns `undefined` for a symbol.
*/
export declare const LIGHTER_DEFAULT_SECURE_MIN_WITHDRAWAL_AMOUNTS: Record<string, number>;
export interface LighterSecureWithdrawalCallbackParams {
/** Withdrawal amount in token units (e.g. "1.5" for 1.5 ETH). */
amountTokenUnits: string;
/** The Lighter asset index (e.g. 1 for ETH, 3 for USDC). */
assetIndex: number;
/**
* Lighter L2 route type ({@link LIGHTER_ROUTE_TYPE}: 0 = perps / USDC
* collateral, 1 = spot). Pass it through to `client.withdraw({ routeType })`
* — USDC shares asset index 3 across both routes, so the route type is what
* selects Perps vs Spot.
*/
routeType: LighterRouteType;
}
type LighterSecureWithdrawalExec = (params: LighterSecureWithdrawalCallbackParams) => Promise<string>;
export interface LighterSecureWithdrawalConfig {
accountIndex: string;
modalTitle?: string;
disableConnectedWallet?: boolean;
iconSrc?: string;
/**
* Submit the Secure withdrawal on Lighter's L2. Funds bridge directly to
* Ethereum mainnet. No relay/swap — the token withdrawn is the token received.
*/
sendLighterSecureWithdrawal: LighterSecureWithdrawalExec;
/**
* Returns the minimum withdrawal amount in token units for the given symbol.
*
* ```ts
* getMinWithdrawalAmount: (symbol) => ({ USDC: 1, ETH: 0.001 }[symbol] ?? 0)
* ```
*/
getMinWithdrawalAmount?: (symbol: string) => number;
/**
* Awaited hook fired before the Secure withdrawal fetches a nonce, prompts
* the wallet, or submits the L2 tx. See {@link LighterWithdrawalConfig['onBeforeSign']}.
*/
onBeforeSign?: () => Promise<void> | void;
}
/**
* Records a Lighter Secure withdrawal in Fun's direct-execution table as
* `EXTERNALLY_FULFILLED` — tracking-only, since Fun is not in the execution
* path. The row is keyed off the L2 tx hash and exists purely for attribution
* and support tooling; the backend writes a one-time terminal `listenerInfo`
* and never polls for L1 settlement (see EXTERNALLY_FULFILLED design doc).
*
* Fire-and-forget: callers should not await this, and any failure here must
* not block the withdrawal success UI. Failures log at warn/error and return.
*/
export declare function trackLighterSecureWithdrawal({ apiKey, userId, txHash, recipientAddr, assetIndex, mainnetTokenAddress, amountTokenUnits, withdrawalUSD, }: {
apiKey: string;
userId: string;
txHash: string;
recipientAddr: Address;
/**
* Lighter L2 asset index. Used as `fromTokenAddress`
* (`pad(toHex(assetIndex))`) and to resolve symbol + mainnet decimals from
* {@link LIGHTER_SECURE_ASSETS_BY_INDEX}.
*/
assetIndex: number;
/** Mainnet ERC-20 address the L2 asset bridges to (resolved by the modal). */
mainnetTokenAddress: Address;
/** User-input amount in token units (e.g. "1.5" for 1.5 ETH). */
amountTokenUnits: string;
/**
* USD value of the withdrawal as computed by the modal (token amount × live
* spot price). Avoids a separate spot-price round-trip from this helper.
*/
withdrawalUSD: string;
}): Promise<void>;
/** Single-method config for Lighter's Secure withdrawal (bridge to Ethereum). */
export declare function createLighterSecureWithdrawalConfig(config: LighterSecureWithdrawalConfig): CustomWithdrawalConfig;
/**
* The single React entry point for Lighter withdrawals. Returns a
* `MultiMethodWithdrawalConfig` ready to hand to the withdrawal modal, or
* `null` while the inputs aren't ready yet.
*
* The hook owns every Lighter-specific concern that requires React context:
* - the user's Lighter account index (resolved from `config.l1Address`)
* - the live Secure-withdrawal delay (`/api/v1/withdrawalDelay`)
* - the active locale (so the disclaimer renders correctly)
*
* Pass `null` while prerequisites (wallet, signer, etc.) aren't ready — the
* hook always invokes its inner hooks (Rules of Hooks) and returns `null`
* until you supply a real config and the account resolves:
*
* ```tsx
* const { address: l1Address } = useFunkitUserInfo()
* const lighter = useLighterWithdrawalConfig(
* l1Address && walletClient
* ? { l1Address, signerClient, sendLighterSecureWithdrawal, ... }
* : null,
* )
* if (!lighter) return { ready: false, disabledReason: '...' }
* ```
*/
export declare function useLighterWithdrawalConfig(config: LighterWithdrawalConfig | null): MultiMethodWithdrawalConfig | null;