@bananapus/core-v6 0.0.9 → 0.0.10

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 (39) hide show
  1. package/foundry.toml +0 -1
  2. package/package.json +2 -2
  3. package/src/JBChainlinkV3PriceFeed.sol +1 -5
  4. package/src/JBChainlinkV3SequencerPriceFeed.sol +1 -1
  5. package/src/JBController.sol +277 -277
  6. package/src/JBDeadline.sol +1 -1
  7. package/src/JBDirectory.sol +93 -93
  8. package/src/JBERC20.sol +43 -39
  9. package/src/JBFeelessAddresses.sol +12 -12
  10. package/src/JBFundAccessLimits.sol +82 -82
  11. package/src/JBMultiTerminal.sol +313 -313
  12. package/src/JBPermissions.sol +104 -100
  13. package/src/JBPrices.sol +68 -68
  14. package/src/JBProjects.sol +31 -31
  15. package/src/JBRulesets.sol +422 -422
  16. package/src/JBSplits.sol +116 -116
  17. package/src/JBTerminalStore.sol +651 -651
  18. package/src/JBTokens.sol +41 -41
  19. package/src/interfaces/IJBCashOutTerminal.sol +25 -7
  20. package/src/interfaces/IJBController.sol +78 -3
  21. package/src/interfaces/IJBDirectory.sol +25 -0
  22. package/src/interfaces/IJBFeeTerminal.sol +31 -0
  23. package/src/interfaces/IJBFeelessAddresses.sol +4 -0
  24. package/src/interfaces/IJBFundAccessLimits.sol +5 -0
  25. package/src/interfaces/IJBMigratable.sol +12 -8
  26. package/src/interfaces/IJBPayoutTerminal.sol +56 -9
  27. package/src/interfaces/IJBPermissions.sol +14 -7
  28. package/src/interfaces/IJBPermitTerminal.sol +4 -0
  29. package/src/interfaces/IJBPrices.sol +6 -0
  30. package/src/interfaces/IJBProjects.sol +8 -0
  31. package/src/interfaces/IJBRulesetApprovalHook.sol +1 -1
  32. package/src/interfaces/IJBRulesetDataHook.sol +23 -23
  33. package/src/interfaces/IJBRulesets.sol +54 -33
  34. package/src/interfaces/IJBSplits.sol +6 -0
  35. package/src/interfaces/IJBTerminal.sol +36 -0
  36. package/src/interfaces/IJBTerminalStore.sol +63 -63
  37. package/src/interfaces/IJBToken.sol +5 -5
  38. package/src/interfaces/IJBTokens.sol +50 -8
  39. package/test/TestDurationUnderflow.sol +3 -2
@@ -183,173 +183,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
183
183
  PERMIT2 = permit2;
184
184
  }
185
185
 
