@rev-net/core-v6 0.0.51 → 0.0.52
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 +12 -0
- package/package.json +1 -1
- package/src/REVOwner.sol +37 -0
package/CHANGELOG.md
CHANGED
|
@@ -21,6 +21,18 @@ This file describes the verified change from `revnet-core-v5` to the current `re
|
|
|
21
21
|
- The v6 test tree is substantially broader than the v5 tree, with dedicated regression, fork, attack, and invariant coverage for loans, cash-outs, split weights, and lifecycle edges.
|
|
22
22
|
- The repo moved from the v5 `0.8.23` baseline to `0.8.28`.
|
|
23
23
|
|
|
24
|
+
## In-v6 changes
|
|
25
|
+
|
|
26
|
+
### `0.0.52` — Cap reported surplus on `REVOwner.beforeCashOutRecordedWith` to fit local liquidity
|
|
27
|
+
|
|
28
|
+
PR #149 scaled the fee + reclaim proportionally when the gross global outflow exceeded local terminal liquidity, preserving a nonzero fee. But the data hook still returned the **unscaled** `effectiveSurplusValue` to `JBTerminalStore._cashOutWithDataHook`, which recomputes the beneficiary reclaim as `cashOutFrom(effSurplus, cashOutCount, totalSupply, taxRate)` and caps it at local surplus before adding the fee spec — so `balanceDiff = localSurplus + feeAmount > localSurplus` reverted with `InadequateTerminalStoreBalance`. Omnichain holders could not cash out locally when global surplus dominated.
|
|
29
|
+
|
|
30
|
+
`cashOutFrom` is linear in `surplus`. After the existing PR #149 scaling, `REVOwner` now lowers the reported `effectiveSurplusValue` proportionally so the store's recomputed reclaim is at most `localSurplus - feeAmount`, leaving exact room for the (preserved) fee spec. The buyback hook still receives the full pre-cap global surplus for its routing decision — only the store-facing return is capped.
|
|
31
|
+
|
|
32
|
+
The fee is **never** trimmed or zeroed: that was the regression PR #149 fixed.
|
|
33
|
+
|
|
34
|
+
Integrator impact: omnichain cash-outs that previously reverted with `InadequateTerminalStoreBalance` when local liquidity was the binding cap now settle. The beneficiary receives `localSurplus - feeAmount` and the fee revnet receives `feeAmount`. The user still burns the full `context.cashOutCount` tokens — semantics are the same as the pre-existing local-cap protocol behavior, just now reachable end-to-end.
|
|
35
|
+
|
|
24
36
|
## Operator delegation
|
|
25
37
|
|
|
26
38
|
- Added new `JBPermissionIds` for operator delegation in `@bananapus/permission-ids-v6`:
|
package/package.json
CHANGED
package/src/REVOwner.sol
CHANGED
|
@@ -239,6 +239,12 @@ contract REVOwner is IJBRulesetDataHook, IJBCashOutHook, IJBPeerChainAdjustedAcc
|
|
|
239
239
|
cashOutTaxRate: context.cashOutTaxRate
|
|
240
240
|
});
|
|
241
241
|
|
|
242
|
+
// Snapshot the unscaled reclaim before the local-liquidity proportional scaling below mutates it. This is
|
|
243
|
+
// what `JBTerminalStore._cashOutWithDataHook` will recompute when it calls
|
|
244
|
+
// `JBCashOuts.cashOutFrom(effectiveSurplusValue, cashOutCount, totalSupply, cashOutTaxRate)` — same inputs,
|
|
245
|
+
// same output. Used to cap the surplus we report to the store so the recompute leaves room for the fee.
|
|
246
|
+
uint256 unscaledReclaim = postFeeReclaimedAmount;
|
|
247
|
+
|
|
242
248
|
// If the gross outflow exceeds local terminal liquidity, scale reclaim AND fee proportionally so the fee
|
|
243
249
|
// is preserved instead of being capped to zero when the reclaim alone consumes all local surplus.
|
|
244
250
|
uint256 grossOutflow = postFeeReclaimedAmount + feeAmount;
|
|
@@ -272,6 +278,37 @@ contract REVOwner is IJBRulesetDataHook, IJBCashOutHook, IJBPeerChainAdjustedAcc
|
|
|
272
278
|
return (cashOutTaxRate, cashOutCount, totalSupply, effectiveSurplusValue, buybackHookSpecifications);
|
|
273
279
|
}
|
|
274
280
|
|
|
281
|
+
// The store will recompute the beneficiary reclaim as `cashOutFrom(effectiveSurplusValue, cashOutCount,
|
|
282
|
+
// totalSupply, cashOutTaxRate)` and add the fee spec on top. When local liquidity is the binding cap, that
|
|
283
|
+
// sum can exceed local surplus and revert. `cashOutFrom` is linear in `surplus`, so scale the surplus we
|
|
284
|
+
// report so the store-side reclaim is at most `localSurplus - feeAmount`, preserving room for the fee.
|
|
285
|
+
// The fee is NOT scaled here — it was already scaled by the PR #149 block above. Only the store-facing
|
|
286
|
+
// surplus is touched; the buyback hook already received the full pre-cap value for its routing decision.
|
|
287
|
+
//
|
|
288
|
+
// Worked example (local=10, global=100, 500 of 1000 tokens at 50% tax):
|
|
289
|
+
// above this block (PR #149):
|
|
290
|
+
// unscaledReclaim = cashOutFrom(100, 487.5, 1000, 5000) ≈ 36 ETH (global)
|
|
291
|
+
// feeAmount = cashOutFrom(64, 12.5, 512.5, 5000) ≈ 0.78 ETH (global)
|
|
292
|
+
// grossOutflow ≈ 36.78 > 10 → scale both proportionally to local liquidity:
|
|
293
|
+
// postFeeReclaimedAmount *= 10/36.78 ≈ 9.79 ETH
|
|
294
|
+
// feeAmount *= 10/36.78 ≈ 0.214 ETH (preserved, nonzero)
|
|
295
|
+
// this block:
|
|
296
|
+
// reclaimCap = 10 − 0.214 = 9.786 ETH
|
|
297
|
+
// unscaledReclaim (36) > reclaimCap (9.786) → cap the surplus we report:
|
|
298
|
+
// effectiveSurplusValue = 100 × 9.786 / 36 ≈ 27.18 ETH
|
|
299
|
+
// store recompute (linear in surplus):
|
|
300
|
+
// storeReclaim = 36 × (27.18 / 100) ≈ 9.786 ETH
|
|
301
|
+
// balanceDiff = 9.786 + 0.214 = 10 ETH = localSurplus ✓ no revert
|
|
302
|
+
//
|
|
303
|
+
// Underflow safety on `localSurplus − feeAmount`: after PR #149 the relation
|
|
304
|
+
// `feeAmount ≤ localSurplus` holds in both branches — in the scaling branch because
|
|
305
|
+
// `feeAmount ≤ grossOutflow` and the multiplier is `localSurplus / grossOutflow ≤ 1`;
|
|
306
|
+
// in the else branch because `feeAmount ≤ grossOutflow ≤ localSurplus` already.
|
|
307
|
+
uint256 reclaimCap = context.surplus.value - feeAmount;
|
|
308
|
+
if (unscaledReclaim > reclaimCap) {
|
|
309
|
+
effectiveSurplusValue = mulDiv({x: effectiveSurplusValue, y: reclaimCap, denominator: unscaledReclaim});
|
|
310
|
+
}
|
|
311
|
+
|
|
275
312
|
// Build a hook spec that routes the fee amount to this contract's `afterCashOutRecordedWith` for processing.
|
|
276
313
|
JBCashOutHookSpecification memory feeSpec = JBCashOutHookSpecification({
|
|
277
314
|
hook: IJBCashOutHook(address(this)), noop: false, amount: feeAmount, metadata: abi.encode(feeTerminal)
|