@bananapus/core-v6 0.0.38 → 0.0.39

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.
Files changed (46) hide show
  1. package/foundry.toml +1 -1
  2. package/package.json +1 -1
  3. package/src/JBChainlinkV3PriceFeed.sol +4 -1
  4. package/src/JBChainlinkV3SequencerPriceFeed.sol +4 -2
  5. package/src/JBController.sol +52 -43
  6. package/src/JBDeadline.sol +4 -4
  7. package/src/JBDirectory.sol +34 -32
  8. package/src/JBERC20.sol +5 -4
  9. package/src/JBFeelessAddresses.sol +6 -3
  10. package/src/JBFundAccessLimits.sol +25 -21
  11. package/src/JBMultiTerminal.sol +53 -50
  12. package/src/JBPermissions.sol +34 -37
  13. package/src/JBPrices.sol +23 -18
  14. package/src/JBProjects.sol +6 -3
  15. package/src/JBRulesets.sol +44 -41
  16. package/src/JBSplits.sol +18 -16
  17. package/src/JBTerminalStore.sol +26 -19
  18. package/src/JBTokens.sol +36 -26
  19. package/src/abstract/JBControlled.sol +3 -1
  20. package/src/abstract/JBPermissioned.sol +3 -1
  21. package/src/enums/JBApprovalStatus.sol +7 -1
  22. package/src/interfaces/IJBController.sol +3 -2
  23. package/src/interfaces/IJBDirectory.sol +3 -1
  24. package/src/interfaces/IJBMultiTerminal.sol +3 -2
  25. package/src/interfaces/IJBPermissions.sol +2 -1
  26. package/src/interfaces/IJBPrices.sol +3 -1
  27. package/src/interfaces/IJBRulesets.sol +2 -1
  28. package/src/interfaces/IJBSplits.sol +2 -1
  29. package/src/interfaces/IJBTerminal.sol +3 -1
  30. package/src/interfaces/IJBTerminalStore.sol +3 -1
  31. package/src/interfaces/IJBTokens.sol +2 -1
  32. package/src/libraries/JBCashOuts.sol +6 -1
  33. package/src/libraries/JBConstants.sol +12 -3
  34. package/src/libraries/JBCurrencyIds.sol +2 -0
  35. package/src/libraries/JBFees.sol +5 -1
  36. package/src/libraries/JBFixedPointNumber.sol +2 -0
  37. package/src/libraries/JBPayoutSplitGroupLib.sol +5 -2
  38. package/src/libraries/JBRulesetMetadataResolver.sol +4 -0
  39. package/src/libraries/JBSplitGroupIds.sol +2 -1
  40. package/src/libraries/JBSurplus.sol +3 -1
  41. package/src/periphery/JBMatchingPriceFeed.sol +2 -0
  42. package/src/structs/JBAccountingContext.sol +7 -4
  43. package/src/structs/JBFundAccessLimitGroup.sol +10 -17
  44. package/src/structs/JBRuleset.sol +18 -26
  45. package/src/structs/JBRulesetConfig.sol +13 -25
  46. package/src/structs/JBRulesetMetadata.sol +25 -32
package/foundry.toml CHANGED
@@ -17,7 +17,7 @@ fail_on_revert = false
17
17
  ethereum = "${RPC_ETHEREUM_MAINNET}"
18
18
 
19
19
  [lint]
20
- exclude_lints = ["block-timestamp", "mixed-case-variable", "pascal-case-struct"]
20
+ exclude_lints = ["mixed-case-variable", "pascal-case-struct"]
21
21
  [fmt]
22
22
  number_underscore = "thousands"
23
23
  multiline_func_header = "all"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bananapus/core-v6",
3
- "version": "0.0.38",
3
+ "version": "0.0.39",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -6,7 +6,9 @@ import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interf
6
6
  import {IJBPriceFeed} from "./interfaces/IJBPriceFeed.sol";
7
7
  import {JBFixedPointNumber} from "./libraries/JBFixedPointNumber.sol";
8
8
 
