> For the complete documentation index, see [llms.txt](https://docs.axis.to/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.axis.to/technical-and-architecture/design-decisions.md).

# Design Decisions

Why the protocol is built the way it is: trade-offs, alternatives considered, and the reasoning behind each major design choice.

{% hint style="info" %}
This is an **Explanation** page. For structural overview, see [System Architecture](/technical-and-architecture/architecture.md). For function signatures, see [Reference](/reference/core-contracts.md).
{% endhint %}

***

## Why Offchain Order Signing (EIP-712)?

Users sign primary market orders offchain; operators submit them onchain to `USDxMarket` for settlement. This provides:

* **Operator-submitted execution** -- the mint/redeem operator (`MINT_OPERATOR_ROLE` / `REDEEM_OPERATOR_ROLE`) pays for the settlement submission; users may still need an onchain token approval
* **Operator control** -- the market controls execution timing and batching, and re-runs every pre-trade check before state changes
* **Replay protection** -- per-account nonce bitmaps and order expiry (`deadline`) prevent reuse

The bitmap-based nonce system (`_nonceBitmaps`) packs 256 nonces into a single storage slot per `accountId`, reducing gas cost compared to sequential nonce tracking. Nonces are namespaced per account and consumed only on successful settlement; a cancelled order is invalidated through an order tombstone rather than by consuming its nonce.

***

## Why Route-Based Custody?

During minting, a `route` specifies the allowed asset pair and settlement mode, and the signed order binds a concrete `channelId` naming the approved custody path (custodian, adapter, or cross-chain rail). This lets collateral settle across approved custody channels instead of a single hard-coded destination. The market validates the route and channel against policy, but route support alone does not prove diversification or remove custody risk.

***

## Why Configurable Linear Reward Vesting?

Realized trading results are delivered to the rewards vault as USDx rewards through `fundRewards()` (gated by `REWARD_MANAGER_ROLE`), which folds the top-up into a **linear vesting schedule** rather than making it available instantly. Where does that reward come from? It is the realized output of strategies whose structural edge is cross-venue and cross-asset fragmentation, a durable, market-neutral yield source that does not rely on any single mechanism. Funding is one component (and can be the larger share in a given period); see the Transparency Dashboard for current attribution, and [How Axis Earns Yield](/susdx-the-rewards-vault/how-axis-earns-yield.md) for the model.

Vesting rather than an instant credit prevents:

* **Front-running** -- depositing just before a reward is delivered, then exiting immediately to capture it
* **Price manipulation** -- sudden jumps in the share exchange rate

Rewards vest **linearly over a configured window**; the live value is a configured parameter. A top-up recomputes `rewardRate` and extends `periodFinish`, folding into the *active* window rather than resetting the clock, and is bounded by an optional `maxRewardRate` cap. Only vested rewards count toward `accountedAssets`, so the exchange rate rises smoothly as rewards vest rather than jumping on each funding.

***

## Why Asynchronous (ERC-7540) Redemption?

`StakedUSDx` uses an **asynchronous redemption** model (modeled on ERC-7540) rather than an instant withdrawal. The lifecycle:

1. A holder calls `requestRedeem()`, which **burns the shares immediately** and moves the reserved USDx out of `accountedAssets` into `pendingRedeemAssets`. The request snapshots its terms, including `eligibleAt = requestedAt + policy.cooldown`.
2. After the cooldown elapses. An account holding `REDEMPTION_SERVICER_ROLE` calls `serviceRedemptions()`, which moves eligible requests from **pending** to **claimable** (`pendingRedeemAssets` → `claimableRedeemAssets`).
3. The controller then claims the underlying USDx.

Because a request's assets are carved out of `accountedAssets` and tracked as **in-vault liabilities** (`pendingRedeemAssets` + `claimableRedeemAssets` = `redeemLiabilities`), the redeeming USDx earns no further rewards and cannot dilute active holders, the same USDx is never counted as both active assets and a liability. There is **no separate escrow (silo) contract**; the pending and claimable buckets live inside the vault.

A still-pending request can be cancelled with `cancelRedeemRequest()`, which releases the reserved assets and re-mints the burned shares to the owner. The cooldown is configurable up to a `MAX_COOLDOWN_DURATION` of 90 days; the live value is a configured parameter, and later cooldown changes affect only future requests because each request snapshots its own `eligibleAt`.

***

## Why Two-Level Restrictions?

Restrictions are a coarse graduated control rather than a single on/off switch, but the granularity stops at two levels. There is no per-action bitmap. `StakedUSDx` tracks two booleans per account, `_restricted` (soft) and `_fullRestriction` (full); there is no `RestrictionState` struct and no per-subject `scope`, `validUntil`, or `evidenceRef` fields. The derived status is one of three values, `CLEAR`, `RESTRICTED`, or `FULL_RESTRICTION`:

* **Soft (`RESTRICTED`)** blocks non-exit actions, its `blockedActions` code is `NON_EXIT`. The account cannot deposit or receive transfers, but can still redeem/exit its own position.
* **Full (`FULL_RESTRICTION`)** blocks everything, its `blockedActions` code is `ALL`, including claims and exits.

`blockedActions` is a single `bytes32` code taking only `BLOCKED_NONE`, `BLOCKED_NON_EXIT`, or `BLOCKED_ALL`. It is not a bitmap of individual actions such as `TRANSFER_IN`, `TRANSFER_OUT`, `DEPOSIT`, `REQUEST_REDEEM`, `CLAIM`, or `CANCEL_REDEEM_REQUEST`, none of those symbols exist in the code, so a subject cannot be blocked from one action while allowed another beyond the soft/full split. The only basis code emitted is `AUTHORITY` (`BASIS_AUTHORITY`); there is no `SANCTIONS`/`LEGAL_ORDER`/`JURISDICTION`/`TERMS`/`ELIGIBILITY` enum onchain. Raw KYC/KYB, sanctions hits, and legal notes stay offchain.

A restriction is applied through `addToBlacklist(target, isFullRestriction)` and cleared with `removeFromBlacklist`, both under `RESTRICTION_ROLE`, which spans both the token (`USDx`) and the vault (`StakedUSDx`). The role is distinct from the mint, burn, settlement, upgrade, and redemption-servicing roles. At the token level, `USDx` implements a coarse Circle-compatible binary `blacklist` (also under `RESTRICTION_ROLE`). There is no `IRestrictionManager` interface in the V2 source, the restriction logic lives inline in the contracts.

***

## Why Donation-Attack Resistance?

`StakedUSDx` computes share conversions against `accountedAssets` (active principal plus already-vested rewards), using ERC-4626 floor rounding and virtual shares/assets offsets, rather than against the vault's raw USDx balance. This mitigates the "donation attack", an attacker manipulating the exchange rate by transferring assets directly to the vault.

Because a direct USDx donation raises the raw `assetBalance` but not `accountedAssets`, it does not move the exchange rate: reserved redemption liabilities and still-unvested rewards are deliberately excluded from the figure that prices shares. The virtual-offset convention further blunts first-depositor rounding manipulation.

***

## Why a Bounded Reward-Manager Role?

Reward delivery is separated from the vault's administrative control plane. `REWARD_MANAGER_ROLE` gates **only** `fundRewards`, folding a top-up into the vesting schedule. It does **not** set reward configuration (`setRewardConfig` is `onlyRole(DEFAULT_ADMIN_ROLE)`) and it does **not** pause reward funding (`pauseRewardFunding` is `onlyRole(PAUSER_ROLE)`). Even the funding it can do is bounded: each top-up is checked against the configured `maxRewardRate` cap and reverts while `_rewardPaused` is set. The role is distinct from `DEFAULT_ADMIN_ROLE`, from the redemption servicer, and from the pause/restriction roles.

Following the Axis `_OPERATOR` / `_MANAGER` split, this keeps frequent reward top-ups on a narrowly-scoped role rather than requiring the admin key for routine yield delivery. The separation limits the reward manager to the contract's defined capabilities; it does not remove operator, admin, or key-management risk.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.axis.to/technical-and-architecture/design-decisions.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
