@bananapus/core-v6 0.0.80 → 0.0.81

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/README.md CHANGED
@@ -81,7 +81,6 @@ The shortest reading path is:
81
81
  - Data hooks and cash-out hooks can change economics and side effects. They are part of the protocol surface.
82
82
  - Permission checks are not always against the project owner. Some flows are scoped to the token holder instead.
83
83
  - Preview and execution are intentionally close, but callers should still treat them as separate surfaces when hooks or routing can change behavior.
84
- - Fee-bearing cash-out, payout, and allowance calls can carry a referral project ID. This credits fee volume; it does not redirect the fee itself.
85
84
 
86
85
  ## Where State Lives
87
86
 
@@ -89,7 +88,6 @@ The shortest reading path is:
89
88
  - controller and terminal routing: `JBDirectory`
90
89
  - ruleset history and activation: `JBRulesets`
91
90
  - balances, surplus, fees, and reclaim accounting: `JBTerminalStore`
92
- - referral fee-volume accounting: `JBTerminalStore`
93
91
  - operator authority: `JBPermissions`
94
92
 
95
93
  When a flow is unclear, read the contract that owns the state before the contract that forwards into it.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bananapus/core-v6",
3
- "version": "0.0.80",
3
+ "version": "0.0.81",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -61,9 +61,9 @@ The core Juicebox V6 protocol on EVM: a modular system for launching treasury-ba
61
61
  | Function | What it does |
62
62
  |----------|--------------|
63
63
  | `pay(uint256 projectId, address token, uint256 amount, address beneficiary, uint256 minReturnedTokens, string memo, bytes metadata)` | Pays a project. Mints project tokens to beneficiary based on ruleset weight. Returns token count. |
64
- | `cashOutTokensOf(address holder, uint256 projectId, uint256 cashOutCount, address tokenToReclaim, uint256 minTokensReclaimed, address payable beneficiary, bytes metadata, uint256 referralProjectId)` | Burns project tokens and reclaims surplus terminal tokens via bonding curve. Optional referral credits protocol fee volume. |
65
- | `sendPayoutsOf(uint256 projectId, address token, uint256 amount, uint256 currency, uint256 minTokensPaidOut, uint256 referralProjectId)` | Distributes payouts from the project's balance to its payout split group, up to the payout limit. Optional referral credits protocol fee volume. |
66
- | `useAllowanceOf(uint256 projectId, address token, uint256 amount, uint256 currency, uint256 minTokensPaidOut, address payable beneficiary, address payable feeBeneficiary, string memo, uint256 referralProjectId)` | Withdraws from the project's surplus allowance to a beneficiary. The `feeBeneficiary` receives tokens minted by the fee payment. Optional referral credits protocol fee volume. |
64
+ | `cashOutTokensOf(address holder, uint256 projectId, uint256 cashOutCount, address tokenToReclaim, uint256 minTokensReclaimed, address payable beneficiary, bytes metadata)` | Burns project tokens and reclaims surplus terminal tokens via bonding curve. |
65
+ | `sendPayoutsOf(uint256 projectId, address token, uint256 amount, uint256 currency, uint256 minTokensPaidOut)` | Distributes payouts from the project's balance to its payout split group, up to the payout limit. |
66
+ | `useAllowanceOf(uint256 projectId, address token, uint256 amount, uint256 currency, uint256 minTokensPaidOut, address payable beneficiary, address payable feeBeneficiary, string memo)` | Withdraws from the project's surplus allowance to a beneficiary. The `feeBeneficiary` receives tokens minted by the fee payment. |
67
67
  | `addToBalanceOf(uint256 projectId, address token, uint256 amount, bool shouldReturnHeldFees, string memo, bytes metadata)` | Adds funds to a project's balance without minting tokens. Can unlock held fees. |
68
68
  | `migrateBalanceOf(uint256 projectId, address token, IJBTerminal to)` | Migrates a project's token balance to another terminal. Requires `allowTerminalMigration`. |
69
69
  | `processHeldFeesOf(uint256 projectId, address token, uint256 count)` | Processes up to `count` held fees for a project, sending them to the fee beneficiary project. |
@@ -74,7 +74,6 @@ The core Juicebox V6 protocol on EVM: a modular system for launching treasury-ba
74
74
  | `previewPayFor(uint256 projectId, address token, uint256 amount, address beneficiary, bytes metadata)` | Simulates a full payment including the reserved/beneficiary token split. Returns `(ruleset, beneficiaryTokenCount, reservedTokenCount, hookSpecifications)`. Composes `STORE.previewPayFrom` + `controller.previewMintOf`. |
75
75
  | `previewCashOutFrom(address holder, uint256 projectId, uint256 cashOutCount, address tokenToReclaim, address payable beneficiary, bytes metadata)` | Simulates a full cash out including bonding curve and data hook effects. Cash-out data hooks may alter pricing inputs, but not the caller-supplied burn count. Returns `(ruleset, reclaimAmount, cashOutTaxRate, hookSpecifications)`. Delegates to `STORE.previewCashOutFrom`. |
76
76
  | `heldFeesOf(uint256 projectId, address token, uint256 count)` | Returns up to `count` held fees for a project/token. |
77
- | `currentReferralProjectId()` | Returns the in-flight packed referral `(chainId << 48) | projectId`, or 0 outside a fee-bearing call. |
78
77
 
79
78
  ### JBTerminalStore
80
79
 
@@ -94,11 +93,8 @@ The core Juicebox V6 protocol on EVM: a modular system for launching treasury-ba
94
93
  | `currentTotalReclaimableSurplusOf(uint256 projectId, uint256 cashOutCount, uint256 decimals, uint256 currency)` | Convenience view: reclaimable surplus across all terminals and all tokens. |
95
94
  | `currentSurplusOf(uint256 projectId, IJBTerminal[] terminals, address[] tokens, uint256 decimals, uint256 currency)` | Returns the current surplus across specified terminals and tokens. Empty arrays default to all. |
