@bananapus/core-v6 0.0.79 → 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 +0 -2
- package/package.json +1 -1
- package/references/entrypoints.md +3 -7
- package/references/types-errors-events.md +2 -4
- package/src/JBMultiTerminal.sol +5 -107
- package/src/JBTerminalStore.sol +0 -112
- package/src/interfaces/IJBCashOutTerminal.sol +1 -4
- package/src/interfaces/IJBMultiTerminal.sol +0 -13
- package/src/interfaces/IJBPayoutTerminal.sol +2 -8
- package/src/interfaces/IJBTerminalStore.sol +0 -56
- package/src/structs/JBFee.sol +0 -10
- package/test/mock/MockMaliciousBeneficiary.sol +2 -4
- package/src/periphery/JBTriangularPriceFeed.sol +0 -58
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
|
@@ -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
|
|
65
|
-
| `sendPayoutsOf(uint256 projectId, address token, uint256 amount, uint256 currency, uint256 minTokensPaidOut
|
|
66
|
-
| `useAllowanceOf(uint256 projectId, address token, uint256 amount, uint256 currency, uint256 minTokensPaidOut, address payable beneficiary, address payable feeBeneficiary, string memo
|
|
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)`, `
|
|
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
|
|
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) |
|
package/src/JBMultiTerminal.sol
CHANGED
|
@@ -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
|
|
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
|
}
|
package/src/JBTerminalStore.sol
CHANGED
|
@@ -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.
|
package/src/structs/JBFee.sol
CHANGED
|
@@ -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
|
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
pragma solidity 0.8.28;
|
|
3
|
-
|
|
4
|
-
import {mulDiv} from "@prb/math/src/Common.sol";
|
|
5
|
-
|
|
6
|
-
import {IJBPriceFeed} from "../interfaces/IJBPriceFeed.sol";
|
|
7
|
-
|
|
8
|
-
/// @notice A composite price feed that triangulates two existing feeds sharing a common quote ("pivot") currency to
|
|
9
|
-
/// price a pair that has no direct feed.
|
|
10
|
-
/// @dev Composes `NUMERATOR` (the pivot priced per unit of the target pair's *unit* currency) and `DENOMINATOR` (the
|
|
11
|
-
/// pivot priced per unit of the target pair's *pricing* currency) into "pricing currency per unit currency". The
|
|
12
|
-
/// pivot is implicit in the two legs supplied at construction — it is never hardcoded — so different instances can
|
|
13
|
-
/// triangulate through different pivots, and `JBPrices` stays a plain registry with no triangulation logic.
|
|
14
|
-
///
|
|
15
|
-
/// Worked example (ETH<->USDC has no direct feed, triangulate through USD): supply
|
|
16
|
-
/// `NUMERATOR` = the USD-per-USDC feed and `DENOMINATOR` = the USD-per-ETH feed. `currentUnitPrice` then returns
|
|
17
|
-
/// "ETH per 1 USDC", and registering this feed for the `(pricingCurrency = ETH, unitCurrency = USDC)` pair lets
|
|
18
|
-
/// `JBPrices` auto-invert it to "USDC per 1 ETH" for the opposite direction.
|
|
19
|
-
///
|
|
20
|
-
/// Safety: this feed inherits each leg's staleness/validity reverts. If either leg reverts (stale, negative, or
|
|
21
|
-
/// incomplete round) the composite reverts, so a stale or invalid leg can never yield a usable composite price.
|
|
22
|
-
contract JBTriangularPriceFeed is IJBPriceFeed {
|
|
23
|
-
//*********************************************************************//
|
|
24
|
-
// --------------- public immutable stored properties ---------------- //
|
|
25
|
-
//*********************************************************************//
|
|
26
|
-
|
|
27
|
-
/// @notice The feed pricing one unit of the target pair's *unit* currency in the shared pivot currency.
|
|
28
|
-
IJBPriceFeed public immutable NUMERATOR;
|
|
29
|
-
|
|
30
|
-
/// @notice The feed pricing one unit of the target pair's *pricing* currency in the shared pivot currency.
|
|
31
|
-
IJBPriceFeed public immutable DENOMINATOR;
|
|
32
|
-
|
|
33
|
-
//*********************************************************************//
|
|
34
|
-
// -------------------------- constructor ---------------------------- //
|
|
35
|
-
//*********************************************************************//
|
|
36
|
-
|
|
37
|
-
/// @param numerator The feed pricing the unit currency in the pivot currency (e.g. a USD-per-USDC feed).
|
|
38
|
-
/// @param denominator The feed pricing the pricing currency in the pivot currency (e.g. a USD-per-ETH feed).
|
|
39
|
-
constructor(IJBPriceFeed numerator, IJBPriceFeed denominator) {
|
|
40
|
-
NUMERATOR = numerator;
|
|
41
|
-
DENOMINATOR = denominator;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
//*********************************************************************//
|
|
45
|
-
// ------------------------- external views -------------------------- //
|
|
46
|
-
//*********************************************************************//
|
|
47
|
-
|
|
48
|
-
/// @inheritdoc IJBPriceFeed
|
|
49
|
-
/// @dev Returns `numerator / denominator` at the requested precision, which cancels the shared pivot unit and
|
|
50
|
-
/// yields "pricing currency per 1 unit currency".
|
|
51
|
-
function currentUnitPrice(uint256 decimals) external view override returns (uint256) {
|
|
52
|
-
return mulDiv({
|
|
53
|
-
x: NUMERATOR.currentUnitPrice(decimals),
|
|
54
|
-
y: 10 ** decimals,
|
|
55
|
-
denominator: DENOMINATOR.currentUnitPrice(decimals)
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
}
|