@bananapus/core-v6 0.0.80 → 0.0.82
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 +10 -12
- package/package.json +1 -1
- package/references/entrypoints.md +4 -8
- package/references/types-errors-events.md +10 -12
- package/src/JBChainlinkV3PriceFeed.sol +5 -0
- package/src/JBChainlinkV3SequencerPriceFeed.sol +3 -0
- package/src/JBController.sol +35 -4
- package/src/JBDirectory.sol +9 -0
- package/src/JBERC20.sol +3 -0
- package/src/JBFeelessAddresses.sol +3 -0
- package/src/JBFundAccessLimits.sol +5 -0
- package/src/JBMultiTerminal.sol +31 -108
- package/src/JBPermissions.sol +5 -0
- package/src/JBPrices.sol +9 -0
- package/src/JBProjects.sol +5 -0
- package/src/JBRulesets.sol +17 -5
- package/src/JBSplits.sol +5 -0
- package/src/JBTerminalStore.sol +29 -115
- package/src/JBTokens.sol +21 -0
- package/src/abstract/JBControlled.sol +1 -0
- package/src/abstract/JBPermissioned.sol +1 -0
- package/src/enums/JBApprovalStatus.sol +6 -6
- 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/libraries/JBMetadataResolver.sol +9 -1
- package/src/libraries/JBPayoutSplitGroupLib.sol +14 -0
- package/src/periphery/JBMatchingPriceFeed.sol +3 -1
- package/src/structs/JBFee.sol +0 -10
- package/test/mock/MockMaliciousBeneficiary.sol +2 -4
package/src/JBMultiTerminal.sol
CHANGED
|
@@ -66,18 +66,43 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
66
66
|
// --------------------------- custom errors ------------------------- //
|
|
67
67
|
//*********************************************************************//
|
|
68
68
|
|
|
69
|
+
/// @notice Thrown when no terminal can be found to pay a fee in the given token.
|
|
69
70
|
error JBMultiTerminal_FeeTerminalNotFound(address token);
|
|
71
|
+
|
|
72
|
+
/// @notice Thrown when a payout split routes back into the project that is paying out.
|
|
70
73
|
error JBMultiTerminal_MintNotAllowed(uint256 projectId, address terminal);
|
|
74
|
+
|
|
75
|
+
/// @notice Thrown when native value is sent with an operation that does not accept it.
|
|
71
76
|
error JBMultiTerminal_NoMsgValueAllowed(uint256 value);
|
|
77
|
+
|
|
78
|
+
/// @notice Thrown when a value exceeds the allowed maximum.
|
|
72
79
|
error JBMultiTerminal_OverflowAlert(uint256 value, uint256 limit);
|
|
80
|
+
|
|
81
|
+
/// @notice Thrown when the Permit2 allowance is less than the amount being paid.
|
|
73
82
|
error JBMultiTerminal_PermitAllowanceNotEnough(uint256 amount, uint256 allowance);
|
|
83
|
+
|
|
84
|
+
/// @notice Thrown when no terminal can be found to pay a recipient project's split in the given token.
|
|
74
85
|
error JBMultiTerminal_RecipientProjectTerminalNotFound(uint256 projectId, address token);
|
|
86
|
+
|
|
87
|
+
/// @notice Thrown when a token transfer reenters during a balance-delta measurement.
|
|
75
88
|
error JBMultiTerminal_ReentrantTokenTransfer(address token);
|
|
89
|
+
|
|
90
|
+
/// @notice Thrown when a split hook does not support the `IJBSplitHook` interface.
|
|
76
91
|
error JBMultiTerminal_SplitHookInvalid(IJBSplitHook hook);
|
|
92
|
+
|
|
93
|
+
/// @notice Thrown when an approved temporary allowance was not fully consumed by the spender.
|
|
77
94
|
error JBMultiTerminal_TemporaryAllowanceNotConsumed(address token, address spender, uint256 allowance);
|
|
95
|
+
|
|
96
|
+
/// @notice Thrown when migrating a terminal to itself.
|
|
78
97
|
error JBMultiTerminal_TerminalMigrationToSelf(uint256 projectId, address token);
|
|
98
|
+
|
|
99
|
+
/// @notice Thrown when the terminal being migrated to does not accept the same token.
|
|
79
100
|
error JBMultiTerminal_TerminalTokensIncompatible(uint256 projectId, address token, IJBTerminal terminal);
|
|
101
|
+
|
|
102
|
+
/// @notice Thrown when the terminal does not accept the given token.
|
|
80
103
|
error JBMultiTerminal_TokenNotAccepted(address token);
|
|
104
|
+
|
|
105
|
+
/// @notice Thrown when a value is less than the required minimum.
|
|
81
106
|
error JBMultiTerminal_UnderMin(uint256 value, uint256 min);
|
|
82
107
|
|
|
83
108
|
//*********************************************************************//
|
|
@@ -109,7 +134,7 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
109
134
|
/// @notice The contract that stores and manages the terminal's data.
|
|
110
135
|
IJBTerminalStore public immutable override STORE;
|
|
111
136
|
|
|
112
|
-
/// @notice The contract
|
|
137
|
+
/// @notice The contract that manages token minting and burning.
|
|
113
138
|
IJBTokens public immutable override TOKENS;
|
|
114
139
|
|
|
115
140
|
//*********************************************************************//
|
|
@@ -146,25 +171,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
146
171
|
/// @custom:param token The token the fees are held in.
|
|
147
172
|
mapping(uint256 projectId => mapping(address token => uint256)) internal _nextHeldFeeIndexOf;
|
|
148
173
|
|
|
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
174
|
//*********************************************************************//
|
|
169
175
|
// -------------- internal transient stored properties -------------- //
|
|
170
176
|
//*********************************************************************//
|
|
@@ -177,9 +183,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
177
183
|
/// the fee basis to `executePayout`.
|
|
178
184
|
uint256 internal transient _internalSplitPayProjectId;
|
|
179
185
|
|
|
180
|
-
/// @notice The in-flight fee amount that can credit `currentReferralProjectId`.
|
|
181
|
-
uint256 internal transient _feeReferralCreditAmount;
|
|
182
|
-
|
|
183
186
|
//*********************************************************************//
|
|
184
187
|
// -------------------------- constructor ---------------------------- //
|
|
185
188
|
//*********************************************************************//
|
|
@@ -303,10 +306,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
303
306
|
/// data hook and cash out hooks if applicable.
|
|
304
307
|
/// @param metadata Bytes to send along to the emitted event, as well as the data hook and cash out hooks if
|
|
305
308
|
/// 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
309
|
/// @return reclaimAmount The amount of **terminal tokens** sent to `beneficiary` in exchange for the burned project
|
|
311
310
|
/// tokens, as a fixed point number with the same number of decimals as the terminal token's accounting context.
|
|
312
311
|
function cashOutTokensOf(
|
|
@@ -316,8 +315,7 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
316
315
|
address tokenToReclaim,
|
|
317
316
|
uint256 minTokensReclaimed,
|
|
318
317
|
address payable beneficiary,
|
|
319
|
-
bytes calldata metadata
|
|
320
|
-
uint256 referralProjectId
|
|
318
|
+
bytes calldata metadata
|
|
321
319
|
)
|
|
322
320
|
external
|
|
323
321
|
override
|
|
@@ -326,9 +324,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
326
324
|
// Enforce permissions.
|
|
327
325
|
_requirePermissionFrom({account: holder, projectId: projectId, permissionId: JBPermissionIds.CASH_OUT_TOKENS});
|
|
328
326
|
|
|
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
327
|
reclaimAmount = _cashOutTokensOf({
|
|
333
328
|
holder: holder,
|
|
334
329
|
projectId: projectId,
|
|
@@ -338,8 +333,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
338
333
|
metadata: metadata
|
|
339
334
|
});
|
|
340
335
|
|
|
341
|
-
_setReferralProjectId(priorReferral);
|
|
342
|
-
|
|
343
336
|
// The amount being reclaimed must be at least as much as was expected.
|
|
344
337
|
_checkMin({value: reclaimAmount, min: minTokensReclaimed});
|
|
345
338
|
}
|
|
@@ -441,7 +434,7 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
441
434
|
revert JBMultiTerminal_MintNotAllowed({projectId: projectId, terminal: address(terminal)});
|
|
442
435
|
}
|
|
443
436
|
|
|
444
|
-
// Send the `projectId` in the metadata
|
|
437
|
+
// Send the source `projectId` in the metadata for same-terminal split-pay accounting.
|
|
445
438
|
bytes memory metadata = bytes(abi.encodePacked(projectId));
|
|
446
439
|
|
|
447
440
|
// Add to balance if preferred.
|
|
@@ -724,9 +717,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
724
717
|
/// @param token The token to process held fees for.
|
|
725
718
|
/// @param count The number of fees to process.
|
|
726
719
|
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
720
|
// Keep a reference to the terminal that'll receive the fees.
|
|
731
721
|
IJBTerminal feeTerminal = _primaryTerminalOf({projectId: JBConstants.FEE_BENEFICIARY_PROJECT_ID, token: token});
|
|
732
722
|
|
|
@@ -761,11 +751,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
761
751
|
_nextHeldFeeIndexOf[projectId][token] = currentIndex + 1;
|
|
762
752
|
}
|
|
763
753
|
|
|
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
754
|
// Process the standard fee on the original gross amount recorded when the held fee was created.
|
|
770
755
|
_processFee({
|
|
771
756
|
projectId: projectId,
|
|
@@ -781,9 +766,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
781
766
|
}
|
|
782
767
|
}
|
|
783
768
|
|
|
784
|
-
// Restore the previous transient value so reentrant held-fee processing does not erase an outer referral.
|
|
785
|
-
currentReferralProjectId = previousReferralProjectId;
|
|
786
|
-
|
|
787
769
|
// If all held fees have been processed, reset the array and index entirely to bound storage growth.
|
|
788
770
|
if (
|
|
789
771
|
_nextHeldFeeIndexOf[projectId][token] >= _heldFeesOf[projectId][token].length
|
|
@@ -810,29 +792,20 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
810
792
|
/// in terms of the token's accounting context currency), as a fixed point number with the same number of decimals
|
|
811
793
|
/// as the token's accounting context. If the amount of tokens paid out would be less than this amount, the send is
|
|
812
794
|
/// 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
795
|
/// @return amountPaidOut The total amount paid out.
|
|
818
796
|
function sendPayoutsOf(
|
|
819
797
|
uint256 projectId,
|
|
820
798
|
address token,
|
|
821
799
|
uint256 amount,
|
|
822
800
|
uint256 currency,
|
|
823
|
-
uint256 minTokensPaidOut
|
|
824
|
-
uint256 referralProjectId
|
|
801
|
+
uint256 minTokensPaidOut
|
|
825
802
|
)
|
|
826
803
|
external
|
|
827
804
|
override
|
|
828
805
|
returns (uint256 amountPaidOut)
|
|
829
806
|
{
|
|
830
|
-
uint256 priorReferral = _setReferralProjectId(referralProjectId);
|
|
831
|
-
|
|
832
807
|
amountPaidOut = _sendPayoutsOf({projectId: projectId, token: token, amount: amount, currency: currency});
|
|
833
808
|
|
|
834
|
-
_setReferralProjectId(priorReferral);
|
|
835
|
-
|
|
836
809
|
// The amount being paid out must be at least as much as was expected.
|
|
837
810
|
_checkMin({value: amountPaidOut, min: minTokensPaidOut});
|
|
838
811
|
}
|
|
@@ -855,10 +828,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
855
828
|
/// @param feeBeneficiary The address that receives the **project tokens** minted by the fee project in exchange
|
|
856
829
|
/// for the protocol fee paid in terminal tokens.
|
|
857
830
|
/// @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
831
|
/// @return netAmountPaidOut The number of **terminal tokens** sent to `beneficiary`, net of the protocol fee, as a
|
|
863
832
|
/// fixed point number with the same number of decimals as the terminal token's accounting context.
|
|
864
833
|
function useAllowanceOf(
|
|
@@ -869,8 +838,7 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
869
838
|
uint256 minTokensPaidOut,
|
|
870
839
|
address payable beneficiary,
|
|
871
840
|
address payable feeBeneficiary,
|
|
872
|
-
string calldata memo
|
|
873
|
-
uint256 referralProjectId
|
|
841
|
+
string calldata memo
|
|
874
842
|
)
|
|
875
843
|
external
|
|
876
844
|
override
|
|
@@ -882,8 +850,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
882
850
|
// Enforce permissions.
|
|
883
851
|
_requirePermissionFrom({account: owner, projectId: projectId, permissionId: JBPermissionIds.USE_ALLOWANCE});
|
|
884
852
|
|
|
885
|
-
uint256 priorReferral = _setReferralProjectId(referralProjectId);
|
|
886
|
-
|
|
887
853
|
netAmountPaidOut = _useAllowanceOf({
|
|
888
854
|
projectId: projectId,
|
|
889
855
|
owner: owner,
|
|
@@ -895,8 +861,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
895
861
|
memo: memo
|
|
896
862
|
});
|
|
897
863
|
|
|
898
|
-
_setReferralProjectId(priorReferral);
|
|
899
|
-
|
|
900
864
|
// The amount being withdrawn must be at least as much as was expected.
|
|
901
865
|
_checkMin({value: netAmountPaidOut, min: minTokensPaidOut});
|
|
902
866
|
}
|
|
@@ -1766,17 +1730,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1766
1730
|
// Keep a reference to the token amount to forward to the store.
|
|
1767
1731
|
JBTokenAmount memory tokenAmount = _tokenAmountOf({projectId: projectId, token: token, value: amount});
|
|
1768
1732
|
|
|
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
1733
|
// Record the payment.
|
|
1781
1734
|
// Keep a reference to the ruleset the payment is being made during.
|
|
1782
1735
|
// Keep a reference to the pay hook specifications.
|
|
@@ -1866,11 +1819,9 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1866
1819
|
)
|
|
1867
1820
|
internal
|
|
1868
1821
|
{
|
|
1869
|
-
if (feeTerminal == IJBTerminal(address(this))) _feeReferralCreditAmount = amount;
|
|
1870
1822
|
try this.executeProcessFee({
|
|
1871
1823
|
projectId: projectId, token: token, amount: amount, beneficiary: beneficiary, feeTerminal: feeTerminal
|
|
1872
1824
|
}) {
|
|
1873
|
-
delete _feeReferralCreditAmount;
|
|
1874
1825
|
emit ProcessFee({
|
|
1875
1826
|
projectId: projectId,
|
|
1876
1827
|
token: token,
|
|
@@ -1880,7 +1831,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1880
1831
|
caller: _msgSender()
|
|
1881
1832
|
});
|
|
1882
1833
|
} catch (bytes memory reason) {
|
|
1883
|
-
delete _feeReferralCreditAmount;
|
|
1884
1834
|
// Fee processing is fail-open for project liveness: a broken project #1 terminal or fee route must not
|
|
1885
1835
|
// trap payouts, cash outs, allowances, held-fee processing, or terminal migration. The fee is forgiven,
|
|
1886
1836
|
// credited back to the originating project on this terminal, and surfaced through `FeeReverted`.
|
|
@@ -2074,22 +2024,13 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
2074
2024
|
_checkFitsIn({value: amount, max: type(uint224).max});
|
|
2075
2025
|
|
|
2076
2026
|
// 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
2027
|
_heldFeesOf[projectId][token].push(
|
|
2083
2028
|
JBFee({
|
|
2084
2029
|
// forge-lint: disable-next-line(unsafe-typecast)
|
|
2085
2030
|
amount: uint224(amount),
|
|
2086
|
-
// forge-lint: disable-next-line(unsafe-typecast)
|
|
2087
|
-
referralChainId: uint32(encodedReferral >> 48),
|
|
2088
2031
|
beneficiary: beneficiary,
|
|
2089
2032
|
// 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)
|
|
2033
|
+
unlockTimestamp: uint48(block.timestamp + _FEE_HOLDING_SECONDS)
|
|
2093
2034
|
})
|
|
2094
2035
|
);
|
|
2095
2036
|
|
|
@@ -2360,22 +2301,4 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
2360
2301
|
function _feeAmountFrom(uint256 amount) private pure returns (uint256) {
|
|
2361
2302
|
return JBFees.standardFeeAmountFrom(amount);
|
|
2362
2303
|
}
|
|
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
2304
|
}
|
package/src/JBPermissions.sol
CHANGED
|
@@ -17,8 +17,13 @@ contract JBPermissions is ERC2771Context, IJBPermissions {
|
|
|
17
17
|
// --------------------------- custom errors ------------------------- //
|
|
18
18
|
//*********************************************************************//
|
|
19
19
|
|
|
20
|
+
/// @notice Thrown when attempting to set the reserved permission ID 0.
|
|
20
21
|
error JBPermissions_NoZeroPermission(address account, address operator, uint256 projectId);
|
|
22
|
+
|
|
23
|
+
/// @notice Thrown when a permission ID is greater than the maximum of 255.
|
|
21
24
|
error JBPermissions_PermissionIdOutOfBounds(uint256 permissionId);
|
|
25
|
+
|
|
26
|
+
/// @notice Thrown when the caller is not the account and lacks ROOT permission to set permissions on its behalf.
|
|
22
27
|
error JBPermissions_Unauthorized(address account, address operator, uint256 projectId, uint256 permissionId);
|
|
23
28
|
|
|
24
29
|
//*********************************************************************//
|
package/src/JBPrices.sol
CHANGED
|
@@ -23,10 +23,19 @@ contract JBPrices is JBControlled, JBPermissioned, ERC2771Context, Ownable, IJBP
|
|
|
23
23
|
// --------------------------- custom errors ------------------------- //
|
|
24
24
|
//*********************************************************************//
|
|
25
25
|
|
|
26
|
+
/// @notice Thrown when adding a price feed that is already registered for the same currency pair.
|
|
26
27
|
error JBPrices_PriceFeedAlreadyAdded(IJBPriceFeed feed);
|
|
28
|
+
|
|
29
|
+
/// @notice Thrown when no configured price feed can be found for the requested currency pair.
|
|
27
30
|
error JBPrices_PriceFeedNotFound(uint256 projectId, uint256 pricingCurrency, uint256 unitCurrency);
|
|
31
|
+
|
|
32
|
+
/// @notice Thrown when the provided price feed is the zero address.
|
|
28
33
|
error JBPrices_ZeroPriceFeed();
|
|
34
|
+
|
|
35
|
+
/// @notice Thrown when the pricing currency provided is zero.
|
|
29
36
|
error JBPrices_ZeroPricingCurrency(uint256 projectId, uint256 pricingCurrency);
|
|
37
|
+
|
|
38
|
+
/// @notice Thrown when the unit currency provided is zero.
|
|
30
39
|
error JBPrices_ZeroUnitCurrency(uint256 projectId, uint256 unitCurrency);
|
|
31
40
|
|
|
32
41
|
//*********************************************************************//
|
package/src/JBProjects.sol
CHANGED
|
@@ -18,8 +18,13 @@ contract JBProjects is ERC721, ERC2771Context, Ownable, IJBProjects {
|
|
|
18
18
|
// --------------------------- custom errors ------------------------- //
|
|
19
19
|
//*********************************************************************//
|
|
20
20
|
|
|
21
|
+
/// @notice Thrown when the configured creation fee exceeds the allowed maximum.
|
|
21
22
|
error JBProjects_CreationFeeExceedsMax(uint256 fee, uint256 max);
|
|
23
|
+
|
|
24
|
+
/// @notice Thrown when the native value sent does not equal the required creation fee.
|
|
22
25
|
error JBProjects_InvalidCreationFee(uint256 value, uint256 requiredFee);
|
|
26
|
+
|
|
27
|
+
/// @notice Thrown when a non-zero creation fee is configured without a fee receiver.
|
|
23
28
|
error JBProjects_ZeroCreationFeeReceiver();
|
|
24
29
|
|
|
25
30
|
//*********************************************************************//
|
package/src/JBRulesets.sol
CHANGED
|
@@ -25,11 +25,23 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
25
25
|
// --------------------------- custom errors ------------------------- //
|
|
26
26
|
//*********************************************************************//
|
|
27
27
|
|
|
28
|
+
/// @notice Thrown when the approval hook is not a contract or does not support the `IJBRulesetApprovalHook`
|
|
29
|
+
/// interface.
|
|
28
30
|
error JBRulesets_InvalidRulesetApprovalHook(IJBRulesetApprovalHook hook);
|
|
31
|
+
|
|
32
|
+
/// @notice Thrown when the ruleset duration exceeds the uint32 maximum.
|
|
29
33
|
error JBRulesets_InvalidRulesetDuration(uint256 duration, uint256 limit);
|
|
34
|
+
|
|
35
|
+
/// @notice Thrown when the ruleset's start plus duration exceeds the uint48 maximum.
|
|
30
36
|
error JBRulesets_InvalidRulesetEndTime(uint256 timestamp, uint256 limit);
|
|
37
|
+
|
|
38
|
+
/// @notice Thrown when the ruleset weight exceeds the uint112 maximum.
|
|
31
39
|
error JBRulesets_InvalidWeight(uint256 weight, uint256 limit);
|
|
40
|
+
|
|
41
|
+
/// @notice Thrown when the weight cut percent exceeds 100%.
|
|
32
42
|
error JBRulesets_InvalidWeightCutPercent(uint256 percent);
|
|
43
|
+
|
|
44
|
+
/// @notice Thrown when too many weight-cut iterations remain and the weight cache must be populated first.
|
|
33
45
|
error JBRulesets_WeightCacheRequired(uint256 projectId);
|
|
34
46
|
|
|
35
47
|
//*********************************************************************//
|
|
@@ -396,8 +408,8 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
396
408
|
// Get a reference to the approval status.
|
|
397
409
|
JBApprovalStatus approvalStatus = _approvalStatusOf({projectId: projectId, ruleset: ruleset});
|
|
398
410
|
|
|
399
|
-
// While the ruleset has
|
|
400
|
-
// the ruleset that the latest is based on, which has the latest approved configuration.
|
|
411
|
+
// While the ruleset has an approval hook that isn't approved or if it hasn't yet started, get a reference
|
|
412
|
+
// to the ruleset that the latest is based on, which has the latest approved configuration.
|
|
401
413
|
while (
|
|
402
414
|
(approvalStatus != JBApprovalStatus.Approved && approvalStatus != JBApprovalStatus.Empty)
|
|
403
415
|
// forge-lint: disable-next-line(block-timestamp)
|
|
@@ -472,7 +484,7 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
472
484
|
// Keep a reference to its approval status.
|
|
473
485
|
JBApprovalStatus approvalStatus;
|
|
474
486
|
|
|
475
|
-
// If an upcoming approvable ruleset has been queued, and
|
|
487
|
+
// If an upcoming approvable ruleset has been queued, and its approval status is Approved or ApprovalExpected,
|
|
476
488
|
// return its ruleset struct
|
|
477
489
|
if (upcomingApprovableRulesetId != 0) {
|
|
478
490
|
ruleset = _getStructFor({projectId: projectId, rulesetId: upcomingApprovableRulesetId, withMetadata: true});
|
|
@@ -495,7 +507,7 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
495
507
|
ruleset = _getStructFor({projectId: projectId, rulesetId: latestRulesetIdOf[projectId], withMetadata: true});
|
|
496
508
|
|
|
497
509
|
// If the latest ruleset starts in the future, it must start in the distant future
|
|
498
|
-
// Since
|
|
510
|
+
// Since it's not the upcoming approvable ruleset. In this case, base the upcoming ruleset on the base
|
|
499
511
|
// ruleset.
|
|
500
512
|
// forge-lint: disable-next-line(block-timestamp)
|
|
501
513
|
while (ruleset.start > block.timestamp) {
|
|
@@ -723,7 +735,7 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
723
735
|
// Get a reference to the approval status.
|
|
724
736
|
JBApprovalStatus approvalStatus = _approvalStatusOf({projectId: projectId, ruleset: baseRuleset});
|
|
725
737
|
|
|
726
|
-
// If the base ruleset has started but wasn't approved if
|
|
738
|
+
// If the base ruleset has started but wasn't approved if an approval hook exists
|
|
727
739
|
// OR it hasn't started but is currently approved
|
|
728
740
|
// OR it hasn't started but it is likely to be approved and takes place before the proposed one,
|
|
729
741
|
// set the struct to be the ruleset it's based on, which carries the latest approved ruleset.
|
package/src/JBSplits.sol
CHANGED
|
@@ -19,8 +19,13 @@ contract JBSplits is JBControlled, IJBSplits {
|
|
|
19
19
|
// --------------------------- custom errors ------------------------- //
|
|
20
20
|
//*********************************************************************//
|
|
21
21
|
|
|
22
|
+
/// @notice Thrown when a new set of splits omits a still-locked split from the previous set.
|
|
22
23
|
error JBSplits_PreviousLockedSplitsNotIncluded(uint256 projectId, uint256 rulesetId);
|
|
24
|
+
|
|
25
|
+
/// @notice Thrown when the splits in a group sum to more than 100%.
|
|
23
26
|
error JBSplits_TotalPercentExceeds100(uint256 projectId, uint256 rulesetId, uint256 groupId, uint256 percentTotal);
|
|
27
|
+
|
|
28
|
+
/// @notice Thrown when a split is configured with a percent of zero.
|
|
24
29
|
error JBSplits_ZeroSplitPercent(uint256 projectId, uint256 rulesetId, uint256 groupId, uint256 splitIndex);
|
|
25
30
|
|
|
26
31
|
//*********************************************************************//
|
package/src/JBTerminalStore.sol
CHANGED
|
@@ -39,22 +39,48 @@ contract JBTerminalStore is IJBTerminalStore {
|
|
|
39
39
|
// --------------------------- custom errors ------------------------- //
|
|
40
40
|
//*********************************************************************//
|
|
41
41
|
|
|
42
|
+
/// @notice Thrown when setting an accounting context for a token that already has one.
|
|
42
43
|
error JBTerminalStore_AccountingContextAlreadySet(address token);
|
|
44
|
+
|
|
45
|
+
/// @notice Thrown when a token's provided decimals do not match the decimals it reports.
|
|
43
46
|
error JBTerminalStore_AccountingContextDecimalsMismatch(
|
|
44
47
|
address token, uint256 providedDecimals, uint256 expectedDecimals
|
|
45
48
|
);
|
|
49
|
+
|
|
50
|
+
/// @notice Thrown when a token's decimals are outside the supported range.
|
|
46
51
|
error JBTerminalStore_AccountingContextDecimalsOutOfRange(address token, uint256 decimals);
|
|
52
|
+
|
|
53
|
+
/// @notice Thrown when the project's current ruleset does not allow adding accounting contexts.
|
|
47
54
|
error JBTerminalStore_AddingAccountingContextNotAllowed(uint256 projectId, uint256 rulesetId, address terminal);
|
|
55
|
+
|
|
56
|
+
/// @notice Thrown when the used surplus allowance exceeds the amount the controller granted.
|
|
48
57
|
error JBTerminalStore_InadequateControllerAllowance(uint256 amount, uint256 allowance);
|
|
49
58
|
|
|
59
|
+
/// @notice Thrown when the amount to use exceeds the terminal's recorded balance or surplus.
|
|
50
60
|
error JBTerminalStore_InadequateTerminalStoreBalance(uint256 amount, uint256 balance);
|
|
61
|
+
|
|
62
|
+
/// @notice Thrown when cashing out more tokens than the effective total supply.
|
|
51
63
|
error JBTerminalStore_InsufficientTokens(uint256 count, uint256 totalSupply);
|
|
64
|
+
|
|
65
|
+
/// @notice Thrown when a hook specification asks to forward more than the amount paid.
|
|
52
66
|
error JBTerminalStore_InvalidAmountToForwardHook(uint256 amount, uint256 paidAmount);
|
|
67
|
+
|
|
68
|
+
/// @notice Thrown when a hook specification is flagged as a no-op but carries a non-zero amount.
|
|
53
69
|
error JBTerminalStore_NoopHookSpecHasAmount(uint256 amount);
|
|
70
|
+
|
|
71
|
+
/// @notice Thrown when the project has no current ruleset.
|
|
54
72
|
error JBTerminalStore_RulesetNotFound(uint256 projectId);
|
|
73
|
+
|
|
74
|
+
/// @notice Thrown when paying a project whose current ruleset pauses payments.
|
|
55
75
|
error JBTerminalStore_RulesetPaymentPaused(uint256 projectId, uint256 rulesetId);
|
|
76
|
+
|
|
77
|
+
/// @notice Thrown when the project's current ruleset does not allow terminal migration.
|
|
56
78
|
error JBTerminalStore_TerminalMigrationNotAllowed(uint256 projectId, uint256 rulesetId);
|
|
79
|
+
|
|
80
|
+
/// @notice Thrown when a value to record exceeds the uint224 maximum.
|
|
57
81
|
error JBTerminalStore_Uint224Overflow(uint256 value);
|
|
82
|
+
|
|
83
|
+
/// @notice Thrown when an accounting context's currency is zero.
|
|
58
84
|
error JBTerminalStore_ZeroAccountingContextCurrency(address token);
|
|
59
85
|
|
|
60
86
|
//*********************************************************************//
|
|
@@ -92,26 +118,6 @@ contract JBTerminalStore is IJBTerminalStore {
|
|
|
92
118
|
public
|
|
93
119
|
override balanceOf;
|
|
94
120
|
|
|
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
121
|
/// @notice The currency-denominated amount of funds that a project has already paid out from its payout limit
|
|
116
122
|
/// during the current ruleset for each terminal, in terms of the payout limit's currency.
|
|
117
123
|
/// @dev Increases as projects pay out funds.
|
|
@@ -365,22 +371,6 @@ contract JBTerminalStore is IJBTerminalStore {
|
|
|
365
371
|
}
|
|
366
372
|
}
|
|
367
373
|
|
|
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
374
|
/// @notice Records a payment — calculates how many project tokens to mint based on the payment amount and the
|
|
385
375
|
/// current ruleset's weight. Uses the data hook if configured, otherwise mints proportionally.
|
|
386
376
|
/// @dev Called by the terminal after accepting funds. Updates the project's recorded balance.
|
|
@@ -501,7 +491,7 @@ contract JBTerminalStore is IJBTerminalStore {
|
|
|
501
491
|
revert JBTerminalStore_InadequateTerminalStoreBalance({amount: amountPaidOut, balance: currentBalance});
|
|
502
492
|
}
|
|
503
493
|
|
|
504
|
-
//
|
|
494
|
+
// Remove the paid out funds from the project's token balance.
|
|
505
495
|
unchecked {
|
|
506
496
|
balanceOf[msg.sender][projectId][token] = currentBalance - amountPaidOut;
|
|
507
497
|
}
|
|
@@ -1173,7 +1163,7 @@ contract JBTerminalStore is IJBTerminalStore {
|
|
|
1173
1163
|
if (weight == 0) return (ruleset, 0, hookSpecifications, balanceDiff);
|
|
1174
1164
|
|
|
1175
1165
|
// If the terminal should base its weight on a currency other than the terminal's currency, determine the
|
|
1176
|
-
// factor. The weight is always a fixed point
|
|
1166
|
+
// factor. The weight is always a fixed point number with 18 decimals. To ensure this, the ratio should use the
|
|
1177
1167
|
// same
|
|
1178
1168
|
// number of decimals as the `amount`.
|
|
1179
1169
|
uint256 weightRatio = amount.currency == ruleset.baseCurrency()
|
|
@@ -1366,7 +1356,7 @@ contract JBTerminalStore is IJBTerminalStore {
|
|
|
1366
1356
|
: mulDiv({
|
|
1367
1357
|
x: surplus,
|
|
1368
1358
|
y: 10 ** _MAX_FIXED_POINT_FIDELITY, // Use `_MAX_FIXED_POINT_FIDELITY` to keep as much of the
|
|
1369
|
-
//
|
|
1359
|
+
// surplus's fidelity as possible when converting.
|
|
1370
1360
|
denominator: PRICES.pricePerUnitOf({
|
|
1371
1361
|
projectId: projectId,
|
|
1372
1362
|
pricingCurrency: accountingContext.currency,
|
|
@@ -1442,80 +1432,4 @@ contract JBTerminalStore is IJBTerminalStore {
|
|
|
1442
1432
|
}
|
|
1443
1433
|
}
|
|
1444
1434
|
}
|
|
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
1435
|
}
|