From dcb180fad1fdc91cf0d7103c718bc4ab1acd088c Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Mon, 18 Sep 2023 14:43:58 +0400 Subject: [PATCH 01/13] wip on minimum input tests --- src/concrete/OrderBook.sol | 3 +++ src/interface/unstable/IOrderBookV3.sol | 3 +++ .../OrderBook.takeOrder.maximumInput.t.sol | 25 +++++++++++++++++++ test/concrete/OrderBook.takeOrder.noop.t.sol | 1 + ...ol => OrderBook.takeOrder.precision.t.sol} | 4 +-- .../OrderBook.takeOrder.tokenMismatch.t.sol | 14 ++++++++--- 6 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 test/concrete/OrderBook.takeOrder.maximumInput.t.sol rename test/concrete/{OrderBook.takeOrder.t.sol => OrderBook.takeOrder.precision.t.sol} (97%) diff --git a/src/concrete/OrderBook.sol b/src/concrete/OrderBook.sol index 0af4432bd..c5fe2ce01 100644 --- a/src/concrete/OrderBook.sol +++ b/src/concrete/OrderBook.sol @@ -349,6 +349,9 @@ contract OrderBook is IOrderBookV3, ReentrancyGuard, Multicall, OrderBookV3Flash Order memory order; uint256 remainingTakerInput = config.maximumInput; + if (remainingTakerInput == 0) { + revert ZeroMaximumInput(); + } while (i < config.orders.length && remainingTakerInput > 0) { takeOrderConfig = config.orders[i]; order = takeOrderConfig.order; diff --git a/src/interface/unstable/IOrderBookV3.sol b/src/interface/unstable/IOrderBookV3.sol index 0d147708b..e3035a3bf 100644 --- a/src/interface/unstable/IOrderBookV3.sol +++ b/src/interface/unstable/IOrderBookV3.sol @@ -11,6 +11,9 @@ import {IO, Order, TakeOrderConfig, ClearConfig, ClearStateChange} from "../IOrd /// Thrown when take orders is called with no orders. error NoOrders(); +/// Thrown when take orders is called with a zero maximum input. +error ZeroMaximumInput(); + /// Config the order owner may provide to define their order. The `msg.sender` /// that adds an order cannot modify the owner nor bypass the integrity check of /// the expression deployer that they specify. However they MAY specify a diff --git a/test/concrete/OrderBook.takeOrder.maximumInput.t.sol b/test/concrete/OrderBook.takeOrder.maximumInput.t.sol new file mode 100644 index 000000000..05fc905e6 --- /dev/null +++ b/test/concrete/OrderBook.takeOrder.maximumInput.t.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: CAL +pragma solidity =0.8.19; + +import {OrderBookExternalRealTest} from "test/util/abstract/OrderBookExternalRealTest.sol"; +import {Order, SignedContextV1, TakeOrderConfig, TakeOrdersConfigV2, ZeroMaximumInput} from "src/interface/unstable/IOrderBookV3.sol"; + +contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { + + /// If there is some live order(s) but the maxTakerInput is zero we error as + /// the caller has full control over this, and it would cause none of the + /// orders to be taken. + function testTakeOrderNoopZeroMaxTakerInput(Order memory order, SignedContextV1 memory signedContext) external { + vm.assume(order.validInputs.length > 0); + vm.assume(order.validOutputs.length > 0); + TakeOrderConfig[] memory orders = new TakeOrderConfig[](1); + SignedContextV1[] memory signedContexts = new SignedContextV1[](1); + signedContexts[0] = signedContext; + orders[0] = TakeOrderConfig(order, 0, 0, signedContexts); + TakeOrdersConfigV2 memory config = TakeOrdersConfigV2(0, 0, type(uint256).max, orders, ""); + vm.expectRevert(ZeroMaximumInput.selector); + (uint256 totalTakerInput, uint256 totalTakerOutput) = iOrderbook.takeOrders(config); + (totalTakerInput, totalTakerOutput); + } + +} \ No newline at end of file diff --git a/test/concrete/OrderBook.takeOrder.noop.t.sol b/test/concrete/OrderBook.takeOrder.noop.t.sol index 26524ead2..f6e3d8af5 100644 --- a/test/concrete/OrderBook.takeOrder.noop.t.sol +++ b/test/concrete/OrderBook.takeOrder.noop.t.sol @@ -133,4 +133,5 @@ contract OrderBookTakeOrderNoopTest is OrderBookExternalRealTest { assertEq(orderHash2, order2.hash()); } } + } diff --git a/test/concrete/OrderBook.takeOrder.t.sol b/test/concrete/OrderBook.takeOrder.precision.t.sol similarity index 97% rename from test/concrete/OrderBook.takeOrder.t.sol rename to test/concrete/OrderBook.takeOrder.precision.t.sol index 56afbfd6a..3ab3606eb 100644 --- a/test/concrete/OrderBook.takeOrder.t.sol +++ b/test/concrete/OrderBook.takeOrder.precision.t.sol @@ -3,9 +3,9 @@ pragma solidity =0.8.19; import "test/util/abstract/OrderBookExternalRealTest.sol"; -/// @title OrderBookTakeOrderTest +/// @title OrderBookTakeOrderPrecisionTest /// @notice A test harness for testing the OrderBook takeOrder function. -contract OrderBookTakeOrderTest is OrderBookExternalRealTest { +contract OrderBookTakeOrderPrecisionTest is OrderBookExternalRealTest { function checkPrecision( bytes memory rainString, uint8 outputTokenDecimals, diff --git a/test/concrete/OrderBook.takeOrder.tokenMismatch.t.sol b/test/concrete/OrderBook.takeOrder.tokenMismatch.t.sol index 14245c293..5f8634621 100644 --- a/test/concrete/OrderBook.takeOrder.tokenMismatch.t.sol +++ b/test/concrete/OrderBook.takeOrder.tokenMismatch.t.sol @@ -19,7 +19,9 @@ contract OrderBookTakeOrderTokenMismatchTest is OrderBookExternalRealTest { uint256 aOutputIOIndex, Order memory b, uint256 bInputIOIndex, - uint256 bOutputIOIndex + uint256 bOutputIOIndex, + uint256 maxTakerInput, + uint256 maxIORatio ) external { vm.assume(a.validInputs.length > 0); aInputIOIndex = bound(aInputIOIndex, 0, a.validInputs.length - 1); @@ -29,6 +31,7 @@ contract OrderBookTakeOrderTokenMismatchTest is OrderBookExternalRealTest { aOutputIOIndex = bound(aOutputIOIndex, 0, a.validOutputs.length - 1); vm.assume(b.validOutputs.length > 0); bOutputIOIndex = bound(bOutputIOIndex, 0, b.validOutputs.length - 1); + maxTakerInput = bound(maxTakerInput, 1, type(uint256).max); // Mismatch on inputs across orders taken. vm.assume(a.validInputs[aInputIOIndex].token != b.validInputs[bInputIOIndex].token); @@ -38,7 +41,7 @@ contract OrderBookTakeOrderTokenMismatchTest is OrderBookExternalRealTest { TakeOrderConfig[] memory orders = new TakeOrderConfig[](2); orders[0] = TakeOrderConfig(a, aInputIOIndex, aOutputIOIndex, new SignedContextV1[](0)); orders[1] = TakeOrderConfig(b, bInputIOIndex, bOutputIOIndex, new SignedContextV1[](0)); - TakeOrdersConfigV2 memory config = TakeOrdersConfigV2(0, type(uint256).max, type(uint256).max, orders, ""); + TakeOrdersConfigV2 memory config = TakeOrdersConfigV2(0, maxTakerInput, maxIORatio, orders, ""); vm.expectRevert( abi.encodeWithSelector( TokenMismatch.selector, b.validInputs[bInputIOIndex].token, a.validInputs[aInputIOIndex].token @@ -55,7 +58,9 @@ contract OrderBookTakeOrderTokenMismatchTest is OrderBookExternalRealTest { uint256 aOutputIOIndex, Order memory b, uint256 bInputIOIndex, - uint256 bOutputIOIndex + uint256 bOutputIOIndex, + uint256 maxTakerInput, + uint256 maxIORatio ) external { vm.assume(a.validInputs.length > 0); aInputIOIndex = bound(aInputIOIndex, 0, a.validInputs.length - 1); @@ -65,6 +70,7 @@ contract OrderBookTakeOrderTokenMismatchTest is OrderBookExternalRealTest { aOutputIOIndex = bound(aOutputIOIndex, 0, a.validOutputs.length - 1); vm.assume(b.validOutputs.length > 0); bOutputIOIndex = bound(bOutputIOIndex, 0, b.validOutputs.length - 1); + maxTakerInput = bound(maxTakerInput, 1, type(uint256).max); // Mismatch on outputs across orders taken. vm.assume(a.validOutputs[aOutputIOIndex].token != b.validOutputs[bOutputIOIndex].token); @@ -74,7 +80,7 @@ contract OrderBookTakeOrderTokenMismatchTest is OrderBookExternalRealTest { TakeOrderConfig[] memory orders = new TakeOrderConfig[](2); orders[0] = TakeOrderConfig(a, aInputIOIndex, aOutputIOIndex, new SignedContextV1[](0)); orders[1] = TakeOrderConfig(b, bInputIOIndex, bOutputIOIndex, new SignedContextV1[](0)); - TakeOrdersConfigV2 memory config = TakeOrdersConfigV2(0, type(uint256).max, type(uint256).max, orders, ""); + TakeOrdersConfigV2 memory config = TakeOrdersConfigV2(0, maxTakerInput, maxIORatio, orders, ""); vm.expectRevert( abi.encodeWithSelector( TokenMismatch.selector, b.validOutputs[bOutputIOIndex].token, a.validOutputs[aOutputIOIndex].token From 61961656f813677de6d3a3da05a718d285d99951 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Tue, 19 Sep 2023 23:22:55 +0400 Subject: [PATCH 02/13] test for max input on taker --- src/interface/unstable/IOrderBookV3.sol | 4 +- .../OrderBook.takeOrder.maximumInput.t.sol | 76 ++++++++++++++++++- test/concrete/OrderBook.takeOrder.noop.t.sol | 1 - 3 files changed, 75 insertions(+), 6 deletions(-) diff --git a/src/interface/unstable/IOrderBookV3.sol b/src/interface/unstable/IOrderBookV3.sol index e3035a3bf..dbcfb12fe 100644 --- a/src/interface/unstable/IOrderBookV3.sol +++ b/src/interface/unstable/IOrderBookV3.sol @@ -2,7 +2,9 @@ pragma solidity ^0.8.18; import "../ierc3156/IERC3156FlashLender.sol"; -import "lib/rain.interpreter/src/lib/caller/LibEvaluable.sol"; +import { + EvaluableConfigV2, IExpressionDeployerV2, Evaluable +} from "lib/rain.interpreter/src/lib/caller/LibEvaluable.sol"; import "lib/rain.interpreter/src/interface/IInterpreterCallerV2.sol"; /// Import unmodified structures from older versions of `IOrderBook`. diff --git a/test/concrete/OrderBook.takeOrder.maximumInput.t.sol b/test/concrete/OrderBook.takeOrder.maximumInput.t.sol index 05fc905e6..40747eae3 100644 --- a/test/concrete/OrderBook.takeOrder.maximumInput.t.sol +++ b/test/concrete/OrderBook.takeOrder.maximumInput.t.sol @@ -1,11 +1,21 @@ // SPDX-License-Identifier: CAL pragma solidity =0.8.19; -import {OrderBookExternalRealTest} from "test/util/abstract/OrderBookExternalRealTest.sol"; -import {Order, SignedContextV1, TakeOrderConfig, TakeOrdersConfigV2, ZeroMaximumInput} from "src/interface/unstable/IOrderBookV3.sol"; +import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; +import {OrderBookExternalRealTest, Vm} from "test/util/abstract/OrderBookExternalRealTest.sol"; +import { + Order, + SignedContextV1, + TakeOrderConfig, + TakeOrdersConfigV2, + ZeroMaximumInput, + IO, + EvaluableConfigV2, + OrderConfigV2 +} from "src/interface/unstable/IOrderBookV3.sol"; +import {IParserV1} from "rain.interpreter/src/interface/unstable/IParserV1.sol"; contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { - /// If there is some live order(s) but the maxTakerInput is zero we error as /// the caller has full control over this, and it would cause none of the /// orders to be taken. @@ -22,4 +32,62 @@ contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { (totalTakerInput, totalTakerOutput); } -} \ No newline at end of file + /// Add an order with unlimited maximum output and take it with a maximum + /// input. Only the maximum input should be taken. + function testTakeOrderMaximumInput() external { + address alice = address(uint160(uint256(keccak256("alice.rain.test")))); + address bob = address(uint160(uint256(keccak256("bob.rain.test")))); + uint256 vaultId = 0; + + Order memory order; + + { + (bytes memory bytecode, uint256[] memory constants) = + IParserV1(address(iDeployer)).parse("_ _:max-decimal18-value() 2e18;:;"); + IO[] memory inputs = new IO[](1); + inputs[0] = IO(address(iToken0), 18, vaultId); + IO[] memory outputs = new IO[](1); + outputs[0] = IO(address(iToken1), 18, vaultId); + EvaluableConfigV2 memory evaluableConfig = EvaluableConfigV2(iDeployer, bytecode, constants); + OrderConfigV2 memory orderConfig = OrderConfigV2(inputs, outputs, evaluableConfig, ""); + + vm.prank(alice); + vm.recordLogs(); + iOrderbook.addOrder(orderConfig); + Vm.Log[] memory entries = vm.getRecordedLogs(); + assertEq(entries.length, 3); + (,, order,) = abi.decode(entries[2].data, (address, address, Order, bytes32)); + + vm.prank(alice); + // Deposit some large amount of output tokens. + vm.mockCall( + address(iToken1), + abi.encodeWithSelector(IERC20.transferFrom.selector, alice, address(iOrderbook), 1e50), + abi.encode(true) + ); + iOrderbook.deposit(address(iToken1), vaultId, 1e50); + } + + uint256 expectedTakerInput = 1e5; + uint256 expectedTakerOutput = 2e5; + vm.prank(bob); + TakeOrderConfig[] memory orders = new TakeOrderConfig[](1); + orders[0] = TakeOrderConfig(order, 0, 0, new SignedContextV1[](0)); + TakeOrdersConfigV2 memory config = TakeOrdersConfigV2(0, expectedTakerInput, type(uint256).max, orders, ""); + + vm.mockCall( + address(iToken1), + abi.encodeWithSelector(IERC20.transfer.selector, bob, expectedTakerInput), + abi.encode(true) + ); + vm.mockCall( + address(iToken0), + abi.encodeWithSelector(IERC20.transferFrom.selector, bob, address(iOrderbook), expectedTakerOutput), + abi.encode(true) + ); + + (uint256 totalTakerInput, uint256 totalTakerOutput) = iOrderbook.takeOrders(config); + assertEq(totalTakerInput, expectedTakerInput); + assertEq(totalTakerOutput, expectedTakerOutput); + } +} diff --git a/test/concrete/OrderBook.takeOrder.noop.t.sol b/test/concrete/OrderBook.takeOrder.noop.t.sol index f6e3d8af5..26524ead2 100644 --- a/test/concrete/OrderBook.takeOrder.noop.t.sol +++ b/test/concrete/OrderBook.takeOrder.noop.t.sol @@ -133,5 +133,4 @@ contract OrderBookTakeOrderNoopTest is OrderBookExternalRealTest { assertEq(orderHash2, order2.hash()); } } - } From e3582b5c2247a00d2a7ea141ffce8733dd64481b Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Wed, 20 Sep 2023 10:21:06 +0400 Subject: [PATCH 03/13] expect calls in maximum input --- test/concrete/OrderBook.takeOrder.maximumInput.t.sol | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/concrete/OrderBook.takeOrder.maximumInput.t.sol b/test/concrete/OrderBook.takeOrder.maximumInput.t.sol index 40747eae3..363296a74 100644 --- a/test/concrete/OrderBook.takeOrder.maximumInput.t.sol +++ b/test/concrete/OrderBook.takeOrder.maximumInput.t.sol @@ -75,16 +75,27 @@ contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { orders[0] = TakeOrderConfig(order, 0, 0, new SignedContextV1[](0)); TakeOrdersConfigV2 memory config = TakeOrdersConfigV2(0, expectedTakerInput, type(uint256).max, orders, ""); + // Mock and expect the token transfers. vm.mockCall( address(iToken1), abi.encodeWithSelector(IERC20.transfer.selector, bob, expectedTakerInput), abi.encode(true) ); + vm.expectCall( + address(iToken1), + abi.encodeWithSelector(IERC20.transfer.selector, bob, expectedTakerInput), + 1 + ); vm.mockCall( address(iToken0), abi.encodeWithSelector(IERC20.transferFrom.selector, bob, address(iOrderbook), expectedTakerOutput), abi.encode(true) ); + vm.expectCall( + address(iToken0), + abi.encodeWithSelector(IERC20.transferFrom.selector, bob, address(iOrderbook), expectedTakerOutput), + 1 + ); (uint256 totalTakerInput, uint256 totalTakerOutput) = iOrderbook.takeOrders(config); assertEq(totalTakerInput, expectedTakerInput); From 75c1e1f803003e60f508064471d56b218a1acac1 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Wed, 20 Sep 2023 11:50:03 +0400 Subject: [PATCH 04/13] more tests for maximum input --- .gas-snapshot | 41 +++---- .../OrderBook.takeOrder.maximumInput.t.sol | 107 ++++++++++++------ 2 files changed, 92 insertions(+), 56 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index caa5da413..60f1b3c82 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -5,8 +5,8 @@ GenericPoolOrderBookV3FlashBorrowerTest:testTakeOrdersSender((address,bool,(addr 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, μ: 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, μ: 2626717, ~: 2600883) -OrderBookAddOrderMockTest:testAddOrderTwoAccountsWithSameConfig(address,address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 2493275, ~: 2492266) +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, μ: 2626597, ~: 2600883) +OrderBookAddOrderMockTest:testAddOrderTwoAccountsWithSameConfig(address,address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 2493242, ~: 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, μ: 1303904, ~: 1290881) OrderBookAddOrderMockTest:testAddOrderWithNonEmptyMetaReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 703690, ~: 697922) @@ -20,36 +20,39 @@ OrderBookAddOrderTest:testAddOrderRealThreeStackCalculate(address,((address,uint OrderBookAddOrderTest:testAddOrderRealTwoStackCalculateReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes)) (runs: 5096, μ: 715298, ~: 711943) OrderBookAddOrderTest:testAddOrderRealZeroStackCalculateReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes)) (runs: 5096, μ: 181518, ~: 180295) OrderBookDepositTest:testDepositEvent(address,uint256,uint256) (runs: 5096, μ: 38710, ~: 38710) -OrderBookDepositTest:testDepositFail(address,uint256,uint256) (runs: 5096, μ: 8937393460516740791, ~: 8937393460516740786) +OrderBookDepositTest:testDepositFail(address,uint256,uint256) (runs: 5096, μ: 8937393460516740788, ~: 8937393460516740786) OrderBookDepositTest:testDepositGas00() (gas: 8176) OrderBookDepositTest:testDepositGas01() (gas: 34620) -OrderBookDepositTest:testDepositMany((address,address,uint256,uint248)[]) (runs: 5096, μ: 5118682, ~: 4755733) +OrderBookDepositTest:testDepositMany((address,address,uint256,uint248)[]) (runs: 5096, μ: 5113360, ~: 4801963) OrderBookDepositTest:testDepositOverflow(address,uint256,uint256,uint256) (runs: 5096, μ: 46645, ~: 46645) -OrderBookDepositTest:testDepositReentrancy(address,uint256,uint256,address,uint256,uint256) (runs: 5096, μ: 495198, ~: 496632) +OrderBookDepositTest:testDepositReentrancy(address,uint256,uint256,address,uint256,uint256) (runs: 5096, μ: 495312, ~: 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, μ: 494014, ~: 495964) +OrderBookDepositTest:testVaultBalanceReentrant(address,uint256,uint256,address,address,uint256) (runs: 5096, μ: 494277, ~: 495964) OrderBookRemoveOrderMockTest:testRemoveOrderAddRemoveMulti(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 7256622, ~: 7139425) 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, μ: 5070365, ~: 5046372) -OrderBookRemoveOrderMockTest:testRemoveOrderDifferentOwners(address,address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 4854788, ~: 4841901) +OrderBookRemoveOrderMockTest:testRemoveOrderDifferentOwners(address,address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 4854223, ~: 4841901) 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, μ: 10466985, ~: 10453491) OrderBookRemoveOrderMockTest:testRemoveOrderDoesNotExist(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 386811, ~: 382063) -OrderBookRemoveOrderMockTest:testRemoveOrderOnlyOwner(address,address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 2603402, ~: 2601080) -OrderBookTakeOrderNoopTest:testTakeOrderNoopNonLiveOrderOne((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,(address,uint256[],bytes)) (runs: 5096, μ: 431665, ~: 427913) -OrderBookTakeOrderNoopTest:testTakeOrderNoopNonLiveOrderTwo((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),(address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,uint256,uint256,(address,uint256[],bytes),(address,uint256[],bytes)) (runs: 5096, μ: 851326, ~: 847158) +OrderBookRemoveOrderMockTest:testRemoveOrderOnlyOwner(address,address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 2603102, ~: 2601080) +OrderBookTakeOrderMaximumInputTest:testTakeOrderMaximumInputSingleOrder(uint256) (runs: 5096, μ: 266955, ~: 266687) +OrderBookTakeOrderMaximumInputTest:testTakeOrderMaximumInputSingleOrderLessThanMaximumOutput(uint256) (runs: 5096, μ: 273355, ~: 273287) +OrderBookTakeOrderMaximumInputTest:testTakeOrderNoopZeroMaxTakerInput((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),(address,uint256[],bytes)) (runs: 5096, μ: 184242, ~: 183154) +OrderBookTakeOrderNoopTest:testTakeOrderNoopNonLiveOrderOne((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,(address,uint256[],bytes)) (runs: 5096, μ: 431694, ~: 427938) +OrderBookTakeOrderNoopTest:testTakeOrderNoopNonLiveOrderTwo((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),(address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,uint256,uint256,(address,uint256[],bytes),(address,uint256[],bytes)) (runs: 5096, μ: 851351, ~: 847183) OrderBookTakeOrderNoopTest:testTakeOrderNoopZeroOrders() (gas: 12403) -OrderBookTakeOrderTest:testTakeOrderPrecisionKnownBad01() (gas: 2631522) -OrderBookTakeOrderTokenMismatchDecimalsTest:testTokenMismatchInputs((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,(address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256) (runs: 5096, μ: 622317, ~: 616897) -OrderBookTakeOrderTokenMismatchDecimalsTest:testTokenMismatchOutputs((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,(address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256) (runs: 5096, μ: 622684, ~: 616897) -OrderBookTakeOrderTokenMismatchTest:testTokenMismatchInputs((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,(address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256) (runs: 5096, μ: 618341, ~: 611981) -OrderBookTakeOrderTokenMismatchTest:testTokenMismatchOutputs((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,(address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256) (runs: 5096, μ: 619601, ~: 613241) +OrderBookTakeOrderPrecisionTest:testTakeOrderPrecisionKnownBad01() (gas: 2631797) +OrderBookTakeOrderTokenMismatchDecimalsTest:testTokenMismatchInputs((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,(address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256) (runs: 5096, μ: 622036, ~: 616303) +OrderBookTakeOrderTokenMismatchDecimalsTest:testTokenMismatchOutputs((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,(address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256) (runs: 5096, μ: 622678, ~: 616922) +OrderBookTakeOrderTokenMismatchTest:testTokenMismatchInputs((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,(address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,uint256,uint256) (runs: 5096, μ: 618202, ~: 618595) +OrderBookTakeOrderTokenMismatchTest:testTokenMismatchOutputs((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,(address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,uint256,uint256) (runs: 5096, μ: 619505, ~: 619862) OrderBookWithdrawTest:testWithdrawEmptyVault(address,address,uint256,uint256) (runs: 5096, μ: 15251, ~: 15251) -OrderBookWithdrawTest:testWithdrawFailure(address,uint256,uint256,uint256) (runs: 5096, μ: 8937393460516719661, ~: 8937393460516738938) -OrderBookWithdrawTest:testWithdrawFullVault(address,uint256,uint256,uint256) (runs: 5096, μ: 41258, ~: 41256) -OrderBookWithdrawTest:testWithdrawMany((bool,address,address,uint256,uint248)[]) (runs: 5096, μ: 2542990, ~: 2235389) +OrderBookWithdrawTest:testWithdrawFailure(address,uint256,uint256,uint256) (runs: 5096, μ: 8937393460516719831, ~: 8937393460516738938) +OrderBookWithdrawTest:testWithdrawFullVault(address,uint256,uint256,uint256) (runs: 5096, μ: 41257, ~: 41254) +OrderBookWithdrawTest:testWithdrawMany((bool,address,address,uint256,uint248)[]) (runs: 5096, μ: 2542859, ~: 2233360) OrderBookWithdrawTest:testWithdrawPartialVault(address,uint256,uint256,uint256) (runs: 5096, μ: 51929, ~: 51929) -OrderBookWithdrawTest:testWithdrawReentrant(address,uint256,uint256,address,address,uint256) (runs: 5096, μ: 506228, ~: 507997) +OrderBookWithdrawTest:testWithdrawReentrant(address,uint256,uint256,address,address,uint256) (runs: 5096, μ: 506161, ~: 507997) OrderBookWithdrawTest:testWithdrawZero(address,address,uint256) (runs: 5096, μ: 12809, ~: 12809) RouteProcessorOrderBookV3ArbOrderTakerTest:testMinimumOutput((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,uint256,uint256) (runs: 5096, μ: 333853, ~: 333304) RouteProcessorOrderBookV3ArbOrderTakerTest:testTakeOrdersSender((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256) (runs: 5096, μ: 268039, ~: 268033) \ No newline at end of file diff --git a/test/concrete/OrderBook.takeOrder.maximumInput.t.sol b/test/concrete/OrderBook.takeOrder.maximumInput.t.sol index 363296a74..d1a71ed49 100644 --- a/test/concrete/OrderBook.takeOrder.maximumInput.t.sol +++ b/test/concrete/OrderBook.takeOrder.maximumInput.t.sol @@ -32,48 +32,62 @@ contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { (totalTakerInput, totalTakerOutput); } - /// Add an order with unlimited maximum output and take it with a maximum - /// input. Only the maximum input should be taken. - function testTakeOrderMaximumInput() external { + function checkTakeOrderMaximumInput( + bytes[] memory orderStrings, + uint256 maximumTakerInput, + uint256 expectedTakerInput, + uint256 expectedTakerOutput + ) internal { address alice = address(uint160(uint256(keccak256("alice.rain.test")))); address bob = address(uint160(uint256(keccak256("bob.rain.test")))); uint256 vaultId = 0; - Order memory order; + Order[] memory orders = new Order[](orderStrings.length); - { - (bytes memory bytecode, uint256[] memory constants) = - IParserV1(address(iDeployer)).parse("_ _:max-decimal18-value() 2e18;:;"); - IO[] memory inputs = new IO[](1); - inputs[0] = IO(address(iToken0), 18, vaultId); - IO[] memory outputs = new IO[](1); - outputs[0] = IO(address(iToken1), 18, vaultId); - EvaluableConfigV2 memory evaluableConfig = EvaluableConfigV2(iDeployer, bytecode, constants); - OrderConfigV2 memory orderConfig = OrderConfigV2(inputs, outputs, evaluableConfig, ""); + for (uint256 i = 0; i < orderStrings.length; i++) { + { + { + (bytes memory bytecode, uint256[] memory constants) = + IParserV1(address(iDeployer)).parse(orderStrings[i]); + IO[] memory inputs = new IO[](1); + inputs[0] = IO(address(iToken0), 18, vaultId); + IO[] memory outputs = new IO[](1); + outputs[0] = IO(address(iToken1), 18, vaultId); + EvaluableConfigV2 memory evaluableConfig = EvaluableConfigV2(iDeployer, bytecode, constants); + OrderConfigV2 memory orderConfig = OrderConfigV2(inputs, outputs, evaluableConfig, ""); - vm.prank(alice); - vm.recordLogs(); - iOrderbook.addOrder(orderConfig); - Vm.Log[] memory entries = vm.getRecordedLogs(); - assertEq(entries.length, 3); - (,, order,) = abi.decode(entries[2].data, (address, address, Order, bytes32)); + vm.prank(alice); + vm.recordLogs(); + iOrderbook.addOrder(orderConfig); + Vm.Log[] memory entries = vm.getRecordedLogs(); + assertEq(entries.length, 3); + (,, Order memory order,) = abi.decode(entries[2].data, (address, address, Order, bytes32)); + orders[i] = order; + } - vm.prank(alice); - // Deposit some large amount of output tokens. - vm.mockCall( - address(iToken1), - abi.encodeWithSelector(IERC20.transferFrom.selector, alice, address(iOrderbook), 1e50), - abi.encode(true) - ); - iOrderbook.deposit(address(iToken1), vaultId, 1e50); + vm.prank(alice); + // Deposit the amount of tokens required to take the order. + vm.mockCall( + address(iToken1), + abi.encodeWithSelector(IERC20.transferFrom.selector, alice, address(iOrderbook), expectedTakerInput), + abi.encode(true) + ); + vm.expectCall( + address(iToken1), + abi.encodeWithSelector(IERC20.transferFrom.selector, alice, address(iOrderbook), expectedTakerInput), + 1 + ); + iOrderbook.deposit(address(iToken1), vaultId, expectedTakerInput); + assertEq(iOrderbook.vaultBalance(alice, address(iToken1), vaultId), expectedTakerInput); + } } - uint256 expectedTakerInput = 1e5; - uint256 expectedTakerOutput = 2e5; vm.prank(bob); - TakeOrderConfig[] memory orders = new TakeOrderConfig[](1); - orders[0] = TakeOrderConfig(order, 0, 0, new SignedContextV1[](0)); - TakeOrdersConfigV2 memory config = TakeOrdersConfigV2(0, expectedTakerInput, type(uint256).max, orders, ""); + TakeOrderConfig[] memory takeOrders = new TakeOrderConfig[](orders.length); + for (uint256 i = 0; i < orders.length; i++) { + takeOrders[i] = TakeOrderConfig(orders[i], 0, 0, new SignedContextV1[](0)); + } + TakeOrdersConfigV2 memory config = TakeOrdersConfigV2(0, maximumTakerInput, type(uint256).max, takeOrders, ""); // Mock and expect the token transfers. vm.mockCall( @@ -81,11 +95,7 @@ contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { abi.encodeWithSelector(IERC20.transfer.selector, bob, expectedTakerInput), abi.encode(true) ); - vm.expectCall( - address(iToken1), - abi.encodeWithSelector(IERC20.transfer.selector, bob, expectedTakerInput), - 1 - ); + vm.expectCall(address(iToken1), abi.encodeWithSelector(IERC20.transfer.selector, bob, expectedTakerInput), 1); vm.mockCall( address(iToken0), abi.encodeWithSelector(IERC20.transferFrom.selector, bob, address(iOrderbook), expectedTakerOutput), @@ -100,5 +110,28 @@ contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { (uint256 totalTakerInput, uint256 totalTakerOutput) = iOrderbook.takeOrders(config); assertEq(totalTakerInput, expectedTakerInput); assertEq(totalTakerOutput, expectedTakerOutput); + assertEq(iOrderbook.vaultBalance(alice, address(iToken1), vaultId), 0); + assertEq(iOrderbook.vaultBalance(alice, address(iToken0), vaultId), expectedTakerOutput); + } + + /// Add an order with unlimited maximum output and take it with a maximum + /// input. Only the maximum input should be taken. + function testTakeOrderMaximumInputSingleOrder(uint256 expectedTakerInput) external { + expectedTakerInput = bound(expectedTakerInput, 1, type(uint128).max); + uint256 expectedTakerOutput = expectedTakerInput * 2; + bytes[] memory orderStrings = new bytes[](1); + orderStrings[0] = "_ _:max-decimal18-value() 2e18;:;"; + checkTakeOrderMaximumInput(orderStrings, expectedTakerInput, expectedTakerInput, expectedTakerOutput); + } + + /// Add an order with less than the maximum output. Only the limit from the + /// order should be taken. + function testTakeOrderMaximumInputSingleOrderLessThanMaximumOutput(uint256 maximumTakerInput) external { + maximumTakerInput = bound(maximumTakerInput, 1000, type(uint256).max); + uint256 expectedTakerInput = 1000; + uint256 expectedTakerOutput = expectedTakerInput * 2; + bytes[] memory orderStrings = new bytes[](1); + orderStrings[0] = "_ _:1000 2e18;:;"; + checkTakeOrderMaximumInput(orderStrings, maximumTakerInput, expectedTakerInput, expectedTakerOutput); } } From 33e0b5c66c891e6cabe2f800337d7ea503fa6deb Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Thu, 21 Sep 2023 12:04:28 +0400 Subject: [PATCH 05/13] test vault balance cap on take orders --- .../OrderBook.takeOrder.maximumInput.t.sol | 69 ++++++++++++++----- 1 file changed, 51 insertions(+), 18 deletions(-) diff --git a/test/concrete/OrderBook.takeOrder.maximumInput.t.sol b/test/concrete/OrderBook.takeOrder.maximumInput.t.sol index d1a71ed49..535396049 100644 --- a/test/concrete/OrderBook.takeOrder.maximumInput.t.sol +++ b/test/concrete/OrderBook.takeOrder.maximumInput.t.sol @@ -34,6 +34,7 @@ contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { function checkTakeOrderMaximumInput( bytes[] memory orderStrings, + uint256 ownerDepositAmount, uint256 maximumTakerInput, uint256 expectedTakerInput, uint256 expectedTakerOutput @@ -65,20 +66,26 @@ contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { orders[i] = order; } - vm.prank(alice); - // Deposit the amount of tokens required to take the order. - vm.mockCall( - address(iToken1), - abi.encodeWithSelector(IERC20.transferFrom.selector, alice, address(iOrderbook), expectedTakerInput), - abi.encode(true) - ); - vm.expectCall( - address(iToken1), - abi.encodeWithSelector(IERC20.transferFrom.selector, alice, address(iOrderbook), expectedTakerInput), - 1 - ); - iOrderbook.deposit(address(iToken1), vaultId, expectedTakerInput); - assertEq(iOrderbook.vaultBalance(alice, address(iToken1), vaultId), expectedTakerInput); + if (ownerDepositAmount > 0) { + vm.prank(alice); + // Deposit the amount of tokens required to take the order. + vm.mockCall( + address(iToken1), + abi.encodeWithSelector( + IERC20.transferFrom.selector, alice, address(iOrderbook), expectedTakerInput + ), + abi.encode(true) + ); + vm.expectCall( + address(iToken1), + abi.encodeWithSelector( + IERC20.transferFrom.selector, alice, address(iOrderbook), expectedTakerInput + ), + 1 + ); + iOrderbook.deposit(address(iToken1), vaultId, ownerDepositAmount); + } + assertEq(iOrderbook.vaultBalance(alice, address(iToken1), vaultId), ownerDepositAmount); } } @@ -95,7 +102,11 @@ contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { abi.encodeWithSelector(IERC20.transfer.selector, bob, expectedTakerInput), abi.encode(true) ); - vm.expectCall(address(iToken1), abi.encodeWithSelector(IERC20.transfer.selector, bob, expectedTakerInput), 1); + vm.expectCall( + address(iToken1), + abi.encodeWithSelector(IERC20.transfer.selector, bob, expectedTakerInput), + expectedTakerInput > 0 ? 1 : 0 + ); vm.mockCall( address(iToken0), abi.encodeWithSelector(IERC20.transferFrom.selector, bob, address(iOrderbook), expectedTakerOutput), @@ -104,7 +115,7 @@ contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { vm.expectCall( address(iToken0), abi.encodeWithSelector(IERC20.transferFrom.selector, bob, address(iOrderbook), expectedTakerOutput), - 1 + expectedTakerOutput > 0 ? 1 : 0 ); (uint256 totalTakerInput, uint256 totalTakerOutput) = iOrderbook.takeOrders(config); @@ -121,7 +132,9 @@ contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { uint256 expectedTakerOutput = expectedTakerInput * 2; bytes[] memory orderStrings = new bytes[](1); orderStrings[0] = "_ _:max-decimal18-value() 2e18;:;"; - checkTakeOrderMaximumInput(orderStrings, expectedTakerInput, expectedTakerInput, expectedTakerOutput); + checkTakeOrderMaximumInput( + orderStrings, expectedTakerInput, expectedTakerInput, expectedTakerInput, expectedTakerOutput + ); } /// Add an order with less than the maximum output. Only the limit from the @@ -132,6 +145,26 @@ contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { uint256 expectedTakerOutput = expectedTakerInput * 2; bytes[] memory orderStrings = new bytes[](1); orderStrings[0] = "_ _:1000 2e18;:;"; - checkTakeOrderMaximumInput(orderStrings, maximumTakerInput, expectedTakerInput, expectedTakerOutput); + checkTakeOrderMaximumInput( + orderStrings, expectedTakerInput, maximumTakerInput, expectedTakerInput, expectedTakerOutput + ); + } + + /// If the vault balance is less than both the maximum input and the order + /// limit, the vault balance should be taken. + function testTakeOrderMaximumInputSingleOrderLessThanMaximumInput( + uint256 ownerDepositAmount, + uint256 maximumTakerInput + ) external { + uint256 orderLimit = 1000; + ownerDepositAmount = bound(ownerDepositAmount, 0, orderLimit - 1); + maximumTakerInput = bound(maximumTakerInput, 1000, type(uint256).max); + uint256 expectedTakerInput = ownerDepositAmount; + uint256 expectedTakerOutput = expectedTakerInput * 2; + bytes[] memory orderStrings = new bytes[](1); + orderStrings[0] = "_ _:1000 2e18;:;"; + checkTakeOrderMaximumInput( + orderStrings, ownerDepositAmount, maximumTakerInput, expectedTakerInput, expectedTakerOutput + ); } } From 947e92bf4d8d2ff983bdf7bb0c3b112bae4ba422 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Thu, 21 Sep 2023 20:32:55 +0400 Subject: [PATCH 06/13] deposit take orders test --- .../OrderBook.takeOrder.maximumInput.t.sol | 47 ++++++++++++++++--- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/test/concrete/OrderBook.takeOrder.maximumInput.t.sol b/test/concrete/OrderBook.takeOrder.maximumInput.t.sol index 535396049..ffd279e99 100644 --- a/test/concrete/OrderBook.takeOrder.maximumInput.t.sol +++ b/test/concrete/OrderBook.takeOrder.maximumInput.t.sol @@ -72,20 +72,22 @@ contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { vm.mockCall( address(iToken1), abi.encodeWithSelector( - IERC20.transferFrom.selector, alice, address(iOrderbook), expectedTakerInput + IERC20.transferFrom.selector, alice, address(iOrderbook), ownerDepositAmount ), abi.encode(true) ); vm.expectCall( address(iToken1), abi.encodeWithSelector( - IERC20.transferFrom.selector, alice, address(iOrderbook), expectedTakerInput + IERC20.transferFrom.selector, alice, address(iOrderbook), ownerDepositAmount ), 1 ); iOrderbook.deposit(address(iToken1), vaultId, ownerDepositAmount); } - assertEq(iOrderbook.vaultBalance(alice, address(iToken1), vaultId), ownerDepositAmount); + assertEq( + iOrderbook.vaultBalance(alice, address(iToken1), vaultId), ownerDepositAmount, "vaultBalance before" + ); } } @@ -119,10 +121,18 @@ contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { ); (uint256 totalTakerInput, uint256 totalTakerOutput) = iOrderbook.takeOrders(config); - assertEq(totalTakerInput, expectedTakerInput); - assertEq(totalTakerOutput, expectedTakerOutput); - assertEq(iOrderbook.vaultBalance(alice, address(iToken1), vaultId), 0); - assertEq(iOrderbook.vaultBalance(alice, address(iToken0), vaultId), expectedTakerOutput); + assertEq(totalTakerInput, expectedTakerInput, "totalTakerInput"); + assertEq(totalTakerOutput, expectedTakerOutput, "totalTakerOutput"); + /// The vault balance should be exactly what was deposited minus the + /// amount sent to the order taker. This can never be negative. + assertEq( + iOrderbook.vaultBalance(alice, address(iToken1), vaultId), + ownerDepositAmount - expectedTakerInput, + "vaultBalance deposited" + ); + assertEq( + iOrderbook.vaultBalance(alice, address(iToken0), vaultId), expectedTakerOutput, "vaultBalance received" + ); } /// Add an order with unlimited maximum output and take it with a maximum @@ -167,4 +177,27 @@ contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { orderStrings, ownerDepositAmount, maximumTakerInput, expectedTakerInput, expectedTakerOutput ); } + + /// The deposit amount can be anything actually, the order taking should + /// adjust accordingly, and leave any unspent deposited tokens in the vault. + function testTakeOrderMaximumInputSingleAnyDeposit(uint256 ownerDepositAmount, uint256 maximumTakerInput) + external + { + uint256 orderLimit = 1000; + bytes[] memory orderStrings = new bytes[](1); + orderStrings[0] = "_ _:1000 2e18;:;"; + maximumTakerInput = bound(maximumTakerInput, 1, type(uint256).max); + // The expected input is the minimum of the maximum input and the order + // limit. + uint256 expectedTakerInput = maximumTakerInput < orderLimit ? maximumTakerInput : orderLimit; + + ownerDepositAmount = bound(ownerDepositAmount, 0, type(uint256).max); + expectedTakerInput = expectedTakerInput < ownerDepositAmount ? expectedTakerInput : ownerDepositAmount; + + uint256 expectedTakerOutput = expectedTakerInput * 2; + + checkTakeOrderMaximumInput( + orderStrings, ownerDepositAmount, maximumTakerInput, expectedTakerInput, expectedTakerOutput + ); + } } From e04f69358b74a2cc61b11f852f1d8bcc7f897592 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Thu, 21 Sep 2023 23:23:10 +0400 Subject: [PATCH 07/13] wip on minimum input tests --- .../OrderBook.takeOrder.maximumInput.t.sol | 238 +++++++++++++----- 1 file changed, 171 insertions(+), 67 deletions(-) diff --git a/test/concrete/OrderBook.takeOrder.maximumInput.t.sol b/test/concrete/OrderBook.takeOrder.maximumInput.t.sol index ffd279e99..fda980097 100644 --- a/test/concrete/OrderBook.takeOrder.maximumInput.t.sol +++ b/test/concrete/OrderBook.takeOrder.maximumInput.t.sol @@ -32,61 +32,78 @@ contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { (totalTakerInput, totalTakerOutput); } + struct TestOrder { + address owner; + bytes orderString; + } + + struct TestVault { + address owner; + address token; + uint256 deposit; + uint256 expect; + } + function checkTakeOrderMaximumInput( - bytes[] memory orderStrings, - uint256 ownerDepositAmount, + TestOrder[] memory testOrders, + TestVault[] memory testVaults, uint256 maximumTakerInput, uint256 expectedTakerInput, uint256 expectedTakerOutput ) internal { - address alice = address(uint160(uint256(keccak256("alice.rain.test")))); address bob = address(uint160(uint256(keccak256("bob.rain.test")))); uint256 vaultId = 0; - Order[] memory orders = new Order[](orderStrings.length); + Order[] memory orders = new Order[](testOrders.length); - for (uint256 i = 0; i < orderStrings.length; i++) { + for (uint256 i = 0; i < testOrders.length; i++) { { + OrderConfigV2 memory orderConfig; { (bytes memory bytecode, uint256[] memory constants) = - IParserV1(address(iDeployer)).parse(orderStrings[i]); + IParserV1(address(iDeployer)).parse(testOrders[i].orderString); IO[] memory inputs = new IO[](1); inputs[0] = IO(address(iToken0), 18, vaultId); IO[] memory outputs = new IO[](1); outputs[0] = IO(address(iToken1), 18, vaultId); EvaluableConfigV2 memory evaluableConfig = EvaluableConfigV2(iDeployer, bytecode, constants); - OrderConfigV2 memory orderConfig = OrderConfigV2(inputs, outputs, evaluableConfig, ""); - - vm.prank(alice); - vm.recordLogs(); - iOrderbook.addOrder(orderConfig); - Vm.Log[] memory entries = vm.getRecordedLogs(); - assertEq(entries.length, 3); - (,, Order memory order,) = abi.decode(entries[2].data, (address, address, Order, bytes32)); - orders[i] = order; + orderConfig = OrderConfigV2(inputs, outputs, evaluableConfig, ""); } - if (ownerDepositAmount > 0) { - vm.prank(alice); - // Deposit the amount of tokens required to take the order. - vm.mockCall( - address(iToken1), - abi.encodeWithSelector( - IERC20.transferFrom.selector, alice, address(iOrderbook), ownerDepositAmount - ), - abi.encode(true) - ); - vm.expectCall( - address(iToken1), - abi.encodeWithSelector( - IERC20.transferFrom.selector, alice, address(iOrderbook), ownerDepositAmount - ), - 1 - ); - iOrderbook.deposit(address(iToken1), vaultId, ownerDepositAmount); - } + vm.prank(testOrders[i].owner); + vm.recordLogs(); + iOrderbook.addOrder(orderConfig); + Vm.Log[] memory entries = vm.getRecordedLogs(); + assertEq(entries.length, 3); + (,, Order memory order,) = abi.decode(entries[2].data, (address, address, Order, bytes32)); + orders[i] = order; + } + } + + for (uint256 i = 0; i < testVaults.length; i++) { + if (testVaults[i].deposit > 0) { + // Deposit the amount of tokens required to take the order. + vm.mockCall( + address(iToken1), + abi.encodeWithSelector( + IERC20.transferFrom.selector, testVaults[i].owner, address(iOrderbook), testVaults[i].deposit + ), + abi.encode(true) + ); + vm.expectCall( + address(iToken1), + abi.encodeWithSelector( + IERC20.transferFrom.selector, testVaults[i].owner, address(iOrderbook), testVaults[i].deposit + ), + 1 + ); + uint256 balanceBefore = iOrderbook.vaultBalance(testVaults[i].owner, testVaults[i].token, vaultId); + vm.prank(testVaults[i].owner); + iOrderbook.deposit(testVaults[i].token, vaultId, testVaults[i].deposit); assertEq( - iOrderbook.vaultBalance(alice, address(iToken1), vaultId), ownerDepositAmount, "vaultBalance before" + iOrderbook.vaultBalance(testVaults[i].owner, testVaults[i].token, vaultId), + balanceBefore + testVaults[i].deposit, + "vaultBalance before" ); } } @@ -123,41 +140,50 @@ contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { (uint256 totalTakerInput, uint256 totalTakerOutput) = iOrderbook.takeOrders(config); assertEq(totalTakerInput, expectedTakerInput, "totalTakerInput"); assertEq(totalTakerOutput, expectedTakerOutput, "totalTakerOutput"); - /// The vault balance should be exactly what was deposited minus the - /// amount sent to the order taker. This can never be negative. - assertEq( - iOrderbook.vaultBalance(alice, address(iToken1), vaultId), - ownerDepositAmount - expectedTakerInput, - "vaultBalance deposited" - ); - assertEq( - iOrderbook.vaultBalance(alice, address(iToken0), vaultId), expectedTakerOutput, "vaultBalance received" - ); + + for (uint256 i = 0; i < testVaults.length; i++) { + assertEq( + iOrderbook.vaultBalance(testVaults[i].owner, testVaults[i].token, vaultId), + testVaults[i].expect, + "vaultBalance" + ); + } } /// Add an order with unlimited maximum output and take it with a maximum /// input. Only the maximum input should be taken. - function testTakeOrderMaximumInputSingleOrder(uint256 expectedTakerInput) external { + function testTakeOrderMaximumInputSingleOrderUnlimitedMax(uint256 expectedTakerInput) external { + address owner = address(uint160(uint256(keccak256("owner.rain.test")))); + expectedTakerInput = bound(expectedTakerInput, 1, type(uint128).max); uint256 expectedTakerOutput = expectedTakerInput * 2; - bytes[] memory orderStrings = new bytes[](1); - orderStrings[0] = "_ _:max-decimal18-value() 2e18;:;"; - checkTakeOrderMaximumInput( - orderStrings, expectedTakerInput, expectedTakerInput, expectedTakerInput, expectedTakerOutput - ); + + TestOrder[] memory testOrders = new TestOrder[](1); + testOrders[0] = TestOrder(owner, "_ _:max-decimal18-value() 2e18;:;"); + + TestVault[] memory testVaults = new TestVault[](2); + testVaults[0] = TestVault(owner, address(iToken1), expectedTakerInput, 0); + testVaults[1] = TestVault(owner, address(iToken0), 0, expectedTakerOutput); + + checkTakeOrderMaximumInput(testOrders, testVaults, expectedTakerInput, expectedTakerInput, expectedTakerOutput); } /// Add an order with less than the maximum output. Only the limit from the /// order should be taken. function testTakeOrderMaximumInputSingleOrderLessThanMaximumOutput(uint256 maximumTakerInput) external { + address owner = address(uint160(uint256(keccak256("owner.rain.test")))); maximumTakerInput = bound(maximumTakerInput, 1000, type(uint256).max); uint256 expectedTakerInput = 1000; uint256 expectedTakerOutput = expectedTakerInput * 2; - bytes[] memory orderStrings = new bytes[](1); - orderStrings[0] = "_ _:1000 2e18;:;"; - checkTakeOrderMaximumInput( - orderStrings, expectedTakerInput, maximumTakerInput, expectedTakerInput, expectedTakerOutput - ); + + TestOrder[] memory testOrders = new TestOrder[](1); + testOrders[0] = TestOrder(owner, "_ _:1000 2e18;:;"); + + TestVault[] memory testVaults = new TestVault[](2); + testVaults[0] = TestVault(owner, address(iToken1), expectedTakerInput, 0); + testVaults[1] = TestVault(owner, address(iToken0), 0, expectedTakerOutput); + + checkTakeOrderMaximumInput(testOrders, testVaults, maximumTakerInput, expectedTakerInput, expectedTakerOutput); } /// If the vault balance is less than both the maximum input and the order @@ -166,16 +192,21 @@ contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { uint256 ownerDepositAmount, uint256 maximumTakerInput ) external { + address owner = address(uint160(uint256(keccak256("owner.rain.test")))); uint256 orderLimit = 1000; ownerDepositAmount = bound(ownerDepositAmount, 0, orderLimit - 1); maximumTakerInput = bound(maximumTakerInput, 1000, type(uint256).max); uint256 expectedTakerInput = ownerDepositAmount; uint256 expectedTakerOutput = expectedTakerInput * 2; - bytes[] memory orderStrings = new bytes[](1); - orderStrings[0] = "_ _:1000 2e18;:;"; - checkTakeOrderMaximumInput( - orderStrings, ownerDepositAmount, maximumTakerInput, expectedTakerInput, expectedTakerOutput - ); + + TestOrder[] memory testOrders = new TestOrder[](1); + testOrders[0] = TestOrder(owner, "_ _:1000 2e18;:;"); + + TestVault[] memory testVaults = new TestVault[](2); + testVaults[0] = TestVault(owner, address(iToken1), ownerDepositAmount, 0); + testVaults[1] = TestVault(owner, address(iToken0), 0, expectedTakerOutput); + + checkTakeOrderMaximumInput(testOrders, testVaults, maximumTakerInput, expectedTakerInput, expectedTakerOutput); } /// The deposit amount can be anything actually, the order taking should @@ -183,21 +214,94 @@ contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { function testTakeOrderMaximumInputSingleAnyDeposit(uint256 ownerDepositAmount, uint256 maximumTakerInput) external { + address owner = address(uint160(uint256(keccak256("owner.rain.test")))); uint256 orderLimit = 1000; - bytes[] memory orderStrings = new bytes[](1); - orderStrings[0] = "_ _:1000 2e18;:;"; + + TestOrder[] memory testOrders = new TestOrder[](1); + testOrders[0] = TestOrder(owner, "_ _:1000 2e18;:;"); + maximumTakerInput = bound(maximumTakerInput, 1, type(uint256).max); // The expected input is the minimum of the maximum input and the order // limit. uint256 expectedTakerInput = maximumTakerInput < orderLimit ? maximumTakerInput : orderLimit; - ownerDepositAmount = bound(ownerDepositAmount, 0, type(uint256).max); expectedTakerInput = expectedTakerInput < ownerDepositAmount ? expectedTakerInput : ownerDepositAmount; + uint256 expectedTakerOutput = expectedTakerInput * 2; + TestVault[] memory testVaults = new TestVault[](2); + testVaults[0] = TestVault(owner, address(iToken1), ownerDepositAmount, ownerDepositAmount - expectedTakerInput); + testVaults[1] = TestVault(owner, address(iToken0), 0, expectedTakerOutput); + + checkTakeOrderMaximumInput(testOrders, testVaults, maximumTakerInput, expectedTakerInput, expectedTakerOutput); + } + + /// The taker input can be sourced from multiple orders. Tests two orders + /// that combined make up the maximum taker input. Both orders have the + /// same owner. + function testTakeOrderMaximumInputMultipleOrders(uint256 ownerDepositAmount, uint256 maximumTakerInput) external { + address owner = address(uint160(uint256(keccak256("owner.rain.test")))); + uint256 orderLimit = 1500; + + TestOrder[] memory testOrders = new TestOrder[](2); + testOrders[0] = TestOrder(owner, "_ _:1000 2e18;:;"); + testOrders[1] = TestOrder(owner, "_ _:500 2e18;:;"); + + maximumTakerInput = bound(maximumTakerInput, 1, type(uint256).max); + // The expected input is the minimum of the maximum input and the order + // limit. + uint256 expectedTakerInput = maximumTakerInput < orderLimit ? maximumTakerInput : orderLimit; + + expectedTakerInput = expectedTakerInput < ownerDepositAmount ? expectedTakerInput : ownerDepositAmount; uint256 expectedTakerOutput = expectedTakerInput * 2; - checkTakeOrderMaximumInput( - orderStrings, ownerDepositAmount, maximumTakerInput, expectedTakerInput, expectedTakerOutput - ); + TestVault[] memory testVaults = new TestVault[](2); + testVaults[0] = TestVault(owner, address(iToken1), ownerDepositAmount, ownerDepositAmount - expectedTakerInput); + testVaults[1] = TestVault(owner, address(iToken0), 0, expectedTakerOutput); + + checkTakeOrderMaximumInput(testOrders, testVaults, maximumTakerInput, expectedTakerInput, expectedTakerOutput); + } + + /// The taker input can be source from multiple orders with multiple owners. + /// Tests two orders that combined make up the maximum taker input. Both + /// orders have different owners. + function testTakeOrderMaximumInputMultipleOrdersMultipleOwners( + uint256 ownerOneDepositAmount, + uint256 ownerTwoDepositAmount, + uint256 maximumTakerInput + ) external { + // Avoid information free overflow. + ownerTwoDepositAmount = bound(ownerTwoDepositAmount, 0, type(uint256).max - ownerOneDepositAmount); + + address ownerOne = address(uint160(uint256(keccak256("ownerOne.rain.test")))); + address ownerTwo = address(uint160(uint256(keccak256("ownerTwo.rain.test")))); + uint256 orderLimit = 1500; + + TestOrder[] memory testOrders = new TestOrder[](2); + testOrders[0] = TestOrder(ownerOne, "_ _:1000 2e18;:;"); + testOrders[1] = TestOrder(ownerTwo, "_ _:500 2e18;:;"); + + maximumTakerInput = bound(maximumTakerInput, 1, type(uint256).max); + // The expected input is the minimum of the maximum input and the order + // limit. + uint256 expectedTakerInput = maximumTakerInput < orderLimit ? maximumTakerInput : orderLimit; + + uint256 totalDepositAmount = ownerOneDepositAmount + ownerTwoDepositAmount; + expectedTakerInput = expectedTakerInput < totalDepositAmount ? expectedTakerInput : totalDepositAmount; + uint256 expectedTakerOutput = expectedTakerInput * 2; + + // The first owner's deposit is fully used before the second owner's + // deposit is used. + TestVault[] memory testVaults = new TestVault[](2); + + uint256 ownerOneRemainingDeposit = expectedTakerInput > ownerOneDepositAmount ? 0 : ownerOneDepositAmount - expectedTakerInput; + uint256 ownerOneExpectedTakerInput = ownerOneDepositAmount - ownerOneRemainingDeposit; + testVaults[0] = TestVault(ownerOne, address(iToken1), ownerOneDepositAmount, ownerOneRemainingDeposit); + + uint256 ownerTwoExpectedTakerInput = expectedTakerInput > ownerOneExpectedTakerInput ? expectedTakerInput - ownerOneExpectedTakerInput : 0; + uint256 ownerTwoRemainingDeposit = ownerTwoDepositAmount - ownerTwoExpectedTakerInput; + testVaults[1] = TestVault(ownerTwo, address(iToken1), ownerTwoDepositAmount, ownerTwoRemainingDeposit); + // testVaults[1] = TestVault(ownerOne, address(iToken0), 0, expectedTakerOutput); + + checkTakeOrderMaximumInput(testOrders, testVaults, maximumTakerInput, expectedTakerInput, expectedTakerOutput); } } From 92a67d81616b44ceac36248ff138ff43f86d4ef8 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Fri, 22 Sep 2023 19:06:00 +0400 Subject: [PATCH 08/13] fix test --- .../OrderBook.takeOrder.maximumInput.t.sol | 47 ++++++++++++------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/test/concrete/OrderBook.takeOrder.maximumInput.t.sol b/test/concrete/OrderBook.takeOrder.maximumInput.t.sol index fda980097..18f3e7bd2 100644 --- a/test/concrete/OrderBook.takeOrder.maximumInput.t.sol +++ b/test/concrete/OrderBook.takeOrder.maximumInput.t.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: CAL pragma solidity =0.8.19; +import {console2} from "forge-std/console2.sol"; import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; import {OrderBookExternalRealTest, Vm} from "test/util/abstract/OrderBookExternalRealTest.sol"; import { @@ -108,13 +109,14 @@ contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { } } - vm.prank(bob); TakeOrderConfig[] memory takeOrders = new TakeOrderConfig[](orders.length); for (uint256 i = 0; i < orders.length; i++) { takeOrders[i] = TakeOrderConfig(orders[i], 0, 0, new SignedContextV1[](0)); } TakeOrdersConfigV2 memory config = TakeOrdersConfigV2(0, maximumTakerInput, type(uint256).max, takeOrders, ""); + console2.log(expectedTakerInput, expectedTakerOutput, maximumTakerInput); + // Mock and expect the token transfers. vm.mockCall( address(iToken1), @@ -137,6 +139,7 @@ contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { expectedTakerOutput > 0 ? 1 : 0 ); + vm.prank(bob); (uint256 totalTakerInput, uint256 totalTakerOutput) = iOrderbook.takeOrders(config); assertEq(totalTakerInput, expectedTakerInput, "totalTakerInput"); assertEq(totalTakerOutput, expectedTakerOutput, "totalTakerOutput"); @@ -274,33 +277,45 @@ contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { address ownerOne = address(uint160(uint256(keccak256("ownerOne.rain.test")))); address ownerTwo = address(uint160(uint256(keccak256("ownerTwo.rain.test")))); - uint256 orderLimit = 1500; TestOrder[] memory testOrders = new TestOrder[](2); testOrders[0] = TestOrder(ownerOne, "_ _:1000 2e18;:;"); testOrders[1] = TestOrder(ownerTwo, "_ _:500 2e18;:;"); maximumTakerInput = bound(maximumTakerInput, 1, type(uint256).max); - // The expected input is the minimum of the maximum input and the order - // limit. - uint256 expectedTakerInput = maximumTakerInput < orderLimit ? maximumTakerInput : orderLimit; - - uint256 totalDepositAmount = ownerOneDepositAmount + ownerTwoDepositAmount; - expectedTakerInput = expectedTakerInput < totalDepositAmount ? expectedTakerInput : totalDepositAmount; - uint256 expectedTakerOutput = expectedTakerInput * 2; // The first owner's deposit is fully used before the second owner's // deposit is used. TestVault[] memory testVaults = new TestVault[](2); - uint256 ownerOneRemainingDeposit = expectedTakerInput > ownerOneDepositAmount ? 0 : ownerOneDepositAmount - expectedTakerInput; - uint256 ownerOneExpectedTakerInput = ownerOneDepositAmount - ownerOneRemainingDeposit; - testVaults[0] = TestVault(ownerOne, address(iToken1), ownerOneDepositAmount, ownerOneRemainingDeposit); + uint256 expectedTakerInput; + uint256 ownerOneTakerInput; + { + // Owner one can't pay more than either their deposit or 1000 set in + // the order. + uint256 ownerOneMaxPayment = ownerOneDepositAmount < 1000 ? ownerOneDepositAmount : 1000; + // taker input from owner one is either the maximum taker input if + // it is less than the max owner one payment, or the max owner one + // payment. + ownerOneTakerInput = maximumTakerInput < ownerOneMaxPayment ? maximumTakerInput : ownerOneMaxPayment; + testVaults[0] = + TestVault(ownerOne, address(iToken1), ownerOneDepositAmount, ownerOneDepositAmount - ownerOneTakerInput); + } - uint256 ownerTwoExpectedTakerInput = expectedTakerInput > ownerOneExpectedTakerInput ? expectedTakerInput - ownerOneExpectedTakerInput : 0; - uint256 ownerTwoRemainingDeposit = ownerTwoDepositAmount - ownerTwoExpectedTakerInput; - testVaults[1] = TestVault(ownerTwo, address(iToken1), ownerTwoDepositAmount, ownerTwoRemainingDeposit); - // testVaults[1] = TestVault(ownerOne, address(iToken0), 0, expectedTakerOutput); + { + // Owner two can't pay more than either their deposit or 500 set in + // the order. + uint256 ownerTwoMaxPayment = ownerTwoDepositAmount < 500 ? ownerTwoDepositAmount : 500; + // Taker input from owner two is either whatever is remaining after + // owner one's payment, or the max owner two payment. + uint256 ownerTwoTakerInput = + ownerOneTakerInput < maximumTakerInput ? maximumTakerInput - ownerOneTakerInput : 0; + ownerTwoTakerInput = ownerTwoTakerInput < ownerTwoMaxPayment ? ownerTwoTakerInput : ownerTwoMaxPayment; + testVaults[1] = + TestVault(ownerTwo, address(iToken1), ownerTwoDepositAmount, ownerTwoDepositAmount - ownerTwoTakerInput); + expectedTakerInput = ownerOneTakerInput + ownerTwoTakerInput; + } + uint256 expectedTakerOutput = expectedTakerInput * 2; checkTakeOrderMaximumInput(testOrders, testVaults, maximumTakerInput, expectedTakerInput, expectedTakerOutput); } From 714d547c458a8061fe1c3497d510fae92cdd178e Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Fri, 22 Sep 2023 19:07:28 +0400 Subject: [PATCH 09/13] lint --- test/concrete/OrderBook.takeOrder.maximumInput.t.sol | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/concrete/OrderBook.takeOrder.maximumInput.t.sol b/test/concrete/OrderBook.takeOrder.maximumInput.t.sol index 18f3e7bd2..1d56f4dff 100644 --- a/test/concrete/OrderBook.takeOrder.maximumInput.t.sol +++ b/test/concrete/OrderBook.takeOrder.maximumInput.t.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: CAL pragma solidity =0.8.19; -import {console2} from "forge-std/console2.sol"; import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; import {OrderBookExternalRealTest, Vm} from "test/util/abstract/OrderBookExternalRealTest.sol"; import { @@ -115,8 +114,6 @@ contract OrderBookTakeOrderMaximumInputTest is OrderBookExternalRealTest { } TakeOrdersConfigV2 memory config = TakeOrdersConfigV2(0, maximumTakerInput, type(uint256).max, takeOrders, ""); - console2.log(expectedTakerInput, expectedTakerOutput, maximumTakerInput); - // Mock and expect the token transfers. vm.mockCall( address(iToken1), From 193617d73391c0a5af00ec2009cf1e7e6e342080 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Sun, 1 Oct 2023 12:08:53 +0400 Subject: [PATCH 10/13] update meta hash --- 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 c5fe2ce01..f0c264acd 100644 --- a/src/concrete/OrderBook.sol +++ b/src/concrete/OrderBook.sol @@ -123,7 +123,7 @@ uint256 constant CONTEXT_VAULT_IO_BALANCE_DIFF = 4; uint256 constant CONTEXT_VAULT_IO_ROWS = 5; /// @dev Hash of the caller contract metadata for construction. -bytes32 constant CALLER_META_HASH = bytes32(0x71fe2f4f68f17dfe6ae7aba2bbd6cbfe5a2a48a93ebbc8b1f1900887b978eeee); +bytes32 constant CALLER_META_HASH = bytes32(0x1317ffd909f4ca1cd6402c7dd02501ba5965a5b8787a9627cde7b5f3f8f6f840); /// All information resulting from an order calculation that allows for vault IO /// to be calculated and applied, then the handle IO entrypoint to be dispatched. From e5a150185d6abc1bc01599c219c84c94946e88cf Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Sun, 1 Oct 2023 12:27:32 +0400 Subject: [PATCH 11/13] rebuild meta --- meta/OrderBook.rain.meta | Bin 5786 -> 5795 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/meta/OrderBook.rain.meta b/meta/OrderBook.rain.meta index 8f567572bbc714dcbd4370e28d0be7b931f36336..eccb4ad6fd855c5b909dff0b54a14fee007c0eec 100644 GIT binary patch delta 1588 zcmV-42Fv-HEu$?B{|br5bnbX`r2tt5LXizMf0oE0=b>*N9O>cbfUG5#R z8L-Vy$|OXL1b3@B489JC??)iS;Ap@|m|XB-9`F@JctvK1{5mSko~|Sqb3>3s&s*R8 zH95-95;BTC`Pb!UrAsP2zJQ2K1Gqs7_a_&et;bN#@b4LY)N6R@@69SQo(G^-5t2x_ ze~BfT(tyep-ea82$tt0%$9pMl9&I?V(}~HXhy$6^A`URtx(tjY79^nlEq!D}#u4;fe=MYohH*GdW|XXJp%q#&Rd4yGbd8ej>M1|? zC_=f4cH9+=O(^YjGgSV_}^S(`&`73N!RlV?vq2h2z%}ie65!^@D#S z%nx8V+S`J|HPL-7H;Uz6*SqC$Isr9t}w# zvRgQ<;=rIW<bU`q>U*TP3dWPr$M_CyldSXDT zZ}pK$EiFta&^uv1GrU^PlS!Dgq^Zq)_A$@hEnlu>zE1TVr zwR@6I%>=!bW43<=%f&DpJxojjn1bblRV4!)^|7Q-h@rP)P*iF$V?$L%$Ht=^WiUva zRs*#{JfH|Qh6885KgzBMe+yLHe!;cgUW%2FB)D5kzFX3c(OsYEYW*HH16+PsT{f_@ znu`Dk;v*KjE)c{Y4Se#7ce1u*D1U~e6{Q1KzjJoZ**RzTKAoLH(jAzVg9HZ&4ier4 zBw%pV-mq#ywBe|#h-w?@t$FN4Cyn^}64}946iZ2wSg!6XO~7t9e@#@{1+#@S-ps|S z5cbbUuMM;|(s-Dd&rX8&uq-A3YLv-ce%#^l*AC5WL}i0f9f(<+pKnUPZ@`=kTJiLM zEa!KUk!9ybdXSwzem#6!tc?p_qnx6g+11hm@C6gf5QWcF@$^p2X{u{@Xz6&!@oC=fBo>To&nms;=`NEJuNjU=%XzV zZA%h1WsAxVwd~Tlp6#ZW1Clmx@Ha(}`(tw}!o1bTyWNrJwRf?6$Dl)sPV0_}+mYf` z$JRzyV#<)K8tp*fva|v1mFrMx_gk3;t6%DIuFbhNOEK8Ce=GKR53GInd(PDeNthI+ z&ZapWT%&oW^)h?Q!lUvGLn71h-^)B-G+h(IZ%A=boYWbKY9|E}ss83ieX%@MkXH38oo-xS z>he;Tmwwzs_=y3QW|z=gD4Z8W-Tzx;Vd)o0x=zoSB}Z mm~#>k8RorKU8qy`elYdHhPE;-$rs%U)~if7`3Dx0~=%j delta 1579 zcmV+`2GseZEt)M2{|br5bnbX`r2tt5Igt%De-_ChXE^-k!I2(*4k(+)QVhQ0pB@kA zoB`YXq)bA@NN~5B!{FkZE2$>YMBo8kSc;}FTJmRLRzqX_ee(H>9!f$U zGpWa>9TKiLUCvNg3%G=-(G8-gkx8{lpH56BMI6Z7E@B5`uIqq^r|-agh%QJFOo{h= zO=tjqyQvFo(pnCOY(WC*-_l1$WE?@yf5}41Xc&jXWJJll7P~?#hUz8Xl+IDITs`Cm zA4Mov(T=-$_14c ztY*iJ3yxvqkerIWM``{`<&z(gmpc+YLXA)fy6G!yMW$y618|g;0m2}9mb$5rOloOi zWPoM{1C!y^a-Iyr=p&6$?z87L*IGVZ%fPG3G?kox&I3K}so<-q_U096e}0Ea12TpG zDkp2};BFsVt*eyaEe2X(QWeRAZc3{qUk=XYapo1q4e=%jObHo}vTcUZ;`)_WD>-C^*AgF(@jvn6aU%++5=*M;Q##s?|WPVAvI* zM!SCI`=jiPu)vMmFSyq0e@ii?k$7oq$#;vs(M{_!T+QDj_{Zso)$zZb)?5TY5FasX zb%7xMXyB7qY{}}9vH3G3ttcJv_B&(ejGZ%f@6*^RB;A2(IY@Aj;2_~$Kms~P?G>xW zMH`N)vZ1z~-kQf=bW)G6FOeNAMX{7*d*$lBQU&Z*(?q46Gh4Wf zBaMfNd3F-Chh;GUP`ym<^8F5vzjkP5BPtt=>OjomB7Bp>eFN%b(2A%3V_v?Kj4Vqq z(i`dgJ?i1>Vy$2J8tD{e%&wLmfG=*ya!e%UPGXG`!<+i+#>_h~L?;{r4n zpt%6;9bQn3A><1;(KaPvleVZV zHOo$&E52^3@=xlu!QUi7?vKr-2(zh=b-N?aYwKe9vOtFroz`6ywbJ5TtbRMknKozIEX813uGr^=uJ&c@e>qblBwDKi?V@x`a(&tKGM zN6vW^@fXwF9o|=28qcp!YKyegZhYs2waFjsJZI2Va+;5jEU)cY>8x1`3NNi$Q35v+ zuw*~7s23uPP;dSDiMk!h6OPo!bVNDroo-LZn|Z#je|4imEpoTYX16ykE_HFKi%UQ5 zCH%wyOS4MoEhNqhqVE4uF|?UGqA@e6BLb*by11^M;&4o`UO`iLV zqqgP`wsb#vu}QYiISB~!UMnxu dDSAJc5d2_6S(%pPi!KH0l_s402D48FR1hw981euB From 748f500ce4e76d2f08a84985d5caa404c2721ef7 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Mon, 9 Oct 2023 02:20:40 +0400 Subject: [PATCH 12/13] snapshot --- .gas-snapshot | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 60f1b3c82..3ebe957f5 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,7 +1,7 @@ -GenericPoolOrderBookV3ArbOrderTakerTest:testMinimumOutput((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,uint256,uint256) (runs: 5096, μ: 333686, ~: 333142) -GenericPoolOrderBookV3ArbOrderTakerTest:testTakeOrdersSender((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256) (runs: 5096, μ: 267873, ~: 268089) -GenericPoolOrderBookV3FlashBorrowerTest:testMinimumOutput((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,uint256,uint256) (runs: 5096, μ: 612882, ~: 610848) -GenericPoolOrderBookV3FlashBorrowerTest:testTakeOrdersSender((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256) (runs: 5096, μ: 525962, ~: 525966) +GenericPoolOrderBookV3ArbOrderTakerTest:testMinimumOutput((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,uint256,uint256) (runs: 5096, μ: 333691, ~: 333142) +GenericPoolOrderBookV3ArbOrderTakerTest:testTakeOrdersSender((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256) (runs: 5096, μ: 267876, ~: 267870) +GenericPoolOrderBookV3FlashBorrowerTest:testMinimumOutput((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,uint256,uint256) (runs: 5096, μ: 612882, ~: 610958) +GenericPoolOrderBookV3FlashBorrowerTest:testTakeOrdersSender((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256) (runs: 5096, μ: 525963, ~: 526185) 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, μ: 2771808, ~: 2761475) @@ -20,39 +20,43 @@ OrderBookAddOrderTest:testAddOrderRealThreeStackCalculate(address,((address,uint OrderBookAddOrderTest:testAddOrderRealTwoStackCalculateReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes)) (runs: 5096, μ: 715298, ~: 711943) OrderBookAddOrderTest:testAddOrderRealZeroStackCalculateReverts(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes)) (runs: 5096, μ: 181518, ~: 180295) OrderBookDepositTest:testDepositEvent(address,uint256,uint256) (runs: 5096, μ: 38710, ~: 38710) -OrderBookDepositTest:testDepositFail(address,uint256,uint256) (runs: 5096, μ: 8937393460516740788, ~: 8937393460516740786) +OrderBookDepositTest:testDepositFail(address,uint256,uint256) (runs: 5096, μ: 8937393460516740789, ~: 8937393460516740786) OrderBookDepositTest:testDepositGas00() (gas: 8176) OrderBookDepositTest:testDepositGas01() (gas: 34620) -OrderBookDepositTest:testDepositMany((address,address,uint256,uint248)[]) (runs: 5096, μ: 5113360, ~: 4801963) +OrderBookDepositTest:testDepositMany((address,address,uint256,uint248)[]) (runs: 5096, μ: 4995652, ~: 4617129) OrderBookDepositTest:testDepositOverflow(address,uint256,uint256,uint256) (runs: 5096, μ: 46645, ~: 46645) -OrderBookDepositTest:testDepositReentrancy(address,uint256,uint256,address,uint256,uint256) (runs: 5096, μ: 495312, ~: 496632) +OrderBookDepositTest:testDepositReentrancy(address,uint256,uint256,address,uint256,uint256) (runs: 5096, μ: 495335, ~: 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, μ: 494277, ~: 495964) +OrderBookDepositTest:testVaultBalanceReentrant(address,uint256,uint256,address,address,uint256) (runs: 5096, μ: 494144, ~: 495964) OrderBookRemoveOrderMockTest:testRemoveOrderAddRemoveMulti(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 7256622, ~: 7139425) 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, μ: 5070365, ~: 5046372) OrderBookRemoveOrderMockTest:testRemoveOrderDifferentOwners(address,address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 4854223, ~: 4841901) 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, μ: 10466985, ~: 10453491) OrderBookRemoveOrderMockTest:testRemoveOrderDoesNotExist(address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 386811, ~: 382063) OrderBookRemoveOrderMockTest:testRemoveOrderOnlyOwner(address,address,((address,uint8,uint256)[],(address,uint8,uint256)[],(address,bytes,uint256[]),bytes),address) (runs: 5096, μ: 2603102, ~: 2601080) -OrderBookTakeOrderMaximumInputTest:testTakeOrderMaximumInputSingleOrder(uint256) (runs: 5096, μ: 266955, ~: 266687) -OrderBookTakeOrderMaximumInputTest:testTakeOrderMaximumInputSingleOrderLessThanMaximumOutput(uint256) (runs: 5096, μ: 273355, ~: 273287) -OrderBookTakeOrderMaximumInputTest:testTakeOrderNoopZeroMaxTakerInput((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),(address,uint256[],bytes)) (runs: 5096, μ: 184242, ~: 183154) -OrderBookTakeOrderNoopTest:testTakeOrderNoopNonLiveOrderOne((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,(address,uint256[],bytes)) (runs: 5096, μ: 431694, ~: 427938) -OrderBookTakeOrderNoopTest:testTakeOrderNoopNonLiveOrderTwo((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),(address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,uint256,uint256,(address,uint256[],bytes),(address,uint256[],bytes)) (runs: 5096, μ: 851351, ~: 847183) +OrderBookTakeOrderMaximumInputTest:testTakeOrderMaximumInputMultipleOrders(uint256,uint256) (runs: 5096, μ: 485915, ~: 503260) +OrderBookTakeOrderMaximumInputTest:testTakeOrderMaximumInputMultipleOrdersMultipleOwners(uint256,uint256,uint256) (runs: 5096, μ: 534417, ~: 560581) +OrderBookTakeOrderMaximumInputTest:testTakeOrderMaximumInputSingleAnyDeposit(uint256,uint256) (runs: 5096, μ: 292768, ~: 298193) +OrderBookTakeOrderMaximumInputTest:testTakeOrderMaximumInputSingleOrderLessThanMaximumInput(uint256,uint256) (runs: 5096, μ: 278017, ~: 280317) +OrderBookTakeOrderMaximumInputTest:testTakeOrderMaximumInputSingleOrderLessThanMaximumOutput(uint256) (runs: 5096, μ: 278220, ~: 278155) +OrderBookTakeOrderMaximumInputTest:testTakeOrderMaximumInputSingleOrderUnlimitedMax(uint256) (runs: 5096, μ: 271824, ~: 271554) +OrderBookTakeOrderMaximumInputTest:testTakeOrderNoopZeroMaxTakerInput((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),(address,uint256[],bytes)) (runs: 5096, μ: 184268, ~: 183180) +OrderBookTakeOrderNoopTest:testTakeOrderNoopNonLiveOrderOne((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,(address,uint256[],bytes)) (runs: 5096, μ: 431689, ~: 427938) +OrderBookTakeOrderNoopTest:testTakeOrderNoopNonLiveOrderTwo((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),(address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,uint256,uint256,(address,uint256[],bytes),(address,uint256[],bytes)) (runs: 5096, μ: 851354, ~: 847183) OrderBookTakeOrderNoopTest:testTakeOrderNoopZeroOrders() (gas: 12403) OrderBookTakeOrderPrecisionTest:testTakeOrderPrecisionKnownBad01() (gas: 2631797) -OrderBookTakeOrderTokenMismatchDecimalsTest:testTokenMismatchInputs((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,(address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256) (runs: 5096, μ: 622036, ~: 616303) -OrderBookTakeOrderTokenMismatchDecimalsTest:testTokenMismatchOutputs((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,(address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256) (runs: 5096, μ: 622678, ~: 616922) -OrderBookTakeOrderTokenMismatchTest:testTokenMismatchInputs((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,(address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,uint256,uint256) (runs: 5096, μ: 618202, ~: 618595) -OrderBookTakeOrderTokenMismatchTest:testTokenMismatchOutputs((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,(address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,uint256,uint256) (runs: 5096, μ: 619505, ~: 619862) +OrderBookTakeOrderTokenMismatchDecimalsTest:testTokenMismatchInputs((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,(address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256) (runs: 5096, μ: 622309, ~: 616965) +OrderBookTakeOrderTokenMismatchDecimalsTest:testTokenMismatchOutputs((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,(address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256) (runs: 5096, μ: 622709, ~: 616922) +OrderBookTakeOrderTokenMismatchTest:testTokenMismatchInputs((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,(address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,uint256,uint256) (runs: 5096, μ: 618189, ~: 618644) +OrderBookTakeOrderTokenMismatchTest:testTokenMismatchOutputs((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,(address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,uint256,uint256) (runs: 5096, μ: 619539, ~: 619901) OrderBookWithdrawTest:testWithdrawEmptyVault(address,address,uint256,uint256) (runs: 5096, μ: 15251, ~: 15251) -OrderBookWithdrawTest:testWithdrawFailure(address,uint256,uint256,uint256) (runs: 5096, μ: 8937393460516719831, ~: 8937393460516738938) +OrderBookWithdrawTest:testWithdrawFailure(address,uint256,uint256,uint256) (runs: 5096, μ: 8937393460516719287, ~: 8937393460516700418) OrderBookWithdrawTest:testWithdrawFullVault(address,uint256,uint256,uint256) (runs: 5096, μ: 41257, ~: 41254) -OrderBookWithdrawTest:testWithdrawMany((bool,address,address,uint256,uint248)[]) (runs: 5096, μ: 2542859, ~: 2233360) +OrderBookWithdrawTest:testWithdrawMany((bool,address,address,uint256,uint248)[]) (runs: 5096, μ: 2543106, ~: 2233585) OrderBookWithdrawTest:testWithdrawPartialVault(address,uint256,uint256,uint256) (runs: 5096, μ: 51929, ~: 51929) -OrderBookWithdrawTest:testWithdrawReentrant(address,uint256,uint256,address,address,uint256) (runs: 5096, μ: 506161, ~: 507997) +OrderBookWithdrawTest:testWithdrawReentrant(address,uint256,uint256,address,address,uint256) (runs: 5096, μ: 506122, ~: 507997) OrderBookWithdrawTest:testWithdrawZero(address,address,uint256) (runs: 5096, μ: 12809, ~: 12809) -RouteProcessorOrderBookV3ArbOrderTakerTest:testMinimumOutput((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,uint256,uint256) (runs: 5096, μ: 333853, ~: 333304) +RouteProcessorOrderBookV3ArbOrderTakerTest:testMinimumOutput((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256,uint256,uint256) (runs: 5096, μ: 333852, ~: 333451) RouteProcessorOrderBookV3ArbOrderTakerTest:testTakeOrdersSender((address,bool,(address,address,address),(address,uint8,uint256)[],(address,uint8,uint256)[]),uint256,uint256) (runs: 5096, μ: 268039, ~: 268033) \ No newline at end of file From b10affd572aa3a27a134d5c3f28a2b56b579976b Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Sat, 28 Oct 2023 14:33:51 +0400 Subject: [PATCH 13/13] debug