Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
52 changes: 52 additions & 0 deletions src/utils/math/LibTanh.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import {FixedPointMathLib} from "solady/utils/FixedPointMathLib.sol";
import {SafeCastLib} from "solady/utils/SafeCastLib.sol";
import {console2} from "forge-std/console2.sol";
Copy link

Choose a reason for hiding this comment

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

Debug import left in production library code

Low Severity

The console2 import from forge-std is a debugging/testing utility that was left in the production library code. It's imported but never actually used in the library. The forge-std package is a testing framework dependency and this import doesn't belong in production smart contract code.

Fix in Cursor Fix in Web


library LibTanh {
using SafeCastLib for uint256;
using SafeCastLib for int256;
using FixedPointMathLib for int256;
using FixedPointMathLib for uint256;

error TanhOverflow();

int256 private constant MAX_EXP_WAD = 135305999368893231588;

/// @notice Computes the hyperbolic tangent of a number.
/// @param x The number to compute the hyperbolic tangent of.
/// @return The hyperbolic tangent of x.
/// @dev tanh can be computed as (exp(x) - exp(-x)) / (exp(x) + exp(-x))
/// but we need to be careful with overflow: x must be less than 135 * WAD.
/// This function will revert if the calculation overflows.
function tanh(uint256 x) public pure returns (uint256) {
return _tanh(x, true);
}

/// @notice Computes the hyperbolic tangent of a number, with no revert on overflow.
/// @param x The number to compute the hyperbolic tangent of.
/// @return The hyperbolic tangent of x.
/// @dev tanh can be computed as (exp(x) - exp(-x)) / (exp(x) + exp(-x))
/// x must be less than 135 * WAD or the calculation will overflow; this function
/// will return the absolute ceiling of 1e18 in this case.
function rawTanh(uint256 x) public pure returns (uint256) {
return _tanh(x, false);
}

function _tanh(uint256 x, bool checked) private pure returns (uint256) {
int256 xInt = x.toInt256();

if (xInt > MAX_EXP_WAD) {
if (checked) {
revert TanhOverflow();
}
xInt = MAX_EXP_WAD;
}
uint256 expX = xInt.expWad().toUint256();
uint256 invExpX = (xInt * -1).expWad().toUint256();

return (expX - invExpX).fullMulDiv(1e18, expX + invExpX);
}
}
83 changes: 83 additions & 0 deletions test/utils/math/LibTanh.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import {Test} from "forge-std/Test.sol";
import {console2} from "forge-std/console2.sol";
import {LibTanh} from "../../../src/utils/math/LibTanh.sol";

contract LibTanhTest is Test {
using LibTanh for uint256;

function testTanh1() public pure {
uint256 x = 1e18;
uint256 y = x.tanh();
// 0.761594155955764888
assertEq(y, 761594155955764888);
}

function testTanh2() public pure {
uint256 x = 2e18;
uint256 y = LibTanh.tanh(x);
assertEq(y, 964027580075816884);
}

function testTanh3() public pure {
uint256 x = 3e18;
uint256 y = LibTanh.tanh(x);
assertEq(y, 995054753686730451);
}

function testTanh4() public pure {
uint256 x = 4e18;
uint256 y = LibTanh.tanh(x);
assertEq(y, 999329299739067043);
}

function testTanh5() public pure {
uint256 x = 5e18;
uint256 y = LibTanh.tanh(x);
assertEq(y, 999909204262595131);
}

function testTanh6() public pure {
uint256 x = 6e18;
uint256 y = LibTanh.tanh(x);
assertEq(y, 999987711650795570);
}

function testTanh7() public pure {
uint256 x = 7e18;
uint256 y = LibTanh.tanh(x);
assertEq(y, 999998336943944671);
}

function testTanh8() public pure {
uint256 x = 8e18;
uint256 y = LibTanh.tanh(x);
assertEq(y, 999999774929675889);
}

function testTanh9() public pure {
uint256 x = 9e18;
uint256 y = LibTanh.tanh(x);
assertEq(y, 999999969540040974);
}

function testTanh10() public pure {
uint256 x = 10e18;
uint256 y = LibTanh.tanh(x);
assertEq(y, 999999995877692763);
}

function testTanhOverflow() public {
uint256 x = 136e18;
vm.expectRevert(LibTanh.TanhOverflow.selector);
LibTanh.tanh(x);
}

function testTanhCeilOverflow() public pure {
uint256 x = 136e18;
uint256 y = LibTanh.rawTanh(x);
assertEq(y, 1e18);
}
}
Loading