At a glance
- Resource:
sdk.withdrawals - Typical flow:
quote → create → wait({ for: 'l2' }) → wait({ for: 'ready' }) → finalize - Auto-routing: ETH vs ERC-20 and base-token vs non-base handled internally
- Error style: Throwing methods (
quote,prepare,create,status,wait,finalize) + result variants (tryQuote,tryPrepare,tryCreate,tryWait,tryFinalize)
Import
Quick start
Withdraw 0.1 ETH from L2 → L1 and finalize on L1:Withdrawals are two-phase: inclusion on L2, then finalization on L1. You can call
finalize directly; it will throw if not yet ready. Prefer wait(..., { for: 'ready' }) to avoid that.Route selection (automatic)
eth-base— Base token is ETH on L2eth-nonbase— Base token is not ETH on L2erc20-nonbase— Withdrawing an ERC-20 that is not the base token
token.
Method reference
quote(p: WithdrawParams) → Promise<WithdrawQuote>
Estimate the operation (route, approvals, gas hints). Does not send txs.
Returns: WithdrawQuote
tryQuote(p) → Promise<{ ok: true; value: WithdrawQuote } | { ok: false; error }>
Result-style quote.
prepare(p: WithdrawParams) → Promise<WithdrawPlan<TransactionRequest>>
Builds the plan (ordered L2 steps + unsigned txs) without sending.
Returns: WithdrawPlan
tryPrepare(p) → Promise<{ ok: true; value: WithdrawPlan } | { ok: false; error }>
Result-style prepare.
create(p: WithdrawParams) → Promise<WithdrawHandle<TransactionRequest>>
Prepares and executes required L2 steps. Returns a handle with the L2 tx hash.
Returns: WithdrawHandle
tryCreate(p) → Promise<{ ok: true; value: WithdrawHandle } | { ok: false; error }>
Result-style create.
status(handleOrHash) → Promise<WithdrawalStatus>
Report current phase for a withdrawal. Accepts the WithdrawHandle from create or a raw L2 tx hash.
Phases
UNKNOWN— no L2 hash providedL2_PENDING— L2 receipt missingPENDING— included on L2 but not yet finalizableREADY_TO_FINALIZE— can be finalized on L1 nowFINALIZED— already finalized on L1
wait(handleOrHash, { for: 'l2' | 'ready' | 'finalized', pollMs?, timeoutMs? })
Block until a target is reached.
{ for: 'l2' }→ resolves L2 receipt (TransactionReceiptZKsyncOS) ornull{ for: 'ready' }→ resolvesnullwhen finalizable{ for: 'finalized' }→ resolves L1 receipt (if found) ornull
tryWait(handleOrHash, opts) → Result<TransactionReceipt | null>
Result-style wait.
finalize(l2TxHash: Hex) → Promise<{ status: WithdrawalStatus; receipt?: TransactionReceipt }>
Sends the L1 finalize transaction if ready. If already finalized, returns the status without sending.
If not ready,
finalize throws a typed STATE error. Use status(…) or wait(..., { for: 'ready' }) first to avoid throws.tryFinalize(l2TxHash) → Promise<{ ok: true; value: { status: WithdrawalStatus; receipt?: TransactionReceipt } } | { ok: false; error }>
Result-style finalize.
End-to-end examples
Minimal happy path
Types (overview)
Notes & pitfalls
- Two chains, two receipts: inclusion on L2 and finalization on L1 are independent events.
- Polling strategy: for production UIs, prefer
thenwait({ for: 'ready' })finalize; it avoids premature finalize calls. - Approvals: if withdrawing ERC-20 requires approvals,
createwill include those steps automatically.