|
| 1 | +import "./common.spec"; |
| 2 | + |
| 3 | +function allAccountValidState() { |
| 4 | + requireInvariant DelegationAccountsCorrelation(); |
| 5 | + requireInvariant DelegationValidRebaseState(); |
| 6 | + requireInvariant stdNonRebasingDoesntYield(); |
| 7 | + requireInvariant alternativeCreditsPerTokenIsOneOrZeroOnly(); |
| 8 | + requireInvariant yieldDelegationSourceHasNonZeroYeildTo(); |
| 9 | + requireInvariant yieldDelegationTargetHasNonZeroYeildFrom(); |
| 10 | + requireInvariant yieldToOfZeroIsZero(); |
| 11 | + requireInvariant yieldFromOfZeroIsZero(); |
| 12 | + requireInvariant cantYieldToSelf(); |
| 13 | + requireInvariant cantYieldFromSelf(); |
| 14 | + requireInvariant zeroAlternativeCreditsPerTokenStates(); |
| 15 | + requireInvariant nonZeroAlternativeCreditsPerTokenStates(); |
| 16 | +} |
| 17 | + |
| 18 | +/// @title Any non zero valued YieldTo points to an account that has a YieldFrom pointing back to the starting account and vice versa. |
| 19 | +/// @property Account Invariants |
| 20 | +invariant DelegationAccountsCorrelation() |
| 21 | + forall address account. |
| 22 | + (OUSD.yieldTo[account] != 0 => (OUSD.yieldFrom[OUSD.yieldTo[account]] == account)) |
| 23 | + && |
| 24 | + (OUSD.yieldFrom[account] != 0 => (OUSD.yieldTo[OUSD.yieldFrom[account]] == account)) |
| 25 | + { |
| 26 | + preserved with (env e) { |
| 27 | + requireInvariant DelegationValidRebaseState(); |
| 28 | + requireInvariant yieldToOfZeroIsZero(); |
| 29 | + requireInvariant yieldFromOfZeroIsZero(); |
| 30 | + } |
| 31 | + } |
| 32 | + |
| 33 | +/// @title Any non zero valued YieldTo points to an account Iff that account is in YieldDelegationSource state and |
| 34 | +/// Any non zero valued YieldFrom points to an account Iff that account is in YieldDelegationTarget state. |
| 35 | +/// @property Account Invariants |
| 36 | +invariant DelegationValidRebaseState() |
| 37 | + forall address account. |
| 38 | + (OUSD.yieldTo[account] != 0 <=> OUSD.rebaseState[account] == YieldDelegationSource()) |
| 39 | + && |
| 40 | + (OUSD.yieldFrom[account] != 0 <=> OUSD.rebaseState[account] == YieldDelegationTarget()) |
| 41 | + { |
| 42 | + preserved with (env e) { |
| 43 | + requireInvariant DelegationAccountsCorrelation(); |
| 44 | + requireInvariant yieldToOfZeroIsZero(); |
| 45 | + requireInvariant yieldFromOfZeroIsZero(); |
| 46 | + } |
| 47 | + } |
| 48 | + |
| 49 | +/// @title Any account with a zero value in alternativeCreditsPerToken has a rebaseState that is one of (NotSet, StdRebasing, or YieldDelegationTarget) |
| 50 | +/// @property Account Invariants |
| 51 | +invariant zeroAlternativeCreditsPerTokenStates() |
| 52 | + forall address account . OUSD.alternativeCreditsPerToken[account] == 0 <=> (OUSD.rebaseState[account] == NotSet() || |
| 53 | + OUSD.rebaseState[account] == StdRebasing() || |
| 54 | + OUSD.rebaseState[account] == YieldDelegationTarget()) |
| 55 | + { |
| 56 | + preserved { |
| 57 | + requireInvariant yieldToOfZeroIsZero(); |
| 58 | + requireInvariant yieldFromOfZeroIsZero(); |
| 59 | + requireInvariant DelegationAccountsCorrelation(); |
| 60 | + requireInvariant DelegationValidRebaseState(); |
| 61 | + } |
| 62 | + } |
| 63 | + |
| 64 | +/// @title Any account with value of 1e18 in alternativeCreditsPerToken has a rebaseState that is one of (StdNonRebasing, YieldDelegationSource) |
| 65 | +/// @property Account Invariants |
| 66 | +invariant nonZeroAlternativeCreditsPerTokenStates() |
| 67 | + forall address account . OUSD.alternativeCreditsPerToken[account] != 0 <=> (OUSD.rebaseState[account] == StdNonRebasing() || |
| 68 | + OUSD.rebaseState[account] == YieldDelegationSource()) |
| 69 | + { |
| 70 | + preserved undelegateYield(address _account) with (env e) { |
| 71 | + requireInvariant yieldToOfZeroIsZero(); |
| 72 | + requireInvariant yieldFromOfZeroIsZero(); |
| 73 | + requireInvariant DelegationAccountsCorrelation(); |
| 74 | + requireInvariant DelegationValidRebaseState(); |
| 75 | + } |
| 76 | + } |
| 77 | + |
| 78 | +/// @title The result of balanceOf of any account in StdNonRebasing state equals the account's credit-balance. |
| 79 | +/// @property Balance Invariants |
| 80 | +invariant stdNonRebasingBalanceEqCreditBalances(address account) |
| 81 | + OUSD.rebaseState[account] == StdNonRebasing() => OUSD.balanceOf(account) == OUSD.creditBalances[account] |
| 82 | + { |
| 83 | + preserved { |
| 84 | + requireInvariant yieldToOfZeroIsZero(); |
| 85 | + requireInvariant yieldFromOfZeroIsZero(); |
| 86 | + requireInvariant DelegationAccountsCorrelation(); |
| 87 | + requireInvariant DelegationValidRebaseState(); |
| 88 | + requireInvariant nonZeroAlternativeCreditsPerTokenStates(); |
| 89 | + requireInvariant stdNonRebasingDoesntYield(); |
| 90 | + requireInvariant alternativeCreditsPerTokenIsOneOrZeroOnly(); |
| 91 | + } |
| 92 | + } |
| 93 | + |
| 94 | +/// @title Any account in StdNonRebasing state doesn't yield to no account. |
| 95 | +/// @property Account Invariants |
| 96 | +invariant stdNonRebasingDoesntYield() |
| 97 | + forall address account . OUSD.rebaseState[account] == StdNonRebasing() => OUSD.yieldTo[account] == 0 |
| 98 | + { |
| 99 | + preserved { |
| 100 | + requireInvariant yieldToOfZeroIsZero(); |
| 101 | + requireInvariant yieldFromOfZeroIsZero(); |
| 102 | + requireInvariant DelegationAccountsCorrelation(); |
| 103 | + requireInvariant DelegationValidRebaseState(); |
| 104 | + } |
| 105 | + } |
| 106 | + |
| 107 | +/// @title alternativeCreditsPerToken can only be set to 0 or 1e18, no other values |
| 108 | +/// @property Account Invariants |
| 109 | +invariant alternativeCreditsPerTokenIsOneOrZeroOnly() |
| 110 | + forall address account . OUSD.alternativeCreditsPerToken[account] == 0 || OUSD.alternativeCreditsPerToken[account] == e18(); |
| 111 | + |
| 112 | +/// @title Any account with rebaseState = YieldDelegationSource has a nonZero yieldTo |
| 113 | +/// @property Account Invariants |
| 114 | +invariant yieldDelegationSourceHasNonZeroYeildTo() |
| 115 | + forall address account . OUSD.rebaseState[account] == YieldDelegationSource() => OUSD.yieldTo[account] != 0; |
| 116 | + |
| 117 | +/// @title Any account with rebaseState = YieldDelegationTarget has a nonZero yieldFrom |
| 118 | +/// @property Account Invariants |
| 119 | +invariant yieldDelegationTargetHasNonZeroYeildFrom() |
| 120 | + forall address account . OUSD.rebaseState[account] == YieldDelegationTarget() => OUSD.yieldFrom[account] != 0; |
| 121 | + |
| 122 | +// Helper Invariants |
| 123 | +/// @title yieldTo of zero is zero |
| 124 | +/// @property Account Invariants |
| 125 | +invariant yieldToOfZeroIsZero() |
| 126 | + yieldTo(0) == 0; |
| 127 | + |
| 128 | +/// @title yieldFrom of zero is zero |
| 129 | +/// @property Account Invariants |
| 130 | +invariant yieldFromOfZeroIsZero() |
| 131 | + yieldFrom(0) == 0; |
| 132 | + |
| 133 | +/// @title yieldTo of an account can't be the same as the account |
| 134 | +/// @property Account Invariants |
| 135 | +invariant cantYieldToSelf() |
| 136 | + forall address account . OUSD.yieldTo[account] != 0 => OUSD.yieldTo[account] != account; |
| 137 | + |
| 138 | +/// @title yieldFrom of an account can't be the same as the account |
| 139 | +/// @property Account Invariants |
| 140 | +invariant cantYieldFromSelf() |
| 141 | + forall address account . OUSD.yieldFrom[account] != 0 => OUSD.yieldFrom[account] != account; |
| 142 | + |
| 143 | +/// @title Only delegation changes the different effective identity. |
| 144 | +/// @property Account Invariants |
| 145 | +rule onlyDelegationChangesPairingState(address accountA, address accountB, method f) |
| 146 | +filtered{f -> !f.isView} |
| 147 | +{ |
| 148 | + bool different_before = differentAccounts(accountA, accountB); |
| 149 | + env e; |
| 150 | + calldataarg args; |
| 151 | + f(e, args); |
| 152 | + bool different_after = differentAccounts(accountA, accountB); |
| 153 | + |
| 154 | + if(delegateMethods(f)) { |
| 155 | + satisfy different_before != different_after; |
| 156 | + } |
| 157 | + assert different_before != different_after => delegateMethods(f); |
| 158 | +} |
0 commit comments