@rev-net/core-v6 0.0.48 → 0.0.50

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rev-net/core-v6",
3
- "version": "0.0.48",
3
+ "version": "0.0.50",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -436,7 +436,18 @@ contract REVDeployer is ERC2771Context, IREVDeployer, IERC721Receiver {
436
436
  terminalToken: terminalToken,
437
437
  sqrtPriceX96: sqrtPriceX96
438
438
  }) {}
439
- catch {} // Pool may already be initialized — that's OK.
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/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
- // Calculate how much surplus the non-fee tokens can reclaim via the bonding curve.
226
- // Use effective (cross-chain) surplus; cap at local surplus.
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
- // Cap the fee reclaim at remaining local surplus. The bonding curve uses the cross-chain effective surplus,
248
- // which can exceed what's actually held locally. Without this cap, the terminal would try to send more than
249
- // it has.
250
- if (feeAmount > context.surplus.value - postFeeReclaimedAmount) {
251
- feeAmount = context.surplus.value - postFeeReclaimedAmount;
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