@bananapus/router-terminal-v6 0.0.16 → 0.0.17

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/ARCHITECTURE.md CHANGED
@@ -53,9 +53,10 @@ Caller → JBRouterTerminal.previewPayFor(projectId, token, amount)
53
53
  ## Composition Boundary
54
54
 
55
55
  The router terminal exposes the `IJBTerminal` surface because it needs to participate in Juicebox routing, but its
56
- accounting context is intentionally synthetic. `accountingContextForTokenOf()` returns `decimals = 18` for any token,
57
- and the registry forwards that value unchanged. Treat the router layer as a payment router only, not as an
58
- accounting-sensitive terminal source for loan sizing, debt normalization, or any other decimals-dependent logic.
56
+ accounting context is intentionally synthetic. `accountingContextForTokenOf()` returns `decimals = 18` for native
57
+ tokens and probes `IERC20Metadata.decimals()` for ERC-20s (falling back to `18` if the call fails). The registry
58
+ forwards that value unchanged. Treat the router layer as a payment router only, not as an accounting-sensitive
59
+ terminal source for loan sizing, debt normalization, or any other decimals-dependent logic.
59
60
 
60
61
  ## Dependencies
61
62
  - `@bananapus/core-v6` — Terminal, directory, permissions
@@ -141,18 +141,18 @@ The registry implements a two-phase terminal assignment:
141
141
 
142
142
  ## Fee-on-Transfer Token Risks
143
143
 
144
- **JBRouterTerminal:** Uses balance-delta accounting in `_acceptFundsFor()` (lines 550-556). Measures `balanceBefore` and `balanceAfter` the transfer, returning the actual amount received. This correctly handles fee-on-transfer tokens at the acceptance stage. However, the amount forwarded to the destination terminal is the delta, which may differ from what the destination terminal expects if it also performs balance-delta checks.
144
+ **JBRouterTerminal:** Uses balance-delta accounting in `_acceptFundsFor()` (lines 569-575). Measures `balanceBefore` and `balanceAfter` the transfer, returning the actual amount received. This correctly handles fee-on-transfer tokens at the acceptance stage. However, the amount forwarded to the destination terminal is the delta, which may differ from what the destination terminal expects if it also performs balance-delta checks.
145
145
 
146
146
  **JBRouterTerminalRegistry:** Does NOT use balance-delta accounting in `_acceptFundsFor()` (line 437). It returns the user-supplied `amount` directly. If a fee-on-transfer token is used through the registry, the forwarded amount will exceed actual tokens received, causing a downstream revert or incorrect accounting.
147
147
 
148
- **Audit focus:** Verify that the registry's `_acceptFundsFor` cannot be exploited with fee-on-transfer tokens. The comment on line 433-435 states these are "not supported by design" -- confirm this is documented clearly enough and that no path silently loses funds.
148
+ **Audit focus:** Verify that the registry's `_acceptFundsFor` cannot be exploited with fee-on-transfer tokens. The comment on lines 433-434 states these are "not supported by design" -- confirm this is documented clearly enough and that no path silently loses funds.
149
149
 
150
150
  ## uint160 Permit2 Truncation Risk
151
151
 
152
152
  Both contracts cast `amount` to `uint160` when falling through to `PERMIT2.transferFrom()`:
153
153
 
154
- - `JBRouterTerminal._transferFrom()` line 1425: `if (amount > type(uint160).max) revert JBRouterTerminal_AmountOverflow(amount);`
155
- - `JBRouterTerminalRegistry._transferFrom()` line 477: `if (amount > type(uint160).max) revert JBRouterTerminalRegistry_AmountOverflow();`
154
+ - `JBRouterTerminal._transferFrom()` line 944: `if (amount > type(uint160).max) revert JBRouterTerminal_AmountOverflow(amount);`
155
+ - `JBRouterTerminalRegistry._transferFrom()` line 510: `if (amount > type(uint160).max) revert JBRouterTerminalRegistry_AmountOverflow();`
156
156
 
157
157
  Both contracts now revert before truncation occurs. Verify these overflow checks are complete and that no code path can reach the `uint160()` cast without hitting the guard.
158
158
 
package/README.md CHANGED
@@ -146,7 +146,22 @@ nana-router-terminal-v6/
146
146
  ├── RouterTerminal.t.sol # Unit tests (mocked dependencies)