96
95
  | `currentTotalSurplusOf(uint256 projectId, uint256 decimals, uint256 currency)` | Convenience view: total surplus across all terminals and all tokens. |
97
- | `feeVolumeByReferralOf(address terminal, uint256 referralChainId, uint256 referralProjectId)` | Returns cumulative protocol fee volume credited to a referrer through a terminal. |
98
96
  | `previewPayFrom(address terminal, address payer, JBTokenAmount amount, uint256 projectId, address beneficiary, bytes metadata)` | Simulates a payment without modifying state. Uses the explicit `terminal` parameter for balance/surplus lookups. Invokes data hooks if configured. Returns ruleset, token count, and hook specifications. |
99
97
  | `previewCashOutFrom(address terminal, address holder, uint256 projectId, uint256 cashOutCount, address tokenToReclaim, bool beneficiaryIsFeeless, bytes metadata)` | Simulates a cash out without modifying state. Uses the explicit `terminal` parameter for balance/surplus lookups. Invokes data hooks if configured, including any pricing-only adjustments they return. Returns ruleset, reclaim amount, tax rate, and hook specifications. |
100
- | `recordFeeReferralCreditOf(uint256 referralProjectId, JBTokenAmount amount)` | Credits normalized fee volume to a packed referral project for the calling terminal. No-ops for zero referral, zero amount, or missing price feed. |
101
- | `totalFeeVolumeOf(address terminal)` | Returns total referral-creditable fee volume recorded for a terminal. |
102
98
 
103
99
  ### JBRulesets
104
100
 
@@ -17,7 +17,7 @@ Use this file when you need deeper protocol reference material after the repo-lo
17
17
  | `JBCurrencyAmount` | `amount (uint224)`, `currency (uint32)` | Payout limits and surplus allowances |
18
18
  | `JBFundAccessLimitGroup` | `terminal (address)`, `token (address)`, `payoutLimits (JBCurrencyAmount[])`, `surplusAllowances (JBCurrencyAmount[])` | `JBRulesetConfig.fundAccessLimitGroups` |
19
19
  | `JBPermissionsData` | `operator (address)`, `projectId (uint64)`, `permissionIds (uint8[])` | `setPermissionsFor()` input |
20
- | `JBFee` | `amount (uint224)`, `referralChainId (uint32)`, `beneficiary (address)`, `unlockTimestamp (uint48)`, `referralProjectId (uint48)` | Held fees in `JBMultiTerminal`; referral fields preserve fee attribution until processing |
20
+ | `JBFee` | `amount (uint224)`, `beneficiary (address)`, `unlockTimestamp (uint48)` | Held fees in `JBMultiTerminal` |
21
21
  | `JBSingleAllowance` | `sigDeadline (uint256)`, `amount (uint160)`, `expiration (uint48)`, `nonce (uint48)`, `signature (bytes)` | Permit2 allowance in terminal payments |
22
22
  | `JBRulesetWithMetadata` | `ruleset (JBRuleset)`, `metadata (JBRulesetMetadata)` | `allRulesetsOf()`, `currentRulesetOf()` return values |
23
23
  | `JBRulesetWeightCache` | `weight (uint112)`, `weightCutMultiple (uint168)` | Weight caching for long-running rulesets in `JBRulesets` |
@@ -93,8 +93,7 @@ Use this file when you need deeper protocol reference material after the repo-lo
93
93
  - `JBProjects` constructor optionally mints project #1 to `feeProjectOwner` -- if `address(0)`, no fee project is created
94
94
  - `JBMultiTerminal` derives `DIRECTORY` from the provided `store` in its constructor -- not passed directly
95
95
  - `JBPrices.pricePerUnitOf()` checks project direct feeds, project inverse feeds, default direct feeds, then default inverse feeds. It skips feeds that revert or return zero.
96
- - `useAllowanceOf()` takes 9 args including `address payable feeBeneficiary` and `uint256 referralProjectId` -- do NOT omit them
97
- - `sendPayoutsOf()` and `cashOutTokensOf()` also take `uint256 referralProjectId`; pass `0` for no referral credit
96
+ - `useAllowanceOf()` takes 8 args including `address payable feeBeneficiary` -- do NOT omit it
98
97
  - `JBFeelessAddresses.isFeelessFor()` takes 3 args: `(addr, projectId, caller)`. The optional hook can use `caller` to scope dynamic grants.
99
98
  - Cash out tax rate of 0% = proportional (1:1) redemption; 100% = nothing reclaimable (all surplus locked). Do NOT confuse with a "cash out rate" where 100% means full redemption.
100
99
  - `cashOutTaxRate` in `JBRulesetMetadata` is `uint16` (max 10,000 basis points), NOT 9-decimal precision
@@ -214,7 +213,6 @@ The most important events for indexing and off-chain monitoring. Indexed params
214
213
  | `ProcessFee` | `IJBFeeTerminal` | `projectId*`, `token*`, `amount*`, `wasHeld`, `beneficiary` |
215
214
  | `ReturnHeldFees` | `IJBFeeTerminal` | `projectId*`, `token*`, `amount*`, `returnedFees`, `leftoverAmount` |
216
215
  | `FeeReverted` | `IJBFeeTerminal` | `projectId*`, `token*`, `feeProjectId*`, `amount`, `reason` |
217
- | `ReferralCredit` | `IJBTerminalStore` | `terminal*`, `referralChainId*`, `referralProjectId*`, `amount`, `newTotal` |
218
216
  | `Create` | `IJBProjects` | `projectId*`, `owner*` |
219
217
  | `SetTokenMetadata` | `IJBTokens` | `projectId*`, `name`, `symbol` |
220
218
  | `OperatorPermissionsSet` | `IJBPermissions` | (operator, account, projectId, permissionIds, packed, caller) |
@@ -146,25 +146,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
146
146
  /// @custom:param token The token the fees are held in.
147
147
  mapping(uint256 projectId => mapping(address token => uint256)) internal _nextHeldFeeIndexOf;
