Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

audit(14): arbitrum block number #280

Merged
merged 12 commits into from
Oct 18, 2024
Original file line number Diff line number Diff line change
@@ -1 +1 @@
198780
198870
2 changes: 1 addition & 1 deletion .forge-snapshots/Base-V3DutchOrder-ExecuteBatch.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
231116
231296
Original file line number Diff line number Diff line change
@@ -1 +1 @@
244626
244817
Original file line number Diff line number Diff line change
@@ -1 +1 @@
302041
302243
Original file line number Diff line number Diff line change
@@ -1 +1 @@
224642
224822
2 changes: 1 addition & 1 deletion .forge-snapshots/Base-V3DutchOrder-ExecuteSingle.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
165165
165255
Original file line number Diff line number Diff line change
@@ -1 +1 @@
150727
150817
Original file line number Diff line number Diff line change
@@ -1 +1 @@
174481
174571
2 changes: 1 addition & 1 deletion .forge-snapshots/Base-V3DutchOrder-RevertInvalidNonce.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
43785
43875
2 changes: 1 addition & 1 deletion .forge-snapshots/Base-V3DutchOrder-V3-ExclusiveFiller.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
169089
169179
2 changes: 1 addition & 1 deletion .forge-snapshots/Base-V3DutchOrder-V3-InputOverride.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
169170
169260
2 changes: 1 addition & 1 deletion .forge-snapshots/Base-V3DutchOrder-V3-OutputOverride.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
169113
169203
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecay.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
13179
13351
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayBounded.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1199
1247
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayFullyDecayed.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6677
6755
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayFullyDecayedNegative.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6365
6443
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayNegative.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1271
1309
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayNoDecay.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
5899
5975
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayNoDecayYet.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4703
4779
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayNoDecayYetNegative.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4703
4779
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayRange.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1271
1309
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-ExtendedMultiPointDutchDecay.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
88354
89192
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-MultiPointDutchDecay.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
26242
26608
31 changes: 31 additions & 0 deletions src/base/BlockNumberish.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// 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;

constructor() {
zhongeric marked this conversation as resolved.
Show resolved Hide resolved
// Set the function to use based on chainid
if (block.chainid == 42161) {
_getBlockNumberish = _getBlockNumberSyscall;
} else {
_getBlockNumberish = _getBlockNumber;
}
}

/// @dev Private function to get the block number on arbitrum
function _getBlockNumberSyscall() private view returns (uint256) {
return IArbSys(0x0000000000000000000000000000000000000064).arbBlockNumber();
zhongeric marked this conversation as resolved.
Show resolved Hide resolved
}

/// @dev Private function to get the block number using the opcode
function _getBlockNumber() private view returns (uint256) {
return block.number;
}
}
13 changes: 13 additions & 0 deletions src/interfaces/IArbSys.sol
Original file line number Diff line number Diff line change
@@ -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 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can add this as a submodule:

[submodule "lib/nitro-contracts"]
	path = lib/nitro-contracts
	url = https://github.com/OffchainLabs/nitro-contracts

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree but not sure if necessary since we also don't need the entire IArbSys interface, just this one func

/**
* @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);
}
6 changes: 4 additions & 2 deletions src/lib/ExclusivityLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
27 changes: 18 additions & 9 deletions src/lib/NonlinearDutchDecayLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol";
import {MathExt} from "./MathExt.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 {
Expand All @@ -21,11 +22,14 @@ library NonlinearDutchDecayLib {
/// @param curve The curve to search
/// @param startAmount The absolute start amount
/// @param decayStartBlock The absolute start block of the decay
/// @param minAmount The minimum amount to decay to
/// @param maxAmount The maximum amount to decay to
/// @dev Expects the relativeBlocks in curve to be strictly increasing
function decay(
NonlinearDutchDecay memory curve,
uint256 startAmount,
uint256 decayStartBlock,
uint256 blockNumberish,
uint256 minAmount,
uint256 maxAmount
) internal view returns (uint256 decayedAmount) {
Expand All @@ -35,11 +39,11 @@ library NonlinearDutchDecayLib {
}

// handle current block before decay or no decay
if (decayStartBlock >= block.number || curve.relativeAmounts.length == 0) {
if (decayStartBlock >= blockNumberish || curve.relativeAmounts.length == 0) {
return startAmount.bound(minAmount, maxAmount);
}

uint16 blockDelta = uint16(block.number - decayStartBlock);
uint16 blockDelta = uint16(blockNumberish - decayStartBlock);
(uint16 startPoint, uint16 endPoint, int256 relStartAmount, int256 relEndAmount) =
locateCurvePosition(curve, blockDelta);
// get decay of only the relative amounts
Expand Down Expand Up @@ -88,43 +92,48 @@ 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
returns (OutputToken memory result)
{
uint256 decayedOutput =
decay(output.curve, output.startAmount, decayStartBlock, output.minAmount, type(uint256).max);
uint256 decayedOutput = decay(
output.curve, output.startAmount, decayStartBlock, blockNumberish, output.minAmount, type(uint256).max
);
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
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
returns (InputToken memory result)
{
uint256 decayedInput = decay(input.curve, input.startAmount, decayStartBlock, 0, input.maxAmount);
uint256 decayedInput =
decay(input.curve, input.startAmount, decayStartBlock, blockNumberish, 0, input.maxAmount);
result = InputToken(input.token, decayedInput, input.maxAmount);
}
}
17 changes: 12 additions & 5 deletions src/reactors/V3DutchOrderReactor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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[];
Expand All @@ -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)
Expand All @@ -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
);
}

Expand Down
52 changes: 52 additions & 0 deletions test/base/BlockNumberish.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import {Test} from "forge-std/Test.sol";
import {BlockNumberish} from "../../src/base/BlockNumberish.sol";

/// 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;
}
}

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);
}
}
Loading
Loading