186
- //*********************************************************************//
187
- // ------------------------- external views -------------------------- //
188
- //*********************************************************************//
189
-
190
- /// @notice A project's accounting context for a token.
191
- /// @dev See the `JBAccountingContext` struct for more information.
192
- /// @param projectId The ID of the project to get token accounting context of.
193
- /// @param token The token to check the accounting context of.
194
- /// @return The token's accounting context for the token.
195
- function accountingContextForTokenOf(
196
- uint256 projectId,
197
- address token
198
- )
199
- external
200
- view
201
- override
202
- returns (JBAccountingContext memory)
203
- {
204
- return _accountingContextForTokenOf[projectId][token];
205
- }
206
-
207
- /// @notice The tokens accepted by a project.
208
- /// @param projectId The ID of the project to get the accepted tokens of.
209
- /// @return tokenContexts The accounting contexts of the accepted tokens.
210
- function accountingContextsOf(uint256 projectId) external view override returns (JBAccountingContext[] memory) {
211
- return _accountingContextsOf[projectId];
212
- }
213
-
214
- /// @notice Gets the total current surplus amount in this terminal for a project, in terms of a given currency.
215
- /// @dev This total surplus only includes tokens that the project accepts (as returned by
216
- /// `accountingContextsOf(...)`).
217
- /// @param projectId The ID of the project to get the current total surplus of.
218
- /// @param accountingContexts The accounting contexts to use to calculate the surplus. Pass an empty array to use
219
- /// all of the project's accounting contexts.
220
- /// @param decimals The number of decimals to include in the fixed point returned value.
221
- /// @param currency The currency to express the returned value in terms of.
222
- /// @return The current surplus amount the project has in this terminal, in terms of `currency` and with the
223
- /// specified number of decimals.
224
- function currentSurplusOf(
225
- uint256 projectId,
226
- JBAccountingContext[] memory accountingContexts,
227
- uint256 decimals,
228
- uint256 currency
229
- )
230
- external
231
- view
232
- override
233
- returns (uint256)
234
- {
235
- return STORE.currentSurplusOf({
236
- terminal: address(this),
237
- projectId: projectId,
238
- accountingContexts: accountingContexts.length != 0 ? accountingContexts : _accountingContextsOf[projectId],
239
- decimals: decimals,
240
- currency: currency
241
- });
242
- }
243
-
244
- /// @notice Fees that are being held for a project.
245
- /// @dev Projects can temporarily hold fees and unlock them later by adding funds to the project's balance.
246
- /// @dev Held fees can be processed at any time by this terminal's owner.
247
- /// @param projectId The ID of the project that is holding fees.
248
- /// @param token The token that the fees are held in.
249
- function heldFeesOf(
250
- uint256 projectId,
251
- address token,
252
- uint256 count
253
- )
254
- external
255
- view
256
- override
257
- returns (JBFee[] memory heldFees)
258
- {
259
- // Keep a reference to the start index.
260
- uint256 startIndex = _nextHeldFeeIndexOf[projectId][token];
261
-
262
- // Get a reference to the number of held fees.
263
- uint256 numberOfHeldFees = _heldFeesOf[projectId][token].length;
264
-
265
- // If the start index is greater than or equal to the number of held fees, return 0.
266
- if (startIndex >= numberOfHeldFees) return new JBFee[](0);
267
-
268
- // If the start index plus the count is greater than the number of fees, set the count to the number of fees
269
- if (startIndex + count > numberOfHeldFees) count = numberOfHeldFees - startIndex;
270
-
271
- // Create a new array to hold the fees.
272
- heldFees = new JBFee[](count);
273
-
274
- // Copy the fees into the array.
275
- for (uint256 i; i < count; i++) {
276
- heldFees[i] = _heldFeesOf[projectId][token][startIndex + i];
277
- }
278
- }
279
-
280
- //*********************************************************************//
281
- // -------------------------- public views --------------------------- //
282
- //*********************************************************************//
283
-
284
- /// @notice Indicates whether this contract adheres to the specified interface.
285
- /// @dev See {IERC165-supportsInterface}.
286
- /// @param interfaceId The ID of the interface to check for adherence to.
287
- /// @return A flag indicating if the provided interface ID is supported.
288
- function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
289
- return interfaceId == type(IJBMultiTerminal).interfaceId || interfaceId == type(IJBPermissioned).interfaceId
290
- || interfaceId == type(IJBTerminal).interfaceId || interfaceId == type(IJBCashOutTerminal).interfaceId
291
- || interfaceId == type(IJBPayoutTerminal).interfaceId || interfaceId == type(IJBPermitTerminal).interfaceId
292
- || interfaceId == type(IJBFeeTerminal).interfaceId || interfaceId == type(IERC165).interfaceId;
293
- }
294
-
295
- //*********************************************************************//
296
- // -------------------------- internal views ------------------------- //
297
- //*********************************************************************//
298
-
299
- /// @notice Checks this terminal's balance of a specific token.
300
- /// @param token The address of the token to get this terminal's balance of.
301
- /// @return This terminal's balance.
302
- function _balanceOf(address token) internal view returns (uint256) {
303
- // If the `token` is native, get the native token balance.
304
- return token == JBConstants.NATIVE_TOKEN ? address(this).balance : IERC20(token).balanceOf(address(this));
305
- }
306
-
307
- /// @dev `ERC-2771` specifies the context as being a single address (20 bytes).
308
- function _contextSuffixLength() internal view override(ERC2771Context, Context) returns (uint256) {
309
- return super._contextSuffixLength();
310
- }
311
-
312
- /// @notice Returns the current controller of a project.
313
- /// @param projectId The ID of the project to get the controller of.
314
- /// @return controller The project's controller.
315
- function _controllerOf(uint256 projectId) internal view returns (IJBController) {
316
- return IJBController(address(DIRECTORY.controllerOf(projectId)));
317
- }
318
-
319
- /// @notice Returns a flag indicating if interacting with an address should not incur fees.
320
- /// @param addr The address to check.
321
- /// @return A flag indicating if the address should not incur fees.
322
- function _isFeeless(address addr) internal view returns (bool) {
323
- return FEELESS_ADDRESSES.isFeeless(addr);
324
- }
325
-
326
- /// @notice The calldata. Preferred to use over `msg.data`.
327
- /// @return calldata The `msg.data` of this call.
328
- function _msgData() internal view override(ERC2771Context, Context) returns (bytes calldata) {
329
- return ERC2771Context._msgData();
330
- }
331
-
332
- /// @notice The message's sender. Preferred to use over `msg.sender`.
333
- /// @return sender The address which sent this call.
334
- function _msgSender() internal view override(ERC2771Context, Context) returns (address sender) {
335
- return ERC2771Context._msgSender();
336
- }
337
-
338
- /// @notice The owner of a project.
339
- /// @param projectId The ID of the project to get the owner of.
340
- /// @return The owner of the project.
341
- function _ownerOf(uint256 projectId) internal view returns (address) {
342
- return PROJECTS.ownerOf(projectId);
343
- }
344
-
345
- /// @notice The primary terminal of a project for a token.
346
- /// @param projectId The ID of the project to get the primary terminal of.
347
- /// @param token The token to get the primary terminal of.
348
- /// @return The primary terminal of the project for the token.
349
- function _primaryTerminalOf(uint256 projectId, address token) internal view returns (IJBTerminal) {
350
- return DIRECTORY.primaryTerminalOf({projectId: projectId, token: token});
351
- }
352
-
353
186
  //*********************************************************************//
