Skip to content

Commit 8489571

Browse files
fix: clear3 refuses a side on its raw calculation, before dividing by its ratio
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent e78441a commit 8489571

7 files changed

Lines changed: 56 additions & 23 deletions

File tree

‎crates/test_fixtures/abis/RaindexV6.json‎

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

‎src/concrete/raindex/RaindexV6.sol‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -628,19 +628,20 @@ contract RaindexV6 is IRaindexV6, IMetaV1_2, ReentrancyGuard, Multicall, Raindex
628628
new bytes32[](0)
629629
);
630630

631-
ClearStateChangeV2 memory clearStateChange =
632-
calculateClearStateChange(aliceOrderIOCalculation, bobOrderIOCalculation);
633-
634-
// Each side must be one `takeOrders4` would take.
631+
// Each side must be one `takeOrders4` would take. Given this, each
632+
// computed output is positive or the Float math reverts.
635633
if (
636-
!clearStateChange.aliceOutput.gt(LibDecimalFloat.FLOAT_ZERO)
637-
|| !clearStateChange.bobOutput.gt(LibDecimalFloat.FLOAT_ZERO)
634+
!aliceOrderIOCalculation.outputMax.gt(LibDecimalFloat.FLOAT_ZERO)
635+
|| !bobOrderIOCalculation.outputMax.gt(LibDecimalFloat.FLOAT_ZERO)
638636
|| aliceOrderIOCalculation.IORatio.lt(LibDecimalFloat.FLOAT_ZERO)
639637
|| bobOrderIOCalculation.IORatio.lt(LibDecimalFloat.FLOAT_ZERO)
640638
) {
641639
revert ClearZeroAmount();
642640
}
643641

642+
ClearStateChangeV2 memory clearStateChange =
643+
calculateClearStateChange(aliceOrderIOCalculation, bobOrderIOCalculation);
644+
644645
Float aliceBounty = clearStateChange.aliceOutput.sub(clearStateChange.bobInput);
645646
Float bobBounty = clearStateChange.bobOutput.sub(clearStateChange.aliceInput);
646647

‎src/generated/candidate/GenericPoolRaindexV6ArbOrderTaker.sol‎

Lines changed: 4 additions & 4 deletions
Large diffs are not rendered by default.

‎src/generated/candidate/GenericPoolRaindexV6FlashBorrower.sol‎

Lines changed: 4 additions & 4 deletions
Large diffs are not rendered by default.

‎src/generated/candidate/RaindexV6.sol‎

Lines changed: 4 additions & 4 deletions
Large diffs are not rendered by default.

‎src/generated/candidate/RouteProcessorRaindexV6ArbOrderTaker.sol‎

Lines changed: 4 additions & 4 deletions
Large diffs are not rendered by default.

‎test/concrete/raindex/RaindexV6.clear.freshDriver.t.sol‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pragma solidity =0.8.25;
44

55
import {Test, Vm} from "forge-std-1.17.0/src/Test.sol";
66
import {NegativeBounty, ClearZeroAmount} from "src/error/ErrRaindexV6.sol";
7+
import {ExponentUnderflow} from "rain-math-float-0.3.10/src/error/ErrDecimalFloat.sol";
78
import {
89
OrderV4,
910
OrderConfigV4,
@@ -393,6 +394,37 @@ contract RaindexV6ClearFreshDriverTest is Test {
393394
assertTrue(raindex.vaultBalance2(bountyBot, address(token0), ALICE_BOUNTY_VAULT).eq(f(1, 0)), "alice bounty 1");
394395
}
395396

397+
/// A zero ratio caps against a negative counterparty max, which would
398+
/// divide by that zero ratio if the sides were not refused first.
399+
function testFreshClearAliceZeroRatioBobNegativeOutputReverts() external {
400+
expectClearZeroAmount(f(0, 0), f(1, 0), f(1, 0), f(-1, 0));
401+
}
402+
403+
function testFreshClearBobZeroRatioAliceNegativeOutputReverts() external {
404+
expectClearZeroAmount(f(1, 0), f(-1, 0), f(0, 0), f(1, 0));
405+
}
406+
407+
/// Both sides pass the refusal but the capped output, the smallest max
408+
/// over the largest ratio, is below every non-zero Float: the division
409+
/// reverts rather than yielding a zero output.
410+
function testFreshClearAliceCappedOutputUnderflowReverts() external {
411+
(OrderV4 memory aliceOrder, OrderV4 memory bobOrder) =
412+
wireOrders(f(1, type(int32).max), f(1, 0), f(1, 0), f(1, type(int32).min), f(10, 0));
413+
414+
vm.prank(bountyBot);
415+
vm.expectPartialRevert(ExponentUnderflow.selector);
416+
raindex.clear3(aliceOrder, bobOrder, clearConfig(), new SignedContextV1[](0), new SignedContextV1[](0));
417+
}
418+
419+
function testFreshClearBobCappedOutputUnderflowReverts() external {
420+
(OrderV4 memory aliceOrder, OrderV4 memory bobOrder) =
421+
wireOrders(f(1, 0), f(1, type(int32).min), f(1, type(int32).max), f(1, 0), f(10, 0));
422+
423+
vm.prank(bountyBot);
424+
vm.expectPartialRevert(ExponentUnderflow.selector);
425+
raindex.clear3(aliceOrder, bobOrder, clearConfig(), new SignedContextV1[](0), new SignedContextV1[](0));
426+
}
427+
396428
// ---------------------------------------------------------------------
397429
// Vault-0 (token-plumbing) clear: record ordering / pushVaultZeroInput (B11)
398430
// ---------------------------------------------------------------------

0 commit comments

Comments
 (0)