@bananapus/router-terminal-v6 0.0.15 → 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 +4 -3
- package/AUDIT_INSTRUCTIONS.md +4 -4
- package/README.md +16 -1
- package/SKILLS.md +1 -1
- package/USER_JOURNEYS.md +1 -1
- package/package.json +1 -1
- package/src/JBRouterTerminal.sol +641 -652
- package/src/JBRouterTerminalRegistry.sol +1 -11
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
|
|
57
|
-
and
|
|
58
|
-
|
|
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
|
package/AUDIT_INSTRUCTIONS.md
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
155
|
-
- `JBRouterTerminalRegistry._transferFrom()` line
|
|
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
|
-
|
|
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
|
-
| `
|
|
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
|
|
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
|
|