> ## Documentation Index
> Fetch the complete documentation index at: https://docs.0xmonaco.com/llms.txt
> Use this file to discover all available pages before exploring further.

# V1.0.50

# Monaco Protocol SDK v1.0.50

Two changes need a decision before you upgrade. Registering a sweeper deposit address is now authenticated and takes no identity at all — `clientId` and `userAddress` are gone from the request, and the session supplies both — with a new optional `depositTarget` that can point swept deposits at margin collateral instead of the spot wallet. And funding an isolated risk bucket that holds an open position now **commits** the money to that position's stored margin by default, which is the right behavior for an Adjust Margin gesture and the wrong one for a funding loop: those must now pass `applyToPositionMargin: false`. `transferCollateralToMarginAccount` is deprecated in the same move, `@0xmonaco/contracts` gains the deposit-address encoder, and the `account` channel's `marginRatio` documents one more state it can saturate in.

## Breaking

### Sweeper registration is authenticated, and carries no identity

`sdk.sweeper.register` (`POST /api/v1/sweeper/register`; gRPC `SweeperService.Register`; Rust REST `register_deposit_address`) now requires a session, and both `clientId` and `userAddress` have been removed from the request. The application is the one the session was established under and the credited address is the session's own, so the call can only ever register the caller's own address under their own application. The argument is now optional and carries nothing but the target.

```typescript theme={null}
// Before
await sdk.sweeper.register({ clientId, userAddress });

// After
await sdk.login(clientId);
await sdk.sweeper.register();
```

A body that still carries either removed field is rejected with a `400` rather than silently ignored — answering it from the session would hand the caller a deposit address for a different user or application than their own body names. Unauthenticated calls answer `401`, and a session whose application is no longer active answers `403`. The endpoint also declares `500` for a server-side failure and `503` for any point at which the sweeper could not complete the registration — several unrelated conditions share it. Treat a `503` as an **unknown** outcome rather than 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. Re-register rather than assuming 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 rather than branching on which one you got.

The per-client (IP-keyed) rate limit is replaced by a **service-wide** admission limit on *new* registrations, which answers `429`. A per-caller bound handed every fresh session its own allowance; registrations create durable state, so the bound is now global. Re-registering an existing address is never limited — it creates nothing — and a refused call stores nothing, so `429` is safe to retry. The REST body's `retryAfter` (and gRPC's `RetryInfo` detail) is the limiter's own remaining wait in seconds, not a fixed window: honor it rather than assuming one.

The new optional `depositTarget` (`"spot"`, the default, or `"margin"`; `SPOT`/`MARGIN` on the wire) asks for the parent margin account's collateral, skipping the separate `transferCollateralToParentMarginAccount` step. **The target is part of the address derivation**, so `"spot"` and `"margin"` return two different deposit addresses for the same application and user, each carrying its own request; a `"spot"` address is never credited to margin. Every address derived before this change is unaffected — `"spot"` reproduces the previous bytes exactly. An unrecognized value is rejected (the TypeScript SDK throws before sending; the API answers `400`) rather than falling back to spot, which would return an address pointed at a ledger the caller did not ask for.

