-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #29 from Aperture-Finance/pcs-dev
Add support for PancakeSwapV3
- Loading branch information
Showing
19 changed files
with
602 additions
and
108 deletions.
There are no files selected for viewing
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 |
---|---|---|
@@ -1,4 +1,5 @@ | ||
@openzeppelin/=node_modules/@openzeppelin/ | ||
@pancakeswap/=node_modules/@pancakeswap/ | ||
@uniswap/=node_modules/@uniswap/ | ||
forge-std/=lib/forge-std/src/ | ||
solady/=node_modules/solady/ |
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,44 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
pragma solidity >=0.5.0; | ||
|
||
import "@pancakeswap/v3-core/contracts/interfaces/IPancakeV3Pool.sol"; | ||
import "./PoolAddressPancakeSwapV3.sol"; | ||
|
||
/// @notice Provides validation for callbacks from PancakeSwapV3 Pools | ||
/// @author Aperture Finance | ||
/// @author Modified from PancakeSwapV3 (https://www.npmjs.com/package/@pancakeswap/v3-periphery?activeTab=code and look for contracts/libraries/CallbackValidation.sol) | ||
library CallbackValidationPancakeSwapV3 { | ||
/// @notice Returns the address of a valid PancakeSwapV3 Pool | ||
/// @param deployer The contract address of the PancakeSwapV3 deployer | ||
/// @param tokenA The contract address of either token0 or token1 | ||
/// @param tokenB The contract address of the other token | ||
/// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip | ||
/// @return pool The V3 pool contract address | ||
function verifyCallback( | ||
address deployer, | ||
address tokenA, | ||
address tokenB, | ||
uint24 fee | ||
) internal view returns (IPancakeV3Pool pool) { | ||
pool = IPancakeV3Pool(PoolAddressPancakeSwapV3.computeAddress(deployer, tokenA, tokenB, fee)); | ||
require(msg.sender == address(pool)); | ||
} | ||
|
||
/// @notice Returns the address of a valid PancakeSwapV3 Pool | ||
/// @param deployer The contract address of the PancakeSwapV3 deployer | ||
/// @param poolKey The identifying key of the V3 pool | ||
/// @return pool The V3 pool contract address | ||
function verifyCallback(address deployer, PoolKey memory poolKey) internal view returns (IPancakeV3Pool pool) { | ||
pool = IPancakeV3Pool(PoolAddressPancakeSwapV3.computeAddressSorted(deployer, poolKey)); | ||
require(msg.sender == address(pool)); | ||
} | ||
|
||
/// @notice Returns the address of a valid PancakeSwapV3 Pool | ||
/// @param deployer The contract address of the PancakeSwapV3 deployer | ||
/// @param poolKey The abi encoded PoolKey of the V3 pool | ||
/// @return pool The V3 pool contract address | ||
function verifyCallbackCalldata(address deployer, bytes calldata poolKey) internal view returns (address pool) { | ||
pool = PoolAddressPancakeSwapV3.computeAddressCalldata(deployer, poolKey); | ||
require(msg.sender == pool); | ||
} | ||
} |
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,150 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
pragma solidity >=0.5.0; | ||
|
||
import "./PoolKey.sol"; | ||
import "./TernaryLib.sol"; | ||
|
||
/// @title Provides functions for deriving a pool address from the deployer, tokens, and the fee | ||
/// @author Aperture Finance | ||
/// @author Modified from PancakeSwapV3 (https://www.npmjs.com/package/@pancakeswap/v3-periphery?activeTab=code and look for contracts/libraries/PoolAddress.sol) | ||
/// @dev Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. | ||
/// However, this is safe because "Note that you do not need to update the free memory pointer if there is no following | ||
/// allocation, but you can only use memory starting from the current offset given by the free memory pointer." | ||
/// according to https://docs.soliditylang.org/en/latest/assembly.html#memory-safety. | ||
library PoolAddressPancakeSwapV3 { | ||
bytes32 internal constant POOL_INIT_CODE_HASH = 0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2; | ||
|
||
/// @notice Returns PoolKey: the ordered tokens with the matched fee levels | ||
/// @param tokenA The first token of a pool, unsorted | ||
/// @param tokenB The second token of a pool, unsorted | ||
/// @param fee The fee level of the pool | ||
/// @return key The pool details with ordered token0 and token1 assignments | ||
function getPoolKey(address tokenA, address tokenB, uint24 fee) internal pure returns (PoolKey memory key) { | ||
(tokenA, tokenB) = TernaryLib.sort2(tokenA, tokenB); | ||
/// @solidity memory-safe-assembly | ||
assembly { | ||
// Must inline this for best performance | ||
mstore(key, tokenA) | ||
mstore(add(key, 0x20), tokenB) | ||
mstore(add(key, 0x40), fee) | ||
} | ||
} | ||
|
||
/// @notice Returns PoolKey: the ordered tokens with the matched fee levels | ||
/// @param token0 The first token of a pool, already sorted | ||
/// @param token1 The second token of a pool, already sorted | ||
/// @param fee The fee level of the pool | ||
/// @return key The pool details with ordered token0 and token1 assignments | ||
function getPoolKeySorted(address token0, address token1, uint24 fee) internal pure returns (PoolKey memory key) { | ||
/// @solidity memory-safe-assembly | ||
assembly { | ||
mstore(key, token0) | ||
mstore(add(key, 0x20), token1) | ||
mstore(add(key, 0x40), fee) | ||
} | ||
} | ||
|
||
/// @notice Deterministically computes the pool address given the deployer and PoolKey | ||
/// @param deployer The PancakeSwapV3 deployer contract address | ||
/// @param key The PoolKey | ||
/// @return pool The contract address of the V3 pool | ||
function computeAddress(address deployer, PoolKey memory key) internal pure returns (address pool) { | ||
require(key.token0 < key.token1); | ||
return computeAddressSorted(deployer, key); | ||
} | ||
|
||
/// @notice Deterministically computes the pool address given the deployer and PoolKey | ||
/// @dev Assumes PoolKey is sorted | ||
/// @param deployer The PancakeSwapV3 deployer contract address | ||
/// @param key The PoolKey | ||
/// @return pool The contract address of the V3 pool | ||
function computeAddressSorted(address deployer, PoolKey memory key) internal pure returns (address pool) { | ||
/// @solidity memory-safe-assembly | ||
assembly { | ||
// Cache the free memory pointer. | ||
let fmp := mload(0x40) | ||
// abi.encodePacked(hex'ff', deployer, poolHash, POOL_INIT_CODE_HASH) | ||
// Prefix the deployer address with 0xff. | ||
mstore(0, or(deployer, 0xff0000000000000000000000000000000000000000)) | ||
mstore(0x20, keccak256(key, 0x60)) | ||
mstore(0x40, POOL_INIT_CODE_HASH) | ||
// Compute the CREATE2 pool address and clean the upper bits. | ||
pool := and(keccak256(0x0b, 0x55), 0xffffffffffffffffffffffffffffffffffffffff) | ||
// Restore the free memory pointer. | ||
mstore(0x40, fmp) | ||
} | ||
} | ||
|
||
/// @notice Deterministically computes the pool address given the deployer, tokens, and the fee | ||
/// @param deployer The PancakeSwapV3 deployer contract address | ||
/// @param tokenA One of the tokens in the pool, unsorted | ||
/// @param tokenB The other token in the pool, unsorted | ||
/// @param fee The fee tier of the pool | ||
function computeAddress( | ||
address deployer, | ||
address tokenA, | ||
address tokenB, | ||
uint24 fee | ||
) internal pure returns (address pool) { | ||
(tokenA, tokenB) = TernaryLib.sort2(tokenA, tokenB); | ||
return computeAddressSorted(deployer, tokenA, tokenB, fee); | ||
} | ||
|
||
/// @notice Deterministically computes the pool address given the deployer, tokens, and the fee | ||
/// @dev Assumes tokens are sorted | ||
/// @param deployer The PancakeSwapV3 deployer contract address | ||
/// @param token0 The first token of a pool, already sorted | ||
/// @param token1 The second token of a pool, already sorted | ||
/// @param fee The fee tier of the pool | ||
function computeAddressSorted( | ||
address deployer, | ||
address token0, | ||
address token1, | ||
uint24 fee | ||
) internal pure returns (address pool) { | ||
/// @solidity memory-safe-assembly | ||
assembly { | ||
// Cache the free memory pointer. | ||
let fmp := mload(0x40) | ||
// Hash the pool key. | ||
mstore(0, token0) | ||
mstore(0x20, token1) | ||
mstore(0x40, fee) | ||
let poolHash := keccak256(0, 0x60) | ||
// abi.encodePacked(hex'ff', deployer, poolHash, POOL_INIT_CODE_HASH) | ||
// Prefix the deployer address with 0xff. | ||
mstore(0, or(deployer, 0xff0000000000000000000000000000000000000000)) | ||
mstore(0x20, poolHash) | ||
mstore(0x40, POOL_INIT_CODE_HASH) | ||
// Compute the CREATE2 pool address and clean the upper bits. | ||
pool := and(keccak256(0x0b, 0x55), 0xffffffffffffffffffffffffffffffffffffffff) | ||
// Restore the free memory pointer. | ||
mstore(0x40, fmp) | ||
} | ||
} | ||
|
||
/// @notice Deterministically computes the pool address given the deployer and PoolKey | ||
/// @dev Uses PoolKey in calldata and assumes PoolKey is sorted | ||
/// @param deployer The PancakeSwapV3 deployer contract address | ||
/// @param key The abi encoded PoolKey of the V3 pool | ||
/// @return pool The contract address of the V3 pool | ||
function computeAddressCalldata(address deployer, bytes calldata key) internal pure returns (address pool) { | ||
/// @solidity memory-safe-assembly | ||
assembly { | ||
// Cache the free memory pointer. | ||
let fmp := mload(0x40) | ||
// Hash the pool key. | ||
calldatacopy(0, key.offset, 0x60) | ||
let poolHash := keccak256(0, 0x60) | ||
// abi.encodePacked(hex'ff', deployer, poolHash, POOL_INIT_CODE_HASH) | ||
// Prefix the deployer address with 0xff. | ||
mstore(0, or(deployer, 0xff0000000000000000000000000000000000000000)) | ||
mstore(0x20, poolHash) | ||
mstore(0x40, POOL_INIT_CODE_HASH) | ||
// Compute the CREATE2 pool address and clean the upper bits. | ||
pool := and(keccak256(0x0b, 0x55), 0xffffffffffffffffffffffffffffffffffffffff) | ||
// Restore the free memory pointer. | ||
mstore(0x40, fmp) | ||
} | ||
} | ||
} |
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,9 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
pragma solidity >=0.5.0; | ||
|
||
/// @notice The identifying key of a liquidity pool | ||
struct PoolKey { | ||
address token0; | ||
address token1; | ||
uint24 fee; | ||
} |
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,30 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.7.6; | ||
pragma abicoder v2; | ||
|
||
import "@pancakeswap/v3-periphery/contracts/libraries/PoolAddress.sol"; | ||
import "./interfaces/IPoolAddress.sol"; | ||
|
||
/// @dev Expose internal functions to test the PoolAddress library. | ||
contract PoolAddressPancakeSwapV3Test is IPoolAddress { | ||
function getPoolKey( | ||
address tokenA, | ||
address tokenB, | ||
uint24 fee | ||
) external pure override returns (PoolKey memory key) { | ||
PoolAddress.PoolKey memory _key = PoolAddress.getPoolKey(tokenA, tokenB, fee); | ||
/// @solidity memory-safe-assembly | ||
assembly { | ||
key := _key | ||
} | ||
} | ||
|
||
function computeAddress(address deployer, PoolKey memory key) external pure override returns (address pool) { | ||
PoolAddress.PoolKey memory _key; | ||
/// @solidity memory-safe-assembly | ||
assembly { | ||
_key := key | ||
} | ||
return PoolAddress.computeAddress(deployer, _key); | ||
} | ||
} |
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.