@rev-net/core-v6 0.0.48 → 0.0.51
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/package.json +2 -2
- package/src/REVDeployer.sol +12 -1
- package/src/REVLoans.sol +11 -0
- package/src/REVOwner.sol +17 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rev-net/core-v6",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.51",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@bananapus/721-hook-v6": "^0.0.47",
|
|
30
30
|
"@bananapus/buyback-hook-v6": "^0.0.39",
|
|
31
|
-
"@bananapus/core-v6": "^0.0.
|
|
31
|
+
"@bananapus/core-v6": "^0.0.48",
|
|
32
32
|
"@bananapus/ownable-v6": "^0.0.24",
|
|
33
33
|
"@bananapus/permission-ids-v6": "^0.0.24",
|
|
34
34
|
"@bananapus/router-terminal-v6": "^0.0.37",
|
package/src/REVDeployer.sol
CHANGED
|
@@ -436,7 +436,18 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
|
|
|
436
436
|
terminalToken: terminalToken,
|
|
437
437
|
sqrtPriceX96: sqrtPriceX96
|
|
438
438
|
}) {}
|
|
439
|
-
catch {
|
|
439
|
+
catch {
|
|
440
|
+
// Two failure modes both end up here and both must NOT block the revnet deploy:
|
|
441
|
+
// 1. The V4 pool is already initialized at the expected price (idempotent re-deploy). The buyback
|
|
442
|
+
// hook's strict price check inside `initializePoolFor` would still call `_setPoolFor`, so the
|
|
443
|
+
// try-branch already covered this. We reach this catch only when the check rejected the existing
|
|
444
|
+
// price.
|
|
445
|
+
// 2. The V4 pool was front-run and pre-initialized at an attacker-chosen `sqrtPriceX96`. The buyback
|
|
446
|
+
// hook's strict price check reverts with `JBBuybackHook_PoolInitializedAtWrongPrice`, which lands
|
|
447
|
+
// here. We deliberately swallow that revert so an attacker cannot DoS the revnet deploy by
|
|
448
|
+
// squatting on the predictable pool address — the revnet ships without buyback configured and
|
|
449
|
+
// can be configured manually post-deploy.
|
|
450
|
+
}
|
|
440
451
|
}
|
|
441
452
|
|
|
442
453
|
//*********************************************************************//
|
package/src/REVLoans.sol
CHANGED
|
@@ -62,6 +62,7 @@ contract REVLoans is ERC721, ERC2771Context, JBPermissioned, Ownable, IREVLoans
|
|
|
62
62
|
error REVLoans_InvalidTerminal(address terminal, uint256 revnetId);
|
|
63
63
|
error REVLoans_LoanExpired(uint256 timeSinceLoanCreated, uint256 loanLiquidationDuration);
|
|
64
64
|
error REVLoans_LoanIdOverflow(uint256 revnetId, uint256 loanNumber, uint256 maxLoanNumber);
|
|
65
|
+
error REVLoans_LoanOwnerChanged(uint256 loanId, address expectedOwner, address actualOwner);
|
|
65
66
|
error REVLoans_NewBorrowAmountGreaterThanLoanAmount(uint256 newBorrowAmount, uint256 loanAmount);
|
|
66
67
|
error REVLoans_NoMsgValueAllowed(uint256 msgValue, address token);
|
|
67
68
|
error REVLoans_NotEnoughCollateral(uint256 collateralCountToRemove, uint256 loanCollateral);
|
|
@@ -884,6 +885,16 @@ contract REVLoans is ERC721, ERC2771Context, JBPermissioned, Ownable, IREVLoans
|
|
|
884
885
|
maxRepayBorrowAmount =
|
|
885
886
|
_acceptFundsFor({token: loan.source.token, amount: maxRepayBorrowAmount, allowance: allowance});
|
|
886
887
|
|
|
888
|
+
// Re-check ownership: an ERC-777/ERC-1363 source token can reenter during the transfer above and transfer
|
|
889
|
+
// the loan NFT to another account. Without this check, `_repayLoan` would burn the new owner's NFT while
|
|
890
|
+
// returning collateral to the stale cached owner.
|
|
891
|
+
{
|
|
892
|
+
address currentOwner = _ownerOf(loanId);
|
|
893
|
+
if (currentOwner != loanOwner) {
|
|
894
|
+
revert REVLoans_LoanOwnerChanged({loanId: loanId, expectedOwner: loanOwner, actualOwner: currentOwner});
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
|
|
887
898
|
// Make sure the minimum borrow amount is met.
|
|
888
899
|
if (repayBorrowAmount > maxRepayBorrowAmount) {
|
|
889
900
|
revert REVLoans_OverMaxRepayBorrowAmount({
|
package/src/REVOwner.sol
CHANGED
|
@@ -222,20 +222,14 @@ contract REVOwner is IJBRulesetDataHook, IJBCashOutHook, IJBPeerChainAdjustedAcc
|
|
|
222
222
|
uint256 feeCashOutCount = mulDiv({x: context.cashOutCount, y: FEE, denominator: JBConstants.MAX_FEE});
|
|
223
223
|
uint256 nonFeeCashOutCount = context.cashOutCount - feeCashOutCount;
|
|
224
224
|
|
|
225
|
-
//
|
|
226
|
-
//
|
|
225
|
+
// Compute the gross (effective-surplus) reclaim and fee amounts. The bonding curve uses cross-chain effective
|
|
226
|
+
// surplus, which can exceed what this chain's terminal actually holds.
|
|
227
227
|
uint256 postFeeReclaimedAmount = JBCashOuts.cashOutFrom({
|
|
228
228
|
surplus: effectiveSurplusValue,
|
|
229
229
|
cashOutCount: nonFeeCashOutCount,
|
|
230
230
|
totalSupply: totalSupply,
|
|
231
231
|
cashOutTaxRate: context.cashOutTaxRate
|
|
232
232
|
});
|
|
233
|
-
// Cap at local surplus — the bonding curve uses cross-chain effective surplus which can exceed what this
|
|
234
|
-
// chain's terminal actually holds.
|
|
235
|
-
if (postFeeReclaimedAmount > context.surplus.value) postFeeReclaimedAmount = context.surplus.value;
|
|
236
|
-
|
|
237
|
-
// Calculate how much the fee tokens reclaim from the remaining surplus after the non-fee reclaim.
|
|
238
|
-
// Use remaining effective surplus; cap at remaining local surplus.
|
|
239
233
|
uint256 feeAmount = JBCashOuts.cashOutFrom({
|
|
240
234
|
surplus: effectiveSurplusValue > postFeeReclaimedAmount
|
|
241
235
|
? effectiveSurplusValue - postFeeReclaimedAmount
|
|
@@ -244,11 +238,21 @@ contract REVOwner is IJBRulesetDataHook, IJBCashOutHook, IJBPeerChainAdjustedAcc
|
|
|
244
238
|
totalSupply: totalSupply - nonFeeCashOutCount,
|
|
245
239
|
cashOutTaxRate: context.cashOutTaxRate
|
|
246
240
|
});
|
|
247
|
-
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
|
|
251
|
-
|
|
241
|
+
|
|
242
|
+
// If the gross outflow exceeds local terminal liquidity, scale reclaim AND fee proportionally so the fee
|
|
243
|
+
// is preserved instead of being capped to zero when the reclaim alone consumes all local surplus.
|
|
244
|
+
uint256 grossOutflow = postFeeReclaimedAmount + feeAmount;
|
|
245
|
+
if (grossOutflow > context.surplus.value) {
|
|
246
|
+
if (grossOutflow == 0) {
|
|
247
|
+
// Defensive — both grossOutflow > localSurplus and grossOutflow == 0 can't both hold, but keep
|
|
248
|
+
// the explicit branch so future edits do not divide by zero.
|
|
249
|
+
postFeeReclaimedAmount = 0;
|
|
250
|
+
feeAmount = 0;
|
|
251
|
+
} else {
|
|
252
|
+
uint256 localSurplus = context.surplus.value;
|
|
253
|
+
postFeeReclaimedAmount = mulDiv({x: postFeeReclaimedAmount, y: localSurplus, denominator: grossOutflow});
|
|
254
|
+
feeAmount = mulDiv({x: feeAmount, y: localSurplus, denominator: grossOutflow});
|
|
255
|
+
}
|
|
252
256
|
}
|
|
253
257
|
|
|
254
258
|
// Build a context for the buyback hook using the non-fee token count and cross-chain-adjusted values
|