`"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. Read the balance back rather than treating the address as proof of where the credit landed. See [Vault](/sdk/typescript/vault#registered-deposit-addresses) and [Registered Deposit Addresses](/developers/vault#registered-deposit-addresses).

## Changed

### Funding an isolated risk bucket commits to the position's margin by default

`transferCollateralToRiskBucket` (`POST /api/v1/margin/risk-buckets/collateral/transfer-in`; gRPC `MarginAccountsService.TransferCollateralToRiskBucket`; the `transfer_collateral_to_risk_bucket` MCP tool) takes a new optional `applyToPositionMargin`, and its default is a behavior change.

* **Omitted or `true`** — the human "Adjust Margin" gesture: the amount is **committed** to the isolated bucket's sole open position's stored margin. Effective leverage drops and stays down, initial margin required rises by the amount, and free collateral is unchanged, so new orders cannot spend it.
* **`false`** — the previous behavior: a plain allocation. Free collateral rises and the next order can spend it.

**Programmatic funding loops that top a bucket up to a free-collateral target must now pass `false`.** Under the default each top-up converts into requirement instead of headroom, and the loop never converges.

A flat isolated bucket has no position to commit to, so both values are a plain allocation there. The cross form has no per-position margin, and the two contracts differ by surface: raw REST and gRPC reject only an explicit `true`, while the TypeScript request type (`never`) and the MCP tool schema reject the field however it is set — **omit it entirely on a cross transfer** rather than passing `false`. Either behavior improves the liquidation cushion identically — the breach check is bucket-equity based.

The response gains an optional `positionMarginCredited` reporting what actually happened: `true` — the credit landed; `false` — a credit was requested (or defaulted) and degraded to a plain allocation because the bucket's persisted position row was stale (a close/reopen race), so re-issue the Adjust Margin once the new row lands if the commitment still matters; absent (never null) on plain allocations, parent deposits, and releases. See [Margin Accounts](/sdk/typescript/margin-accounts) and [Perps Collateral](/developers/perps-collateral).

## Deprecated

### `transferCollateralToMarginAccount`

`transferCollateralToMarginAccount` (`POST /api/v1/margin/accounts/{margin_account_id}/collateral/transfer-in`; gRPC `MarginAccountsService.TransferCollateralToMarginAccount`) is marked deprecated — a JSDoc `@deprecated` in TypeScript, `deprecated: true` in the OpenAPI operation. It overloads two unrelated operations behind one route: with `tradingPairId` it allocates into that pair's isolated risk bucket, without it it performs a wallet-debiting deposit to the parent margin account.

Use `transferCollateralToRiskBucket` for bucket funding — which, as of this release, applies the same position-margin credit — and `transferCollateralToParentMarginAccount` for wallet-to-margin deposits. The endpoint keeps working and no removal date is scheduled.

## Added

### The deposit-address encoder is exported from `@0xmonaco/contracts`

`predictSweeperAddress` accepts an optional `depositTarget` (`"spot"`, the default, or `"margin"`), and `encodeDepositApplicationData(clientId, target)` plus the `DepositTarget` type are now exported from `@0xmonaco/contracts`. Omitting the target reproduces the previous derivation byte-for-byte, so existing calls are unaffected; pass the same target the address was registered with, or the prediction points at the other ledger's address.

`encodeDepositApplicationData` is the canonical encoder for a deposit's on-chain `applicationData` — the bytes a sweeper address is a hash of, and the counterpart of the backend's own encoder. `@0xmonaco/core` consumes it internally rather than keeping a second copy, and `@0xmonaco/types` re-exports `DepositTarget` from the same place: the value selects both a direct deposit's on-chain routing hint and a sweeper address's derivation, and two definitions could disagree about the bytes an address is derived from. The importable path is `@0xmonaco/contracts` — core's package root does not re-export it. `DepositTarget` itself is untouched: it changed packages, not shape, so its name and its two members are the same and it is still reachable from `@0xmonaco/types`.

Both `predictSweeperAddress` and `encodeDepositApplicationData` throw on a target that is not exactly `"spot"` or `"margin"` rather than treating anything unrecognized as spot. The likely mistake is the wire form `"MARGIN"` copied from the API reference; without the check it would derive a real, fundable **spot** address while the caller believed it was a margin one, and no server round-trip would reveal it.

## Fixed

### `marginRatio` on the `account` channel saturates on dust equity too

The documented contract of `AccountEvent`'s `marginRatio` widens. The maximum-distress sentinel (`79228162514264337593543950335`) appears whenever a live maintenance requirement makes the ratio impossible to compute or represent — not only for an account still owing one at zero or negative equity, but equally at near-zero **positive** equity, where the true `maintenance / equity` exceeds the decimal range. Previously the producer crashed on that state instead of emitting a frame. An account carrying no maintenance requirement is unchanged and still reports `0`, whatever its equity: an empty account is not distressed.

No type change, and consumers that already clamp the sentinel for display need no code change: treat any value at or above the liquidation threshold as maximal distress rather than distinguishing the sentinel's causes. See [Account Channel](/sdk/typescript/websockets#account-channel).

## Upgrade

```bash theme={null}
npm install @0xmonaco/core@1.0.50 @0xmonaco/types@1.0.50 @0xmonaco/react@1.0.50 @0xmonaco/contracts@1.0.50
# or bun
bun add @0xmonaco/core@1.0.50 @0xmonaco/types@1.0.50 @0xmonaco/react@1.0.50 @0xmonaco/contracts@1.0.50
```

The MCP server ships at `1.0.50` too; it runs via `npx -y @0xmonaco/mcp-server`, so restarting your assistant picks up the new version. Every SDK bump is a patch release. There is no `1.0.49` — that version number was never released.

Two action items. If you call `sweeper.register`, log in first and drop `clientId` and `userAddress` from the body; a partially-migrated body is a `400`, not a silent ignore. And if any code path funds an isolated risk bucket to reach a free-collateral level, pass `applyToPositionMargin: false` — the new default commits the amount to the open position's margin instead, and a loop that measures free collateral will never converge. Deriving deposit addresses off-chain? Pass the same `depositTarget` you register with, and import `encodeDepositApplicationData` from `@0xmonaco/contracts`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.