Skip to content

Commit

Permalink
audit(16): Round decays in favor of swapper (#305)
Browse files Browse the repository at this point in the history
* feat, test: round decays in favor of swapper

* refactor: move v3 decay functions together

* refactor: remove unused function

* refactor: unwind isInput from v3LinearDecay

* refactor: unwind isInput from decay & tests

* style: forge fmt

* test: round in favor of swapper when resolving output

* refactor: clean curveDelta use

* test: split uint16 overflow test into input & output

* Pass in decay function for input/output (#312)

* Pass in decay function for input/output

* forge fmt

* Remove MockNonlinearDutchDecayLibContract

---------

Co-authored-by: Cody Born <[email protected]>
  • Loading branch information
alanhwu and codyborn authored Oct 18, 2024
1 parent d7cea37 commit 9a35aad
Show file tree
Hide file tree
Showing 26 changed files with 392 additions and 111 deletions.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
199172
199182
2 changes: 1 addition & 1 deletion .forge-snapshots/Base-V3DutchOrder-ExecuteBatch.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
231968
231988
Original file line number Diff line number Diff line change
@@ -1 +1 @@
245818
245843
Original file line number Diff line number Diff line change
@@ -1 +1 @@
303592
303622
Original file line number Diff line number Diff line change
@@ -1 +1 @@
225494
225514
2 changes: 1 addition & 1 deletion .forge-snapshots/Base-V3DutchOrder-ExecuteSingle.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
165555
165565
Original file line number Diff line number Diff line change
@@ -1 +1 @@
151117
151127
Original file line number Diff line number Diff line change
@@ -1 +1 @@
174866
174876
2 changes: 1 addition & 1 deletion .forge-snapshots/Base-V3DutchOrder-RevertInvalidNonce.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
44191
44201
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 @@
169490
169500
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 @@
169571
169581
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 @@
169514
169524
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecay.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
13371
17903
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayBounded.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1193
3389
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayFullyDecayed.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6779
9958
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayFullyDecayedNegative.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6467
9672
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayNegative.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1265
3861
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayNoDecay.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
5899
9977
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayNoDecayYet.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4697
7890
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayNoDecayYetNegative.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4697
7864
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-DutchDecayRange.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1265
3861
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-ExtendedMultiPointDutchDecay.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
88450
103346
2 changes: 1 addition & 1 deletion .forge-snapshots/V3-MultiPointDutchDecay.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
26539
34003
74 changes: 68 additions & 6 deletions src/lib/NonlinearDutchDecayLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,18 @@ library NonlinearDutchDecayLib {
/// @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 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
/// @return decayedAmount The amount after applying the decay, bounded by minAmount and maxAmount
/// @return decayedAmount The decayed amount
function decay(
NonlinearDutchDecay memory curve,
uint256 startAmount,
uint256 decayStartBlock,
uint256 minAmount,
uint256 maxAmount
uint256 maxAmount,
function(uint256, uint256, uint256, int256, int256) internal pure returns (int256) decayFunc
) internal view returns (uint256 decayedAmount) {
// mismatch of relativeAmounts and relativeBlocks
if (curve.relativeAmounts.length > 16) {
Expand All @@ -46,7 +50,7 @@ library NonlinearDutchDecayLib {
(uint16 startPoint, uint16 endPoint, int256 relStartAmount, int256 relEndAmount) =
locateCurvePosition(curve, blockDelta);
// get decay of only the relative amounts
int256 curveDelta = DutchDecayLib.linearDecay(startPoint, endPoint, blockDelta, relStartAmount, relEndAmount);
int256 curveDelta = decayFunc(startPoint, endPoint, blockDelta, relStartAmount, relEndAmount);

return startAmount.boundedSub(curveDelta, minAmount, maxAmount);
}
Expand Down Expand Up @@ -100,8 +104,9 @@ library NonlinearDutchDecayLib {
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, output.minAmount, type(uint256).max, v3LinearOutputDecay
);
result = OutputToken(output.token, decayedOutput, output.recipient);
}

Expand Down Expand Up @@ -130,7 +135,64 @@ library NonlinearDutchDecayLib {
view
returns (InputToken memory result)
{
uint256 decayedInput = decay(input.curve, input.startAmount, decayStartBlock, 0, input.maxAmount);
uint256 decayedInput =
decay(input.curve, input.startAmount, decayStartBlock, 0, input.maxAmount, v3LinearInputDecay);
result = InputToken(input.token, decayedInput, input.maxAmount);
}

/// @notice returns the linear interpolation between the two points
/// @param startPoint The start of the decay
/// @param endPoint The end of the decay
/// @param currentPoint The current position in the decay
/// @param startAmount The amount of the start of the decay
/// @param endAmount The amount of the end of the decay
/// @dev rounds in favor of the swapper based on input or output
function v3LinearInputDecay(
uint256 startPoint,
uint256 endPoint,
uint256 currentPoint,
int256 startAmount,
int256 endAmount
) internal pure returns (int256) {
if (currentPoint >= endPoint) {
return endAmount;
}
uint256 elapsed = currentPoint - startPoint;
uint256 duration = endPoint - startPoint;
int256 delta;

// Because startAmount + delta is subtracted from the original amount,
// we want to maximize startAmount + delta to favor the swapper
if (endAmount < startAmount) {
delta = -int256(uint256(startAmount - endAmount).mulDivDown(elapsed, duration));
} else {
delta = int256(uint256(endAmount - startAmount).mulDivUp(elapsed, duration));
}

return startAmount + delta;
}

function v3LinearOutputDecay(
uint256 startPoint,
uint256 endPoint,
uint256 currentPoint,
int256 startAmount,
int256 endAmount
) internal pure returns (int256) {
if (currentPoint >= endPoint) {
return endAmount;
}
uint256 elapsed = currentPoint - startPoint;
uint256 duration = endPoint - startPoint;
int256 delta;

// For outputs, we want to minimize startAmount + delta to favor the swapper
if (endAmount < startAmount) {
delta = -int256(uint256(startAmount - endAmount).mulDivUp(elapsed, duration));
} else {
delta = int256(uint256(endAmount - startAmount).mulDivDown(elapsed, duration));
}

return startAmount + delta;
}
}
Loading

0 comments on commit 9a35aad

Please sign in to comment.