9
- /// @notice An `IJBPriceFeed` implementation that reports prices from a Chainlink `AggregatorV3Interface`.
9
+ /// @notice A price feed adapter that reads from a Chainlink V3 aggregator. Reverts if the price is stale (older than
10
+ /// `THRESHOLD` seconds), negative, or from an incomplete round — protecting against serving outdated oracle data.
11
+ /// Used by `JBPrices` to convert between currencies (e.g. ETH/USD).
10
12
  contract JBChainlinkV3PriceFeed is IJBPriceFeed {
11
13
  // A library that provides utility for fixed point numbers.
12
14
  using JBFixedPointNumber for uint256;
@@ -60,6 +62,7 @@ contract JBChainlinkV3PriceFeed is IJBPriceFeed {
60
62
  if (answeredInRound < roundId) revert JBChainlinkV3PriceFeed_IncompleteRound();
61
63
 
62
64
  // Make sure the price's update threshold is met.
65
+ // forge-lint: disable-next-line(block-timestamp)
63
66
  if (block.timestamp > THRESHOLD + updatedAt) {
64
67
  revert JBChainlinkV3PriceFeed_StalePrice(block.timestamp, THRESHOLD, updatedAt);
65
68
  }
@@ -6,8 +6,9 @@ import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interf
6
6
 
7
7
  import {JBChainlinkV3PriceFeed} from "./JBChainlinkV3PriceFeed.sol";
8
8
 
9
- /// @notice An `IJBPriceFeed` implementation that reports prices from a Chainlink `AggregatorV3Interface` from
10
- /// optimistic sequencers.
9
+ /// @notice Extends `JBChainlinkV3PriceFeed` with L2 sequencer uptime checks (for Optimism, Arbitrum, etc.). Reverts if
10
+ /// the sequencer is down or has not been back online for at least `GRACE_PERIOD_TIME` seconds — preventing stale
11
+ /// prices from being used immediately after an outage.
11
12
  contract JBChainlinkV3SequencerPriceFeed is JBChainlinkV3PriceFeed {
12
13
  //*********************************************************************//
13
14
  // --------------------------- custom errors ------------------------- //
@@ -64,6 +65,7 @@ contract JBChainlinkV3SequencerPriceFeed is JBChainlinkV3PriceFeed {
64
65
  if (startedAt == 0) revert JBChainlinkV3SequencerPriceFeed_InvalidRound();
65
66
 
66
67
  // Revert if sequencer has too recently restarted or is currently down.
68
+ // forge-lint: disable-next-line(block-timestamp)
67
69
  if (block.timestamp <= GRACE_PERIOD_TIME + startedAt || answer != 0) {
68
70
  revert JBChainlinkV3SequencerPriceFeed_SequencerDownOrRestarting(
69
71
  block.timestamp, GRACE_PERIOD_TIME, startedAt
@@ -41,8 +41,13 @@ import {JBSplitGroup} from "./structs/JBSplitGroup.sol";
41
41
  import {JBSplitHookContext} from "./structs/JBSplitHookContext.sol";
42
42
  import {JBTerminalConfig} from "./structs/JBTerminalConfig.sol";
43
43
 
44
- /// @notice `JBController` coordinates rulesets and project tokens, and is the entry point for most operations related
45
- /// to rulesets and project tokens.
44
+ /// @notice The orchestrator for every Juicebox project's lifecycle. Use the controller to launch a project, queue new
45
+ /// rulesets (funding cycles), mint or burn tokens, deploy an ERC-20, distribute reserved tokens, and manage
46
+ /// permissions. The controller coordinates between the terminal (money), rulesets (rules), tokens (issuance), and
47
+ /// splits (distribution).
48
+ /// @dev Supports ERC-2771 meta-transactions. Implements `IJBMigratable` for controller-to-controller migration.
49
+ /// An omnichain deployer address is trusted to launch and queue rulesets on behalf of any project for cross-chain
50
+ /// coordination.
46
51
  contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigratable {
47
52
  // A library that parses packed ruleset metadata into a friendlier format.
48
53
  using JBRulesetMetadataResolver for JBRuleset;
@@ -166,8 +171,9 @@ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigra
166
171
  // ---------------------- external transactions ---------------------- //
167
172
  //*********************************************************************//
168
173
 
169
- /// @notice Add a price feed for a project.
170
- /// @dev Can only be called by the project's owner or an address with the owner's permission to `ADD_PRICE_FEED`.
174
+ /// @notice Registers a price feed so the project can use a new currency for payout limits or surplus allowances.
175
+ /// @dev Can only be called by the project's owner or an operator with `ADD_PRICE_FEED` permission. The current
176
+ /// ruleset must have `allowAddPriceFeed` enabled.
171
177
  /// @param projectId The ID of the project to add the feed for.
172
178
  /// @param pricingCurrency The currency the feed's output price is in terms of.
173
179
  /// @param unitCurrency The currency being priced by the feed.
@@ -234,9 +240,9 @@ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigra
234
240
  }
235
241
  }
236
242
 
237
- /// @notice Burns a project's tokens or credits from the specific holder's balance.
238
- /// @dev Can only be called by the holder, an address with the holder's permission to `BURN_TOKENS`, or a project's
239
- /// terminal.
243
+ /// @notice Burns a holder's project tokens (or credits), permanently removing them from supply. Used by terminals
244
+ /// during cash outs, or directly by holders who want to burn voluntarily.
245
+ /// @dev Can only be called by the holder, an operator with `BURN_TOKENS` permission, or a project terminal.
240
246
  /// @param holder The address whose tokens are being burned.
241
247
  /// @param projectId The ID of the project whose tokens are being burned.
242
248
  /// @param tokenCount The number of tokens to burn.
@@ -269,8 +275,9 @@ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigra
269
275
  TOKENS.burnFrom({holder: holder, projectId: projectId, count: tokenCount});
270
276
  }
271
277
 
272
- /// @notice Redeem credits to claim tokens into a `beneficiary`'s account.
273
- /// @dev Can only be called by the credit holder or an address with the holder's permission to `CLAIM_TOKENS`.
278
+ /// @notice Converts internal credits into the project's ERC-20 token, transferring them to the beneficiary's
279
+ /// wallet. Credits and ERC-20 tokens are interchangeable this just makes them transferable/tradeable.
280
+ /// @dev Can only be called by the credit holder or an operator with `CLAIM_TOKENS` permission.
274
281
  /// @param holder The address to redeem credits from.
275
282
  /// @param projectId The ID of the project whose tokens are being claimed.
276
283
  /// @param tokenCount The number of tokens to claim.
@@ -290,9 +297,10 @@ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigra
290
297
  TOKENS.claimTokensFor({holder: holder, projectId: projectId, count: tokenCount, beneficiary: beneficiary});
291
298
  }
292
299
 
293
- /// @notice Deploys an ERC-20 token for a project. It will be used when claiming tokens (with credits).
294
- /// @dev Deploys the project's ERC-20 contract.
295
- /// @dev Can only be called by the project's owner or an address with the owner's permission to `DEPLOY_ERC20`.
300
+ /// @notice Deploys a new ERC-20 token for a project. Once deployed, holders can claim their credits as this token.
301
+ /// Includes ERC20Votes (governance) and ERC20Permit (gasless approvals).
302
+ /// @dev Can only be called by the project's owner or an operator with `DEPLOY_ERC20` permission.
303
+ /// @dev Each project can only have one ERC-20 deployed — calling this again after deployment will revert.
296
304
  /// @param projectId The ID of the project to deploy the ERC-20 for.
297
305
  /// @param name The ERC-20's name.
298
306
  /// @param symbol The ERC-20's symbol.
@@ -368,10 +376,11 @@ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigra
368
376
  }
369
377
  }
370
378
 
371
- /// @notice Creates a project.
372
- /// @dev This will mint the project's ERC-721 to the `owner`'s address, queue the specified rulesets, and set up the
373
- /// specified splits and terminals. Each operation within this transaction can be done in sequence separately.
374
- /// @dev Anyone can deploy a project to any `owner`'s address.
379
+ /// @notice Creates a new Juicebox project in one transaction — mints the project NFT, queues initial rulesets,
380
+ /// and
381
+ /// configures terminals. This is the primary entry point for launching a project.
382
+ /// @dev Anyone can call this on behalf of any owner. Each sub-operation (mint, queue, configure) can also be done
383
+ /// individually if needed.
375
384
  /// @param owner The project's owner. The project ERC-721 will be minted to this address.
376
385
  /// @param projectUri The project's metadata URI. This is typically an IPFS hash, optionally with the `ipfs://`
377
386
  /// prefix. This can be updated by the project's owner.
@@ -414,10 +423,10 @@ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigra
414
423
  });
