@rev-net/core-v6 0.0.9 → 0.0.11
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.
- package/ARCHITECTURE.md +1 -1
- package/README.md +4 -4
- package/SKILLS.md +2 -8
- package/STYLE_GUIDE.md +127 -51
- package/docs/src/README.md +2 -2
- package/foundry.toml +3 -0
- package/package.json +12 -9
- package/remappings.txt +1 -1
- package/script/Deploy.s.sol +1 -1
- package/script/helpers/RevnetCoreDeploymentLib.sol +1 -1
- package/src/REVDeployer.sol +30 -26
- package/src/REVLoans.sol +1 -0
- package/test/{REVDeployerAuditRegressions.t.sol → REVDeployerRegressions.t.sol} +1 -1
- package/test/REVInvincibility.t.sol +15 -19
- package/test/REVLifecycle.t.sol +0 -1
- package/test/REVLoansAttacks.t.sol +3 -7
- package/test/REVLoansFeeRecovery.t.sol +0 -2
- package/test/{REVLoans_AuditFindings.t.sol → REVLoansFindings.t.sol} +6 -6
- package/test/{REVLoansAuditRegressions.t.sol → REVLoansRegressions.t.sol} +2 -2
- package/test/REVLoansSourced.t.sol +3 -1
- package/test/{TestPR26_BurnHeldTokens.t.sol → TestBurnHeldTokens.t.sol} +1 -1
- package/test/{TestPR27_CEIPattern.t.sol → TestCEIPattern.t.sol} +3 -3
- package/test/{TestPR15_CashOutCallerValidation.t.sol → TestCashOutCallerValidation.t.sol} +1 -3
- package/test/{TestPR09_ConversionDocumentation.t.sol → TestConversionDocumentation.t.sol} +1 -1
- package/test/{TestPR13_CrossSourceReallocation.t.sol → TestCrossSourceReallocation.t.sol} +1 -1
- package/test/{TestPR12_FlashLoanSurplus.t.sol → TestFlashLoanSurplus.t.sol} +1 -1
- package/test/{TestPR22_HookArrayOOB.t.sol → TestHookArrayOOB.t.sol} +1 -1
- package/test/{TestPR10_LiquidationBehavior.t.sol → TestLiquidationBehavior.t.sol} +4 -4
- package/test/{TestPR11_LowFindings.t.sol → TestLowFindings.t.sol} +1 -1
- package/test/{TestPR32_MixedFixes.t.sol → TestMixedFixes.t.sol} +1 -1
- package/test/TestSplitWeightFork.t.sol +118 -159
- package/test/{TestPR29_SwapTerminalPermission.t.sol → TestSwapTerminalPermission.t.sol} +1 -1
- package/test/{TestPR21_Uint112Overflow.t.sol → TestUint112Overflow.t.sol} +4 -4
- package/test/{TestPR16_ZeroRepayment.t.sol → TestZeroRepayment.t.sol} +4 -6
- package/test/fork/ForkTestBase.sol +83 -51
- package/test/fork/TestCashOutFork.t.sol +12 -11
- package/test/fork/TestLoanBorrowFork.t.sol +10 -12
- package/test/fork/TestLoanCrossRulesetFork.t.sol +300 -0
- package/test/fork/TestLoanLiquidationFork.t.sol +13 -8
- package/test/fork/TestLoanReallocateFork.t.sol +21 -12
- package/test/fork/TestLoanRepayFork.t.sol +17 -14
- package/test/fork/TestSplitWeightFork.t.sol +34 -34
- package/test/mock/MockBuybackDataHook.sol +4 -7
- package/test/mock/MockBuybackDataHookMintPath.sol +5 -8
- package/test/regression/{TestI20_CumulativeLoanCounter.t.sol → TestCumulativeLoanCounter.t.sol} +4 -4
- package/test/regression/{TestL27_LiquidateGapHandling.t.sol → TestLiquidateGapHandling.t.sol} +3 -3
|
@@ -373,7 +373,7 @@ contract REVInvincibility_PropertyTests is TestBaseWorkflow {
|
|
|
373
373
|
/// @notice hasMintPermissionFor returns false for random addresses.
|
|
374
374
|
/// @dev With the buyback hook removed, hasMintPermissionFor should return false
|
|
375
375
|
/// for addresses that are not the loans contract or a sucker.
|
|
376
|
-
function test_fixVerify_hasMintPermission_noBuyback() public {
|
|
376
|
+
function test_fixVerify_hasMintPermission_noBuyback() public view {
|
|
377
377
|
// The fee project was deployed without buyback hook in our setup
|
|
378
378
|
JBRuleset memory currentRuleset = jbRulesets().currentOf(FEE_PROJECT_ID);
|
|
379
379
|
|
|
@@ -574,7 +574,7 @@ contract REVInvincibility_PropertyTests is TestBaseWorkflow {
|
|
|
574
574
|
function test_econ_loanAmplificationSpiral() public {
|
|
575
575
|
// Step 1: Pay to get tokens
|
|
576
576
|
uint256 payAmount = 10e18;
|
|
577
|
-
(
|
|
577
|
+
(,, uint256 borrow1) = _setupLoan(USER, payAmount, 25);
|
|
578
578
|
assertTrue(borrow1 > 0, "First loan should have borrow amount");
|
|
579
579
|
|
|
580
580
|
// Step 2: Add borrowed amount back to balance (inflating surplus)
|
|
@@ -588,8 +588,7 @@ contract REVInvincibility_PropertyTests is TestBaseWorkflow {
|
|
|
588
588
|
jbMultiTerminal().pay{value: payAmount}(REVNET_ID, JBConstants.NATIVE_TOKEN, payAmount, USER, 0, "", "");
|
|
589
589
|
|
|
590
590
|
// Step 4: Try to borrow again
|
|
591
|
-
|
|
592
|
-
LOANS_CONTRACT.borrowableAmountFrom(REVNET_ID, tokens2, 18, uint32(uint160(JBConstants.NATIVE_TOKEN)));
|
|
591
|
+
LOANS_CONTRACT.borrowableAmountFrom(REVNET_ID, tokens2, 18, uint32(uint160(JBConstants.NATIVE_TOKEN)));
|
|
593
592
|
|
|
594
593
|
// The totalBorrowed from loan1 is added to surplus in borrowableAmountFrom,
|
|
595
594
|
// so the second borrow should not amplify beyond what the real surplus supports.
|
|
@@ -619,7 +618,7 @@ contract REVInvincibility_PropertyTests is TestBaseWorkflow {
|
|
|
619
618
|
jbMultiTerminal().pay{value: 0.01e18}(REVNET_ID, JBConstants.NATIVE_TOKEN, 0.01e18, payor, 0, "", "");
|
|
620
619
|
|
|
621
620
|
// Get current ruleset to verify we're in stage 1
|
|
622
|
-
|
|
621
|
+
jbRulesets().currentOf(REVNET_ID);
|
|
623
622
|
|
|
624
623
|
// Cash out at the new (lower) tax rate
|
|
625
624
|
// Note: there's a 30-day cash out delay, so we advance more
|
|
@@ -653,8 +652,7 @@ contract REVInvincibility_PropertyTests is TestBaseWorkflow {
|
|
|
653
652
|
function test_econ_reservedTokenDilution() public {
|
|
654
653
|
// Pay to create surplus + mint tokens (some go to reserved)
|
|
655
654
|
vm.prank(USER);
|
|
656
|
-
|
|
657
|
-
jbMultiTerminal().pay{value: 10e18}(REVNET_ID, JBConstants.NATIVE_TOKEN, 10e18, USER, 0, "", "");
|
|
655
|
+
jbMultiTerminal().pay{value: 10e18}(REVNET_ID, JBConstants.NATIVE_TOKEN, 10e18, USER, 0, "", "");
|
|
658
656
|
|
|
659
657
|
// Send reserved tokens to splits
|
|
660
658
|
try jbController().sendReservedTokensToSplitsOf(REVNET_ID) {} catch {}
|
|
@@ -721,8 +719,7 @@ contract REVInvincibility_PropertyTests is TestBaseWorkflow {
|
|
|
721
719
|
jbMultiTerminal().pay{value: 10e18}(REVNET_ID, JBConstants.NATIVE_TOKEN, 10e18, userA, 0, "", "");
|
|
722
720
|
|
|
723
721
|
vm.prank(userB);
|
|
724
|
-
|
|
725
|
-
jbMultiTerminal().pay{value: 10e18}(REVNET_ID, JBConstants.NATIVE_TOKEN, 10e18, userB, 0, "", "");
|
|
722
|
+
jbMultiTerminal().pay{value: 10e18}(REVNET_ID, JBConstants.NATIVE_TOKEN, 10e18, userB, 0, "", "");
|
|
726
723
|
|
|
727
724
|
// UserA borrows (tokens locked as collateral)
|
|
728
725
|
mockExpect(
|
|
@@ -757,7 +754,7 @@ contract REVInvincibility_PropertyTests is TestBaseWorkflow {
|
|
|
757
754
|
/// @dev Extraction should be bounded by the bonding curve.
|
|
758
755
|
function test_econ_collateralRotation() public {
|
|
759
756
|
// Setup initial loan
|
|
760
|
-
(uint256 loanId
|
|
757
|
+
(uint256 loanId,, uint256 borrowAmount) = _setupLoan(USER, 5e18, 25);
|
|
761
758
|
if (borrowAmount == 0) return;
|
|
762
759
|
|
|
763
760
|
// Surplus increases (someone else pays in)
|
|
@@ -787,7 +784,7 @@ contract REVInvincibility_PropertyTests is TestBaseWorkflow {
|
|
|
787
784
|
/// @dev Borrow all available surplus → new payments and repayment still functional.
|
|
788
785
|
function test_econ_zeroSurplusLoanDefault() public {
|
|
789
786
|
// Pay and borrow maximum
|
|
790
|
-
(
|
|
787
|
+
(,, uint256 borrowAmount) = _setupLoan(USER, 10e18, 25);
|
|
791
788
|
if (borrowAmount == 0) return;
|
|
792
789
|
|
|
793
790
|
// New user can still pay into the system
|
|
@@ -802,7 +799,7 @@ contract REVInvincibility_PropertyTests is TestBaseWorkflow {
|
|
|
802
799
|
/// @notice Loans across stage boundary: loans stay healthy when tax rate decreases.
|
|
803
800
|
function test_econ_stageTransitionWithLoans() public {
|
|
804
801
|
// Create loan in stage 0
|
|
805
|
-
(uint256 loanId
|
|
802
|
+
(uint256 loanId,, uint256 borrowAmount) = _setupLoan(USER, 10e18, 25);
|
|
806
803
|
if (borrowAmount == 0) return;
|
|
807
804
|
|
|
808
805
|
REVLoan memory loanBefore = LOANS_CONTRACT.loanOf(loanId);
|
|
@@ -822,7 +819,7 @@ contract REVInvincibility_PropertyTests is TestBaseWorkflow {
|
|
|
822
819
|
assertEq(loanAfter.collateral, loanBefore.collateral, "Loan collateral unchanged across stages");
|
|
823
820
|
|
|
824
821
|
// Borrowable amount may have changed (different tax rate)
|
|
825
|
-
|
|
822
|
+
LOANS_CONTRACT.borrowableAmountFrom(
|
|
826
823
|
REVNET_ID, loanAfter.collateral, 18, uint32(uint160(JBConstants.NATIVE_TOKEN))
|
|
827
824
|
);
|
|
828
825
|
// With lower tax rate in stage 1, borrowable should increase
|
|
@@ -834,8 +831,7 @@ contract REVInvincibility_PropertyTests is TestBaseWorkflow {
|
|
|
834
831
|
function test_econ_splitOperatorRug() public {
|
|
835
832
|
// Pay to build up surplus and reserved tokens
|
|
836
833
|
vm.prank(USER);
|
|
837
|
-
|
|
838
|
-
jbMultiTerminal().pay{value: 50e18}(REVNET_ID, JBConstants.NATIVE_TOKEN, 50e18, USER, 0, "", "");
|
|
834
|
+
jbMultiTerminal().pay{value: 50e18}(REVNET_ID, JBConstants.NATIVE_TOKEN, 50e18, USER, 0, "", "");
|
|
839
835
|
|
|
840
836
|
// Send reserved tokens to splits (multisig = split beneficiary)
|
|
841
837
|
try jbController().sendReservedTokensToSplitsOf(REVNET_ID) {} catch {}
|
|
@@ -1168,7 +1164,7 @@ contract REVInvincibility_Invariants is StdInvariant, TestBaseWorkflow {
|
|
|
1168
1164
|
// INV-REV-2: Collateral accounting exact
|
|
1169
1165
|
// =====================================================================
|
|
1170
1166
|
/// @notice Ghost collateral sum must match contract's totalCollateralOf.
|
|
1171
|
-
function invariant_REV_2_collateralAccountingExact() public {
|
|
1167
|
+
function invariant_REV_2_collateralAccountingExact() public view {
|
|
1172
1168
|
assertEq(
|
|
1173
1169
|
HANDLER.COLLATERAL_SUM(),
|
|
1174
1170
|
LOANS_CONTRACT.totalCollateralOf(REVNET_ID),
|
|
@@ -1180,7 +1176,7 @@ contract REVInvincibility_Invariants is StdInvariant, TestBaseWorkflow {
|
|
|
1180
1176
|
// INV-REV-3: Borrow accounting exact
|
|
1181
1177
|
// =====================================================================
|
|
1182
1178
|
/// @notice Ghost borrowed sum must match contract's totalBorrowedFrom.
|
|
1183
|
-
function invariant_REV_3_borrowAccountingExact() public {
|
|
1179
|
+
function invariant_REV_3_borrowAccountingExact() public view {
|
|
1184
1180
|
uint256 actualTotalBorrowed =
|
|
1185
1181
|
LOANS_CONTRACT.totalBorrowedFrom(REVNET_ID, jbMultiTerminal(), JBConstants.NATIVE_TOKEN);
|
|
1186
1182
|
|
|
@@ -1196,7 +1192,7 @@ contract REVInvincibility_Invariants is StdInvariant, TestBaseWorkflow {
|
|
|
1196
1192
|
/// @dev Loans CAN become undercollateralized when new payments increase totalSupply
|
|
1197
1193
|
/// faster than surplus grows (bonding curve dilution). This is expected behavior.
|
|
1198
1194
|
/// We verify that the loan struct itself is internally consistent.
|
|
1199
|
-
function invariant_REV_4_noUndercollateralizedLoans() public {
|
|
1195
|
+
function invariant_REV_4_noUndercollateralizedLoans() public view {
|
|
1200
1196
|
if (HANDLER.callCount_payAndBorrow() == 0) return;
|
|
1201
1197
|
|
|
1202
1198
|
for (uint256 i = 1; i <= HANDLER.callCount_payAndBorrow(); i++) {
|
|
@@ -1226,7 +1222,7 @@ contract REVInvincibility_Invariants is StdInvariant, TestBaseWorkflow {
|
|
|
1226
1222
|
// INV-REV-5: Supply + collateral consistency
|
|
1227
1223
|
// =====================================================================
|
|
1228
1224
|
/// @notice totalSupply + totalCollateral should be coherent with token tracking.
|
|
1229
|
-
function invariant_REV_5_supplyCollateralConsistency() public {
|
|
1225
|
+
function invariant_REV_5_supplyCollateralConsistency() public view {
|
|
1230
1226
|
uint256 totalSupply = jbController().totalTokenSupplyWithReservedTokensOf(REVNET_ID);
|
|
1231
1227
|
uint256 totalCollateral = LOANS_CONTRACT.totalCollateralOf(REVNET_ID);
|
|
1232
1228
|
|
package/test/REVLifecycle.t.sol
CHANGED
|
@@ -252,7 +252,6 @@ contract REVLifecycle_Local is TestBaseWorkflow {
|
|
|
252
252
|
|
|
253
253
|
// Cash out half in stage 0 (50% tax)
|
|
254
254
|
uint256 halfTokens = tokens / 2;
|
|
255
|
-
uint256 user1BalBefore = USER1.balance;
|
|
256
255
|
vm.prank(USER1);
|
|
257
256
|
uint256 reclaimedStage0 = jbMultiTerminal()
|
|
258
257
|
.cashOutTokensOf({
|
|
@@ -524,7 +524,7 @@ contract REVLoansAttacks is TestBaseWorkflow {
|
|
|
524
524
|
|
|
525
525
|
// Setup: create a loan first
|
|
526
526
|
uint256 payAmount = 10e18;
|
|
527
|
-
(uint256 loanId
|
|
527
|
+
(uint256 loanId,, uint256 borrowAmount) = _setupLoan(USER, payAmount, 25);
|
|
528
528
|
vm.assume(borrowAmount > 0);
|
|
529
529
|
|
|
530
530
|
// The loan exists. The reentrancy risk during repayLoan:
|
|
@@ -559,8 +559,7 @@ contract REVLoansAttacks is TestBaseWorkflow {
|
|
|
559
559
|
jbMultiTerminal().pay{value: 10e18}(REVNET_ID, JBConstants.NATIVE_TOKEN, 10e18, userA, 0, "", "");
|
|
560
560
|
|
|
561
561
|
vm.prank(userB);
|
|
562
|
-
|
|
563
|
-
jbMultiTerminal().pay{value: 10e18}(REVNET_ID, JBConstants.NATIVE_TOKEN, 10e18, userB, 0, "", "");
|
|
562
|
+
jbMultiTerminal().pay{value: 10e18}(REVNET_ID, JBConstants.NATIVE_TOKEN, 10e18, userB, 0, "", "");
|
|
564
563
|
|
|
565
564
|
// Record pre-borrow state
|
|
566
565
|
uint256 totalSupplyBefore = jbController().totalTokenSupplyWithReservedTokensOf(REVNET_ID);
|
|
@@ -604,7 +603,7 @@ contract REVLoansAttacks is TestBaseWorkflow {
|
|
|
604
603
|
/// @notice After LOAN_LIQUIDATION_DURATION (3650 days), the loan expires and cannot be repaid.
|
|
605
604
|
function test_liquidation_borrowRepayAfterExpiry() public {
|
|
606
605
|
uint256 payAmount = 10e18;
|
|
607
|
-
(uint256 loanId
|
|
606
|
+
(uint256 loanId,, uint256 borrowAmount) = _setupLoan(USER, payAmount, 25);
|
|
608
607
|
vm.assume(borrowAmount > 0);
|
|
609
608
|
|
|
610
609
|
// Warp past the liquidation duration (3650 days)
|
|
@@ -715,9 +714,6 @@ contract REVLoansAttacks is TestBaseWorkflow {
|
|
|
715
714
|
// Calculate repay amount
|
|
716
715
|
uint256 repayAmount = loan.amount;
|
|
717
716
|
|
|
718
|
-
// The user needs to have ETH to repay
|
|
719
|
-
uint256 userBalanceBefore = USER.balance;
|
|
720
|
-
|
|
721
717
|
// Repay the full loan
|
|
722
718
|
vm.prank(USER);
|
|
723
719
|
LOANS_CONTRACT.repayLoan{value: repayAmount}({
|
|
@@ -195,8 +195,6 @@ contract REVLoansFeeRecovery is TestBaseWorkflow {
|
|
|
195
195
|
extraMetadata: 0
|
|
196
196
|
});
|
|
197
197
|
|
|
198
|
-
REVLoanSource[] memory _loanSources = new REVLoanSource[](0);
|
|
199
|
-
|
|
200
198
|
REVConfig memory revnetConfiguration = REVConfig({
|
|
201
199
|
description: REVDescription(
|
|
202
200
|
"Revnet", "$REV", "ipfs://QmNRHT91HcDgMcenebYX7rJigt77cgNcosvuhX21wkF3tx", ERC20_SALT
|
|
@@ -129,12 +129,12 @@ contract GarbageTerminal is ERC165, IJBPayoutTerminal {
|
|
|
129
129
|
receive() external payable {}
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
/// @notice Regression tests for
|
|
132
|
+
/// @notice Regression tests for loan findings.
|
|
133
133
|
/// Unvalidated loan source terminal
|
|
134
134
|
/// RepayLoan event emits zeroed values
|
|
135
135
|
/// Auto-issuance timing guard bypass (false positive)
|
|
136
136
|
/// repayLoan revert on excess collateral (false positive)
|
|
137
|
-
contract
|
|
137
|
+
contract REVLoansFindings is TestBaseWorkflow {
|
|
138
138
|
bytes32 REV_DEPLOYER_SALT = "REVDeployer";
|
|
139
139
|
bytes32 ERC20_SALT = "REV_TOKEN";
|
|
140
140
|
|
|
@@ -327,7 +327,7 @@ contract REVLoans_AuditFindings is TestBaseWorkflow {
|
|
|
327
327
|
//*********************************************************************//
|
|
328
328
|
|
|
329
329
|
/// @notice borrowFrom rejects a fake terminal not registered in the directory.
|
|
330
|
-
function
|
|
330
|
+
function test_borrowFromRejectsUnregisteredTerminal() public {
|
|
331
331
|
// Step 1: User pays into the revnet to get tokens.
|
|
332
332
|
uint256 tokens = _payAndGetTokens(1e18);
|
|
333
333
|
assertGt(tokens, 0, "user should receive tokens");
|
|
@@ -367,10 +367,10 @@ contract REVLoans_AuditFindings is TestBaseWorkflow {
|
|
|
367
367
|
|
|
368
368
|
/// @notice RepayLoan event emits non-zero loan amount and collateral
|
|
369
369
|
/// when fully repaying a loan.
|
|
370
|
-
function
|
|
370
|
+
function test_repayLoanEventEmitsNonZeroValues() public {
|
|
371
371
|
// Step 1: Pay in and borrow.
|
|
372
372
|
uint256 tokens = _payAndGetTokens(1e18);
|
|
373
|
-
(uint256 loanId, REVLoan memory loan,
|
|
373
|
+
(uint256 loanId, REVLoan memory loan,) = _borrow(tokens);
|
|
374
374
|
|
|
375
375
|
assertGt(loan.amount, 0, "loan amount should be non-zero");
|
|
376
376
|
assertGt(loan.collateral, 0, "loan collateral should be non-zero");
|
|
@@ -408,7 +408,7 @@ contract REVLoans_AuditFindings is TestBaseWorkflow {
|
|
|
408
408
|
|
|
409
409
|
/// @notice Secondary check: verify the original loan data in the emitted event
|
|
410
410
|
/// has the expected non-zero amount and collateral by recording logs.
|
|
411
|
-
function
|
|
411
|
+
function test_repayLoanEventLoanFieldIsNonZero() public {
|
|
412
412
|
// Step 1: Pay in and borrow.
|
|
413
413
|
uint256 tokens = _payAndGetTokens(1e18);
|
|
414
414
|
(uint256 loanId, REVLoan memory loan,) = _borrow(tokens);
|
|
@@ -129,7 +129,7 @@ contract FakeTerminal is ERC165, IJBPayoutTerminal {
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
/// @notice Regression tests for REVLoans unvalidated source terminal.
|
|
132
|
-
contract
|
|
132
|
+
contract REVLoansRegressions is TestBaseWorkflow {
|
|
133
133
|
bytes32 REV_DEPLOYER_SALT = "REVDeployer";
|
|
134
134
|
bytes32 ERC20_SALT = "REV_TOKEN";
|
|
135
135
|
|
|
@@ -289,7 +289,7 @@ contract REVLoansRegressions_Local is TestBaseWorkflow {
|
|
|
289
289
|
}
|
|
290
290
|
|
|
291
291
|
/// @notice Verify that the configured loan source (real terminal) is properly registered.
|
|
292
|
-
function test_configuredSourceIsRegistered() public {
|
|
292
|
+
function test_configuredSourceIsRegistered() public view {
|
|
293
293
|
// The real terminal should be in the directory
|
|
294
294
|
IJBTerminal[] memory terminals = jbDirectory().terminalsOf(REVNET_ID);
|
|
295
295
|
bool found = false;
|
|
@@ -729,7 +729,9 @@ contract REVLoansSourcedTests is TestBaseWorkflow {
|
|
|
729
729
|
|
|
730
730
|
assertApproxEqAbs(balance, reclaimableSurplus - nanaFee, 1);
|
|
731
731
|
|
|
732
|
-
|
|
732
|
+
// Allow 2 wei absolute tolerance alongside 3% relative tolerance — at very small
|
|
733
|
+
// surplus values (e.g. 90 wei), a single mulDiv rounding error exceeds 3%.
|
|
734
|
+
assertGe(reclaimableSurplus + revFee + 2, mulDiv(loanable, 97, 100));
|
|
733
735
|
}
|
|
734
736
|
|
|
735
737
|
function test_Pay_Borrow_With_Loan_Source() public {
|
|
@@ -37,7 +37,7 @@ struct FeeProjectConfig {
|
|
|
37
37
|
REVSuckerDeploymentConfig suckerDeploymentConfiguration;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
contract
|
|
40
|
+
contract TestBurnHeldTokens is TestBaseWorkflow {
|
|
41
41
|
bytes32 REV_DEPLOYER_SALT = "REVDeployer";
|
|
42
42
|
bytes32 ERC20_SALT = "REV_TOKEN";
|
|
43
43
|
|
|
@@ -59,7 +59,7 @@ contract ReentrantBorrower {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
/// @title
|
|
62
|
+
/// @title TestCEIPattern
|
|
63
63
|
/// @notice Tests for CEI pattern fix in REVLoans._adjust()
|
|
64
64
|
///
|
|
65
65
|
/// Source context (_addTo/_removeFrom/_addCollateralTo/_returnCollateralFrom):
|
|
@@ -69,7 +69,7 @@ contract ReentrantBorrower {
|
|
|
69
69
|
/// - _returnCollateralFrom(uint256 revnetId, uint256 collateralCount, ...) — no loan reference
|
|
70
70
|
/// None of the four helpers read loan.amount or loan.collateral — they all use pre-computed deltas.
|
|
71
71
|
/// The CEI fix writes loan.amount and loan.collateral BEFORE calling any of these helpers.
|
|
72
|
-
contract
|
|
72
|
+
contract TestCEIPattern is TestBaseWorkflow {
|
|
73
73
|
bytes32 REV_DEPLOYER_SALT = "REVDeployer";
|
|
74
74
|
|
|
75
75
|
REVDeployer REV_DEPLOYER;
|
|
@@ -253,7 +253,7 @@ contract TestPR27_CEIPattern is TestBaseWorkflow {
|
|
|
253
253
|
|
|
254
254
|
/// @notice Repay a loan and verify state is consistent afterwards.
|
|
255
255
|
function test_repayLoan_stateConsistent() public {
|
|
256
|
-
(uint256 loanId
|
|
256
|
+
(uint256 loanId,, uint256 borrowAmount) = _setupLoan(USER, 10e18, 500);
|
|
257
257
|
assertTrue(borrowAmount > 0, "Should borrow nonzero");
|
|
258
258
|
|
|
259
259
|
REVLoan memory loan = LOANS_CONTRACT.loanOf(loanId);
|
|
@@ -37,7 +37,7 @@ struct FeeProjectConfig {
|
|
|
37
37
|
REVSuckerDeploymentConfig suckerDeploymentConfiguration;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
contract
|
|
40
|
+
contract TestCashOutCallerValidation is TestBaseWorkflow {
|
|
41
41
|
bytes32 REV_DEPLOYER_SALT = "REVDeployer";
|
|
42
42
|
bytes32 ERC20_SALT = "REV_TOKEN";
|
|
43
43
|
|
|
@@ -96,8 +96,6 @@ contract TestPR15_CashOutCallerValidation is TestBaseWorkflow {
|
|
|
96
96
|
});
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
REVLoanSource[] memory loanSources = new REVLoanSource[](0);
|
|
100
|
-
|
|
101
99
|
REVConfig memory revnetConfiguration = REVConfig({
|
|
102
100
|
description: REVDescription(name, symbol, projectUri, ERC20_SALT),
|
|
103
101
|
baseCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
|
|
@@ -31,7 +31,7 @@ import {JB721TiersHookStore} from "@bananapus/721-hook-v6/src/JB721TiersHookStor
|
|
|
31
31
|
import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressRegistry.sol";
|
|
32
32
|
import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
|
|
33
33
|
|
|
34
|
-
contract
|
|
34
|
+
contract TestConversionDocumentation is TestBaseWorkflow {
|
|
35
35
|
bytes32 REV_DEPLOYER_SALT = "REVDeployer";
|
|
36
36
|
bytes32 ERC20_SALT = "REV_TOKEN";
|
|
37
37
|
|
|
@@ -31,7 +31,7 @@ import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressReg
|
|
|
31
31
|
import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
|
|
32
32
|
|
|
33
33
|
/// @notice Tests for PR #13: cross-source reallocation prevention.
|
|
34
|
-
contract
|
|
34
|
+
contract TestCrossSourceReallocation is TestBaseWorkflow {
|
|
35
35
|
bytes32 REV_DEPLOYER_SALT = "REVDeployer";
|
|
36
36
|
|
|
37
37
|
REVDeployer REV_DEPLOYER;
|
|
@@ -31,7 +31,7 @@ import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressReg
|
|
|
31
31
|
import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
|
|
32
32
|
|
|
33
33
|
/// @notice Tests showing that flash loan surplus manipulation is economically unprofitable.
|
|
34
|
-
contract
|
|
34
|
+
contract TestFlashLoanSurplus is TestBaseWorkflow {
|
|
35
35
|
bytes32 REV_DEPLOYER_SALT = "REVDeployer";
|
|
36
36
|
bytes32 ERC20_SALT = "REV_TOKEN";
|
|
37
37
|
|
|
@@ -36,7 +36,7 @@ import {JBRuleset} from "@bananapus/core-v6/src/structs/JBRuleset.sol";
|
|
|
36
36
|
/// The bug: `hookSpecifications[1] = buybackHookSpecifications[0]` would revert with OOB
|
|
37
37
|
/// when there is no tiered 721 hook (array size is 1, not 2).
|
|
38
38
|
/// The fix: `hookSpecifications[usesTiered721Hook ? 1 : 0] = buybackHookSpecifications[0]`.
|
|
39
|
-
contract
|
|
39
|
+
contract TestHookArrayOOB is TestBaseWorkflow {
|
|
40
40
|
bytes32 REV_DEPLOYER_SALT = "REVDeployer";
|
|
41
41
|
|
|
42
42
|
REVDeployer REV_DEPLOYER;
|
|
@@ -33,7 +33,7 @@ import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/
|
|
|
33
33
|
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
|
|
34
34
|
|
|
35
35
|
/// @notice Tests for PR #10: liquidation behavior documentation and collateral burn mechanics.
|
|
36
|
-
contract
|
|
36
|
+
contract TestLiquidationBehavior is TestBaseWorkflow {
|
|
37
37
|
bytes32 REV_DEPLOYER_SALT = "REVDeployer";
|
|
38
38
|
|
|
39
39
|
REVDeployer REV_DEPLOYER;
|
|
@@ -251,7 +251,7 @@ contract TestPR10_LiquidationBehavior is TestBaseWorkflow {
|
|
|
251
251
|
function test_borrowerKeepsBorrowedFunds() public {
|
|
252
252
|
uint256 userBalanceBefore = USER.balance;
|
|
253
253
|
|
|
254
|
-
(uint256 loanId,,
|
|
254
|
+
(uint256 loanId,,) = _setupLoan(USER, 10e18, 25);
|
|
255
255
|
require(loanId != 0, "Loan setup failed");
|
|
256
256
|
|
|
257
257
|
uint256 userBalanceAfter = USER.balance;
|
|
@@ -271,7 +271,7 @@ contract TestPR10_LiquidationBehavior is TestBaseWorkflow {
|
|
|
271
271
|
|
|
272
272
|
/// @notice Repay before expiry returns collateral (re-mints tokens).
|
|
273
273
|
function test_repayBeforeExpiry_collateralReminted() public {
|
|
274
|
-
(uint256 loanId,,
|
|
274
|
+
(uint256 loanId,,) = _setupLoan(USER, 10e18, 25);
|
|
275
275
|
require(loanId != 0, "Loan setup failed");
|
|
276
276
|
|
|
277
277
|
REVLoan memory loan = LOANS_CONTRACT.loanOf(loanId);
|
|
@@ -296,7 +296,7 @@ contract TestPR10_LiquidationBehavior is TestBaseWorkflow {
|
|
|
296
296
|
|
|
297
297
|
/// @notice After liquidation, the loan NFT is burned and collateral/borrow tracking is decremented.
|
|
298
298
|
function test_loanDataDeletedAfterLiquidation() public {
|
|
299
|
-
(uint256 loanId,,
|
|
299
|
+
(uint256 loanId,,) = _setupLoan(USER, 10e18, 25);
|
|
300
300
|
require(loanId != 0, "Loan setup failed");
|
|
301
301
|
|
|
302
302
|
REVLoan memory loan = LOANS_CONTRACT.loanOf(loanId);
|
|
@@ -37,7 +37,7 @@ struct FeeProjectConfig {
|
|
|
37
37
|
REVSuckerDeploymentConfig suckerDeploymentConfiguration;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
contract
|
|
40
|
+
contract TestLowFindings is TestBaseWorkflow {
|
|
41
41
|
bytes32 REV_DEPLOYER_SALT = "REVDeployer";
|
|
42
42
|
bytes32 ERC20_SALT = "REV_TOKEN";
|
|
43
43
|
|
|
@@ -31,7 +31,7 @@ import {JBAddressRegistry} from "@bananapus/address-registry-v6/src/JBAddressReg
|
|
|
31
31
|
import {IJBAddressRegistry} from "@bananapus/address-registry-v6/src/interfaces/IJBAddressRegistry.sol";
|
|
32
32
|
|
|
33
33
|
/// @notice Tests for PR #32: liquidation boundary, reallocate msg.value, and decimal normalization fixes.
|
|
34
|
-
contract
|
|
34
|
+
contract TestMixedFixes is TestBaseWorkflow {
|
|
35
35
|
bytes32 REV_DEPLOYER_SALT = "REVDeployer";
|
|
36
36
|
|
|
37
37
|
REVDeployer REV_DEPLOYER;
|