Vault Operations
(assetId: string, amount: bigint, autoWait?: boolean, target?: DepositTarget, options?: DepositOptions) => Promise<TransactionResult>
Deposit tokens into vault. Uses asset ID (UUID) from trading pair.Parameters:
assetId: string - Asset UUID (from trading pair)amount: bigint - Token amount in smallest unitautoWait?: boolean - Wait for on-chain confirmation (default: true)target?:"spot" | "margin"- Destination ledger (default:"spot")"spot"— credits the spot wallet (unchanged behavior)"margin"— routes the deposit straight into the parent margin account’s collateral, skipping the separatetransferCollateralToParentMarginAccountstep. Deposits that cannot be routed to margin (e.g. unsupported asset) fall back to spot automatically.
options?:DepositOptions- Deposit options.asErc20: truedeposits the chain’s wrapped-native asset (e.g. WSEI) as its ERC20 through approve +depositERC20, instead of the native-coin default below; it is ignored for every other asset. The ERC20 path is not auto-approved —depositthrows aContractError(code === "CONTRACT_ERROR") withrevertReason === "APPROVAL_REQUIRED"if the allowance is short, soapprove(orneedsApprovalwith the same option) first.
Wrapped-native assets deposit as native coin. When the asset is the chain’s wrapped-native token (e.g. WSEI) — the
wrappedNative: true flag on its balance row — deposit routes to the vault’s payable depositNative and sends amount as msg.value; the vault wraps it on entry. No ERC20 approval is required or checked for these assets, so you can skip the approve / needsApproval step. Every other asset keeps the approve + depositERC20 flow. Withdrawals of a wrapped-native asset pay out native coin (the vault unwraps), decided server-side with no request change.To deposit the wrapped-native asset from a wallet that already holds the wrapped ERC20 itself, pass { asErc20: true } as the fifth argument: deposit then takes the standard approve + depositERC20 path (not depositNative), and needsApproval(assetId, amount, { asErc20: true }) reads the real allowance instead of returning false.(assetId: string, amount: bigint, autoWait?: boolean, source?: WithdrawalSource) => Promise<WithdrawResult>
Withdraw tokens from vault. Posts to Returns:
/api/v1/withdrawals, waits for merkle-proof-backed executeWithdrawal(...) calldata, then submits the transaction on-chain.Parameters:assetId: string - Asset UUID (from trading pair)amount: bigint - Token amount in smallest unitautoWait?: boolean - Wait for on-chain confirmation (default: true)source?:"spot" | "margin"- Source ledger (default:"spot")"spot"— debits the spot wallet"margin"— directly debits withdrawable collateral from the parent margin account
autoWait is true (default), the call waits for the withdrawal’s on-chain merkle-proof calldata before submitting. The default wait timeout is 1 minute (60 seconds), polling every 5000 ms. Override these via WithdrawalRetryOptions { pollIntervalMs?: number; timeoutMs?: number }.When autoWait is false, the call returns immediately after the withdrawal is registered — it does not poll for the merkle proof. Use this when you want to initiate the withdrawal and complete the on-chain step later:WithdrawResult:withdrawalIndex: number — the index allocated by the matching engine. Store this — you’ll need it if the on-chain submission fails and you want to retryhash?: string — transaction hash; absent whenautoWaitisfalsestatus: string —"awaiting_proof"whenautoWaitisfalse; transaction status otherwise
(withdrawalIndex: number, autoWait?: boolean) => Promise<WithdrawResult>
Re-submit a withdrawal whose on-chain transaction failed or was dropped. Fetches the same merkle-proof-backed calldata for that
withdrawalIndex and resubmits it. Does not allocate a new withdrawal slot — safe to call multiple times.Parameters:withdrawalIndex: number — returned by the originalwithdraw()call
WithdrawResult shape as withdraw().() => Promise<string>
Get the vault contract address for the current network.Returns: Vault contract address (e.g., Network-specific:
0x1234...)Use cases:- Add vault address to wallet for direct contract interaction
- Verify transactions on blockchain explorers
- Advanced integrations requiring direct contract access
- Staging (testnet): Returns Atlantic-2 vault address
Low-Level Withdrawals
Thesdk.withdrawals API exposes the raw withdrawal calldata flow. Unlike
sdk.vault.withdraw — which waits for the merkle-proof-backed calldata and
broadcasts the transaction on-chain — sdk.withdrawals returns the ABI-encoded
executeWithdrawal(...) calldata without broadcasting. Use it when you want
to submit the transaction yourself (custom signer, relayer, batching, or
inspection).
(request: InitiateWithdrawalRequest) => Promise<WithdrawalResponse>
Initiate a withdrawal. Authenticated (master accounts with the withdraw permission). Debits the caller’s balance via the matching engine and allocates a withdrawal index. Does not submit on-chain.Request:
assetId: Asset UUID to withdrawamount: Raw token amount in the smallest unit, as a stringified positive integerdestination: On-chain address that will receive the withdrawal (EVM, 0x-prefixed)
WithdrawalResponse:withdrawalIndex: number — matchesexecuteWithdrawal.indexon-chainvaultAddress: string — vault contract the calldata is submitted tocalldata: string — ABI-encodedexecuteWithdrawal(...)calldata; empty until the merkle proof is available
(withdrawalIndex: number) => Promise<WithdrawalResponse>
Re-fetch a previously-initiated withdrawal’s executable calldata. Public — no auth required.Parameters:
withdrawalIndex: number — returned byinitiateWithdrawal()
WithdrawalResponse shape as initiateWithdrawal().Registered Deposit Addresses
Instead of theapprove → deposit flow above, you can give a user a stable, deterministic deposit address and have deposits of the watched assets swept into the rollup automatically. Only the assets sweeper.getChains (below) lists are indexed — the transfer indexer filters logs to those token addresses — so an unlisted ERC20 sent to the address is not swept. Every (application, user, deposit target) triple maps to one such address; registering the triple makes the backend monitor it and forward a watched asset once its accumulated balance reaches that asset’s minimum, crediting the user under the application — no per-deposit signature or transaction from your app.
(body?: RegisterSweeperRequest) => Promise<RegisterSweeperResponse>
Register a deposit address so it is monitored and swept. Requires authentication — call Errors:
sdk.login() first.Both halves of the identity come from the session: the application is the one sdk.login() was called with, and the credited address is the session’s own. Neither is a request field, so this can only ever register the caller’s own address under their own application — and the body carries nothing but the target.Request — RegisterSweeperRequest (optional; omit it entirely for a spot address):depositTarget?:"spot" | "margin"— which ledger swept deposits ask to be credited to. Defaults to"spot"."spot"— credits the spot wallet (unchanged behavior)."margin"— asks for the parent margin account’s collateral, skipping the separatetransferCollateralToParentMarginAccountstep. A request, not a guarantee — see the note below.
RegisterSweeperResponse:status:"registered"(the triple was added by this call) or"already_registered"(it was known before).sweeperAddress: string — the deposit address for this triple. Stable, and valid to publish and fund before any contract exists there.initialSweepCheck: boolean — whether the one-time registration balance check has completed.falseright after a fresh registration; it runs in the background and flips once every pre-existing balance has been swept.
already_registered with the same derived address. A completed initial check is never repeated; if initialSweepCheck is still false, registration schedules it again, while an already-running check is deduplicated.Example:400 (a depositTarget that is neither spot nor margin — the SDK rejects it before sending — or a body that still carries the removed clientId or userAddress, which unknown-field rejection turns into a 400 rather than ignoring it; that one only reaches you from an untyped or hand-rolled request, since the typed request has no such fields), 401 (no or invalid session), 403 (the session’s application is no longer active), 429 (the service-wide admission limit on new registrations — they create durable state, so they are bounded across all callers; re-registering an existing address is never limited, and a refused call stores nothing. The body’s retryAfter is the limiter’s own remaining wait in seconds, not a fixed window and not the 24-hour default other limits use — the bucket refills continuously, so it is usually short. Honor the value rather than assuming one), 500 (a server-side failure while registering), and 503 (the sweeper could not complete the registration — several unrelated conditions share this status, from missing configuration to an unreachable chain or store). Treat a 503 as an unknown outcome, not a negative one: the registration is stored before the reply is composed, so a failure reported after that write is indistinguishable from one reported before it, and the status alone never tells you which happened. Retrying is always safe — registration is idempotent, and the retry answers registered or already_registered according to whether the first attempt had landed. Both are success and both carry the same address, so re-register rather than reporting failure, and accept either status.() => Promise<GetSweeperChainsResponse>
List the chains and assets the sweeper watches. Public — it takes no arguments and needs no session, so a deposit page can show the supported set before the user logs in.Each The listing is all-or-nothing: rather than publish a partial set, the resolver refuses the whole call whenever any configured chain cannot be advertised. How current it is depends on the chain’s token source — a hub backed by the active-asset registry picks up a listing or delisting on the resolver’s own refresh, with no restart, while a chain configured with an explicit token list changes only when that configuration is rolled out. The gateway also serves the last answer from a short cache. The two intervals stack — at the defaults the resolver refreshes its asset registry every 60 seconds and the gateway caches the resolver’s answer for 60 seconds — so a change can take close to two minutes to appear. Treat the listing as recent, not live.Errors:
SweeperChain carries chainId (the EVM chain id, a number — the service refuses ids above Number.MAX_SAFE_INTEGER, so it is always exact), a short name, a hub flag marking the settlement chain that deposits on every other listed chain are bridged into, and its assets. Each SweeperChainAsset carries symbol, the tokenAddress to send on that chain, decimals (0 when the token does not publish them), and minSweepRaw — the minimum sweepable balance in raw base units, as a decimal string because raw amounts can exceed Number.MAX_SAFE_INTEGER. A balance strictly below the minimum stays on the deposit address until a later deposit brings the total up to it; a balance exactly at the minimum sweeps.Example:500 (a server-side failure) and 503 — both safe to retry. There is no 401: the call is unauthenticated. The 503 covers more than a missing configuration: a configured chain disabled by its own configuration, a chain whose id the resolver has not yet verified against its RPC (an unreachable RPC included — until it verifies, no indexer is watching that chain, so it must not be advertised), a chain whose RPC reports an id outside the JSON-safe range, and a resolver that could not answer at all.Bind a deposit to the exact
(chainId, tokenAddress) pair getChains returns. Never resolve a token by symbol alone: the same symbol can front a different contract on another chain, and a deposit sent to the wrong contract or the wrong chain is not recoverable. Show the user the chain and the token address from the same entry you took the minimum from.One registration covers every listed chain. The address
register returns is identical on, and watched on, every chain getChains lists, so there is nothing chain-specific to pass at registration. Use getChains to tell a depositor where they may send and which token address and minimum applies there — not to choose where to register."margin" is a routing request, not a guarantee. A deposit that arrives at a margin address but cannot be routed to collateral — an unsupported collateral asset, or a margin account that fails validation — is credited to the spot wallet instead, exactly as it is for a direct deposit(..., "margin"). Funds are never stranded, but do not treat a margin deposit address as proof the credit landed in collateral: read the balance back (getParentMarginAccountSummary) rather than assuming.Deriving the address off-chain:
@0xmonaco/contracts exports predictSweeperAddress({ factory, forwarder, clientId, user, depositTarget? }), which returns the same EIP-55 checksummed address without an RPC round-trip. The forwarder is the fixed delegation target every clone points at — read it once from factory.forwarder(); the sweeper implementation is deliberately not a derivation input, so logic upgrades never move addresses. It still takes clientId explicitly — off-chain derivation has no session to read it from, and it is your own application’s id — useful to display or fund an address before registering. Pass the same depositTarget you register with, or the prediction points at the other ledger’s address. encodeDepositApplicationData(clientId, target) exposes the underlying encoding, and the SWEEPER_ABI / SWEEPER_FACTORY_ABI exports cover direct contract interaction.SweepParams binds a sweep to an exact amount. The executor-supplied struct the ABIs encode for sweep(token, params) / sweepWithParams leads with amount, ahead of minSwapOut and minBridgeOut — the exact balance the quote was computed for. The sweep moves exactly that much and leaves any excess, such as a deposit that landed after the quote, for the next re-quoted sweep, so the minimums always cover the full swept amount and a later arrival can never dilute them. A balance that has fallen below the quoted amount reverts with StaleQuote rather than sweeping less against minimums quoted for more: re-quote and retry. amount: 0n binds nothing and sweeps the execution-time balance, and is accepted only on the direct CCTP route, whose burn is exact-amount and carries no minimum that could go stale — every other route (Stargate, swap-then-bridge, and the hub unswap) rejects the sentinel with QuoteNotBound. A sweep against an empty balance reverts with NothingToSweep. Both errors are declared on SWEEPER_ABI only — SWEEPER_FACTORY_ABI carries the new amount field on sweepWithParams but declares neither — so decode factory-route reverts with both ABIs, not the factory’s alone. Address derivation does not read SweepParams, so predictSweeperAddress(...) is unaffected by the struct’s shape.Token Approvals
(assetId: string, amount: bigint, autoWait?: boolean) => Promise<TransactionResult>
Approve vault to spend tokens. Uses asset ID (UUID).
(assetId: string) => Promise<bigint>
Check current token allowance. Uses asset ID (UUID).
(assetId: string, amount: bigint, options?: DepositOptions) => Promise<boolean>
Check if approval is needed before deposit. Uses asset ID (UUID). Returns
false for a wrappedNative asset (e.g. WSEI) without reading the on-chain allowance — its deposit goes through the payable depositNative, which consumes no allowance. Pass { asErc20: true } to check the real allowance for depositing that wrapped-native asset as its ERC20 (matching a deposit with the same option).Deprecated Methods
Thevault.getBalance() method is still exported for compatibility but always throws an APIError with statusCode: 410 client-side, without sending a request. For balance queries, use the Profile API which provides more detailed information:
- Profile API provides more detailed balance information (available, locked, total)
- Consolidates balance queries with other profile data
- Improves performance with backend optimizations
Getting Asset IDs
Asset IDs (UUIDs) are obtained from trading pairs. Each trading pair hasbaseAssetId and quoteAssetId.