415
424
  }
416
425
 
417
- /// @notice Queue a project's initial rulesets and set up terminals for it. Projects which already have rulesets
418
- /// should use `queueRulesetsOf(...)`.
419
- /// @dev Each operation within this transaction can be done in sequence separately.
420
- /// @dev Can only be called by the project's owner or an address with the owner's permission to `LAUNCH_RULESETS`.
426
+ /// @notice Queues the first rulesets for an existing project and configures its terminals. For projects that
427
+ /// already have active rulesets, use `queueRulesetsOf(...)` instead.
428
+ /// @dev Can only be called by the project's owner or an operator with `LAUNCH_RULESETS` permission.
429
+ /// @dev Each sub-operation can also be done individually if needed.
421
430
  /// @param projectId The ID of the project to launch rulesets for.
422
431
  /// @param projectUri The project's metadata URI. Pass an empty string to leave it unchanged.
423
432
  /// @param rulesetConfigurations The rulesets to queue.
@@ -508,12 +517,10 @@ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigra
508
517
  if (pendingReservedTokenBalance != 0) revert JBController_PendingReservedTokens(pendingReservedTokenBalance);
509
518
  }
510
519
 
511
- /// @notice Add new project tokens or credits to the specified beneficiary's balance. Optionally, reserve a portion
512
- /// according to the ruleset's reserved percent.
513
- /// @dev Can only be called by the project's owner, an address with the owner's permission to `MINT_TOKENS`, one of
514
- /// the project's terminals, or the project's data hook.
515
- /// @dev If the ruleset's metadata has `allowOwnerMinting` set to `false`, this function can only be called by the
516
- /// project's terminals or data hook.
520
+ /// @notice Mints new project tokens to a beneficiary. Optionally reserves a portion according to the ruleset's
521
+ /// reserved percent (which accumulates until `sendReservedTokensToSplitsOf` is called).
522
+ /// @dev Can be called by the project owner, an operator with `MINT_TOKENS` permission, a project terminal, or the
523
+ /// data hook. If `allowOwnerMinting` is false in the current ruleset, only terminals and the data hook can mint.
517
524
  /// @param projectId The ID of the project whose tokens are being minted.
518
525
  /// @param tokenCount The number of tokens to mint, including any reserved tokens.
519
526
  /// @param beneficiary The address which will receive the (non-reserved) tokens.
@@ -594,9 +601,9 @@ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigra
594
601
  }
595
602
  }
596
603
 
597
- /// @notice Add one or more rulesets to the end of a project's ruleset queue. Rulesets take effect after the
598
- /// previous ruleset in the queue ends, and only if they are approved by the previous ruleset's approval hook.
599
- /// @dev Can only be called by the project's owner or an address with the owner's permission to `QUEUE_RULESETS`.
604
+ /// @notice Queues new rulesets to take effect after the current one ends. Each queued ruleset must be approved by
605
+ /// the previous ruleset's approval hook (if one is set) before it can take effect.
606
+ /// @dev Can only be called by the project's owner or an operator with `QUEUE_RULESETS` permission.
600
607
  /// @param projectId The ID of the project to queue rulesets for.
601
608
  /// @param rulesetConfigurations The rulesets to queue.
602
609
  /// @param memo A memo to pass along to the emitted event.
