-
Notifications
You must be signed in to change notification settings - Fork 14
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/multi quoter not isolation #57
Merged
Merged
Changes from 16 commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
9f4a4da
feat: Support not isolate for v4 CL swap
ChefSnoopy 682c890
feat: Support not isolate for v2, v3 , SS2
ChefSnoopy afcec65
feat: Add test cases for v2 , SS2
ChefSnoopy b379162
feat: Add v2 and SS test cases
ChefSnoopy 7000dd5
feat: Rename SWAP_V4_LIST
ChefSnoopy 12b1882
feat: Add v3 test cases
ChefSnoopy 574d878
feat: Support not isolation for bin pools
ChefSnoopy dfaf8d2
feat: Add v3 swap test cases
ChefSnoopy bc76905
feat: Remove console import
ChefSnoopy e34124c
feat: Remove useless functions
ChefSnoopy e4de30b
feat: Add multiple route test cases
ChefSnoopy cb8c575
feat: Refactor codes
ChefSnoopy 54b2237
fix: Update setPoolSwapTokenAccumulation
ChefSnoopy 6f53be5
feat: Optimize quoteExactInputSingleV2 with accumulation
ChefSnoopy 8e3a7e0
feat: Update test cases
ChefSnoopy 7ad1c7c
feat: Update MixedQuoterRecorder
ChefSnoopy 6d349e2
feat: Rename quoteMixedExactInputSharedContext
ChefSnoopy File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
pragma solidity 0.8.26; | ||
|
||
import {PoolKey} from "pancake-v4-core/src/types/PoolKey.sol"; | ||
|
||
/// @dev Record all token accumulation and swap direction of the transaction for non-v4 pools. | ||
/// @dev Record v4 swap history list for v4 pools. | ||
library MixedQuoterRecorder { | ||
/// @dev uint256 internal constant SWAP_DIRECTION = uint256(keccak256("MIXED_QUOTER_SWAP_DIRECTION")) - 1; | ||
uint256 internal constant SWAP_DIRECTION = 0x420071594cddc2905acbd674683749db4c139d373cc290ba8d49c75296a9f1f9; | ||
|
||
/// @dev uint256 internal constant SWAP_TOKEN0_ACCUMULATION = uint256(keccak256("MIXED_QUOTER_SWAP_TOKEN0_ACCUMULATION")) - 1; | ||
uint256 internal constant SWAP_TOKEN0_ACCUMULATION = | ||
0x6859b060ba2f84c00df66c40e8848222c89b2fcc89d5edc84074b9878818ea86; | ||
|
||
/// @dev uint256 internal constant SWAP_TOKEN1_ACCUMULATION = uint256(keccak256("MIXED_QUOTER_SWAP_TOKEN1_ACCUMULATION")) - 1; | ||
uint256 internal constant SWAP_TOKEN1_ACCUMULATION = | ||
0x8039a0cfe43b448f327ddf378771d67fba431d4dbc5c8f9531fa80f8a45125e9; | ||
|
||
/// @dev uint256 internal SWAP_SS = uint256(keccak256("MIXED_QUOTER_SWAP_SS")) - 1; | ||
uint256 internal constant SWAP_SS = 0x0b6c8b64c3ab4ac7b96ca59ae1454278ba2d62c99873c03d98ae968df846210a; | ||
|
||
/// @dev uint256 internal SWAP_V2 = uint256(keccak256("MIXED_QUOTER_SWAP_V2")) - 1; | ||
uint256 internal constant SWAP_V2 = 0xfb50ad98219c08ac49c2f2012c28ee455be42a0adc9a9a5df9e0882de4cf56b5; | ||
|
||
/// @dev uint256 internal constant SWAP_V3 = uint256(keccak256("MIXED_QUOTER_SWAP_V3")) - 1; | ||
uint256 internal constant SWAP_V3 = 0xd9d373c35d602baa7832c86d4af60fe46a2e18634c87bebc20d0050afb7633b3; | ||
|
||
/// @dev uint256 internal constant SWAP_V4_CL = uint256(keccak256("MIXED_QUOTER_SWAP_V4_CL")) - 1; | ||
uint256 internal constant SWAP_V4_CL = 0x1a7c9a13842b613486d9207eda875c24e33425305b8b8df2e040c19ef2ae3088; | ||
|
||
/// @dev uint256 internal constant SWAP_V4_BIN = uint256(keccak256("MIXED_QUOTER_SWAP_V4_BIN")) - 1; | ||
uint256 internal constant SWAP_V4_BIN = 0xea33987d3dc3e2595aa727354eec3d9b92d4061c1331c4a19f9862248f2e1040; | ||
|
||
/// @dev uint256 internal constant SWAP_V4_LIST = uint256(keccak256("MIXED_QUOTER_SWAP_V4_LIST")) - 1; | ||
uint256 internal constant SWAP_V4_LIST = 0xecc1e5328541d701c0936cbe59876b89db17cc11dfd146412e855a9a2e1ecbd3; | ||
|
||
enum SwapDirection { | ||
NONE, | ||
ZeroForOne, | ||
OneForZero | ||
} | ||
|
||
error INVALID_SWAP_DIRECTION(); | ||
|
||
/// @dev Record and check the swap direction of the transaction. | ||
/// @dev Only support one direction for same non-v4 pool in one transaction. | ||
/// @param poolHash The hash of the pool. | ||
/// @param isZeroForOne The direction of the swap. | ||
function setAndCheckSwapDirection(bytes32 poolHash, bool isZeroForOne) internal { | ||
uint256 swapDirection = isZeroForOne ? uint256(SwapDirection.ZeroForOne) : uint256(SwapDirection.OneForZero); | ||
|
||
uint256 currentDirection = getSwapDirection(poolHash); | ||
if (currentDirection == uint256(SwapDirection.NONE)) { | ||
uint256 directionSlot = uint256(keccak256(abi.encode(poolHash, SWAP_DIRECTION))); | ||
assembly ("memory-safe") { | ||
tstore(directionSlot, swapDirection) | ||
} | ||
} else if (currentDirection != swapDirection) { | ||
revert INVALID_SWAP_DIRECTION(); | ||
} | ||
} | ||
|
||
/// @dev Get the swap direction of the transaction. | ||
/// @param poolHash The hash of the pool. | ||
/// @return swapDirection The direction of the swap. | ||
function getSwapDirection(bytes32 poolHash) internal view returns (uint256 swapDirection) { | ||
uint256 directionSlot = uint256(keccak256(abi.encode(poolHash, SWAP_DIRECTION))); | ||
assembly ("memory-safe") { | ||
swapDirection := tload(directionSlot) | ||
} | ||
} | ||
|
||
/// @dev Record the swap token accumulation of the pool. | ||
/// @param poolHash The hash of the pool. | ||
/// @param amountIn The amount of tokenIn. | ||
/// @param amountOut The amount of tokenOut. | ||
/// @param isZeroForOne The direction of the swap. | ||
function setPoolSwapTokenAccumulation(bytes32 poolHash, uint256 amountIn, uint256 amountOut, bool isZeroForOne) | ||
internal | ||
{ | ||
uint256 token0Slot = uint256(keccak256(abi.encode(poolHash, SWAP_TOKEN0_ACCUMULATION))); | ||
uint256 token1Slot = uint256(keccak256(abi.encode(poolHash, SWAP_TOKEN1_ACCUMULATION))); | ||
uint256 amount0; | ||
uint256 amount1; | ||
if (isZeroForOne) { | ||
amount0 = amountIn; | ||
amount1 = amountOut; | ||
} else { | ||
amount0 = amountOut; | ||
amount1 = amountIn; | ||
} | ||
assembly ("memory-safe") { | ||
tstore(token0Slot, amount0) | ||
tstore(token1Slot, amount1) | ||
} | ||
} | ||
|
||
// @dev Get the swap token accumulation of the pool. | ||
// @param poolHash The hash of the pool. | ||
// @param isZeroForOne The direction of the swap. | ||
// @return accAmountIn The accumulation amount of tokenIn. | ||
// @return accAmountOut The accumulation amount of tokenOut. | ||
function getPoolSwapTokenAccumulation(bytes32 poolHash, bool isZeroForOne) | ||
internal | ||
view | ||
returns (uint256, uint256) | ||
{ | ||
uint256 token0Slot = uint256(keccak256(abi.encode(poolHash, SWAP_TOKEN0_ACCUMULATION))); | ||
uint256 token1Slot = uint256(keccak256(abi.encode(poolHash, SWAP_TOKEN1_ACCUMULATION))); | ||
uint256 amount0; | ||
uint256 amount1; | ||
assembly ("memory-safe") { | ||
amount0 := tload(token0Slot) | ||
amount1 := tload(token1Slot) | ||
} | ||
if (isZeroForOne) { | ||
return (amount0, amount1); | ||
} else { | ||
return (amount1, amount0); | ||
} | ||
} | ||
|
||
/// @dev Record the swap history list of the v4 pool. | ||
/// @param poolHash The hash of the pool. | ||
/// @param swapListBytes The swap history list bytes. | ||
function setV4PoolSwapList(bytes32 poolHash, bytes memory swapListBytes) internal { | ||
uint256 swapListSlot = uint256(keccak256(abi.encode(poolHash, SWAP_V4_LIST))); | ||
assembly ("memory-safe") { | ||
// save the length of the bytes | ||
tstore(swapListSlot, mload(swapListBytes)) | ||
|
||
// save data in next slot | ||
let dataSlot := add(swapListSlot, 1) | ||
for { let i := 0 } lt(i, mload(swapListBytes)) { i := add(i, 32) } { | ||
tstore(add(dataSlot, div(i, 32)), mload(add(swapListBytes, add(0x20, i)))) | ||
} | ||
} | ||
} | ||
|
||
/// @dev Get the swap history list of the v4 pool. | ||
/// @param poolHash The hash of the pool. | ||
/// @return swapListBytes The swap history list bytes. | ||
function getV4PoolSwapList(bytes32 poolHash) internal view returns (bytes memory swapListBytes) { | ||
uint256 swapListSlot = uint256(keccak256(abi.encode(poolHash, SWAP_V4_LIST))); | ||
assembly ("memory-safe") { | ||
// get the length of the bytes | ||
let length := tload(swapListSlot) | ||
swapListBytes := mload(0x40) | ||
mstore(swapListBytes, length) | ||
let dataSlot := add(swapListSlot, 1) | ||
for { let i := 0 } lt(i, length) { i := add(i, 32) } { | ||
mstore(add(swapListBytes, add(0x20, i)), tload(add(dataSlot, div(i, 32)))) | ||
} | ||
mstore(0x40, add(swapListBytes, add(0x20, length))) | ||
} | ||
} | ||
|
||
/// @dev Get the stable swap pool hash. | ||
/// @param token0 The address of token0. | ||
/// @param token1 The address of token1. | ||
/// @return poolHash The hash of the pool. | ||
function getSSPoolHash(address token0, address token1) internal pure returns (bytes32) { | ||
if (token0 == token1) revert(); | ||
(token0, token1) = token0 < token1 ? (token0, token1) : (token1, token0); | ||
return keccak256(abi.encode(token0, token1, SWAP_SS)); | ||
} | ||
|
||
/// @dev Get the v2 pool hash. | ||
/// @param token0 The address of token0. | ||
/// @param token1 The address of token1. | ||
/// @return poolHash The hash of the pool. | ||
function getV2PoolHash(address token0, address token1) internal pure returns (bytes32) { | ||
if (token0 == token1) revert(); | ||
(token0, token1) = token0 < token1 ? (token0, token1) : (token1, token0); | ||
return keccak256(abi.encode(token0, token1, SWAP_V2)); | ||
} | ||
|
||
/// @dev Get the v3 pool hash. | ||
/// @param token0 The address of token0. | ||
/// @param token1 The address of token1. | ||
/// @param fee The fee of the pool. | ||
function getV3PoolHash(address token0, address token1, uint24 fee) internal pure returns (bytes32) { | ||
if (token0 == token1) revert(); | ||
(token0, token1) = token0 < token1 ? (token0, token1) : (token1, token0); | ||
return keccak256(abi.encode(token0, token1, fee, SWAP_V3)); | ||
} | ||
|
||
/// @dev Get the v4 cl pool hash. | ||
/// @param key The pool key. | ||
/// @return poolHash The hash of the pool. | ||
function getV4CLPoolHash(PoolKey memory key) internal pure returns (bytes32) { | ||
return keccak256(abi.encode(key, SWAP_V4_CL)); | ||
} | ||
|
||
/// @dev Get the v4 bin pool hash. | ||
/// @param key The pool key. | ||
/// @return poolHash The hash of the pool. | ||
function getV4BinPoolHash(PoolKey memory key) internal pure returns (bytes32) { | ||
return keccak256(abi.encode(key, SWAP_V4_BIN)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
curious, why not directly key.toId() here ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no special reason, just do not want to confuse , and keep same style with other pools