Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions apps/docs/overview/how-it-works.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ the user's wallet

## Withdraw flow

Symmetric to deposit. The user specifies a share amount (mUSDC), the API builds a `vault.withdraw(caller, shares)` invocation, Freighter signs, and the vault redeems the proportional adapter position and returns USDC.
Symmetric to deposit. The user specifies a share amount (mUSDC), the API builds a `vault.withdraw(caller, shares, min_usdc_out)` invocation, Freighter signs, and the vault redeems the proportional adapter position and returns USDC.

`min_usdc_out` is a caller-supplied floor, not a fixed protocol parameter. The vault's adapter-share ratio is a shared, mutable value, so a concurrent withdrawal by another depositor can shift it between when the API quoted a payout and when this transaction lands. If the delivered amount would fall below the floor, the transaction reverts with a typed `MinAmountOutNotMet` error instead of silently paying out less than the user was shown.

## Rate selection

Expand All @@ -62,8 +64,19 @@ usdc_out = <the adapter's redemption of the caller's proportional share of adapt

This means early depositors automatically benefit from yield without any claim or harvest action.

## Automatic yield accrual and rebalancing

Deposit and withdraw are the only actions a user ever takes. Two scheduled keeper jobs (GitHub Actions cron, hitting dedicated API routes) handle everything else:

- **Accrual keeper** (every 15 minutes): refreshes the active adapter's cached yield figure, so `total_assets()` reflects interest actually earned rather than going stale between user interactions. Permissionless by design, a duplicate run is harmless.
- **Migration keeper** (hourly): when a different supported protocol is offering meaningfully better yield, moves the vault's entire position to it via `migrate_adapter`, in one atomic, slippage-bounded transaction. Admin-gated, and cross-invocation deduplicated (via a shared claim/lease record) so a slow or retried run can't submit the same migration twice.

Neither keeper changes what a user sees or does; they exist so a deposit made once keeps earning the best available rate without the user ever having to come back and move funds manually.

## Security properties

- **No server-side keys.** The API returns unsigned XDR only. Private keys never leave Freighter.
- **User-visible transaction contents.** Freighter shows the exact contract, function, and amount before the user signs — there is no hidden parameter deciding where funds go; that's determined entirely by the vault's current adapter, which is itself a matter of on-chain, auditable state (`vault.get_adapter()`).
- **No server-side keys.** The API returns unsigned XDR only. Private keys never leave the user's wallet.
- **User-visible transaction contents.** The wallet shows the exact contract, function, and amount before the user signs. There is no hidden parameter deciding where funds go; that's determined entirely by the vault's current adapter, which is itself a matter of on-chain, auditable state (`vault.get_adapter()`).
- **On-chain state.** USDC balances, share balances, and the active adapter are all stored in Soroban contract storage, auditable by anyone.
- **Slippage-bound withdrawals.** `withdraw()` takes a caller-supplied `min_usdc_out` floor, so a ratio shift from a concurrent withdrawal produces a typed revert instead of a silently reduced payout.
- **Immutable contracts.** No vault or adapter contract exposes an upgrade entry point. Once deployed, contract logic can't be rewritten by anyone, including Meridian, the tradeoff is that a fix requires a fresh deployment (see [Contract immutability](https://github.com/drydocs/meridian/blob/main/docs/contracts.md#contract-immutability)), not an in-place patch.
2 changes: 1 addition & 1 deletion apps/docs/overview/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Meridian is a stablecoin yield aggregator on the Stellar network. Users deposit
4. The user receives mUSDC share tokens representing their position. Share price appreciates as yield accrues.
5. At any time the user can withdraw by burning their mUSDC shares, receiving USDC plus accumulated yield.

Switching which protocol a vault routes to happens via `set_adapter` (admin-only, deploying a new adapter contract and pointing the vault at it) — it is not something that happens per-deposit or per-user.
Which protocol a vault routes to can change after a deposit, without any action from the depositor. An hourly migration keeper compares the vault's current adapter against other supported protocols and, when a meaningfully better rate is available, atomically moves the entire position via `migrate_adapter`, slippage-bounded so the move can't complete at a worse value than before it started. A one-off manual swap (`set_adapter`, admin-only) also exists, for cases like recovering from a broken adapter, but ongoing rebalancing is the keeper's job, not something an admin does per-deposit or per-user.

## What it does not do

Expand Down
2 changes: 1 addition & 1 deletion apps/docs/overview/why-meridian.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Stellar is the right infrastructure layer for this use case:

Yield rates on DeFi protocols are not static. A protocol offering 8% today may offer 5% next week as utilization changes. Without active monitoring, a depositor's funds sit in a suboptimal position indefinitely.

Meridian solves this by separating the routing decision (off-chain, by the API reading live rates) from the custody decision (on-chain, by the vault contract). Every deposit records which protocol was chosen, and the user signs off on that choice before any funds move.
Meridian solves this by separating the routing decision (off-chain, by the API reading live rates) from the custody decision (on-chain, by the vault contract). Every deposit records which protocol was chosen, and the user signs off on that choice before any funds move. The choice doesn't have to be made again: a scheduled keeper re-checks rates on an ongoing basis and moves the vault's position to a better-yielding protocol automatically, so a deposit made once keeps chasing the best available rate without the user coming back to do it manually.

## The target user

Expand Down
Loading