@bananapus/core-v6 0.0.48 → 0.0.49

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/foundry.toml CHANGED
@@ -1,5 +1,6 @@
1
1
  [profile.default]
2
2
  solc = '0.8.28'
3
+ bytecode_hash = "none"
3
4
  evm_version = 'cancun'
4
5
  optimizer_runs = 200
5
6
  libs = ["node_modules", "lib"]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bananapus/core-v6",
3
- "version": "0.0.48",
3
+ "version": "0.0.49",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -88,10 +88,6 @@ library JBPayoutSplitGroupLib {
88
88
  // Native vs ERC-20 governs the transfer mechanism (push via msg.value vs allowance pull).
89
89
  bool isNative = token == JBConstants.NATIVE_TOKEN;
90
90
 
91
- // Snapshot the relevant balance before the hook call. The post-call delta tells us how much the hook
92
- // actually took, regardless of whether it pulled the full allowance, partially pulled, or reverted.
93
- uint256 balanceBefore = isNative ? address(this).balance : IERC20(token).balanceOf(address(this));
94
-
95
91
  // Build the hook context inline so the terminal call site doesn't have to. `decimals` is looked up from
96
92
  // the terminal store's recorded accounting context for this (projectId, token) pair.
97
93
  JBSplitHookContext memory context = JBSplitHookContext({
@@ -113,16 +109,33 @@ library JBPayoutSplitGroupLib {
113
109
  }
114
110
 
115
111
  // Wrap the hook call in try/catch so a reverting hook does not bubble out. On revert no tokens leave
116
- // this contract (transferFrom inside the hook is rolled back; pushed ETH is returned), so `sent` will
117
- // resolve to 0 via balance-delta below.
118
- try split.hook.processSplitWith{value: payValue}(context) {} catch {}
119
-
120
- // Revoke any unconsumed ERC-20 allowance immediately after the call so the hook can never pull later.
121
- // ETH path has no allowance to revoke.
122
- if (!isNative) SafeERC20.forceApprove({token: IERC20(token), spender: address(split.hook), value: 0});
112
+ // this contract (transferFrom inside the hook is rolled back; pushed ETH is returned). The success
113
+ // flag drives the native-ETH `sent` computation below — we cannot use a balance delta because the
114
+ // hook may reenter into this terminal (pay/cashOut/etc.) and shift our balance independently of its
115
+ // own consumption.
116
+ bool hookOk;
117
+ try split.hook.processSplitWith{value: payValue}(context) {
118
+ hookOk = true;
119
+ } catch {}
123
120
 
124
- // The hook's actual consumption is the drop in this contract's balance for the token.
125
- sent = balanceBefore - (isNative ? address(this).balance : IERC20(token).balanceOf(address(this)));
121
+ if (isNative) {
122
+ // Native ETH is pushed via `value:`. There is no on-the-fly "give some back" mechanism — a
123
+ // successful hook consumed exactly `netPayoutAmount`; a reverting hook consumed 0 (the EVM
124
+ // refunds the value on revert). Any side-effects the hook produced via reentrant terminal
125
+ // calls (pay/addToBalance/cashOut) are recorded through those calls' own bookkeeping and must
126
+ // not bleed into this split's consumption accounting.
127
+ sent = hookOk ? netPayoutAmount : 0;
128
+ } else {
129
+ // ERC-20 hooks pull via `transferFrom` against the allowance we granted. The allowance delta
130
+ // is the only consumption measure that is robust against reentrant balance manipulation: the
131
+ // hook cannot raise its own allowance, and any pull on this allowance reduces it 1:1 with
132
+ // what the hook actually received. Reentrant flows through other paths use independent
133
+ // allowances/values and so cannot inflate this measurement.
134
+ sent = netPayoutAmount - IERC20(token).allowance({owner: address(this), spender: address(split.hook)});
135
+
136
+ // Revoke any unconsumed ERC-20 allowance immediately after the call so the hook can never pull later.
137
+ SafeERC20.forceApprove({token: IERC20(token), spender: address(split.hook), value: 0});
138
+ }
126
139
 
127
140
  // If the hook took less than offered, refund the proportional gross portion to the project's balance.
128
141
  // refund = amount * (netPayoutAmount - sent) / netPayoutAmount. For full consumption this branch is