From 74f1d3e24187381099f5a126e85e653cc94e30ca Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Fri, 25 Aug 2023 18:35:47 +0400 Subject: [PATCH 1/6] wip on flash swap style --- src/abstract/OrderBookFlashBorrower.sol | 6 ++--- src/abstract/OrderBookFlashLender.sol | 4 +++- .../GenericPoolOrderBookFlashBorrower.sol | 2 +- src/concrete/OrderBook.sol | 22 ++++++++++++++---- src/interface/unstable/IOrderBookV3.sol | 9 ++++++-- .../unstable/IOrderBookV3OrderTaker.sol | 23 +++++++++++++++++++ ...ricPoolOrderBookFlashBorrower.sender.t.sol | 10 ++++---- test/util/abstract/IOrderBookV3Stub.sol | 2 +- 8 files changed, 61 insertions(+), 17 deletions(-) create mode 100644 src/interface/unstable/IOrderBookV3OrderTaker.sol diff --git a/src/abstract/OrderBookFlashBorrower.sol b/src/abstract/OrderBookFlashBorrower.sol index 26a95b1c7..1d88c81ca 100644 --- a/src/abstract/OrderBookFlashBorrower.sol +++ b/src/abstract/OrderBookFlashBorrower.sol @@ -197,7 +197,7 @@ abstract contract OrderBookFlashBorrower is /// @param takeOrders As per `arb`. /// @param exchangeData As per `arb`. //slither-disable-next-line dead-code - function _exchange(TakeOrdersConfig memory takeOrders, bytes memory exchangeData) internal virtual {} + function _exchange(TakeOrdersConfigV2 memory takeOrders, bytes memory exchangeData) internal virtual {} /// @inheritdoc IERC3156FlashBorrower function onFlashLoan(address initiator, address, uint256, uint256, bytes calldata data) @@ -214,7 +214,7 @@ abstract contract OrderBookFlashBorrower is revert BadInitiator(initiator); } - (TakeOrdersConfig memory takeOrders, bytes memory exchangeData) = abi.decode(data, (TakeOrdersConfig, bytes)); + (TakeOrdersConfigV2 memory takeOrders, bytes memory exchangeData) = abi.decode(data, (TakeOrdersConfigV2, bytes)); // Dispatch the `_exchange` hook to ensure we have the correct asset // type and amount to fill the orders. @@ -259,7 +259,7 @@ abstract contract OrderBookFlashBorrower is /// for decoding this data and defining how it controls interactions with /// the external liquidity. For example, `GenericPoolOrderBookFlashBorrower` /// uses this data as a literal encoded external call. - function arb(TakeOrdersConfig calldata takeOrders, uint256 minimumSenderOutput, bytes calldata exchangeData) + function arb(TakeOrdersConfigV2 calldata takeOrders, uint256 minimumSenderOutput, bytes calldata exchangeData) external nonReentrant onlyNotInitializing diff --git a/src/abstract/OrderBookFlashLender.sol b/src/abstract/OrderBookFlashLender.sol index a2fbb95f3..9c4ff2aab 100644 --- a/src/abstract/OrderBookFlashLender.sol +++ b/src/abstract/OrderBookFlashLender.sol @@ -97,7 +97,8 @@ abstract contract OrderBookFlashLender is IERC3156FlashLender { /// @param token The token being sent or for the debt being paid. /// @param receiver The receiver of the token or holder of the debt. /// @param sendAmount The amount to send or repay. - function _decreaseFlashDebtThenSendToken(address token, address receiver, uint256 sendAmount) internal { + /// @return The final amount sent after any debt repayment. + function _decreaseFlashDebtThenSendToken(address token, address receiver, uint256 sendAmount) internal returns (uint256) { // If this token transfer matches the active debt then prioritise // reducing debt over sending tokens. if (token == _sToken && receiver == address(_sReceiver)) { @@ -112,6 +113,7 @@ abstract contract OrderBookFlashLender is IERC3156FlashLender { if (sendAmount > 0) { IERC20(token).safeTransfer(receiver, sendAmount); } + return sendAmount; } /// @inheritdoc IERC3156FlashLender diff --git a/src/concrete/GenericPoolOrderBookFlashBorrower.sol b/src/concrete/GenericPoolOrderBookFlashBorrower.sol index 35ff17214..d7e8ea4d3 100644 --- a/src/concrete/GenericPoolOrderBookFlashBorrower.sol +++ b/src/concrete/GenericPoolOrderBookFlashBorrower.sol @@ -30,7 +30,7 @@ contract GenericPoolOrderBookFlashBorrower is OrderBookFlashBorrower { {} /// @inheritdoc OrderBookFlashBorrower - function _exchange(TakeOrdersConfig memory takeOrders, bytes memory exchangeData) internal virtual override { + function _exchange(TakeOrdersConfigV2 memory takeOrders, bytes memory exchangeData) internal virtual override { (address spender, address pool, bytes memory encodedFunctionCall) = abi.decode(exchangeData, (address, address, bytes)); diff --git a/src/concrete/OrderBook.sol b/src/concrete/OrderBook.sol index 6c54f563a..a57e81a5a 100644 --- a/src/concrete/OrderBook.sol +++ b/src/concrete/OrderBook.sol @@ -19,6 +19,7 @@ import { import "rain.interpreter/src/lib/bytecode/LibBytecode.sol"; import "../interface/unstable/IOrderBookV3.sol"; +import "../interface/unstable/IOrderBookV3OrderTaker.sol"; import "../lib/LibOrder.sol"; import "../abstract/OrderBookFlashLender.sol"; @@ -321,7 +322,7 @@ contract OrderBook is IOrderBookV3, ReentrancyGuard, Multicall, OrderBookFlashLe } /// @inheritdoc IOrderBookV3 - function takeOrders(TakeOrdersConfig calldata config) + function takeOrders(TakeOrdersConfigV2 calldata config) external nonReentrant returns (uint256 totalInput, uint256 totalOutput) @@ -381,13 +382,26 @@ contract OrderBook is IOrderBookV3, ReentrancyGuard, Multicall, OrderBookFlashLe revert MinimumInput(config.minimumInput, totalInput); } + // Prioritise paying down any active flash loans before sending any + // tokens to `msg.sender`. We send the tokens to `msg.sender` first + // adopting a similar pattern to Uniswap flash swaps. We call the caller + // before attempting to pull tokens from them in order to facilitate + // better integrations with external liquidity sources. This could be + // done by the caller using flash loans but this callback: + // - may be simpler for the caller to implement + // - allows the caller to call `takeOrders` _before_ placing external + // trades, which is important if the order logic itself is dependent on + // external data (e.g. prices) that could be modified by the caller's + // trades. + uint256 inputAmountSent = _decreaseFlashDebtThenSendToken(config.input, msg.sender, totalInput); + if (inputAmountSent > 0 && config.data.length > 0) { + IOrderBookV3OrderTaker(msg.sender).onTakeOrders(config.input, config.output, inputAmountSent, totalOutput, config.data); + } + // We already updated vault balances before we took tokens from // `msg.sender` which is usually NOT the correct order of operations for // depositing to a vault. We rely on reentrancy guards to make this safe. IERC20(config.output).safeTransferFrom(msg.sender, address(this), totalOutput); - // Prioritise paying down any active flash loans before sending any - // tokens to `msg.sender`. - _decreaseFlashDebtThenSendToken(config.input, msg.sender, totalInput); } /// @inheritdoc IOrderBookV3 diff --git a/src/interface/unstable/IOrderBookV3.sol b/src/interface/unstable/IOrderBookV3.sol index a15c4d4db..a3fd628ac 100644 --- a/src/interface/unstable/IOrderBookV3.sol +++ b/src/interface/unstable/IOrderBookV3.sol @@ -78,13 +78,18 @@ struct Order { /// hit. Takers are expected to prioritise orders that appear to be offering /// better deals i.e. lower IO ratios. This prioritisation and sorting MUST /// happen offchain, e.g. via. some simulator. -struct TakeOrdersConfig { +/// @param data If nonzero length, triggers `onTakeOrders` on the caller of +/// `takeOrders` with this data. This allows the caller to perform arbitrary +/// onchain actions between receiving their input tokens, before having to send +/// their output tokens. +struct TakeOrdersConfigV2 { address output; address input; uint256 minimumInput; uint256 maximumInput; uint256 maximumIORatio; TakeOrderConfig[] orders; + bytes data; } /// Config for an individual take order from the overall list of orders in a @@ -536,7 +541,7 @@ interface IOrderBookV3 is IERC3156FlashLender, IInterpreterCallerV2 { /// vaults processed. /// @return totalOutput Total tokens taken from `msg.sender` and distributed /// between vaults. - function takeOrders(TakeOrdersConfig calldata config) external returns (uint256 totalInput, uint256 totalOutput); + function takeOrders(TakeOrdersConfigV2 calldata config) external returns (uint256 totalInput, uint256 totalOutput); /// Allows `msg.sender` to match two live orders placed earlier by /// non-interactive parties and claim a bounty in the process. The clearer is diff --git a/src/interface/unstable/IOrderBookV3OrderTaker.sol b/src/interface/unstable/IOrderBookV3OrderTaker.sol new file mode 100644 index 000000000..1637f2d96 --- /dev/null +++ b/src/interface/unstable/IOrderBookV3OrderTaker.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: CAL +pragma solidity ^0.8.18; + +interface IOrderBookV3OrderTaker { + /// @notice Called by `OrderBookV3` when `takeOrders` is called with non-zero + /// data, if it caused a non-zero input amount. I.e. if the order(s) taker + /// received some tokens. Input and output directions are relative to the + /// `IOrderBookV3OrderTaker` contract. If the order(s) taker had an active + /// debt from a flash loan then that debt will be paid _before_ calculating + /// any input amounts sent. + /// i.e. the debt is deducted from the input amount before this callback is + /// called. + /// @param inputToken The token that was sent to `IOrderBookV3OrderTaker`. + /// @param outputToken The token that `IOrderBookV3` will attempt to pull + /// from `IOrderBookV3OrderTaker` after this callback returns. + /// @param inputAmountSent The amount of `inputToken` that was sent to + /// `IOrderBookV3OrderTaker`. + /// @param totalOutputAmount The total amount of `outputToken` that + /// `IOrderBookV3` will attempt to pull from `IOrderBookV3OrderTaker` after + /// this callback returns. + /// @param takeOrdersData The data passed to `takeOrders` by the caller. + function onTakeOrders(address inputToken, address outputToken, uint256 inputAmountSent, uint256 totalOutputAmount, bytes calldata takeOrdersData) external; +} \ No newline at end of file diff --git a/test/concrete/GenericPoolOrderBookFlashBorrower.sender.t.sol b/test/concrete/GenericPoolOrderBookFlashBorrower.sender.t.sol index 58d3ddd6c..db150f308 100644 --- a/test/concrete/GenericPoolOrderBookFlashBorrower.sender.t.sol +++ b/test/concrete/GenericPoolOrderBookFlashBorrower.sender.t.sol @@ -28,7 +28,7 @@ contract MockOrderBook is IOrderBookV3 { return true; } - function takeOrders(TakeOrdersConfig calldata) external pure returns (uint256 totalInput, uint256 totalOutput) { + function takeOrders(TakeOrdersConfigV2 calldata) external pure returns (uint256 totalInput, uint256 totalOutput) { return (0, 0); } @@ -102,8 +102,8 @@ contract GenericPoolOrderBookFlashBorrowerTest is Test { ); arb_.arb( - TakeOrdersConfig( - address(output_), address(input_), 0, type(uint256).max, type(uint256).max, new TakeOrderConfig[](0) + TakeOrdersConfigV2( + address(output_), address(input_), 0, type(uint256).max, type(uint256).max, new TakeOrderConfig[](0), "" ), 0, abi.encode(address(proxy_), address(proxy_), "") @@ -131,8 +131,8 @@ contract GenericPoolOrderBookFlashBorrowerTest is Test { vm.expectRevert(abi.encodeWithSelector(MinimumOutput.selector, minimumOutput, mintAmount)); arb.arb( - TakeOrdersConfig( - address(output), address(input), 0, type(uint256).max, type(uint256).max, new TakeOrderConfig[](0) + TakeOrdersConfigV2( + address(output), address(input), 0, type(uint256).max, type(uint256).max, new TakeOrderConfig[](0), "" ), minimumOutput, abi.encode(address(proxy), address(proxy), "") diff --git a/test/util/abstract/IOrderBookV3Stub.sol b/test/util/abstract/IOrderBookV3Stub.sol index 566e8c0de..1fcf4e7ec 100644 --- a/test/util/abstract/IOrderBookV3Stub.sol +++ b/test/util/abstract/IOrderBookV3Stub.sol @@ -48,7 +48,7 @@ abstract contract IOrderBookV3Stub is IOrderBookV3 { } /// @inheritdoc IOrderBookV3 - function takeOrders(TakeOrdersConfig calldata) external pure returns (uint256, uint256) { + function takeOrders(TakeOrdersConfigV2 calldata) external pure returns (uint256, uint256) { revert("takeOrders"); } From a10b4b917e98579258be66fa0c9b67e02d365a23 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Fri, 25 Aug 2023 19:16:09 +0400 Subject: [PATCH 2/6] wip on order taker --- src/abstract/OrderBookArbCommon.sol | 13 ++ src/abstract/OrderBookFlashBorrower.sol | 19 +- src/abstract/OrderBookFlashLender.sol | 5 +- src/abstract/OrderBookFlashOrderTaker.sol | 176 ++++++++++++++++++ src/concrete/OrderBook.sol | 4 +- src/interface/unstable/IOrderBookV3.sol | 4 +- .../unstable/IOrderBookV3OrderTaker.sol | 10 +- 7 files changed, 212 insertions(+), 19 deletions(-) create mode 100644 src/abstract/OrderBookArbCommon.sol create mode 100644 src/abstract/OrderBookFlashOrderTaker.sol diff --git a/src/abstract/OrderBookArbCommon.sol b/src/abstract/OrderBookArbCommon.sol new file mode 100644 index 000000000..6a55b1eab --- /dev/null +++ b/src/abstract/OrderBookArbCommon.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: CAL +pragma solidity ^0.8.18; + +/// Thrown when the minimum output for the sender is not met after the arb. +/// @param minimum The minimum output expected by the sender. +/// @param actual The actual output that would be received by the sender. +error MinimumOutput(uint256 minimum, uint256 actual); + +/// Thrown when calling functions while the contract is still initializing. +error Initializing(); + +/// Thrown when the stack is not empty after the access control dispatch. +error NonZeroBeforeArbStack(); \ No newline at end of file diff --git a/src/abstract/OrderBookFlashBorrower.sol b/src/abstract/OrderBookFlashBorrower.sol index 1d88c81ca..ca53ca20b 100644 --- a/src/abstract/OrderBookFlashBorrower.sol +++ b/src/abstract/OrderBookFlashBorrower.sol @@ -18,6 +18,7 @@ import "rain.interpreter/src/lib/bytecode/LibBytecode.sol"; import "../interface/unstable/IOrderBookV3.sol"; import "rain.factory/src/interface/ICloneableV2.sol"; +import "./OrderBookArbCommon.sol"; /// Thrown when the lender is not the trusted `OrderBook`. /// @param badLender The untrusted lender calling `onFlashLoan`. @@ -30,22 +31,11 @@ error BadInitiator(address badInitiator); /// Thrown when the flash loan fails somehow. error FlashLoanFailed(); -/// Thrown when calling functions while the contract is still initializing. -error Initializing(); - /// Thrown when the swap fails. error SwapFailed(); -/// Thrown when the minimum output for the sender is not met after the arb. -/// @param minimum The minimum output expected by the sender. -/// @param actual The actual output that would be received by the sender. -error MinimumOutput(uint256 minimum, uint256 actual); - -/// Thrown when the stack is not empty after the access control dispatch. -error NonZeroBeforeArbStack(); - /// Config for `OrderBookFlashBorrower` to initialize. -/// @param orderBook The `OrderBook` contract to arb against. +/// @param orderBook The `IOrderBookV3` contract to arb against. /// @param evaluableConfig The config to eval for access control to arb. /// @param implementationData Arbitrary bytes to pass to the implementation in /// the `beforeInitialize` hook. @@ -141,7 +131,7 @@ abstract contract OrderBookFlashBorrower is /// Type hints for the input encoding for the `initialize` function. /// Reverts ALWAYS with `InitializeSignatureFn` as per ICloneableV2. - function initialize(OrderBookFlashBorrowerConfigV2 memory) external pure returns (bytes32) { + function initialize(OrderBookFlashBorrowerConfigV2 calldata) external pure returns (bytes32) { revert InitializeSignatureFn(); } @@ -214,7 +204,8 @@ abstract contract OrderBookFlashBorrower is revert BadInitiator(initiator); } - (TakeOrdersConfigV2 memory takeOrders, bytes memory exchangeData) = abi.decode(data, (TakeOrdersConfigV2, bytes)); + (TakeOrdersConfigV2 memory takeOrders, bytes memory exchangeData) = + abi.decode(data, (TakeOrdersConfigV2, bytes)); // Dispatch the `_exchange` hook to ensure we have the correct asset // type and amount to fill the orders. diff --git a/src/abstract/OrderBookFlashLender.sol b/src/abstract/OrderBookFlashLender.sol index 9c4ff2aab..70e2acd1a 100644 --- a/src/abstract/OrderBookFlashLender.sol +++ b/src/abstract/OrderBookFlashLender.sol @@ -98,7 +98,10 @@ abstract contract OrderBookFlashLender is IERC3156FlashLender { /// @param receiver The receiver of the token or holder of the debt. /// @param sendAmount The amount to send or repay. /// @return The final amount sent after any debt repayment. - function _decreaseFlashDebtThenSendToken(address token, address receiver, uint256 sendAmount) internal returns (uint256) { + function _decreaseFlashDebtThenSendToken(address token, address receiver, uint256 sendAmount) + internal + returns (uint256) + { // If this token transfer matches the active debt then prioritise // reducing debt over sending tokens. if (token == _sToken && receiver == address(_sReceiver)) { diff --git a/src/abstract/OrderBookFlashOrderTaker.sol b/src/abstract/OrderBookFlashOrderTaker.sol new file mode 100644 index 000000000..c1eb98aee --- /dev/null +++ b/src/abstract/OrderBookFlashOrderTaker.sol @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: CAL +pragma solidity =0.8.19; + +import {ERC165, IERC165} from "openzeppelin-contracts/contracts/utils/introspection/ERC165.sol"; +import {ReentrancyGuard} from "openzeppelin-contracts/contracts/security/ReentrancyGuard.sol"; +import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; +import {Initializable} from "openzeppelin-contracts/contracts/proxy/utils/Initializable.sol"; +import {SafeERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; +import {Address} from "openzeppelin-contracts/contracts/utils/Address.sol"; +import { + DeployerDiscoverableMetaV2, + DeployerDiscoverableMetaV2ConstructionConfig, + LibMeta +} from "rain.interpreter/src/abstract/DeployerDiscoverableMetaV2.sol"; +import "rain.factory/src/interface/ICloneableV2.sol"; +import "rain.interpreter/src/lib/caller/LibContext.sol"; +import "rain.interpreter/src/lib/caller/LibEncodedDispatch.sol"; +import "rain.interpreter/src/lib/bytecode/LibBytecode.sol"; + +import "../interface/unstable/IOrderBookV3.sol"; +import "../interface/unstable/IOrderBookV3OrderTaker.sol"; + +import "./OrderBookArbCommon.sol"; + +/// Config for `OrderBookFlashOrderTakerConfigV1` to initialize. +/// @param orderBook The `IOrderBookV3` to use for `takeOrders`. +/// @param evaluableConfig The config to eval for access control to arb. +/// @param implementationData Arbitrary bytes to pass to the implementation in +/// the `beforeInitialize` hook. +struct OrderBookFlashOrderTakerConfigV1 { + address orderBook; + EvaluableConfigV2 evaluableConfig; + bytes implementationData; +} + +/// @dev "Before arb" is evaluabled before the arb is executed. Ostensibly this +/// is to allow for access control to the arb, the return values are ignored. +SourceIndex constant BEFORE_ARB_SOURCE_INDEX = SourceIndex.wrap(0); +/// @dev "Before arb" has no return values. +uint256 constant BEFORE_ARB_MIN_OUTPUTS = 0; +/// @dev "Before arb" has no return values. +uint16 constant BEFORE_ARB_MAX_OUTPUTS = 0; + +abstract contract OrderBookFlashOrderTaker is IOrderBookV3OrderTaker, ReentrancyGuard, Initializable, ICloneableV2, DeployerDiscoverableMetaV2, ERC165 { + using SafeERC20 for IERC20; + + event Initialize(address sender, OrderBookFlashOrderTakerConfigV1 config); + + IOrderBookV3 public sOrderBook; + EncodedDispatch public sI9rDispatch; + IInterpreterV1 public sI9r; + IInterpreterStoreV1 public sI9rStore; + + constructor(bytes32 metaHash, DeployerDiscoverableMetaV2ConstructionConfig memory config) + DeployerDiscoverableMetaV2(metaHash, config) + { + _disableInitializers(); + } + + /// @inheritdoc IERC165 + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IOrderBookV3OrderTaker).interfaceId || interfaceId == type(ICloneableV2).interfaceId || super.supportsInterface(interfaceId); + } + + function _beforeInitialize(bytes memory data) internal virtual {} + + /// Ensure the contract is not initializing. + modifier onlyNotInitializing() { + if (_isInitializing()) { + revert Initializing(); + } + _; + } + + function initialize(OrderBookFlashOrderTakerConfigV1 calldata) external pure returns (bytes32) { + revert InitializeSignatureFn(); + } + + /// @inheritdoc ICloneableV2 + function initialize(bytes memory data) external initializer nonReentrant returns (bytes32) { + OrderBookFlashOrderTakerConfigV1 memory config = abi.decode(data, (OrderBookFlashOrderTakerConfigV1)); + + // Dispatch the hook before any external calls are made. + _beforeInitialize(config.implementationData); + + // @todo this could be paramaterised on `arb`. + sOrderBook = IOrderBookV3(config.orderBook); + + // Emit events before any external calls are made. + emit Initialize(msg.sender, config); + + // If there are any sources to eval then initialize the dispatch, + // otherwise it will remain 0 and we can skip evaluation on `arb`. + if (LibBytecode.sourceCount(config.evaluableConfig.bytecode) > 0) { + address expression; + + uint256[] memory entrypoints = new uint256[](1); + entrypoints[SourceIndex.unwrap(BEFORE_ARB_SOURCE_INDEX)] = BEFORE_ARB_MIN_OUTPUTS; + + // We have to trust the deployer because it produces the expression + // address for dispatch anyway. + // All external functions on this contract have `onlyNotInitializing` + // modifier on them so can't be reentered here anyway. + //slither-disable-next-line reentrancy-benign + (sI9r, sI9rStore, expression) = config.evaluableConfig.deployer.deployExpression( + config.evaluableConfig.bytecode, config.evaluableConfig.constants, entrypoints + ); + sI9rDispatch = LibEncodedDispatch.encode(expression, BEFORE_ARB_SOURCE_INDEX, BEFORE_ARB_MAX_OUTPUTS); + } + + return ICLONEABLE_V2_SUCCESS; + } + + function arb(TakeOrdersConfigV2 calldata takeOrders, uint256 minimumSenderOutput) + external + nonReentrant + onlyNotInitializing + { + // Run the access control dispatch if it is set. + EncodedDispatch dispatch = sI9rDispatch; + if (EncodedDispatch.unwrap(dispatch) > 0) { + (uint256[] memory stack, uint256[] memory kvs) = sI9r.eval( + sI9rStore, + DEFAULT_STATE_NAMESPACE, + dispatch, + LibContext.build(new uint256[][](0), new SignedContextV1[](0)) + ); + // This can only happen if interpreter is broken. + if (stack.length > 0) { + revert NonZeroBeforeArbStack(); + } + // Persist any state changes from the expression. + if (kvs.length > 0) { + sI9rStore.set(DEFAULT_STATE_NAMESPACE, kvs); + } + } + + IERC20(takeOrders.output).safeApprove(address(sOrderBook), 0); + IERC20(takeOrders.output).safeApprove(address(sOrderBook), type(uint256).max); + (uint256 totalInput, uint256 totalOutput) = sOrderBook.takeOrders(takeOrders); + (totalInput, totalOutput); + IERC20(takeOrders.output).safeApprove(address(sOrderBook), 0); + + // Send all unspent input tokens to the sender. + uint256 inputBalance = IERC20(takeOrders.input).balanceOf(address(this)); + if (inputBalance > 0) { + IERC20(takeOrders.input).safeTransfer(msg.sender, inputBalance); + } + // Send all unspent output tokens to the sender. + uint256 outputBalance = IERC20(takeOrders.output).balanceOf(address(this)); + if (outputBalance < minimumSenderOutput) { + revert MinimumOutput(minimumSenderOutput, outputBalance); + } + if (outputBalance > 0) { + IERC20(takeOrders.output).safeTransfer(msg.sender, outputBalance); + } + + // Send any remaining gas to the sender. + // Slither false positive here. We want to send everything to the sender + // because this contract should be empty of all gas and tokens between + // uses. Anyone who sends tokens or gas to an arb contract without + // calling `arb` is going to lose their tokens/gas. + // See https://github.com/crytic/slither/issues/1658 + Address.sendValue(payable(msg.sender), address(this).balance); + } + + /// @inheritdoc IOrderBookV3OrderTaker + function onTakeOrders( + address inputToken, + address outputToken, + uint256 inputAmountSent, + uint256 totalOutputAmount, + bytes calldata takeOrdersData + ) external override virtual onlyNotInitializing { + } +} diff --git a/src/concrete/OrderBook.sol b/src/concrete/OrderBook.sol index a57e81a5a..1999838e3 100644 --- a/src/concrete/OrderBook.sol +++ b/src/concrete/OrderBook.sol @@ -395,7 +395,9 @@ contract OrderBook is IOrderBookV3, ReentrancyGuard, Multicall, OrderBookFlashLe // trades. uint256 inputAmountSent = _decreaseFlashDebtThenSendToken(config.input, msg.sender, totalInput); if (inputAmountSent > 0 && config.data.length > 0) { - IOrderBookV3OrderTaker(msg.sender).onTakeOrders(config.input, config.output, inputAmountSent, totalOutput, config.data); + IOrderBookV3OrderTaker(msg.sender).onTakeOrders( + config.input, config.output, inputAmountSent, totalOutput, config.data + ); } // We already updated vault balances before we took tokens from diff --git a/src/interface/unstable/IOrderBookV3.sol b/src/interface/unstable/IOrderBookV3.sol index a3fd628ac..ac82b6d89 100644 --- a/src/interface/unstable/IOrderBookV3.sol +++ b/src/interface/unstable/IOrderBookV3.sol @@ -541,7 +541,9 @@ interface IOrderBookV3 is IERC3156FlashLender, IInterpreterCallerV2 { /// vaults processed. /// @return totalOutput Total tokens taken from `msg.sender` and distributed /// between vaults. - function takeOrders(TakeOrdersConfigV2 calldata config) external returns (uint256 totalInput, uint256 totalOutput); + function takeOrders(TakeOrdersConfigV2 calldata config) + external + returns (uint256 totalInput, uint256 totalOutput); /// Allows `msg.sender` to match two live orders placed earlier by /// non-interactive parties and claim a bounty in the process. The clearer is diff --git a/src/interface/unstable/IOrderBookV3OrderTaker.sol b/src/interface/unstable/IOrderBookV3OrderTaker.sol index 1637f2d96..6244bcf7f 100644 --- a/src/interface/unstable/IOrderBookV3OrderTaker.sol +++ b/src/interface/unstable/IOrderBookV3OrderTaker.sol @@ -19,5 +19,11 @@ interface IOrderBookV3OrderTaker { /// `IOrderBookV3` will attempt to pull from `IOrderBookV3OrderTaker` after /// this callback returns. /// @param takeOrdersData The data passed to `takeOrders` by the caller. - function onTakeOrders(address inputToken, address outputToken, uint256 inputAmountSent, uint256 totalOutputAmount, bytes calldata takeOrdersData) external; -} \ No newline at end of file + function onTakeOrders( + address inputToken, + address outputToken, + uint256 inputAmountSent, + uint256 totalOutputAmount, + bytes calldata takeOrdersData + ) external; +} From 2b41147481145c1a9d5e7a26f50fb4571034ef26 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Fri, 25 Aug 2023 19:42:31 +0400 Subject: [PATCH 3/6] order book order taker --- ...enericPoolOrderBookFlashBorrower.rain.meta | Bin 1387 -> 1394 bytes meta/OrderBook.rain.meta | Bin 5755 -> 5756 bytes ...eployGenericPoolOrderBookFlashBorrower.sol | 2 +- script/DeployOrderBook.sol | 2 +- src/abstract/OrderBookArbCommon.sol | 6 ++- ...erTaker.sol => OrderBookArbOrderTaker.sol} | 28 ++++++++---- src/abstract/OrderBookFlashBorrower.sol | 4 -- .../GenericPoolOrderBookArbOrderTaker.sol | 42 ++++++++++++++++++ .../GenericPoolOrderBookFlashBorrower.sol | 2 +- src/concrete/OrderBook.sol | 2 +- ...ricPoolOrderBookFlashBorrower.sender.t.sol | 1 + test/concrete/OrderBook.withdraw.t.sol | 2 + .../abstract/OrderBookExternalMockTest.sol | 2 +- 13 files changed, 74 insertions(+), 19 deletions(-) rename src/abstract/{OrderBookFlashOrderTaker.sol => OrderBookArbOrderTaker.sol} (92%) create mode 100644 src/concrete/GenericPoolOrderBookArbOrderTaker.sol diff --git a/meta/GenericPoolOrderBookFlashBorrower.rain.meta b/meta/GenericPoolOrderBookFlashBorrower.rain.meta index ee4ceacd8d07a294caa5993ac51c8cb21f3ceab0..aa664e479efc3455695db38b1b573b18a8c56a12 100644 GIT binary patch delta 1063 zcmV+?1larQ3i1kn{|br5bnbX`r2tt32<=!)Z`3dl{wrwDd!am3xKY}QNR*XW=mE3` zZ#->H6Fah?s1t+n2K_Q960VKZB%`NxKj`a3_puv)jL6cf8U%cNe+fqu) zG}O;d3rnX=g<=PiY$Lcp4VOpn1<&^|!SVkUyRL17<#S<0r%42v6{U%Wi&T>>iEKXE;YRolTLIch;BSyCCo=vs!#JLfqoMrPPa0;Ua+q)dr>iy>t zQ8yn2;pc>ZML;J?q2(33W=MLAV#W{#B|G(nMc=68sxTaROID!aKQLYZBi2owJp=Dep_& z%B22G7|+u4`3zGpj%s7DPaxDlKVS^DOyagama#Q|e8Etg+xs!Lfp>LhAgKgy6IVPwoi-GlWGKp%$>Dx28hlx*JS$I3a=niIqjZ4H^XDAkubTGeDAr#rHl)k&g# zwK8aG@F|!v**}to)n}8$ZXGRe`a1WHPvuL0A);FDhHx4|u(HC(tov|zU>1dLCulW;i|uCZ4ITdOiJ=EV?HHOJkxj!?UU(p_Zkd2d?W0-qe%$99bjS&Zb+Va5sJ zxFcz#1L|%8-EIh0cA3nY*&t_vrVmV+{HMH-_sA|cYzC`vtEHOI7j#Dsa{<9BFtuWT z9xvsTJgCC+CKXON6BFLuereciXY)1MD5>snH8$*+i14NCw3 delta 1056 zcmV+*1mFAe3hN4g{|br5bnbX`r2tt30qs~zZ`&{o{wqVyxwPGeuDA7t8E6-v>3Ud^ zgJQF-R$DS8IZZb7zmM`$w&jQ176Z0jg4hztPZar)^zE-1WpSe9>C3mOoOa zKrj+s?_!u8%}5Xkka9MkF%sz)0mLESfxtJazU6t|l3wqB6d1A*C{oE~i_fchQ%Wk4 z`0CwhZt0XtpKm~rbqJTJ;b#AYvuqFL4FBKJ`^tu2Jm*$a5{Hmlk%}m|OcYtukg6T7 zG0tML(|W7@exaL-{6wXvhFr5Ifybz#M9a3_vnn?pTQ`CblWbl93t-S-bC<`Wp32}^pay~3fe3g)}7w%=Ie~~DJG}4z}Ir|QRAHy9N@L8;viujLi=WHZy!n#to zG^wr#WodfuO)zz^Um1gK48DTk3&vo>ByQ_s8B;@l=GPAS3iLNtn9{iG+biS*Sz;IQ z1i{~tP{O=^mH@VxAk|WTy2`FxojVgT7pUo&^T#RLkmZy>H@)-Dwy~B$CN22(X8(2A zUO)OgfL7RaX2$KR#^XrX8h$f9a94NHIK%8tG^1yA!8{Apms%xa@IW-eeG$5p=)!YK zx{6tUZ%E`g7sc(RRC~-Z+@3(RL3fw47U>$nyFrjI4qolzm(>o~MS30@nE zQzDHxSB-{cvi^ZI(8b}s%0_lL1)Dedv2@P3<^(Z>Yfa`2N_C}6UD2b(CmV zt@P>|Tnc7Hwy&gNaix>kuA|{iSLZ&lv3$vYd05Fk5Eg{sEsXHd>n>dG=>?>7{7s{* zyt4B3C|p*BOYBv_)GGChX)y$4&9Qf_1JrJzbQ_sF-kai&z(xo5p;;q+8X-Bfm~lin zZb%X;FR-_Ob~ktnvrMMVtd}uC-3Pi%{!?DadSsg$R=riY(Nc}*3)&-xz5s9G=~^*= zjh8Y??p5JfH1)0=h*l~S2(esNIc%9PN_i{divXPRSPPXskw4qG1!$USs*rNv|<*0{>^Oi72v zk)21v($6h!b7RnthMK)=1!{P}vyXLuFFVQq@#`-czg{wK^$c2X9;|VVFh?ewr9bcf z0y&~Jo7UM+t9es+Zh%oZD?eTSaZ0IBN$->Bhcnp2+Z*LJybXmXH(>aAJtoS3=m&Vl zG?xU%=I%>;C1A^Zz;Jb2Yf^b5-z|&^FbZQSaC7iB;OtTUzA*{j5g*KEJKtm$WRXnb amP4fI7}!i=C#-rT0@#G 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 Date: Mon, 28 Aug 2023 08:19:19 +0400 Subject: [PATCH 4/6] snapshot --- .gas-snapshot | 70 +++++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 310b99be7..8ed4c2ce5 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,43 +1,43 @@ -GenericPoolOrderBookFlashBorrowerTest:testMinimumOutput(uint256,uint256) (runs: 5096, μ: 2328298, ~: 2331602) -GenericPoolOrderBookFlashBorrowerTest:testTakeOrdersSender() (gas: 2243437) +GenericPoolOrderBookFlashBorrowerTest:testMinimumOutput(uint256,uint256) (runs: 5096, μ: 2326245, ~: 2329549) +GenericPoolOrderBookFlashBorrowerTest:testTakeOrdersSender() (gas: 2241372) LibOrderTest:testHashEqual((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[])) (runs: 5096, μ: 194389, ~: 191140) LibOrderTest:testHashNotEqual((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),(address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[])) (runs: 5096, μ: 298734, ~: 298554) -OrderBookAddOrderMockTest:testAddOrderSameAccountWithDifferentConfig(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address,address) (runs: 5096, μ: 2771896, ~: 2761563) -OrderBookAddOrderMockTest:testAddOrderTwoAccountsWithDifferentConfig(address,address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address,address) (runs: 5096, μ: 2626805, ~: 2600971) -OrderBookAddOrderMockTest:testAddOrderTwoAccountsWithSameConfig(address,address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 2493363, ~: 2492354) -OrderBookAddOrderMockTest:testAddOrderWithCalculationsInputsAndOutputsSucceeds(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 1295837, ~: 1282002) -OrderBookAddOrderMockTest:testAddOrderWithNonEmptyMetaEmitsMetaV1(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 1303948, ~: 1290925) -OrderBookAddOrderMockTest:testAddOrderWithNonEmptyMetaReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 703712, ~: 697944) -OrderBookAddOrderMockTest:testAddOrderWithoutCalculationsReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes)) (runs: 5096, μ: 226617, ~: 224824) -OrderBookAddOrderMockTest:testAddOrderWithoutInputsReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes)) (runs: 5096, μ: 182440, ~: 181924) -OrderBookAddOrderMockTest:testAddOrderWithoutOutputsReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes)) (runs: 5096, μ: 182862, ~: 182048) -OrderBookAddOrderTest:testAddOrderRealNoHandleIOReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes)) (runs: 5096, μ: 172809, ~: 171585) -OrderBookAddOrderTest:testAddOrderRealNoSourcesReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes)) (runs: 5096, μ: 176067, ~: 174435) -OrderBookAddOrderTest:testAddOrderRealOneStackCalculateReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes)) (runs: 5096, μ: 186152, ~: 184929) -OrderBookAddOrderTest:testAddOrderRealThreeStackCalculate(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes)) (runs: 5096, μ: 722175, ~: 718820) -OrderBookAddOrderTest:testAddOrderRealTwoStackCalculateReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes)) (runs: 5096, μ: 715348, ~: 711993) -OrderBookAddOrderTest:testAddOrderRealZeroStackCalculateReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes)) (runs: 5096, μ: 181324, ~: 180101) -OrderBookDepositTest:testDepositEvent(address,uint256,uint256) (runs: 5096, μ: 38710, ~: 38710) -OrderBookDepositTest:testDepositFail(address,uint256,uint256) (runs: 5096, μ: 8937393460516740786, ~: 8937393460516740786) +OrderBookAddOrderMockTest:testAddOrderSameAccountWithDifferentConfig(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address,address) (runs: 5096, μ: 2771808, ~: 2761475) +OrderBookAddOrderMockTest:testAddOrderTwoAccountsWithDifferentConfig(address,address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address,address) (runs: 5096, μ: 2626897, ~: 2601235) +OrderBookAddOrderMockTest:testAddOrderTwoAccountsWithSameConfig(address,address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 2493275, ~: 2492266) +OrderBookAddOrderMockTest:testAddOrderWithCalculationsInputsAndOutputsSucceeds(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 1295793, ~: 1281958) +OrderBookAddOrderMockTest:testAddOrderWithNonEmptyMetaEmitsMetaV1(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 1303882, ~: 1290859) +OrderBookAddOrderMockTest:testAddOrderWithNonEmptyMetaReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 703690, ~: 697922) +OrderBookAddOrderMockTest:testAddOrderWithoutCalculationsReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes)) (runs: 5096, μ: 226595, ~: 224802) +OrderBookAddOrderMockTest:testAddOrderWithoutInputsReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes)) (runs: 5096, μ: 182418, ~: 181902) +OrderBookAddOrderMockTest:testAddOrderWithoutOutputsReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes)) (runs: 5096, μ: 182840, ~: 182026) +OrderBookAddOrderTest:testAddOrderRealNoHandleIOReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes)) (runs: 5096, μ: 172765, ~: 171541) +OrderBookAddOrderTest:testAddOrderRealNoSourcesReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes)) (runs: 5096, μ: 176045, ~: 174413) +OrderBookAddOrderTest:testAddOrderRealOneStackCalculateReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes)) (runs: 5096, μ: 186108, ~: 184885) +OrderBookAddOrderTest:testAddOrderRealThreeStackCalculate(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes)) (runs: 5096, μ: 722153, ~: 718798) +OrderBookAddOrderTest:testAddOrderRealTwoStackCalculateReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes)) (runs: 5096, μ: 715304, ~: 711949) +OrderBookAddOrderTest:testAddOrderRealZeroStackCalculateReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes)) (runs: 5096, μ: 181302, ~: 180079) +OrderBookDepositTest:testDepositEvent(address,uint256,uint256) (runs: 5096, μ: 38755, ~: 38755) +OrderBookDepositTest:testDepositFail(address,uint256,uint256) (runs: 5096, μ: 8937393460516740787, ~: 8937393460516740786) OrderBookDepositTest:testDepositGas00() (gas: 8176) OrderBookDepositTest:testDepositGas01() (gas: 34620) -OrderBookDepositTest:testDepositMany((address,address,uint256,uint248)[]) (runs: 5096, μ: 5183067, ~: 4940788) +OrderBookDepositTest:testDepositMany((address,address,uint256,uint248)[]) (runs: 5096, μ: 5173597, ~: 4894479) OrderBookDepositTest:testDepositOverflow(address,uint256,uint256,uint256) (runs: 5096, μ: 46645, ~: 46645) -OrderBookDepositTest:testDepositReentrancy(address,uint256,uint256,address,uint256,uint256) (runs: 5096, μ: 495280, ~: 496632) +OrderBookDepositTest:testDepositReentrancy(address,uint256,uint256,address,uint256,uint256) (runs: 5096, μ: 495128, ~: 496632) OrderBookDepositTest:testDepositSimple(address,uint256,uint256) (runs: 5096, μ: 37840, ~: 37840) OrderBookDepositTest:testDepositZero(address,uint256) (runs: 5096, μ: 12639, ~: 12639) OrderBookDepositTest:testVaultBalanceNoDeposits(address,uint256) (runs: 5096, μ: 8263, ~: 8263) -OrderBookDepositTest:testVaultBalanceReentrant(address,uint256,uint256,address,address,uint256) (runs: 5096, μ: 494116, ~: 495964) -OrderBookRemoveOrderMockTest:testRemoveOrderAddRemoveMulti(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 7256754, ~: 7139557) -OrderBookRemoveOrderMockTest:testRemoveOrderDifferent(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 5070453, ~: 5046460) -OrderBookRemoveOrderMockTest:testRemoveOrderDifferentOwners(address,address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 4854311, ~: 4841989) -OrderBookRemoveOrderMockTest:testRemoveOrderDifferentOwnersDifferent(address,address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 10467161, ~: 10453667) -OrderBookRemoveOrderMockTest:testRemoveOrderDoesNotExist(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 386746, ~: 381998) -OrderBookRemoveOrderMockTest:testRemoveOrderOnlyOwner(address,address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 2603146, ~: 2601124) -OrderBookWithdrawTest:testWithdrawEmptyVault(address,address,uint256,uint256) (runs: 5096, μ: 15251, ~: 15251) -OrderBookWithdrawTest:testWithdrawFailure(address,uint256,uint256,uint256) (runs: 5096, μ: 8937393460516719460, ~: 8937393460516700411) -OrderBookWithdrawTest:testWithdrawFullVault(address,uint256,uint256,uint256) (runs: 5096, μ: 41244, ~: 41242) -OrderBookWithdrawTest:testWithdrawMany((bool,address,address,uint256,uint248)[]) (runs: 5096, μ: 1389147, ~: 1313082) -OrderBookWithdrawTest:testWithdrawPartialVault(address,uint256,uint256,uint256) (runs: 5096, μ: 51914, ~: 51914) -OrderBookWithdrawTest:testWithdrawReentrant(address,uint256,uint256,address,address,uint256) (runs: 5096, μ: 506284, ~: 507991) -OrderBookWithdrawTest:testWithdrawZero(address,address,uint256) (runs: 5096, μ: 12809, ~: 12809) \ No newline at end of file +OrderBookDepositTest:testVaultBalanceReentrant(address,uint256,uint256,address,address,uint256) (runs: 5096, μ: 494155, ~: 495964) +OrderBookRemoveOrderMockTest:testRemoveOrderAddRemoveMulti(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 7256892, ~: 7139695) +OrderBookRemoveOrderMockTest:testRemoveOrderDifferent(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 5070545, ~: 5046552) +OrderBookRemoveOrderMockTest:testRemoveOrderDifferentOwners(address,address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 4855105, ~: 4842171) +OrderBookRemoveOrderMockTest:testRemoveOrderDifferentOwnersDifferent(address,address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 10467503, ~: 10454009) +OrderBookRemoveOrderMockTest:testRemoveOrderDoesNotExist(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 386856, ~: 382108) +OrderBookRemoveOrderMockTest:testRemoveOrderOnlyOwner(address,address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 2603652, ~: 2601305) +OrderBookWithdrawTest:testWithdrawEmptyVault(address,address,uint256,uint256) (runs: 5096, μ: 15316, ~: 15316) +OrderBookWithdrawTest:testWithdrawFailure(address,uint256,uint256,uint256) (runs: 5096, μ: 8937393460516719594, ~: 8937393460516700429) +OrderBookWithdrawTest:testWithdrawFullVault(address,uint256,uint256,uint256) (runs: 5096, μ: 41258, ~: 41256) +OrderBookWithdrawTest:testWithdrawMany((bool,address,address,uint256,uint248)[]) (runs: 5096, μ: 1448793, ~: 1371051) +OrderBookWithdrawTest:testWithdrawPartialVault(address,uint256,uint256,uint256) (runs: 5096, μ: 51929, ~: 51929) +OrderBookWithdrawTest:testWithdrawReentrant(address,uint256,uint256,address,address,uint256) (runs: 5096, μ: 506286, ~: 507997) +OrderBookWithdrawTest:testWithdrawZero(address,address,uint256) (runs: 5096, μ: 12787, ~: 12787) \ No newline at end of file From 0265443117ad06d43efa5ab8d2ca1d067e536e51 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Mon, 28 Aug 2023 08:24:37 +0400 Subject: [PATCH 5/6] call onTakeOrders --- src/concrete/OrderBook.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/concrete/OrderBook.sol b/src/concrete/OrderBook.sol index 38dc70d87..9ed1206cb 100644 --- a/src/concrete/OrderBook.sol +++ b/src/concrete/OrderBook.sol @@ -394,7 +394,7 @@ contract OrderBook is IOrderBookV3, ReentrancyGuard, Multicall, OrderBookFlashLe // external data (e.g. prices) that could be modified by the caller's // trades. uint256 inputAmountSent = _decreaseFlashDebtThenSendToken(config.input, msg.sender, totalInput); - if (inputAmountSent > 0 && config.data.length > 0) { + if (config.data.length > 0) { IOrderBookV3OrderTaker(msg.sender).onTakeOrders( config.input, config.output, inputAmountSent, totalOutput, config.data ); From 2e46b651d65f86cbdb5db9f2a72e65466d42c05e Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Mon, 28 Aug 2023 08:29:26 +0400 Subject: [PATCH 6/6] remove redundant modifier --- src/concrete/GenericPoolOrderBookArbOrderTaker.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/concrete/GenericPoolOrderBookArbOrderTaker.sol b/src/concrete/GenericPoolOrderBookArbOrderTaker.sol index 4efb0ce74..57dbdb2ef 100644 --- a/src/concrete/GenericPoolOrderBookArbOrderTaker.sol +++ b/src/concrete/GenericPoolOrderBookArbOrderTaker.sol @@ -23,7 +23,7 @@ contract GenericPoolOrderBookArbOrderTaker is OrderBookArbOrderTaker { uint256 inputAmountSent, uint256 totalOutputAmount, bytes calldata takeOrdersData - ) public virtual override onlyNotInitializing { + ) public virtual override { super.onTakeOrders(inputToken, outputToken, inputAmountSent, totalOutputAmount, takeOrdersData); (address spender, address pool, bytes memory encodedFunctionCall) = abi.decode(takeOrdersData, (address, address, bytes));