diff --git a/src/contracts/adapters/CavalReMultiswapAdapter.sol b/src/contracts/adapters/CavalReMultiswapAdapter.sol new file mode 100644 index 00000000..3a350915 --- /dev/null +++ b/src/contracts/adapters/CavalReMultiswapAdapter.sol @@ -0,0 +1,160 @@ +// ╟╗ ╔╬ +// ╞╬╬ ╬╠╬ +// ╔╣╬╬╬ ╠╠╠╠╦ +// ╬╬╬╬╬╩ ╘╠╠╠╠╬ +// ║╬╬╬╬╬ ╘╠╠╠╠╬ +// ╣╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬ ╒╬╬╬╬╬╬╬╜ ╠╠╬╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬ ╬╬╬╬╬╬╬╬╠╠╠╠╠╠╠╠ +// ╙╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╕ ╬╬╬╬╬╬╬╜ ╣╠╠╬╬╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬ ╬╬╬╬╬╬╬╬╬╠╠╠╠╠╠╠╩ +// ╙╣╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬ ╔╬╬╬╬╬╬╬ ╔╠╠╠╬╬╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬ ╣╬╬╬╬╬╬╬╬╬╬╬╠╠╠╠╝╙ +// ╘╣╬╬╬╬╬╬╬╬╬╬╬╬╬╬ ╒╠╠╠╬╠╬╩╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬╣╬╬╬╬╬╬╬╙ +// ╣╬╬╬╬╬╬╬╬╬╬╠╣ ╣╬╠╠╠╬╩ ╚╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬╬╬╬╬╬╬╬ +// ╣╬╬╬╬╬╬╬╬╬╣ ╣╬╠╠╠╬╬ ╣╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬╬╬╬╬╬╬╬ +// ╟╬╬╬╬╬╬╬╩ ╬╬╠╠╠╠╬╬╬╬╬╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬╠╬╬╬╬╬╬╬ +// ╬╬╬╬╬╬╬ ╒╬╬╠╠╬╠╠╬╬╬╬╬╬╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬ ╣╬╬╬╬╬╬╬ +// ╬╬╬╬╬╬╬ ╬╬╬╠╠╠╠╝╝╝╝╝╝╝╠╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬ ╚╬╬╬╬╬╬╬╬ +// ╬╬╬╬╬╬╬ ╣╬╬╬╬╠╠╩ ╘╬╬╬╬╬╬╬ ╠╬╬╬╬╬╬╬ ╙╬╬╬╬╬╬╬╬ +// + +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.0; +import "../YakAdapter.sol"; +import "../interface/ICavalReMultiswapBasePool.sol"; +import "../interface/IMinimalSwapInfoPool.sol"; + +contract CavalReMultiswapAdapter is YakAdapter { + using SafeERC20 for IERC20; + + mapping(address => mapping(address => address[])) internal tokensToPools; + + constructor( + string memory _name, + address[] memory _pools, + uint256 _swapGasEstimate + ) YakAdapter(_name, _swapGasEstimate) { + addPools(_pools); + } + + function addPools(address[] memory _pools) public onlyMaintainer { + for (uint128 i = 0; i < _pools.length; i++) { + address poolAddress = _pools[i]; + ICavalReMultiswapBasePool pool = ICavalReMultiswapBasePool(poolAddress); + address[] memory assets = pool.assetAddresses(); + for (uint128 j = 0; j < assets.length; j++) { + address token = assets[j]; + for (uint128 k = 0; k < assets.length; k++) { + if (j != k) { + tokensToPools[token][assets[k]].push(pool); + _approveIfNeeded(token, UINT_MAX, poolAddress); + } + } + } + } + } + + function removePools(address[] memory _pools) public onlyMaintainer { + for (uint256 i = 0; i < _pools.length; i++) { + address poolAddress = _pools[i]; + ICavalReMultiswapBasePool pool = ICavalReMultiswapBasePool(poolAddress); + address[] memory assets = pool.assetAddresses(); + for (uint128 j = 0; j < assets.length; j++) { + address token = assets[j]; + for (uint128 k = 0; k < assets.length; k++) { + if (j != k) { + address[] memory currentPools = tokensToPools[token][assets[k]]; + for (uint128 l = 0; l < currentPools.length; l++) { + if (currentPools[l] == poolAddress) { + delete currentPools[l]; + } + } + tokensToPools[token][assets[k]] = currentPools; + } + } + } + } + } + + function getPools(address tokenIn, address tokenOut) public view returns (address[] memory) { + return tokensToPools[tokenIn][tokenOut]; + } + + function _approveIfNeeded(address _tokenIn, uint256 _amount, address pool) internal { + uint256 allowance = IERC20(_tokenIn).allowance(address(this), pool); + if (allowance < _amount) { + IERC20(_tokenIn).safeApprove(pool, _amount); + } + } + + function _query(uint256 _amountIn, address _tokenIn, address _tokenOut) internal view override returns (uint256) { + if (_amountIn == 0 || _tokenIn == _tokenOut) { + return 0; + } + + address[] memory pools = getPools(_tokenIn, _tokenOut); + if (pools.length == 0) { + return 0; + } + + (, uint256 amountOut) = _getBestPoolForSwap(pools, _tokenIn, _tokenOut, _amountIn); + return amountOut; + } + + function _swap( + uint256 _amountIn, + uint256 _amountOut, + address _tokenIn, + address _tokenOut, + address to + ) internal override { + address[] memory pools = getPools(_tokenIn, _tokenOut); + + require(pools.length > 0, "No pools for swapping"); + //TODO find best rate + (address poolAddress, ) = _getBestPoolForSwap(pools, _tokenIn, _tokenOut, _amountIn); + + require(poolAddress != address(0), "Undefined pool"); + + (uint256 receiveAmount, ) = ICavalReMultiswapBasePool(poolAddress).swap( + _tokenIn, + _tokenOut, + _amountIn, + _amountOut + ); + IERC20(_tokenOut).safeTransfer(to, receiveAmount); + } + + function _getBestPoolForSwap( + address[] memory pools, + address _tokenIn, + address _tokenOut, + uint256 _amountIn + ) internal view returns (address bestPool, uint256 amountOut) { + amountOut = 0; + bestPool = address(0); + for (uint128 i; i < pools.length; i++) { + address pool = pools[i]; + if (pool == address(0)) { + continue; + } + ICavalReMultiswapBasePool poolContract = ICavalReMultiswapBasePool(pool); + if (poolContract.paused()) { + continue; + } + + uint256 newAmountOut = _getAmountOut(_tokenIn, _tokenOut, _amountIn, pool); + if (newAmountOut > amountOut) { + amountOut = newAmountOut; + bestPool = pool; + } + } + } + + function _getAmountOut( + address _tokenIn, + address _tokenOut, + uint256 _amountIn, + address _pool + ) internal view returns (uint256 amountOut) { + //use _querySimpleSwap for now and possibly add logic for other pools later + (amountOut, ) = ICavalReMultiswapBasePool(_pool).quoteSwap(_tokenIn, _tokenOut, _amountIn); + } +} diff --git a/src/contracts/interface/ICavalReMultiswapBasePool.sol b/src/contracts/interface/ICavalReMultiswapBasePool.sol new file mode 100644 index 00000000..75201a40 --- /dev/null +++ b/src/contracts/interface/ICavalReMultiswapBasePool.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: Business Source License 1.1 +pragma solidity ^0.8.19; + +interface ICavalReMultiswapBasePool { + + function assetAddresses() external view returns (address[] memory); + + function quoteSwap( + address payToken, + address receiveToken, + uint256 payAmount + ) external returns (uint256 receiveAmount, uint256 feeAmount); + + function swap( + address payToken, + address receiveToken, + uint256 payAmount, + uint256 minReceiveAmount + ) external returns (uint256 receiveAmount, uint256 feeAmount); + +} diff --git a/src/contracts/lib/FixedPointMathLib.sol b/src/contracts/lib/FixedPointMathLib.sol new file mode 100644 index 00000000..4e1823d7 --- /dev/null +++ b/src/contracts/lib/FixedPointMathLib.sol @@ -0,0 +1,835 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +/// @notice Arithmetic library with operations for fixed-point numbers. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol) +/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) +library FixedPointMathLib { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The operation failed, as the output exceeds the maximum value of uint256. + error ExpOverflow(); + + /// @dev The operation failed, as the output exceeds the maximum value of uint256. + error FactorialOverflow(); + + /// @dev The operation failed, due to an overflow. + error RPowOverflow(); + + /// @dev The operation failed, due to an multiplication overflow. + error MulWadFailed(); + + /// @dev The operation failed, either due to a + /// multiplication overflow, or a division by a zero. + error DivWadFailed(); + + /// @dev The multiply-divide operation failed, either due to a + /// multiplication overflow, or a division by a zero. + error MulDivFailed(); + + /// @dev The division failed, as the denominator is zero. + error DivFailed(); + + /// @dev The full precision multiply-divide operation failed, either due + /// to the result being larger than 256 bits, or a division by a zero. + error FullMulDivFailed(); + + /// @dev The output is undefined, as the input is less-than-or-equal to zero. + error LnWadUndefined(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The scalar of ETH and most ERC20s. + uint256 internal constant WAD = 1e18; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* SIMPLIFIED FIXED POINT OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Equivalent to `(x * y) / WAD` rounded down. + function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`. + if mul(y, gt(x, div(not(0), y))) { + mstore(0x00, 0xbac65e5b) // `MulWadFailed()`. + revert(0x1c, 0x04) + } + z := div(mul(x, y), WAD) + } + } + + /// @dev Equivalent to `(x * y) / WAD` rounded up. + function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`. + if mul(y, gt(x, div(not(0), y))) { + mstore(0x00, 0xbac65e5b) // `MulWadFailed()`. + revert(0x1c, 0x04) + } + z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD)) + } + } + + /// @dev Equivalent to `(x * WAD) / y` rounded down. + function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + // Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`. + if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) { + mstore(0x00, 0x7c5f487d) // `DivWadFailed()`. + revert(0x1c, 0x04) + } + z := div(mul(x, WAD), y) + } + } + + /// @dev Equivalent to `(x * WAD) / y` rounded up. + function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + // Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`. + if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) { + mstore(0x00, 0x7c5f487d) // `DivWadFailed()`. + revert(0x1c, 0x04) + } + z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y)) + } + } + + /// @dev Equivalent to `x` to the power of `y`. + /// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`. + function powWad(int256 x, int256 y) internal pure returns (int256) { + // Using `ln(x)` means `x` must be greater than 0. + return expWad((lnWad(x) * y) / int256(WAD)); + } + + /// @dev Returns `exp(x)`, denominated in `WAD`. + function expWad(int256 x) internal pure returns (int256 r) { + unchecked { + // When the result is < 0.5 we return zero. This happens when + // x <= floor(log(0.5e18) * 1e18) ~ -42e18 + if (x <= -42139678854452767551) return r; + + /// @solidity memory-safe-assembly + assembly { + // When the result is > (2**255 - 1) / 1e18 we can not represent it as an + // int. This happens when x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135. + if iszero(slt(x, 135305999368893231589)) { + mstore(0x00, 0xa37bfec9) // `ExpOverflow()`. + revert(0x1c, 0x04) + } + } + + // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96 + // for more intermediate precision and a binary basis. This base conversion + // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78. + x = (x << 78) / 5 ** 18; + + // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers + // of two such that exp(x) = exp(x') * 2**k, where k is an integer. + // Solving this gives k = round(x / log(2)) and x' = x - k * log(2). + int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96; + x = x - k * 54916777467707473351141471128; + + // k is in the range [-61, 195]. + + // Evaluate using a (6, 7)-term rational approximation. + // p is made monic, we'll multiply by a scale factor later. + int256 y = x + 1346386616545796478920950773328; + y = ((y * x) >> 96) + 57155421227552351082224309758442; + int256 p = y + x - 94201549194550492254356042504812; + p = ((p * y) >> 96) + 28719021644029726153956944680412240; + p = p * x + (4385272521454847904659076985693276 << 96); + + // We leave p in 2**192 basis so we don't need to scale it back up for the division. + int256 q = x - 2855989394907223263936484059900; + q = ((q * x) >> 96) + 50020603652535783019961831881945; + q = ((q * x) >> 96) - 533845033583426703283633433725380; + q = ((q * x) >> 96) + 3604857256930695427073651918091429; + q = ((q * x) >> 96) - 14423608567350463180887372962807573; + q = ((q * x) >> 96) + 26449188498355588339934803723976023; + + /// @solidity memory-safe-assembly + assembly { + // Div in assembly because solidity adds a zero check despite the unchecked. + // The q polynomial won't have zeros in the domain as all its roots are complex. + // No scaling is necessary because p is already 2**96 too large. + r := sdiv(p, q) + } + + // r should be in the range (0.09, 0.25) * 2**96. + + // We now need to multiply r by: + // * the scale factor s = ~6.031367120. + // * the 2**k factor from the range reduction. + // * the 1e18 / 2**96 factor for base conversion. + // We do this all at once, with an intermediate result in 2**213 + // basis, so the final right shift is always by a positive amount. + r = int256( + (uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k) + ); + } + } + + /// @dev Returns `ln(x)`, denominated in `WAD`. + function lnWad(int256 x) internal pure returns (int256 r) { + unchecked { + /// @solidity memory-safe-assembly + assembly { + if iszero(sgt(x, 0)) { + mstore(0x00, 0x1615e638) // `LnWadUndefined()`. + revert(0x1c, 0x04) + } + } + + // We want to convert x from 10**18 fixed point to 2**96 fixed point. + // We do this by multiplying by 2**96 / 10**18. But since + // ln(x * C) = ln(x) + ln(C), we can simply do nothing here + // and add ln(2**96 / 10**18) at the end. + + // Compute k = log2(x) - 96. + int256 k; + /// @solidity memory-safe-assembly + assembly { + k := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) + k := or(k, shl(6, lt(0xffffffffffffffff, shr(k, x)))) + k := or(k, shl(5, lt(0xffffffff, shr(k, x)))) + k := or(k, shl(4, lt(0xffff, shr(k, x)))) + k := or(k, shl(3, lt(0xff, shr(k, x)))) + k := or(k, shl(2, lt(0xf, shr(k, x)))) + k := sub(or(k, byte(shr(k, x), hex"00000101020202020303030303030303")), 96) + } + + // Reduce range of x to (1, 2) * 2**96 + // ln(2^k * x) = k * ln(2) + ln(x) + x = int256(uint256(x << uint256(159 - k)) >> 159); + + // Evaluate using a (8, 8)-term rational approximation. + // p is made monic, we will multiply by a scale factor later. + int256 p = x + 3273285459638523848632254066296; + p = ((p * x) >> 96) + 24828157081833163892658089445524; + p = ((p * x) >> 96) + 43456485725739037958740375743393; + p = ((p * x) >> 96) - 11111509109440967052023855526967; + p = ((p * x) >> 96) - 45023709667254063763336534515857; + p = ((p * x) >> 96) - 14706773417378608786704636184526; + p = p * x - (795164235651350426258249787498 << 96); + + // We leave p in 2**192 basis so we don't need to scale it back up for the division. + // q is monic by convention. + int256 q = x + 5573035233440673466300451813936; + q = ((q * x) >> 96) + 71694874799317883764090561454958; + q = ((q * x) >> 96) + 283447036172924575727196451306956; + q = ((q * x) >> 96) + 401686690394027663651624208769553; + q = ((q * x) >> 96) + 204048457590392012362485061816622; + q = ((q * x) >> 96) + 31853899698501571402653359427138; + q = ((q * x) >> 96) + 909429971244387300277376558375; + /// @solidity memory-safe-assembly + assembly { + // Div in assembly because solidity adds a zero check despite the unchecked. + // The q polynomial is known not to have zeros in the domain. + // No scaling required because p is already 2**96 too large. + r := sdiv(p, q) + } + + // r is in the range (0, 0.125) * 2**96 + + // Finalization, we need to: + // * multiply by the scale factor s = 5.549… + // * add ln(2**96 / 10**18) + // * add k * ln(2) + // * multiply by 10**18 / 2**96 = 5**18 >> 78 + + // mul s * 5e18 * 2**96, base is now 5**18 * 2**192 + r *= 1677202110996718588342820967067443963516166; + // add ln(2) * k * 5e18 * 2**192 + r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k; + // add ln(2**96 / 10**18) * 5e18 * 2**192 + r += 600920179829731861736702779321621459595472258049074101567377883020018308; + // base conversion: mul 2**18 / 2**192 + r >>= 174; + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* GENERAL NUMBER UTILITIES */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Calculates `floor(a * b / d)` with full precision. + /// Throws if result overflows a uint256 or when `d` is zero. + /// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv + function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) { + /// @solidity memory-safe-assembly + assembly { + for {} 1 {} { + // 512-bit multiply `[p1 p0] = x * y`. + // Compute the product mod `2**256` and mod `2**256 - 1` + // then use the Chinese Remainder Theorem to reconstruct + // the 512 bit result. The result is stored in two 256 + // variables such that `product = p1 * 2**256 + p0`. + + // Least significant 256 bits of the product. + let p0 := mul(x, y) + let mm := mulmod(x, y, not(0)) + // Most significant 256 bits of the product. + let p1 := sub(mm, add(p0, lt(mm, p0))) + + // Handle non-overflow cases, 256 by 256 division. + if iszero(p1) { + if iszero(d) { + mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. + revert(0x1c, 0x04) + } + result := div(p0, d) + break + } + + // Make sure the result is less than `2**256`. Also prevents `d == 0`. + if iszero(gt(d, p1)) { + mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. + revert(0x1c, 0x04) + } + + /*------------------- 512 by 256 division --------------------*/ + + // Make division exact by subtracting the remainder from `[p1 p0]`. + // Compute remainder using mulmod. + let r := mulmod(x, y, d) + // `t` is the least significant bit of `d`. + // Always greater or equal to 1. + let t := and(d, sub(0, d)) + // Divide `d` by `t`, which is a power of two. + d := div(d, t) + // Invert `d mod 2**256` + // Now that `d` is an odd number, it has an inverse + // modulo `2**256` such that `d * inv = 1 mod 2**256`. + // Compute the inverse by starting with a seed that is correct + // correct for four bits. That is, `d * inv = 1 mod 2**4`. + let inv := xor(mul(3, d), 2) + // Now use Newton-Raphson iteration to improve the precision. + // Thanks to Hensel's lifting lemma, this also works in modular + // arithmetic, doubling the correct bits in each step. + inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8 + inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16 + inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32 + inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64 + inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128 + result := + mul( + // Divide [p1 p0] by the factors of two. + // Shift in bits from `p1` into `p0`. For this we need + // to flip `t` such that it is `2**256 / t`. + or(mul(sub(p1, gt(r, p0)), add(div(sub(0, t), t), 1)), div(sub(p0, r), t)), + // inverse mod 2**256 + mul(inv, sub(2, mul(d, inv))) + ) + break + } + } + } + + /// @dev Calculates `floor(x * y / d)` with full precision, rounded up. + /// Throws if result overflows a uint256 or when `d` is zero. + /// Credit to Uniswap-v3-core under MIT license: + /// https://github.com/Uniswap/v3-core/blob/contracts/libraries/FullMath.sol + function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) { + result = fullMulDiv(x, y, d); + /// @solidity memory-safe-assembly + assembly { + if mulmod(x, y, d) { + result := add(result, 1) + if iszero(result) { + mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. + revert(0x1c, 0x04) + } + } + } + } + + /// @dev Returns `floor(x * y / d)`. + /// Reverts if `x * y` overflows, or `d` is zero. + function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + // Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y)) + if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) { + mstore(0x00, 0xad251c27) // `MulDivFailed()`. + revert(0x1c, 0x04) + } + z := div(mul(x, y), d) + } + } + + /// @dev Returns `ceil(x * y / d)`. + /// Reverts if `x * y` overflows, or `d` is zero. + function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + // Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y)) + if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) { + mstore(0x00, 0xad251c27) // `MulDivFailed()`. + revert(0x1c, 0x04) + } + z := add(iszero(iszero(mod(mul(x, y), d))), div(mul(x, y), d)) + } + } + + /// @dev Returns `ceil(x / d)`. + /// Reverts if `d` is zero. + function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + if iszero(d) { + mstore(0x00, 0x65244e4e) // `DivFailed()`. + revert(0x1c, 0x04) + } + z := add(iszero(iszero(mod(x, d))), div(x, d)) + } + } + + /// @dev Returns `max(0, x - y)`. + function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + z := mul(gt(x, y), sub(x, y)) + } + } + + /// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`. + /// Reverts if the computation overflows. + function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`. + if x { + z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x` + let half := shr(1, b) // Divide `b` by 2. + // Divide `y` by 2 every iteration. + for { y := shr(1, y) } y { y := shr(1, y) } { + let xx := mul(x, x) // Store x squared. + let xxRound := add(xx, half) // Round to the nearest number. + // Revert if `xx + half` overflowed, or if `x ** 2` overflows. + if or(lt(xxRound, xx), shr(128, x)) { + mstore(0x00, 0x49f7642b) // `RPowOverflow()`. + revert(0x1c, 0x04) + } + x := div(xxRound, b) // Set `x` to scaled `xxRound`. + // If `y` is odd: + if and(y, 1) { + let zx := mul(z, x) // Compute `z * x`. + let zxRound := add(zx, half) // Round to the nearest number. + // If `z * x` overflowed or `zx + half` overflowed: + if or(xor(div(zx, x), z), lt(zxRound, zx)) { + // Revert if `x` is non-zero. + if iszero(iszero(x)) { + mstore(0x00, 0x49f7642b) // `RPowOverflow()`. + revert(0x1c, 0x04) + } + } + z := div(zxRound, b) // Return properly scaled `zxRound`. + } + } + } + } + } + + /// @dev Returns the square root of `x`. + function sqrt(uint256 x) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + // `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`. + z := 181 // The "correct" value is 1, but this saves a multiplication later. + + // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad + // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. + + // Let `y = x / 2**r`. We check `y >= 2**(k + 8)` + // but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`. + let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x)) + r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x)))) + r := or(r, shl(5, lt(0xffffffffff, shr(r, x)))) + r := or(r, shl(4, lt(0xffffff, shr(r, x)))) + z := shl(shr(1, r), z) + + // Goal was to get `z*z*y` within a small factor of `x`. More iterations could + // get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`. + // We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small. + // That's not possible if `x < 256` but we can just verify those cases exhaustively. + + // Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`. + // Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`. + // Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps. + + // For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)` + // is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`, + // with largest error when `s = 1` and when `s = 256` or `1/256`. + + // Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`. + // Then we can estimate `sqrt(y)` using + // `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`. + + // There is no overflow risk here since `y < 2**136` after the first branch above. + z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181. + + // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. + z := shr(1, add(z, div(x, z))) + z := shr(1, add(z, div(x, z))) + z := shr(1, add(z, div(x, z))) + z := shr(1, add(z, div(x, z))) + z := shr(1, add(z, div(x, z))) + z := shr(1, add(z, div(x, z))) + z := shr(1, add(z, div(x, z))) + + // If `x+1` is a perfect square, the Babylonian method cycles between + // `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor. + // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division + z := sub(z, lt(div(x, z), z)) + } + } + + /// @dev Returns the cube root of `x`. + /// Credit to bout3fiddy and pcaversaccio under AGPLv3 license: + /// https://github.com/pcaversaccio/snekmate/blob/main/src/utils/Math.vy + function cbrt(uint256 x) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) + r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) + r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) + r := or(r, shl(4, lt(0xffff, shr(r, x)))) + r := or(r, shl(3, lt(0xff, shr(r, x)))) + + z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3))) + + z := div(add(add(div(x, mul(z, z)), z), z), 3) + z := div(add(add(div(x, mul(z, z)), z), z), 3) + z := div(add(add(div(x, mul(z, z)), z), z), 3) + z := div(add(add(div(x, mul(z, z)), z), z), 3) + z := div(add(add(div(x, mul(z, z)), z), z), 3) + z := div(add(add(div(x, mul(z, z)), z), z), 3) + z := div(add(add(div(x, mul(z, z)), z), z), 3) + + z := sub(z, lt(div(x, mul(z, z)), z)) + } + } + + /// @dev Returns the square root of `x`, denominated in `WAD`. + function sqrtWad(uint256 x) internal pure returns (uint256 z) { + unchecked { + z = 10 ** 9; + if (x <= type(uint256).max / 10 ** 36 - 1) { + x *= 10 ** 18; + z = 1; + } + z *= sqrt(x); + } + } + + /// @dev Returns the cube root of `x`, denominated in `WAD`. + function cbrtWad(uint256 x) internal pure returns (uint256 z) { + unchecked { + z = 10 ** 12; + if (x <= (type(uint256).max / 10 ** 36) * 10 ** 18 - 1) { + if (x >= type(uint256).max / 10 ** 36) { + x *= 10 ** 18; + z = 10 ** 6; + } else { + x *= 10 ** 36; + z = 1; + } + } + z *= cbrt(x); + } + } + + /// @dev Returns the factorial of `x`. + function factorial(uint256 x) internal pure returns (uint256 result) { + /// @solidity memory-safe-assembly + assembly { + if iszero(lt(x, 58)) { + mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`. + revert(0x1c, 0x04) + } + for { result := 1 } x { x := sub(x, 1) } { result := mul(result, x) } + } + } + + /// @dev Returns the log2 of `x`. + /// Equivalent to computing the index of the most significant bit (MSB) of `x`. + /// Returns 0 if `x` is zero. + function log2(uint256 x) internal pure returns (uint256 r) { + /// @solidity memory-safe-assembly + assembly { + r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) + r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) + r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) + r := or(r, shl(4, lt(0xffff, shr(r, x)))) + r := or(r, shl(3, lt(0xff, shr(r, x)))) + r := or(r, shl(2, lt(0xf, shr(r, x)))) + r := or(r, byte(shr(r, x), hex"00000101020202020303030303030303")) + } + } + + /// @dev Returns the log2 of `x`, rounded up. + /// Returns 0 if `x` is zero. + function log2Up(uint256 x) internal pure returns (uint256 r) { + r = log2(x); + /// @solidity memory-safe-assembly + assembly { + r := add(r, lt(shl(r, 1), x)) + } + } + + /// @dev Returns the log10 of `x`. + /// Returns 0 if `x` is zero. + function log10(uint256 x) internal pure returns (uint256 r) { + /// @solidity memory-safe-assembly + assembly { + if iszero(lt(x, 100000000000000000000000000000000000000)) { + x := div(x, 100000000000000000000000000000000000000) + r := 38 + } + if iszero(lt(x, 100000000000000000000)) { + x := div(x, 100000000000000000000) + r := add(r, 20) + } + if iszero(lt(x, 10000000000)) { + x := div(x, 10000000000) + r := add(r, 10) + } + if iszero(lt(x, 100000)) { + x := div(x, 100000) + r := add(r, 5) + } + r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999))))) + } + } + + /// @dev Returns the log10 of `x`, rounded up. + /// Returns 0 if `x` is zero. + function log10Up(uint256 x) internal pure returns (uint256 r) { + r = log10(x); + /// @solidity memory-safe-assembly + assembly { + r := add(r, lt(exp(10, r), x)) + } + } + + /// @dev Returns the log256 of `x`. + /// Returns 0 if `x` is zero. + function log256(uint256 x) internal pure returns (uint256 r) { + /// @solidity memory-safe-assembly + assembly { + r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) + r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) + r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) + r := or(r, shl(4, lt(0xffff, shr(r, x)))) + r := or(shr(3, r), lt(0xff, shr(r, x))) + } + } + + /// @dev Returns the log256 of `x`, rounded up. + /// Returns 0 if `x` is zero. + function log256Up(uint256 x) internal pure returns (uint256 r) { + r = log256(x); + /// @solidity memory-safe-assembly + assembly { + r := add(r, lt(shl(shl(3, r), 1), x)) + } + } + + /// @dev Returns the average of `x` and `y`. + function avg(uint256 x, uint256 y) internal pure returns (uint256 z) { + unchecked { + z = (x & y) + ((x ^ y) >> 1); + } + } + + /// @dev Returns the average of `x` and `y`. + function avg(int256 x, int256 y) internal pure returns (int256 z) { + unchecked { + z = (x >> 1) + (y >> 1) + (((x & 1) + (y & 1)) >> 1); + } + } + + /// @dev Returns the absolute value of `x`. + function abs(int256 x) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + z := xor(sub(0, shr(255, x)), add(sub(0, shr(255, x)), x)) + } + } + + /// @dev Returns the absolute distance between `x` and `y`. + function dist(int256 x, int256 y) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + z := xor(mul(xor(sub(y, x), sub(x, y)), sgt(x, y)), sub(y, x)) + } + } + + /// @dev Returns the minimum of `x` and `y`. + function min(uint256 x, uint256 y) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + z := xor(x, mul(xor(x, y), lt(y, x))) + } + } + + /// @dev Returns the minimum of `x` and `y`. + function min(int256 x, int256 y) internal pure returns (int256 z) { + /// @solidity memory-safe-assembly + assembly { + z := xor(x, mul(xor(x, y), slt(y, x))) + } + } + + /// @dev Returns the maximum of `x` and `y`. + function max(uint256 x, uint256 y) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + z := xor(x, mul(xor(x, y), gt(y, x))) + } + } + + /// @dev Returns the maximum of `x` and `y`. + function max(int256 x, int256 y) internal pure returns (int256 z) { + /// @solidity memory-safe-assembly + assembly { + z := xor(x, mul(xor(x, y), sgt(y, x))) + } + } + + /// @dev Returns `x`, bounded to `minValue` and `maxValue`. + function clamp(uint256 x, uint256 minValue, uint256 maxValue) + internal + pure + returns (uint256 z) + { + /// @solidity memory-safe-assembly + assembly { + z := xor(x, mul(xor(x, minValue), gt(minValue, x))) + z := xor(z, mul(xor(z, maxValue), lt(maxValue, z))) + } + } + + /// @dev Returns `x`, bounded to `minValue` and `maxValue`. + function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) { + /// @solidity memory-safe-assembly + assembly { + z := xor(x, mul(xor(x, minValue), sgt(minValue, x))) + z := xor(z, mul(xor(z, maxValue), slt(maxValue, z))) + } + } + + /// @dev Returns greatest common divisor of `x` and `y`. + function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + for { z := x } y {} { + let t := y + y := mod(z, y) + z := t + } + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* RAW NUMBER OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns `x + y`, without checking for overflow. + function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) { + unchecked { + z = x + y; + } + } + + /// @dev Returns `x + y`, without checking for overflow. + function rawAdd(int256 x, int256 y) internal pure returns (int256 z) { + unchecked { + z = x + y; + } + } + + /// @dev Returns `x - y`, without checking for underflow. + function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) { + unchecked { + z = x - y; + } + } + + /// @dev Returns `x - y`, without checking for underflow. + function rawSub(int256 x, int256 y) internal pure returns (int256 z) { + unchecked { + z = x - y; + } + } + + /// @dev Returns `x * y`, without checking for overflow. + function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) { + unchecked { + z = x * y; + } + } + + /// @dev Returns `x * y`, without checking for overflow. + function rawMul(int256 x, int256 y) internal pure returns (int256 z) { + unchecked { + z = x * y; + } + } + + /// @dev Returns `x / y`, returning 0 if `y` is zero. + function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + z := div(x, y) + } + } + + /// @dev Returns `x / y`, returning 0 if `y` is zero. + function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) { + /// @solidity memory-safe-assembly + assembly { + z := sdiv(x, y) + } + } + + /// @dev Returns `x % y`, returning 0 if `y` is zero. + function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + z := mod(x, y) + } + } + + /// @dev Returns `x % y`, returning 0 if `y` is zero. + function rawSMod(int256 x, int256 y) internal pure returns (int256 z) { + /// @solidity memory-safe-assembly + assembly { + z := smod(x, y) + } + } + + /// @dev Returns `(x + y) % d`, return 0 if `d` if zero. + function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + z := addmod(x, y, d) + } + } + + /// @dev Returns `(x * y) % d`, return 0 if `d` if zero. + function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + z := mulmod(x, y, d) + } + } +} \ No newline at end of file