diff --git a/.forge-snapshots/Base-V3DutchOrder-BaseExecuteSingleWithFee.snap b/.forge-snapshots/Base-V3DutchOrder-BaseExecuteSingleWithFee.snap index 19f8a514..6db99900 100644 --- a/.forge-snapshots/Base-V3DutchOrder-BaseExecuteSingleWithFee.snap +++ b/.forge-snapshots/Base-V3DutchOrder-BaseExecuteSingleWithFee.snap @@ -1 +1 @@ -199182 \ No newline at end of file +199641 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatch.snap b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatch.snap index 2f913ad6..cbbcd95c 100644 --- a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatch.snap +++ b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatch.snap @@ -1 +1 @@ -231988 \ No newline at end of file +232940 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputs.snap b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputs.snap index c6e7704a..af110859 100644 --- a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputs.snap +++ b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputs.snap @@ -1 +1 @@ -245843 \ No newline at end of file +247008 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputsDifferentTokens.snap b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputsDifferentTokens.snap index 9576e68b..8696206c 100644 --- a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputsDifferentTokens.snap +++ b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchMultipleOutputsDifferentTokens.snap @@ -1 +1 @@ -303622 \ No newline at end of file +305002 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchNativeOutput.snap b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchNativeOutput.snap index 8a2c58e1..c9a1343f 100644 --- a/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchNativeOutput.snap +++ b/.forge-snapshots/Base-V3DutchOrder-ExecuteBatchNativeOutput.snap @@ -1 +1 @@ -225514 \ No newline at end of file +226466 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-ExecuteSingle.snap b/.forge-snapshots/Base-V3DutchOrder-ExecuteSingle.snap index 92a988c2..317fd64d 100644 --- a/.forge-snapshots/Base-V3DutchOrder-ExecuteSingle.snap +++ b/.forge-snapshots/Base-V3DutchOrder-ExecuteSingle.snap @@ -1 +1 @@ -165565 \ No newline at end of file +166023 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleNativeOutput.snap b/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleNativeOutput.snap index 33f1a96d..b6e1692c 100644 --- a/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleNativeOutput.snap +++ b/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleNativeOutput.snap @@ -1 +1 @@ -151127 \ No newline at end of file +151585 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleValidation.snap b/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleValidation.snap index 2d1d814a..ec59532e 100644 --- a/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleValidation.snap +++ b/.forge-snapshots/Base-V3DutchOrder-ExecuteSingleValidation.snap @@ -1 +1 @@ -174876 \ No newline at end of file +175334 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-RevertInvalidNonce.snap b/.forge-snapshots/Base-V3DutchOrder-RevertInvalidNonce.snap index 28473c4c..e7bbbf04 100644 --- a/.forge-snapshots/Base-V3DutchOrder-RevertInvalidNonce.snap +++ b/.forge-snapshots/Base-V3DutchOrder-RevertInvalidNonce.snap @@ -1 +1 @@ -44201 \ No newline at end of file +44659 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-V3-ExclusiveFiller.snap b/.forge-snapshots/Base-V3DutchOrder-V3-ExclusiveFiller.snap index 9ee997dc..40ed9262 100644 --- a/.forge-snapshots/Base-V3DutchOrder-V3-ExclusiveFiller.snap +++ b/.forge-snapshots/Base-V3DutchOrder-V3-ExclusiveFiller.snap @@ -1 +1 @@ -169500 \ No newline at end of file +169958 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-V3-InputOverride.snap b/.forge-snapshots/Base-V3DutchOrder-V3-InputOverride.snap index 230c9851..215fd8d5 100644 --- a/.forge-snapshots/Base-V3DutchOrder-V3-InputOverride.snap +++ b/.forge-snapshots/Base-V3DutchOrder-V3-InputOverride.snap @@ -1 +1 @@ -169581 \ No newline at end of file +170039 \ No newline at end of file diff --git a/.forge-snapshots/Base-V3DutchOrder-V3-OutputOverride.snap b/.forge-snapshots/Base-V3DutchOrder-V3-OutputOverride.snap index 73c52189..e0d596df 100644 --- a/.forge-snapshots/Base-V3DutchOrder-V3-OutputOverride.snap +++ b/.forge-snapshots/Base-V3DutchOrder-V3-OutputOverride.snap @@ -1 +1 @@ -169524 \ No newline at end of file +169982 \ No newline at end of file diff --git a/.forge-snapshots/V3-DutchDecay.snap b/.forge-snapshots/V3-DutchDecay.snap index f15b865b..14ce921c 100644 --- a/.forge-snapshots/V3-DutchDecay.snap +++ b/.forge-snapshots/V3-DutchDecay.snap @@ -1 +1 @@ -17903 \ No newline at end of file +19019 \ No newline at end of file diff --git a/.forge-snapshots/V3-DutchDecayBounded.snap b/.forge-snapshots/V3-DutchDecayBounded.snap index d239a2b0..77d6fc01 100644 --- a/.forge-snapshots/V3-DutchDecayBounded.snap +++ b/.forge-snapshots/V3-DutchDecayBounded.snap @@ -1 +1 @@ -3389 \ No newline at end of file +3607 \ No newline at end of file diff --git a/.forge-snapshots/V3-DutchDecayFullyDecayed.snap b/.forge-snapshots/V3-DutchDecayFullyDecayed.snap index b9bae990..f05530e9 100644 --- a/.forge-snapshots/V3-DutchDecayFullyDecayed.snap +++ b/.forge-snapshots/V3-DutchDecayFullyDecayed.snap @@ -1 +1 @@ -9958 \ No newline at end of file +10514 \ No newline at end of file diff --git a/.forge-snapshots/V3-DutchDecayFullyDecayedNegative.snap b/.forge-snapshots/V3-DutchDecayFullyDecayedNegative.snap index 5b4e69b0..6013b888 100644 --- a/.forge-snapshots/V3-DutchDecayFullyDecayedNegative.snap +++ b/.forge-snapshots/V3-DutchDecayFullyDecayedNegative.snap @@ -1 +1 @@ -9672 \ No newline at end of file +10229 \ No newline at end of file diff --git a/.forge-snapshots/V3-DutchDecayNegative.snap b/.forge-snapshots/V3-DutchDecayNegative.snap index 9cbd0e0f..ba2e90f3 100644 --- a/.forge-snapshots/V3-DutchDecayNegative.snap +++ b/.forge-snapshots/V3-DutchDecayNegative.snap @@ -1 +1 @@ -3861 \ No newline at end of file +4079 \ No newline at end of file diff --git a/.forge-snapshots/V3-DutchDecayNoDecay.snap b/.forge-snapshots/V3-DutchDecayNoDecay.snap index 49be3686..450d874e 100644 --- a/.forge-snapshots/V3-DutchDecayNoDecay.snap +++ b/.forge-snapshots/V3-DutchDecayNoDecay.snap @@ -1 +1 @@ -9977 \ No newline at end of file +9503 \ No newline at end of file diff --git a/.forge-snapshots/V3-DutchDecayNoDecayYet.snap b/.forge-snapshots/V3-DutchDecayNoDecayYet.snap index 6ee71bda..a343f520 100644 --- a/.forge-snapshots/V3-DutchDecayNoDecayYet.snap +++ b/.forge-snapshots/V3-DutchDecayNoDecayYet.snap @@ -1 +1 @@ -7890 \ No newline at end of file +8326 \ No newline at end of file diff --git a/.forge-snapshots/V3-DutchDecayNoDecayYetNegative.snap b/.forge-snapshots/V3-DutchDecayNoDecayYetNegative.snap index 44439158..997cd828 100644 --- a/.forge-snapshots/V3-DutchDecayNoDecayYetNegative.snap +++ b/.forge-snapshots/V3-DutchDecayNoDecayYetNegative.snap @@ -1 +1 @@ -7864 \ No newline at end of file +8300 \ No newline at end of file diff --git a/.forge-snapshots/V3-DutchDecayRange.snap b/.forge-snapshots/V3-DutchDecayRange.snap index 9cbd0e0f..ba2e90f3 100644 --- a/.forge-snapshots/V3-DutchDecayRange.snap +++ b/.forge-snapshots/V3-DutchDecayRange.snap @@ -1 +1 @@ -3861 \ No newline at end of file +4079 \ No newline at end of file diff --git a/.forge-snapshots/V3-ExtendedMultiPointDutchDecay.snap b/.forge-snapshots/V3-ExtendedMultiPointDutchDecay.snap index f660d6fa..9340c418 100644 --- a/.forge-snapshots/V3-ExtendedMultiPointDutchDecay.snap +++ b/.forge-snapshots/V3-ExtendedMultiPointDutchDecay.snap @@ -1 +1 @@ -103346 \ No newline at end of file +109317 \ No newline at end of file diff --git a/.forge-snapshots/V3-MultiPointDutchDecay.snap b/.forge-snapshots/V3-MultiPointDutchDecay.snap index 9dce265a..3345a318 100644 --- a/.forge-snapshots/V3-MultiPointDutchDecay.snap +++ b/.forge-snapshots/V3-MultiPointDutchDecay.snap @@ -1 +1 @@ -34003 \ No newline at end of file +36476 \ No newline at end of file diff --git a/src/base/BlockNumberish.sol b/src/base/BlockNumberish.sol new file mode 100644 index 00000000..6a6f9e70 --- /dev/null +++ b/src/base/BlockNumberish.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IArbSys} from "../interfaces/IArbSys.sol"; + +/// @title BlockNumberish +/// A helper contract to get the current block number on different chains +/// inspired by https://github.com/ProjectOpenSea/tstorish/blob/main/src/Tstorish.sol +contract BlockNumberish { + // Declare an immutable function type variable for the _getBlockNumberish function + function() view returns (uint256) internal immutable _getBlockNumberish; + + uint256 private constant ARB_CHAIN_ID = 42161; + address private constant ARB_SYS_ADDRESS = 0x0000000000000000000000000000000000000064; + + constructor() { + // Set the function to use based on chainid + if (block.chainid == ARB_CHAIN_ID) { + _getBlockNumberish = _getBlockNumberSyscall; + } else { + _getBlockNumberish = _getBlockNumber; + } + } + + /// @dev Private function to get the block number on arbitrum + function _getBlockNumberSyscall() private view returns (uint256) { + return IArbSys(ARB_SYS_ADDRESS).arbBlockNumber(); + } + + /// @dev Private function to get the block number using the opcode + function _getBlockNumber() private view returns (uint256) { + return block.number; + } +} diff --git a/src/interfaces/IArbSys.sol b/src/interfaces/IArbSys.sol new file mode 100644 index 00000000..c96aaa45 --- /dev/null +++ b/src/interfaces/IArbSys.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +/** + * @notice Minimal interface for interacting with Arbitrum system contracts + */ +interface IArbSys { + /** + * @notice Get Arbitrum block number (distinct from L1 block number; Arbitrum genesis block has block number 0) + * @return block number as int + */ + function arbBlockNumber() external view returns (uint256); +} diff --git a/src/lib/ExclusivityLib.sol b/src/lib/ExclusivityLib.sol index 81eb6375..f27e8cc6 100644 --- a/src/lib/ExclusivityLib.sol +++ b/src/lib/ExclusivityLib.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.0; import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol"; import {ResolvedOrder, OutputToken} from "../base/ReactorStructs.sol"; +import {IArbSys} from "../interfaces/IArbSys.sol"; /// @title ExclusiveOverride /// @dev This library handles order exclusivity @@ -40,9 +41,10 @@ library ExclusivityLib { ResolvedOrder memory order, address exclusive, uint256 exclusivityEnd, - uint256 exclusivityOverrideBps + uint256 exclusivityOverrideBps, + uint256 blockNumberish ) internal view { - _handleExclusiveOverride(order, exclusive, exclusivityEnd, exclusivityOverrideBps, block.number); + _handleExclusiveOverride(order, exclusive, exclusivityEnd, exclusivityOverrideBps, blockNumberish); } /// @notice Applies exclusivity override to the resolved order if necessary diff --git a/src/lib/NonlinearDutchDecayLib.sol b/src/lib/NonlinearDutchDecayLib.sol index 6aaaa62e..4b75a888 100644 --- a/src/lib/NonlinearDutchDecayLib.sol +++ b/src/lib/NonlinearDutchDecayLib.sol @@ -8,6 +8,7 @@ import {MathExt} from "./MathExt.sol"; import {Math} from "openzeppelin-contracts/utils/math/Math.sol"; import {Uint16ArrayLibrary, Uint16Array, fromUnderlying} from "../types/Uint16Array.sol"; import {DutchDecayLib} from "./DutchDecayLib.sol"; +import {IArbSys} from "../interfaces/IArbSys.sol"; /// @notice helpers for handling non-linear dutch order objects library NonlinearDutchDecayLib { @@ -18,41 +19,47 @@ library NonlinearDutchDecayLib { /// @notice thrown when the decay curve is invalid error InvalidDecayCurve(); - /// @notice Calculates the decayed amount based on the current block and the defined curve + /// @notice Struct to hold decay parameters /// @param curve The nonlinear decay curve definition /// @param startAmount The initial amount at the start of the decay /// @param decayStartBlock The absolute block number when the decay begins + /// @param blockNumberish The current block number /// @param minAmount The minimum amount to decay to /// @param maxAmount The maximum amount to decay to /// @param decayFunc The decay function to use /// @dev Expects the relativeBlocks in curve to be strictly increasing + struct DecayParams { + NonlinearDutchDecay curve; + uint256 startAmount; + uint256 decayStartBlock; + uint256 blockNumberish; + uint256 minAmount; + uint256 maxAmount; + function(uint256, uint256, uint256, int256, int256) internal pure returns (int256) decayFunc; + } + + /// @notice Calculates the decayed amount based on the current block and the defined curve + /// @param params The decay parameters /// @return decayedAmount The decayed amount - function decay( - NonlinearDutchDecay memory curve, - uint256 startAmount, - uint256 decayStartBlock, - uint256 minAmount, - uint256 maxAmount, - function(uint256, uint256, uint256, int256, int256) internal pure returns (int256) decayFunc - ) internal view returns (uint256 decayedAmount) { + function decay(DecayParams memory params) internal pure returns (uint256 decayedAmount) { // mismatch of relativeAmounts and relativeBlocks - if (curve.relativeAmounts.length > 16) { + if (params.curve.relativeAmounts.length > 16) { revert InvalidDecayCurve(); } // handle current block before decay or no decay - if (decayStartBlock >= block.number || curve.relativeAmounts.length == 0) { - return startAmount.bound(minAmount, maxAmount); + if (params.decayStartBlock >= params.blockNumberish || params.curve.relativeAmounts.length == 0) { + return params.startAmount.bound(params.minAmount, params.maxAmount); } // If the blockDelta is larger than type(uint16).max, a downcast overflow will occur // We prevent this by capping the blockDelta to type(uint16).max to express a full decay - uint16 blockDelta = uint16(Math.min(block.number - decayStartBlock, type(uint16).max)); + uint16 blockDelta = uint16(Math.min(params.blockNumberish - params.decayStartBlock, type(uint16).max)); (uint16 startPoint, uint16 endPoint, int256 relStartAmount, int256 relEndAmount) = - locateCurvePosition(curve, blockDelta); + locateCurvePosition(params.curve, blockDelta); // get decay of only the relative amounts - int256 curveDelta = decayFunc(startPoint, endPoint, blockDelta, relStartAmount, relEndAmount); + int256 curveDelta = params.decayFunc(startPoint, endPoint, blockDelta, relStartAmount, relEndAmount); - return startAmount.boundedSub(curveDelta, minAmount, maxAmount); + return params.startAmount.boundedSub(curveDelta, params.minAmount, params.maxAmount); } /// @notice Locates the current position on the decay curve based on the elapsed blocks @@ -98,45 +105,63 @@ library NonlinearDutchDecayLib { /// @notice returns a decayed output using the given dutch spec and blocks /// @param output The output to decay /// @param decayStartBlock The block to start decaying + /// @param blockNumberish The block number to decay to /// @return result a decayed output - function decay(V3DutchOutput memory output, uint256 decayStartBlock) + function decay(V3DutchOutput memory output, uint256 decayStartBlock, uint256 blockNumberish) internal - view + pure returns (OutputToken memory result) { - uint256 decayedOutput = decay( - output.curve, output.startAmount, decayStartBlock, output.minAmount, type(uint256).max, v3LinearOutputDecay - ); + DecayParams memory params = DecayParams({ + curve: output.curve, + startAmount: output.startAmount, + decayStartBlock: decayStartBlock, + blockNumberish: blockNumberish, + minAmount: output.minAmount, + maxAmount: type(uint256).max, + decayFunc: v3LinearOutputDecay + }); + uint256 decayedOutput = decay(params); result = OutputToken(output.token, decayedOutput, output.recipient); } /// @notice returns a decayed output array using the given dutch spec and blocks /// @param outputs The output array to decay /// @param decayStartBlock The block to start decaying + /// @param blockNumberish The block number to decay to /// @return result a decayed output array - function decay(V3DutchOutput[] memory outputs, uint256 decayStartBlock) + function decay(V3DutchOutput[] memory outputs, uint256 decayStartBlock, uint256 blockNumberish) internal - view + pure returns (OutputToken[] memory result) { uint256 outputLength = outputs.length; result = new OutputToken[](outputLength); for (uint256 i = 0; i < outputLength; i++) { - result[i] = decay(outputs[i], decayStartBlock); + result[i] = decay(outputs[i], decayStartBlock, blockNumberish); } } /// @notice returns a decayed input using the given dutch spec and times /// @param input The input to decay /// @param decayStartBlock The block to start decaying + /// @param blockNumberish The block number to decay to /// @return result a decayed input - function decay(V3DutchInput memory input, uint256 decayStartBlock) + function decay(V3DutchInput memory input, uint256 decayStartBlock, uint256 blockNumberish) internal - view + pure returns (InputToken memory result) { - uint256 decayedInput = - decay(input.curve, input.startAmount, decayStartBlock, 0, input.maxAmount, v3LinearInputDecay); + DecayParams memory params = DecayParams({ + curve: input.curve, + startAmount: input.startAmount, + decayStartBlock: decayStartBlock, + blockNumberish: blockNumberish, + minAmount: 0, + maxAmount: input.maxAmount, + decayFunc: v3LinearInputDecay + }); + uint256 decayedInput = decay(params); result = InputToken(input.token, decayedInput, input.maxAmount); } diff --git a/src/reactors/V3DutchOrderReactor.sol b/src/reactors/V3DutchOrderReactor.sol index 95faae6a..a61c32a7 100644 --- a/src/reactors/V3DutchOrderReactor.sol +++ b/src/reactors/V3DutchOrderReactor.sol @@ -8,6 +8,7 @@ import {ExclusivityLib} from "../lib/ExclusivityLib.sol"; import {NonlinearDutchDecayLib} from "../lib/NonlinearDutchDecayLib.sol"; import {V3DutchOrderLib, V3DutchOrder, CosignerData, V3DutchOutput, V3DutchInput} from "../lib/V3DutchOrderLib.sol"; import {SignedOrder, ResolvedOrder} from "../base/ReactorStructs.sol"; +import {BlockNumberish} from "../base/BlockNumberish.sol"; import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol"; import {MathExt} from "../lib/MathExt.sol"; import {Math} from "openzeppelin-contracts/utils/math/Math.sol"; @@ -22,7 +23,7 @@ import {CosignerLib} from "../lib/CosignerLib.sol"; /// - For each outputAmount: /// - If amount is 0, then use baseOutput /// - If amount is nonzero, then ensure it is greater than specified baseOutput and replace startAmount -contract V3DutchOrderReactor is BaseReactor { +contract V3DutchOrderReactor is BaseReactor, BlockNumberish { using Permit2Lib for ResolvedOrder; using V3DutchOrderLib for V3DutchOrder; using NonlinearDutchDecayLib for V3DutchOutput[]; @@ -40,7 +41,10 @@ contract V3DutchOrderReactor is BaseReactor { /// @notice thrown when an order's cosigner output is less than the specified error InvalidCosignerOutput(); - constructor(IPermit2 _permit2, address _protocolFeeOwner) BaseReactor(_permit2, _protocolFeeOwner) {} + constructor(IPermit2 _permit2, address _protocolFeeOwner) + BaseReactor(_permit2, _protocolFeeOwner) + BlockNumberish() + {} /// @inheritdoc BaseReactor function _resolve(SignedOrder calldata signedOrder) @@ -58,17 +62,20 @@ contract V3DutchOrderReactor is BaseReactor { _updateWithCosignerAmounts(order); _updateWithGasAdjustment(order); + uint256 blockNumberish = _getBlockNumberish(); + resolvedOrder = ResolvedOrder({ info: order.info, - input: order.baseInput.decay(order.cosignerData.decayStartBlock), - outputs: order.baseOutputs.decay(order.cosignerData.decayStartBlock), + input: order.baseInput.decay(order.cosignerData.decayStartBlock, blockNumberish), + outputs: order.baseOutputs.decay(order.cosignerData.decayStartBlock, blockNumberish), sig: signedOrder.sig, hash: orderHash }); resolvedOrder.handleExclusiveOverrideBlock( order.cosignerData.exclusiveFiller, order.cosignerData.decayStartBlock, - order.cosignerData.exclusivityOverrideBps + order.cosignerData.exclusivityOverrideBps, + blockNumberish ); } diff --git a/test/base/BlockNumberish.t.sol b/test/base/BlockNumberish.t.sol new file mode 100644 index 00000000..24eaca0c --- /dev/null +++ b/test/base/BlockNumberish.t.sol @@ -0,0 +1,35 @@ +import {Test} from "forge-std/Test.sol"; +import {MockArbSys} from "../util/mock/MockArbSys.sol"; +import {BlockNumberish} from "../../src/base/BlockNumberish.sol"; + +contract MockBlockNumberish is BlockNumberish { + function getBlockNumberish() external view returns (uint256) { + return _getBlockNumberish(); + } +} + +contract BlockNumberishTest is Test { + MockArbSys arbSys; + MockBlockNumberish blockNumberish; + + function setUp() public { + // etch MockArbSys to address(100) + vm.etch(address(100), address(new MockArbSys()).code); + arbSys = MockArbSys(address(100)); + } + + function test_getBlockNumber() public { + blockNumberish = new MockBlockNumberish(); + + vm.roll(100); + assertEq(blockNumberish.getBlockNumberish(), 100); + } + + function test_getBlockNumberSyscall() public { + vm.chainId(42161); + blockNumberish = new MockBlockNumberish(); + + arbSys.setBlockNumber(1); + assertEq(blockNumberish.getBlockNumberish(), 1); + } +} diff --git a/test/lib/ExclusivityLib.t.sol b/test/lib/ExclusivityLib.t.sol index c6cc0e18..bf3efd5a 100644 --- a/test/lib/ExclusivityLib.t.sol +++ b/test/lib/ExclusivityLib.t.sol @@ -18,11 +18,14 @@ contract ExclusivityLibTest is Test { address token2; address recipient; + uint256 blockNumberish; + function setUp() public { exclusivity = new MockExclusivityLib(); token1 = makeAddr("token1"); token2 = makeAddr("token2"); recipient = makeAddr("recipient"); + blockNumberish = block.number; } function testTimestampExclusivity(address exclusive) public { @@ -68,7 +71,7 @@ contract ExclusivityLibTest is Test { order.outputs = OutputsBuilder.single(token1, amount, recipient); vm.prank(exclusive); ResolvedOrder memory handled = - exclusivity.handleExclusiveOverrideBlock(order, exclusive, block.number + 1, overrideAmt); + exclusivity.handleExclusiveOverrideBlock(order, exclusive, block.number + 1, overrideAmt, blockNumberish); // no changes assertEq(handled.outputs[0].amount, amount); assertEq(handled.outputs[0].recipient, recipient); @@ -96,7 +99,7 @@ contract ExclusivityLibTest is Test { order.outputs = OutputsBuilder.single(token1, amount, recipient); vm.prank(caller); ResolvedOrder memory handled = - exclusivity.handleExclusiveOverrideBlock(order, address(0), block.number + 1, overrideAmt); + exclusivity.handleExclusiveOverrideBlock(order, address(0), block.number + 1, overrideAmt, blockNumberish); // no changes assertEq(handled.outputs[0].amount, amount); assertEq(handled.outputs[0].recipient, recipient); @@ -134,7 +137,8 @@ contract ExclusivityLibTest is Test { order.outputs = OutputsBuilder.single(token1, amount, recipient); vm.roll(100); vm.prank(caller); - ResolvedOrder memory handled = exclusivity.handleExclusiveOverrideBlock(order, address(0), 99, overrideAmt); + ResolvedOrder memory handled = + exclusivity.handleExclusiveOverrideBlock(order, address(0), 99, overrideAmt, blockNumberish); // no changes assertEq(handled.outputs[0].amount, amount); assertEq(handled.outputs[0].recipient, recipient); @@ -157,7 +161,7 @@ contract ExclusivityLibTest is Test { order.outputs = OutputsBuilder.single(token1, amount, recipient); vm.prank(caller); vm.expectRevert(ExclusivityLib.NoExclusiveOverride.selector); - exclusivity.handleExclusiveOverrideBlock(order, exclusive, block.number + 1, 0); + exclusivity.handleExclusiveOverrideBlock(order, exclusive, block.number + 1, 0, blockNumberish); } function testHandleExclusiveOverrideTimestamp() public { @@ -178,7 +182,7 @@ contract ExclusivityLibTest is Test { uint256 overrideAmt = 3000; vm.prank(address(2)); ResolvedOrder memory handled = - exclusivity.handleExclusiveOverrideBlock(order, address(1), block.number + 1, overrideAmt); + exclusivity.handleExclusiveOverrideBlock(order, address(1), block.number + 1, overrideAmt, blockNumberish); // assert overrideAmt applied assertEq(handled.outputs[0].amount, 1.3 ether); assertEq(handled.outputs[0].recipient, recipient); @@ -202,7 +206,7 @@ contract ExclusivityLibTest is Test { uint256 overrideAmt = 3000; vm.prank(address(2)); ResolvedOrder memory handled = - exclusivity.handleExclusiveOverrideBlock(order, address(1), block.number + 1, overrideAmt); + exclusivity.handleExclusiveOverrideBlock(order, address(1), block.number + 1, overrideAmt, blockNumberish); // assert overrideAmt applied assertEq(handled.outputs[0].amount, 1.3 ether + 2); assertEq(handled.outputs[0].recipient, recipient); @@ -240,7 +244,7 @@ contract ExclusivityLibTest is Test { order.outputs = OutputsBuilder.single(token1, amount, recipient); vm.prank(caller); ResolvedOrder memory handled = - exclusivity.handleExclusiveOverrideBlock(order, exclusive, block.number + 1, overrideAmt); + exclusivity.handleExclusiveOverrideBlock(order, exclusive, block.number + 1, overrideAmt, blockNumberish); // assert overrideAmt applied assertEq(handled.outputs[0].amount, uint256(amount).mulDivUp(10000 + overrideAmt, 10000)); assertEq(handled.outputs[0].recipient, recipient); @@ -290,7 +294,7 @@ contract ExclusivityLibTest is Test { order.outputs = OutputsBuilder.multiple(token1, amounts, recipient); vm.prank(caller); ResolvedOrder memory handled = - exclusivity.handleExclusiveOverrideBlock(order, exclusive, block.number + 1, overrideAmt); + exclusivity.handleExclusiveOverrideBlock(order, exclusive, block.number + 1, overrideAmt, blockNumberish); // assert overrideAmt applied for (uint256 i = 0; i < amounts.length; i++) { assertEq(handled.outputs[i].amount, uint256(amounts[i]).mulDivUp(10000 + overrideAmt, 10000)); diff --git a/test/lib/NonLinearDutchDecayLib.t.sol b/test/lib/NonLinearDutchDecayLib.t.sol index a148bd41..391b8838 100644 --- a/test/lib/NonLinearDutchDecayLib.t.sol +++ b/test/lib/NonLinearDutchDecayLib.t.sol @@ -11,10 +11,11 @@ import {Uint16Array, toUint256} from "../../src/types/Uint16Array.sol"; import {Math} from "openzeppelin-contracts/utils/math/Math.sol"; import {ArrayBuilder} from "../util/ArrayBuilder.sol"; import {CurveBuilder} from "../util/CurveBuilder.sol"; +import {BlockNumberish} from "../../src/base/BlockNumberish.sol"; import {MockERC20} from "../util/mock/MockERC20.sol"; import {OutputToken, InputToken} from "../../src/base/ReactorStructs.sol"; -contract NonlinearDutchDecayLibTest is Test, GasSnapshot { +contract NonlinearDutchDecayLibTest is Test, GasSnapshot, BlockNumberish { MockERC20 tokenIn; MockERC20 tokenOut; @@ -30,7 +31,7 @@ contract NonlinearDutchDecayLibTest is Test, GasSnapshot { uint256 maxAmount ) internal view returns (uint256 decayedAmount) { V3DutchInput memory input = V3DutchInput(tokenIn, startAmount, curve, maxAmount, 0); - return NonlinearDutchDecayLib.decay(input, decayStartBlock).amount; + return NonlinearDutchDecayLib.decay(input, decayStartBlock, _getBlockNumberish()).amount; } function decayOutput( @@ -40,7 +41,7 @@ contract NonlinearDutchDecayLibTest is Test, GasSnapshot { uint256 minAmount ) internal view returns (uint256 decayedAmount) { V3DutchOutput memory output = V3DutchOutput(address(tokenOut), startAmount, curve, address(0), minAmount, 0); - return NonlinearDutchDecayLib.decay(output, decayStartBlock).amount; + return NonlinearDutchDecayLib.decay(output, decayStartBlock, _getBlockNumberish()).amount; } function testLocateCurvePositionSingle() public { diff --git a/test/util/mock/MockArbSys.sol b/test/util/mock/MockArbSys.sol new file mode 100644 index 00000000..1a9952a5 --- /dev/null +++ b/test/util/mock/MockArbSys.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +/// Mock Arbitrum syscall contract +contract MockArbSys { + uint256 _blockNumber; + + /// @dev helper function to set the block number + function setBlockNumber(uint256 blockNumber) external { + _blockNumber = blockNumber; + } + + /// @notice returns the block number + function arbBlockNumber() external view returns (uint256) { + return _blockNumber; + } +} diff --git a/test/util/mock/MockExclusivityLib.sol b/test/util/mock/MockExclusivityLib.sol index ee6f860d..20e23208 100644 --- a/test/util/mock/MockExclusivityLib.sol +++ b/test/util/mock/MockExclusivityLib.sol @@ -19,9 +19,12 @@ contract MockExclusivityLib { ResolvedOrder memory order, address exclusive, uint256 exclusivityEnd, - uint256 exclusivityOverrideBps + uint256 exclusivityOverrideBps, + uint256 blockNumberish ) external view returns (ResolvedOrder memory) { - ExclusivityLib.handleExclusiveOverrideBlock(order, exclusive, exclusivityEnd, exclusivityOverrideBps); + ExclusivityLib.handleExclusiveOverrideBlock( + order, exclusive, exclusivityEnd, exclusivityOverrideBps, blockNumberish + ); return order; }