@bananapus/router-terminal-v6 0.0.60 → 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/router-terminal-v6",
3
- "version": "0.0.60",
3
+ "version": "0.0.62",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -24,9 +24,9 @@
24
24
  "artifacts": "source ./.env && npx sphinx artifacts --org-id 'ea165b21-7cdc-4d7b-be59-ecdd4c26bee4' --project-name 'nana-router-terminal-v6'"
25
25
  },
26
26
  "dependencies": {
27
- "@bananapus/buyback-hook-v6": "^0.0.64",
28
- "@bananapus/core-v6": "^0.0.72",
29
- "@bananapus/permission-ids-v6": "^0.0.27",
27
+ "@bananapus/buyback-hook-v6": "^0.0.66",
28
+ "@bananapus/core-v6": "^0.0.78",
29
+ "@bananapus/permission-ids-v6": "^0.0.28",
30
30
  "@bananapus/univ4-router-v6": "^0.0.46",
31
31
  "@openzeppelin/contracts": "5.6.1",
32
32
  "@uniswap/permit2": "github:Uniswap/permit2#cc56ad0f3439c502c246fc5cfcc3db92bb8b7219",
@@ -1161,6 +1161,8 @@ contract JBRouterTerminal is
1161
1161
  /// @param token The current token to process.
1162
1162
  /// @param amount The amount of the current token.
1163
1163
  /// @param metadata Bytes in `JBMetadataResolver`'s format (may contain a `cashOut` reclaim floor).
1164
+ /// @param refundTo The address that should receive any unsold source project tokens returned by a partial
1165
+ /// buyback-hook cash-out fill (otherwise they would strand in this router).
1164
1166
  /// @return destTerminal The terminal that accepts the final token (address(0) if no direct acceptance found).
1165
1167
  /// @return finalToken The token after all cashouts.
1166
1168
  /// @return finalAmount The amount of the final token.
@@ -1169,7 +1171,8 @@ contract JBRouterTerminal is
1169
1171
  address token,
1170
1172
  uint256 amount,
1171
1173
  bytes calldata metadata,
1172
- address preferredToken
1174
+ address preferredToken,
1175
+ address payable refundTo
1173
1176
  )
1174
1177
  internal
1175
1178
  returns (IJBTerminal destTerminal, address finalToken, uint256 finalAmount)
@@ -1209,6 +1212,10 @@ contract JBRouterTerminal is
1209
1212
  uint256 cashOutCount = amount;
1210
1213
  uint256 balanceBefore = _balanceOf({token: tokenToReclaim, account: address(this)});
1211
1214
 
1215
+ // Snapshot the source project-token balance so the unsold residue a partial buyback fill returns to this
1216
+ // router can be measured precisely below (only this hop's residue, never pre-existing balances).
1217
+ uint256 sourceBalanceBefore = _balanceOf({token: token, account: address(this)});
1218
+
1212
1219
  // Cash out the source project's tokens.
1213
1220
  // Don't rely on the terminal return value here. Buyback-hook sell-side execution returns 0 reclaimAmount
1214
1221
  // from nana-core, then transfers the real proceeds during the hook callback.
@@ -1244,6 +1251,16 @@ contract JBRouterTerminal is
1244
1251
  revert JBRouterTerminal_SlippageExceeded({amountOut: amount, minAmountOut: minTokensReclaimed});
1245
1252
  }
1246
1253
 
1254
+ // Refund any unsold source project tokens the buyback hook returned on a partial fill. The terminal burned
1255
+ // `cashOutCount` source tokens before the hook ran, so the post-cash-out source balance is
1256
+ // `sourceBalanceBefore - cashOutCount + unsold`; recovering `unsold` refunds exactly this hop's residue to
1257
+ // the route's refund recipient instead of stranding it, without sweeping any pre-existing balance.
1258
+ uint256 sourceResidue =
1259
+ _balanceOf({token: token, account: address(this)}) + cashOutCount - sourceBalanceBefore;
1260
+ if (sourceResidue != 0) {
1261
+ _transferFrom({from: address(this), to: refundTo, token: token, amount: sourceResidue});
1262
+ }
1263
+
1247
1264
  // Clear the reclaim minimum after the first hop.
1248
1265
  // Multi-hop routes can change token units between hops, so there is no sound generic way to rescale a
1249
1266
  // single metadata amount across the remaining path.
@@ -1545,7 +1562,8 @@ contract JBRouterTerminal is
1545
1562
  tokenIn: tokenIn,
1546
1563
  amount: amount,
1547
1564
  metadata: metadata,
1548
- preferredToken: address(0)
1565
+ preferredToken: address(0),
1566
+ refundTo: refundTo
1549
1567
  });
1550
1568
 