@@ -628,17 +635,18 @@ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigra
628
635
  emit QueueRulesets({rulesetId: rulesetId, projectId: projectId, memo: memo, caller: _msgSender()});
629
636
  }
630
637
 
631
- /// @notice Sends a project's pending reserved tokens to its reserved token splits.
632
- /// @dev If the project has no reserved token splits, or if they don't add up to 100%, leftover tokens are sent to
633
- /// the project's owner.
638
+ /// @notice Mints and distributes all pending reserved tokens to the project's reserved token split recipients.
639
+ /// Anyone can call this it's permissionless.
640
+ /// @dev If splits don't add up to 100%, the remainder goes to the project owner.
634
641
  /// @param projectId The ID of the project to send reserved tokens for.
635
642
  /// @return The amount of reserved tokens minted and sent.
636
643
  function sendReservedTokensToSplitsOf(uint256 projectId) external override returns (uint256) {
637
644
  return _sendReservedTokensToSplitsOf(projectId);
638
645
  }
639
646
 
640
- /// @notice Sets a project's split groups. The new split groups must include any current splits which are locked.
641
- /// @dev Can only be called by the project's owner or an address with the owner's permission to `SET_SPLIT_GROUPS`.
647
+ /// @notice Configures how a project distributes payouts and reserved tokens. Locked splits from the current
648
+ /// configuration must be preserved in the new split groups.
649
+ /// @dev Can only be called by the project's owner or an operator with `SET_SPLIT_GROUPS` permission.
642
650
  /// @param projectId The ID of the project to set the split groups of.
643
651
  /// @param rulesetId The ID of the ruleset the split groups should be active in. Use a `rulesetId` of 0 to set the
644
652
  /// default split groups, which are used when a ruleset has no splits set. If there are no default splits and no
@@ -716,8 +724,10 @@ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigra
716
724
  emit SetUri({projectId: projectId, uri: uri, caller: _msgSender()});
717
725
  }
718
726
 
719
- /// @notice Allows a credit holder to transfer credits to another address.
720
- /// @dev Can only be called by the credit holder or an address with the holder's permission to `TRANSFER_CREDITS`.
727
+ /// @notice Transfers internal credits (unclaimed tokens) from one address to another. Credits function like tokens
728
+ /// but live inside the protocol rather than as an ERC-20.
729
+ /// @dev Can only be called by the credit holder or an operator with `TRANSFER_CREDITS` permission. The current
730
+ /// ruleset must not have credit transfers paused.
721
731
  /// @param holder The address to transfer credits from.
722
732
  /// @param projectId The ID of the project whose credits are being transferred.
723
733
  /// @param recipient The address to transfer credits to.
@@ -747,8 +757,7 @@ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigra
747
757
  // ------------------------- external views -------------------------- //
748
758
  //*********************************************************************//
749
759
 
750
- /// @notice Get an array of a project's rulesets (with metadata) up to a maximum array size, sorted from latest to
751
- /// earliest.
760
+ /// @notice Returns a paginated history of a project's rulesets (with decoded metadata), sorted newest-first.
752
761
  /// @param projectId The ID of the project to get the rulesets of.
753
762
  /// @param startingId The ID of the ruleset to begin with. This will be the latest ruleset in the result. If the
754
763
  /// `startingId` is 0, passed, the project's latest ruleset will be used.
@@ -786,7 +795,7 @@ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigra
786
795
  }
787
796
  }
788
797
 
789
- /// @notice A project's currently active ruleset and its metadata.
798
+ /// @notice Returns the ruleset currently governing a project, along with its decoded metadata.
790
799
  /// @param projectId The ID of the project to get the current ruleset of.
791
800
  /// @return ruleset The current ruleset's struct.
792
801
  /// @return metadata The current ruleset's metadata.
@@ -862,21 +871,21 @@ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigra
862
871
  });
863
872
  }
864
873
 
865
- /// @notice Check whether the project's controller can currently be set.
874
+ /// @notice Whether the project's current ruleset allows migrating to a different controller.
866
875
  /// @param projectId The ID of the project to check.
867
876
  /// @return A `bool` which is true if the project allows controllers to be set.
868
877
  function setControllerAllowed(uint256 projectId) external view returns (bool) {
869
878
  return _currentRulesetOf(projectId).expandMetadata().allowSetController;
870
879
  }
871
880
 
872
- /// @notice Check whether the project's terminals can currently be set.
881
+ /// @notice Whether the project's current ruleset allows changing its terminals.
873
882
  /// @param projectId The ID of the project to check.
874
883
  /// @return A `bool` which is true if the project allows terminals to be set.
875
884
  function setTerminalsAllowed(uint256 projectId) external view returns (bool) {
876
885
  return _currentRulesetOf(projectId).expandMetadata().allowSetTerminals;
877
886
  }
878
887
 
879
- /// @notice Gets the a project token's total supply, including pending reserved tokens.
888
+ /// @notice Returns the project's total token supply including tokens that have been reserved but not yet minted.
880
889
  /// @param projectId The ID of the project to get the total token supply of.
881
890
  /// @return The total supply of the project's token, including pending reserved tokens.
882
891
  function totalTokenSupplyWithReservedTokensOf(uint256 projectId) external view override returns (uint256) {
@@ -884,7 +893,7 @@ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigra
884
893
  return TOKENS.totalSupplyOf(projectId) + pendingReservedTokenBalanceOf[projectId];
885
894
  }
