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
8 changes: 4 additions & 4 deletions src/IndexVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ contract IndexVault is ERC4626, Ownable2Step, IERC7540, ReentrancyGuard {

/// @notice Whether the current epoch's pending redemptions exceed the idle
/// buffer, so the rebalancer must free USDC from the basket before settle can
/// pay them. This is a first-class rebalance trigger (Section 3).
/// pay them. This is a first-class rebalance trigger.
function redemptionFundingNeeded() external view returns (bool) {
return pendingRedeemAssets() > idleAssets();
}
Expand Down Expand Up @@ -520,7 +520,7 @@ contract IndexVault is ERC4626, Ownable2Step, IERC7540, ReentrancyGuard {
}

/// @dev Restricts membership mutation to the governor, which enforces the
/// timelocked, bounded change lifecycle (Section 16). The vault holds the
/// timelocked, bounded change lifecycle. The vault holds the
/// set and applies changes; the governor owns the policy.
modifier onlyGovernor() {
if (msg.sender != governor) revert IndexVault_NotGovernor(msg.sender);
Expand All @@ -545,7 +545,7 @@ contract IndexVault is ERC4626, Ownable2Step, IERC7540, ReentrancyGuard {
/// @notice Marks a constituent for wind-down. It stays in the set and in NAV
/// so its value is never orphaned; the rebalancer zeroes its target and sells
/// the position to USDC at the oracle-anchored minimum-out. This is the
/// "wind-down, not dump" execution path (Section 16.5).
/// "wind-down, not dump" execution path.
function governorBeginWindDown(address token) external onlyGovernor {
if (!isConstituent[token]) revert IndexVault_NotConstituent(token);
windingDown[token] = true;
Expand All @@ -556,7 +556,7 @@ contract IndexVault is ERC4626, Ownable2Step, IERC7540, ReentrancyGuard {
/// removal only ever drops a position the vault no longer meaningfully holds.
/// @dev Reverts while the position still has material value, which also means
/// a constituent whose feed is dead cannot be finalized here (it cannot be
/// priced or wound down): that is the quarantine case deferred to Section 4.
/// priced or wound down): that is the quarantine case handled by the safety layer.
function governorFinalizeRemoval(address token) external onlyGovernor {
if (!windingDown[token]) revert IndexVault_NotWindingDown(token);

Expand Down
6 changes: 3 additions & 3 deletions src/governance/ConstituentGovernor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ error ConstituentGovernor_InvalidParams();
* `ExcludedAddressRegistry`: once an admin curates which assets belong to an
* index, that curation becomes a central trust assumption, so it gets a
* timelocked AND bounded lifecycle. A timelock alone only delays a change; it
* does not bound what the change can be. Both are enforced here (Section 16).
* does not bound what the change can be. Both are enforced here.
*
* The privileged actor may propose, but every executed change is checked
* against on-chain invariants that protect holders, so even a compromised owner
Expand All @@ -53,8 +53,8 @@ error ConstituentGovernor_InvalidParams();
* on the vault, the rebalancer exits the position through CoW at the
* oracle-anchored minimum-out, and the constituent is deleted only once the
* position is dust. The stale-feed special case (the asset you must exit is
* the one your oracle cannot price) is the quarantine path deferred to
* Section 4; such a forced-removed asset sits marked for wind-down until then.
* the one your oracle cannot price) is the quarantine path handled by the
* safety layer; such a forced-removed asset sits marked for wind-down until then.
*/
contract ConstituentGovernor is Ownable2Step, TimelockedProposals {
using Math for uint256;
Expand Down
16 changes: 8 additions & 8 deletions src/rebalancer/Rebalancer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ error Rebalancer_BelowMinOut(uint256 buyAmount, uint256 minOut);
*
* An epoch freezes the target. `openEpoch` snapshots each constituent's target
* USD value (weight times NAV at open) and the NAV, so orders validate against a
* fixed target while the vault's NAV continues to read from actual balances
* (spec 6.3 and 8.3). This removes the target-drift-during-rebalance problem and
* fixed target while the vault's NAV continues to read from actual balances.
* This removes the target-drift-during-rebalance problem and
* keeps `validateOrder` cheap: it reads a stored target rather than recomputing
* the whole methodology on every solver call.
*
Expand Down Expand Up @@ -174,7 +174,7 @@ contract Rebalancer {
// A redemption the buffer cannot cover is a first-class trigger: the
// keeper may open an epoch to free USDC from the basket regardless of
// drift or cadence, because redemption liveness cannot wait for the
// reweight schedule (Section 3). The min-interval floor still applies.
// reweight schedule. The min-interval floor still applies.
bool fundingNeeded = VAULT.redemptionFundingNeeded();
if (drift < D_LARGE_BPS && !fundingNeeded) {
// Not an emergency and no funding need: scheduled reweight path,
Expand All @@ -199,9 +199,9 @@ contract Rebalancer {

// Snapshot the new target over the FRESH constituents only. A quarantined
// (stale-feed) constituent cannot be priced, so the methodology cannot
// weight it and the rebalancer cannot anchor a minimum-out to sell it
// (Section 16.5). It is excluded from the epoch entirely, neither bought
// nor sold, and held marked-down (Section 4) until its feed recovers; the
// weight it and the rebalancer cannot anchor a minimum-out to sell it.
// It is excluded from the epoch entirely, neither bought
// nor sold, and held marked-down until its feed recovers; the
// healthy names rebalance around it instead of the whole epoch halting.
address[] memory fresh = _freshSubset(VAULT.getConstituents());
uint256[] memory weights = METHODOLOGY.getWeights(fresh);
Expand All @@ -210,7 +210,7 @@ contract Rebalancer {
// Hold back a USDC reserve for pending redemptions the buffer cannot
// cover, then weight the constituents over the deployable remainder. This
// makes the basket overweight relative to its targets, so it is sold to
// USDC and the redemption is funded before settle pays it (Section 3).
// USDC and the redemption is funded before settle pays it.
uint256 reserveUsd = VAULT.rebalanceReserveUsd();
if (reserveUsd > 0) {
// Selling the basket nets only (1 - slippage) of oracle value, so
Expand All @@ -224,7 +224,7 @@ contract Rebalancer {
address token = fresh[i];
// A constituent marked for wind-down targets zero, so the whole
// position becomes overweight and is sold to USDC at the
// oracle-anchored minimum-out (Section 16.5, wind-down not dump).
// oracle-anchored minimum-out (wind-down, not dump).
uint256 target = VAULT.windingDown(token) ? 0 : deployableNav.mulDiv(weights[i], WAD, Math.Rounding.Floor);
targetUsd[token] = target;
inEpoch[token] = true;
Expand Down
2 changes: 1 addition & 1 deletion test/BasketFundedRedemption.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { MockSupplyOracle } from "test/mocks/MockSupplyOracle.sol";

/// @notice Basket-funded redemptions: when a redemption exceeds the buffer, the
/// rebalancer holds back a USDC reserve and sells the basket down to raise it, so
/// settle can pay a large exit that the buffer alone could not cover (Section 3).
/// settle can pay a large exit that the buffer alone could not cover.
contract BasketFundedRedemptionTest is Test {
uint256 internal constant WAD = 1e18;
uint48 internal constant HEARTBEAT = 1 days;
Expand Down
2 changes: 1 addition & 1 deletion test/ConstituentGovernor.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { MockAggregator } from "test/mocks/MockAggregator.sol";
import { MockSupplyOracle } from "test/mocks/MockSupplyOracle.sol";
import { MockGPv2Settlement } from "test/mocks/MockGPv2Settlement.sol";

/// @notice Section 16 constituent-governance guardrails: timelocked, bounded,
/// @notice Constituent-governance guardrails: timelocked, bounded,
/// two-path removal with wind-down execution safety.
contract ConstituentGovernorTest is Test {
uint256 internal constant WAD = 1e18;
Expand Down
2 changes: 1 addition & 1 deletion test/IndexVaultCircuitBreaker.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { IndexVault_Paused, IndexVault_NotGuardian, IndexVault_InvalidNavDeviati
import { MockERC20 } from "test/mocks/MockERC20.sol";
import { MockAggregator } from "test/mocks/MockAggregator.sol";

/// @notice Section 4 Slice 2: the vault pause / guardian brake and the
/// @notice The vault pause / guardian brake and the
/// NAV-per-share circuit breaker (the backstop for a collective mispricing that
/// passes every per-feed check).
contract IndexVaultCircuitBreakerTest is Test {
Expand Down
2 changes: 1 addition & 1 deletion test/IndexVaultQuarantine.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
import { MockERC20 } from "test/mocks/MockERC20.sol";
import { MockAggregator } from "test/mocks/MockAggregator.sol";

/// @notice Section 4 Slice 1: constituent quarantine and graceful redemption
/// @notice Constituent quarantine and graceful redemption
/// degradation. A stale constituent feed degrades NAV (so buffer redemptions
/// survive) rather than halting the vault, while mints and settlement fail closed.
contract IndexVaultQuarantineTest is Test {
Expand Down
2 changes: 1 addition & 1 deletion test/Rebalancer.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { MockERC20 } from "test/mocks/MockERC20.sol";
import { MockAggregator } from "test/mocks/MockAggregator.sol";
import { MockSupplyOracle } from "test/mocks/MockSupplyOracle.sol";

/// @notice Slice 1 tests for the Rebalancer brain: epoch snapshot, deltas, and
/// @notice Tests for the Rebalancer brain: epoch snapshot, deltas, and
/// both-leg order derivation and validation. No settlement wiring yet.
contract RebalancerTest is Test {
uint256 internal constant WAD = 1e18;
Expand Down
2 changes: 1 addition & 1 deletion test/RebalancerQuarantine.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { MockERC20 } from "test/mocks/MockERC20.sol";
import { MockAggregator } from "test/mocks/MockAggregator.sol";
import { MockSupplyOracle } from "test/mocks/MockSupplyOracle.sol";

/// @notice Section 4 Slice 3: the rebalancer rebalances around a quarantined
/// @notice The rebalancer rebalances around a quarantined
/// constituent (it weights and trades over the fresh subset) instead of the
/// whole epoch halting when a single feed goes stale.
contract RebalancerQuarantineTest is Test {
Expand Down
2 changes: 1 addition & 1 deletion test/RebalancerSettle.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { MockERC20 } from "test/mocks/MockERC20.sol";
import { MockAggregator } from "test/mocks/MockAggregator.sol";
import { MockSupplyOracle } from "test/mocks/MockSupplyOracle.sol";

/// @notice Slice 2 end-to-end: the vault is the CoW order owner and delegates
/// @notice End-to-end: the vault is the CoW order owner and delegates
/// validation to the rebalancer, and a mock settle runs both legs so an
/// off-target basket moves toward target while NAV stays within the value-loss
/// guard. Proves the full delta to order to settle to closer-to-target loop.
Expand Down
2 changes: 1 addition & 1 deletion test/RebalancerTrigger.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { MockERC20 } from "test/mocks/MockERC20.sol";
import { MockAggregator } from "test/mocks/MockAggregator.sol";
import { MockSupplyOracle } from "test/mocks/MockSupplyOracle.sol";

/// @notice Slice 3 tests for the dual-threshold trigger policy, starting from a
/// @notice Tests for the dual-threshold trigger policy, starting from a
/// balanced basket so drift can be dialled into the scheduled and emergency
/// bands deliberately.
contract RebalancerTriggerTest is Test {
Expand Down