354
187
  // ---------------------- external transactions ---------------------- //
355
188
  //*********************************************************************//
@@ -938,7 +771,116 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
938
771
  }
939
772
 
940
773
  //*********************************************************************//
941
- // ------------------------ internal functions ----------------------- //
774
+ // ------------------------- external views -------------------------- //
775
+ //*********************************************************************//
776
+
777
+ /// @notice A project's accounting context for a token.
778
+ /// @dev See the `JBAccountingContext` struct for more information.
779
+ /// @param projectId The ID of the project to get token accounting context of.
780
+ /// @param token The token to check the accounting context of.
781
+ /// @return The token's accounting context for the token.
782
+ function accountingContextForTokenOf(
783
+ uint256 projectId,
784
+ address token
785
+ )
786
+ external
787
+ view
788
+ override
789
+ returns (JBAccountingContext memory)
790
+ {
791
+ return _accountingContextForTokenOf[projectId][token];
792
+ }
793
+
794
+ /// @notice The tokens accepted by a project.
795
+ /// @param projectId The ID of the project to get the accepted tokens of.
796
+ /// @return tokenContexts The accounting contexts of the accepted tokens.
797
+ function accountingContextsOf(uint256 projectId) external view override returns (JBAccountingContext[] memory) {
798
+ return _accountingContextsOf[projectId];
799
+ }
800
+
801
+ /// @notice Gets the total current surplus amount in this terminal for a project, in terms of a given currency.
802
+ /// @dev This total surplus only includes tokens that the project accepts (as returned by
803
+ /// `accountingContextsOf(...)`).
804
+ /// @param projectId The ID of the project to get the current total surplus of.
805
+ /// @param accountingContexts The accounting contexts to use to calculate the surplus. Pass an empty array to use
806
+ /// all of the project's accounting contexts.
807
+ /// @param decimals The number of decimals to include in the fixed point returned value.
808
+ /// @param currency The currency to express the returned value in terms of.
809
+ /// @return The current surplus amount the project has in this terminal, in terms of `currency` and with the
810
+ /// specified number of decimals.
811
+ function currentSurplusOf(
812
+ uint256 projectId,
813
+ JBAccountingContext[] memory accountingContexts,
814
+ uint256 decimals,
815
+ uint256 currency
816
+ )
817
+ external
818
+ view
819
+ override
820
+ returns (uint256)
821
+ {
822
+ return STORE.currentSurplusOf({
823
+ terminal: address(this),
824
+ projectId: projectId,
825
+ accountingContexts: accountingContexts.length != 0 ? accountingContexts : _accountingContextsOf[projectId],
826
+ decimals: decimals,
827
+ currency: currency
828
+ });
829
+ }
830
+
831
+ /// @notice Fees that are being held for a project.
832
+ /// @dev Projects can temporarily hold fees and unlock them later by adding funds to the project's balance.
833
+ /// @dev Held fees can be processed at any time by this terminal's owner.
834
+ /// @param projectId The ID of the project that is holding fees.
835
+ /// @param token The token that the fees are held in.
836
+ function heldFeesOf(
837
+ uint256 projectId,
838
+ address token,
839
+ uint256 count
840
+ )
841
+ external
842
+ view
843
+ override
844
+ returns (JBFee[] memory heldFees)
845
+ {
846
+ // Keep a reference to the start index.
847
+ uint256 startIndex = _nextHeldFeeIndexOf[projectId][token];
848
+
849
+ // Get a reference to the number of held fees.
850
+ uint256 numberOfHeldFees = _heldFeesOf[projectId][token].length;
851
+
852
+ // If the start index is greater than or equal to the number of held fees, return 0.
853
+ if (startIndex >= numberOfHeldFees) return new JBFee[](0);
854
+
855
+ // If the start index plus the count is greater than the number of fees, set the count to the number of fees
856
+ if (startIndex + count > numberOfHeldFees) count = numberOfHeldFees - startIndex;
857
+
858
+ // Create a new array to hold the fees.
859
+ heldFees = new JBFee[](count);
860
+
861
+ // Copy the fees into the array.
862
+ for (uint256 i; i < count; i++) {
863
+ heldFees[i] = _heldFeesOf[projectId][token][startIndex + i];
864
+ }
865
+ }
866
+
867
+ //*********************************************************************//
868
+ // -------------------------- public views --------------------------- //
869
+ //*********************************************************************//
870
+
871
+ /// @notice Indicates whether this contract adheres to the specified interface.
872
+ /// @dev See {IERC165-supportsInterface}.
873
+ /// @param interfaceId The ID of the interface to check for adherence to.
874
+ /// @return A flag indicating if the provided interface ID is supported.
875
+ function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
876
+ return interfaceId == type(IJBMultiTerminal).interfaceId || interfaceId == type(IJBPermissioned).interfaceId
877
+ || interfaceId == type(IJBTerminal).interfaceId || interfaceId == type(IJBCashOutTerminal).interfaceId
878
+ || interfaceId == type(IJBPayoutTerminal).interfaceId || interfaceId == type(IJBPermitTerminal).interfaceId
879
+ || interfaceId == type(IJBFeeTerminal).interfaceId || interfaceId == type(IERC165).interfaceId;
880
+ }
881
+
882
+ //*********************************************************************//
883
+ // ---------------------- internal transactions ---------------------- //
942
884
  //*********************************************************************//