886
895
 
887
- /// @notice A project's next ruleset along with its metadata.
896
+ /// @notice Returns the ruleset that will take effect after the current one ends, along with its decoded metadata.
888
897
  /// @dev If an upcoming ruleset isn't found, returns an empty ruleset with all properties set to 0.
889
898
  /// @param projectId The ID of the project to get the next ruleset of.
890
899
  /// @return ruleset The upcoming ruleset's struct.
@@ -7,10 +7,9 @@ import {JBApprovalStatus} from "./enums/JBApprovalStatus.sol";
7
7
  import {IJBRulesetApprovalHook} from "./interfaces/IJBRulesetApprovalHook.sol";
8
8
  import {JBRuleset} from "./structs/JBRuleset.sol";
9
9
 
10
- /// @notice `JBDeadline` is a ruleset approval hook which rejects rulesets if they are not queued at least `duration`
11
- /// seconds before the current ruleset ends. In other words, rulesets must be queued before the deadline to take effect.
12
- /// @dev Project rulesets are stored in a queue. Rulesets take effect after the previous ruleset in the queue ends, and
13
- /// only if they are approved by the previous ruleset's approval hook.
10
+ /// @notice A ruleset approval hook that enforces a queuing deadline. If a new ruleset is not queued at least `DURATION`
11
+ /// seconds before the current ruleset ends, it is rejected and the existing rules continue. This gives token holders
12
+ /// a guaranteed notice period before any project configuration changes take effect.
14
13
  /// @dev If `DURATION` is set longer than the ruleset's cycle duration, no queued ruleset can ever satisfy the deadline
15
14
  /// and the current ruleset will effectively be locked in perpetuity. Choose a `DURATION` shorter than the shortest
16
15
  /// cycle it will govern.
