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(9): Round gas adjustments in favor of swapper #302

Merged
merged 5 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1 +1 @@
198780
198680
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
230916
Original file line number Diff line number Diff line change
@@ -1 +1 @@
244626
244376
Original file line number Diff line number Diff line change
@@ -1 +1 @@
302041
301741
Original file line number Diff line number Diff line change
@@ -1 +1 @@
224642
224442
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
165065
Original file line number Diff line number Diff line change
@@ -1 +1 @@
150727
150627
Original file line number Diff line number Diff line change
@@ -1 +1 @@
174481
174381
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
43685
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
168989
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
169070
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
169013
23 changes: 17 additions & 6 deletions src/reactors/V3DutchOrderReactor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol";
import {MathExt} from "../lib/MathExt.sol";
import {Math} from "openzeppelin-contracts/utils/math/Math.sol";
import {CosignerLib} from "../lib/CosignerLib.sol";
import {SafeCast} from "openzeppelin-contracts/utils/math/SafeCast.sol";

/// @notice Reactor for V3 dutch orders
/// @dev V3 orders must be cosigned by the specified cosigner to override starting block and value
Expand Down Expand Up @@ -109,22 +110,32 @@ contract V3DutchOrderReactor is BaseReactor {
}

function _updateWithGasAdjustment(V3DutchOrder memory order) internal view {
// positive means an increase in gas
int256 gasDeltaGwei = block.basefee.sub(order.startingBaseFee);
// Positive means an increase in gas
int256 gasDeltaWei = block.basefee.sub(order.startingBaseFee);

// Gas increase should increase input
int256 inputDelta = int256(order.baseInput.adjustmentPerGweiBaseFee) * gasDeltaGwei / 1 gwei;
// Round in favor of swapper
int256 inputDelta = _computeDelta(order.baseInput.adjustmentPerGweiBaseFee, gasDeltaWei);
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;
// Round in favor of swapper
int256 outputDelta = _computeDelta(output.adjustmentPerGweiBaseFee, gasDeltaWei);
output.startAmount = output.startAmount.boundedSub(outputDelta, output.minAmount, type(uint256).max);
}
}

function _computeDelta(uint256 adjustmentPerGweiBaseFee, int256 gasDeltaWei) internal pure returns (int256) {
if (gasDeltaWei >= 0) {
// Gas increase: round adjustment down to decrease amount added to input or subtracted from output
return int256(adjustmentPerGweiBaseFee.mulDivDown(uint256(gasDeltaWei), 1 gwei));
} else {
// Gas decrease: round adjustment up to increase amount added to output or subtracted from input
return -int256(adjustmentPerGweiBaseFee.mulDivUp(SafeCast.toUint256(-gasDeltaWei), 1 gwei));
alanhwu marked this conversation as resolved.
Show resolved Hide resolved
}
}

/// @notice validate the dutch order fields
/// - deadline must have not passed
/// - cosigner is valid if specified
Expand Down
50 changes: 50 additions & 0 deletions test/reactors/V3DutchOrderReactor.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1401,6 +1401,56 @@ contract V3DutchOrderTest is PermitSignature, DeployPermit2, BaseReactorTest {
assertEq(resolvedOrder.input.amount, 0);
}

function testV3GasAdjustmentRounding() public {
uint256 currentBlock = 21212121;
vm.roll(currentBlock);
vm.fee(1 gwei);

// Order with 1 wei gas adjustments
SignedOrder memory order = generateOrder(
TestDutchOrderSpec({
currentBlock: currentBlock,
startBlock: currentBlock,
deadline: currentBlock + 21,
input: V3DutchInput(tokenIn, 1000, CurveBuilder.emptyCurve(), 1100, 1),
outputs: OutputsBuilder.singleV3Dutch(
V3DutchOutput(address(tokenOut), 1000, CurveBuilder.emptyCurve(), address(0), 900, 1)
)
})
);

// Test gas increase
vm.fee(1.5 gwei);
ResolvedOrder memory resolvedOrder = quoter.quote(order.order, order.sig);
// The gas adjusted input would be 1000.5, which should round down to 1000
assertEq(resolvedOrder.input.amount, 1000, "Input should round down");
// The gas adjusted output would be 999.5, which should round up to 1000
assertEq(resolvedOrder.outputs[0].amount, 1000, "Output should round up");

// Test gas decrease
vm.fee(0.5 gwei);
resolvedOrder = quoter.quote(order.order, order.sig);
// The gas adjusted input would be 999.5, which should round down to 999
assertEq(resolvedOrder.input.amount, 999, "Input should round down");
// The gas adjusted output would be 1000.5, which should round up to 1001
assertEq(resolvedOrder.outputs[0].amount, 1001, "Output should round up");

// Test smaller gas changes
vm.fee(1.1 gwei);
resolvedOrder = quoter.quote(order.order, order.sig);
// The gas adjusted input would be 1000.1, which should round down to 1000
assertEq(resolvedOrder.input.amount, 1000, "Input should round down");
// The gas adjusted output would be 999.9, which should round up to 1000
assertEq(resolvedOrder.outputs[0].amount, 1000, "Output should round up");

vm.fee(0.9 gwei);
resolvedOrder = quoter.quote(order.order, order.sig);
// The gas adjusted input would be 999.9, which should round down to 999
assertEq(resolvedOrder.input.amount, 999, "Input should round down");
// The gas adjusted output would be 1000.1, which should round up to 1001
assertEq(resolvedOrder.outputs[0].amount, 1001, "Output should round up");
}

/* Test helpers */

struct TestDutchOrderSpec {
Expand Down
Loading