1551
1569
  // If the cashout loop found a destination terminal, the route is already complete.
@@ -1605,7 +1623,12 @@ contract JBRouterTerminal is
1605
1623
 
1606
1624
  // First route through any source-project cashout path so project-token inputs are converted before swap logic.
1607
1625
  (cashOutResolvedTerminal, tokenIn, amount) = _routeInputFromSource({
1608
- destProjectId: destProjectId, tokenIn: tokenIn, amount: amount, metadata: metadata, preferredToken: tokenOut
1626
+ destProjectId: destProjectId,
1627
+ tokenIn: tokenIn,
1628
+ amount: amount,
1629
+ metadata: metadata,
1630
+ preferredToken: tokenOut,
1631
+ refundTo: refundTo
1609
1632
  });
1610
1633
 
1611
1634
  // Return early when the source cashout path already reached the final destination terminal.
@@ -1629,6 +1652,7 @@ contract JBRouterTerminal is
1629
1652
  /// @param amount The current route input amount.
1630
1653
  /// @param metadata Metadata that may include a `cashOut` reclaim floor.
1631
1654
  /// @param preferredToken The preferred token to target during any cashout loop.
1655
+ /// @param refundTo The address that should receive any unsold source project tokens from a partial buyback fill.
1632
1656
  /// @return resolvedTerminal The terminal found by the cashout loop, or address(0) if conversion should continue.
1633
1657
  /// @return routedTokenIn The token that remains to be routed after the cashout step.
1634
1658
  /// @return routedAmountIn The amount of `routedTokenIn` that remains to be routed.
@@ -1637,7 +1661,8 @@ contract JBRouterTerminal is
1637
1661
  address tokenIn,
1638
1662
  uint256 amount,
1639
1663
  bytes calldata metadata,
1640
- address preferredToken
1664
+ address preferredToken,
1665
+ address payable refundTo
1641
1666
  )
1642
1667
  internal
1643
1668
  returns (IJBTerminal resolvedTerminal, address routedTokenIn, uint256 routedAmountIn)
@@ -1651,7 +1676,8 @@ contract JBRouterTerminal is
1651
1676
  token: tokenIn,
1652
1677
  amount: amount,
1653
1678
  metadata: metadata,
1654
- preferredToken: preferredToken
1679
+ preferredToken: preferredToken,
1680
+ refundTo: refundTo
1655
1681
  });
1656
1682
  }
1657
1683
 
@@ -153,8 +153,15 @@ contract JBRouterTerminalRegistry is IJBRouterTerminalRegistry, JBPermissioned,
153
153
  override
154
154
  returns (JBAccountingContext memory context)
155
155
  {
156
- // Get the terminal for the project (falls back to the threshold-resolved default).
157
- IJBTerminal terminal = _requireResolvedTerminalOf(projectId);
156
+ // Discovery view, fail-open: resolve the project's effective terminal WITHOUT reverting. When no terminal can
157
+ // be resolved (e.g. no default terminal has been set on this chain yet), return an empty context
158
+ // (`token == address(0)`) rather than reverting. Callers such as `JBDirectory.primaryTerminalOf` read this to
159
+ // decide whether the registry accepts the token; an empty context means "not accepted", letting them fall
160
+ // through to `address(0)` instead of propagating a revert that would brick the originating operation (e.g. a
161
+ // protocol-fee cash out/payout routed to project #1). Transactional paths keep `_requireResolvedTerminalOf`
162
+ // and still revert before accepting funds or forwarding into `address(0)`.
163
+ IJBTerminal terminal = _resolvedTerminalOf(projectId);
164
+ if (terminal == IJBTerminal(address(0))) return context;
158
165
 
159
166
  // Get the accounting context for the token.
160
167
  return terminal.accountingContextForTokenOf({projectId: projectId, token: token});
@@ -169,8 +176,11 @@ contract JBRouterTerminalRegistry is IJBRouterTerminalRegistry, JBPermissioned,
169
176
  override
170
177
  returns (JBAccountingContext[] memory contexts)
171
178
  {
172
- // Get the terminal for the project (falls back to the threshold-resolved default).
173
- IJBTerminal terminal = _requireResolvedTerminalOf(projectId);
179
+ // Discovery view, fail-open: resolve WITHOUT reverting and return an empty array when no terminal can be
180
+ // resolved on this chain (see `accountingContextForTokenOf`). Transactional paths keep
181
+ // `_requireResolvedTerminalOf` and still revert.
182
+ IJBTerminal terminal = _resolvedTerminalOf(projectId);
183
+ if (terminal == IJBTerminal(address(0))) return contexts;
174
184
 
175
185
  // Get the accounting contexts.
176
186
  return terminal.accountingContextsOf(projectId);