Skip to main content
Package: monaco.api.sweeper Source: protos/api/sweeper.proto Use SweeperService to register a deposit address so the watched assets sent there are swept into the rollup automatically once each asset’s minimum is reached, and to read the chains and assets it watches. Only the assets GetChains lists are indexed — the transfer indexer filters logs to those token addresses — so an unlisted ERC20 sent to the address is not swept.

Notes

  • Register requires authentication, and the request carries no identity at all: the application is the one the session was established under (login takes its client id) and the credited address is the session’s own. A caller can therefore only register their own address under their own application. An unauthenticated call returns UNAUTHENTICATED.
  • Every (application, user, deposit target) triple has a deterministic deposit address; registering the triple makes the backend monitor that address and forward deposits of the watched assets into the rollup, crediting the user under the application. GetChains is the authoritative list of what is watched; a token outside it is not indexed and not swept.
  • deposit_target is optional: SPOT (the default when omitted or empty) credits the spot wallet, MARGIN asks for the parent margin account’s collateral. It is part of the address derivation, so SPOT and MARGIN yield two different deposit addresses for the same application and user, each carrying its own request. A SPOT address is never credited to margin.
  • MARGIN is a routing request rather than a guarantee: a deposit the matching engine cannot route to collateral — an unsupported collateral asset, or a margin account that fails validation — is credited to the spot wallet instead, so funds are never stranded.
  • The response returns immediately with the derived sweeper_address and a status of registered (added by this call) or already_registered (known before). A one-time initial balance check — which sweeps whatever is already sitting on the address at or above that asset’s minimum, the same floor every later sweep applies — runs in the background and is reported by initial_sweep_check.
  • Idempotent and safe to retry within the current forwarder-based derivation: re-registering an existing triple returns already_registered with the same derived address. A completed initial check is never repeated; if initial_sweep_check is still false, registration schedules it again, while an already-running check is deduplicated.
  • Pre-v1.0.53 registrations need an operator migration. Calling Register for one returns and monitors the new forwarder-derived address in the running resolver, but does not replace that row’s stored address; after a resolver restart, warmup reloads only the old value. Pause deposits for that registration and do not display or fund the new address until Monaco confirms its stored row was migrated. Re-registration alone is not restart-durable.
  • A deposit_target that is neither SPOT nor MARGIN returns INVALID_ARGUMENT. An unrecognized target is rejected rather than defaulting to SPOT, which would answer with an address pointed at a ledger the caller did not ask for.
  • PERMISSION_DENIED means the application the session was established under is no longer active.
  • RESOURCE_EXHAUSTED means the service-wide admission limit on new registrations was hit. They create durable state, so they are bounded across all callers rather than per caller; re-registering an existing address is never limited, and a refused call stores nothing, so it is safe to retry. The status carries a google.rpc.RetryInfo detail with the wait — the same interval REST returns as retryAfter — so honor that rather than guessing.
  • INTERNAL is a generic server-side failure. It can happen before the sweeper is contacted at all — a failed application lookup, for instance — so unlike UNAVAILABLE it says nothing about the resolver.
  • GetChains is public: it carries no auth interceptor requirement and takes no request fields, because a depositor needs the supported set before they have a session. It returns one SweeperChain per watched chain — the EVM chain_id, a short name, a hub flag marking the settlement chain that deposits on every other listed chain are bridged into, and the SweeperChainAsset entries swept there (symbol, token_address, decimals, and min_sweep_raw, the minimum sweepable balance in raw base units). 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. Only an operator changes the set, and how fast that lands 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 serves the last answer from a short cache either way, so refetch rather than treating a cached set as permanent.
  • Every registered deposit address is watched on every listed chain and is identical on all of them, so Register takes no chain and one registration covers the whole set. GetChains is for showing a depositor where they may send, not for choosing where to register.
  • GetChains is all-or-nothing: rather than publish a partial listing, it returns UNAVAILABLE whenever any configured chain cannot be advertised — the sweeper is not configured at all, a configured chain is disabled by its own configuration, a chain’s id is not yet verified against its RPC (an unreachable RPC included; until it verifies, its indexer is still seeding and nothing watches that chain), a chain’s RPC reports an id outside the JSON-safe range the listing serves, or the resolver could not answer. All of them are safe to retry. INTERNAL is a generic server-side failure.
  • UNAVAILABLE means the sweeper could not complete the registration. Several unrelated conditions share it — missing configuration, an unreachable chain or factory, a store that would not write or read back, a reply that never arrived — so treat it as an unknown outcome rather than a negative one: the registration is stored before the reply is composed, and the status alone never tells you whether that happened. Retry either way — 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 accept either.