148
148
 
149
- //*********************************************************************//
150
- // --------------- public transient stored properties --------------- //
151
- //*********************************************************************//
152
-
153
- /// @notice Caller-originated referrer reference for the duration of the current external fee-paying call.
154
- /// @dev Encoded as `(referralChainId << 48) | referralProjectId`: bits [79:48] are the referrer's EIP-155 chain
155
- /// ID (uint32), bits [47:0] are the referrer's project ID on that chain (uint48). The upper bits of the
156
- /// uint256 are reserved for future encoding extensions.
157
- /// @dev The entry points `cashOutTokensOf`, `sendPayoutsOf`, and `useAllowanceOf` auto-resolve a bare project ID
158
- /// (non-zero project, zero chain bits) to the current execution chain via `block.chainid` before writing this
159
- /// slot. So storage (and indexers reading `feeVolumeByReferralOf`) always observe a fully-resolved
160
- /// `(chainId, projectId)` pair — callers can write `referralProjectId: someProjectId` without manually packing
161
- /// their own chain ID.
162
- /// @dev Set by the three entry points via the `_setReferralProjectId` save-restore wrapper. Read inside `_pay`
163
- /// to credit `feeVolumeByReferralOf` when the fee project's pay call is recorded locally.
164
- /// @dev Public so pay, cash out, and split hooks can introspect which referral originated the in-flight call (e.g.
165
- /// to apply referral-specific logic). Reads `0` outside any fee-paying call.
166
- uint256 public transient override currentReferralProjectId;
167
-
168
149
  //*********************************************************************//
169
150
  // -------------- internal transient stored properties -------------- //
170
151
  //*********************************************************************//
@@ -177,9 +158,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
177
158
  /// the fee basis to `executePayout`.
178
159
  uint256 internal transient _internalSplitPayProjectId;
179
160
 
180
- /// @notice The in-flight fee amount that can credit `currentReferralProjectId`.
181
- uint256 internal transient _feeReferralCreditAmount;
182
-
183
161
  //*********************************************************************//
184
162
  // -------------------------- constructor ---------------------------- //
185
163
  //*********************************************************************//
@@ -303,10 +281,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
303
281
  /// data hook and cash out hooks if applicable.
304
282
  /// @param metadata Bytes to send along to the emitted event, as well as the data hook and cash out hooks if
305
283
  /// applicable.
306
- /// @param referralProjectId Optional referrer reference to credit with the protocol fee volume taken by this
307
- /// call, encoded as `(referralChainId << 48) | referralProjectId` (chain ID in the upper 32 bits, project ID
308
- /// in the lower 48). A bare project ID (chain bits zero) is auto-resolved to the current chain via `block.chainid`.
309
- /// Pass `0` for no referral credit.
310
284
  /// @return reclaimAmount The amount of **terminal tokens** sent to `beneficiary` in exchange for the burned project
311
285
  /// tokens, as a fixed point number with the same number of decimals as the terminal token's accounting context.
312
286
  function cashOutTokensOf(
@@ -316,8 +290,7 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
316
290
  address tokenToReclaim,
317
291
  uint256 minTokensReclaimed,
318
292
  address payable beneficiary,
319
- bytes calldata metadata,
320
- uint256 referralProjectId
293
+ bytes calldata metadata
321
294
  )
322
295
  external
323
296
  override
@@ -326,9 +299,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
326
299
  // Enforce permissions.
327
300
  _requirePermissionFrom({account: holder, projectId: projectId, permissionId: JBPermissionIds.CASH_OUT_TOKENS});
328
301
 
329
- // Save-restore the transient referral slot so nested reentrant fee-paying calls don't pollute each other.
330
- uint256 priorReferral = _setReferralProjectId(referralProjectId);
331
-
332
302
  reclaimAmount = _cashOutTokensOf({
333
303
  holder: holder,
334
304
  projectId: projectId,
@@ -338,8 +308,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
338
308
  metadata: metadata
339
309
  });
340
310
 
341
- _setReferralProjectId(priorReferral);
342
-
343
311
  // The amount being reclaimed must be at least as much as was expected.
344
312
  _checkMin({value: reclaimAmount, min: minTokensReclaimed});
345
313
  }
@@ -441,7 +409,7 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
441
409
  revert JBMultiTerminal_MintNotAllowed({projectId: projectId, terminal: address(terminal)});
442
410
  }
443
411
 
444
- // Send the `projectId` in the metadata as a referral.
412
+ // Send the source `projectId` in the metadata for same-terminal split-pay accounting.
445
413
  bytes memory metadata = bytes(abi.encodePacked(projectId));
446
414
 
447
415
  // Add to balance if preferred.
@@ -724,9 +692,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
724
692
  /// @param token The token to process held fees for.
725
693
  /// @param count The number of fees to process.
726
694
  function processHeldFeesOf(uint256 projectId, address token, uint256 count) external override {
727
- // Preserve any in-flight referral context if this function is reached through reentrancy.
728
- uint256 previousReferralProjectId = currentReferralProjectId;
729
-
730
695
  // Keep a reference to the terminal that'll receive the fees.
731
696
  IJBTerminal feeTerminal = _primaryTerminalOf({projectId: JBConstants.FEE_BENEFICIARY_PROJECT_ID, token: token});
732
697
 
@@ -761,11 +726,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
761
726
  _nextHeldFeeIndexOf[projectId][token] = currentIndex + 1;
762
727
  }
763
728
 
764
- // Restore the originating fee-paying call's referral project for this fee's processing so the credit in
765
- // `_processFee` attributes to the right (chain, project) pair. Reconstructs the packed encoding from the
766
- // two struct halves: `(chainId << 48) | projectId`.
767
- currentReferralProjectId = (uint256(heldFee.referralChainId) << 48) | uint256(heldFee.referralProjectId);
768
-
769
729
  // Process the standard fee on the original gross amount recorded when the held fee was created.
770
730
  _processFee({
771
731
  projectId: projectId,
@@ -781,9 +741,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
781
741
  }
782
742
  }
