@rev-net/core-v6 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,164 +0,0 @@
1
- # Revnet Pre-Deployment Security Checklist
2
-
3
- **Status**: All findings documented, tests written. Fixes required before deployment.
4
- **Test Suite**: `forge test --match-contract REVInvincibility -vvv`
5
- **Date**: 2026-02-21
6
-
7
- ---
8
-
9
- ## Critical Findings (5)
10
-
11
- ### C-1: uint112 Truncation in REVLoans._adjust
12
- - **File**: `REVLoans.sol:922-923`
13
- - **Code**: `loan.amount = uint112(newBorrowAmount); loan.collateral = uint112(newCollateralCount);`
14
- - **Impact**: Silently truncates borrow amounts > 5.19e33 (uint112.max), allowing loans with near-zero recorded debt but full ETH disbursement
15
- - **Fix Required**: Add `require(newBorrowAmount <= type(uint112).max)` and `require(newCollateralCount <= type(uint112).max)` before the casts
16
- - **Test**: `test_fixVerify_C1_uint112Truncation` — proves the truncation math
17
- - **Status**: [ ] UNFIXED
18
-
19
- ### C-2: Array OOB in REVDeployer.beforePayRecordedWith
20
- - **File**: `REVDeployer.sol:248-258`
21
- - **Code**: `hookSpecifications[1] = buybackHookSpecifications[0]` hardcoded to index [1]
22
- - **Impact**: Payment to any revnet with buyback hook but no 721 hook reverts (OOB on size-1 array)
23
- - **Fix Required**: Change line 258 to use dynamic index: `hookSpecifications[usesTiered721Hook ? 1 : 0]`
24
- - **Test**: `test_fixVerify_C2_arrayOOB_noBuybackWithBuyback` — proves the index logic
25
- - **Status**: [ ] UNFIXED
26
-
27
- ### C-3: Reentrancy in REVLoans._adjust
28
- - **File**: `REVLoans.sol:910 vs 922-923`
29
- - **Code**: `terminal.pay()` at line 910 before `loan.amount = ...` at line 922
30
- - **Impact**: Malicious fee terminal can reenter borrowFrom() with stale loan state, potentially extracting more than collateral supports
31
- - **Fix Required**: Either add `nonReentrant` modifier or move state writes (lines 922-923) before external calls (line 910)
32
- - **Test**: `test_fixVerify_C3_reentrancyDoubleBorrow` — confirms CEI violation pattern
33
- - **Status**: [ ] UNFIXED
34
-
35
- ### C-4: hasMintPermissionFor Reverts on address(0)
36
- - **File**: `REVDeployer.sol:353-354`
37
- - **Code**: `buybackHook.hasMintPermissionFor(...)` called when `buybackHook == address(0)`
38
- - **Impact**: Blocks ALL sucker claims and external mint operations for revnets without buyback hooks
39
- - **Fix Required**: Add `address(buybackHook) != address(0) &&` guard before the call
40
- - **Test**: `test_fixVerify_C4_hasMintPermission_noBuyback` — triggers the revert
41
- - **Status**: [ ] UNFIXED
42
-
43
- ### C-5: Zero-Supply Cash Out Drains Surplus
44
- - **File**: `JBCashOuts.sol:31`
45
- - **Code**: `if (cashOutCount >= totalSupply) return surplus;` — 0 >= 0 is true
46
- - **Impact**: When totalSupply=0, cashing out 0 tokens returns the ENTIRE surplus
47
- - **Fix Required**: Add `if (cashOutCount == 0) return 0;` before the totalSupply check
48
- - **Test**: `test_fixVerify_C5_zeroSupplyCashOutDrain` — proves 0/0 returns full surplus
49
- - **Status**: [ ] UNFIXED (in JBCashOuts library)
50
-
51
- ---
52
-
53
- ## High Findings (4 revnet-specific)
54
-
55
- ### H-1: Double Fee on Cash-Outs
56
- - **File**: `REVDeployer.sol:567-624`
57
- - **Impact**: Cash-out fees are charged twice — once by JBMultiTerminal (protocol fee) and once by REVDeployer's afterCashOutRecordedWith (revnet fee). REVDeployer is not registered as feeless.
58
- - **Fix Required**: Register REVDeployer as feeless address, or adjust fee calculation to account for the protocol fee already taken
59
- - **Test**: `test_econ_doubleFeeH1` — measures actual fee amounts
60
- - **Status**: [ ] UNFIXED
61
-
62
- ### H-2: Broken Fee Terminal Bricks Cash-Outs
63
- - **File**: `REVDeployer.sol:615`
64
- - **Impact**: In the catch block of afterCashOutRecordedWith, `addToBalanceOf()` is NOT wrapped in try/catch. If both feeTerminal.pay() and addToBalanceOf() revert, ALL cash-outs for the revnet become permanently impossible.
65
- - **Fix Required**: Wrap the fallback `addToBalanceOf()` at line 615 in its own try/catch
66
- - **Test**: `test_fixVerify_H2_brokenFeeTerminalBricksCashOuts` — demonstrates both paths revert
67
- - **Status**: [ ] UNFIXED
68
-
69
- ### H-5: Auto-Issuance Stage ID Mismatch
70
- - **File**: `REVDeployer.sol:1223`
71
- - **Code**: `amountToAutoIssue[revnetId][block.timestamp + i][...] += ...`
72
- - **Impact**: Stage ID computed as `block.timestamp + i` but actual ruleset IDs from JBRulesets may differ. Auto-issuance tokens for non-first stages become permanently unclaimable.
73
- - **Fix Required**: Use the actual ruleset IDs returned by `jbController().queueRulesetsOf()` instead of `block.timestamp + i`
74
- - **Test**: `test_fixVerify_H5_autoIssuanceStageIdMismatch` — confirms mismatch for stage 1+
75
- - **Status**: [ ] UNFIXED
76
-
77
- ### H-6: Unvalidated Source Terminal
78
- - **File**: `REVLoans.sol:788-791`
79
- - **Impact**: Any terminal can be registered as a loan source. Attacker can grow `_loanSourcesOf` array unboundedly, causing gas DoS on functions that iterate loan sources.
80
- - **Fix Required**: Validate that `loan.source.terminal` is a registered terminal for the project via `DIRECTORY.isTerminalOf(revnetId, loan.source.terminal)`
81
- - **Test**: `test_fixVerify_H6_unvalidatedSourceTerminal` — documents the unvalidated registration
82
- - **Status**: [ ] UNFIXED
83
-
84
- ---
85
-
86
- ## Medium Findings (3 revnet-specific)
87
-
88
- ### M-7: Silent Fee Failure in REVLoans._addTo
89
- - **File**: `REVLoans.sol:833-841`
90
- - **Impact**: REV fee payment in `_addTo` is wrapped in try/catch. If the fee terminal reverts, the fee is silently lost — REV holders lose fee revenue without any notification.
91
- - **Fix Required**: At minimum, emit an event on fee failure. Consider reverting to ensure fees are always collected.
92
- - **Status**: [ ] UNFIXED
93
-
94
- ### M-10: Cross-Source Value Extraction via reallocateCollateralFromLoan
95
- - **File**: `REVLoans.sol:619-654`
96
- - **Impact**: Collateral from one loan source can be transferred to create a loan from a different source. If source terminals have different fee structures, this enables fee arbitrage.
97
- - **Fix Required**: Consider restricting collateral reallocation to same-source loans
98
- - **Status**: [ ] UNFIXED
99
-
100
- ### M-11: Flash Loan Surplus Inflation
101
- - **File**: `REVLoans.sol:308-332`
102
- - **Impact**: `borrowableAmountFrom` reads live surplus. An attacker can `addToBalance` (inflating surplus without minting tokens) then immediately borrow at an inflated rate within the same block.
103
- - **Fix Required**: Consider using a time-weighted average surplus or adding a borrowing delay
104
- - **Test**: `test_econ_flashLoanSurplusInflation` — quantifies exact inflation factor
105
- - **Status**: [ ] UNFIXED
106
-
107
- ---
108
-
109
- ## Invariant Properties (Verified by Fuzzing)
110
-
111
- | ID | Property | Handler Operations | Runs |
112
- |----|----------|-------------------|------|
113
- | INV-REV-1 | Terminal balance covers outstanding loans | payAndBorrow, repayLoan, addToBalance | 256 |
114
- | INV-REV-2 | Ghost collateral sum == totalCollateralOf | payAndBorrow, repayLoan, reallocate | 256 |
115
- | INV-REV-3 | Ghost borrowed sum == totalBorrowedFrom | payAndBorrow, repayLoan | 256 |
116
- | INV-REV-4 | No undercollateralized loans (when no cash-outs) | payAndBorrow, advanceTime | 256 |
117
- | INV-REV-5 | totalSupply + totalCollateral coherent | All 10 operations | 256 |
118
- | INV-REV-6 | Fee project balance monotonically increasing | payAndBorrow (generates fees) | 256 |
119
-
120
- ---
121
-
122
- ## Test Execution
123
-
124
- ```bash
125
- # Section A+B: Fix verification + economic attacks (18 tests)
126
- forge test --match-contract REVInvincibility_FixVerify -vvv
127
-
128
- # Section C: Invariant properties (6 invariants)
129
- forge test --match-contract REVInvincibility_Invariants -vvv
130
-
131
- # Full suite
132
- forge test --match-contract REVInvincibility -vvv
133
-
134
- # Full regression (all existing tests still pass)
135
- forge test -vvv
136
- ```
137
-
138
- ---
139
-
140
- ## Post-Deployment Monitoring Recommendations
141
-
142
- 1. **Loan Health Monitor**: Track `totalBorrowedFrom` vs terminal balance for each revnet. Alert if borrowed exceeds 80% of surplus.
143
- 2. **Fee Collection Monitor**: Verify fee project token supply increases after every borrow operation. Alert on silent fee failures.
144
- 3. **Collateral Consistency**: Periodically verify `sum(loan.collateral)` for all active loans matches `totalCollateralOf(revnetId)`.
145
- 4. **Loan Source Array**: Monitor `_loanSourcesOf` array length. Alert if it exceeds expected number of terminals.
146
- 5. **Auto-Issuance Claims**: After each stage transition, verify auto-issuance can be claimed at the correct ruleset ID.
147
- 6. **Cash-Out Availability**: Monitor that cash-outs succeed after fee terminal configuration changes.
148
-
149
- ---
150
-
151
- ## Fix Priority Order
152
-
153
- 1. **C-3** (Reentrancy) — Highest risk, enables active exploitation
154
- 2. **C-5** (Zero-supply drain) — Direct fund loss
155
- 3. **C-1** (uint112 truncation) — Fund loss at extreme values
156
- 4. **C-4** (hasMintPermission revert) — Blocks sucker claims
157
- 5. **C-2** (Array OOB) — Breaks payments for buyback-only revnets
158
- 6. **H-2** (Broken fee terminal) — Permanent cash-out DoS
159
- 7. **H-5** (Auto-issuance mismatch) — Permanent token loss
160
- 8. **H-6** (Unvalidated terminal) — Gas DoS vector
161
- 9. **H-1** (Double fee) — Economic loss for users
162
- 10. **M-11** (Flash surplus inflation) — Economic exploitation
163
- 11. **M-10** (Cross-source extraction) — Fee arbitrage
164
- 12. **M-7** (Silent fee failure) — Revenue leakage