@bananapus/core-v6 0.0.61 → 0.0.62

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bananapus/core-v6",
3
- "version": "0.0.61",
3
+ "version": "0.0.62",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -97,8 +97,11 @@ library CoreDeploymentLib {
97
97
  })
98
98
  );
99
99
 
100
+ // Controller is loaded best-effort so the periphery deploy script can bootstrap on a fresh chain that
101
+ // hasn't yet produced `JBController.json` — that script is the one that creates the controller. Other
102
+ // core artifacts are still required.
100
103
  deployment.controller = JBController(
101
- _getDeploymentAddress({
104
+ _tryGetDeploymentAddress({
102
105
  path: path, projectName: PROJECT_NAME, networkName: networkName, contractName: "JBController"
103
106
  })
104
107
  );
@@ -164,4 +167,24 @@ library CoreDeploymentLib {
164
167
  vm.readFile(string.concat(path, projectName, "/", networkName, "/", contractName, ".json"));
165
168
  return stdJson.readAddress({json: deploymentJson, key: ".address"});
166
169
  }
170
+
171
+ /// @notice Best-effort variant of `_getDeploymentAddress`. Returns `address(0)` when the artifact file does
172
+ /// not exist on disk, rather than reverting. Used for fields that may legitimately be absent during a
173
+ /// fresh-chain bootstrap (e.g. the controller artifact when the periphery script is the one creating it).
174
+ function _tryGetDeploymentAddress(
175
+ string memory path,
176
+ string memory projectName,
177
+ string memory networkName,
178
+ string memory contractName
179
+ )
180
+ internal
181
+ view
182
+ returns (address)
183
+ {
184
+ string memory filePath = string.concat(path, projectName, "/", networkName, "/", contractName, ".json");
185
+ // forge-lint: disable-next-line(unsafe-cheatcode)
186
+ if (!vm.exists(filePath)) return address(0);
187
+ // forge-lint: disable-next-line(unsafe-cheatcode)
188
+ return stdJson.readAddress({json: vm.readFile(filePath), key: ".address"});
189
+ }
167
190
  }
@@ -172,8 +172,10 @@ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigra
172
172
  //*********************************************************************//
173
173
 
174
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.
175
+ /// @dev Can only be called by the project's owner or an operator with `ADD_PRICE_FEED` permission. When a current
176
+ /// ruleset exists, it must have `allowAddPriceFeed` enabled. If no current ruleset exists (`ruleset.id == 0`),
177
+ /// the call is allowed unconditionally — this is the symmetric counterpart to `setTokenFor`, which mirrors the
178
+ /// gap-state allowance so projects can configure prerequisites before their first ruleset activates.
177
179
  /// @param projectId The ID of the project to add the feed for.
178
180
  /// @param pricingCurrency The currency the feed's output price is in terms of.
179
181
  /// @param unitCurrency The currency the feed prices.
@@ -194,8 +196,12 @@ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigra
194
196
 
195
197
  JBRuleset memory ruleset = _currentRulesetOf(projectId);
196
198
 
197
- // Make sure the project's ruleset allows adding price feeds.
198
- if (!ruleset.allowAddPriceFeed()) revert JBController_AddingPriceFeedNotAllowed(projectId);
199
+ // When a current ruleset exists, it must allow adding price feeds. If no current ruleset exists
200
+ // (`ruleset.id == 0`), the call is allowed unconditionally so projects can register feeds during the
201
+ // pre-launch or gap state — matching the gap-state semantics of `setTokenFor`.
202
+ if (ruleset.id != 0 && !ruleset.allowAddPriceFeed()) {
203
+ revert JBController_AddingPriceFeedNotAllowed(projectId);
204
+ }
199
205
 
200
206
  PRICES.addPriceFeedFor({
201
207
  projectId: projectId, pricingCurrency: pricingCurrency, unitCurrency: unitCurrency, feed: feed
@@ -1102,7 +1108,9 @@ contract JBController is JBPermissioned, ERC2771Context, IJBController, IJBMigra
1102
1108
  })
1103
1109
  ) {}
1104
1110
  catch (bytes memory reason) {
1105
- emit SplitHookReverted({projectId: projectId, hook: address(split.hook), reason: reason});
1111
+ emit SplitHookReverted({
1112
+ projectId: projectId, hook: address(split.hook), reason: reason, caller: messageSender
1113
+ });
1106
1114
  }
1107
1115
 
1108
1116
  // For ERC-20 tokens, burn any tokens the hook did not consume.
@@ -501,8 +501,11 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
501
501
  /// @param token The token the fee is paid in.
502
502
  /// @param amount The fee amount, as a fixed point number with the same number of decimals as the token's
503
503
  /// accounting context.