783
743
 
784
- // Restore the previous transient value so reentrant held-fee processing does not erase an outer referral.
785
- currentReferralProjectId = previousReferralProjectId;
786
-
787
744
  // If all held fees have been processed, reset the array and index entirely to bound storage growth.
788
745
  if (
789
746
  _nextHeldFeeIndexOf[projectId][token] >= _heldFeesOf[projectId][token].length
@@ -810,29 +767,20 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
810
767
  /// in terms of the token's accounting context currency), as a fixed point number with the same number of decimals
811
768
  /// as the token's accounting context. If the amount of tokens paid out would be less than this amount, the send is
812
769
  /// reverted.
813
- /// @param referralProjectId Optional referrer reference to credit with the protocol fee volume taken by this
814
- /// call, encoded as `(referralChainId << 48) | referralProjectId` (chain ID in the upper 32 bits, project ID
815
- /// in the lower 48). A bare project ID (chain bits zero) is auto-resolved to the current chain via `block.chainid`.
816
- /// Pass `0` for no referral credit.
817
770
  /// @return amountPaidOut The total amount paid out.
818
771
  function sendPayoutsOf(
819
772
  uint256 projectId,
820
773
  address token,
821
774
  uint256 amount,
822
775
  uint256 currency,
823
- uint256 minTokensPaidOut,
824
- uint256 referralProjectId
776
+ uint256 minTokensPaidOut
825
777
  )
826
778
  external
827
779
  override
828
780
  returns (uint256 amountPaidOut)
829
781
  {
830
- uint256 priorReferral = _setReferralProjectId(referralProjectId);
831
-
832
782
  amountPaidOut = _sendPayoutsOf({projectId: projectId, token: token, amount: amount, currency: currency});
833
783
 
834
- _setReferralProjectId(priorReferral);
835
-
836
784
  // The amount being paid out must be at least as much as was expected.
837
785
  _checkMin({value: amountPaidOut, min: minTokensPaidOut});
838
786
  }
@@ -855,10 +803,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
855
803
  /// @param feeBeneficiary The address that receives the **project tokens** minted by the fee project in exchange
856
804
  /// for the protocol fee paid in terminal tokens.
857
805
  /// @param memo A memo to pass along to the emitted event.
858
- /// @param referralProjectId Optional referrer reference to credit with the protocol fee volume taken by this
859
- /// call, encoded as `(referralChainId << 48) | referralProjectId` (chain ID in the upper 32 bits, project ID
860
- /// in the lower 48). A bare project ID (chain bits zero) is auto-resolved to the current chain via `block.chainid`.
861
- /// Pass `0` for no referral credit.
862
806
  /// @return netAmountPaidOut The number of **terminal tokens** sent to `beneficiary`, net of the protocol fee, as a
863
807
  /// fixed point number with the same number of decimals as the terminal token's accounting context.
864
808
  function useAllowanceOf(
@@ -869,8 +813,7 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
869
813
  uint256 minTokensPaidOut,
870
814
  address payable beneficiary,
871
815
  address payable feeBeneficiary,
872
- string calldata memo,
873
- uint256 referralProjectId
816
+ string calldata memo
874
817
  )
875
818
  external
876
819
  override
@@ -882,8 +825,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
882
825
  // Enforce permissions.
883
826
  _requirePermissionFrom({account: owner, projectId: projectId, permissionId: JBPermissionIds.USE_ALLOWANCE});
884
827
 
885
- uint256 priorReferral = _setReferralProjectId(referralProjectId);
886
-
887
828
  netAmountPaidOut = _useAllowanceOf({
888
829
  projectId: projectId,
889
830
  owner: owner,
@@ -895,8 +836,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
895
836
  memo: memo
896
837
  });
897
838
 
898
- _setReferralProjectId(priorReferral);
899
-
900
839
  // The amount being withdrawn must be at least as much as was expected.
901
840
  _checkMin({value: netAmountPaidOut, min: minTokensPaidOut});
902
841
  }
@@ -1766,17 +1705,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
1766
1705
  // Keep a reference to the token amount to forward to the store.
1767
1706
  JBTokenAmount memory tokenAmount = _tokenAmountOf({projectId: projectId, token: token, value: amount});
1768
1707
 
1769
- // Credit only the one pay call currently being made by `_processFee`. Ordinary split pays to project #1 can
1770
- // happen while `currentReferralProjectId` is set, but they are not protocol-fee payments. Consume this before
1771
- // recording the payment so fee-project data hooks cannot reenter and use the in-flight credit.
1772
- if (
1773
- projectId == JBConstants.FEE_BENEFICIARY_PROJECT_ID && currentReferralProjectId != 0
1774
- && _feeReferralCreditAmount != 0
1775
- ) {
1776
- delete _feeReferralCreditAmount;
1777
- STORE.recordFeeReferralCreditOf({referralProjectId: currentReferralProjectId, amount: tokenAmount});
1778
- }
1779
-
1780
1708
  // Record the payment.
1781
1709
  // Keep a reference to the ruleset the payment is being made during.
1782
1710
  // Keep a reference to the pay hook specifications.
@@ -1866,11 +1794,9 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
1866
1794
  )
1867
1795
  internal
