Skip to content

Commit

Permalink
Merge pull request #37 from shuhuiluo/safecast
Browse files Browse the repository at this point in the history
perf: Optimize `SafeCast` and test `TernaryLib`
  • Loading branch information
gnarlycow authored Jul 30, 2024
2 parents a36e87d + b144924 commit 063251c
Show file tree
Hide file tree
Showing 10 changed files with 291 additions and 162 deletions.
215 changes: 116 additions & 99 deletions .gas-snapshot

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@aperture_finance/uni-v3-lib",
"description": "A suite of Solidity libraries that have been imported and rewritten from Uniswap's v3-core and v3-periphery",
"version": "3.0.2",
"version": "3.0.3",
"author": "Aperture Finance",
"homepage": "https://aperture.finance/",
"license": "GPL-2.0-or-later",
Expand Down Expand Up @@ -51,4 +51,4 @@
"endOfLine": "lf",
"printWidth": 120
}
}
}
79 changes: 28 additions & 51 deletions src/SafeCast.sol
Original file line number Diff line number Diff line change
@@ -1,73 +1,50 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.4;
// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;

/// @title Safe casting methods
/// @author Aperture Finance
/// @author Modified from Uniswap (https://github.com/uniswap/v3-core/blob/main/contracts/libraries/SafeCast.sol)
/// @notice Contains methods for safely casting between types
library SafeCast {
/// @notice Cast a uint256 to a uint160, revert on overflow
/// @param y The uint256 to be downcasted
/// @return z The downcasted integer, now type uint160
function toUint160(uint256 y) internal pure returns (uint160 z) {
/// @solidity memory-safe-assembly
assembly {
if shr(160, y) {
revert(0, 0)
}
z := y
}
/// @param x The uint256 to be downcasted
/// @return The downcasted integer, now type uint160
function toUint160(uint256 x) internal pure returns (uint160) {
if (x >= 1 << 160) revert();
return uint160(x);
}

/// @notice Cast a uint256 to a uint128, revert on overflow
/// @param y The uint256 to be downcasted
/// @return z The downcasted integer, now type uint128
function toUint128(uint256 y) internal pure returns (uint128 z) {
/// @solidity memory-safe-assembly
assembly {
if shr(128, y) {
revert(0, 0)
}
z := y
}
/// @param x The uint256 to be downcasted
/// @return The downcasted integer, now type uint128
function toUint128(uint256 x) internal pure returns (uint128) {
if (x >= 1 << 128) revert();
return uint128(x);
}

/// @notice Cast a int256 to a int128, revert on overflow or underflow
/// @param y The int256 to be downcasted
/// @return z The downcasted integer, now type int128
function toInt128(int256 y) internal pure returns (int128 z) {
/// @solidity memory-safe-assembly
assembly {
if sub(y, signextend(15, y)) {
revert(0, 0)
}
z := y
/// @param x The int256 to be downcasted
/// @return The downcasted integer, now type int128
function toInt128(int256 x) internal pure returns (int128) {
unchecked {
if (((1 << 127) + uint256(x)) >> 128 == uint256(0)) return int128(x);
revert();
}
}

/// @notice Cast a uint256 to a int256, revert on overflow
/// @param y The uint256 to be casted
/// @return z The casted integer, now type int256
function toInt256(uint256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
if slt(y, 0) {
revert(0, 0)
}
z := y
}
/// @param x The uint256 to be casted
/// @return The casted integer, now type int256
function toInt256(uint256 x) internal pure returns (int256) {
if (int256(x) >= 0) return int256(x);
revert();
}

/// @notice Cast a uint256 to a int128, revert on overflow
/// @param y The uint256 to be downcasted
/// @return z The downcasted integer, now type int128
function toInt128(uint256 y) internal pure returns (int128 z) {
/// @solidity memory-safe-assembly
assembly {
if shr(127, y) {
revert(0, 0)
}
z := y
}
/// @param x The uint256 to be downcasted
/// @return The downcasted integer, now type int128
function toInt128(uint256 x) internal pure returns (int128) {
if (x >= 1 << 127) revert();
return int128(int256(x));
}
}
2 changes: 1 addition & 1 deletion test/NPMCaller.t.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import {LiquidityAmounts} from "src/LiquidityAmounts.sol";
import "src/NPMCaller.sol";
import "./Base.t.sol";
Expand Down
4 changes: 2 additions & 2 deletions test/PoolCaller.t.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@pancakeswap/v3-core/contracts/interfaces/IPancakeV3Pool.sol";
import "src/PoolCaller.sol";
import {IPancakeV3Pool} from "@pancakeswap/v3-core/contracts/interfaces/IPancakeV3Pool.sol";
import {PoolCaller, V3PoolCallee} from "src/PoolCaller.sol";
import "./Base.t.sol";

/// @dev Expose internal functions to test the PoolCaller library.
Expand Down
4 changes: 2 additions & 2 deletions test/SafeCast.t.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "forge-std/Test.sol";
import "src/SafeCast.sol";
import {Test} from "forge-std/Test.sol";
import {SafeCast} from "src/SafeCast.sol";

contract SafeCastTest is Test {
function testRevert_ToUint160() public {
Expand Down
3 changes: 2 additions & 1 deletion test/SqrtPriceMath.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
pragma solidity ^0.8.0;

import {ISqrtPriceMath} from "src/test/interfaces/ISqrtPriceMath.sol";
import "src/SqrtPriceMath.sol";
import {FullMath} from "src/FullMath.sol";
import {SqrtPriceMath} from "src/SqrtPriceMath.sol";
import "./Base.t.sol";

contract SqrtPriceMathWrapper is ISqrtPriceMath {
Expand Down
133 changes: 133 additions & 0 deletions test/TernaryLib.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {Test} from "forge-std/Test.sol";
import {TernaryLib} from "src/TernaryLib.sol";

/// @dev Test contract for TernaryLib
contract TernaryLibTest is Test {
function test_Ternary() public pure {
assertEq(TernaryLib.ternary(true, 1, 2), 1);
assertEq(TernaryLib.ternary(false, 1, 2), 2);
}

function testFuzz_Ternary(bool condition, uint256 a, uint256 b) public pure {
if (condition) {
assertEq(TernaryLib.ternary(condition, a, b), a);
} else {
assertEq(TernaryLib.ternary(condition, a, b), b);
}
}

function testFuzz_Ternary(bool condition, address a, address b) public pure {
if (condition) {
assertEq(TernaryLib.ternary(condition, a, b), a);
} else {
assertEq(TernaryLib.ternary(condition, a, b), b);
}
}

function test_Abs() public pure {
assertEq(TernaryLib.abs(1), 1);
assertEq(TernaryLib.abs(-1), 1);
assertEq(TernaryLib.abs(type(int256).min), 1 << 255);
}

function testFuzz_Abs(int256 x) public pure {
vm.assume(x != type(int256).min);
if (x >= 0) {
assertEq(TernaryLib.abs(x), uint256(x));
} else {
assertEq(TernaryLib.abs(x), uint256(-x));
}
}

function test_AbsDiff() public pure {
assertEq(TernaryLib.absDiff(1, 2), 1);
assertEq(TernaryLib.absDiff(2, 1), 1);
}

function testFuzz_AbsDiff(uint256 a, uint256 b) public pure {
if (a > b) {
assertEq(TernaryLib.absDiff(a, b), a - b);
} else {
assertEq(TernaryLib.absDiff(a, b), b - a);
}
}

function test_AbsDiffU160() public pure {
assertEq(TernaryLib.absDiffU160(1, 2), 1);
assertEq(TernaryLib.absDiffU160(2, 1), 1);
}

function testFuzz_AbsDiffU160(uint160 a, uint160 b) public pure {
if (a > b) {
assertEq(TernaryLib.absDiffU160(a, b), a - b);
} else {
assertEq(TernaryLib.absDiffU160(a, b), b - a);
}
}

function test_Min() public pure {
assertEq(TernaryLib.min(1, 2), 1);
assertEq(TernaryLib.min(2, 1), 1);
}

function testFuzz_Min(uint256 a, uint256 b) public pure {
if (a < b) {
assertEq(TernaryLib.min(a, b), a);
} else {
assertEq(TernaryLib.min(a, b), b);
}
}

function test_Max() public pure {
assertEq(TernaryLib.max(1, 2), 2);
assertEq(TernaryLib.max(2, 1), 2);
}

function testFuzz_Max(uint256 a, uint256 b) public pure {
if (a > b) {
assertEq(TernaryLib.max(a, b), a);
} else {
assertEq(TernaryLib.max(a, b), b);
}
}

function test_SwitchIf() public pure {
(uint256 a, uint256 b) = TernaryLib.switchIf(true, 1, 2);
assertEq(a, 2);
assertEq(b, 1);
}

function testFuzz_SwitchIf(bool condition, uint256 a, uint256 b) public pure {
(uint256 x, uint256 y) = TernaryLib.switchIf(condition, a, b);
if (condition) {
assertEq(x, b);
assertEq(y, a);
} else {
assertEq(x, a);
assertEq(y, b);
}
}

function test_Sort2() public pure {
(uint256 a, uint256 b) = TernaryLib.sort2(1, 2);
assertEq(a, 1);
assertEq(b, 2);
(a, b) = TernaryLib.sort2(2, 1);
assertEq(a, 1);
assertEq(b, 2);
}

function testFuzz_Sort2(uint256 a, uint256 b) public pure {
(uint256 x, uint256 y) = TernaryLib.sort2(a, b);
if (a < b) {
assertEq(x, a);
assertEq(y, b);
} else {
assertEq(x, b);
assertEq(y, a);
}
}
}
7 changes: 4 additions & 3 deletions test/TickBitmap.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
pragma solidity ^0.8.0;

import {ITickBitmap} from "src/test/interfaces/ITickBitmap.sol";
import "src/TickBitmap.sol";
import {V3PoolCallee} from "src/PoolCaller.sol";
import {TickBitmap} from "src/TickBitmap.sol";
import "./Base.t.sol";

contract TickBitmapWrapper is ITickBitmap {
Expand Down Expand Up @@ -131,7 +132,7 @@ contract TickBitmapTest is BaseTest {
int24 tick;
bool initialized;
for (int16 wordPos = -128; wordPos < 128; ++wordPos) {
uint8 bitPos = uint8(pseudoRandom(uint16(wordPos)) & 255);
uint8 bitPos = uint8(pseudoRandom(uint16(wordPos)) & 0xff);
assembly {
tick := add(shl(8, wordPos), bitPos)
}
Expand All @@ -150,7 +151,7 @@ contract TickBitmapTest is BaseTest {
int24 tick;
bool initialized;
for (int16 wordPos = -128; wordPos < 128; ++wordPos) {
uint8 bitPos = uint8(pseudoRandom(uint16(wordPos)) & 255);
uint8 bitPos = uint8(pseudoRandom(uint16(wordPos)) & 0xff);
assembly {
tick := add(shl(8, wordPos), bitPos)
}
Expand Down
2 changes: 1 addition & 1 deletion test/TickMath.t.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {Test} from "forge-std/Test.sol";
import {ITickMath} from "src/test/interfaces/ITickMath.sol";
import {TickMath} from "src/TickMath.sol";
import "./Base.t.sol";

contract TickMathWrapper is ITickMath {
function getSqrtRatioAtTick(int24 tick) external pure returns (uint160 sqrtPriceX96) {
Expand Down

0 comments on commit 063251c

Please sign in to comment.