@bananapus/core-v6 0.0.64 → 0.0.65

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": "@bananapus/core-v6",
3
- "version": "0.0.64",
3
+ "version": "0.0.65",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -148,8 +148,8 @@ contract DeployPeriphery is Script, Sphinx {
148
148
  feed: feed
149
149
  }) {}
150
150
  catch {}
151
- // `addPriceFeedFor` can revert if this feed was already registered. Still require the feed to exist so a
152
- // different failure mode can't silently skip this required deployment step.
151
+ // `addPriceFeedFor` can revert if this feed was already registered. Still require this feed to be the
152
+ // authoritative default so a different existing feed can't silently satisfy this deployment step.
153
153
  require(
154
154
  address(
155
155
  core.prices
@@ -158,8 +158,8 @@ contract DeployPeriphery is Script, Sphinx {
158
158
  pricingCurrency: JBCurrencyIds.USD,
159
159
  unitCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN))
160
160
  })
161
- ) != address(0),
162
- "Missing USD/native price feed"
161
+ ) == address(feed),
162
+ "Unexpected USD/native price feed"
163
163
  );
164
164
 
165
165
  // WARN: We are using the same price feed as the native token for the USD price feed. Which is only valid on
@@ -169,14 +169,14 @@ contract DeployPeriphery is Script, Sphinx {
169
169
  projectId: 0, pricingCurrency: JBCurrencyIds.USD, unitCurrency: JBCurrencyIds.ETH, feed: feed
170
170
  }) {}
171
171
  catch {}
172
- // `addPriceFeedFor` can revert if this feed was already registered. Still require the feed to exist so a
173
- // different failure mode can't silently skip this required deployment step.
172
+ // `addPriceFeedFor` can revert if this feed was already registered. Still require this feed to be the
173
+ // authoritative default so a different existing feed can't silently satisfy this deployment step.
174
174
  require(
175
175
  address(
176
176
  core.prices
177
177
  .priceFeedFor({projectId: 0, pricingCurrency: JBCurrencyIds.USD, unitCurrency: JBCurrencyIds.ETH})
178
- ) != address(0),
179
- "Missing USD/ETH price feed"
178
+ ) == address(feed),
179
+ "Unexpected USD/ETH price feed"
180
180
  );
181
181
 
182
182
  // If the native asset for this chain is ether, then the conversion from native asset to ether is 1:1.
@@ -190,8 +190,8 @@ contract DeployPeriphery is Script, Sphinx {
190
190
  feed: matchingPriceFeed
191
191
  }) {}
192
192
  catch {}
193
- // `addPriceFeedFor` can revert if this feed was already registered. Still require the feed to exist so a
194
- // different failure mode can't silently skip this required deployment step.
193
+ // `addPriceFeedFor` can revert if this feed was already registered. Still require this feed to be the
194
+ // authoritative default so a different existing feed can't silently satisfy this deployment step.
195
195
  require(
196
196
  address(
197
197
  core.prices
@@ -200,8 +200,8 @@ contract DeployPeriphery is Script, Sphinx {
200
200
  pricingCurrency: JBCurrencyIds.ETH,
201
201
  unitCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN))
202
202
  })
203
- ) != address(0),
204
- "Missing ETH/native price feed"
203
+ ) == address(matchingPriceFeed),
204
+ "Unexpected ETH/native price feed"
205
205
  );
206
206
 
207
207
  // Deploy the USDC/USD price feed.
@@ -318,14 +318,14 @@ contract DeployPeriphery is Script, Sphinx {
318
318
  projectId: 0, pricingCurrency: JBCurrencyIds.USD, unitCurrency: usdcCurrencyId, feed: usdcFeed
319
319
  }) {}
320
320
  catch {}
321
- // `addPriceFeedFor` can revert if this feed was already registered. Still require the feed to exist so a
322
- // different failure mode can't silently skip this required deployment step.
321
+ // `addPriceFeedFor` can revert if this feed was already registered. Still require this feed to be the
322
+ // authoritative default so a different existing feed can't silently satisfy this deployment step.
323
323
  require(
324
324
  address(
325
325
  core.prices
326
326
  .priceFeedFor({projectId: 0, pricingCurrency: JBCurrencyIds.USD, unitCurrency: usdcCurrencyId})
327
- ) != address(0),
328
- "Missing USD/USDC price feed"
327
+ ) == address(usdcFeed),
328
+ "Unexpected USD/USDC price feed"
329
329
  );
330
330
  }
331
331
 
@@ -715,6 +715,9 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
715
715
  /// @param token The token to process held fees for.
716
716
  /// @param count The number of fees to process.
