@bananapus/router-terminal-v6 0.0.14 → 0.0.15

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/router-terminal-v6",
3
- "version": "0.0.14",
3
+ "version": "0.0.15",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -17,7 +17,7 @@
17
17
  "artifacts": "source ./.env && npx sphinx artifacts --org-id 'ea165b21-7cdc-4d7b-be59-ecdd4c26bee4' --project-name 'nana-router-terminal-v6'"
18
18
  },
19
19
  "dependencies": {
20
- "@bananapus/core-v6": "^0.0.20",
20
+ "@bananapus/core-v6": "^0.0.23",
21
21
  "@bananapus/permission-ids-v6": "^0.0.10",
22
22
  "@openzeppelin/contracts": "^5.6.1",
23
23
  "@uniswap/permit2": "github:Uniswap/permit2",
@@ -14,7 +14,6 @@ import {IJBTokens} from "@bananapus/core-v6/src/interfaces/IJBTokens.sol";
14
14
  import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
15
15
  import {JBMetadataResolver} from "@bananapus/core-v6/src/libraries/JBMetadataResolver.sol";
16
16
  import {JBAccountingContext} from "@bananapus/core-v6/src/structs/JBAccountingContext.sol";
17
- import {JBCashOutHookSpecification} from "@bananapus/core-v6/src/structs/JBCashOutHookSpecification.sol";
18
17
  import {JBPayHookSpecification} from "@bananapus/core-v6/src/structs/JBPayHookSpecification.sol";
19
18
  import {JBRuleset} from "@bananapus/core-v6/src/structs/JBRuleset.sol";
20
19
  import {JBSingleAllowance} from "@bananapus/core-v6/src/structs/JBSingleAllowance.sol";
@@ -220,7 +219,7 @@ contract JBRouterTerminal is
220
219
  /// @notice This terminal holds no surplus. Always returns 0.
221
220
  function currentSurplusOf(
222
221
  uint256,
223
- JBAccountingContext[] memory,
222
+ address[] calldata,
224
223
  uint256,
225
224
  uint256
226
225
  )
@@ -426,16 +425,12 @@ contract JBRouterTerminal is
426
425
  override
427
426
  {
428
427
  IJBTerminal destTerminal;
429
- {
430
- amount = _acceptFundsFor({token: token, amount: amount, metadata: metadata});
431
-
432
- address tokenOut;
433
- uint256 amountOut;
434
- (destTerminal, tokenOut, amountOut) =
435
- _route({destProjectId: projectId, tokenIn: token, amount: amount, metadata: metadata});
436
- token = tokenOut;
437
- amount = amountOut;
438
- }
428
+ (destTerminal, token, amount) = _route({
429
+ destProjectId: projectId,
430
+ tokenIn: token,
431
+ amount: _acceptFundsFor({token: token, amount: amount, metadata: metadata}),
432
+ metadata: metadata
433
+ });
439
434
 
440
435
  uint256 payValue = _beforeTransferFor({to: address(destTerminal), token: token, amount: amount});
441
436
 
@@ -480,16 +475,12 @@ contract JBRouterTerminal is
480
475
  returns (uint256 beneficiaryTokenCount)
481
476
  {
482
477
  IJBTerminal destTerminal;
483
- {
484
- amount = _acceptFundsFor({token: token, amount: amount, metadata: metadata});
485
-
486
- address tokenOut;
487
- uint256 amountOut;
488
- (destTerminal, tokenOut, amountOut) =
489
- _route({destProjectId: projectId, tokenIn: token, amount: amount, metadata: metadata});
490
- token = tokenOut;
491
- amount = amountOut;
492
- }
478
+ (destTerminal, token, amount) = _route({
479
+ destProjectId: projectId,
480
+ tokenIn: token,
481
+ amount: _acceptFundsFor({token: token, amount: amount, metadata: metadata}),
482
+ metadata: metadata
483
+ });
493
484
 
494
485
  uint256 payValue = _beforeTransferFor({to: address(destTerminal), token: token, amount: amount});
495
486
 
@@ -553,22 +544,20 @@ contract JBRouterTerminal is
553
544
  });
554
545
 
555
546
  // Determine input/output amounts from the delta.
547
+ int128 delta0 = delta.amount0();
548
+ int128 delta1 = delta.amount1();
556
549
  uint256 amountIn;
557
550
  uint256 amountOut;
558
- {
559
- int128 delta0 = delta.amount0();
560
- int128 delta1 = delta.amount1();
561
- if (zeroForOne) {
562
- // forge-lint: disable-next-line(unsafe-typecast)
563
- amountIn = uint256(uint128(-delta0));
564
- // forge-lint: disable-next-line(unsafe-typecast)
565
- amountOut = uint256(uint128(delta1));
566
- } else {
567
- // forge-lint: disable-next-line(unsafe-typecast)
568
- amountIn = uint256(uint128(-delta1));
569
- // forge-lint: disable-next-line(unsafe-typecast)
570
- amountOut = uint256(uint128(delta0));
571
- }
551
+ if (zeroForOne) {
552
+ // forge-lint: disable-next-line(unsafe-typecast)
553
+ amountIn = uint256(uint128(-delta0));
554
+ // forge-lint: disable-next-line(unsafe-typecast)
555
+ amountOut = uint256(uint128(delta1));
556
+ } else {
557
+ // forge-lint: disable-next-line(unsafe-typecast)
558
+ amountIn = uint256(uint128(-delta1));
559
+ // forge-lint: disable-next-line(unsafe-typecast)
560
+ amountOut = uint256(uint128(delta0));
572
561
  }
573
562
 
574
563
  if (amountOut < minAmountOut) revert JBRouterTerminal_SlippageExceeded(amountOut, minAmountOut);
@@ -595,23 +584,21 @@ contract JBRouterTerminal is
595
584
  /// @return The amount of tokens that have been accepted.
596
585
  function _acceptFundsFor(address token, uint256 amount, bytes calldata metadata) internal returns (uint256) {
597
586
  // Check for credit cash-out metadata.
598
- {
599
- (bool creditExists, bytes memory creditData) =
600
- JBMetadataResolver.getDataFor({id: JBMetadataResolver.getId("cashOutSource"), metadata: metadata});
587
+ (bool creditExists, bytes memory creditData) =
588
+ JBMetadataResolver.getDataFor({id: JBMetadataResolver.getId("cashOutSource"), metadata: metadata});
601
589
 
602
- if (creditExists) {
603
- // Credit cashouts don't use msg.value — revert if ETH was sent to prevent it being trapped.
604
- if (msg.value != 0) revert JBRouterTerminal_NoMsgValueAllowed(msg.value);
590
+ if (creditExists) {
591
+ // Credit cashouts don't use msg.value — revert if ETH was sent to prevent it being trapped.
592
+ if (msg.value != 0) revert JBRouterTerminal_NoMsgValueAllowed(msg.value);
605
593
 
606
- (uint256 sourceProjectId, uint256 creditAmount) = abi.decode(creditData, (uint256, uint256));
594
+ (uint256 sourceProjectId, uint256 creditAmount) = abi.decode(creditData, (uint256, uint256));
607
595
 
608
- // Pull credits from the payer (requires payer to have granted TRANSFER_CREDITS to this contract).
609
- TOKENS.transferCreditsFrom({
610
- holder: _msgSender(), projectId: sourceProjectId, recipient: address(this), count: creditAmount
611
- });
596
+ // Pull credits from the payer (requires payer to have granted TRANSFER_CREDITS to this contract).
597
+ TOKENS.transferCreditsFrom({
598
+ holder: _msgSender(), projectId: sourceProjectId, recipient: address(this), count: creditAmount
599
+ });
612
600
 
613
- return creditAmount;
614
- }
601
+ return creditAmount;
615
602
  }
616
603
 
617
604
  // If native tokens are being paid in, return the `msg.value`.
@@ -676,6 +663,15 @@ contract JBRouterTerminal is
676
663
  return 0;
677
664
  }
678
665
 
666
+ /// @notice Parse the optional `cashOutMinReclaimed` metadata.
667
+ /// @param metadata The metadata to inspect for a minimum reclaim amount.
668
+ /// @return minTokensReclaimed The minimum reclaim amount, or 0 if none is specified.
669
+ function _minReclaimedFrom(bytes calldata metadata) internal view returns (uint256 minTokensReclaimed) {
670
+ (bool exists, bytes memory minData) =
671
+ JBMetadataResolver.getDataFor({id: JBMetadataResolver.getId("cashOutMinReclaimed"), metadata: metadata});
672
+ if (exists) minTokensReclaimed = abi.decode(minData, (uint256));
673
+ }
674
+
679
675
  /// @notice Parse the optional `cashOutSource` metadata.
680
676
  /// @param metadata The metadata to inspect for a credit cashout override.
681
677
  /// @return sourceProjectId The source project override, or 0 if none is specified.
@@ -740,12 +736,7 @@ contract JBRouterTerminal is
740
736
  returns (IJBTerminal destTerminal, address finalToken, uint256 finalAmount)
741
737
  {
742
738
  // Check for a user-provided minimum cashout reclaim amount (slippage protection).
743
- uint256 minTokensReclaimed;
744
- {
745
- (bool exists, bytes memory minData) =
746
- JBMetadataResolver.getDataFor({id: JBMetadataResolver.getId("cashOutMinReclaimed"), metadata: metadata});
747
- if (exists) minTokensReclaimed = abi.decode(minData, (uint256));
748
- }
739
+ uint256 minTokensReclaimed = _minReclaimedFrom(metadata);
749
740
 
750
741
  // Intermediate steps have no per-step slippage protection. The final output amount is
751
742
  // checked against the user's minReclaimed parameter, providing end-to-end slippage protection. Per-step
@@ -817,15 +808,7 @@ contract JBRouterTerminal is
817
808
  returns (IJBTerminal destTerminal, address finalToken, uint256 finalAmount)
818
809
  {
819
810
  // Track the one-time minimum reclaim amount that the caller may require on the first hop.
820
- uint256 minTokensReclaimed;
821
- {
822
- // Read the optional `cashOutMinReclaimed` payload from metadata.
823
- (bool exists, bytes memory minData) =
824
- JBMetadataResolver.getDataFor({id: JBMetadataResolver.getId("cashOutMinReclaimed"), metadata: metadata});
825
-
826
- // Decode the first-hop minimum reclaim amount if the payload is present.
827
- if (exists) minTokensReclaimed = abi.decode(minData, (uint256));
828
- }
811
+ uint256 minTokensReclaimed = _minReclaimedFrom(metadata);
829
812
 
830
813
  // Walk the same cash-out path execution would take, bounded to prevent circular routes.
831
814
  for (uint256 i; i < _MAX_CASHOUT_ITERATIONS; i++) {
@@ -1199,15 +1182,13 @@ contract JBRouterTerminal is
1199
1182
 
1200
1183
  for (uint256 i; i < terminals.length; i++) {
1201
1184
  // Check if this terminal supports the IJBCashOutTerminal interface.
1202
- {
1203
- // slither-disable-next-line calls-loop
1204
- try IERC165(address(terminals[i])).supportsInterface(type(IJBCashOutTerminal).interfaceId) returns (
1205
- bool supported
1206
- ) {
1207
- if (!supported) continue;
1208
- } catch {
1209
- continue;
1210
- }
1185
+ // slither-disable-next-line calls-loop
1186
+ try IERC165(address(terminals[i])).supportsInterface(type(IJBCashOutTerminal).interfaceId) returns (
1187
+ bool supported
1188
+ ) {
1189
+ if (!supported) continue;
1190
+ } catch {
1191
+ continue;
1211
1192
  }
1212
1193
 
1213
1194
  IJBCashOutTerminal terminal = IJBCashOutTerminal(address(terminals[i]));
@@ -1218,12 +1199,10 @@ contract JBRouterTerminal is
1218
1199
  address contextToken = contexts[j].token;
1219
1200
 
1220
1201
  // Priority 1: Does the destination project directly accept this token?
1221
- {
1222
- // slither-disable-next-line calls-loop
1223
- IJBTerminal destTerminal =
1224
- DIRECTORY.primaryTerminalOf({projectId: destProjectId, token: contextToken});
1225
- if (address(destTerminal) != address(0)) return (contextToken, terminal);
1226
- }
1202
+ // slither-disable-next-line calls-loop
1203
+ IJBTerminal destTerminal =
1204
+ DIRECTORY.primaryTerminalOf({projectId: destProjectId, token: contextToken});
1205
+ if (address(destTerminal) != address(0)) return (contextToken, terminal);
1227
1206
 
1228
1207
  // Priority 2: Is this a JB project token (so we can recurse)?
1229
1208
  if (address(fallbackTerminal) == address(0) && contextToken != JBConstants.NATIVE_TOKEN) {
@@ -1493,15 +1472,13 @@ contract JBRouterTerminal is
1493
1472
  returns (address tokenOut, IJBTerminal destTerminal)
1494
1473
  {
1495
1474
  // 1. Metadata override — payer specifies tokenOut explicitly.
1496
- {
1497
- (bool exists, bytes memory routeData) =
1498
- JBMetadataResolver.getDataFor({id: JBMetadataResolver.getId("routeTokenOut"), metadata: metadata});
1499
- if (exists) {
1500
- (tokenOut) = abi.decode(routeData, (address));
1501
- destTerminal = DIRECTORY.primaryTerminalOf({projectId: projectId, token: tokenOut});
1502
- if (address(destTerminal) == address(0)) revert JBRouterTerminal_NoRouteFound(projectId, tokenOut);
1503
- return (tokenOut, destTerminal);
1504
- }
1475
+ (bool exists, bytes memory routeData) =
1476
+ JBMetadataResolver.getDataFor({id: JBMetadataResolver.getId("routeTokenOut"), metadata: metadata});
1477
+ if (exists) {
1478
+ (tokenOut) = abi.decode(routeData, (address));
1479
+ destTerminal = DIRECTORY.primaryTerminalOf({projectId: projectId, token: tokenOut});
1480
+ if (address(destTerminal) == address(0)) revert JBRouterTerminal_NoRouteFound(projectId, tokenOut);
1481
+ return (tokenOut, destTerminal);
1505
1482
  }
1506
1483
 
1507
1484
  // 2. Direct acceptance — project accepts tokenIn as-is.
@@ -1540,14 +1517,7 @@ contract JBRouterTerminal is
1540
1517
  returns (IJBTerminal destTerminal, address tokenOut, uint256 amountOut)
1541
1518
  {
1542
1519
  // Check for credit source override.
1543
- uint256 sourceProjectIdOverride;
1544
- {
1545
- (bool creditExists, bytes memory creditData) =
1546
- JBMetadataResolver.getDataFor({id: JBMetadataResolver.getId("cashOutSource"), metadata: metadata});
1547
- if (creditExists) {
1548
- (sourceProjectIdOverride,) = abi.decode(creditData, (uint256, uint256));
1549
- }
1550
- }
1520
+ (uint256 sourceProjectIdOverride,) = _cashOutSourceFrom(metadata);
1551
1521
 
1552
1522
  // Check if input is a JB project token (credit or ERC-20).
1553
1523
  uint256 sourceProjectId = sourceProjectIdOverride;
@@ -142,13 +142,13 @@ contract JBRouterTerminalRegistry is IJBRouterTerminalRegistry, JBPermissioned,
142
142
 
143
143
  /// @notice Empty implementation to satisfy the interface. This terminal has no surplus.
144
144
  function currentSurplusOf(
145
- uint256 projectId,
146
- JBAccountingContext[] memory accountingContexts,
147
- uint256 decimals,
148
- uint256 currency
145
+ uint256,
146
+ address[] calldata,
147
+ uint256,
148
+ uint256
149
149
  )
150
150
  external
151
- view
151
+ pure
152
152
  override
153
153
  returns (uint256)
154
154
  {}
@@ -419,7 +419,7 @@ contract RouterTerminalTest is Test {
419
419
  }
420
420
 
421
421
  function test_currentSurplus_zero() public view {
422
- assertEq(routerTerminal.currentSurplusOf(1, new JBAccountingContext[](0), 18, 1), 0);
422
+ assertEq(routerTerminal.currentSurplusOf(1, new address[](0), 18, 1), 0);
423
423
  }
424
424
 
425
425
  //*********************************************************************//