1868
1796
  {
1869
- if (feeTerminal == IJBTerminal(address(this))) _feeReferralCreditAmount = amount;
1870
1797
  try this.executeProcessFee({
1871
1798
  projectId: projectId, token: token, amount: amount, beneficiary: beneficiary, feeTerminal: feeTerminal
1872
1799
  }) {
1873
- delete _feeReferralCreditAmount;
1874
1800
  emit ProcessFee({
1875
1801
  projectId: projectId,
1876
1802
  token: token,
@@ -1880,7 +1806,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
1880
1806
  caller: _msgSender()
1881
1807
  });
1882
1808
  } catch (bytes memory reason) {
1883
- delete _feeReferralCreditAmount;
1884
1809
  // Fee processing is fail-open for project liveness: a broken project #1 terminal or fee route must not
1885
1810
  // trap payouts, cash outs, allowances, held-fee processing, or terminal migration. The fee is forgiven,
1886
1811
  // credited back to the originating project on this terminal, and surfaced through `FeeReverted`.
@@ -2074,22 +1999,13 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
2074
1999
  _checkFitsIn({value: amount, max: type(uint224).max});
2075
2000
 
2076
2001
  // Store the gross amount so future repayments can recover the corresponding fee.
2077
- // Capture the in-flight `currentReferralProjectId` so attribution survives the 28-day hold window —
2078
- // by the time `processHeldFeesOf` runs, the transient slot has been cleared. The encoded
2079
- // `(chainId << 48) | projectId` pair in the transient slot is decomposed into its two halves so the
2080
- // struct stays in 2 storage slots.
2081
- uint256 encodedReferral = currentReferralProjectId;
2082
2002
  _heldFeesOf[projectId][token].push(
2083
2003
  JBFee({
2084
2004
  // forge-lint: disable-next-line(unsafe-typecast)
2085
2005
  amount: uint224(amount),
2086
- // forge-lint: disable-next-line(unsafe-typecast)
2087
- referralChainId: uint32(encodedReferral >> 48),
2088
2006
  beneficiary: beneficiary,
2089
2007
  // forge-lint: disable-next-line(unsafe-typecast)
2090
- unlockTimestamp: uint48(block.timestamp + _FEE_HOLDING_SECONDS),
2091
- // forge-lint: disable-next-line(unsafe-typecast)
2092
- referralProjectId: uint48(encodedReferral)
2008
+ unlockTimestamp: uint48(block.timestamp + _FEE_HOLDING_SECONDS)
2093
2009
  })
2094
2010
  );
2095
2011
 
@@ -2360,22 +2276,4 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
2360
2276
  function _feeAmountFrom(uint256 amount) private pure returns (uint256) {
2361
2277
  return JBFees.standardFeeAmountFrom(amount);
2362
2278
  }
2363
-
2364
- /// @notice Set the transient `currentReferralProjectId` slot and return the prior value (for save-restore).
2365
- /// @dev Returning the prior value lets the caller restore it after the inner call completes, which is required
2366
- /// to keep nested reentrant fee-paying calls from polluting each other. Per EIP-1153, a revert in the inner
2367
- /// call also reverts the transient write, so no explicit cleanup on the failure path is needed.
2368
- /// @dev Backfills `block.chainid` into the chain-bits half of the encoding when the caller passed a bare
2369
- /// project ID (non-zero project, zero chain). This lets callers write `referralProjectId: someProjectId`
2370
- /// without manually packing their own chain ID — the entry point resolves it to the current execution chain,
2371
- /// so storage and indexers always see a fully-resolved `(chainId, projectId)` pair.
2372
- /// @param referralProjectId The new value to write into the transient slot.
2373
- /// @return prior The value previously stored in the slot.
2374
- function _setReferralProjectId(uint256 referralProjectId) private returns (uint256 prior) {
2375
- if (referralProjectId != 0 && referralProjectId >> 48 == 0) {
2376
- referralProjectId |= block.chainid << 48;
2377
- }
2378
- prior = currentReferralProjectId;
2379
- currentReferralProjectId = referralProjectId;
2380
- }
2381
2279
  }
@@ -92,26 +92,6 @@ contract JBTerminalStore is IJBTerminalStore {
92
92
  public
93
93
  override balanceOf;
94
94
 
95
- /// @notice Cumulative fee payment amount credited to a referrer (chainId, projectId) pair as a result of
96
- /// fee-paying calls that originated through a given terminal.
97
- /// @dev Written by terminals via `recordFeeReferralCreditOf`; the writing terminal is `msg.sender`, so a caller
98
- /// can only pollute their own bucket.
99
- /// @dev Nested by chain ID then project ID so off-chain consumers can read the credit for a specific
100
- /// `(chainId, projectId)` directly without re-packing the encoded form themselves.
101
- /// @custom:param terminal The terminal that originated the fee-paying call.
102
- /// @custom:param referralChainId The EIP-155 chain ID of the referrer's home chain.
103
- /// @custom:param referralProjectId The referrer's bare project ID on `referralChainId`.
104
- mapping(address terminal => mapping(uint256 referralChainId => mapping(uint256 referralProjectId => uint256)))
105
- public
106
- override feeVolumeByReferralOf;
107
-
108
- /// @notice Cumulative fee payment amount credited across all referral projects for a given terminal.
109
- /// @dev Updated in lockstep with `feeVolumeByReferralOf` so consumers can compute a referrer's pro-rata share
110
- /// in a single SLOAD pair without enumerating referrers. Used as the denominator by split hooks that distribute
111
- /// rewards proportional to attributed fee volume.
112
- /// @custom:param terminal The terminal that originated the fee-paying calls.
113
- mapping(address terminal => uint256) public override totalFeeVolumeOf;
114
-
115
95
  /// @notice The currency-denominated amount of funds that a project has already paid out from its payout limit
116
96
  /// during the current ruleset for each terminal, in terms of the payout limit's currency.
117
97
  /// @dev Increases as projects pay out funds.
@@ -365,22 +345,6 @@ contract JBTerminalStore is IJBTerminalStore {
365
345
  }
366
346
  }
367
347
 
368
- /// @notice Credit a referral project with a fee payment amount routed through `msg.sender` (the calling terminal).
369
- /// @dev Called by `JBMultiTerminal._pay` after a payment lands on the fee project. Permissionless: writes are
370
- /// scoped to `msg.sender`'s slots so an arbitrary caller can only pollute their own buckets — off-chain
371
- /// consumers should filter on known terminal addresses. The amount is normalized to `NATIVE_TOKEN` units
372
- /// (18 decimals) here in the store (where `PRICES` is available) so all credits share a common denominator.
373
- /// @param referralProjectId The referral project to credit.
374
- /// @param amount The fee amount paid by the originating fee-take call (raw value, decimals, currency).
375
- function recordFeeReferralCreditOf(uint256 referralProjectId, JBTokenAmount calldata amount) external override {
376
- _creditFeeReferral({
377
- referralProjectId: referralProjectId,
378
- amount: _normalizeToNativeTokenUnits({
379
- value: amount.value, decimals: amount.decimals, currency: amount.currency
380
- })
381
- });
382
- }
383
-
384
348
  /// @notice Records a payment — calculates how many project tokens to mint based on the payment amount and the
385
349
  /// current ruleset's weight. Uses the data hook if configured, otherwise mints proportionally.
386
350
  /// @dev Called by the terminal after accepting funds. Updates the project's recorded balance.
@@ -1442,80 +1406,4 @@ contract JBTerminalStore is IJBTerminalStore {
1442
1406
  }
1443
1407
  }
