@@ -107,7 +107,7 @@ contract ArbitraryEVMFlowExecutorTest is Test {
107107 });
108108 }
109109
110- // ----- Branch 1: action fails -> initialToken returned, finalToken rewritten to initialToken -----
110+ // ----- Action fails -> initialToken returned, finalToken rewritten to initialToken -----
111111 function testActionFails_FallsBackToInitialToken () public {
112112 tokenIn.mint (address (harness), 1000e6 );
113113
@@ -127,8 +127,7 @@ contract ArbitraryEVMFlowExecutorTest is Test {
127127 assertEq (tokenIn.balanceOf (address (multicallHandler)), 0 , "handler drained " );
128128 }
129129
130- // ----- Branch 2: same input/output token, action consumes more than it returns -----
131- // Pre-fix this case incorrectly reported finalAmount = 0.
130+ // ----- Same input/output token, action consumes more than it returns (net loss) -----
132131 function testSameToken_PartialConsumption () public {
133132 tokenIn.mint (address (harness), 1000e6 );
134133 tokenIn.mint (address (swap), 1000e6 ); // pre-fund swap with output liquidity
@@ -145,13 +144,14 @@ contract ArbitraryEVMFlowExecutorTest is Test {
145144 CommonFlowParams memory out = harness.executeFlow (p);
146145
147146 assertEq (out.finalToken, address (tokenIn), "finalToken unchanged " );
148- assertEq (out.amountInEVM, 400e6 , "finalAmount = amountInEVM - (X - Y) = 500 - 100 = 400 " );
147+ // finalAmount = amountInEVM + eBI - sBI = 500 + 900 - 1000 = 400.
148+ assertEq (out.amountInEVM, 400e6 , "credits net delta against amountInEVM " );
149149 // Harness: 1000 - 500 transfer + 400 drain back = 900.
150150 assertEq (tokenIn.balanceOf (address (harness)), 900e6 );
151151 assertEq (tokenIn.balanceOf (address (multicallHandler)), 0 );
152152 }
153153
154- // ----- Branch 1 (no-op): same token, empty calls -> full amountInEVM returned -----
154+ // ----- Same token, empty calls -> full amountInEVM returned -----
155155 function testSameToken_NoCalls () public {
156156 tokenIn.mint (address (harness), 1000e6 );
157157
@@ -165,9 +165,8 @@ contract ArbitraryEVMFlowExecutorTest is Test {
165165 assertEq (tokenIn.balanceOf (address (harness)), 1000e6 , "harness balance unchanged " );
166166 }
167167
168- // ----- Edge case: same token, profitable (Y > X) ----
169- // The `<=` in branch 1 swallows the surplus; documents current behaviour.
170- function testSameToken_Profitable_SurplusStaysInContract () public {
168+ // ----- Same token, profitable (Y > X) -> surplus is credited to finalAmount -----
169+ function testSameToken_Profitable_SurplusIsCredited () public {
171170 tokenIn.mint (address (harness), 1000e6 );
172171 tokenIn.mint (address (swap), 1000e6 );
173172
@@ -183,13 +182,12 @@ contract ArbitraryEVMFlowExecutorTest is Test {
183182 CommonFlowParams memory out = harness.executeFlow (p);
184183
185184 assertEq (out.finalToken, address (tokenIn));
186- // Branch 1 triggers (initialBalance > initialAmountSnapshot via `<=`); reports the original input.
187- assertEq (out.amountInEVM, 500e6 , "branch 1 reports amountInEVM, ignoring surplus " );
188- // Harness physically holds 1000 - 500 + 600 = 1100. Surplus of 100 is held but unreported.
189- assertEq (tokenIn.balanceOf (address (harness)), 1100e6 , "surplus is retained in the contract " );
185+ // finalAmount = amountInEVM + eBI - sBI = 500 + 1100 - 1000 = 600.
186+ assertEq (out.amountInEVM, 600e6 , "surplus is credited via balance delta " );
187+ assertEq (tokenIn.balanceOf (address (harness)), 1100e6 , "harness physically holds the surplus " );
190188 }
191189
192- // ----- Branch 3: different tokens, normal swap -----
190+ // ----- Different tokens, normal swap -----
193191 function testDifferentTokens_NormalSwap () public {
194192 tokenIn.mint (address (harness), 1000e6 );
195193 tokenOut.mint (address (swap), 1000e6 );
@@ -210,10 +208,8 @@ contract ArbitraryEVMFlowExecutorTest is Test {
210208 assertEq (tokenOut.balanceOf (address (harness)), 400e6 , "tokenOut received " );
211209 }
212210
213- // ----- Pre-existing handler dust in initialToken must not orphan the swap output -----
214- // Pre-fix: initialBalance from dust drain triggered the "swap didn't happen" branch,
215- // rewriting finalToken to initialToken and stranding the actual finalToken output in the executor.
216- function testDifferentTokens_HandlerDustInInitialToken_DoesNotOrphanSwapOutput () public {
211+ // ----- Pre-existing handler dust in initialToken is drained upfront and not credited to the flow -----
212+ function testDifferentTokens_HandlerDustInInitialToken_IsDrainedUpfront () public {
217213 tokenIn.mint (address (harness), 1000e6 );
218214 tokenIn.mint (address (multicallHandler), 500e6 ); // pre-existing dust on handler
219215 tokenOut.mint (address (swap), 1000e6 );
@@ -228,17 +224,43 @@ contract ArbitraryEVMFlowExecutorTest is Test {
228224 EVMFlowParams memory p = _params (address (tokenIn), address (tokenOut), 500e6 , abi.encode (calls));
229225 CommonFlowParams memory out = harness.executeFlow (p);
230226
231- assertEq (out.finalToken, address (tokenOut), "finalToken must remain tokenOut despite handler dust " );
232- assertEq (out.amountInEVM, 400e6 , "credits actual swap output, not stale initialAmountSnapshot " );
233- // Harness physically holds 1000 - 500 transferred + 500 dust returned = 1000 tokenIn,
234- // plus the 400 tokenOut from the swap. The dust stays on the executor but is not credited to the user.
235- assertEq (tokenIn.balanceOf (address (harness)), 1000e6 , "handler dust drained back to executor " );
236- assertEq (tokenOut.balanceOf (address (harness)), 400e6 , "swap output preserved " );
237- assertEq (tokenIn.balanceOf (address (multicallHandler)), 0 , "handler fully drained " );
227+ assertEq (out.finalToken, address (tokenOut));
228+ assertEq (out.amountInEVM, 400e6 , "credits finalToken balance delta only " );
229+ // _drainMulticallHandlerDust pulled 500 tokenIn back to the harness before the snapshot,
230+ // so sBI captured it and the swap delta is unaffected by the dust.
231+ assertEq (tokenIn.balanceOf (address (harness)), 1000e6 );
232+ assertEq (tokenOut.balanceOf (address (harness)), 400e6 );
233+ assertEq (tokenIn.balanceOf (address (multicallHandler)), 0 );
234+ assertEq (tokenOut.balanceOf (address (multicallHandler)), 0 );
235+ }
236+
237+ // ----- Pre-existing handler dust in finalToken is drained upfront and not credited to the flow -----
238+ function testDifferentTokens_HandlerDustInFinalToken_IsDrainedUpfront () public {
239+ tokenIn.mint (address (harness), 1000e6 );
240+ tokenOut.mint (address (multicallHandler), 250e6 ); // pre-existing finalToken dust on handler
241+ tokenOut.mint (address (swap), 1000e6 );
242+
243+ ArbitraryEVMFlowExecutor.CompressedCall[] memory calls = _buildSwapCalls (
244+ address (tokenIn),
245+ address (tokenOut),
246+ 500e6 ,
247+ 400e6
248+ );
249+
250+ EVMFlowParams memory p = _params (address (tokenIn), address (tokenOut), 500e6 , abi.encode (calls));
251+ CommonFlowParams memory out = harness.executeFlow (p);
252+
253+ assertEq (out.finalToken, address (tokenOut));
254+ // Without the upfront drain, sBF would have started at 250 and the swap's 400 output
255+ // would still pass eBF > sBF. Verifying 400e6 here also confirms the dust wasn't double-credited.
256+ assertEq (out.amountInEVM, 400e6 , "finalAmount = eBF - sBF, dust excluded by upfront drain " );
257+ // Harness keeps the drained dust (250) + swap output (400) = 650 tokenOut.
258+ assertEq (tokenOut.balanceOf (address (harness)), 650e6 );
259+ assertEq (tokenIn.balanceOf (address (multicallHandler)), 0 );
238260 assertEq (tokenOut.balanceOf (address (multicallHandler)), 0 );
239261 }
240262
241- // ----- Branch 3 ( partial consumption): different tokens, leftover initialToken returned -----
263+ // ----- Different tokens, partial consumption: leftover initialToken returned by handler's tail drain -----
242264 function testDifferentTokens_PartialConsumption_LeftoverInitialTokenReturned () public {
243265 tokenIn.mint (address (harness), 1000e6 );
244266 tokenOut.mint (address (swap), 1000e6 );
@@ -255,9 +277,9 @@ contract ArbitraryEVMFlowExecutorTest is Test {
255277 CommonFlowParams memory out = harness.executeFlow (p);
256278
257279 assertEq (out.finalToken, address (tokenOut));
258- assertEq (out.amountInEVM, 400e6 , "credits finalToken received " );
259- // The 200 of unspent initialToken at handler is drained by MulticallHandler 's tail drain.
260- assertEq (tokenIn.balanceOf (address (harness)), 700e6 , " 1000 - 500 transferred + 200 leftover returned " );
280+ assertEq (out.amountInEVM, 400e6 , "finalAmount = eBF - sBF ( finalToken delta) " );
281+ // The 200 of unspent initialToken left at handler is returned by handleV3AcrossMessage 's tail drain.
282+ assertEq (tokenIn.balanceOf (address (harness)), 700e6 );
261283 assertEq (tokenOut.balanceOf (address (harness)), 400e6 );
262284 assertEq (tokenIn.balanceOf (address (multicallHandler)), 0 );
263285 }
0 commit comments