717
717
  function processHeldFeesOf(uint256 projectId, address token, uint256 count) external override {
718
+ // Preserve any in-flight referral context if this function is reached through reentrancy.
719
+ uint256 previousReferralProjectId = currentReferralProjectId;
720
+
718
721
  // Keep a reference to the terminal that'll receive the fees.
719
722
  IJBTerminal feeTerminal = _primaryTerminalOf({projectId: JBConstants.FEE_BENEFICIARY_PROJECT_ID, token: token});
720
723
 
@@ -749,11 +752,9 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
749
752
  _nextHeldFeeIndexOf[projectId][token] = currentIndex + 1;
750
753
  }
751
754
 
752
- // Restore the originating fee-paying call's referral project for the duration of this fee's processing
753
- // so the credit in `_processFee` attributes to the right (chain, project) pair. No save needed:
754
- // `processHeldFeesOf` is a top-level keeper call in practice — the incoming transient is 0. Defensive
755
- // cleanup happens once after the loop instead of per-iteration. Reconstructs the packed encoding from
756
- // the two struct halves: `(chainId << 48) | projectId`.
755
+ // Restore the originating fee-paying call's referral project for this fee's processing so the credit in
756
+ // `_processFee` attributes to the right (chain, project) pair. Reconstructs the packed encoding from the
757
+ // two struct halves: `(chainId << 48) | projectId`.
757
758
  currentReferralProjectId = (uint256(heldFee.referralChainId) << 48) | uint256(heldFee.referralProjectId);
758
759
 
759
760
  // Process the standard fee on the original gross amount recorded when the held fee was created.
@@ -771,10 +772,8 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
771
772
  }
772
773
  }
773
774
 
774
- // Defensive cleanup: zero the transient so any subsequent in-tx work (e.g. hook reentrancy) doesn't
775
- // inherit the last processed fee's referral. EIP-1153 would clear it at end-of-tx anyway, but in-tx
776
- // reentry is the only case where this matters.
777
- currentReferralProjectId = 0;
775
+ // Restore the previous transient value so reentrant held-fee processing does not erase an outer referral.
776
+ currentReferralProjectId = previousReferralProjectId;
778
777
 
779
778
  // If all held fees have been processed, reset the array and index entirely to bound storage growth.
780
779
  if (
@@ -339,18 +339,28 @@ contract JBTerminalStore is IJBTerminalStore {
339
339
  }
340
340
  }
341
341
 
342
- // Cache the balance slot to avoid redundant storage reads.
343
- uint256 currentBalance = balanceOf[msg.sender][projectId][tokenToReclaim];
342
+ // The selected terminal token can only pay out its own local surplus. Cash-out pricing may use shared surplus
343
+ // across terminals/tokens, but settlement must not dip into this token's payout-limit reserve.
344
+ JBAccountingContext memory accountingContext =
345
+ _accountingContextForTokenOf[msg.sender][projectId][tokenToReclaim];
346
+ uint256 localSurplus = _tokenSurplusFrom({
347
+ terminal: msg.sender,
348
+ projectId: projectId,
349
+ accountingContext: accountingContext,
350
+ ruleset: ruleset,
351
+ targetDecimals: accountingContext.decimals,
352
+ targetCurrency: accountingContext.currency
353
+ });
344
354
 
345
- // The amount being reclaimed must be within the project's balance.
346
- if (balanceDiff > currentBalance) {
347
- revert JBTerminalStore_InadequateTerminalStoreBalance({amount: balanceDiff, balance: currentBalance});
355
+ // The amount being reclaimed must be within the project's local surplus.
356
+ if (balanceDiff > localSurplus) {
357
+ revert JBTerminalStore_InadequateTerminalStoreBalance({amount: balanceDiff, balance: localSurplus});
348
358
  }
349
359
 
350
360
  // Remove the reclaimed funds from the project's balance.
351
361
  if (balanceDiff != 0) {
352
362
  unchecked {
353
- balanceOf[msg.sender][projectId][tokenToReclaim] = currentBalance - balanceDiff;
363
+ balanceOf[msg.sender][projectId][tokenToReclaim] -= balanceDiff;
354
364
  }
355
365
  }
356
366
  }
@@ -207,7 +207,10 @@ library JBPayoutSplitGroupLib {
207
207
  uint256 sentAmount, uint256 feeEligible
208
208
  ) {
209
209
  netPayoutAmount = sentAmount;
210
- amountEligibleForFees += feeEligible;
210
+ // The standard fee is `STANDARD_FEE / MAX_FEE`, currently 25 / 1000 = 1 / 40. The `40` below is
211
+ // that reduced denominator, not an independent fee parameter. Round each split's fee basis down to
212
+ // it so aggregation cannot charge more than per-split floors.
213
+ amountEligibleForFees += feeEligible - (feeEligible % 40);
211
214
  } catch (bytes memory failureReason) {
212
215
  emit PayoutReverted({
213
216
  projectId: projectId, split: split, amount: payoutAmount, reason: failureReason, caller: caller