@bananapus/core-v6 0.0.42 → 0.0.43
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/CHANGELOG.md +1 -1
- package/README.md +3 -3
- package/package.json +1 -1
- package/references/types-errors-events.md +0 -1
- package/src/JBChainlinkV3PriceFeed.sol +14 -6
- package/src/JBChainlinkV3SequencerPriceFeed.sol +5 -6
- package/src/JBController.sol +61 -50
- package/src/JBDirectory.sol +4 -7
- package/src/JBERC20.sol +8 -7
- package/src/JBFundAccessLimits.sol +12 -4
- package/src/JBMultiTerminal.sol +14 -39
- package/src/JBPermissions.sol +6 -3
- package/src/JBPrices.sol +18 -12
- package/src/JBRulesets.sol +4 -25
- package/src/JBSplits.sol +13 -5
- package/src/JBTerminalStore.sol +36 -25
- package/src/JBTokens.sol +11 -13
- package/src/abstract/JBControlled.sol +1 -2
- package/src/interfaces/IJBController.sol +0 -6
- package/src/libraries/JBCashOuts.sol +6 -2
- package/src/libraries/JBCurrencyIds.sol +3 -0
- package/src/libraries/JBMetadataResolver.sol +20 -12
- package/src/libraries/JBPayoutSplitGroupLib.sol +8 -3
- package/src/libraries/JBSplitGroupIds.sol +1 -0
- package/src/periphery/JBDeadline1Day.sol +1 -0
- package/src/periphery/JBDeadline3Days.sol +1 -0
- package/src/periphery/JBDeadline3Hours.sol +1 -0
- package/src/periphery/JBDeadline7Days.sol +1 -0
package/src/JBMultiTerminal.sol
CHANGED
|
@@ -64,7 +64,7 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
64
64
|
//*********************************************************************//
|
|
65
65
|
|
|
66
66
|
error JBMultiTerminal_FeeTerminalNotFound(address token);
|
|
67
|
-
error JBMultiTerminal_MintNotAllowed();
|
|
67
|
+
error JBMultiTerminal_MintNotAllowed(uint256 projectId, uint256 splitProjectId, address terminal);
|
|
68
68
|
error JBMultiTerminal_NoMsgValueAllowed(uint256 value);
|
|
69
69
|
error JBMultiTerminal_OverflowAlert(uint256 value, uint256 limit);
|
|
70
70
|
error JBMultiTerminal_PermitAllowanceNotEnough(uint256 amount, uint256 allowance);
|
|
@@ -213,7 +213,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
213
213
|
|
|
214
214
|
// Emit an event for each accounting context.
|
|
215
215
|
for (uint256 i; i < accountingContexts.length;) {
|
|
216
|
-
// slither-disable-next-line reentrancy-events
|
|
217
216
|
emit SetAccountingContext({projectId: projectId, context: accountingContexts[i], caller: _msgSender()});
|
|
218
217
|
unchecked {
|
|
219
218
|
++i;
|
|
@@ -248,15 +247,15 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
248
247
|
_addToBalanceOf({
|
|
249
248
|
projectId: projectId,
|
|
250
249
|
token: token,
|
|
251
|
-
amount: _acceptFundsFor(projectId, token, amount, metadata),
|
|
250
|
+
amount: _acceptFundsFor({projectId: projectId, token: token, amount: amount, metadata: metadata}),
|
|
252
251
|
shouldReturnHeldFees: shouldReturnHeldFees,
|
|
253
252
|
memo: memo,
|
|
254
253
|
metadata: metadata
|
|
255
254
|
});
|
|
256
255
|
}
|
|
257
256
|
|
|
258
|
-
/// @notice
|
|
259
|
-
///
|
|
257
|
+
/// @notice Cash out project tokens. The project's current ruleset determines the reclaimed surplus and any data
|
|
258
|
+
/// hook or cash out hook behavior.
|
|
260
259
|
/// @dev Only the token holder or an operator with `CASH_OUT_TOKENS` permission from that holder can call this.
|
|
261
260
|
/// @param holder The account cashing out tokens.
|
|
262
261
|
/// @param projectId The ID of the project the project tokens belong to.
|
|
@@ -330,7 +329,7 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
330
329
|
if (split.hook != IJBSplitHook(address(0))) {
|
|
331
330
|
// Make sure that the address supports the split hook interface.
|
|
332
331
|
if (!split.hook.supportsInterface(type(IJBSplitHook).interfaceId)) {
|
|
333
|
-
revert JBMultiTerminal_SplitHookInvalid(split.hook);
|
|
332
|
+
revert JBMultiTerminal_SplitHookInvalid({hook: split.hook});
|
|
334
333
|
}
|
|
335
334
|
|
|
336
335
|
// This payout is eligible for a fee since the funds are leaving this contract and the split hook isn't a
|
|
@@ -370,7 +369,7 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
370
369
|
|
|
371
370
|
// The project must have a terminal to send funds to.
|
|
372
371
|
if (terminal == IJBTerminal(address(0))) {
|
|
373
|
-
revert JBMultiTerminal_RecipientProjectTerminalNotFound(split.projectId, token);
|
|
372
|
+
revert JBMultiTerminal_RecipientProjectTerminalNotFound({projectId: split.projectId, token: token});
|
|
374
373
|
}
|
|
375
374
|
|
|
376
375
|
// Fees apply to fund egress, not intra-terminal accounting. When both projects share this terminal,
|
|
@@ -409,7 +408,9 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
409
408
|
// Cross-project pay splits on the same terminal are allowed (different project receives the funds).
|
|
410
409
|
// The try-catch in the split group lib catches this revert and restores the balance.
|
|
411
410
|
if (terminal == this && split.projectId == projectId) {
|
|
412
|
-
revert JBMultiTerminal_MintNotAllowed(
|
|
411
|
+
revert JBMultiTerminal_MintNotAllowed({
|
|
412
|
+
projectId: projectId, splitProjectId: split.projectId, terminal: address(terminal)
|
|
413
|
+
});
|
|
413
414
|
}
|
|
414
415
|
|
|
415
416
|
// Keep a reference to the beneficiary of the payment.
|
|
@@ -429,7 +430,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
429
430
|
// destination project's data hook forwarded part of the payment to pay hooks, the store
|
|
430
431
|
// only recorded a partial balance increase. Without this cap, _feeFreeSurplusOf can exceed
|
|
431
432
|
// STORE.balanceOf, causing users to be overcharged fees on zero-tax cashouts.
|
|
432
|
-
// slither-disable-next-line reentrancy-eth
|
|
433
433
|
_capFeeFreeSurplus({projectId: split.projectId, token: token});
|
|
434
434
|
}
|
|
435
435
|
} else {
|
|
@@ -473,7 +473,7 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
473
473
|
require(msg.sender == address(this));
|
|
474
474
|
|
|
475
475
|
if (address(feeTerminal) == address(0)) {
|
|
476
|
-
revert JBMultiTerminal_FeeTerminalNotFound(token);
|
|
476
|
+
revert JBMultiTerminal_FeeTerminalNotFound({token: token});
|
|
477
477
|
}
|
|
478
478
|
|
|
479
479
|
// Send the projectId in the metadata.
|
|
@@ -537,7 +537,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
537
537
|
// sends fees to the fee project terminal. The migrated project's balance on this terminal is zero, but held
|
|
538
538
|
// fees are backed by the terminal's own token balance (not the project's recorded balance).
|
|
539
539
|
// Record the migration in the store.
|
|
540
|
-
// slither-disable-next-line reentrancy-events
|
|
541
540
|
balance = STORE.recordTerminalMigration({projectId: projectId, token: token});
|
|
542
541
|
|
|
543
542
|
emit MigrateTerminal({projectId: projectId, token: token, to: to, amount: balance, caller: _msgSender()});
|
|
@@ -566,8 +565,8 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
566
565
|
}
|
|
567
566
|
}
|
|
568
567
|
|
|
569
|
-
/// @notice Pay a project
|
|
570
|
-
///
|
|
568
|
+
/// @notice Pay a project. The project's current ruleset determines how many project tokens the beneficiary receives
|
|
569
|
+
/// and any data hook or pay hook behavior.
|
|
571
570
|
/// @param projectId The ID of the project to pay.
|
|
572
571
|
/// @param amount The amount of tokens to send, as a fixed point number with the same number of
|
|
573
572
|
/// decimals as the token's accounting context. If this terminal's token is native, this is ignored and `msg.value`
|
|
@@ -669,7 +668,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
669
668
|
_nextHeldFeeIndexOf[projectId][token] = currentIndex + 1;
|
|
670
669
|
|
|
671
670
|
// Process the fee.
|
|
672
|
-
// slither-disable-next-line reentrancy-no-eth
|
|
673
671
|
_processFee({
|
|
674
672
|
projectId: projectId,
|
|
675
673
|
token: token,
|
|
@@ -1019,7 +1017,7 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1019
1017
|
|
|
1020
1018
|
// Make sure the permit allowance is enough for this payment. If not we revert early.
|
|
1021
1019
|
if (amount > allowance.amount) {
|
|
1022
|
-
revert JBMultiTerminal_PermitAllowanceNotEnough(amount, allowance.amount);
|
|
1020
|
+
revert JBMultiTerminal_PermitAllowanceNotEnough({amount: amount, allowance: allowance.amount});
|
|
1023
1021
|
}
|
|
1024
1022
|
|
|
1025
1023
|
// Keep a reference to the permit rules.
|
|
@@ -1034,8 +1032,7 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1034
1032
|
// Set the allowance to `spend` tokens for the user.
|
|
1035
1033
|
try PERMIT2.permit({owner: _msgSender(), permitSingle: permitSingle, signature: allowance.signature}) {}
|
|
1036
1034
|
catch (bytes memory reason) {
|
|
1037
|
-
|
|
1038
|
-
emit Permit2AllowanceFailed(token, _msgSender(), reason);
|
|
1035
|
+
emit Permit2AllowanceFailed({token: token, owner: _msgSender(), reason: reason});
|
|
1039
1036
|
}
|
|
1040
1037
|
}
|
|
1041
1038
|
|
|
@@ -1118,7 +1115,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1118
1115
|
|
|
1119
1116
|
// Cap fee-free surplus at the remaining balance.
|
|
1120
1117
|
if (feeFreeSurplus > remainingBalance) {
|
|
1121
|
-
// slither-disable-next-line reentrancy-no-eth,reentrancy-eth,reentrancy-benign
|
|
1122
1118
|
_feeFreeSurplusOf[projectId][token] = remainingBalance;
|
|
1123
1119
|
}
|
|
1124
1120
|
}
|
|
@@ -1199,7 +1195,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1199
1195
|
uint256 feeFreeSurplus = _feeFreeSurplusOf[projectId][tokenToReclaim];
|
|
1200
1196
|
if (feeFreeSurplus != 0) {
|
|
1201
1197
|
uint256 feeableAmount = reclaimAmount < feeFreeSurplus ? reclaimAmount : feeFreeSurplus;
|
|
1202
|
-
// slither-disable-next-line reentrancy-no-eth,reentrancy-eth,reentrancy-benign
|
|
1203
1198
|
unchecked {
|
|
1204
1199
|
_feeFreeSurplusOf[projectId][tokenToReclaim] = feeFreeSurplus - feeableAmount;
|
|
1205
1200
|
}
|
|
@@ -1242,7 +1237,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1242
1237
|
// balance during a prior inbound payout), overcharging fees on round-trip prevention.
|
|
1243
1238
|
// Placed after hook fulfillment so any further balance reductions from cashout hooks are
|
|
1244
1239
|
// also accounted for.
|
|
1245
|
-
// slither-disable-next-line reentrancy-eth
|
|
1246
1240
|
_capFeeFreeSurplus({projectId: projectId, token: tokenToReclaim});
|
|
1247
1241
|
|
|
1248
1242
|
// Take the fee from all outbound reclaimings.
|
|
@@ -1344,12 +1338,10 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1344
1338
|
} else {
|
|
1345
1339
|
// Trigger any inherited pre-transfer logic.
|
|
1346
1340
|
// Keep a reference to the amount that'll be paid as a `msg.value`.
|
|
1347
|
-
// slither-disable-next-line reentrancy-events
|
|
1348
1341
|
uint256 payValue = _beforeTransferTo({to: address(terminal), token: token, amount: amount});
|
|
1349
1342
|
|
|
1350
1343
|
// Send the fee.
|
|
1351
1344
|
// If this terminal's token is ETH, send it in msg.value.
|
|
1352
|
-
// slither-disable-next-line unused-return
|
|
1353
1345
|
terminal.pay{value: payValue}({
|
|
1354
1346
|
projectId: projectId,
|
|
1355
1347
|
token: token,
|
|
@@ -1382,7 +1374,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1382
1374
|
{
|
|
1383
1375
|
// Trigger any inherited pre-transfer logic.
|
|
1384
1376
|
// Keep a reference to the amount that'll be paid as a `msg.value`.
|
|
1385
|
-
// slither-disable-next-line reentrancy-events
|
|
1386
1377
|
uint256 payValue = _beforeTransferTo({to: address(terminal), token: token, amount: amount});
|
|
1387
1378
|
|
|
1388
1379
|
// Add to balance on the recipient terminal.
|
|
@@ -1441,7 +1432,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1441
1432
|
cashOutMetadata: metadata
|
|
1442
1433
|
});
|
|
1443
1434
|
|
|
1444
|
-
// slither-disable-next-line calls-loop
|
|
1445
1435
|
for (uint256 i; i < specifications.length;) {
|
|
1446
1436
|
// Set the specification being iterated on.
|
|
1447
1437
|
JBCashOutHookSpecification memory specification = specifications[i];
|
|
@@ -1477,13 +1467,11 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1477
1467
|
|
|
1478
1468
|
// Trigger any inherited pre-transfer logic.
|
|
1479
1469
|
// Keep a reference to the amount that'll be paid as a `msg.value`.
|
|
1480
|
-
// slither-disable-next-line reentrancy-events
|
|
1481
1470
|
uint256 payValue = _beforeTransferTo({
|
|
1482
1471
|
to: address(specification.hook), token: beneficiaryReclaimAmount.token, amount: specification.amount
|
|
1483
1472
|
});
|
|
1484
1473
|
|
|
1485
1474
|
// Fulfill the specification.
|
|
1486
|
-
// slither-disable-next-line reentrancy-events,calls-loop
|
|
1487
1475
|
specification.hook.afterCashOutRecordedWith{value: payValue}(context);
|
|
1488
1476
|
|
|
1489
1477
|
// Revoke the temporary pull allowance now that the hook call has finished.
|
|
@@ -1538,7 +1526,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1538
1526
|
});
|
|
1539
1527
|
|
|
1540
1528
|
// Fulfill each specification through their pay hooks.
|
|
1541
|
-
// slither-disable-next-line calls-loop
|
|
1542
1529
|
for (uint256 i; i < specifications.length;) {
|
|
1543
1530
|
// Set the specification being iterated on.
|
|
1544
1531
|
JBPayHookSpecification memory specification = specifications[i];
|
|
@@ -1564,13 +1551,11 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1564
1551
|
|
|
1565
1552
|
// Trigger any inherited pre-transfer logic.
|
|
1566
1553
|
// Keep a reference to the amount that'll be paid as a `msg.value`.
|
|
1567
|
-
// slither-disable-next-line reentrancy-events
|
|
1568
1554
|
uint256 payValue = _beforeTransferTo({
|
|
1569
1555
|
to: address(specification.hook), token: tokenAmount.token, amount: specification.amount
|
|
1570
1556
|
});
|
|
1571
1557
|
|
|
1572
1558
|
// Fulfill the specification.
|
|
1573
|
-
// slither-disable-next-line reentrancy-events,calls-loop
|
|
1574
1559
|
specification.hook.afterPayRecordedWith{value: payValue}(context);
|
|
1575
1560
|
|
|
1576
1561
|
// Revoke the temporary pull allowance now that the hook call has finished.
|
|
@@ -1618,7 +1603,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1618
1603
|
// Keep a reference to the ruleset the payment is being made during.
|
|
1619
1604
|
// Keep a reference to the pay hook specifications.
|
|
1620
1605
|
// Keep a reference to the token count that'll be minted as a result of the payment.
|
|
1621
|
-
// slither-disable-next-line reentrancy-events
|
|
1622
1606
|
(JBRuleset memory ruleset, uint256 tokenCount, JBPayHookSpecification[] memory hookSpecifications) = STORE.recordPaymentFrom({
|
|
1623
1607
|
payer: payer, amount: tokenAmount, projectId: projectId, beneficiary: beneficiary, metadata: metadata
|
|
1624
1608
|
});
|
|
@@ -1630,7 +1614,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1630
1614
|
if (tokenCount != 0) {
|
|
1631
1615
|
// Set the token count to be the number of tokens minted for the beneficiary instead of the total
|
|
1632
1616
|
// amount.
|
|
1633
|
-
// slither-disable-next-line reentrancy-events
|
|
1634
1617
|
newlyIssuedTokenCount = _controllerOf(projectId)
|
|
1635
1618
|
.mintTokensOf({
|
|
1636
1619
|
projectId: projectId,
|
|
@@ -1686,7 +1669,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1686
1669
|
)
|
|
1687
1670
|
internal
|
|
1688
1671
|
{
|
|
1689
|
-
// slither-disable-next-line reentrancy-events,calls-loop
|
|
1690
1672
|
try this.executeProcessFee({
|
|
1691
1673
|
projectId: projectId, token: token, amount: amount, beneficiary: beneficiary, feeTerminal: feeTerminal
|
|
1692
1674
|
}) {
|
|
@@ -1723,7 +1705,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1723
1705
|
/// this
|
|
1724
1706
|
/// terminal.
|
|
1725
1707
|
function _recordAddedBalanceFor(uint256 projectId, address token, uint256 amount) internal {
|
|
1726
|
-
// slither-disable-next-line calls-loop
|
|
1727
1708
|
STORE.recordAddedBalanceFor({projectId: projectId, token: token, amount: amount});
|
|
1728
1709
|
}
|
|
1729
1710
|
|
|
@@ -1760,7 +1741,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1760
1741
|
// Save the fee being iterated on.
|
|
1761
1742
|
JBFee memory heldFee = _heldFeesOf[projectId][token][startIndex + i];
|
|
1762
1743
|
|
|
1763
|
-
// slither-disable-next-line incorrect-equality
|
|
1764
1744
|
if (leftoverAmount == 0) {
|
|
1765
1745
|
break;
|
|
1766
1746
|
} else {
|
|
@@ -1878,7 +1858,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1878
1858
|
leftoverPayoutAmount = netLeftoverPayoutAmount;
|
|
1879
1859
|
}
|
|
1880
1860
|
} catch (bytes memory reason) {
|
|
1881
|
-
// slither-disable-next-line reentrancy-events
|
|
1882
1861
|
emit PayoutTransferReverted({
|
|
1883
1862
|
projectId: projectId,
|
|
1884
1863
|
addr: projectOwner,
|
|
@@ -1896,7 +1875,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
1896
1875
|
|
|
1897
1876
|
// Cap fee-free surplus at remaining balance. Non-fee-free funds leave first.
|
|
1898
1877
|
// Placed after all payouts settle so the cap reflects post-payout state.
|
|
1899
|
-
// slither-disable-next-line reentrancy-no-eth,reentrancy-eth,reentrancy-benign
|
|
1900
1878
|
_capFeeFreeSurplus({projectId: projectId, token: token});
|
|
1901
1879
|
|
|
1902
1880
|
// Take the fee.
|
|
@@ -2042,12 +2020,10 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
2042
2020
|
STORE.recordUsedAllowanceOf({projectId: projectId, token: token, amount: amount, currency: currency});
|
|
2043
2021
|
|
|
2044
2022
|
// Cap fee-free surplus at remaining balance. Non-fee-free funds leave first.
|
|
2045
|
-
// slither-disable-next-line reentrancy-no-eth,reentrancy-eth,reentrancy-benign
|
|
2046
2023
|
_capFeeFreeSurplus({projectId: projectId, token: token});
|
|
2047
2024
|
|
|
2048
2025
|
// Take a fee from the `amountPaidOut`, if needed.
|
|
2049
2026
|
// The net amount is the final amount withdrawn after the fee has been taken.
|
|
2050
|
-
// slither-disable-next-line reentrancy-events
|
|
2051
2027
|
netAmountPaidOut = amountPaidOut
|
|
2052
2028
|
- (_isFeeless(owner) || _isFeeless(beneficiary)
|
|
2053
2029
|
? 0
|
|
@@ -2092,7 +2068,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
|
|
|
2092
2068
|
if (token == JBConstants.NATIVE_TOKEN) return;
|
|
2093
2069
|
|
|
2094
2070
|
// Revert if the callee returned without consuming the full forwarded ERC-20 amount.
|
|
2095
|
-
// slither-disable-next-line calls-loop
|
|
2096
2071
|
uint256 allowance = IERC20(token).allowance({owner: address(this), spender: to});
|
|
2097
2072
|
if (allowance != 0) revert JBMultiTerminal_TemporaryAllowanceNotConsumed(token, to, allowance);
|
|
2098
2073
|
}
|
package/src/JBPermissions.sol
CHANGED
|
@@ -17,8 +17,7 @@ contract JBPermissions is ERC2771Context, IJBPermissions {
|
|
|
17
17
|
// --------------------------- custom errors ------------------------- //
|
|
18
18
|
//*********************************************************************//
|
|
19
19
|
|
|
20
|
-
error
|
|
21
|
-
error JBPermissions_NoZeroPermission();
|
|
20
|
+
error JBPermissions_NoZeroPermission(address account, address operator, uint256 projectId);
|
|
22
21
|
error JBPermissions_PermissionIdOutOfBounds(uint256 permissionId);
|
|
23
22
|
error JBPermissions_Unauthorized(address account, address operator, uint256 projectId, uint256 permissionId);
|
|
24
23
|
|
|
@@ -69,7 +68,11 @@ contract JBPermissions is ERC2771Context, IJBPermissions {
|
|
|
69
68
|
uint256 packed = _packedPermissions(permissionsData.permissionIds);
|
|
70
69
|
|
|
71
70
|
// Make sure the 0 permission is not set.
|
|
72
|
-
if (_includesPermission({permissions: packed, permissionId: 0}))
|
|
71
|
+
if (_includesPermission({permissions: packed, permissionId: 0})) {
|
|
72
|
+
revert JBPermissions_NoZeroPermission({
|
|
73
|
+
account: account, operator: permissionsData.operator, projectId: permissionsData.projectId
|
|
74
|
+
});
|
|
75
|
+
}
|
|
73
76
|
|
|
74
77
|
// Cache the sender.
|
|
75
78
|
address msgSender = _msgSender();
|
package/src/JBPrices.sol
CHANGED
|
@@ -26,9 +26,9 @@ contract JBPrices is JBControlled, JBPermissioned, ERC2771Context, Ownable, IJBP
|
|
|
26
26
|
//*********************************************************************//
|
|
27
27
|
|
|
28
28
|
error JBPrices_PriceFeedAlreadyExists(IJBPriceFeed feed);
|
|
29
|
-
error JBPrices_PriceFeedNotFound();
|
|
30
|
-
error JBPrices_ZeroPricingCurrency();
|
|
31
|
-
error JBPrices_ZeroUnitCurrency();
|
|
29
|
+
error JBPrices_PriceFeedNotFound(uint256 projectId, uint256 pricingCurrency, uint256 unitCurrency);
|
|
30
|
+
error JBPrices_ZeroPricingCurrency(uint256 projectId, uint256 pricingCurrency);
|
|
31
|
+
error JBPrices_ZeroUnitCurrency(uint256 projectId, uint256 unitCurrency);
|
|
32
32
|
|
|
33
33
|
//*********************************************************************//
|
|
34
34
|
// ------------------------- public constants ------------------------ //
|
|
@@ -111,20 +111,23 @@ contract JBPrices is JBControlled, JBPermissioned, ERC2771Context, Ownable, IJBP
|
|
|
111
111
|
projectId == DEFAULT_PROJECT_ID ? _checkOwner() : _onlyControllerOf(projectId);
|
|
112
112
|
|
|
113
113
|
// Make sure the pricing currency isn't 0.
|
|
114
|
-
if (pricingCurrency == 0)
|
|
114
|
+
if (pricingCurrency == 0) {
|
|
115
|
+
revert JBPrices_ZeroPricingCurrency({projectId: projectId, pricingCurrency: pricingCurrency});
|
|
116
|
+
}
|
|
115
117
|
|
|
116
118
|
// Make sure the unit currency isn't 0.
|
|
117
|
-
if (unitCurrency == 0) revert JBPrices_ZeroUnitCurrency();
|
|
119
|
+
if (unitCurrency == 0) revert JBPrices_ZeroUnitCurrency({projectId: projectId, unitCurrency: unitCurrency});
|
|
118
120
|
|
|
119
121
|
// Make sure there isn't already a default price feed for the pair or its inverse.
|
|
120
122
|
if (
|
|
121
123
|
priceFeedFor[DEFAULT_PROJECT_ID][pricingCurrency][unitCurrency] != IJBPriceFeed(address(0))
|
|
122
124
|
|| priceFeedFor[DEFAULT_PROJECT_ID][unitCurrency][pricingCurrency] != IJBPriceFeed(address(0))
|
|
123
125
|
) {
|
|
124
|
-
revert JBPrices_PriceFeedAlreadyExists(
|
|
125
|
-
|
|
126
|
+
revert JBPrices_PriceFeedAlreadyExists({
|
|
127
|
+
feed: priceFeedFor[DEFAULT_PROJECT_ID][pricingCurrency][unitCurrency] != IJBPriceFeed(address(0))
|
|
126
128
|
? priceFeedFor[DEFAULT_PROJECT_ID][pricingCurrency][unitCurrency]
|
|
127
|
-
: priceFeedFor[DEFAULT_PROJECT_ID][unitCurrency][pricingCurrency]
|
|
129
|
+
: priceFeedFor[DEFAULT_PROJECT_ID][unitCurrency][pricingCurrency]
|
|
130
|
+
});
|
|
128
131
|
}
|
|
129
132
|
|
|
130
133
|
// Make sure this project doesn't already have a price feed for the pair or its inverse.
|
|
@@ -132,10 +135,11 @@ contract JBPrices is JBControlled, JBPermissioned, ERC2771Context, Ownable, IJBP
|
|
|
132
135
|
priceFeedFor[projectId][pricingCurrency][unitCurrency] != IJBPriceFeed(address(0))
|
|
133
136
|
|| priceFeedFor[projectId][unitCurrency][pricingCurrency] != IJBPriceFeed(address(0))
|
|
134
137
|
) {
|
|
135
|
-
revert JBPrices_PriceFeedAlreadyExists(
|
|
136
|
-
|
|
138
|
+
revert JBPrices_PriceFeedAlreadyExists({
|
|
139
|
+
feed: priceFeedFor[projectId][pricingCurrency][unitCurrency] != IJBPriceFeed(address(0))
|
|
137
140
|
? priceFeedFor[projectId][pricingCurrency][unitCurrency]
|
|
138
|
-
: priceFeedFor[projectId][unitCurrency][pricingCurrency]
|
|
141
|
+
: priceFeedFor[projectId][unitCurrency][pricingCurrency]
|
|
142
|
+
});
|
|
139
143
|
}
|
|
140
144
|
|
|
141
145
|
// Price feed immutability is by design to prevent admin-key attacks on price oracles.
|
|
@@ -212,7 +216,9 @@ contract JBPrices is JBControlled, JBPermissioned, ERC2771Context, Ownable, IJBP
|
|
|
212
216
|
}
|
|
213
217
|
|
|
214
218
|
// No price feed available, revert.
|
|
215
|
-
revert JBPrices_PriceFeedNotFound(
|
|
219
|
+
revert JBPrices_PriceFeedNotFound({
|
|
220
|
+
projectId: projectId, pricingCurrency: pricingCurrency, unitCurrency: unitCurrency
|
|
221
|
+
});
|
|
216
222
|
}
|
|
217
223
|
|
|
218
224
|
//*********************************************************************//
|
package/src/JBRulesets.sol
CHANGED
|
@@ -123,7 +123,7 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
123
123
|
|
|
124
124
|
// Weight cut percent must be less than or equal to 100%.
|
|
125
125
|
if (weightCutPercent > JBConstants.MAX_WEIGHT_CUT_PERCENT) {
|
|
126
|
-
revert JBRulesets_InvalidWeightCutPercent(weightCutPercent);
|
|
126
|
+
revert JBRulesets_InvalidWeightCutPercent({percent: weightCutPercent});
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
// Weight must fit into a uint112.
|
|
@@ -137,7 +137,7 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
137
137
|
// Make sure the min start date fits in a uint48, and that the start date of the following ruleset will also fit
|
|
138
138
|
// within the max.
|
|
139
139
|
if (mustStartAtOrAfter + duration > type(uint48).max) {
|
|
140
|
-
revert JBRulesets_InvalidRulesetEndTime(mustStartAtOrAfter + duration, type(uint48).max);
|
|
140
|
+
revert JBRulesets_InvalidRulesetEndTime({timestamp: mustStartAtOrAfter + duration, limit: type(uint48).max});
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
// Approval hook should be a valid contract, supporting the correct interface
|
|
@@ -152,7 +152,7 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
152
152
|
// with the
|
|
153
153
|
// wrong interface
|
|
154
154
|
} catch {
|
|
155
|
-
revert JBRulesets_InvalidRulesetApprovalHook(approvalHook); // No ERC165 support
|
|
155
|
+
revert JBRulesets_InvalidRulesetApprovalHook({hook: approvalHook}); // No ERC165 support
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
158
|
|
|
@@ -217,7 +217,6 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
217
217
|
_getStructFor({projectId: projectId, rulesetId: rulesetId, withMetadata: false});
|
|
218
218
|
|
|
219
219
|
// Nothing to cache if the target ruleset doesn't have a duration or a weight cut percent.
|
|
220
|
-
// slither-disable-next-line incorrect-equality
|
|
221
220
|
if (targetRuleset.duration == 0 || targetRuleset.weightCutPercent == 0) return;
|
|
222
221
|
|
|
223
222
|
// Get a reference to the current cache.
|
|
@@ -356,7 +355,6 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
356
355
|
/// @return ruleset The project's current ruleset.
|
|
357
356
|
function currentOf(uint256 projectId) external view override returns (JBRuleset memory ruleset) {
|
|
358
357
|
// If the project does not have a ruleset, return an empty struct.
|
|
359
|
-
// slither-disable-next-line incorrect-equality
|
|
360
358
|
if (latestRulesetIdOf[projectId] == 0) {
|
|
361
359
|
return _getStructFor({projectId: 0, rulesetId: 0, withMetadata: false});
|
|
362
360
|
}
|
|
@@ -375,7 +373,6 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
375
373
|
|
|
376
374
|
// Check to see if this ruleset's approval hook is approved if it exists.
|
|
377
375
|
// If so, return it.
|
|
378
|
-
// slither-disable-next-line incorrect-equality
|
|
379
376
|
if (approvalStatus == JBApprovalStatus.Approved || approvalStatus == JBApprovalStatus.Empty) {
|
|
380
377
|
return ruleset;
|
|
381
378
|
}
|
|
@@ -413,7 +410,6 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
413
410
|
}
|
|
414
411
|
|
|
415
412
|
// If the base has no duration, it's still the current one.
|
|
416
|
-
// slither-disable-next-line incorrect-equality
|
|
417
413
|
if (ruleset.duration == 0) return ruleset;
|
|
418
414
|
|
|
419
415
|
// Return a simulation of the current ruleset.
|
|
@@ -466,7 +462,6 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
466
462
|
/// @return ruleset The struct for the project's upcoming ruleset.
|
|
467
463
|
function upcomingOf(uint256 projectId) external view override returns (JBRuleset memory ruleset) {
|
|
468
464
|
// If the project does not have a latest ruleset, return an empty struct.
|
|
469
|
-
// slither-disable-next-line incorrect-equality
|
|
470
465
|
if (latestRulesetIdOf[projectId] == 0) {
|
|
471
466
|
return _getStructFor({projectId: 0, rulesetId: 0, withMetadata: false});
|
|
472
467
|
}
|
|
@@ -487,7 +482,6 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
487
482
|
|
|
488
483
|
// If the approval hook is empty, expects approval, or has approved the ruleset, return it.
|
|
489
484
|
if (
|
|
490
|
-
// slither-disable-next-line incorrect-equality
|
|
491
485
|
approvalStatus == JBApprovalStatus.Approved || approvalStatus == JBApprovalStatus.ApprovalExpected
|
|
492
486
|
|| approvalStatus == JBApprovalStatus.Empty
|
|
493
487
|
) return ruleset;
|
|
@@ -510,7 +504,6 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
510
504
|
}
|
|
511
505
|
|
|
512
506
|
// There's no queued if the current has a duration of 0.
|
|
513
|
-
// slither-disable-next-line incorrect-equality
|
|
514
507
|
if (ruleset.duration == 0) return _getStructFor({projectId: 0, rulesetId: 0, withMetadata: false});
|
|
515
508
|
|
|
516
509
|
// Get a reference to the approval status.
|
|
@@ -518,7 +511,6 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
518
511
|
|
|
519
512
|
// Check to see if this ruleset's approval hook hasn't failed.
|
|
520
513
|
// If so, return a ruleset based on it.
|
|
521
|
-
// slither-disable-next-line incorrect-equality
|
|
522
514
|
if (approvalStatus == JBApprovalStatus.Approved || approvalStatus == JBApprovalStatus.Empty) {
|
|
523
515
|
return _simulateCycledRulesetBasedOn({projectId: projectId, baseRuleset: ruleset, allowMidRuleset: false});
|
|
524
516
|
}
|
|
@@ -528,7 +520,6 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
528
520
|
ruleset = _getStructFor({projectId: projectId, rulesetId: ruleset.basedOnId, withMetadata: true});
|
|
529
521
|
|
|
530
522
|
// There's no queued if the base, which must still be the current, has a duration of 0.
|
|
531
|
-
// slither-disable-next-line incorrect-equality
|
|
532
523
|
if (ruleset.duration == 0) return _getStructFor({projectId: 0, rulesetId: 0, withMetadata: false});
|
|
533
524
|
|
|
534
525
|
// Return a simulated cycled ruleset.
|
|
@@ -557,7 +548,6 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
557
548
|
returns (uint256)
|
|
558
549
|
{
|
|
559
550
|
// A subsequent ruleset to one with a duration of 0 should be the next number.
|
|
560
|
-
// slither-disable-next-line incorrect-equality
|
|
561
551
|
if (baseRulesetDuration == 0) {
|
|
562
552
|
return baseRulesetCycleNumber + 1;
|
|
563
553
|
}
|
|
@@ -585,7 +575,6 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
585
575
|
returns (uint256 start)
|
|
586
576
|
{
|
|
587
577
|
// A subsequent ruleset to one with a duration of 0 should start as soon as possible.
|
|
588
|
-
// slither-disable-next-line incorrect-equality
|
|
589
578
|
if (baseRulesetDuration == 0) return mustStartAtOrAfter;
|
|
590
579
|
|
|
591
580
|
// The time when the ruleset immediately after the specified ruleset starts.
|
|
@@ -598,7 +587,6 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
598
587
|
|
|
599
588
|
// The amount of seconds since the `mustStartAtOrAfter` time which results in a start time that might satisfy
|
|
600
589
|
// the specified limits.
|
|
601
|
-
// slither-disable-next-line weak-prng
|
|
602
590
|
uint256 timeFromImmediateStartMultiple = (mustStartAtOrAfter - nextImmediateStart) % baseRulesetDuration;
|
|
603
591
|
|
|
604
592
|
// A reference to the first possible start timestamp.
|
|
@@ -634,7 +622,6 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
634
622
|
returns (uint256 weight)
|
|
635
623
|
{
|
|
636
624
|
// A subsequent ruleset to one with a duration of 0 should have the next possible weight.
|
|
637
|
-
// slither-disable-next-line incorrect-equality
|
|
638
625
|
if (baseRulesetDuration == 0) {
|
|
639
626
|
return mulDiv(
|
|
640
627
|
baseRulesetWeight,
|
|
@@ -647,7 +634,6 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
647
634
|
weight = baseRulesetWeight;
|
|
648
635
|
|
|
649
636
|
// If the weight cut percent is 0, the weight doesn't change.
|
|
650
|
-
// slither-disable-next-line incorrect-equality
|
|
651
637
|
if (baseRulesetWeightCutPercent == 0) return weight;
|
|
652
638
|
|
|
653
639
|
// The difference between the start of the base ruleset and the proposed start.
|
|
@@ -678,7 +664,7 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
678
664
|
// If too many iterations remain after cache lookup, require the cache to be populated first.
|
|
679
665
|
// This prevents gas exhaustion for short-duration rulesets with large cycle counts.
|
|
680
666
|
if (weightCutMultiple > _WEIGHT_CUT_MULTIPLE_CACHE_LOOKUP_THRESHOLD) {
|
|
681
|
-
revert JBRulesets_WeightCacheRequired(projectId);
|
|
667
|
+
revert JBRulesets_WeightCacheRequired({projectId: projectId});
|
|
682
668
|
}
|
|
683
669
|
|
|
684
670
|
// Cache the cut factor and max percent to avoid recomputing each iteration.
|
|
@@ -719,7 +705,6 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
719
705
|
uint256 latestId = latestRulesetIdOf[projectId];
|
|
720
706
|
|
|
721
707
|
// If the project doesn't have a ruleset yet, initialize one.
|
|
722
|
-
// slither-disable-next-line incorrect-equality
|
|
723
708
|
if (latestId == 0) {
|
|
724
709
|
// Use an empty ruleset as the base.
|
|
725
710
|
return _initializeRulesetFor({
|
|
@@ -807,7 +792,6 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
807
792
|
internal
|
|
808
793
|
{
|
|
809
794
|
// If there is no base, initialize a first ruleset.
|
|
810
|
-
// slither-disable-next-line incorrect-equality
|
|
811
795
|
if (baseRuleset.cycleNumber == 0) {
|
|
812
796
|
// Set fresh intrinsic properties.
|
|
813
797
|
_packAndStoreIntrinsicPropertiesOf({
|
|
@@ -910,7 +894,6 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
910
894
|
/// @return The approval status of the project.
|
|
911
895
|
function _approvalStatusOf(uint256 projectId, JBRuleset memory ruleset) internal view returns (JBApprovalStatus) {
|
|
912
896
|
// If there is no ruleset ID to check the approval hook of, the approval hook is empty.
|
|
913
|
-
// slither-disable-next-line incorrect-equality
|
|
914
897
|
if (ruleset.basedOnId == 0) return JBApprovalStatus.Empty;
|
|
915
898
|
|
|
916
899
|
// Read only the packed user properties to extract the approval hook address,
|
|
@@ -928,7 +911,6 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
928
911
|
// Wrap in try/catch to prevent a reverting approval hook from permanently freezing the project.
|
|
929
912
|
// Note: A malicious hook that consumes all gas (e.g. infinite loop) could still DoS via gas exhaustion.
|
|
930
913
|
// This is accepted risk since the project owner chose their own approval hook.
|
|
931
|
-
// slither-disable-next-line calls-loop
|
|
932
914
|
try approvalHook.approvalStatusOf({projectId: projectId, ruleset: ruleset}) returns (JBApprovalStatus status) {
|
|
933
915
|
return status;
|
|
934
916
|
} catch {
|
|
@@ -988,7 +970,6 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
988
970
|
returns (JBRuleset memory ruleset)
|
|
989
971
|
{
|
|
990
972
|
// Return an empty ruleset if the specified `rulesetId` is 0.
|
|
991
|
-
// slither-disable-next-line incorrect-equality
|
|
992
973
|
if (rulesetId == 0) return ruleset;
|
|
993
974
|
|
|
994
975
|
// forge-lint: disable-next-line(unsafe-typecast)
|
|
@@ -1104,12 +1085,10 @@ contract JBRulesets is JBControlled, IJBRulesets {
|
|
|
1104
1085
|
JBRuleset memory ruleset = _getStructFor({projectId: projectId, rulesetId: rulesetId, withMetadata: false});
|
|
1105
1086
|
|
|
1106
1087
|
// There is no upcoming ruleset if the latest ruleset has already started.
|
|
1107
|
-
// slither-disable-next-line incorrect-equality
|
|
1108
1088
|
// forge-lint: disable-next-line(block-timestamp)
|
|
1109
1089
|
if (block.timestamp >= ruleset.start) return 0;
|
|
1110
1090
|
|
|
1111
1091
|
// If this is the first ruleset, it is queued.
|
|
1112
|
-
// slither-disable-next-line incorrect-equality
|
|
1113
1092
|
if (ruleset.cycleNumber == 1) return rulesetId;
|
|
1114
1093
|
|
|
1115
1094
|
// Get a reference to the ID of the ruleset the latest ruleset was based on.
|
package/src/JBSplits.sol
CHANGED
|
@@ -20,8 +20,8 @@ contract JBSplits is JBControlled, IJBSplits {
|
|
|
20
20
|
//*********************************************************************//
|
|
21
21
|
|
|
22
22
|
error JBSplits_PreviousLockedSplitsNotIncluded(uint256 projectId, uint256 rulesetId);
|
|
23
|
-
error JBSplits_TotalPercentExceeds100();
|
|
24
|
-
error JBSplits_ZeroSplitPercent();
|
|
23
|
+
error JBSplits_TotalPercentExceeds100(uint256 projectId, uint256 rulesetId, uint256 groupId, uint256 percentTotal);
|
|
24
|
+
error JBSplits_ZeroSplitPercent(uint256 projectId, uint256 rulesetId, uint256 groupId, uint256 splitIndex);
|
|
25
25
|
|
|
26
26
|
//*********************************************************************//
|
|
27
27
|
// ------------------------- public constants ------------------------ //
|
|
@@ -180,7 +180,7 @@ contract JBSplits is JBControlled, IJBSplits {
|
|
|
180
180
|
block.timestamp < currentSplits[i].lockedUntil
|
|
181
181
|
&& !_includesLockedSplits({splits: splits, lockedSplit: currentSplits[i]})
|
|
182
182
|
) {
|
|
183
|
-
revert JBSplits_PreviousLockedSplitsNotIncluded(projectId, rulesetId);
|
|
183
|
+
revert JBSplits_PreviousLockedSplitsNotIncluded({projectId: projectId, rulesetId: rulesetId});
|
|
184
184
|
}
|
|
185
185
|
unchecked {
|
|
186
186
|
++i;
|
|
@@ -198,13 +198,21 @@ contract JBSplits is JBControlled, IJBSplits {
|
|
|
198
198
|
JBSplit memory split = splits[i];
|
|
199
199
|
|
|
200
200
|
// The percent should be greater than 0.
|
|
201
|
-
if (split.percent == 0)
|
|
201
|
+
if (split.percent == 0) {
|
|
202
|
+
revert JBSplits_ZeroSplitPercent({
|
|
203
|
+
projectId: projectId, rulesetId: rulesetId, groupId: groupId, splitIndex: i
|
|
204
|
+
});
|
|
205
|
+
}
|
|
202
206
|
|
|
203
207
|
// Add to the `percent` total.
|
|
204
208
|
percentTotal += split.percent;
|
|
205
209
|
|
|
206
210
|
// Ensure the total does not exceed 100%.
|
|
207
|
-
if (percentTotal > JBConstants.SPLITS_TOTAL_PERCENT)
|
|
211
|
+
if (percentTotal > JBConstants.SPLITS_TOTAL_PERCENT) {
|
|
212
|
+
revert JBSplits_TotalPercentExceeds100({
|
|
213
|
+
projectId: projectId, rulesetId: rulesetId, groupId: groupId, percentTotal: percentTotal
|
|
214
|
+
});
|
|
215
|
+
}
|
|
208
216
|
|
|
209
217
|
uint256 packedSplitParts1;
|
|
210
218
|
|