@@ -60,6 +59,7 @@ contract JBDeadline is IJBRulesetApprovalHook {
60
59
  // If we've already passed the deadline, the ruleset is `Approved`.
61
60
  return (ruleset.start - ruleset.id < DURATION)
62
61
  ? JBApprovalStatus.Failed
62
+ // forge-lint: disable-next-line(block-timestamp)
63
63
  : (block.timestamp + DURATION < ruleset.start)
64
64
  ? JBApprovalStatus.ApprovalExpected
65
65
  : JBApprovalStatus.Approved;
@@ -13,9 +13,11 @@ import {IJBPermissions} from "./interfaces/IJBPermissions.sol";
13
13
  import {IJBProjects} from "./interfaces/IJBProjects.sol";
14
14
  import {IJBTerminal} from "./interfaces/IJBTerminal.sol";
15
15
 
16
- /// @notice `JBDirectory` tracks the terminals and the controller used by each project.
17
- /// @dev Tracks which `IJBTerminal`s each project is currently accepting funds through, and which `IJBController` is
18
- /// managing each project's tokens and rulesets.
16
+ /// @notice The routing table for the protocol. Every project registers which terminals accept its payments and which
17
+ /// controller manages its rulesets and tokens. Frontends and other contracts use the directory to discover where to
18
+ /// send funds for a given project and token.
19
+ /// @dev Also manages controller migration — when a project upgrades its controller, the directory orchestrates the
20
+ /// handoff including `beforeReceiveMigrationFrom`, `migrate`, and `afterReceiveMigrationFrom` lifecycle hooks.
19
21
  contract JBDirectory is JBPermissioned, Ownable, IJBDirectory {
20
22
  //*********************************************************************//
21
23
  // --------------------------- custom errors ------------------------- //
@@ -83,12 +85,14 @@ contract JBDirectory is JBPermissioned, Ownable, IJBDirectory {
83
85
  // ---------------------- external transactions ---------------------- //
84
86
  //*********************************************************************//
85
87
 
86
- /// @notice Set a project's controller. Controllers manage how terminals interact with tokens and rulesets.
88
+ /// @notice Assign a new controller to a project. The controller dictates how the project's terminals interact with
89
+ /// its tokens and rulesets. If the project already has a controller, this triggers a full migration lifecycle
90
+ /// (`beforeReceiveMigrationFrom` → `migrate` → state update → `afterReceiveMigrationFrom`).
87
91
  /// @dev Can only be called if:
88
- /// - The ruleset's metadata has `allowSetController` enabled, and the message's sender is the project's owner or an
89
- /// address with the owner's permission to `SET_CONTROLLER`.
90
- /// - OR the message's sender is the project's current controller.
91
- /// - OR an address which `isAllowedToSetFirstController` is setting a project's first controller.
92
+ /// - The ruleset's metadata has `allowSetController` enabled, and the caller is the project's owner or has
93
+ /// `SET_CONTROLLER` permission.
94
+ /// - OR the caller is the project's current controller.
95
+ /// - OR the caller `isAllowedToSetFirstController` and the project has no controller yet.
92
96
  /// @param projectId The ID of the project whose controller is being set.
93
97
  /// @param controller The address of the controller to set.
94
98
  function setControllerOf(uint256 projectId, IERC165 controller) external override {
@@ -149,15 +153,13 @@ contract JBDirectory is JBPermissioned, Ownable, IJBDirectory {
149
153
  }
150
154
  }
151
155
 
152
- /// @notice Add or remove an address/contract from a list of trusted addresses which are allowed to set a first
153
- /// controller for projects.
154
- /// @dev Only this contract's owner can call this function.
155
- /// @dev These addresses are vetted controllers as well as contracts designed to launch new projects.
156
- /// @dev A project can set its own controller without being on this list.
157
- /// @dev If you would like to add an address/contract to this list, please reach out to this contract's owner.
158
- /// @param addr The address to allow or not allow.
159
- /// @param flag Whether the address is allowed to set first controllers for projects. Use `true` to allow and
160
- /// `false` to not allow.
156
+ /// @notice Allow or disallow an address to set the first controller for new projects. Typically used to whitelist
157
+ /// deployer contracts (like `JBController`) that set a controller during `launchProjectFor`.
158
+ /// @dev Only this contract's owner can call this function. These addresses are vetted controllers and project
159
+ /// launchers. A project owner can always set their own controller this list only governs *first* controller
160
+ /// assignment by third parties.
161
+ /// @param addr The address to allow or disallow.
162
+ /// @param flag Whether the address is allowed to set first controllers. `true` to allow, `false` to revoke.
161
163
  function setIsAllowedToSetFirstController(address addr, bool flag) external override onlyOwner {
162
164
  // Set the flag in the allowlist.
163
165
  isAllowedToSetFirstController[addr] = flag;
@@ -165,11 +167,11 @@ contract JBDirectory is JBPermissioned, Ownable, IJBDirectory {
165
167
  emit SetIsAllowedToSetFirstController({addr: addr, isAllowed: flag, caller: msg.sender});
166
168
  }
167
169
 
168
- /// @notice Set a project's primary terminal for a token.
169
- /// @dev The primary terminal for a token is where payments in that token are routed to by default.
170
- /// @dev This is useful in cases where a project has multiple terminals which accept the same token.
171
- /// @dev Can only be called by the project's owner, or an address with the owner's permission to
172
- /// `SET_PRIMARY_TERMINAL`.
170
+ /// @notice Designate which terminal should receive payments by default when someone pays a project in a specific
171
+ /// token. Useful when a project has multiple terminals that accept the same token.
172
+ /// @dev Can only be called by the project's owner or an address with `SET_PRIMARY_TERMINAL` permission. The
173
+ /// terminal must accept the token for this project. If the terminal isn't already in the project's terminal list,
174
+ /// it will be added automatically (requires `ADD_TERMINALS` permission).
173
175
  /// @param projectId The ID of the project whose primary terminal is being set.
174
176
  /// @param token The token to set the primary terminal for.
175
177
  /// @param terminal The terminal being set as the primary terminal.
@@ -203,10 +205,10 @@ contract JBDirectory is JBPermissioned, Ownable, IJBDirectory {
203
205
  emit SetPrimaryTerminal({projectId: projectId, token: token, terminal: terminal, caller: msg.sender});
204
206
  }
205
207
 
206
- /// @notice Set a project's terminals.
207
- /// @dev Can only be called by the project's owner, an address with the owner's permission to `SET_TERMINALS`, or
208
- /// the project's controller.
209
- /// @dev Unless the caller is the project's controller, the project's ruleset must allow setting terminals.
208
+ /// @notice Replace a project's entire terminal list. Terminals are the contracts that accept payments and process
209
+ /// cash outs for a project. This overwrites the existing list.
210
+ /// @dev Can only be called by the project's owner, an address with `SET_TERMINALS` permission, or the project's
211
+ /// controller. Unless the caller is the controller, the ruleset must have `allowSetTerminals` enabled.
210
212
  /// @param projectId The ID of the project whose terminals are being set.
211
213
  /// @param terminals An array of terminal addresses to set for the project.
212
214
  function setTerminalsOf(uint256 projectId, IJBTerminal[] calldata terminals) external override {
@@ -254,10 +256,9 @@ contract JBDirectory is JBPermissioned, Ownable, IJBDirectory {
254
256
  // ------------------------- external views -------------------------- //
255
257
  //*********************************************************************//
256
258
 
257
- /// @notice The primary terminal that a project uses for the specified token.
258
- /// @dev Returns the first terminal that accepts the token if the project hasn't explicitly set a primary terminal
259
- /// for it.
260
- /// @dev Returns the zero address if no terminal accepts the token.
259
+ /// @notice Look up the terminal where payments in a given token should be sent for a project. Returns the
260
+ /// explicitly-set primary terminal, or falls back to the first terminal in the project's list that accepts the
261
+ /// token. Returns the zero address if no terminal accepts the token.
261
262
  /// @param projectId The ID of the project to get the primary terminal of.
262
263
  /// @param token The token that the terminal accepts.
263
264
  /// @return The primary terminal's address.
@@ -298,7 +299,8 @@ contract JBDirectory is JBPermissioned, Ownable, IJBDirectory {
298
299
  return IJBTerminal(address(0));
299
300
  }
300
301
 
301
- /// @notice The specified project's terminals.
302
+ /// @notice Get all terminals registered for a project. Terminals are the contracts that hold a project's funds and
303
+ /// process payments and cash outs on its behalf.
302
304
  /// @param projectId The ID of the project to get the terminals of.
303
305
  /// @return An array of the project's terminal addresses.
304
306
  function terminalsOf(uint256 projectId) external view override returns (IJBTerminal[] memory) {
@@ -309,7 +311,7 @@ contract JBDirectory is JBPermissioned, Ownable, IJBDirectory {
309
311
  // -------------------------- public views --------------------------- //
310
312
  //*********************************************************************//
311
313
 
312
- /// @notice Check if a project uses a specific terminal.
314
+ /// @notice Check whether a specific terminal is in a project's registered terminal list.
313
315
  /// @param projectId The ID of the project to check.
314
316
  /// @param terminal The terminal to check for.
315
317
  /// @return A flag indicating whether the project uses the terminal.
package/src/JBERC20.sol CHANGED
@@ -15,10 +15,11 @@ import {IJBProjects} from "./interfaces/IJBProjects.sol";
15
15
  import {IJBToken} from "./interfaces/IJBToken.sol";
16
16
  import {IJBTokens} from "./interfaces/IJBTokens.sol";
17
17
 
18
- /// @notice An ERC-20 token that can be used by a project in `JBTokens` and `JBController`.
19
- /// @dev By default, a project uses "credits" to track balances. Once a project sets their `IJBToken` using
20
- /// `JBController.deployERC20For(...)` or `JBController.setTokenFor(...)`, credits can be redeemed to claim tokens.
21
- /// @dev `JBController.deployERC20For(...)` deploys a `JBERC20` contract and sets it as the project's token.
18
+ /// @notice The ERC-20 token implementation used by Juicebox projects. Includes ERC20Votes (governance delegation) and
19
+ /// ERC20Permit (gasless approvals). Deployed as a minimal clone via `JBController.deployERC20For` once deployed,
20
+ /// holders can claim their internal credits into this transferable token.
21
+ /// @dev Only `JBTokens` can mint and burn. The project owner (via `SET_TOKEN_METADATA` permission) can rename the
22
+ /// token. Supports ERC-1271 signature validation for smart-contract wallets.
22
23
  contract JBERC20 is ERC20Votes, ERC20Permit, JBPermissioned, IERC1271, IJBToken {
23
24
  //*********************************************************************//
24
25
  // --------------------------- custom errors ------------------------- //
@@ -6,7 +6,9 @@ import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
6
6
 
7
7
  import {IJBFeelessAddresses} from "./interfaces/IJBFeelessAddresses.sol";
8
8
 
9
- /// @notice Stores a list of addresses that shouldn't incur fees when sending or receiving payments.
9
+ /// @notice A registry of addresses exempt from the protocol's 2.5% fee. Feeless addresses don't incur fees on
10
+ /// payouts they receive, surplus allowance they use, or cash outs where they are the beneficiary. Managed by the
11
+ /// contract owner (typically the protocol multisig).
10
12
  contract JBFeelessAddresses is Ownable, IJBFeelessAddresses, IERC165 {
11
13
  //*********************************************************************//
12
14
  // --------------------- public stored properties -------------------- //
@@ -30,8 +32,9 @@ contract JBFeelessAddresses is Ownable, IJBFeelessAddresses, IERC165 {
30
32
  // ---------------------- external transactions ---------------------- //
31
33
  //*********************************************************************//
32
34
 
33
- /// @notice Sets whether an address is feeless.
34
- /// @dev Can only be called by this contract's owner.
35
+ /// @notice Add or remove an address from the fee-exempt list. Feeless addresses don't pay the 2.5% protocol fee
36
+ /// on payouts received, surplus allowance used, or cash outs where they're the beneficiary.
37
+ /// @dev Can only be called by this contract's owner (typically the protocol multisig).
35
38
  /// @param addr The address to set as feeless or not feeless.
36
39
  /// @param flag Whether the address should be feeless (`true`) or not feeless (`false`).
37
40
  function setFeelessAddress(address addr, bool flag) external virtual override onlyOwner {
@@ -7,8 +7,12 @@ import {IJBFundAccessLimits} from "./interfaces/IJBFundAccessLimits.sol";
7
7
  import {JBCurrencyAmount} from "./structs/JBCurrencyAmount.sol";
8
8
  import {JBFundAccessLimitGroup} from "./structs/JBFundAccessLimitGroup.sol";
9
9
 
10
- /// @notice Stores and manages terminal fund access limits for each project.
11
- /// @dev See the `JBFundAccessLimitGroup` struct to learn about payout limits and surplus allowances.
10
+ /// @notice Controls how much a project can withdraw from its terminals each funding cycle. Two types of limits:
11
+ /// **Payout limits** cap how much can be distributed to splits and the project owner. **Surplus allowances** cap how
12
+ /// much the project owner can pull from the surplus (funds above payout limits). Both reset each ruleset cycle.
13
+ /// @dev Limits are denominated in a currency (which may differ from the held token) and resolved at withdrawal time
14
+ /// via `JBPrices`. An empty `fundAccessLimitGroups` array means zero access (not unlimited) — use `type(uint224).max`
15
+ /// for unlimited.
12
16
  contract JBFundAccessLimits is JBControlled, IJBFundAccessLimits {
13
17
  //*********************************************************************//
14
18
  // --------------------------- custom errors ------------------------- //
@@ -61,10 +65,11 @@ contract JBFundAccessLimits is JBControlled, IJBFundAccessLimits {
61
65
  // ---------------------- external transactions ---------------------- //
62
66
  //*********************************************************************//
63
67
 
64
- /// @notice Sets limits on the amount of funds a project can access from its terminals during a ruleset.
65
- /// @dev Only a project's controller can set its fund access limits.
66
- /// @dev Payout limits and surplus allowances must be specified in strictly increasing order (by currency) to
67
- /// prevent duplicates.
68
+ /// @notice Configure how much a project can withdraw from each of its terminals during a ruleset. Payout limits
69
+ /// cap how much can be distributed to splits/owner; surplus allowances cap how much extra the owner can pull from
70
+ /// surplus. Both reset each funding cycle.
71
+ /// @dev Only a project's controller can set fund access limits (called during `queueRulesetsOf`).
72
+ /// @dev Limits within each group must be sorted by currency in strictly increasing order to prevent duplicates.
68
73
  /// @param projectId The ID of the project whose fund access limits are being set.
69
74
  /// @param rulesetId The ID of the ruleset that the limits will apply within.
70
75
  /// @param fundAccessLimitGroups An array containing payout limits and surplus allowances for each payment terminal.
@@ -152,14 +157,15 @@ contract JBFundAccessLimits is JBControlled, IJBFundAccessLimits {
152
157
  // ------------------------- external views -------------------------- //
153
158
  //*********************************************************************//
154
159
 
155
- /// @notice A project's payout limit for a given ruleset, terminal, token, and currency.
156
- /// @dev The fixed point return amount will use the same number of decimals as the `terminal`.
160
+ /// @notice Look up how much a project can distribute (via `sendPayoutsOf`) from a specific terminal and token,
161
+ /// denominated in a specific currency. Returns 0 if no limit is configured for that currency.
162
+ /// @dev The fixed point return amount uses the same number of decimals as the terminal.
157
163
  /// @param projectId The project's ID.
158
164
  /// @param rulesetId The ruleset's ID.
159
165
  /// @param terminal The terminal the payout limit applies to.
160
166
  /// @param token The token the payout limit applies to.
161
167
  /// @param currency The currency the payout limit is denominated in.
162
- /// @return payoutLimit The payout limit, as a fixed point number with the same number of decimals as the provided
168
+ /// @return payoutLimit The payout limit, as a fixed point number with the same number of decimals as the
163
169
  /// terminal.
164
170
  function payoutLimitOf(
165
171
  uint256 projectId,
@@ -195,10 +201,9 @@ contract JBFundAccessLimits is JBControlled, IJBFundAccessLimits {
195
201
  }
196
202
  }
197
203
 
198
- /// @notice A project's payout limits for a given ruleset, terminal, and token.
199
- /// @dev The total value of `token`s that a project can pay out from the terminal during the ruleset is dictated
200
- /// by a list of payout limits. Each payout limit is a fixed-point amount in terms of a currency.
201
- /// @dev The fixed point `amount`s returned will use the same number of decimals as the `terminal`.
204
+ /// @notice Get all payout limits for a project's terminal and token during a ruleset. A project can have multiple
205
+ /// payout limits denominated in different currencies (e.g. 10,000 USD + 5 ETH). Each is enforced independently.
206
+ /// @dev The fixed point `amount`s returned use the same number of decimals as the terminal.
202
207
  /// @param projectId The project's ID.
203
208
  /// @param rulesetId The ruleset's ID.
204
209
  /// @param terminal The terminal the payout limits apply to.
@@ -243,15 +248,16 @@ contract JBFundAccessLimits is JBControlled, IJBFundAccessLimits {
243
248
  }
244
249
  }
245
250
 
246
- /// @notice A project's surplus allowance for a given ruleset, terminal, token, and currency.
247
- /// @dev The fixed point return amount will use the same number of decimals as the `terminal`.
251
+ /// @notice Look up how much a project's owner can withdraw from the surplus (via `useAllowanceOf`) from a specific
252
+ /// terminal and token, denominated in a specific currency. Returns 0 if no allowance is configured.
253
+ /// @dev The fixed point return amount uses the same number of decimals as the terminal.
248
254
  /// @param projectId The project's ID.
249
255
  /// @param rulesetId The ruleset's ID.
250
256
  /// @param terminal The terminal the surplus allowance applies to.
251
257
  /// @param token The token the surplus allowance applies to.
252
258
  /// @param currency The currency that the surplus allowance is denominated in.
253
259
  /// @return surplusAllowance The surplus allowance, as a fixed point number with the same number of decimals as the
254
- /// provided terminal.
260
+ /// terminal.
255
261
  function surplusAllowanceOf(
256
262
  uint256 projectId,
257
263
  uint256 rulesetId,
@@ -287,11 +293,9 @@ contract JBFundAccessLimits is JBControlled, IJBFundAccessLimits {
287
293
  }
288
294
  }
289
295
 
290
- /// @notice A project's surplus allowances for a given ruleset, terminal, and token.
291
- /// @dev The total value of `token`s that a project can pay out from its surplus in a terminal during the ruleset
292
- /// is dictated by a list of surplus allowances. Each surplus allowance is a fixed-point amount in terms of a
293
- /// currency.
294
- /// @dev The fixed point `amount`s returned will use the same number of decimals as the `terminal`.
296
+ /// @notice Get all surplus allowances for a project's terminal and token during a ruleset. Like payout limits, a
297
+ /// project can have multiple surplus allowances in different currencies, each enforced independently.
298
+ /// @dev The fixed point `amount`s returned use the same number of decimals as the terminal.
295
299
  /// @param projectId The project's ID.
296
300
  /// @param rulesetId The ruleset's ID.
297
301
  /// @param terminal The terminal the surplus allowances apply to.