Skip to content

Commit

Permalink
Merge branch 'main' into audit-v3-14
Browse files Browse the repository at this point in the history
  • Loading branch information
zhongeric committed Oct 16, 2024
2 parents 8d03b1b + f370eab commit e6e01eb
Show file tree
Hide file tree
Showing 32 changed files with 155 additions and 50 deletions.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
198870
199230
2 changes: 1 addition & 1 deletion .forge-snapshots/Base-V3DutchOrder-ExecuteBatch.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
231296
232079
Original file line number Diff line number Diff line change
@@ -1 +1 @@
244817
245939
Original file line number Diff line number Diff line change
@@ -1 +1 @@
302243
303724
Original file line number Diff line number Diff line change
@@ -1 +1 @@
224822
225606
2 changes: 1 addition & 1 deletion .forge-snapshots/Base-V3DutchOrder-ExecuteSingle.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
165255
165613
Original file line number Diff line number Diff line change
@@ -1 +1 @@
150817
151175
Original file line number Diff line number Diff line change
@@ -1 +1 @@
174571
174924
2 changes: 1 addition & 1 deletion .forge-snapshots/Base-V3DutchOrder-RevertInvalidNonce.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
43875
44248
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 @@
169179
169548
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 @@
169260
169629
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 @@
169203
169572
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecay.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
13351
13543
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayBounded.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1247
1244
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayFullyDecayed.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6755
6857
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayFullyDecayedNegative.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6443
6545
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayNegative.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1309
1303
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayNoDecayYet.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4779
4773
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayNoDecayYetNegative.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4779
4773
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayRange.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1309
1303
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-ExtendedMultiPointDutchDecay.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
89192
89288
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-LocateCurvePositionMulti.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20492
20330
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-LocateCurvePositionSingle.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6860
6830
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-MultiPointDutchDecay.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
26608
26905
7 changes: 5 additions & 2 deletions src/base/BlockNumberish.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ 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 == 42161) {
if (block.chainid == ARB_CHAIN_ID) {
_getBlockNumberish = _getBlockNumberSyscall;
} else {
_getBlockNumberish = _getBlockNumber;
Expand All @@ -21,7 +24,7 @@ contract BlockNumberish {

/// @dev Private function to get the block number on arbitrum
function _getBlockNumberSyscall() private view returns (uint256) {
return IArbSys(0x0000000000000000000000000000000000000064).arbBlockNumber();
return IArbSys(ARB_SYS_ADDRESS).arbBlockNumber();
}

/// @dev Private function to get the block number using the opcode
Expand Down
2 changes: 2 additions & 0 deletions src/lib/MathExt.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ library MathExt {
/// @param min The minimum bound for the result.
/// @param max The maximum bound for the result.
/// @return r The result of the bounded addition.
/// @dev This function reverts when `b == type(int256).min` due to integer overflow.
function boundedAdd(uint256 a, int256 b, uint256 min, uint256 max) internal pure returns (uint256 r) {
r = boundedSub(a, 0 - b, min, max);
}
Expand All @@ -33,6 +34,7 @@ library MathExt {
/// @param min The minimum bound for the result.
/// @param max The maximum bound for the result.
/// @return r The result of the bounded subtraction.
/// @dev This function reverts when `b == type(int256).min` due to integer overflow.
function boundedSub(uint256 a, int256 b, uint256 min, uint256 max) internal pure returns (uint256 r) {
if (b < 0) {
// If b is negative, add its absolute value to a
Expand Down
33 changes: 20 additions & 13 deletions src/lib/NonlinearDutchDecayLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {OutputToken, InputToken} from "../base/ReactorStructs.sol";
import {V3DutchOutput, V3DutchInput, NonlinearDutchDecay} from "../lib/V3DutchOrderLib.sol";
import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol";
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";
Expand All @@ -18,13 +19,15 @@ library NonlinearDutchDecayLib {
/// @notice thrown when the decay curve is invalid
error InvalidDecayCurve();

/// @notice locates the current position on the curve and calculates the decay
/// @param curve The curve to search
/// @param startAmount The absolute start amount
/// @param decayStartBlock The absolute start block of the decay
/// @notice Calculates the decayed amount based on the current block and the defined curve
/// @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
/// @dev Expects the relativeBlocks in curve to be strictly increasing
/// @return decayedAmount The amount after applying the decay, bounded by minAmount and maxAmount
function decay(
NonlinearDutchDecay memory curve,
uint256 startAmount,
Expand All @@ -42,8 +45,9 @@ library NonlinearDutchDecayLib {
if (decayStartBlock >= blockNumberish || curve.relativeAmounts.length == 0) {
return startAmount.bound(minAmount, maxAmount);
}

uint16 blockDelta = uint16(blockNumberish - decayStartBlock);
// 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(blockNumberish - decayStartBlock, type(uint16).max));
(uint16 startPoint, uint16 endPoint, int256 relStartAmount, int256 relEndAmount) =
locateCurvePosition(curve, blockDelta);
// get decay of only the relative amounts
Expand All @@ -52,13 +56,16 @@ library NonlinearDutchDecayLib {
return startAmount.boundedSub(curveDelta, minAmount, maxAmount);
}

/// @notice Locates the current position on the curve
/// @param curve The curve to search
/// @param currentRelativeBlock The current relative position
/// @return startPoint The relative block before the current position
/// @return endPoint The relative block after the current position
/// @return startAmount The relative amount before the current position
/// @return endAmount The relative amount after the current position
/// @notice Locates the current position on the decay curve based on the elapsed blocks
/// @param curve The nonlinear decay curve definition
/// @param currentRelativeBlock The number of blocks elapsed since decayStartBlock
/// @return startPoint The relative block number of the previous curve point
/// @return endPoint The relative block number of the next curve point
/// @return startAmount The relative change from initial amount at the previous curve point
/// @return endAmount The relative change from initial amount at the next curve point
/// @dev The returned amounts are changes relative to the initial startAmount, not absolute values
/// @dev If currentRelativeBlock is before the first curve point, startPoint and startAmount will be 0
/// @dev If currentRelativeBlock is after the last curve point, both points will be the last curve point
function locateCurvePosition(NonlinearDutchDecay memory curve, uint16 currentRelativeBlock)
internal
pure
Expand Down
8 changes: 5 additions & 3 deletions src/lib/V3DutchOrderLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ library V3DutchOrderLib {
"uint256 maxAmount,",
"uint256 adjustmentPerGweiBaseFee)"
);
bytes32 internal constant V3_DUTCH_INPUT_TYPE_HASH = keccak256(V3_DUTCH_INPUT_TYPE);
bytes32 internal constant V3_DUTCH_INPUT_TYPE_HASH =
keccak256(abi.encodePacked(V3_DUTCH_INPUT_TYPE, NON_LINEAR_DECAY_TYPE));
bytes internal constant V3_DUTCH_OUTPUT_TYPE = abi.encodePacked(
"V3DutchOutput(",
"address token,",
Expand All @@ -105,7 +106,8 @@ library V3DutchOrderLib {
"uint256 minAmount,",
"uint256 adjustmentPerGweiBaseFee)"
);
bytes32 internal constant V3_DUTCH_OUTPUT_TYPE_HASH = keccak256(V3_DUTCH_OUTPUT_TYPE);
bytes32 internal constant V3_DUTCH_OUTPUT_TYPE_HASH =
keccak256(abi.encodePacked(V3_DUTCH_OUTPUT_TYPE, NON_LINEAR_DECAY_TYPE));
bytes internal constant NON_LINEAR_DECAY_TYPE =
abi.encodePacked("NonlinearDutchDecay(", "uint256 relativeBlocks,", "int256[] relativeAmounts)");
bytes32 internal constant NON_LINEAR_DECAY_TYPE_HASH = keccak256(NON_LINEAR_DECAY_TYPE);
Expand Down Expand Up @@ -208,7 +210,7 @@ library V3DutchOrderLib {
}

/// @notice get the digest of the cosigner data
/// @param order the priorityOrder
/// @param order the V3DutchOrder
/// @param orderHash the hash of the order
function cosignerDigest(V3DutchOrder memory order, bytes32 orderHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(orderHash, abi.encode(order.cosignerData)));
Expand Down
18 changes: 11 additions & 7 deletions src/reactors/V3DutchOrderReactor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {Math} from "openzeppelin-contracts/utils/math/Math.sol";
import {CosignerLib} from "../lib/CosignerLib.sol";

/// @notice Reactor for V3 dutch orders
/// @dev V3 orders must be cosigned by the specified cosigner to override starting block and value
/// @dev V3 orders must be cosigned by the specified cosigner to set the starting block and override the value
/// @dev resolution behavior:
/// - If cosignature is invalid or not from specified cosigner, revert
/// - If inputAmount is 0, then use baseInput
Expand Down Expand Up @@ -120,21 +120,25 @@ contract V3DutchOrderReactor is BaseReactor, BlockNumberish {
int256 gasDeltaGwei = block.basefee.sub(order.startingBaseFee);

// Gas increase should increase input
int256 inputDelta = int256(order.baseInput.adjustmentPerGweiBaseFee) * gasDeltaGwei / 1 gwei;
order.baseInput.startAmount = order.baseInput.startAmount.boundedAdd(inputDelta, 0, order.baseInput.maxAmount);

if (order.baseInput.adjustmentPerGweiBaseFee != 0) {
int256 inputDelta = int256(order.baseInput.adjustmentPerGweiBaseFee) * gasDeltaGwei / 1 gwei;
order.baseInput.startAmount =
order.baseInput.startAmount.boundedAdd(inputDelta, 0, order.baseInput.maxAmount);
}
// Gas increase should decrease output
uint256 outputsLength = order.baseOutputs.length;
for (uint256 i = 0; i < outputsLength; i++) {
V3DutchOutput memory output = order.baseOutputs[i];
int256 outputDelta = int256(output.adjustmentPerGweiBaseFee) * gasDeltaGwei / 1 gwei;
output.startAmount = output.startAmount.boundedSub(outputDelta, output.minAmount, type(uint256).max);
if (output.adjustmentPerGweiBaseFee != 0) {
int256 outputDelta = int256(output.adjustmentPerGweiBaseFee) * gasDeltaGwei / 1 gwei;
output.startAmount = output.startAmount.boundedSub(outputDelta, output.minAmount, type(uint256).max);
}
}
}

/// @notice validate the dutch order fields
/// - deadline must have not passed
/// - cosigner is valid if specified
/// - cosigner must always be provided and sign the cosignerData
/// @dev Throws if the order is invalid
function _validateOrder(bytes32 orderHash, V3DutchOrder memory order) internal view {
if (order.info.deadline < block.timestamp) {
Expand Down
2 changes: 1 addition & 1 deletion src/types/Uint16Array.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ library Uint16ArrayLibrary {
}
unchecked {
uint256 shiftAmount = n * 16;
uint16 result = uint16((Uint16Array.unwrap(packedData) >> shiftAmount) & 0xFFFF);
uint16 result = uint16(Uint16Array.unwrap(packedData) >> shiftAmount);
return result;
}
}
Expand Down
46 changes: 46 additions & 0 deletions test/lib/EIP712.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {Test} from "forge-std/Test.sol";
import {NonlinearDutchDecay, V3DutchOrderLib, V3DutchOutput} from "../../src/lib/V3DutchOrderLib.sol";

contract EIP712Test is Test {
function test_NonlinearDutchDecayHash() public pure {
assertEq(
V3DutchOrderLib.NON_LINEAR_DECAY_TYPE_HASH,
hex"30c39ae6ecb284279579f99803ba5d7b54275a8a6a04180056b5031b8c19a01a"
);

int256[] memory amounts = new int256[](1);
amounts[0] = 1;
NonlinearDutchDecay memory curve = NonlinearDutchDecay(1, amounts);
assertEq(V3DutchOrderLib.hash(curve), hex"ad28931e960b684a49cdf1aca21bd966df5bac39996c5a0615c0a54f2f22a06f");
}

function test_V3DutchInputHash() public pure {
assertEq(
V3DutchOrderLib.V3_DUTCH_INPUT_TYPE_HASH,
hex"2cc4ccc271072d8b406616a16a6e9a3935dea10f0eb920f44737e1855ecc68eb"
);
}

function test_V3DutchOutputHash() public pure {
assertEq(
V3DutchOrderLib.V3_DUTCH_OUTPUT_TYPE_HASH,
hex"7fd857ffad1736e72f90e17c9d15cabe562b86b45c6e618ae0e7fa92c4a6fde9"
);

address token = address(0);
uint256 startAmount = 21;
int256[] memory amounts = new int256[](1);
amounts[0] = 1;
NonlinearDutchDecay memory curve = NonlinearDutchDecay(1, amounts);
address recipient = address(0);
uint256 minAmount = 20;
uint256 adjustmentPerGweiBaseFee = 0;
V3DutchOutput memory output =
V3DutchOutput(token, startAmount, curve, recipient, minAmount, adjustmentPerGweiBaseFee);
assertEq(V3DutchOrderLib.hash(output), hex"c57ac5e0436939ec593af412dde4a05d4972a0a8a56bbdb63ca7cd949c5326e2");
}

function test_OrderTypeHash() public pure {
assertEq(V3DutchOrderLib.ORDER_TYPE_HASH, hex"186c8af0344af94faab60c9dc413f68b8ca7aea1aded04a300c7fa35562ed1b7");
}
}
Loading

0 comments on commit e6e01eb

Please sign in to comment.