1444
1408
  }
1445
-
1446
- //*********************************************************************//
1447
- // -------------------------- private helpers ------------------------ //
1448
- //*********************************************************************//
1449
-
1450
- /// @notice Credit a referrer with a fee payment amount. Internal counterpart of `recordFeeReferralCreditOf` —
1451
- /// both write to the same slots and emit the same event.
1452
- /// @dev No-op when `referralProjectId == 0` or `amount == 0`.
1453
- /// @dev Unpacks the encoded `(chainId << 48) | projectId` form into the nested mapping at write-time so the
1454
- /// public getter exposes `(terminal, chainId, projectId) → cumulative` directly. The event topics carry the
1455
- /// two halves separately as well.
1456
- /// @param referralProjectId The packed `(chainId << 48) | projectId` referrer reference to credit.
1457
- /// @param amount The fee amount to credit.
1458
- function _creditFeeReferral(uint256 referralProjectId, uint256 amount) private {
1459
- if (referralProjectId == 0 || amount == 0) return;
1460
-
1461
- uint256 referralChainId = referralProjectId >> 48;
1462
- uint256 bareProjectId = referralProjectId & ((1 << 48) - 1);
1463
-
1464
- feeVolumeByReferralOf[msg.sender][referralChainId][bareProjectId] += amount;
1465
- uint256 newTotal = totalFeeVolumeOf[msg.sender] + amount;
1466
- totalFeeVolumeOf[msg.sender] = newTotal;
1467
-
1468
- emit ReferralCredit({
1469
- terminal: msg.sender,
1470
- referralChainId: referralChainId,
1471
- referralProjectId: bareProjectId,
1472
- amount: amount,
1473
- newTotal: newTotal,
1474
- caller: msg.sender
1475
- });
1476
- }
1477
-
1478
- /// @notice Normalize a fee-token amount to `JBConstants.NATIVE_TOKEN` units at 18 decimals.
1479
- /// @dev Two-step: first adjust decimals to 18 via `JBFixedPointNumber.adjustDecimals`, then convert currency
1480
- /// via `PRICES.pricePerUnitOf` using the fee project's price feeds. If no price feed exists for the pair, the
1481
- /// `try` block catches the revert and the credit is silently skipped — the payment itself still succeeds.
1482
- /// @param value The amount in the source token's native decimals.
1483
- /// @param decimals The source token's decimals.
1484
- /// @param currency The source token's accounting-context currency (`uint32(uint160(token))`).
1485
- /// @return normalized The amount expressed in `NATIVE_TOKEN` units (18 decimals), or 0 if conversion failed.
1486
- function _normalizeToNativeTokenUnits(
1487
- uint256 value,
1488
- uint256 decimals,
1489
- uint256 currency
1490
- )
1491
- private
1492
- view
1493
- returns (uint256 normalized)
1494
- {
1495
- // Adjust the source amount up/down to 18 decimals so all credits share a common precision.
1496
- normalized = decimals == _MAX_FIXED_POINT_FIDELITY
1497
- ? value
1498
- : JBFixedPointNumber.adjustDecimals({
1499
- value: value, decimals: decimals, targetDecimals: _MAX_FIXED_POINT_FIDELITY
1500
- });
1501
-
1502
- if (normalized == 0 || currency == JBConstants.NATIVE_TOKEN_CURRENCY) return normalized;
1503
-
1504
- // Convert from the source currency to NATIVE_TOKEN via the fee project's price feeds. A missing feed
1505
- // reverts inside `PRICES.pricePerUnitOf` — caught here so the payment is not blocked.
1506
- try PRICES.pricePerUnitOf({
1507
- projectId: JBConstants.FEE_BENEFICIARY_PROJECT_ID,
1508
- pricingCurrency: currency,
1509
- unitCurrency: JBConstants.NATIVE_TOKEN_CURRENCY,
1510
- decimals: _MAX_FIXED_POINT_FIDELITY
1511
- }) returns (
1512
- uint256 price
1513
- ) {
1514
- normalized = price == 0
1515
- ? 0
1516
- : mulDiv({x: normalized, y: 10 ** _MAX_FIXED_POINT_FIDELITY, denominator: price});
1517
- } catch {
1518
- normalized = 0;
1519
- }
1520
- }
1521
1409
  }