943
885
 
944
886
  /// @notice Accepts an incoming token.
@@ -1233,119 +1175,48 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
1233
1175
  /// terminal's `pay` function.
1234
1176
  /// @param terminal The terminal on which the project is expecting to receive payments.
1235
1177
  /// @param projectId The ID of the project being paid.
1236
- /// @param token The token being paid in.
1237
- /// @param amount The amount being paid, as a fixed point number with the amount of decimals that the terminal's
1238
- /// accounting context specifies.
1239
- /// @param beneficiary The address to receive any platform tokens minted.
1240
- /// @param metadata Additional metadata to include with the payment.
1241
- function _efficientPay(
1242
- IJBTerminal terminal,
1243
- uint256 projectId,
1244
- address token,
1245
- uint256 amount,
1246
- address beneficiary,
1247
- bytes memory metadata
1248
- )
1249
- internal
1250
- {
1251
- if (terminal == IJBTerminal(address(this))) {
1252
- _pay({
1253
- projectId: projectId,
1254
- token: token,
1255
- amount: amount,
1256
- payer: address(this),
1257
- beneficiary: beneficiary,
1258
- memo: "",
1259
- metadata: metadata
1260
- });
1261
- } else {
1262
- // Trigger any inherited pre-transfer logic.
1263
- // Keep a reference to the amount that'll be paid as a `msg.value`.
1264
- // slither-disable-next-line reentrancy-events
1265
- uint256 payValue = _beforeTransferTo({to: address(terminal), token: token, amount: amount});
1266
-
1267
- // Send the fee.
1268
- // If this terminal's token is ETH, send it in msg.value.
1269
- // slither-disable-next-line unused-return
1270
- terminal.pay{value: payValue}({
1271
- projectId: projectId,
1272
- token: token,
1273
- amount: amount,
1274
- beneficiary: beneficiary,
1275
- minReturnedTokens: 0,
1276
- memo: "",
1277
- metadata: metadata
1278
- });
1279
- }
1280
- }
1281
-
1282
- /// @notice Fulfills a list of pay hook specifications.
1283
- /// @param projectId The ID of the project being paid.
1284
- /// @param specifications The pay hook specifications to be fulfilled.
1285
- /// @param tokenAmount The amount of tokens that the project was paid.
1286
- /// @param payer The address that sent the payment.
1287
- /// @param ruleset The ruleset the payment is being accepted during.
1288
- /// @param beneficiary The address which will receive any tokens that the payment yields.
1289
- /// @param newlyIssuedTokenCount The amount of tokens that are being issued and sent to the beneificary.
1290
- /// @param metadata Bytes to send along to the emitted event and pay hooks as applicable.
1291
- function _fulfillPayHookSpecificationsFor(
1292
- uint256 projectId,
1293
- JBPayHookSpecification[] memory specifications,
1294
- JBTokenAmount memory tokenAmount,
1295
- address payer,
1296
- JBRuleset memory ruleset,
1297
- address beneficiary,
1298
- uint256 newlyIssuedTokenCount,
1299
- bytes memory metadata
1300
- )
1301
- internal
1302
- {
1303
- // Keep a reference to payment context for the pay hooks.
1304
- JBAfterPayRecordedContext memory context = JBAfterPayRecordedContext({
1305
- payer: payer,
1306
- projectId: projectId,
1307
- rulesetId: ruleset.id,
1308
- amount: tokenAmount,
1309
- forwardedAmount: tokenAmount,
1310
- weight: ruleset.weight,
1311
- newlyIssuedTokenCount: newlyIssuedTokenCount,
1312
- beneficiary: beneficiary,
1313
- hookMetadata: bytes(""),
1314
- payerMetadata: metadata
1315
- });
1316
-
1317
- // Fulfill each specification through their pay hooks.
1318
- for (uint256 i; i < specifications.length; i++) {
1319
- // Set the specification being iterated on.
1320
- JBPayHookSpecification memory specification = specifications[i];
1321
-
1322
- // Pass the correct token `forwardedAmount` to the hook.
1323
- context.forwardedAmount = JBTokenAmount({
1324
- value: specification.amount,
1325
- token: tokenAmount.token,
1326
- decimals: tokenAmount.decimals,
1327
- currency: tokenAmount.currency
1178
+ /// @param token The token being paid in.
1179
+ /// @param amount The amount being paid, as a fixed point number with the amount of decimals that the terminal's
1180
+ /// accounting context specifies.
1181
+ /// @param beneficiary The address to receive any platform tokens minted.
1182
+ /// @param metadata Additional metadata to include with the payment.
1183
+ function _efficientPay(
1184
+ IJBTerminal terminal,
1185
+ uint256 projectId,
1186
+ address token,
1187
+ uint256 amount,
1188
+ address beneficiary,
1189
+ bytes memory metadata
1190
+ )
1191
+ internal
1192
+ {
1193
+ if (terminal == IJBTerminal(address(this))) {
1194
+ _pay({
1195
+ projectId: projectId,
1196
+ token: token,
1197
+ amount: amount,
1198
+ payer: address(this),
1199
+ beneficiary: beneficiary,
1200
+ memo: "",
1201
+ metadata: metadata
1328
1202
  });
1329
-
1330
- // Pass the correct metadata from the data hook's specification.
1331
- context.hookMetadata = specification.metadata;
1332
-
1203
+ } else {
1333
1204
  // Trigger any inherited pre-transfer logic.
1334
1205
  // Keep a reference to the amount that'll be paid as a `msg.value`.
1335
1206
  // slither-disable-next-line reentrancy-events
1336
- uint256 payValue = _beforeTransferTo({
1337
- to: address(specification.hook), token: tokenAmount.token, amount: specification.amount
1338
- });
1339
-
1340
- // Fulfill the specification.
1341
- // slither-disable-next-line reentrancy-events
1342
- specification.hook.afterPayRecordedWith{value: payValue}(context);
1207
+ uint256 payValue = _beforeTransferTo({to: address(terminal), token: token, amount: amount});
1343
1208
 
1344
- emit HookAfterRecordPay({
1345
- hook: specification.hook,
1346
- context: context,
1347
- specificationAmount: specification.amount,
1348
- caller: _msgSender()
1209
+ // Send the fee.
1210
+ // If this terminal's token is ETH, send it in msg.value.
1211
+ // slither-disable-next-line unused-return
1212
+ terminal.pay{value: payValue}({
1213
+ projectId: projectId,
1214
+ token: token,
1215
+ amount: amount,
1216
+ beneficiary: beneficiary,
1217
+ minReturnedTokens: 0,
1218
+ memo: "",
1219
+ metadata: metadata
1349
1220
  });
1350
1221
  }
1351
1222
  }
@@ -1437,6 +1308,77 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
1437
1308
  }
1438
1309
  }
1439
1310
 
1311
+ /// @notice Fulfills a list of pay hook specifications.
1312
+ /// @param projectId The ID of the project being paid.
1313
+ /// @param specifications The pay hook specifications to be fulfilled.
1314
+ /// @param tokenAmount The amount of tokens that the project was paid.
1315
+ /// @param payer The address that sent the payment.
1316
+ /// @param ruleset The ruleset the payment is being accepted during.
1317
+ /// @param beneficiary The address which will receive any tokens that the payment yields.
1318
+ /// @param newlyIssuedTokenCount The amount of tokens that are being issued and sent to the beneificary.
1319
+ /// @param metadata Bytes to send along to the emitted event and pay hooks as applicable.
1320
+ function _fulfillPayHookSpecificationsFor(
1321
+ uint256 projectId,
1322
+ JBPayHookSpecification[] memory specifications,
1323
+ JBTokenAmount memory tokenAmount,
1324
+ address payer,
1325
+ JBRuleset memory ruleset,
1326
+ address beneficiary,
1327
+ uint256 newlyIssuedTokenCount,
1328
+ bytes memory metadata
1329
+ )
1330
+ internal
1331
+ {
1332
+ // Keep a reference to payment context for the pay hooks.
1333
+ JBAfterPayRecordedContext memory context = JBAfterPayRecordedContext({
1334
+ payer: payer,
1335
+ projectId: projectId,
1336
+ rulesetId: ruleset.id,
1337
+ amount: tokenAmount,
1338
+ forwardedAmount: tokenAmount,
1339
+ weight: ruleset.weight,
1340
+ newlyIssuedTokenCount: newlyIssuedTokenCount,
1341
+ beneficiary: beneficiary,
1342
+ hookMetadata: bytes(""),
1343
+ payerMetadata: metadata
1344
+ });
1345
+
1346
+ // Fulfill each specification through their pay hooks.
1347
+ for (uint256 i; i < specifications.length; i++) {
1348
+ // Set the specification being iterated on.
1349
+ JBPayHookSpecification memory specification = specifications[i];
1350
+
1351
+ // Pass the correct token `forwardedAmount` to the hook.
1352
+ context.forwardedAmount = JBTokenAmount({
1353
+ value: specification.amount,
1354
+ token: tokenAmount.token,
1355
+ decimals: tokenAmount.decimals,
1356
+ currency: tokenAmount.currency
1357
+ });
1358
+
1359
+ // Pass the correct metadata from the data hook's specification.
1360
+ context.hookMetadata = specification.metadata;
1361
+
1362
+ // Trigger any inherited pre-transfer logic.
1363
+ // Keep a reference to the amount that'll be paid as a `msg.value`.
1364
+ // slither-disable-next-line reentrancy-events
1365
+ uint256 payValue = _beforeTransferTo({
1366
+ to: address(specification.hook), token: tokenAmount.token, amount: specification.amount
1367
+ });
1368
+
1369
+ // Fulfill the specification.
1370
+ // slither-disable-next-line reentrancy-events
1371
+ specification.hook.afterPayRecordedWith{value: payValue}(context);
1372
+
1373
+ emit HookAfterRecordPay({
1374
+ hook: specification.hook,
1375
+ context: context,
1376
+ specificationAmount: specification.amount,
1377
+ caller: _msgSender()
1378
+ });
1379
+ }
1380
+ }
1381
+
1440
1382
  /// @notice Pay a project with tokens.
1441
1383
  /// @param projectId The ID of the project being paid.
1442
1384
  /// @param token The address of the token which the project is being paid with.
@@ -1665,6 +1607,43 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
1665
1607
  /// `hook`, `projectId`, or `beneficiary`) to send funds to the `_msgSender()` which calls this function. This can
1666
1608
  /// be used to incentivize calling this function.
1667
1609
  /// @dev Payouts sent to addresses which aren't feeless incur the protocol fee.
1610
+ /// @notice Sends a payout to a split.
1611
+ /// @param split The split to pay.
1612
+ /// @param projectId The ID of the project the split was specified by.
1613
+ /// @param token The address of the token being paid out.
1614
+ /// @param amount The total amount that the split is being paid, as a fixed point number with the same number of
1615
+ /// decimals as this terminal.
1616
+ /// @return netPayoutAmount The amount sent to the split after subtracting fees.
1617
+ function _sendPayoutToSplit(
1618
+ JBSplit memory split,
1619
+ uint256 projectId,
1620
+ address token,
1621
+ uint256 amount
1622
+ )
1623
+ internal
1624
+ returns (uint256)
1625
+ {
1626
+ // Attempt to distribute this split.
1627
+ // slither-disable-next-line reentrancy-events
1628
+ try this.executePayout({
1629
+ split: split, projectId: projectId, token: token, amount: amount, originalMessageSender: _msgSender()
1630
+ }) returns (
1631
+ uint256 netPayoutAmount
1632
+ ) {
1633
+ return netPayoutAmount;
1634
+ } catch (bytes memory failureReason) {
1635
+ emit PayoutReverted({
1636
+ projectId: projectId, split: split, amount: amount, reason: failureReason, caller: _msgSender()
1637
+ });
1638
+
1639
+ // Add balance back to the project.
1640
+ _recordAddedBalanceFor({projectId: projectId, token: token, amount: amount});
1641
+
1642
+ // Since the payout failed the netPayoutAmount is zero.
1643
+ return 0;
1644
+ }
1645
+ }
1646
+
1668
1647
  /// @param projectId The ID of the project to send the payouts of.
1669
1648
  /// @param token The token being paid out.
1670
1649
  /// @param amount The number of terminal tokens to pay out, as a fixed point number with same number of decimals as
@@ -1762,43 +1741,6 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
1762
1741
  });
1763
1742
  }
1764
1743
 
1765
- /// @notice Sends a payout to a split.
1766
- /// @param split The split to pay.
1767
- /// @param projectId The ID of the project the split was specified by.
1768
- /// @param token The address of the token being paid out.
1769
- /// @param amount The total amount that the split is being paid, as a fixed point number with the same number of
1770
- /// decimals as this terminal.
1771
- /// @return netPayoutAmount The amount sent to the split after subtracting fees.
1772
- function _sendPayoutToSplit(
1773
- JBSplit memory split,
1774
- uint256 projectId,
1775
- address token,
1776
- uint256 amount
1777
- )
1778
- internal
1779
- returns (uint256)
1780
- {
1781
- // Attempt to distribute this split.
1782
- // slither-disable-next-line reentrancy-events
1783
- try this.executePayout({
1784
- split: split, projectId: projectId, token: token, amount: amount, originalMessageSender: _msgSender()
1785
- }) returns (
1786
- uint256 netPayoutAmount
1787
- ) {
1788
- return netPayoutAmount;
1789
- } catch (bytes memory failureReason) {
1790
- emit PayoutReverted({
1791
- projectId: projectId, split: split, amount: amount, reason: failureReason, caller: _msgSender()
1792
- });
1793
-
1794
- // Add balance back to the project.
1795
- _recordAddedBalanceFor({projectId: projectId, token: token, amount: amount});
1796
-
1797
- // Since the payout failed the netPayoutAmount is zero.
1798
- return 0;
1799
- }
1800
- }
1801
-
1802
1744
  /// @notice Sends payouts to the payout splits group specified in a project's ruleset.
1803
1745
  /// @param projectId The ID of the project to send the payouts of.
1804
1746
  /// @param token The address of the token being paid out.
@@ -2021,4 +1963,62 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
2021
1963
  _transferFrom({from: address(this), to: beneficiary, token: token, amount: netAmountPaidOut});
2022
1964
  }
