-
Notifications
You must be signed in to change notification settings - Fork 254
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
569 additions
and
51 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 |
---|---|---|
@@ -0,0 +1,104 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
/* | ||
* @title Solidity Bytes Arrays Utils | ||
* @author Gonçalo Sá <[email protected]> | ||
* | ||
* @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. | ||
* The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. | ||
*/ | ||
pragma solidity 0.8.12; | ||
|
||
library BytesLib { | ||
function slice( | ||
bytes memory _bytes, | ||
uint256 _start, | ||
uint256 _length | ||
) internal pure returns (bytes memory) { | ||
require(_length + 31 >= _length, "slice_overflow"); | ||
require(_start + _length >= _start, "slice_overflow"); | ||
require(_bytes.length >= _start + _length, "slice_outOfBounds"); | ||
|
||
bytes memory tempBytes; | ||
|
||
assembly { | ||
switch iszero(_length) | ||
case 0 { | ||
// Get a location of some free memory and store it in tempBytes as | ||
// Solidity does for memory variables. | ||
tempBytes := mload(0x40) | ||
|
||
// The first word of the slice result is potentially a partial | ||
// word read from the original array. To read it, we calculate | ||
// the length of that partial word and start copying that many | ||
// bytes into the array. The first word we copy will start with | ||
// data we don't care about, but the last `lengthmod` bytes will | ||
// land at the beginning of the contents of the new array. When | ||
// we're done copying, we overwrite the full first word with | ||
// the actual length of the slice. | ||
let lengthmod := and(_length, 31) | ||
|
||
// The multiplication in the next line is necessary | ||
// because when slicing multiples of 32 bytes (lengthmod == 0) | ||
// the following copy loop was copying the origin's length | ||
// and then ending prematurely not copying everything it should. | ||
let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) | ||
let end := add(mc, _length) | ||
|
||
for { | ||
// The multiplication in the next line has the same exact purpose | ||
// as the one above. | ||
let cc := add( | ||
add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), | ||
_start | ||
) | ||
} lt(mc, end) { | ||
mc := add(mc, 0x20) | ||
cc := add(cc, 0x20) | ||
} { | ||
mstore(mc, mload(cc)) | ||
} | ||
|
||
mstore(tempBytes, _length) | ||
|
||
//update free-memory pointer | ||
//allocating the array padded to 32 bytes like the compiler does now | ||
mstore(0x40, and(add(mc, 31), not(31))) | ||
} | ||
//if we want a zero-length slice let's just return a zero-length array | ||
default { | ||
tempBytes := mload(0x40) | ||
//zero out the 32 bytes slice we are about to return | ||
//we need to do it because Solidity does not garbage collect | ||
mstore(tempBytes, 0) | ||
|
||
mstore(0x40, add(tempBytes, 0x20)) | ||
} | ||
} | ||
|
||
return tempBytes; | ||
} | ||
|
||
function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { | ||
require(_start + 20 >= _start, "toAddress_overflow"); | ||
require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); | ||
address tempAddress; | ||
|
||
assembly { | ||
tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) | ||
} | ||
|
||
return tempAddress; | ||
} | ||
|
||
function toUint24(bytes memory _bytes, uint256 _start) internal pure returns (uint24) { | ||
require(_start + 3 >= _start, "toUint24_overflow"); | ||
require(_bytes.length >= _start + 3, "toUint24_outOfBounds"); | ||
uint24 tempUint; | ||
|
||
assembly { | ||
tempUint := mload(add(add(_bytes, 0x3), _start)) | ||
} | ||
|
||
return tempUint; | ||
} | ||
} |
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,35 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
pragma solidity 0.8.12; | ||
|
||
import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; | ||
Check warning on line 4 in contracts/callers/helpers/uniswap/CallbackValidation.sol GitHub Actions / lint
|
||
import "./PoolAddress.sol"; | ||
Check warning on line 5 in contracts/callers/helpers/uniswap/CallbackValidation.sol GitHub Actions / lint
|
||
|
||
/// @notice Provides validation for callbacks from Uniswap V3 Pools | ||
library CallbackValidation { | ||
/// @notice Returns the address of a valid Uniswap V3 Pool | ||
/// @param factory The contract address of the Uniswap V3 factory | ||
/// @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 factory, | ||
address tokenA, | ||
address tokenB, | ||
uint24 fee | ||
) internal view returns (IUniswapV3Pool pool) { | ||
return verifyCallback(factory, PoolAddress.getPoolKey(tokenA, tokenB, fee)); | ||
} | ||
|
||
/// @notice Returns the address of a valid Uniswap V3 Pool | ||
/// @param factory The contract address of the Uniswap V3 factory | ||
/// @param poolKey The identifying key of the V3 pool | ||
/// @return pool The V3 pool contract address | ||
function verifyCallback( | ||
address factory, | ||
PoolAddress.PoolKey memory poolKey | ||
) internal view returns (IUniswapV3Pool pool) { | ||
pool = IUniswapV3Pool(PoolAddress.computeAddress(factory, poolKey)); | ||
require(msg.sender == address(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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
pragma solidity 0.8.12; | ||
|
||
import "./BytesLib.sol"; | ||
|
||
/// @title Functions for manipulating path data for multihop swaps | ||
library Path { | ||
using BytesLib for bytes; | ||
|
||
/// @dev The length of the bytes encoded address | ||
uint256 private constant ADDR_SIZE = 20; | ||
/// @dev The length of the bytes encoded fee | ||
uint256 private constant FEE_SIZE = 3; | ||
|
||
/// @dev The offset of a single token address and pool fee | ||
uint256 private constant NEXT_OFFSET = ADDR_SIZE + FEE_SIZE; | ||
|
||
/// @notice Decodes the first pool in path | ||
/// @param path The bytes encoded swap path | ||
/// @return tokenA The first token of the given pool | ||
/// @return tokenB The second token of the given pool | ||
/// @return fee The fee level of the pool | ||
function decodeFirstPool( | ||
bytes memory path | ||
) internal pure returns (address tokenA, address tokenB, uint24 fee) { | ||
tokenA = path.toAddress(0); | ||
fee = path.toUint24(ADDR_SIZE); | ||
tokenB = path.toAddress(NEXT_OFFSET); | ||
} | ||
} |
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,54 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
pragma solidity 0.8.12; | ||
|
||
/// @title Provides functions for deriving a pool address from the factory, tokens, and the fee | ||
library PoolAddress { | ||
bytes32 internal constant POOL_INIT_CODE_HASH = | ||
0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54; | ||
|
||
/// @notice The identifying key of the pool | ||
struct PoolKey { | ||
address token0; | ||
address token1; | ||
uint24 fee; | ||
} | ||
|
||
/// @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 Poolkey The pool details with ordered token0 and token1 assignments | ||
function getPoolKey( | ||
address tokenA, | ||
address tokenB, | ||
uint24 fee | ||
) internal pure returns (PoolKey memory) { | ||
if (tokenA > tokenB) (tokenA, tokenB) = (tokenB, tokenA); | ||
return PoolKey({ token0: tokenA, token1: tokenB, fee: fee }); | ||
} | ||
|
||
/// @notice Deterministically computes the pool address given the factory and PoolKey | ||
/// @param factory The Uniswap V3 factory contract address | ||
/// @param key The PoolKey | ||
/// @return pool The contract address of the V3 pool | ||
function computeAddress( | ||
address factory, | ||
PoolKey memory key | ||
) internal pure returns (address pool) { | ||
require(key.token0 < key.token1); | ||
pool = address( | ||
uint160( | ||
uint256( | ||
keccak256( | ||
abi.encodePacked( | ||
hex"ff", | ||
factory, | ||
keccak256(abi.encode(key.token0, key.token1, key.fee)), | ||
POOL_INIT_CODE_HASH | ||
) | ||
) | ||
) | ||
) | ||
); | ||
} | ||
} |
Oops, something went wrong.