Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds an abstract flash-loan arbitrage router and a concrete Raindex router with on-chain route-leg processing (Sushi support), wires the new router into the ARB deployment, adds end-to-end tests/mocks for arb4, and adds a zero-division guard in OrderBookV6.takeOrders4. Changes
Sequence DiagramssequenceDiagram
participant User
participant DeployScript as Deploy Script
participant RaindexRouter as RaindexRouterOrderBookV6Arb
participant OrderBook as OrderBookV6
participant FlashLender as Flash Lender
participant RouteProcessor as RouteProcessor (Sushi)
User->>DeployScript: run deploy
DeployScript->>RaindexRouter: instantiate with config
User->>RaindexRouter: call arb4(orderBook, takeOrders, exchangeData)
RaindexRouter->>OrderBook: query vault balance / compute flashLoanAmount
RaindexRouter->>FlashLender: request flash loan(amount)
FlashLender->>RaindexRouter: onFlashLoan callback
RaindexRouter->>RaindexRouter: decode payload, _exchange(takeOrders, exchangeData)
RaindexRouter->>RouteProcessor: processRoute(tokenIn, amountIn, tokenOut, route)
RouteProcessor->>RaindexRouter: returns swapped amount
RaindexRouter->>OrderBook: finalize takeOrders with swap results
RaindexRouter->>FlashLender: repay flash loan
sequenceDiagram
participant Router as RaindexRouter
participant Decoder as Exchange Data Decoder
participant Processor as Route Processor
participant Token as ERC20 Token
Router->>Decoder: decode exchangeData -> RouteLeg[]
loop per RouteLeg
alt leg == SUSHI
Router->>Token: approve Processor(amount)
Router->>Processor: processRoute(tokenIn, amountIn, tokenOut, route)
Processor->>Router: return amountOut
Router->>Router: convert amountOut -> Float, propagate to next leg / takeOrders
Router->>Token: clear approval
else
Router->>Router: revert (not implemented)
end
end
Router->>Router: finalize arb and update IOs
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 Fix all issues with AI agents
In `@src/abstract/OrderBookV6RaindexRouter.sol`:
- Line 3: The pragma in OrderBookV6RaindexRouter.sol currently reads ^0.8.19
which mismatches the project standard; update the pragma directive at the top of
the file to use the exact compiler version =0.8.25 (replace the existing pragma
line) so the contract (OrderBookV6RaindexRouter) compiles with the project's
foundry.toml setting and remains consistent with other contracts.
- Around line 77-94: Add a check in onFlashLoan to validate that msg.sender is
the trusted lender (e.g., compare msg.sender to a stored sExpectedLender or to
the known orderBook address) and revert if it is not; additionally, in arb4 set
sExpectedLender = address(orderBook) immediately before calling flashLoan and
clear sExpectedLender after the call to avoid reuse. Ensure you update the
onFlashLoan function and the arb4 flow (setting/clearing sExpectedLender around
flashLoan) so the callback only accepts calls from the legitimate lender.
- Around line 125-129: The code accesses takeOrders[0] and takeOrders[1] before
validating the array length, which can cause an out-of-bounds revert; move the
require(takeOrders.length == 2, "Unexpected take orders config length") check to
before any access to takeOrders, then keep the existing empty-order check that
reverts IOrderBookV6.NoOrders() for takeOrders[0].orders.length == 0 ||
takeOrders[1].orders.length == 0; ensure you reference the same symbols
(takeOrders, IOrderBookV6.NoOrders) so the semantics don't change.
In `@src/concrete/arb/RaindexRouterOrderBookV6Arb.sol`:
- Around line 119-122: The fallback() function is not payable so it cannot
receive ETH as the comment implies; either replace it with a receive() external
payable {} if you only need to accept plain ETH transfers, or mark fallback() as
payable (fallback() external payable {}) if you need fallback behavior for
calldata too. Also remove the unused debugging artifact function a(RouteLeg
calldata x) (or, if intended, add a clear purpose/comment and usages) to
eliminate dead code; search for the symbol a and the RouteLeg type to
update/remove accordingly.
- Around line 101-105: The logic in RaindexRouterOrderBookV6Arb.sol that calls
LibDecimalFloat.toFixedDecimalLossy(LibDecimalFloat.FLOAT_ZERO, toTokenDecimals)
and then increments toTokenAmount when lossless==false is incorrect and
unnecessary; replace this block so the minimum output amount is zero
(toTokenAmount = 0) or, if slippage protection is required, compute the minimum
from the expected output (not from FLOAT_ZERO) using the expected output
variable and the appropriate rounding/decimal conversion routine; remove the
conditional increment branch tied to FLOAT_ZERO and the use of lossless in this
context (references: LibDecimalFloat.toFixedDecimalLossy, FLOAT_ZERO,
toTokenAmount, lossless).
In `@test/concrete/arb/RaindexRouterOrderBookV6Arb.t.sol`:
- Line 244: The assertion message is incorrect: update the assertEq call that
checks bobInputVaultBalance (the assertion using assertEq(bobInputVaultBalance,
5e19, "...")) to use a matching comment string such as "expected 50 token C
vault balance for bob input vault" (or equivalent) so the failure message
correctly identifies bob's input vault rather than mentioning Alice's output
vault.
- Around line 314-329: MockSushiRP::processRoute currently does unnecessary
self-approvals and uses transferFrom to move tokens the contract already holds
and ignores the `to` parameter; change it so the contract still pulls tokenIn
from msg.sender via IERC20(tokenIn).transferFrom(msg.sender, address(this),
amountIn) but remove any IERC20(tokenOut).approve calls and replace
IERC20(tokenOut).transferFrom(address(this), msg.sender, amountIn) with
IERC20(tokenOut).transfer(to, amountOut) (or transfer(to, amountIn) to mirror
current return) so tokens are sent to the `to` recipient and no self-approval is
performed. Ensure the function returns the correct amountOut as before.
- Around line 126-245: Add additional focused test functions alongside
testArb4Success to cover edge cases and failure paths: 1) zero-order amounts —
create orders via createOrder with zero quantities and assert router.arb4
reverts or no balances change; 2) token mismatch between legs — build RouteLegs
where encoded tokens don't line up (e.g., route leg uses token pair that doesn't
connect alice/bob orders) and assert arb4 reverts or results in no execution; 3)
swap/flashloan failure — simulate failing SUSHI by deploying a mock that reverts
on expected call and assert router.arb4 reverts and vault balances unchanged; 4)
unsupported RouteLegType — pass an unimplemented RouteLegType and assert revert;
and 5) task validation/access control — pass a TaskV2 with invalid EvaluableV4
(e.g., empty interpreter/store or malformed bytecode) and assert arb4 reverts;
reference testArb4Success, router.arb4, createTakeOrdersConfig,
RouteLeg/RouteLegType, TaskV2, and createOrder to locate where to add each new
test and which assertions to check (revert or specific balance invariants).
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/abstract/OrderBookV6RaindexRouter.sol`:
- Around line 159-160: Guard against a zero flash loan amount by checking the
computed flashLoanAmount (from
IERC20(startTakeOrdersInputToken).balanceOf(address(orderBook)) / 2) before
converting to Float via LibDecimalFloat.fromFixedDecimalLosslessPacked; if
flashLoanAmount == 0 revert with a clear error (e.g., "ZeroFlashLoanAmount") or
return early so you don't attempt a no-op or trigger FlashLoanFailed—update the
logic around the flashLoanAmount variable and any callers that assume a non-zero
Float to handle this short-circuit.
In `@src/concrete/arb/RaindexRouterOrderBookV6Arb.sol`:
- Around line 70-73: After constructing the route, add an explicit assertion
that the token produced by the final leg (prevLegTokenAddress) matches the token
expected by the end order (endTakeOrdersInputToken) before performing the
approvals; specifically, in the section that computes endTakeOrdersInputToken
and then calls IERC20(...).forceApprove(msg.sender, ...), insert a require/check
that prevLegTokenAddress == endTakeOrdersInputToken (with a clear revert
message) so the contract cannot approve the wrong token to the orderbook when
exchangeData/leg ordering is misconfigured.
- Line 87: Remove the stale Slither suppression "slither-disable-next-line
no-unused-vars" that sits above/near the _processSushiLeg usage; since
_processSushiLeg (and its parameters/returns) are used, this no-unused-vars
disable is incorrect and should be deleted (and verify there are no other
unnecessary "no-unused-vars" suppressions around the _processSushiLeg
declaration or its callers); if you intended to suppress a real finding, replace
it with the specific, correct Slither pragma for that particular issue instead
of masking no-unused-vars.
---
Duplicate comments:
In `@src/abstract/OrderBookV6RaindexRouter.sol`:
- Line 3: Update the Solidity pragma to exactly match the project's compiler
version by replacing the current pragma declaration with "pragma solidity
=0.8.25;" so the contract (OrderBookV6RaindexRouter) compiles with the version
specified in foundry.toml; ensure no other files in this contract still use a
different pragma specifier.
- Around line 77-84: The onFlashLoan function currently only checks initiator
and should also validate that msg.sender is the trusted lender; add a check in
onFlashLoan that reverts (reuse BadInitiator or add a new error like BadLender)
if msg.sender != <trusted lender storage variable> (e.g., trustedLender or
lender) before proceeding, so the contract only accepts callbacks from the
authorized lender.
In `@src/concrete/arb/RaindexRouterOrderBookV6Arb.sol`:
- Around line 114-115: The fallback() function is non-payable but the comment
says "Allow receiving gas" (i.e., accept ETH); add a receive() external payable
{} to accept plain ETH transfers (e.g., from WETH unwrap) or make fallback()
payable if you intend arbitrary calldata ETH receipts; update the contract by
adding receive() external payable {} (and leave fallback() as-is or change
fallback() to fallback() external payable {} only if you need fallback to accept
ETH with calldata).
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/abstract/OrderBookV6RaindexRouter.sol`:
- Around line 165-173: Capture and check the boolean success flag returned by
orderBook.quote2 instead of discarding it; change the tuple unpacking to (bool
exists, Float maxOutput, Float iORatio) when calling orderBook.quote2 (the call
inside the block that builds QuoteV2 from takeOrders[1].orders[0]) and if exists
is false revert/abort the flow (e.g., revert or skip) so you don't silently
continue with maxOutput == 0 and set takeOrders[0].maximumIO incorrectly; also
remove the //slither-disable-next-line unused-return and, to satisfy the linter,
explicitly reference any intentionally unused return values in a no-op statement
rather than suppressing the warning.
- Around line 178-184: The cap assigned to takeOrders[0].maximumIO is
denominated in startTakeOrdersInputToken (variables maxOutput and
flashLoanAmountFloat) but is applied with IOIsInput = false which limits the
first order's output token—mismatching token denominations; to fix, when the
intention is to limit clearing by the last order's capacity, convert the chosen
minimum (min(maxOutput, flashLoanAmountFloat)) from startTakeOrdersInputToken
into the token units of takeOrders[0]’s output before assigning to
takeOrders[0].maximumIO (preserving IOIsInput = false), taking into account
token decimals and exchange rate/price (use existing normalization/price
conversion helpers or introduce a conversion using the route/order price) so the
cap correctly matches the first order’s output token; alternatively, if you
meant to cap the first order’s input instead, set takeOrders[0].IOIsInput = true
and assign the min directly to maximumIO but document the change.
---
Duplicate comments:
In `@src/abstract/OrderBookV6RaindexRouter.sol`:
- Line 3: The file's Solidity pragma currently uses "^0.8.19" which mismatches
the project standard; update the pragma line in OrderBookV6RaindexRouter.sol to
use the exact compiler version "=0.8.25" (replace the existing "pragma solidity
^0.8.19;" with "pragma solidity =0.8.25;") so it aligns with foundry.toml and
project guidelines.
- Around line 159-160: The computed flashLoanAmount
(IERC20(startTakeOrdersInputToken).balanceOf(address(orderBook)) / 2) can be
zero for balances 0 or 1, so add a guard before calling
LibDecimalFloat.fromFixedDecimalLosslessPacked: read balance into a local (e.g.,
orderBookBalance), compute flashLoanAmount = orderBookBalance / 2, and if
flashLoanAmount == 0 either revert with a clear error (e.g.,
"NoFlashLoanLiquidity") or return/skip the flow; only call
LibDecimalFloat.fromFixedDecimalLosslessPacked(flashLoanAmount,
startInputDecimals) when flashLoanAmount > 0 to avoid no-op arbs or
FlashLoanFailed reverts. Ensure checks reference the variables flashLoanAmount,
orderBookBalance, and the call to LibDecimalFloat.fromFixedDecimalLosslessPacked
so maintainers can locate the fix.
- Around line 78-95: The onFlashLoan callback currently only checks initiator ==
address(this) but fails to validate msg.sender, allowing a malicious lender to
spoof initiator; add a check at the start of onFlashLoan to require msg.sender
== address(orderBook) (or the contract's trusted flash-lender/OrderBook address
variable) and revert if not (use an existing error like BadInitiator or add
BadFlashLender), keeping the existing initiator check and performing this
validation before abi.decode(...) and before calling _exchange(takeOrders,
exchangeData); this ensures only the trusted OrderBook/flash-lender can invoke
onFlashLoan.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/concrete/arb/RaindexRouterOrderBookV6Arb.sol`:
- Around line 104-106: The call to
IRouteProcessor(routeLeg.destination).processRoute currently passes amountOutMin
= 0 which provides no slippage protection; compute a conservative minimum (e.g.,
multiply the expected output derived from prevLegOutputAmount and the
known/quoted rate by a safety factor like 95–99%) and pass that as the minOut
parameter instead of 0, then check the returned amountOut against that minimum
and revert if it is below it; update the call site where processRoute is invoked
(the IRouteProcessor(routeLeg.destination).processRoute(...) call that sets
amountOut) to compute and use amountOutMin from prevLegOutputAmount/expected
rate and enforce the check.
- Around line 59-65: Replace the string reverts for unimplemented RouteLegType
cases with custom errors to save gas: declare a custom error (e.g., error
UnimplementedRouteLeg(RouteLegType legType) or distinct errors like error
RaindexNotImplemented();) and update the checks in
RaindexRouterOrderBookV6Arb.sol where you currently do revert("raindex route leg
type is not yet implemented") / revert("balancer route leg type is not yet
implemented") / revert("stabull route leg type is not yet implemented") to use
revert UnimplementedRouteLeg(leg.routeLegType) or revert RaindexNotImplemented()
etc.; ensure the error is declared at contract or file scope and replace each
string-based revert in the branch handling RouteLegType.RAINDEX,
RouteLegType.BALANCER and RouteLegType.STABULL accordingly.
---
Duplicate comments:
In `@src/concrete/arb/RaindexRouterOrderBookV6Arb.sol`:
- Around line 114-115: The fallback() function is currently non-payable so the
contract cannot accept ETH despite the comment; update the contract to allow
receiving ETH by adding a receive() external payable {} function (or making
fallback() external payable if you prefer to handle calldata) so that WETH
unwraps or refunds do not revert—locate the fallback() definition and either add
the receive() external payable {} or change fallback() to fallback() external
payable {} accordingly.
- Line 87: Remove the stale Slither suppression comment
"//slither-disable-next-line no-unused-vars" because the function
_processSushiLeg uses all its parameters and return values; locate the
suppression immediately above _processSushiLeg and delete that line (or replace
it with a relevant, justified slither rule if another true positive exists) so
the code no longer contains an unnecessary no-unused-vars suppression.
- Around line 70-73: After constructing the route legs, the code independently
reads endTakeOrdersInputToken from takeOrders but never verifies it matches
prevLegTokenAddress (the last swap output), so approvals may be applied to the
wrong token; update the logic in the section using prevLegTokenAddress and
endTakeOrdersInputToken to assert they are equal (e.g.,
require(prevLegTokenAddress == endTakeOrdersInputToken, "mismatched route
token")), or else use prevLegTokenAddress directly for the approve calls
(replace the read of endTakeOrdersInputToken or add a require) so the contract
approves the actual last-leg output token before calling takeOrders4.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (4)
src/abstract/OrderBookV6RaindexRouter.sol (4)
3-3: Pragma version mismatch — still not addressed.As per coding guidelines: "Use Solidity compiler version 0.8.25 as specified in
foundry.toml"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/abstract/OrderBookV6RaindexRouter.sol` at line 3, The pragma in OrderBookV6RaindexRouter.sol is using ^0.8.19 but the project requires Solidity 0.8.25; update the pragma directive at the top of the file from ^0.8.19 to ^0.8.25 so the contract (OrderBookV6RaindexRouter) compiles with the version specified in foundry.toml and matches project guidelines.
159-160: No guard against zero flash loan amount — still unaddressed.If the orderbook holds 0 or 1 wei of the token,
balanceOf / 2truncates to 0, leading to a wasted-gas no-op or an opaqueFlashLoanFailedrevert.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/abstract/OrderBookV6RaindexRouter.sol` around lines 159 - 160, The code computes flashLoanAmount by dividing IERC20(startTakeOrdersInputToken).balanceOf(address(orderBook)) by 2 then converts it to a Float; add a guard that checks the raw balance or flashLoanAmount before calling LibDecimalFloat.fromFixedDecimalLosslessPacked to avoid a zero flash loan. Specifically, read the balance (via IERC20(...).balanceOf(address(orderBook))) or use flashLoanAmount and require flashLoanAmount > 0 (or balance >= 2 if you want to ensure a non-truncated half) and revert or skip the flash-loan path with a clear error if the check fails, placing this check before calling LibDecimalFloat.fromFixedDecimalLosslessPacked and any subsequent flash-loan logic.
178-185:maximumIOcap applied in wrong token denomination — still unaddressed.Both
flashLoanAmountFloatandmaxOutputare denominated instartTakeOrdersInputToken, butIOIsInput = false(line 185) meansmaximumIOcaps the output oftakeOrders[0], which is the intermediate token. For non-1:1/non-identical-decimals pairs, this constraint is applied in the wrong units.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/abstract/OrderBookV6RaindexRouter.sol` around lines 178 - 185, The cap for takeOrders[0].maximumIO is being applied using flashLoanAmountFloat and maxOutput which are denominated in startTakeOrdersInputToken, but since takeOrders[0].IOIsInput is set to false the cap must be applied in the intermediate/output token units; update the logic that sets takeOrders[0].maximumIO (and the comparisons using LibDecimalFloat.gt) to first convert flashLoanAmountFloat and maxOutput into the takeOrders[0] output denomination (using the same conversion/price/decimal helper used elsewhere for startTakeOrders → intermediate conversions), then compare and set maximumIO in that output unit, and keep IOIsInput = false; ensure you reference and use the same conversion routine used by the router to avoid mismatched decimals.
78-95: Missingmsg.sendervalidation inonFlashLoan— still unaddressed.The callback only checks
initiator == address(this)but never verifies thatmsg.senderis the trusted lender (orderbook). A malicious contract could callonFlashLoandirectly withinitiator = address(this)and attacker-controlleddata, causing_exchangeto execute with arbitrary decoded parameters.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/abstract/OrderBookV6RaindexRouter.sol` around lines 78 - 95, The onFlashLoan callback currently only checks initiator but must also verify msg.sender is the trusted lender; update the onFlashLoan function to require msg.sender == <trusted lender address/state> (for example an existing state variable like orderBook or a dedicated lender address set in the contract) and revert with a clear error (e.g., BadLender(msg.sender) or reuse BadInitiator) before decoding/dispatching to _exchange; ensure the trusted lender value is read from the existing state or an accessor (add one if missing) so untrusted contracts cannot call onFlashLoan with initiator == address(this).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/abstract/OrderBookV6RaindexRouter.sol`:
- Around line 175-176: The first explicit call to
IERC20(startTakeOrdersInputToken).forceApprove(address(orderBook), 0) is
redundant because OpenZeppelin's forceApprove already handles the zero-then-set
pattern for non-standard tokens; remove that first call and keep a single
IERC20(startTakeOrdersInputToken).forceApprove(address(orderBook),
type(uint256).max) to set the full allowance for the orderBook (referencing
startTakeOrdersInputToken and orderBook in OrderBookV6RaindexRouter); this
eliminates the wasted gas while preserving correct approval semantics.
---
Duplicate comments:
In `@src/abstract/OrderBookV6RaindexRouter.sol`:
- Line 3: The pragma in OrderBookV6RaindexRouter.sol is using ^0.8.19 but the
project requires Solidity 0.8.25; update the pragma directive at the top of the
file from ^0.8.19 to ^0.8.25 so the contract (OrderBookV6RaindexRouter) compiles
with the version specified in foundry.toml and matches project guidelines.
- Around line 159-160: The code computes flashLoanAmount by dividing
IERC20(startTakeOrdersInputToken).balanceOf(address(orderBook)) by 2 then
converts it to a Float; add a guard that checks the raw balance or
flashLoanAmount before calling LibDecimalFloat.fromFixedDecimalLosslessPacked to
avoid a zero flash loan. Specifically, read the balance (via
IERC20(...).balanceOf(address(orderBook))) or use flashLoanAmount and require
flashLoanAmount > 0 (or balance >= 2 if you want to ensure a non-truncated half)
and revert or skip the flash-loan path with a clear error if the check fails,
placing this check before calling LibDecimalFloat.fromFixedDecimalLosslessPacked
and any subsequent flash-loan logic.
- Around line 178-185: The cap for takeOrders[0].maximumIO is being applied
using flashLoanAmountFloat and maxOutput which are denominated in
startTakeOrdersInputToken, but since takeOrders[0].IOIsInput is set to false the
cap must be applied in the intermediate/output token units; update the logic
that sets takeOrders[0].maximumIO (and the comparisons using LibDecimalFloat.gt)
to first convert flashLoanAmountFloat and maxOutput into the takeOrders[0]
output denomination (using the same conversion/price/decimal helper used
elsewhere for startTakeOrders → intermediate conversions), then compare and set
maximumIO in that output unit, and keep IOIsInput = false; ensure you reference
and use the same conversion routine used by the router to avoid mismatched
decimals.
- Around line 78-95: The onFlashLoan callback currently only checks initiator
but must also verify msg.sender is the trusted lender; update the onFlashLoan
function to require msg.sender == <trusted lender address/state> (for example an
existing state variable like orderBook or a dedicated lender address set in the
contract) and revert with a clear error (e.g., BadLender(msg.sender) or reuse
BadInitiator) before decoding/dispatching to _exchange; ensure the trusted
lender value is read from the existing state or an accessor (add one if missing)
so untrusted contracts cannot call onFlashLoan with initiator == address(this).
Motivation
This PR adds Raindex Router Arb contract, which can perform routed
takeOrders()by doing a flash loan and making a intermediate swap through external source (or even can be another raindex order although this PR only implements the sushi RP handler), here is a simple example:Note: The maximum clearable amount in this case cannot exceed
total orderbook balance of token A / 2, thats because we cant take all the orderbook token A balance as loan since we need them for the lasttakeOrder()to complete, example:Assume the order C/A has deposited 100 A tokens, and thats all the A tokens orderbook has, so at most half of it can be flash loaned, which goes towards taking the first order and next half that stayed in orderbook for taking the last order
Solution
Checks
By submitting this for review, I'm confirming I've done the following:
Summary by CodeRabbit
New Features
Bug Fixes
Tests