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
20 changes: 20 additions & 0 deletions src/StdMath.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.13 <0.9.0;

/// @notice Math helpers used across forge-std tests.
library stdMath {
int256 private constant INT256_MIN = -57896044618658097711785492504343953926634992332820282019728792003956564819968;

/// @notice Returns the absolute value of a signed integer.
/// @param a The signed integer input.
/// @return The absolute value of `a` as an unsigned integer.
function abs(int256 a) internal pure returns (uint256) {
// Required or it will fail when `a = type(int256).min`
if (a == INT256_MIN) {
Expand All @@ -13,10 +17,18 @@ library stdMath {
return uint256(a > 0 ? a : -a);
}

/// @notice Returns the absolute difference between two unsigned integers.
/// @param a The first unsigned integer.
/// @param b The second unsigned integer.
/// @return The absolute difference between `a` and `b`.
function delta(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a - b : b - a;
}

/// @notice Returns the absolute difference between two signed integers.
/// @param a The first signed integer.
/// @param b The second signed integer.
/// @return The absolute difference between `a` and `b`.
function delta(int256 a, int256 b) internal pure returns (uint256) {
// a and b are of the same sign
// this works thanks to two's complement, the left-most bit is the sign bit
Expand All @@ -28,6 +40,10 @@ library stdMath {
return abs(a) + abs(b);
}

/// @notice Returns the absolute percentage delta between two unsigned integers, scaled by `1e18`.
/// @param a The current unsigned value.
/// @param b The reference unsigned value (divisor).
/// @return The percentage delta scaled by `1e18`.
function percentDelta(uint256 a, uint256 b) internal pure returns (uint256) {
// Prevent division by zero
require(b != 0, "stdMath percentDelta(uint256,uint256): Divisor is zero");
Expand All @@ -36,6 +52,10 @@ library stdMath {
return absDelta * 1e18 / b;
}

/// @notice Returns the absolute percentage delta between two signed integers, scaled by `1e18`.
/// @param a The current signed value.
/// @param b The reference signed value (absolute divisor).
/// @return The percentage delta scaled by `1e18`.
function percentDelta(int256 a, int256 b) internal pure returns (uint256) {
uint256 absDelta = delta(a, b);
uint256 absB = abs(b);
Expand Down
63 changes: 55 additions & 8 deletions src/StdUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ abstract contract StdUtils {
INTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/

/// @notice Maps an unsigned integer into the inclusive range `[min, max]`.
/// @dev Values outside the range are wrapped into it.
/// @param x The unsigned value to bound.
/// @param min The inclusive lower bound.
/// @param max The inclusive upper bound.
/// @return result The bounded value.
function _bound(uint256 x, uint256 min, uint256 max) internal pure virtual returns (uint256 result) {
require(min <= max, "StdUtils bound(uint256,uint256,uint256): Max is less than min.");
// If x is between min and max, return x directly. This is to ensure that dictionary values
Expand Down Expand Up @@ -50,10 +56,21 @@ abstract contract StdUtils {
}
}

/// @notice Wrapper for `_bound(uint256,uint256,uint256)`.
/// @param x The unsigned value to bound.
/// @param min The inclusive lower bound.
/// @param max The inclusive upper bound.
/// @return result The bounded value.
function bound(uint256 x, uint256 min, uint256 max) internal pure virtual returns (uint256 result) {
result = _bound(x, min, max);
}

/// @notice Maps a signed integer into the inclusive range `[min, max]`.
/// @dev Values outside the range are wrapped into it.
/// @param x The signed value to bound.
/// @param min The inclusive lower bound.
/// @param max The inclusive upper bound.
/// @return result The bounded value.
function _bound(int256 x, int256 min, int256 max) internal pure virtual returns (int256 result) {
require(min <= max, "StdUtils bound(int256,int256,int256): Max is less than min.");

Expand All @@ -74,25 +91,46 @@ abstract contract StdUtils {
result = y < INT256_MIN_ABS ? int256(~(INT256_MIN_ABS - y) + 1) : int256(y - INT256_MIN_ABS);
}

/// @notice Wrapper for `_bound(int256,int256,int256)`.
/// @param x The signed value to bound.
/// @param min The inclusive lower bound.
/// @param max The inclusive upper bound.
/// @return result The bounded value.
function bound(int256 x, int256 min, int256 max) internal pure virtual returns (int256 result) {
result = _bound(x, min, max);
}

/// @notice Maps a value into the valid secp256k1 private key range `[1, n - 1]`.
/// @param privateKey The raw private key candidate.
/// @return result The bounded private key.
function boundPrivateKey(uint256 privateKey) internal pure virtual returns (uint256 result) {
result = _bound(privateKey, 1, SECP256K1_ORDER - 1);
}

/// @notice Converts a byte array (up to 32 bytes) into a `uint256`.
/// @param b The byte array to decode.
/// @return The decoded unsigned integer.
function bytesToUint(bytes memory b) internal pure virtual returns (uint256) {
require(b.length <= 32, "StdUtils bytesToUint(bytes): Bytes length exceeds 32.");
return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256));
}

/// @dev Compute the address a contract will be deployed at for a given deployer address and nonce
/// @notice Computes the CREATE deployment address for `deployer` and `nonce`.
/// @dev Deprecated in favor of `vm.computeCreateAddress`.
/// @param deployer The deployer address.
/// @param nonce The deployer nonce used for CREATE.
/// @return The computed CREATE address.
function computeCreateAddress(address deployer, uint256 nonce) internal pure virtual returns (address) {
console2_log_StdUtils("computeCreateAddress is deprecated. Please use vm.computeCreateAddress instead.");
return vm.computeCreateAddress(deployer, nonce);
}

/// @notice Computes the CREATE2 address from a salt, init code hash, and deployer.
/// @dev Deprecated in favor of `vm.computeCreate2Address`.
/// @param salt The CREATE2 salt.
/// @param initcodeHash The hash of the full init code.
/// @param deployer The deployer address.
/// @return The computed CREATE2 address.
function computeCreate2Address(bytes32 salt, bytes32 initcodeHash, address deployer)
internal
pure
Expand All @@ -103,26 +141,35 @@ abstract contract StdUtils {
return vm.computeCreate2Address(salt, initcodeHash, deployer);
}

/// @dev returns the address of a contract created with CREATE2 using the default CREATE2 deployer
/// @notice Computes a CREATE2 address using the default CREATE2 deployer.
/// @dev Deprecated in favor of `vm.computeCreate2Address`.
/// @param salt The CREATE2 salt.
/// @param initCodeHash The hash of the full init code.
/// @return The computed CREATE2 address.
function computeCreate2Address(bytes32 salt, bytes32 initCodeHash) internal pure returns (address) {
console2_log_StdUtils("computeCreate2Address is deprecated. Please use vm.computeCreate2Address instead.");
return vm.computeCreate2Address(salt, initCodeHash);
}

/// @dev returns the hash of the init code (creation code + no args) used in CREATE2 with no constructor arguments
/// @param creationCode the creation code of a contract C, as returned by type(C).creationCode
/// @notice Returns the init code hash for CREATE2 without constructor arguments.
/// @param creationCode The creation code of contract `C`, as returned by `type(C).creationCode`.
/// @return The keccak256 hash of the init code.
function hashInitCode(bytes memory creationCode) internal pure returns (bytes32) {
return hashInitCode(creationCode, "");
}

/// @dev returns the hash of the init code (creation code + ABI-encoded args) used in CREATE2
/// @param creationCode the creation code of a contract C, as returned by type(C).creationCode
/// @param args the ABI-encoded arguments to the constructor of C
/// @notice Returns the init code hash for CREATE2 with ABI-encoded constructor arguments.
/// @param creationCode The creation code of contract `C`, as returned by `type(C).creationCode`.
/// @param args The ABI-encoded constructor arguments for `C`.
/// @return The keccak256 hash of `creationCode || args`.
function hashInitCode(bytes memory creationCode, bytes memory args) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(creationCode, args));
}

// Performs a single call with Multicall3 to query the ERC-20 token balances of the given addresses.
/// @notice Queries ERC-20 balances for multiple addresses in one Multicall3 request.
/// @param token The ERC-20 token contract to query.
/// @param addresses The addresses to query balances for.
/// @return balances The token balances in the same order as `addresses`.
function getTokenBalances(address token, address[] memory addresses)
internal
virtual
Expand Down