2023
1965
  }
1966
+
1967
+ //*********************************************************************//
1968
+ // -------------------------- internal views ------------------------- //
1969
+ //*********************************************************************//
1970
+
1971
+ /// @notice Checks this terminal's balance of a specific token.
1972
+ /// @param token The address of the token to get this terminal's balance of.
1973
+ /// @return This terminal's balance.
1974
+ function _balanceOf(address token) internal view returns (uint256) {
1975
+ // If the `token` is native, get the native token balance.
1976
+ return token == JBConstants.NATIVE_TOKEN ? address(this).balance : IERC20(token).balanceOf(address(this));
1977
+ }
1978
+
1979
+ /// @dev `ERC-2771` specifies the context as being a single address (20 bytes).
1980
+ function _contextSuffixLength() internal view override(ERC2771Context, Context) returns (uint256) {
1981
+ return super._contextSuffixLength();
1982
+ }
1983
+
1984
+ /// @notice Returns the current controller of a project.
1985
+ /// @param projectId The ID of the project to get the controller of.
1986
+ /// @return controller The project's controller.
1987
+ function _controllerOf(uint256 projectId) internal view returns (IJBController) {
1988
+ return IJBController(address(DIRECTORY.controllerOf(projectId)));
1989
+ }
1990
+
1991
+ /// @notice Returns a flag indicating if interacting with an address should not incur fees.
1992
+ /// @param addr The address to check.
1993
+ /// @return A flag indicating if the address should not incur fees.
1994
+ function _isFeeless(address addr) internal view returns (bool) {
1995
+ return FEELESS_ADDRESSES.isFeeless(addr);
1996
+ }
1997
+
1998
+ /// @notice The calldata. Preferred to use over `msg.data`.
1999
+ /// @return calldata The `msg.data` of this call.
2000
+ function _msgData() internal view override(ERC2771Context, Context) returns (bytes calldata) {
2001
+ return ERC2771Context._msgData();
2002
+ }
2003
+
2004
+ /// @notice The message's sender. Preferred to use over `msg.sender`.
2005
+ /// @return sender The address which sent this call.
2006
+ function _msgSender() internal view override(ERC2771Context, Context) returns (address sender) {
2007
+ return ERC2771Context._msgSender();
2008
+ }
2009
+
2010
+ /// @notice The owner of a project.
2011
+ /// @param projectId The ID of the project to get the owner of.
2012
+ /// @return The owner of the project.
2013
+ function _ownerOf(uint256 projectId) internal view returns (address) {
2014
+ return PROJECTS.ownerOf(projectId);
2015
+ }
2016
+
2017
+ /// @notice The primary terminal of a project for a token.
2018
+ /// @param projectId The ID of the project to get the primary terminal of.
2019
+ /// @param token The token to get the primary terminal of.
2020
+ /// @return The primary terminal of the project for the token.
2021
+ function _primaryTerminalOf(uint256 projectId, address token) internal view returns (IJBTerminal) {
2022
+ return DIRECTORY.primaryTerminalOf({projectId: projectId, token: token});
2023
+ }
2024
2024
  }