@@ -84,8 +84,6 @@ interface IJBCashOutTerminal is IJBTerminal {
84
84
  /// @param minTokensReclaimed The minimum number of terminal tokens that must be reclaimed.
85
85
  /// @param beneficiary The address to send the reclaimed terminal tokens to.
86
86
  /// @param metadata Extra data to send to the data hook and cash out hooks.
87
- /// @param referralProjectId Optional project to credit with the protocol fee volume taken by this call. Pass `0`
88
- /// for no referral credit.
89
87
  /// @return reclaimAmount The number of terminal tokens reclaimed from the project's surplus.
90
88
  function cashOutTokensOf(
91
89
  address holder,
@@ -94,8 +92,7 @@ interface IJBCashOutTerminal is IJBTerminal {
94
92
  address tokenToReclaim,
95
93
  uint256 minTokensReclaimed,
96
94
  address payable beneficiary,
97
- bytes calldata metadata,
98
- uint256 referralProjectId
95
+ bytes calldata metadata
99
96
  )
100
97
  external
101
98
  returns (uint256 reclaimAmount);
@@ -31,19 +31,6 @@ interface IJBMultiTerminal is IJBTerminal, IJBFeeTerminal, IJBCashOutTerminal, I
31
31
  /// @notice The contract that manages token minting and burning.
32
32
  function TOKENS() external view returns (IJBTokens);
33
33
 
34
- /// @notice The caller-originated referrer reference for the in-flight fee-paying external call.
35
- /// @dev Encoded as `(referralChainId << 48) | referralProjectId`: bits [79:48] are the referrer's EIP-155 chain
36
- /// ID (uint32), bits [47:0] are the referrer's project ID on that chain (uint48). Allows a referrer with a
37
- /// project on chain X to be credited for activity on chain Y. A bare project ID (chain bits zero) is auto-
38
- /// resolved to the current execution chain via `block.chainid` at the entry point, so storage and indexers
39
- /// always see a fully-resolved `(chainId, projectId)` pair.
40
- /// @dev Backed by transient storage. Set by `cashOutTokensOf`, `sendPayoutsOf`, and `useAllowanceOf` (save-
41
- /// restore wrapper) so hooks invoked during that call (pay hooks, cash out hooks, split hooks) can introspect
42
- /// which referrer originated the activity. Reads `0` outside any fee-paying call.
43
- /// @dev Per-referrer cumulative fee payment amounts credited via this terminal are stored in
44
- /// `JBTerminalStore.feeVolumeByReferralOf(address terminal, uint256 referralChainId, uint256 referralProjectId)`.
45
- function currentReferralProjectId() external view returns (uint256);
46
-
47
34
  /// @notice The cumulative amount of fee-free intra-terminal payouts a project has received for a given token.
48
35
  /// @dev Incremented each time a fee-free payout lands (same terminal, no fee charged) and consumed during
49
36
  /// zero-tax cash outs to prevent a round-trip fee bypass (intra-terminal payout -> zero-tax cash out). Exposed
@@ -102,16 +102,13 @@ interface IJBPayoutTerminal is IJBTerminal {
102
102
  /// @param amount The total amount of tokens to pay out.
103
103
  /// @param currency The currency the amount is denominated in.
104
104
  /// @param minTokensPaidOut The minimum number of terminal tokens expected to be paid out.
105
- /// @param referralProjectId Optional project to credit with the protocol fee volume taken by this call. Pass `0`
106
- /// for no referral credit.
107
105
  /// @return amountPaidOut The total amount paid out.
108
106
  function sendPayoutsOf(
109
107
  uint256 projectId,
110
108
  address token,
111
109
  uint256 amount,
112
110
  uint256 currency,
113
- uint256 minTokensPaidOut,
114
- uint256 referralProjectId
111
+ uint256 minTokensPaidOut
115
112
  )
116
113
  external
117
114
  returns (uint256 amountPaidOut);
@@ -125,8 +122,6 @@ interface IJBPayoutTerminal is IJBTerminal {
125
122
  /// @param beneficiary The address to send the funds to.
126
123
  /// @param feeBeneficiary The address that will receive any project tokens minted from fees.
127
124
  /// @param memo A memo to pass along to the emitted event.
128
- /// @param referralProjectId Optional project to credit with the protocol fee volume taken by this call. Pass `0`
129
- /// for no referral credit.
130
125
  /// @return netAmountPaidOut The net amount paid out to the beneficiary after fees.
131
126
  function useAllowanceOf(
132
127
  uint256 projectId,
@@ -136,8 +131,7 @@ interface IJBPayoutTerminal is IJBTerminal {
136
131
  uint256 minTokensPaidOut,
137
132
  address payable beneficiary,
138
133
  address payable feeBeneficiary,
139
- string calldata memo,
140
- uint256 referralProjectId
134
+ string calldata memo
141
135
  )
142
136
  external
143
137
  returns (uint256 netAmountPaidOut);
@@ -15,25 +15,6 @@ import {JBTokenAmount} from "../structs/JBTokenAmount.sol";
15
15
  /// allowances, calculates token issuance per payment, and determines cash-out reclaim amounts via the bonding curve.
16
16
  /// Terminals delegate all state-changing accounting to this contract.
17
17
  interface IJBTerminalStore {
18
- /// @notice Emitted when a referrer is credited with a fee payment amount.
19
- /// @dev `referralChainId` and `referralProjectId` are emitted as separate indexed topics so off-chain consumers
20
- /// can filter directly on either dimension. The public `feeVolumeByReferralOf` getter exposes the same unpacked
21
- /// `(terminal, referralChainId, referralProjectId)` tuple.
22
- /// @param terminal The terminal that originated the fee-paying call (`msg.sender` on `recordFeeReferralCreditOf`).
23
- /// @param referralChainId The EIP-155 chain ID of the referrer's home chain.
24
- /// @param referralProjectId The referrer's bare project ID on `referralChainId` (no chain bits).
25
- /// @param amount The fee amount credited, in the terminal's accounting-context units.
26
- /// @param newTotal The new value of `totalFeeVolumeOf[terminal]` after this credit.
27
- /// @param caller The address that recorded the credit.
28
- event ReferralCredit(
29
- address indexed terminal,
30
- uint256 indexed referralChainId,
31
- uint256 indexed referralProjectId,
32
- uint256 amount,
33
- uint256 newTotal,
34
- address caller
35
- );
36
-
37
18
  /// @notice The directory of terminals and controllers for projects.
38
19
  function DIRECTORY() external view returns (IJBDirectory);
39
20
 
@@ -161,27 +142,6 @@ interface IJBTerminalStore {
161
142
  view
162
143
  returns (uint256);
163
144
 
164
- /// @notice The cumulative fee payment amount credited to a referrer (chainId, projectId) pair as a result of
165
- /// fee-paying calls that originated through a given terminal.
166
- /// @dev Written by terminals via `recordFeeReferralCreditOf` — `msg.sender` is recorded as the writing terminal,
167
- /// so a malicious caller can only pollute their own slot. Off-chain consumers should filter on known terminal
168
- /// addresses.
169
- /// @dev Nested by chain ID then project ID so consumers can read the credit for a specific
170
- /// `(chainId, projectId)` directly without re-packing the encoded form. The encoded `(chainId << 48) | projectId`
171
- /// form is used only inside the transient slot and the entry-point parameter; storage exposes the unpacked pair.
172
- /// @param terminal The terminal that originated the fee-paying call.
173
- /// @param referralChainId The EIP-155 chain ID of the referrer's home chain.
174
- /// @param referralProjectId The referrer's bare project ID on `referralChainId`.
175
- /// @return The cumulative fee amount credited.
176
- function feeVolumeByReferralOf(
177
- address terminal,
178
- uint256 referralChainId,
179
- uint256 referralProjectId
180
- )
181
- external
182
- view
183
- returns (uint256);
184
-
185
145
  /// @notice Simulates a cash out without modifying state.
186
146
  /// @param terminal The terminal to simulate the cash out from.
187
147
  /// @param holder The address cashing out.
@@ -234,13 +194,6 @@ interface IJBTerminalStore {
234
194
  view
235
195
  returns (JBRuleset memory ruleset, uint256 tokenCount, JBPayHookSpecification[] memory hookSpecifications);
236
196
 
237
- /// @notice The cumulative fee payment amount credited across all referral projects for a given terminal.
238
- /// @dev Incremented in lockstep with `feeVolumeByReferralOf` so consumers can compute pro-rata shares in a
239
- /// single SLOAD pair without enumerating referrers.
240
- /// @param terminal The terminal that originated the fee-paying calls.
241
- /// @return The cumulative total fee amount credited across all referrers for this terminal.
242
- function totalFeeVolumeOf(address terminal) external view returns (uint256);
243
-
244
197
  /// @notice Returns the amount of payout limit used by a terminal for a project in a given cycle.
245
198
  /// @param terminal The terminal to get the used payout limit of.
246
199
  /// @param projectId The ID of the project.
@@ -316,15 +269,6 @@ interface IJBTerminalStore {
316
269
  JBCashOutHookSpecification[] memory hookSpecifications
317
270
  );
318
271
 
319
- /// @notice Credit a referral project with a fee payment amount routed through `msg.sender` (the calling terminal).
320
- /// @dev Permissionless: the write is scoped to `msg.sender`'s slot, so an arbitrary caller can only pollute
321
- /// their own bucket. The amount is normalized to `JBConstants.NATIVE_TOKEN` units (18 decimals) using the fee
322
- /// project's price feeds so credits across different fee tokens (ETH, USDC, USDT, …) are summable. No-op when
323
- /// `referralProjectId == 0`, when `amount.value == 0`, or when no price feed exists for the pair.
324
- /// @param referralProjectId The referral project to credit.
325
- /// @param amount The fee amount paid by this fee-take call (raw token amount, decimals, and currency).
326
- function recordFeeReferralCreditOf(uint256 referralProjectId, JBTokenAmount calldata amount) external;
327
-
328
272
  /// @notice Records a payment to a project.
329
273
  /// @param payer The address of the payer.
330
274
  /// @param amount The amount to pay.
@@ -4,20 +4,10 @@ pragma solidity ^0.8.0;
4
4
  /// @custom:member amount The total amount the fee was taken from, as a fixed point number with the same number of
5
5
  /// decimals as the token's accounting context. `uint224` covers any realistic per-call fee basis (max
6
6
  /// ~2.7e49 ETH-equivalent at 18 decimals) and is the same width the protocol's payout/surplus-allowance limits use.
7
- /// @custom:member referralChainId The EIP-155 chain ID of the referrer's home chain, captured from the upper bits of
8
- /// the transient referral encoding at fee-take time. A value of `0` is the "current chain" sentinel — a referrer that
9
- /// only encoded a project ID without a chain prefix is credited on the chain the fee is paid on. Packing this beside
10
- /// `amount` in the same storage slot avoids growing `JBFee` to a third slot.
11
7
  /// @custom:member beneficiary The address that will receive the tokens that are minted as a result of the fee payment.
12
8
  /// @custom:member unlockTimestamp The timestamp at which the fee is unlocked and can be processed.
13
- /// @custom:member referralProjectId The referrer's project ID on `referralChainId`. Captured from the lower bits of
14
- /// `currentReferralProjectId` at fee-take time so held-fee attribution survives the 28-day hold window. The transient
15
- /// slot and terminal entry-point arguments use the packed `(referralChainId << 48) | referralProjectId` form; this
16
- /// struct stores the two halves separately for cheap storage.
17
9
  struct JBFee {
18
10
  uint224 amount;
19
- uint32 referralChainId;
20
11
  address beneficiary;
21
12
  uint48 unlockTimestamp;
22
- uint48 referralProjectId;
23
13
  }
@@ -18,8 +18,7 @@ contract MaliciousPayoutBeneficiary is IERC721Receiver, Test {
18
18
  amount: 5 * 10 ** 18,
19
19
  currency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
20
20
  token: JBConstants.NATIVE_TOKEN,
21
- minTokensPaidOut: 0,
22
- referralProjectId: 0
21
+ minTokensPaidOut: 0
23
22
  });
24
23
  assertEq(_reentrantPayout, 0);
25
24
  }
@@ -50,8 +49,7 @@ contract MaliciousAllowanceBeneficiary is IERC721Receiver, Test {
50
49
  minTokensPaidOut: 0,
51
50
  beneficiary: payable(address(this)),
52
51
  feeBeneficiary: payable(0x000000000000000000000000000000000000007B),
53
- memo: "MEMO",
54
- referralProjectId: 0
52
+ memo: "MEMO"
55
53
  });
56
54
  }
57
55