147
147
  ├── RouterTerminalRegistry.t.sol # Registry unit tests
148
148
  ├── RouterTerminalFork.t.sol # Fork tests against mainnet Uniswap pools
149
- └── RouterTerminalPreviewFork.t.sol # Fork parity tests for previewPayFor
149
+ ├── RouterTerminalPreviewFork.t.sol # Fork parity tests for previewPayFor
150
+ ├── RouterTerminalCashOutFork.t.sol # Fork tests for cashout routing
151
+ ├── RouterTerminalCreditCashout.t.sol # Credit cashout unit tests
152
+ ├── RouterTerminalERC2771.t.sol # ERC-2771 meta-transaction tests
153
+ ├── RouterTerminalFeeCashOutFork.t.sol # Fee routing through cashout (fork)
154
+ ├── RouterTerminalMultihopFork.t.sol # Multi-hop routing (fork)
155
+ ├── RouterTerminalReentrancy.t.sol # Reentrancy attack tests
156
+ ├── RouterTerminalSandwichFork.t.sol # MEV/sandwich resistance (fork)
157
+ ├── fork/
158
+ │ └── V4QuoteAndSettlementFork.t.sol # V4 quote and settlement (fork)
159
+ ├── invariant/
160
+ │ └── RouterTerminalInvariant.t.sol # Invariant/fuzz tests
161
+ └── regression/
162
+ ├── CashOutLoopLimit.t.sol # Circular cashout loop cap
163
+ ├── LockTerminalRace.t.sol # Lock terminal race condition
164
+ └── V4SpotPriceSlippage.t.sol # Sigmoid slippage math
150
165
  ```
151
166
 
152
167
  ## Payment Metadata
package/SKILLS.md CHANGED
@@ -115,7 +115,7 @@ Accept payments in any ERC-20 token (or native ETH), dynamically discover what t
115
115
  | Error | When |
116
116
  |-------|------|
117
117
  | `JBRouterTerminal_NoRouteFound(uint256 projectId, address tokenIn)` | No accepted token found for the project when iterating all terminals |
118
- | `JBRouterTerminal_TokenNotAccepted(uint256 projectId, address token)` | The `routeTokenOut` metadata override specifies a token the project does not accept |
118
+ | `JBRouterTerminal_NoRouteFound(uint256 projectId, address tokenIn)` | No accepted token found for the project, or the `routeTokenOut` metadata override specifies a token the project does not accept |
119
119
  | `JBRouterTerminal_CallerNotPool(address caller)` | V3 swap callback called by an address that is not a legitimate factory pool |
120
120
  | `JBRouterTerminal_CallerNotPoolManager(address caller)` | V4 unlock callback called by an address other than the PoolManager |
121
121
  | `JBRouterTerminal_SlippageExceeded(uint256 amountOut, uint256 minAmountOut)` | Swap output is below the minimum acceptable amount |
package/USER_JOURNEYS.md CHANGED
@@ -108,7 +108,7 @@ State touched: Source project's token supply (burned), terminal balances. Potent
108
108
  - **Slippage exceeded:** Reverts with `JBRouterTerminal_SlippageExceeded(amountOut, minAmountOut)`.
109
109
  - **Amount overflow:** Reverts with `JBRouterTerminal_AmountOverflow(amount)` if swap amount exceeds `type(uint128).max`, or if Permit2 transfer amount exceeds `type(uint160).max`.
110
110
  - **ETH sent with ERC-20 payment:** Reverts with `JBRouterTerminal_NoMsgValueAllowed(value)`.
111
- - **Router is destination terminal:** If `primaryTerminalOf` returns the router itself, it is skipped to prevent infinite recursion (line 625).
111
+ - **Router is destination terminal:** If `primaryTerminalOf` returns the router itself, it is skipped to prevent infinite recursion (line 624).
112
112
  - **Destination terminal reverts:** The entire transaction reverts atomically. No tokens are stuck.
113
113
  - **Destination terminal accepts tokens but misbehaves:** If it does not revert but does not credit the project, tokens are lost. No recovery mechanism.
114
114
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bananapus/router-terminal-v6",
3
- "version": "0.0.16",
3
+ "version": "0.0.17",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",