@rev-net/core-v6 0.0.37 → 0.0.39
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/CHANGELOG.md +2 -2
- package/README.md +6 -7
- package/foundry.toml +1 -1
- package/package.json +23 -16
- package/references/operations.md +1 -1
- package/references/runtime.md +1 -1
- package/script/Deploy.s.sol +12 -9
- package/src/REVDeployer.sol +60 -65
- package/src/REVHiddenTokens.sol +2 -2
- package/src/REVLoans.sol +17 -10
- package/src/REVOwner.sol +121 -14
- package/src/interfaces/IREVDeployer.sol +2 -1
- package/src/interfaces/IREVHiddenTokens.sol +4 -1
- package/src/interfaces/IREVOwner.sol +5 -0
- package/ADMINISTRATION.md +0 -73
- package/ARCHITECTURE.md +0 -116
- package/AUDIT_INSTRUCTIONS.md +0 -90
- package/RISKS.md +0 -107
- package/SKILLS.md +0 -46
- package/STYLE_GUIDE.md +0 -610
- package/USER_JOURNEYS.md +0 -195
- package/foundry.lock +0 -11
- package/slither-ci.config.json +0 -10
- package/sphinx.lock +0 -507
- package/test/REV.integrations.t.sol +0 -573
- package/test/REVAutoIssuanceFuzz.t.sol +0 -328
- package/test/REVDeployerRegressions.t.sol +0 -396
- package/test/REVInvincibility.t.sol +0 -1371
- package/test/REVInvincibilityHandler.sol +0 -387
- package/test/REVLifecycle.t.sol +0 -420
- package/test/REVLoans.invariants.t.sol +0 -724
- package/test/REVLoansAttacks.t.sol +0 -816
- package/test/REVLoansFeeRecovery.t.sol +0 -783
- package/test/REVLoansFindings.t.sol +0 -711
- package/test/REVLoansRegressions.t.sol +0 -364
- package/test/REVLoansSourceFeeRecovery.t.sol +0 -517
- package/test/REVLoansSourced.t.sol +0 -1839
- package/test/REVLoansUnSourced.t.sol +0 -409
- package/test/TestAuditFixVerification.t.sol +0 -675
- package/test/TestBurnHeldTokens.t.sol +0 -394
- package/test/TestCEIPattern.t.sol +0 -508
- package/test/TestCashOutCallerValidation.t.sol +0 -452
- package/test/TestConversionDocumentation.t.sol +0 -365
- package/test/TestCrossCurrencyReclaim.t.sol +0 -610
- package/test/TestCrossSourceReallocation.t.sol +0 -361
- package/test/TestERC2771MetaTx.t.sol +0 -585
- package/test/TestEmptyBuybackSpecs.t.sol +0 -300
- package/test/TestFlashLoanSurplus.t.sol +0 -365
- package/test/TestHiddenTokens.t.sol +0 -474
- package/test/TestHookArrayOOB.t.sol +0 -278
- package/test/TestLiquidationBehavior.t.sol +0 -398
- package/test/TestLoanSourceRotation.t.sol +0 -553
- package/test/TestLoansCashOutDelay.t.sol +0 -493
- package/test/TestLongTailEconomics.t.sol +0 -677
- package/test/TestLowFindings.t.sol +0 -677
- package/test/TestMixedFixes.t.sol +0 -593
- package/test/TestPermit2Signatures.t.sol +0 -683
- package/test/TestReallocationSandwich.t.sol +0 -412
- package/test/TestRevnetRegressions.t.sol +0 -350
- package/test/TestSplitWeightAdjustment.t.sol +0 -527
- package/test/TestSplitWeightE2E.t.sol +0 -605
- package/test/TestSplitWeightFork.t.sol +0 -855
- package/test/TestStageTransitionBorrowable.t.sol +0 -301
- package/test/TestSwapTerminalPermission.t.sol +0 -262
- package/test/TestTerminalEncodingInHash.t.sol +0 -326
- package/test/TestUint112Overflow.t.sol +0 -311
- package/test/TestZeroAmountLoanGuard.t.sol +0 -378
- package/test/TestZeroRepayment.t.sol +0 -354
- package/test/audit/CrossChainBuybackRouteMismatch.t.sol +0 -184
- package/test/audit/HiddenSupplyCashout.t.sol +0 -61
- package/test/audit/LoanIdOverflowGuard.t.sol +0 -523
- package/test/audit/NemesisVerification.t.sol +0 -97
- package/test/audit/OperatorDelegation.t.sol +0 -356
- package/test/audit/PhantomSurplusTerminal.t.sol +0 -367
- package/test/audit/REVOwnerCurrencyMismatch.t.sol +0 -188
- package/test/audit/REVOwnerRemoteSurplusCurrencyMismatch.t.sol +0 -140
- package/test/audit/ReallocatePermission.t.sol +0 -363
- package/test/audit/RemoteLoanAccountingGap.t.sol +0 -74
- package/test/audit/SupportsInterfaceTest.t.sol +0 -51
- package/test/audit/TestFeeAllowanceLeak.t.sol +0 -197
- package/test/audit/TestLoansAndDeployerFixes.t.sol +0 -576
- package/test/fork/ForkTestBase.sol +0 -727
- package/test/fork/TestAutoIssuanceFork.t.sol +0 -148
- package/test/fork/TestCashOutFork.t.sol +0 -253
- package/test/fork/TestIssuanceDecayFork.t.sol +0 -158
- package/test/fork/TestLoanAdversarialFork.t.sol +0 -744
- package/test/fork/TestLoanBorrowFork.t.sol +0 -163
- package/test/fork/TestLoanCrossRulesetFork.t.sol +0 -308
- package/test/fork/TestLoanERC20Fork.t.sol +0 -459
- package/test/fork/TestLoanLiquidationFork.t.sol +0 -135
- package/test/fork/TestLoanReallocateFork.t.sol +0 -113
- package/test/fork/TestLoanRepayFork.t.sol +0 -188
- package/test/fork/TestLoanTransferFork.t.sol +0 -143
- package/test/fork/TestPermit2PaymentFork.t.sol +0 -300
- package/test/fork/TestSplitWeightFork.t.sol +0 -189
- package/test/helpers/MaliciousContracts.sol +0 -247
- package/test/helpers/REVEmpty721Config.sol +0 -45
- package/test/mock/MockBuybackCashOutRecorder.sol +0 -84
- package/test/mock/MockBuybackDataHook.sol +0 -112
- package/test/mock/MockBuybackDataHookMintPath.sol +0 -68
- package/test/mock/MockSuckerRegistry.sol +0 -17
- package/test/regression/TestBurnPermissionRequired.t.sol +0 -294
- package/test/regression/TestCashOutBuybackFeeLeak.t.sol +0 -232
- package/test/regression/TestCrossRevnetLiquidation.t.sol +0 -255
- package/test/regression/TestCumulativeLoanCounter.t.sol +0 -361
- package/test/regression/TestLiquidateGapHandling.t.sol +0 -394
- package/test/regression/TestZeroPriceFeed.t.sol +0 -422
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
pragma solidity 0.8.28;
|
|
3
|
-
|
|
4
|
-
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
|
|
5
|
-
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
|
|
6
|
-
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
7
|
-
import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
|
|
8
|
-
import {IJBTerminal} from "@bananapus/core-v6/src/interfaces/IJBTerminal.sol";
|
|
9
|
-
import {IJBPayoutTerminal} from "@bananapus/core-v6/src/interfaces/IJBPayoutTerminal.sol";
|
|
10
|
-
import {JBAccountingContext} from "@bananapus/core-v6/src/structs/JBAccountingContext.sol";
|
|
11
|
-
import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
|
|
12
|
-
import {JBRuleset} from "@bananapus/core-v6/src/structs/JBRuleset.sol";
|
|
13
|
-
import {JBPayHookSpecification} from "@bananapus/core-v6/src/structs/JBPayHookSpecification.sol";
|
|
14
|
-
import {REVLoanSource} from "../../src/structs/REVLoanSource.sol";
|
|
15
|
-
import {REVLoansFeeRecovery} from "../REVLoansFeeRecovery.t.sol";
|
|
16
|
-
|
|
17
|
-
contract StickyAllowanceFeeTerminal is ERC165, IJBPayoutTerminal {
|
|
18
|
-
IERC20 public immutable token;
|
|
19
|
-
address public immutable loans;
|
|
20
|
-
address public thief;
|
|
21
|
-
uint256 public stealAmount;
|
|
22
|
-
|
|
23
|
-
constructor(IERC20 _token, address _loans) {
|
|
24
|
-
token = _token;
|
|
25
|
-
loans = _loans;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function configureSteal(address _thief, uint256 _stealAmount) external {
|
|
29
|
-
thief = _thief;
|
|
30
|
-
stealAmount = _stealAmount;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function pay(
|
|
34
|
-
uint256,
|
|
35
|
-
address,
|
|
36
|
-
uint256,
|
|
37
|
-
address,
|
|
38
|
-
uint256,
|
|
39
|
-
string calldata,
|
|
40
|
-
bytes calldata
|
|
41
|
-
)
|
|
42
|
-
external
|
|
43
|
-
payable
|
|
44
|
-
override
|
|
45
|
-
returns (uint256)
|
|
46
|
-
{
|
|
47
|
-
uint256 amount = stealAmount;
|
|
48
|
-
if (amount != 0) {
|
|
49
|
-
stealAmount = 0;
|
|
50
|
-
token.transferFrom(loans, thief, amount);
|
|
51
|
-
}
|
|
52
|
-
return 0;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function accountingContextForTokenOf(uint256, address) external view override returns (JBAccountingContext memory) {
|
|
56
|
-
return JBAccountingContext({token: address(token), decimals: 6, currency: uint32(uint160(address(token)))});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function accountingContextsOf(uint256) external pure override returns (JBAccountingContext[] memory) {
|
|
60
|
-
return new JBAccountingContext[](0);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function addAccountingContextsFor(uint256, JBAccountingContext[] calldata) external override {}
|
|
64
|
-
|
|
65
|
-
function addToBalanceOf(
|
|
66
|
-
uint256,
|
|
67
|
-
address,
|
|
68
|
-
uint256,
|
|
69
|
-
bool,
|
|
70
|
-
string calldata,
|
|
71
|
-
bytes calldata
|
|
72
|
-
)
|
|
73
|
-
external
|
|
74
|
-
payable
|
|
75
|
-
override
|
|
76
|
-
{}
|
|
77
|
-
|
|
78
|
-
function currentSurplusOf(uint256, address[] calldata, uint256, uint256) external pure override returns (uint256) {
|
|
79
|
-
return 0;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function migrateBalanceOf(uint256, address, IJBTerminal) external pure override returns (uint256) {
|
|
83
|
-
return 0;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function sendPayoutsOf(uint256, address, uint256, uint256, uint256) external pure override returns (uint256) {
|
|
87
|
-
return 0;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function useAllowanceOf(
|
|
91
|
-
uint256,
|
|
92
|
-
address,
|
|
93
|
-
uint256,
|
|
94
|
-
uint256,
|
|
95
|
-
uint256,
|
|
96
|
-
address payable,
|
|
97
|
-
address payable,
|
|
98
|
-
string calldata
|
|
99
|
-
)
|
|
100
|
-
external
|
|
101
|
-
pure
|
|
102
|
-
override
|
|
103
|
-
returns (uint256)
|
|
104
|
-
{
|
|
105
|
-
return 0;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function previewPayFor(
|
|
109
|
-
uint256,
|
|
110
|
-
address,
|
|
111
|
-
uint256,
|
|
112
|
-
address,
|
|
113
|
-
bytes calldata
|
|
114
|
-
)
|
|
115
|
-
external
|
|
116
|
-
pure
|
|
117
|
-
override
|
|
118
|
-
returns (JBRuleset memory, uint256, uint256, JBPayHookSpecification[] memory)
|
|
119
|
-
{
|
|
120
|
-
JBRuleset memory ruleset;
|
|
121
|
-
return (ruleset, 0, 0, new JBPayHookSpecification[](0));
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function supportsInterface(bytes4 interfaceId) public view override(ERC165, IERC165) returns (bool) {
|
|
125
|
-
return interfaceId == type(IJBTerminal).interfaceId || interfaceId == type(IJBPayoutTerminal).interfaceId
|
|
126
|
-
|| super.supportsInterface(interfaceId);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
contract TestFeeAllowanceLeak is REVLoansFeeRecovery {
|
|
131
|
-
StickyAllowanceFeeTerminal internal stickyFeeTerminal;
|
|
132
|
-
address internal attacker = makeAddr("attacker");
|
|
133
|
-
|
|
134
|
-
function _stickyFeeTerminal() internal returns (StickyAllowanceFeeTerminal) {
|
|
135
|
-
if (address(stickyFeeTerminal) == address(0)) {
|
|
136
|
-
stickyFeeTerminal = new StickyAllowanceFeeTerminal(TOKEN, address(LOANS_CONTRACT));
|
|
137
|
-
}
|
|
138
|
-
return stickyFeeTerminal;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/// @notice Verifies that stale allowance is cleared — the original exploit no longer works.
|
|
142
|
-
/// @dev Previously, a sticky fee terminal could accumulate reusable allowance across borrows.
|
|
143
|
-
/// After the fix (_afterTransferTo clears allowance on success), the allowance is zero.
|
|
144
|
-
function test_feeTerminalCannotHarvestStaleAllowanceAfterFix() public {
|
|
145
|
-
StickyAllowanceFeeTerminal terminal = _stickyFeeTerminal();
|
|
146
|
-
|
|
147
|
-
vm.mockCall(
|
|
148
|
-
address(jbDirectory()),
|
|
149
|
-
abi.encodeWithSelector(IJBDirectory.primaryTerminalOf.selector, FEE_PROJECT_ID, address(TOKEN)),
|
|
150
|
-
abi.encode(address(terminal))
|
|
151
|
-
);
|
|
152
|
-
|
|
153
|
-
REVLoanSource memory source = REVLoanSource({token: address(TOKEN), terminal: jbMultiTerminal()});
|
|
154
|
-
uint256 payAmount = 1_000_000;
|
|
155
|
-
|
|
156
|
-
deal(address(TOKEN), USER, payAmount * 2);
|
|
157
|
-
|
|
158
|
-
vm.startPrank(USER);
|
|
159
|
-
TOKEN.approve(address(jbMultiTerminal()), payAmount * 2);
|
|
160
|
-
uint256 firstTokenCount = jbMultiTerminal().pay(REVNET_ID, address(TOKEN), payAmount, USER, 0, "", "");
|
|
161
|
-
vm.stopPrank();
|
|
162
|
-
|
|
163
|
-
_mockLoanPermission(USER);
|
|
164
|
-
vm.prank(USER);
|
|
165
|
-
LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, firstTokenCount, payable(USER), 25, USER);
|
|
166
|
-
|
|
167
|
-
// Allowance is now cleared after successful fee payment.
|
|
168
|
-
uint256 allowanceAfterBorrow = TOKEN.allowance(address(LOANS_CONTRACT), address(stickyFeeTerminal));
|
|
169
|
-
assertEq(allowanceAfterBorrow, 0, "no stale allowance after successful borrow");
|
|
170
|
-
|
|
171
|
-
// The uncollected fee is still parked in REVLoans (terminal didn't pull it),
|
|
172
|
-
// but there's no allowance for the terminal to steal it later.
|
|
173
|
-
uint256 loansBalance = TOKEN.balanceOf(address(LOANS_CONTRACT));
|
|
174
|
-
assertGt(loansBalance, 0, "uncollected fee is parked in REVLoans");
|
|
175
|
-
|
|
176
|
-
// Second borrow — terminal tries to steal but can't because allowance is 0.
|
|
177
|
-
vm.prank(USER);
|
|
178
|
-
uint256 secondTokenCount = jbMultiTerminal().pay(REVNET_ID, address(TOKEN), payAmount, USER, 0, "", "");
|
|
179
|
-
|
|
180
|
-
terminal.configureSteal(attacker, loansBalance);
|
|
181
|
-
|
|
182
|
-
_mockLoanPermission(USER);
|
|
183
|
-
vm.prank(USER);
|
|
184
|
-
LOANS_CONTRACT.borrowFrom(REVNET_ID, source, 0, secondTokenCount, payable(USER), 25, USER);
|
|
185
|
-
|
|
186
|
-
// The attacker gets nothing — the steal attempt fails silently (transferFrom reverts,
|
|
187
|
-
// caught by _tryPayFee's try-catch).
|
|
188
|
-
assertEq(TOKEN.balanceOf(attacker), 0, "attacker cannot drain stale allowance");
|
|
189
|
-
|
|
190
|
-
// And the current borrow also leaves zero allowance.
|
|
191
|
-
assertEq(
|
|
192
|
-
TOKEN.allowance(address(LOANS_CONTRACT), address(terminal)),
|
|
193
|
-
0,
|
|
194
|
-
"no fresh stale allowance after second borrow"
|
|
195
|
-
);
|
|
196
|
-
}
|
|
197
|
-
}
|