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 all 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
21 changes: 16 additions & 5 deletions src/reactors/V3DutchOrderReactor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,12 @@ 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
if (order.baseInput.adjustmentPerGweiBaseFee != 0) {
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);
}
Expand All @@ -123,12 +123,23 @@ contract V3DutchOrderReactor is BaseReactor {
for (uint256 i = 0; i < outputsLength; i++) {
V3DutchOutput memory output = order.baseOutputs[i];
if (output.adjustmentPerGweiBaseFee != 0) {
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(uint256(-gasDeltaWei), 1 gwei));
}
}

/// @notice validate the dutch order fields
/// - deadline must have not passed
/// - cosigner must always be provided and sign the cosignerData
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