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

feat: abstract router #86

Merged
merged 106 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
106 commits
Select commit Hold shift + click to select a range
6313eb5
add PoolTicksCounter library
ConjunctiveNormalForm Nov 6, 2023
664c4ff
quoter exact input single
ConjunctiveNormalForm Nov 7, 2023
d67f597
quoter test
ConjunctiveNormalForm Nov 7, 2023
ee84418
return deltas instead
ConjunctiveNormalForm Nov 10, 2023
d68e464
safe casting to correct types
ConjunctiveNormalForm Nov 11, 2023
bc381b0
QuoteExactInput skeleton
ConjunctiveNormalForm Nov 11, 2023
3bd47d9
multiple entries
ConjunctiveNormalForm Nov 11, 2023
f75b87a
break handleRevert by type
ConjunctiveNormalForm Nov 12, 2023
a69c782
quoteExactInput and unit tests
ConjunctiveNormalForm Nov 15, 2023
4f9519f
more QuoteExactInput tests
ConjunctiveNormalForm Nov 15, 2023
7823167
remove lgos
ConjunctiveNormalForm Nov 15, 2023
e2d0c22
remove commented out struct
ConjunctiveNormalForm Nov 15, 2023
6ba70f4
via-ir in ci
ConjunctiveNormalForm Nov 15, 2023
b093a78
remove unused imports/functions
ConjunctiveNormalForm Nov 16, 2023
69c2c5b
store iteration params locally instead of editing function input
ConjunctiveNormalForm Nov 16, 2023
20af595
pull out sqrtPriceLimit to its own function
ConjunctiveNormalForm Nov 16, 2023
e3f6c7e
PathKey to its own library
ConjunctiveNormalForm Nov 16, 2023
a8a0ed1
rename initializedTicksCrossed to initializedTicksLoaded
ConjunctiveNormalForm Nov 16, 2023
bd22b11
remove manual abi encoding in yul :p
ConjunctiveNormalForm Nov 16, 2023
1e0277b
fix linter warnings for Quoter
ConjunctiveNormalForm Nov 16, 2023
ca62ec2
natspec for IQuoter
ConjunctiveNormalForm Nov 16, 2023
d526f75
feat: update v4-core
marktoda Nov 16, 2023
3e3ab5d
fix: tests
marktoda Nov 16, 2023
c5b8c22
style fixes
ConjunctiveNormalForm Nov 17, 2023
1d8f14f
inheritdoc
ConjunctiveNormalForm Nov 17, 2023
55db578
ExactInSingleBatch
ConjunctiveNormalForm Nov 17, 2023
4fe142c
fix: update tests
marktoda Nov 17, 2023
15a9c8a
fix: test router was borked
marktoda Nov 17, 2023
f12b2c3
exact out
ConjunctiveNormalForm Nov 18, 2023
0dc0c0b
fix: alice comments
marktoda Nov 20, 2023
3665d41
fix ExactOutput
ConjunctiveNormalForm Nov 20, 2023
f432926
add ExactOput unit tests
ConjunctiveNormalForm Nov 21, 2023
eb3441f
add quoteExactOutputBatch
ConjunctiveNormalForm Nov 21, 2023
94f1a20
remove solhint config
ConjunctiveNormalForm Nov 22, 2023
45fd156
remove newline
ConjunctiveNormalForm Nov 22, 2023
57330b2
add QuoteExactOutput in interface
ConjunctiveNormalForm Nov 22, 2023
c841c34
refactor lockAcquired
ConjunctiveNormalForm Nov 22, 2023
a13509b
move magic numbers to constants + doc
ConjunctiveNormalForm Nov 22, 2023
dcd6471
add more natspec
ConjunctiveNormalForm Nov 22, 2023
9fb0ab4
natspec
ConjunctiveNormalForm Nov 28, 2023
3f0e6a7
named imports
ConjunctiveNormalForm Nov 28, 2023
4a8e57a
self-call branching
ConjunctiveNormalForm Dec 4, 2023
b1c2292
remove old code
ConjunctiveNormalForm Dec 4, 2023
238a23e
remove console2 import
ConjunctiveNormalForm Dec 4, 2023
5daedb0
refactor PathKeyLib
ConjunctiveNormalForm Dec 4, 2023
b6a7373
amountOutCached
ConjunctiveNormalForm Dec 4, 2023
ebac179
inherit ILockCallback
ConjunctiveNormalForm Dec 4, 2023
1912701
add base contracts and interfaces (#75)
tinaszheng Nov 28, 2023
b683fe8
Merge branch 'main' into revert-quoter
ConjunctiveNormalForm Dec 4, 2023
7d123ac
remove unused errors
ConjunctiveNormalForm Dec 4, 2023
7bfcffb
test lockAcquired reverts
ConjunctiveNormalForm Dec 5, 2023
54373b1
remove ...Batch interface
ConjunctiveNormalForm Dec 5, 2023
6ecf72b
REASON -> RESPONSE when valid
ConjunctiveNormalForm Dec 5, 2023
a40476e
complete natspec
ConjunctiveNormalForm Dec 5, 2023
7e7b880
remove SwapInfo imports
ConjunctiveNormalForm Dec 5, 2023
cb15b3e
rename to SwapParameters
ConjunctiveNormalForm Dec 6, 2023
710705b
move quoter structs into IQuoter interface
ConjunctiveNormalForm Dec 6, 2023
311ff6f
update to latest core
snreynolds Dec 11, 2023
5f4b717
use prev values
snreynolds Dec 11, 2023
ffe3b05
change twamm to use pool getters
snreynolds Dec 11, 2023
d559965
Merge branch 'main' into update-v4-core
snreynolds Dec 11, 2023
6a72276
changes after merging main
snreynolds Dec 11, 2023
57183bd
use --via-ir in cli
snreynolds Dec 11, 2023
18d68e8
fix formatting
snreynolds Dec 14, 2023
fead64a
fix FullRange/TWAMM hook
snreynolds Dec 14, 2023
7dc6b82
Merge remote-tracking branch 'origin/update-v4-core' into revert-quoter
ConjunctiveNormalForm Dec 14, 2023
588ffde
update ticks counter
ConjunctiveNormalForm Dec 15, 2023
f6a5516
update Quoter test
ConjunctiveNormalForm Dec 15, 2023
9204cea
typo
ConjunctiveNormalForm Dec 18, 2023
678919f
typo
ConjunctiveNormalForm Dec 18, 2023
b7f737f
simplify handleRevertSingle
ConjunctiveNormalForm Dec 18, 2023
67772de
merge QuoteInput/OutputSingle structs
ConjunctiveNormalForm Dec 18, 2023
fbb6d1b
combine IQuoter structs
ConjunctiveNormalForm Dec 18, 2023
ad3a966
using ... ordering
ConjunctiveNormalForm Dec 18, 2023
b098593
Merge branch 'main' into revert-quoter
ConjunctiveNormalForm Dec 19, 2023
6a7882a
update snapshots
ConjunctiveNormalForm Dec 19, 2023
c772ab2
start routing
ewilz Aug 17, 2023
e33a8cb
start routing contract
ewilz Aug 23, 2023
2a282e4
naive swapExactIn impl
ewilz Aug 24, 2023
849892c
lint + bytecode snapshot
ewilz Aug 30, 2023
dcd2dd3
change concept of hops to token hops
ewilz Aug 31, 2023
5df3e70
UniswapV4Routing --> Routing
ewilz Sep 1, 2023
e0bef3d
use PathKey
ewilz Sep 1, 2023
ac4e706
exactInputSingle
ewilz Sep 1, 2023
aac1d8f
save DRY progress
ewilz Sep 1, 2023
947947b
no sqrtPriceLimit for multipool hops
ewilz Sep 5, 2023
42fca24
exactOut implemented w awkward loops/int conversions
ewilz Sep 5, 2023
aa88f49
gas savings from not doing double negative number
ewilz Sep 5, 2023
8880d1c
gas savings from unchecked math
ewilz Sep 5, 2023
299c35c
add swapExactOuputSingle
ewilz Sep 5, 2023
e4a0f6b
break out structs into interface
ewilz Sep 5, 2023
d78e011
PR comments
ewilz Sep 25, 2023
7f9e098
pass hook data along
ewilz Sep 26, 2023
fa4e7ca
gas and coherency optimization
ewilz Oct 2, 2023
5b6538d
merge Quoter
ConjunctiveNormalForm Dec 11, 2023
5efe6f8
remove SwapIntention
ConjunctiveNormalForm Dec 11, 2023
7e621fa
IV4Router structs
ConjunctiveNormalForm Dec 11, 2023
ac71ea8
remove SwapIntention
ConjunctiveNormalForm Dec 11, 2023
bda8efe
remove logs
ConjunctiveNormalForm Dec 11, 2023
0c14e20
natspec
ConjunctiveNormalForm Dec 18, 2023
47a862e
rebase onto latest core
ConjunctiveNormalForm Dec 18, 2023
9fb824f
simplify function naming
ConjunctiveNormalForm Dec 18, 2023
659d36b
Merge branch 'routing' into routing-zach
hensha256 Jun 26, 2024
a5e4e71
Routing diana (#104)
dianakocsis Jun 28, 2024
72c10b6
merge routing
hensha256 Jun 28, 2024
86993ee
update imports
hensha256 Jun 28, 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/RouterBytecode.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
5027
5925
2 changes: 1 addition & 1 deletion .forge-snapshots/RouterExactIn1Hop.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
195446
101468
2 changes: 1 addition & 1 deletion .forge-snapshots/RouterExactIn2Hops.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
273998
160449
2 changes: 1 addition & 1 deletion .forge-snapshots/RouterExactIn3Hops.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
352561
212680
2 changes: 1 addition & 1 deletion .forge-snapshots/RouterExactInputSingle.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
193868
106771
2 changes: 1 addition & 1 deletion .forge-snapshots/RouterExactOut1Hop.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
194612
102242
2 changes: 1 addition & 1 deletion .forge-snapshots/RouterExactOut2Hops.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
274060
159812
2 changes: 1 addition & 1 deletion .forge-snapshots/RouterExactOut3Hops.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
353539
212732
2 changes: 1 addition & 1 deletion .forge-snapshots/RouterExactOutputSingle.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
193088
105380
78 changes: 39 additions & 39 deletions contracts/V4Router.sol
Original file line number Diff line number Diff line change
@@ -1,59 +1,58 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;

import {Hooks} from "@uniswap/v4-core/contracts/libraries/Hooks.sol";
import {IPoolManager} from "@uniswap/v4-core/contracts/interfaces/IPoolManager.sol";
import {BalanceDelta} from "@uniswap/v4-core/contracts/types/BalanceDelta.sol";
import {PoolKey} from "@uniswap/v4-core/contracts/types/PoolKey.sol";
import {Currency, CurrencyLibrary} from "@uniswap/v4-core/contracts/types/Currency.sol";
import {TickMath} from "@uniswap/v4-core/contracts/libraries/TickMath.sol";
import {IHooks} from "@uniswap/v4-core/contracts/interfaces/IHooks.sol";
import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol";
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
import {IUnlockCallback} from "@uniswap/v4-core/src/interfaces/callback/IUnlockCallback.sol";
import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
import {Currency, CurrencyLibrary} from "@uniswap/v4-core/src/types/Currency.sol";
import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol";
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
import {PathKey} from "./libraries/PathKey.sol";
import {IV4Router} from "./interfaces/IV4Router.sol";

/// @title UniswapV4Routing
/// @title UniswapV4Router
/// @notice Abstract contract that contains all internal logic needed for routing through Uniswap V4 pools
abstract contract V4Router is IV4Router {
using CurrencyLibrary for Currency;

IPoolManager immutable poolManager;

/// @dev Only the pool manager may call this function
modifier poolManagerOnly() {
if (msg.sender != address(poolManager)) revert NotPoolManager();
_;
}

constructor(IPoolManager _poolManager) {
poolManager = _poolManager;
}

function _v4Swap(SwapType swapType, bytes memory params) internal {
poolManager.lock(abi.encode(SwapInfo(swapType, msg.sender, params)));
poolManager.unlock(abi.encode(SwapInfo(swapType, msg.sender, params)));
}

function lockAcquired(bytes calldata encodedSwapInfo) external poolManagerOnly returns (bytes memory) {
/// @inheritdoc IUnlockCallback
function unlockCallback(bytes calldata encodedSwapInfo) external override returns (bytes memory) {
if (msg.sender != address(poolManager)) revert NotPoolManager();

SwapInfo memory swapInfo = abi.decode(encodedSwapInfo, (SwapInfo));

if (swapInfo.swapType == SwapType.ExactInput) {
_swapExactInput(abi.decode(swapInfo.params, (ExactInputParams)), swapInfo.msgSender);
_swapExactInput(abi.decode(swapInfo.params, (IV4Router.ExactInputParams)), swapInfo.msgSender);
ConjunctiveNormalForm marked this conversation as resolved.
Show resolved Hide resolved
} else if (swapInfo.swapType == SwapType.ExactInputSingle) {
_swapExactInputSingle(abi.decode(swapInfo.params, (ExactInputSingleParams)), swapInfo.msgSender);
_swapExactInputSingle(abi.decode(swapInfo.params, (IV4Router.ExactInputSingleParams)), swapInfo.msgSender);
} else if (swapInfo.swapType == SwapType.ExactOutput) {
_swapExactOutput(abi.decode(swapInfo.params, (ExactOutputParams)), swapInfo.msgSender);
_swapExactOutput(abi.decode(swapInfo.params, (IV4Router.ExactOutputParams)), swapInfo.msgSender);
} else if (swapInfo.swapType == SwapType.ExactOutputSingle) {
_swapExactOutputSingle(abi.decode(swapInfo.params, (ExactOutputSingleParams)), swapInfo.msgSender);
_swapExactOutputSingle(abi.decode(swapInfo.params, (IV4Router.ExactOutputSingleParams)), swapInfo.msgSender);
} else {
revert InvalidSwapType();
}

return bytes("");
}

function _swapExactInputSingle(ExactInputSingleParams memory params, address msgSender) private {
_swapExactPrivate(
function _swapExactInputSingle(IV4Router.ExactInputSingleParams memory params, address msgSender) private {

Choose a reason for hiding this comment

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

nit: any reason for private over internal?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think derived contracts would just use the single entry point _swap()?

_swap(
params.poolKey,
params.zeroForOne,
int256(int128(params.amountIn)),
int256(-int128(params.amountIn)),
params.sqrtPriceLimitX96,
msgSender,
true,
Expand All @@ -62,18 +61,18 @@ abstract contract V4Router is IV4Router {
);
}

function _swapExactInput(ExactInputParams memory params, address msgSender) private {
function _swapExactInput(IV4Router.ExactInputParams memory params, address msgSender) private {
unchecked {
uint256 pathLength = params.path.length;
uint128 amountOut;

for (uint256 i = 0; i < pathLength; i++) {
(PoolKey memory poolKey, bool zeroForOne) = _getPoolAndSwapDirection(params.path[i], params.currencyIn);
amountOut = uint128(
-_swapExactPrivate(
_swap(
poolKey,
zeroForOne,
int256(int128(params.amountIn)),
int256(-int128(params.amountIn)),
0,
msgSender,
i == 0,
Expand All @@ -90,11 +89,11 @@ abstract contract V4Router is IV4Router {
}
}

function _swapExactOutputSingle(ExactOutputSingleParams memory params, address msgSender) private {
_swapExactPrivate(
function _swapExactOutputSingle(IV4Router.ExactOutputSingleParams memory params, address msgSender) private {
_swap(
params.poolKey,
params.zeroForOne,
-int256(int128(params.amountOut)),
int256(int128(params.amountOut)),
params.sqrtPriceLimitX96,
msgSender,
true,
Expand All @@ -103,7 +102,7 @@ abstract contract V4Router is IV4Router {
);
}

function _swapExactOutput(ExactOutputParams memory params, address msgSender) private {
function _swapExactOutput(IV4Router.ExactOutputParams memory params, address msgSender) private {
unchecked {
uint256 pathLength = params.path.length;
uint128 amountIn;
Expand All @@ -112,10 +111,10 @@ abstract contract V4Router is IV4Router {
(PoolKey memory poolKey, bool oneForZero) =
_getPoolAndSwapDirection(params.path[i - 1], params.currencyOut);
amountIn = uint128(
_swapExactPrivate(
-_swap(
poolKey,
!oneForZero,
-int256(int128(params.amountOut)),
int256(int128(params.amountOut)),
0,
msgSender,
i == 1,
Expand All @@ -131,7 +130,7 @@ abstract contract V4Router is IV4Router {
}
}

function _swapExactPrivate(
function _swap(
PoolKey memory poolKey,
bool zeroForOne,
int256 amountSpecified,
Expand All @@ -147,20 +146,20 @@ abstract contract V4Router is IV4Router {
zeroForOne,
amountSpecified,
sqrtPriceLimitX96 == 0
? (zeroForOne ? TickMath.MIN_SQRT_RATIO + 1 : TickMath.MAX_SQRT_RATIO - 1)
? (zeroForOne ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1)
: sqrtPriceLimitX96
),
hookData
);

if (zeroForOne) {
reciprocalAmount = amountSpecified > 0 ? delta.amount1() : delta.amount0();
reciprocalAmount = amountSpecified < 0 ? delta.amount1() : delta.amount0();
if (settle) _payAndSettle(poolKey.currency0, msgSender, delta.amount0());
if (take) poolManager.take(poolKey.currency1, msgSender, uint128(-delta.amount1()));
if (take) poolManager.take(poolKey.currency1, msgSender, uint128(delta.amount1()));
} else {
reciprocalAmount = amountSpecified > 0 ? delta.amount0() : delta.amount1();
reciprocalAmount = amountSpecified < 0 ? delta.amount0() : delta.amount1();
if (settle) _payAndSettle(poolKey.currency1, msgSender, delta.amount1());
if (take) poolManager.take(poolKey.currency0, msgSender, uint128(-delta.amount0()));
if (take) poolManager.take(poolKey.currency0, msgSender, uint128(delta.amount0()));
}
}

Expand All @@ -178,7 +177,8 @@ abstract contract V4Router is IV4Router {
}

function _payAndSettle(Currency currency, address msgSender, int128 settleAmount) private {
_pay(Currency.unwrap(currency), msgSender, address(poolManager), uint256(uint128(settleAmount)));
poolManager.sync(currency);
_pay(Currency.unwrap(currency), msgSender, address(poolManager), uint256(uint128(-settleAmount)));
poolManager.settle(currency);
}

Expand Down
2 changes: 1 addition & 1 deletion contracts/hooks/examples/LimitOrder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ contract LimitOrder is BaseHook {
) external selfOnly returns (uint128 amount0Fee, uint128 amount1Fee) {
int24 tickUpper = tickLower + key.tickSpacing;

// because `modifyPosition` includes not just principal value but also fees, we cannot allocate
// because `modifyLiquidity` includes not just principal value but also fees, we cannot allocate
// the proceeds pro-rata. if we were to do so, users who have been in a limit order that's partially filled
// could be unfairly diluted by a user sychronously placing then killing a limit order to skim off fees.
// to prevent this, we allocate all fee revenue to remaining limit order placers, unless this is the last order.
Expand Down
2 changes: 1 addition & 1 deletion contracts/interfaces/IPeripheryPayments.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;
pragma solidity ^0.8.20;

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

Expand Down
29 changes: 10 additions & 19 deletions contracts/interfaces/IV4Router.sol
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;

import "forge-std/console.sol";
import {Hooks} from "@uniswap/v4-core/contracts/libraries/Hooks.sol";
import {IPoolManager} from "@uniswap/v4-core/contracts/interfaces/IPoolManager.sol";
import {BalanceDelta} from "@uniswap/v4-core/contracts/types/BalanceDelta.sol";
import {PoolKey} from "@uniswap/v4-core/contracts/types/PoolKey.sol";
import {Currency, CurrencyLibrary} from "@uniswap/v4-core/contracts/types/Currency.sol";
import {TickMath} from "@uniswap/v4-core/contracts/libraries/TickMath.sol";
import {IHooks} from "@uniswap/v4-core/contracts/interfaces/IHooks.sol";
import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol";
import {IUnlockCallback} from "@uniswap/v4-core/src/interfaces/callback/IUnlockCallback.sol";
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
import {BalanceDelta} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
import {Currency, CurrencyLibrary} from "@uniswap/v4-core/src/types/Currency.sol";
import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol";
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
import {PathKey} from "../libraries/PathKey.sol";

/// @title UniswapV4Routing
/// @notice Abstract contract that contains all internal logic needed for routing through Uniswap V4 pools
interface IV4Router {
interface IV4Router is IUnlockCallback {
error NotPoolManager();
error InvalidSwapType();
error TooLittleReceived();
Expand All @@ -24,14 +25,6 @@ interface IV4Router {
bytes params;
}

struct PathKey {
Currency intermediateCurrency;
uint24 fee;
int24 tickSpacing;
IHooks hooks;
bytes hookData;
}

struct ExactInputSingleParams {
PoolKey poolKey;
bool zeroForOne;
Expand Down Expand Up @@ -74,6 +67,4 @@ interface IV4Router {
ExactOutput,
ExactOutputSingle
}

function lockAcquired(bytes calldata encodedSwapInfo) external returns (bytes memory);
}
2 changes: 1 addition & 1 deletion test/FullRange.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ contract TestFullRange is Test, Deployers, GasSnapshot {
int24 tickSpacing,
IHooks hooks
);
event ModifyPosition(
event ModifyLiquidity(
PoolId indexed poolId, address indexed sender, int24 tickLower, int24 tickUpper, int256 liquidityDelta
);
event Swap(
Expand Down
Loading
Loading