504
- /// @param beneficiary The address to mint tokens to (from the project which receives fees), and pass along to the
505
- /// ruleset's data hook and pay hook if applicable.
504
+ /// @param beneficiary The address to mint fee-project tokens to (and pass along to the fee project's
505
+ /// data/pay hooks). If `address(0)`, the fee is routed via `addToBalanceOf` instead of `pay`, crediting the
506
+ /// fee project's balance directly without minting fee-project tokens. This honors the protocol-fee intent
507
+ /// (the fee project still receives the value) when no beneficiary is specified, instead of letting `pay`
508
+ /// revert inside `mintTokensOf` and having the catch path forgive the fee.
506
509
  /// @param feeTerminal The terminal that'll receive the fees.
507
510
  function executeProcessFee(
508
511
  uint256 projectId,
@@ -523,14 +526,24 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
523
526
  // Send the projectId in the metadata.
524
527
  bytes memory metadata = bytes(abi.encodePacked(projectId));
525
528
 
526
- _efficientPay({
527
- terminal: feeTerminal,
528
- projectId: JBConstants.FEE_BENEFICIARY_PROJECT_ID,
529
- token: token,
530
- amount: amount,
531
- beneficiary: beneficiary,
532
- metadata: metadata
533
- });
529
+ if (beneficiary == address(0)) {
530
+ _efficientAddToBalance({
531
+ terminal: feeTerminal,
532
+ projectId: JBConstants.FEE_BENEFICIARY_PROJECT_ID,
533
+ token: token,
534
+ amount: amount,
535
+ metadata: metadata
536
+ });
537
+ } else {
538
+ _efficientPay({
539
+ terminal: feeTerminal,
540
+ projectId: JBConstants.FEE_BENEFICIARY_PROJECT_ID,
541
+ token: token,
542
+ amount: amount,
543
+ beneficiary: beneficiary,
544
+ metadata: metadata
545
+ });
546
+ }
534
547
  }
535
548
 
536
549
  /// @notice Transfer funds to an address.
@@ -2158,7 +2171,8 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
2158
2171
  projectId: projectId,
2159
2172
  token: token,
2160
2173
  amount: amountPaidOut,
2161
- // The project owner will receive tokens minted by paying the platform fee.
2174
+ // The `feeBeneficiary` will receive the fee-project tokens minted in exchange for the
2175
+ // platform fee paid in terminal tokens.
2162
2176
  beneficiary: feeBeneficiary,
2163
2177
  shouldHoldFees: ruleset.holdFees()
2164
2178
  }));
@@ -1442,7 +1442,8 @@ contract JBTerminalStore is IJBTerminalStore {
1442
1442
  referralChainId: referralChainId,
1443
1443
  referralProjectId: bareProjectId,
1444
1444
  amount: amount,
1445
- newTotal: newTotal
1445
+ newTotal: newTotal,
1446
+ caller: msg.sender
1446
1447
  });
1447
1448
  }
1448
1449
 
@@ -102,7 +102,8 @@ interface IJBController is IERC165, IJBProjectUriRegistry, IJBDirectoryAccessCon
102
102
  /// @param projectId The ID of the project.
103
103
  /// @param hook The split hook that reverted.
104
104
  /// @param reason The revert reason.
105
- event SplitHookReverted(uint256 indexed projectId, address hook, bytes reason);
105
+ /// @param caller The address that called the distribution function.
106
+ event SplitHookReverted(uint256 indexed projectId, address hook, bytes reason, address caller);
106
107
 
107
108
  /// @notice Reserved tokens were sent to a specific split.
108
109
  /// @param projectId The ID of the project.
@@ -25,12 +25,14 @@ interface IJBTerminalStore {
25
25
  /// @param referralProjectId The referrer's bare project ID on `referralChainId` (no chain bits).
26
26
  /// @param amount The fee amount credited, in the terminal's accounting-context units.
27
27
  /// @param newTotal The new value of `totalFeeVolumeOf[terminal]` after this credit.
28
+ /// @param caller The address that recorded the credit.
28
29
  event ReferralCredit(
29
30
  address indexed terminal,
30
31
  uint256 indexed referralChainId,
31
32
  uint256 indexed referralProjectId,
32
33
  uint256 amount,
33
- uint256 newTotal
34
+ uint256 newTotal,
35
+ address caller
34
36
  );
35
37
 
36
38
  /// @notice The directory of terminals and controllers for projects.
@@ -92,7 +92,10 @@ library JBRulesetMetadataResolver {
92
92
 
93
93
  /// @notice Pack the funding cycle metadata.
94
94
  /// @param rulesetMetadata The ruleset metadata to validate and pack.
95
- /// @return packed The packed uint256 of all metadata params. The first 8 bits specify the version.
95
+ /// @return packed The packed uint256 of all metadata params. The first 4 bits (bits 0-3) specify the version;
96
+ /// supported values are 0-15. A future protocol version that needs more than 16 distinct metadata layouts must
97
+ /// widen this field before assigning a new version number, otherwise the high bits will silently spill into
98
+ /// the `reservedPercent` field that begins at bit 4.
96
99
  function packRulesetMetadata(JBRulesetMetadata memory rulesetMetadata) internal pure returns (uint256 packed) {
97
100
  // version 1 in the bits 0-3 (4 bits).
98
101
  packed = 1;