Skip to content

Commit 3e1b413

Browse files
authored
Merge pull request #440 from Baskarayelu/docs/config-413-model
docs(config): document model and invariants
2 parents 4ac9231 + 111d0ba commit 3e1b413

1 file changed

Lines changed: 80 additions & 0 deletions

File tree

docs/config.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# StableRoute — Config Model & Invariants
2+
3+
Authoritative reference for the router's admin-configurable state
4+
([`src/lib.rs`](../src/lib.rs)): what can be configured, which entrypoints
5+
write it, and the invariants the code enforces. For the fee *arithmetic*
6+
itself see [`docs/fees.md`](fees.md); for raw storage-key shapes see
7+
[`docs/storage.md`](storage.md).
8+
9+
## Two config surfaces
10+
11+
Config splits into two independent surfaces:
12+
13+
- **Per-pair config** — scoped to a `(source, destination)` corridor.
14+
- **Global config** — singleton, contract-wide.
15+
16+
### Per-pair config
17+
18+
| Field | Setter | Getter | Bound | Default |
19+
|-------|--------|--------|-------|---------|
20+
| Registration | `register_pair` / `register_pairs` | `is_pair_registered` | `source != destination` | `false` |
21+
| Fee (bps) | `set_pair_fee_bps` / `set_pair_fees_bps` | `get_pair_fee_bps` | `<= MAX_FEE_BPS` (#4) | `0` |
22+
| Min amount | `set_pair_min_amount` | `get_pair_min_amount` | `>= 0` (#6) | `0` |
23+
| Max amount | `set_pair_max_amount` | `get_pair_max_amount` | `> 0` (#6) | `i128::MAX` (unbounded) |
24+
| Cooldown (secs) | `set_pair_cooldown` | — (see `PairInfoExt`) | `<= MAX_COOLDOWN_SECS` (#20) | `0` (disabled) |
25+
| Liquidity | `set_pair_liquidity` | `get_pair_liquidity` | `>= 0` (#6) | unbounded when unset |
26+
27+
`get_pair_info` / `get_pair_info_ext` (see `docs/abi.md`) return the whole
28+
per-pair surface in one call instead of five-plus separate getters.
29+
30+
### Global config
31+
32+
| Field | Setter | Getter | Bound | Default |
33+
|-------|--------|--------|-------|---------|
34+
| Fee recipient | `set_fee_recipient` | `get_fee_recipient` || `None` |
35+
| Max fee (absolute) | `set_max_fee_absolute` / `clear_max_fee_absolute` | `get_max_fee_absolute` | `> 0` (#6, #21) | `None` |
36+
| Min fee (absolute) | `set_min_fee_absolute` | `get_min_fee_absolute` | `>= 0` (#6) | `None` |
37+
| Oracle | `set_oracle` / `remove_oracle` | `get_oracle` || `None` |
38+
| Timelock delay | `set_timelock` | `get_timelock` || `0` |
39+
40+
`get_global_config` returns this whole surface — fee recipient, both
41+
absolute fee bounds, oracle, and timelock delay — in a single read-only
42+
call (added in #409).
43+
44+
## Invariants
45+
46+
1. **Admin-gated writes.** Every setter above calls `Self::require_admin`,
47+
which loads the stored admin and calls `require_auth()`. There is no
48+
config field that can be written by a non-admin caller. (`set_pair_liquidity`
49+
is the one exception: it also accepts calls from the configured oracle —
50+
see `docs/roles.md`.)
51+
2. **Registration-first.** `set_pair_fee_bps`, `set_pair_min_amount`,
52+
`set_pair_max_amount`, `set_pair_cooldown`, and `set_pair_liquidity` all
53+
require the pair to already be registered via `register_pair`, and panic
54+
with `PairNotRegistered` (#5) otherwise. A corridor's config cannot exist
55+
without the corridor itself existing.
56+
3. **All-or-nothing batches.** `register_pairs` and `set_pair_fees_bps`
57+
validate every entry before writing any of them; a single invalid entry
58+
rolls back the whole call (Soroban transaction atomicity).
59+
4. **Read views never mutate.** `get_pair_info`, `get_pair_info_ext`,
60+
`get_global_config`, and every individual getter are pure reads — no
61+
entrypoint that returns config data writes to storage or emits events.
62+
5. **Config change events are not duplicated.** Every setter that changes
63+
persisted config state emits a dedicated event carrying the new value
64+
(`fee_set`, `min_set`, `max_set`, `cd_set`, `liq_set`, `maxfee`,
65+
`minfee`, `recip_set`, `tlock_set`, …). `register_pair`/`register_pairs`
66+
specifically guard against re-emitting `pair_reg` on an idempotent
67+
re-registration of an already-registered pair (see #410).
68+
6. **Clearing config is explicit, not defaulting.** `unregister_pair` and
69+
`purge_pair_metrics` remove state (and emit `cfg_clr` / `pair_mrst`
70+
respectively) rather than silently falling back to defaults on the next
71+
read; `clear_max_fee_absolute` is the equivalent for the global absolute
72+
fee cap.
73+
74+
## See also
75+
76+
- [`docs/fees.md`](fees.md) — fee arithmetic, relative/absolute cap
77+
composition, worked examples
78+
- [`docs/storage.md`](storage.md)`DataKey` shapes and TTL classification
79+
- [`docs/roles.md`](roles.md) — admin vs. oracle authorization
80+
- [`docs/abi.md`](abi.md) — full entrypoint signatures

0 commit comments

Comments
 (0)