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

Routing #58

Merged
merged 64 commits into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
b6f8d3b
start routing
ewilz Aug 17, 2023
d5dc31a
start routing contract
ewilz Aug 23, 2023
2ca710a
naive swapExactIn impl
ewilz Aug 24, 2023
664d2c2
lint + bytecode snapshot
ewilz Aug 30, 2023
8b687b8
change concept of hops to token hops
ewilz Aug 31, 2023
1717039
UniswapV4Routing --> Routing
ewilz Sep 1, 2023
2549c3a
use PathKey
ewilz Sep 1, 2023
e1c46fd
exactInputSingle
ewilz Sep 1, 2023
8aae01b
save DRY progress
ewilz Sep 1, 2023
5823d2f
no sqrtPriceLimit for multipool hops
ewilz Sep 5, 2023
7e25390
exactOut implemented w awkward loops/int conversions
ewilz Sep 5, 2023
607ea3b
gas savings from not doing double negative number
ewilz Sep 5, 2023
cf82527
gas savings from unchecked math
ewilz Sep 5, 2023
9ebc9d5
add swapExactOuputSingle
ewilz Sep 5, 2023
54a48e5
break out structs into interface
ewilz Sep 5, 2023
01a5db0
PR comments
ewilz Sep 25, 2023
31cbfe5
pass hook data along
ewilz Sep 26, 2023
d50f18d
gas and coherency optimization
ewilz Oct 2, 2023
4b010ff
updated lib/v4-core submodule to main branch
dianakocsis Mar 19, 2024
7c6675b
Merge branch 'main' into routing
hensha256 Jun 28, 2024
aa148b3
feat: abstract router (#86)
ConjunctiveNormalForm Jun 28, 2024
1586c0d
allow payer and recipient to be different
hensha256 Jul 2, 2024
06961bf
try to fix ci
hensha256 Jul 5, 2024
528f15d
improve casting
hensha256 Jul 5, 2024
0ac638a
reverting 3 commits to make branch
hensha256 Jul 17, 2024
1844d70
remove unused recipient param
hensha256 Jul 17, 2024
86039e4
remove payment logic from swap logic
hensha256 Jul 17, 2024
90f3f35
factor out payment functions
hensha256 Jul 17, 2024
50372c7
gas opt removing struct
hensha256 Jul 17, 2024
64f4645
gas opt: decode in assembly
hensha256 Jul 17, 2024
e92b023
Merge branch 'main' into routing
hensha256 Jul 18, 2024
8283fb6
merge error
hensha256 Jul 18, 2024
7aacd94
merge main
hensha256 Jul 18, 2024
f2a3dd8
merge main
hensha256 Jul 23, 2024
4792d1c
merge routing
hensha256 Jul 23, 2024
903d5fa
use base actions router in v4router
hensha256 Jul 23, 2024
f1c4746
use isolate
hensha256 Jul 23, 2024
4b7d019
Merge pull request #155 from Uniswap/v4-routing
hensha256 Jul 23, 2024
f555329
Merge branch 'main' into routing
hensha256 Jul 23, 2024
9c11de4
merge conflicts
hensha256 Jul 23, 2024
b2fdb51
removing submodules
hensha256 Jul 23, 2024
963c360
renaming to stop clashes in UR
hensha256 Jul 24, 2024
eb801c7
Merge branch 'main' into routing
hensha256 Jul 24, 2024
86fd91a
Merge branch 'main' into routing
hensha256 Jul 25, 2024
22c0879
PR comments and gas optimisations
hensha256 Jul 25, 2024
3a4c36d
add _getLocker
hensha256 Jul 25, 2024
e86036b
Amount field on settle and take
hensha256 Jul 25, 2024
2236812
rename snaps
hensha256 Jul 25, 2024
456d0c8
correcy casting order
hensha256 Jul 25, 2024
9e5e418
Merge branch 'main' into routing
hensha256 Jul 25, 2024
5ceaadf
Add deltaresolver to router
hensha256 Jul 25, 2024
20224d7
take_all command, remove from delta resolver
hensha256 Jul 26, 2024
d02049b
Routing test helper
hensha256 Jul 26, 2024
ff206ec
Separate gas tests and regular tests
hensha256 Jul 26, 2024
09b2e23
remove duplicate snapshot name
hensha256 Jul 26, 2024
b51f0ea
another gas test
hensha256 Jul 26, 2024
b625d74
merge main
hensha256 Jul 26, 2024
d1d66ec
Merge branch 'main' into routing
hensha256 Jul 26, 2024
e2ae6d3
Merge branch 'main' into routing
hensha256 Jul 29, 2024
7094a75
PR comments
hensha256 Jul 29, 2024
9ee5768
remove unused function
hensha256 Jul 29, 2024
f14c6f0
Merge branch 'main' into routing
hensha256 Jul 29, 2024
7545fa3
PR cmments
hensha256 Jul 29, 2024
a92da59
handle hook edgecase
hensha256 Jul 29, 2024
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
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_Bytecode.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6129
6214
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactIn1Hop_oneForZero.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
129132
129205
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactIn1Hop_zeroForOne.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
135962
136035
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactIn2Hops.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
187241
187387
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactIn3Hops.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
238549
238768
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactOut1Hop_oneForZero.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
129979
130046
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactOut1Hop_zeroForOne.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
134780
134847
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactOut2Hops.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
186674
186808
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactOut3Hops.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
238612
238813
8 changes: 6 additions & 2 deletions src/V4Router.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ import {IV4Router} from "./interfaces/IV4Router.sol";
import {BaseActionsRouter} from "./base/BaseActionsRouter.sol";
import {DeltaResolver} from "./base/DeltaResolver.sol";
import {Actions} from "./libraries/Actions.sol";
import {SafeCast} from "./libraries/SafeCast.sol";

/// @title UniswapV4Router
/// @notice Abstract contract that contains all internal logic needed for routing through Uniswap V4 pools
/// @dev the entry point to executing actions in this contract is calling `BaseActionsRouter._executeActions`
/// An inheriting contract should call _executeActions at the point that they wish actions to be executed
abstract contract V4Router is IV4Router, BaseActionsRouter, DeltaResolver {
using SafeCast for *;
using PathKeyLib for PathKey;
using CalldataDecoder for bytes;
using TransientStateLibrary for IPoolManager;
Expand Down Expand Up @@ -98,7 +100,8 @@ abstract contract V4Router is IV4Router, BaseActionsRouter, DeltaResolver {
for (uint256 i = 0; i < pathLength; i++) {
hensha256 marked this conversation as resolved.
Show resolved Hide resolved
pathKey = params.path[i];
(PoolKey memory poolKey, bool zeroForOne) = pathKey.getPoolAndSwapDirection(currencyIn);
amountOut = uint128(_swap(poolKey, zeroForOne, -int256(uint256(amountIn)), 0, pathKey.hookData));
// The output delta will always be positive, except for when interacting with certain hook pools
amountOut = _swap(poolKey, zeroForOne, -int256(uint256(amountIn)), 0, pathKey.hookData).toUint128();

amountIn = amountOut;
currencyIn = pathKey.intermediateCurrency;
Expand Down Expand Up @@ -130,7 +133,8 @@ abstract contract V4Router is IV4Router, BaseActionsRouter, DeltaResolver {
for (uint256 i = pathLength; i > 0; i--) {
pathKey = params.path[i - 1];
(PoolKey memory poolKey, bool oneForZero) = pathKey.getPoolAndSwapDirection(currencyOut);
amountIn = uint128(-_swap(poolKey, !oneForZero, int256(uint256(amountOut)), 0, pathKey.hookData));
// The output delta will always be negative, except for when interacting with certain hook pools
amountIn = (-_swap(poolKey, !oneForZero, int256(uint256(amountOut)), 0, pathKey.hookData)).toUint128();

amountOut = amountIn;
currencyOut = pathKey.intermediateCurrency;
Expand Down
20 changes: 20 additions & 0 deletions src/libraries/SafeCast.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import {CustomRevert} from "@uniswap/v4-core/src/libraries/CustomRevert.sol";

/// @title Safe casting methods
/// @notice Contains methods for safely casting between types
library SafeCast {
Copy link
Member

Choose a reason for hiding this comment

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

why not just import SafeCast from core?

Copy link
Contributor

Choose a reason for hiding this comment

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

this function doesnt exist in core rip

using CustomRevert for bytes4;

error SafeCastOverflow();

/// @notice Cast a int128 to a uint128, revert on overflow or underflow
/// @param x The int128 to be casted
/// @return y The casted integer, now type uint128
function toUint128(int128 x) internal pure returns (uint128 y) {
if (x < 0) SafeCastOverflow.selector.revertWith();
y = uint128(x);
}
}
30 changes: 10 additions & 20 deletions test/router/V4Router.gas.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ contract V4RouterTest is RoutingTestHelpers, GasSnapshot {
IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, 0, bytes(""));

plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params));
_finalizePlan(key0.currency0, key0.currency1, address(this));
bytes memory data = plan.encode();
bytes memory data = plan.finalizeSwap(key0.currency0, key0.currency1, address(this));

router.executeActions(data);
snapLastCall("V4Router_ExactInputSingle");
Expand All @@ -44,8 +43,7 @@ contract V4RouterTest is RoutingTestHelpers, GasSnapshot {
IV4Router.ExactInputParams memory params = _getExactInputParams(tokenPath, amountIn);

plan = plan.add(Actions.SWAP_EXACT_IN, abi.encode(params));
_finalizePlan(currency0, currency1, address(this));
bytes memory data = plan.encode();
bytes memory data = plan.finalizeSwap(currency0, currency1, address(this));

router.executeActions(data);
snapLastCall("V4Router_ExactIn1Hop_zeroForOne");
Expand All @@ -59,8 +57,7 @@ contract V4RouterTest is RoutingTestHelpers, GasSnapshot {
IV4Router.ExactInputParams memory params = _getExactInputParams(tokenPath, amountIn);

plan = plan.add(Actions.SWAP_EXACT_IN, abi.encode(params));
_finalizePlan(currency1, currency0, address(this));
bytes memory data = plan.encode();
bytes memory data = plan.finalizeSwap(currency1, currency0, address(this));

router.executeActions(data);
snapLastCall("V4Router_ExactIn1Hop_oneForZero");
Expand All @@ -75,8 +72,7 @@ contract V4RouterTest is RoutingTestHelpers, GasSnapshot {
IV4Router.ExactInputParams memory params = _getExactInputParams(tokenPath, amountIn);

plan = plan.add(Actions.SWAP_EXACT_IN, abi.encode(params));
_finalizePlan(currency0, currency2, address(this));
bytes memory data = plan.encode();
bytes memory data = plan.finalizeSwap(currency0, currency2, address(this));

router.executeActions(data);
snapLastCall("V4Router_ExactIn2Hops");
Expand All @@ -92,8 +88,7 @@ contract V4RouterTest is RoutingTestHelpers, GasSnapshot {
IV4Router.ExactInputParams memory params = _getExactInputParams(tokenPath, amountIn);

plan = plan.add(Actions.SWAP_EXACT_IN, abi.encode(params));
_finalizePlan(currency0, currency3, address(this));
bytes memory data = plan.encode();
bytes memory data = plan.finalizeSwap(currency0, currency3, address(this));

router.executeActions(data);
snapLastCall("V4Router_ExactIn3Hops");
Expand All @@ -106,8 +101,7 @@ contract V4RouterTest is RoutingTestHelpers, GasSnapshot {
IV4Router.ExactOutputSingleParams(key0, true, uint128(amountOut), 0, 0, bytes(""));

plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params));
_finalizePlan(key0.currency0, key0.currency1, address(this));
bytes memory data = plan.encode();
bytes memory data = plan.finalizeSwap(key0.currency0, key0.currency1, address(this));

router.executeActions(data);
snapLastCall("V4Router_ExactOutputSingle");
Expand All @@ -121,8 +115,7 @@ contract V4RouterTest is RoutingTestHelpers, GasSnapshot {
IV4Router.ExactOutputParams memory params = _getExactOutputParams(tokenPath, amountOut);

plan = plan.add(Actions.SWAP_EXACT_OUT, abi.encode(params));
_finalizePlan(currency0, currency1, address(this));
bytes memory data = plan.encode();
bytes memory data = plan.finalizeSwap(currency0, currency1, address(this));

router.executeActions(data);
snapLastCall("V4Router_ExactOut1Hop_zeroForOne");
Expand All @@ -136,8 +129,7 @@ contract V4RouterTest is RoutingTestHelpers, GasSnapshot {
IV4Router.ExactOutputParams memory params = _getExactOutputParams(tokenPath, amountOut);

plan = plan.add(Actions.SWAP_EXACT_OUT, abi.encode(params));
_finalizePlan(currency1, currency0, address(this));
bytes memory data = plan.encode();
bytes memory data = plan.finalizeSwap(currency1, currency0, address(this));

router.executeActions(data);
snapLastCall("V4Router_ExactOut1Hop_oneForZero");
Expand All @@ -152,8 +144,7 @@ contract V4RouterTest is RoutingTestHelpers, GasSnapshot {
IV4Router.ExactOutputParams memory params = _getExactOutputParams(tokenPath, amountOut);

plan = plan.add(Actions.SWAP_EXACT_OUT, abi.encode(params));
_finalizePlan(currency0, currency2, address(this));
bytes memory data = plan.encode();
bytes memory data = plan.finalizeSwap(currency0, currency2, address(this));

router.executeActions(data);
snapLastCall("V4Router_ExactOut2Hops");
Expand All @@ -169,8 +160,7 @@ contract V4RouterTest is RoutingTestHelpers, GasSnapshot {
IV4Router.ExactOutputParams memory params = _getExactOutputParams(tokenPath, amountOut);

plan = plan.add(Actions.SWAP_EXACT_OUT, abi.encode(params));
_finalizePlan(currency0, currency3, address(this));
bytes memory data = plan.encode();
bytes memory data = plan.finalizeSwap(currency0, currency3, address(this));

router.executeActions(data);
snapLastCall("V4Router_ExactOut3Hops");
Expand Down
36 changes: 12 additions & 24 deletions test/router/V4Router.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ contract V4RouterTest is RoutingTestHelpers {
uint256 prevBalance1 = key0.currency1.balanceOf(address(this));

plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params));
_finalizePlan(key0.currency0, key0.currency1, address(this));
bytes memory data = plan.encode();
bytes memory data = plan.finalizeSwap(key0.currency0, key0.currency1, address(this));

router.executeActions(data);

Expand All @@ -50,8 +49,7 @@ contract V4RouterTest is RoutingTestHelpers {
uint256 prevBalance1 = key0.currency1.balanceOf(address(this));

plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params));
_finalizePlan(key0.currency1, key0.currency0, address(this));
bytes memory data = plan.encode();
bytes memory data = plan.finalizeSwap(key0.currency1, key0.currency0, address(this));

router.executeActions(data);

Expand All @@ -74,8 +72,7 @@ contract V4RouterTest is RoutingTestHelpers {
uint256 prevBalance1 = currency1.balanceOfSelf();

plan = plan.add(Actions.SWAP_EXACT_IN, abi.encode(params));
_finalizePlan(currency0, currency1, address(this));
bytes memory data = plan.encode();
bytes memory data = plan.finalizeSwap(currency0, currency1, address(this));

router.executeActions(data);

Expand All @@ -97,8 +94,7 @@ contract V4RouterTest is RoutingTestHelpers {
uint256 prevBalance1 = currency1.balanceOfSelf();

plan = plan.add(Actions.SWAP_EXACT_IN, abi.encode(params));
_finalizePlan(currency1, currency0, address(this));
bytes memory data = plan.encode();
bytes memory data = plan.finalizeSwap(currency1, currency0, address(this));

router.executeActions(data);

Expand All @@ -123,8 +119,7 @@ contract V4RouterTest is RoutingTestHelpers {
uint256 prevBalance2 = currency2.balanceOfSelf();

plan = plan.add(Actions.SWAP_EXACT_IN, abi.encode(params));
_finalizePlan(currency0, currency2, address(this));
bytes memory data = plan.encode();
bytes memory data = plan.finalizeSwap(currency0, currency2, address(this));

router.executeActions(data);

Expand Down Expand Up @@ -154,8 +149,7 @@ contract V4RouterTest is RoutingTestHelpers {
uint256 prevBalance3 = currency3.balanceOfSelf();

plan = plan.add(Actions.SWAP_EXACT_IN, abi.encode(params));
_finalizePlan(currency0, currency3, address(this));
bytes memory data = plan.encode();
bytes memory data = plan.finalizeSwap(currency0, currency3, address(this));

router.executeActions(data);

Expand All @@ -181,8 +175,7 @@ contract V4RouterTest is RoutingTestHelpers {
uint256 prevBalance1 = key0.currency1.balanceOf(address(this));

plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params));
_finalizePlan(key0.currency0, key0.currency1, address(this));
bytes memory data = plan.encode();
bytes memory data = plan.finalizeSwap(key0.currency0, key0.currency1, address(this));

router.executeActions(data);

Expand All @@ -204,8 +197,7 @@ contract V4RouterTest is RoutingTestHelpers {
uint256 prevBalance1 = key0.currency1.balanceOf(address(this));

plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params));
_finalizePlan(key0.currency1, key0.currency0, address(this));
bytes memory data = plan.encode();
bytes memory data = plan.finalizeSwap(key0.currency1, key0.currency0, address(this));

router.executeActions(data);

Expand All @@ -228,8 +220,7 @@ contract V4RouterTest is RoutingTestHelpers {
uint256 prevBalance1 = currency1.balanceOfSelf();

plan = plan.add(Actions.SWAP_EXACT_OUT, abi.encode(params));
_finalizePlan(currency0, currency1, address(this));
bytes memory data = plan.encode();
bytes memory data = plan.finalizeSwap(currency0, currency1, address(this));

router.executeActions(data);

Expand All @@ -252,8 +243,7 @@ contract V4RouterTest is RoutingTestHelpers {
uint256 prevBalance1 = currency1.balanceOfSelf();

plan = plan.add(Actions.SWAP_EXACT_OUT, abi.encode(params));
_finalizePlan(currency1, currency0, address(this));
bytes memory data = plan.encode();
bytes memory data = plan.finalizeSwap(currency1, currency0, address(this));

router.executeActions(data);

Expand All @@ -278,8 +268,7 @@ contract V4RouterTest is RoutingTestHelpers {
uint256 prevBalance2 = currency2.balanceOfSelf();

plan = plan.add(Actions.SWAP_EXACT_OUT, abi.encode(params));
_finalizePlan(currency0, currency2, address(this));
bytes memory data = plan.encode();
bytes memory data = plan.finalizeSwap(currency0, currency2, address(this));

router.executeActions(data);

Expand Down Expand Up @@ -309,8 +298,7 @@ contract V4RouterTest is RoutingTestHelpers {
uint256 prevBalance3 = currency3.balanceOfSelf();

plan = plan.add(Actions.SWAP_EXACT_OUT, abi.encode(params));
_finalizePlan(currency0, currency3, address(this));
bytes memory data = plan.encode();
bytes memory data = plan.finalizeSwap(currency0, currency3, address(this));

router.executeActions(data);

Expand Down
15 changes: 15 additions & 0 deletions test/shared/ActionsRouterPlanner.sol
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
import {Actions} from "../../src/libraries/Actions.sol";

struct Plan {
uint256[] actions;
bytes[] params;
}

library ActionsRouterPlanner {
using ActionsRouterPlanner for Plan;

function init() internal pure returns (Plan memory plan) {
return Plan({actions: new uint256[](0), params: new bytes[](0)});
}
Expand All @@ -33,4 +38,14 @@ library ActionsRouterPlanner {
function encode(Plan memory plan) internal pure returns (bytes memory) {
return abi.encode(plan.actions, plan.params);
}

function finalizeSwap(Plan memory plan, Currency inputCurrency, Currency outputCurrency, address recipient)
internal
pure
returns (bytes memory)
{
plan = plan.add(Actions.SETTLE_ALL, abi.encode(inputCurrency));
plan = plan.add(Actions.TAKE_ALL, abi.encode(outputCurrency, recipient));
return plan.encode();
}
}
7 changes: 1 addition & 6 deletions test/shared/RoutingTestHelpers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {IERC20} from "forge-std/interfaces/IERC20.sol";
import {LiquidityOperations} from "./LiquidityOperations.sol";
import {IV4Router} from "../../src/interfaces/IV4Router.sol";

/// @notice A shared test contract that wraps the v4-core deployers contract and exposes basic liquidity operations on posm.
/// @notice A shared test contract that wraps the v4-core deployers contract and exposes basic helpers for swapping with the router.
contract RoutingTestHelpers is Test, Deployers {
using ActionsRouterPlanner for Plan;

Expand Down Expand Up @@ -107,9 +107,4 @@ contract RoutingTestHelpers is Test, Deployers {
params.amountOut = uint128(amountOut);
params.amountInMaximum = type(uint128).max;
}

function _finalizePlan(Currency inputCurrency, Currency outputCurrency, address recipient) internal {
plan = plan.add(Actions.SETTLE_ALL, abi.encode(inputCurrency));
plan = plan.add(Actions.TAKE_ALL, abi.encode(outputCurrency, recipient));
}
}
Loading