Overview
S Balance
S Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
12267604 | 3 days ago | Contract Creation | 0 S |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
IrmFactory
Compiler Version
v0.8.27+commit.40a35a09
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: ISC pragma solidity ^0.8.27; import { CREATE3 } from "../../../lib/solady/src/utils/CREATE3.sol"; import { VariableIrm } from "../contracts/VariableIrm.sol"; import { IrmConstants } from "../helpers/IrmConstants.sol"; contract IrmFactory { event VariableIrmCreated(address indexed caller, address indexed irmAddress); error MaxUtilizationTooHigh(); error MinUtilizationOutOfRange(); error FullUtilizationRateRangeInvalid(); error IrmNameIsNotSet(); function createVariableIrm(VariableIrm.Config memory config) external returns (address irm) { require(config.maxTargetUtilization < IrmConstants.UTILIZATION_100_PERCENT, MaxUtilizationTooHigh()); require(config.minTargetUtilization < config.maxTargetUtilization, MinUtilizationOutOfRange()); require(config.minFullUtilizationRate <= config.maxFullUtilizationRate, FullUtilizationRateRangeInvalid()); require(bytes(config.name).length > 0, IrmNameIsNotSet()); bytes memory encodedArgs = abi.encode(config); bytes32 salt = keccak256(encodedArgs); irm = CREATE3.predictDeterministicAddress(salt); if (irm.code.length == 0) { bytes memory initCode = abi.encodePacked(type(VariableIrm).creationCode, encodedArgs); irm = CREATE3.deployDeterministic(0, initCode, salt); emit VariableIrmCreated(msg.sender, irm); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Deterministic deployments agnostic to the initialization code. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/CREATE3.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/CREATE3.sol) /// @author Modified from 0xSequence (https://github.com/0xSequence/create3/blob/master/contracts/Create3.sol) library CREATE3 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Unable to deploy the contract. error DeploymentFailed(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTECODE CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /** * -------------------------------------------------------------------+ * Opcode | Mnemonic | Stack | Memory | * -------------------------------------------------------------------| * 36 | CALLDATASIZE | cds | | * 3d | RETURNDATASIZE | 0 cds | | * 3d | RETURNDATASIZE | 0 0 cds | | * 37 | CALLDATACOPY | | [0..cds): calldata | * 36 | CALLDATASIZE | cds | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 cds | [0..cds): calldata | * 34 | CALLVALUE | value 0 cds | [0..cds): calldata | * f0 | CREATE | newContract | [0..cds): calldata | * -------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * -------------------------------------------------------------------| * 67 bytecode | PUSH8 bytecode | bytecode | | * 3d | RETURNDATASIZE | 0 bytecode | | * 52 | MSTORE | | [0..8): bytecode | * 60 0x08 | PUSH1 0x08 | 0x08 | [0..8): bytecode | * 60 0x18 | PUSH1 0x18 | 0x18 0x08 | [0..8): bytecode | * f3 | RETURN | | [0..8): bytecode | * -------------------------------------------------------------------+ */ /// @dev The proxy initialization code. uint256 private constant _PROXY_INITCODE = 0x67363d3d37363d34f03d5260086018f3; /// @dev Hash of the `_PROXY_INITCODE`. /// Equivalent to `keccak256(abi.encodePacked(hex"67363d3d37363d34f03d5260086018f3"))`. bytes32 internal constant PROXY_INITCODE_HASH = 0x21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CREATE3 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Deploys `initCode` deterministically with a `salt`. /// Returns the deterministic address of the deployed contract, /// which solely depends on `salt`. function deployDeterministic(bytes memory initCode, bytes32 salt) internal returns (address deployed) { deployed = deployDeterministic(0, initCode, salt); } /// @dev Deploys `initCode` deterministically with a `salt`. /// The deployed contract is funded with `value` (in wei) ETH. /// Returns the deterministic address of the deployed contract, /// which solely depends on `salt`. function deployDeterministic(uint256 value, bytes memory initCode, bytes32 salt) internal returns (address deployed) { /// @solidity memory-safe-assembly assembly { mstore(0x00, _PROXY_INITCODE) // Store the `_PROXY_INITCODE`. let proxy := create2(0, 0x10, 0x10, salt) if iszero(proxy) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } mstore(0x14, proxy) // Store the proxy's address. // 0xd6 = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x01). // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex). mstore(0x00, 0xd694) mstore8(0x34, 0x01) // Nonce of the proxy contract (1). deployed := keccak256(0x1e, 0x17) if iszero( mul( // The arguments of `mul` are evaluated last to first. extcodesize(deployed), call(gas(), proxy, value, add(initCode, 0x20), mload(initCode), 0x00, 0x00) ) ) { mstore(0x00, 0x30116425) // `DeploymentFailed()`. revert(0x1c, 0x04) } } } /// @dev Returns the deterministic address for `salt`. function predictDeterministicAddress(bytes32 salt) internal view returns (address deployed) { deployed = predictDeterministicAddress(salt, address(this)); } /// @dev Returns the deterministic address for `salt` with `deployer`. function predictDeterministicAddress(bytes32 salt, address deployer) internal pure returns (address deployed) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, deployer) // Store `deployer`. mstore8(0x0b, 0xff) // Store the prefix. mstore(0x20, salt) // Store the salt. mstore(0x40, PROXY_INITCODE_HASH) // Store the bytecode hash. mstore(0x14, keccak256(0x0b, 0x55)) // Store the proxy's address. mstore(0x40, m) // Restore the free memory pointer. // 0xd6 = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x01). // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex). mstore(0x00, 0xd694) mstore8(0x34, 0x01) // Nonce of the proxy contract (1). deployed := keccak256(0x1e, 0x17) } } }
// SPDX-License-Identifier: ISC pragma solidity ^0.8.27; // Adapted from https://github.com/FraxFinance/fraxlend/ import { FixedPointMathLib } from "../../../lib/solady/src/utils/FixedPointMathLib.sol"; import { SafeCastLib } from "../../../lib/solady/src/utils/SafeCastLib.sol"; import { IrmConstants } from "../helpers/IrmConstants.sol"; import { IIrm } from "../interfaces/IIrm.sol"; /// @title Variable Interest Rate Model /// @notice Calculates interest rates based on utilization and time contract VariableIrm is IIrm { using FixedPointMathLib for uint256; using SafeCastLib for uint256; /// @notice Emitted when the contract is deployed /// @param config Initial config event VariableIrmConfig(Config config); struct Config { /// @notice Min utilization where no rate adjustment happens /// @dev Should be less than `targetUtilization`, e.g., 0.75 * Constants.UTILIZATION_100_PERCENT uint256 minTargetUtilization; /// @notice Max utilization where no rate adjustment happens /// @dev Should be more than `targetUtilization`, e.g., 0.80 * Constants.UTILIZATION_100_PERCENT uint256 maxTargetUtilization; /// @notice Utilization level where IR curve slope increases /// e.g., 0.80 * Constants.UTILIZATION_100_PERCENT uint256 targetUtilization; /// @notice Half-life of interest rate in seconds, affects adjustment speed /// At 100% utilization, rates double at this rate; at 0%, they halve /// e.g., 172,800 seconds (2 days) /// @dev Max value is 194.18 days uint256 rateHalfLife; // Interest Rate Settings (per second), 365.24 days/year /// @notice Min interest rate at 100% utilization /// e.g., 1582470460 (~5% yearly), 18 decimals uint256 minFullUtilizationRate; /// @notice Max interest rate at 100% utilization /// e.g., 3_164_940_920_000 (~10000% yearly), 18 decimals uint256 maxFullUtilizationRate; /// @notice Interest rate at 0% utilization /// e.g., 158247046 (~0.5% yearly), 18 decimals uint256 zeroUtilizationRate; /// @notice Percentage of delta between full and zero utilization rates /// e.g., 0.2e18, 18 decimals uint256 targetRatePercent; /// @notice IRM name string name; } uint256 public immutable minFullUtilizationRate; uint256 public immutable maxFullUtilizationRate; uint256 public immutable zeroUtilizationRate; uint256 public immutable targetRatePercent; uint24 public immutable minTargetUtilization; // 3 bytes uint24 public immutable maxTargetUtilization; // 3 bytes uint24 public immutable targetUtilization; // 3 bytes uint24 public immutable rateHalfLife; // 3 bytes string public name; /// @param _config Config parameters for variable interest rate constructor(Config memory _config) { minFullUtilizationRate = _config.minFullUtilizationRate; maxFullUtilizationRate = _config.maxFullUtilizationRate; zeroUtilizationRate = _config.zeroUtilizationRate; targetRatePercent = _config.targetRatePercent; minTargetUtilization = _config.minTargetUtilization.toUint24(); maxTargetUtilization = _config.maxTargetUtilization.toUint24(); targetUtilization = _config.targetUtilization.toUint24(); rateHalfLife = _config.rateHalfLife.toUint24(); name = _config.name; emit VariableIrmConfig(_config); } /// @inheritdoc IIrm function version() external pure returns (uint256) { return 1; } /// @notice Calculate new max interest rate at 100% utilization /// @dev Interest is per second /// @param deltaTime Time since last update in seconds /// @param utilization Utilization % with 5 decimals precision /// @param fullUtilizationRate Interest at 100% utilization, 18 decimals /// @return newFullUtilizationRate New max interest rate function _getFullUtilizationInterest(uint256 deltaTime, uint256 utilization, uint256 fullUtilizationRate) internal view returns (uint256 newFullUtilizationRate) { uint256 _minTargetUtilization = minTargetUtilization; uint256 _maxTargetUtilization = maxTargetUtilization; uint256 _maxFullUtilizationRate = maxFullUtilizationRate; uint256 _minFullUtilizationRate = minFullUtilizationRate; if (utilization < _minTargetUtilization) { uint256 _rateHalfLife = rateHalfLife; uint256 _deltaUtilization = _minTargetUtilization - utilization; // 36 decimals uint256 _decayGrowth = _rateHalfLife + (_deltaUtilization * _deltaUtilization * deltaTime / _minTargetUtilization / _minTargetUtilization); // 18 decimals newFullUtilizationRate = (fullUtilizationRate * _rateHalfLife) / _decayGrowth; } else if (utilization > _maxTargetUtilization) { uint256 _rateHalfLife = rateHalfLife; uint256 _leftUtilization = IrmConstants.UTILIZATION_100_PERCENT - _maxTargetUtilization; uint256 _deltaUtilization = utilization - _maxTargetUtilization; // 36 decimals uint256 _decayGrowth = _rateHalfLife + (_deltaUtilization * _deltaUtilization * deltaTime) / _leftUtilization / _leftUtilization; // 18 decimals newFullUtilizationRate = (fullUtilizationRate * _decayGrowth) / _rateHalfLife; } else { newFullUtilizationRate = fullUtilizationRate; } return newFullUtilizationRate.min(_maxFullUtilizationRate).max(_minFullUtilizationRate); } /// @inheritdoc IIrm function getNewRate(uint256 deltaTime, uint256 utilization, uint256 oldFullUtilizationRate) external view returns (uint256 newRatePerSec, uint256 newFullUtilizationRate) { return _getNewRate(deltaTime, utilization, oldFullUtilizationRate); } function _getNewRate(uint256 deltaTime, uint256 utilization, uint256 oldFullUtilizationRate) internal view returns (uint256 newRatePerSec, uint256 newFullUtilizationRate) { uint256 _zeroUtilizationRate = zeroUtilizationRate; uint256 _targetUtilization = targetUtilization; newFullUtilizationRate = _getFullUtilizationInterest(deltaTime, utilization, oldFullUtilizationRate); // Calculate target rate as a percentage of the delta between min and max interest uint256 _targetRate = _zeroUtilizationRate + FixedPointMathLib.mulWad(newFullUtilizationRate - _zeroUtilizationRate, targetRatePercent); if (utilization < _targetUtilization) { // For readability, the following formula is equivalent to: // slope = ((_targetRate - zeroUtilizationRate) * Constants.UTILIZATION_100_PERCENT) / targetUtilization; // newRatePerSec = uint64(zeroUtilizationRate + ((utilization * slope) / Constants.UTILIZATION_100_PERCENT)); // 18 decimals newRatePerSec = _zeroUtilizationRate + (utilization * (_targetRate - _zeroUtilizationRate)) / _targetUtilization; } else { // For readability, the following formula is equivalent to: // slope = (((_newFullUtilizationInterest - _targetRate) * Constants.UTILIZATION_100_PERCENT) / (Constants.UTILIZATION_100_PERCENT - // _targetUtilization)); // newRatePerSec = uint64(_targetRate + (((_utilization - _targetUtilization) * slope) / Constants.UTILIZATION_100_PERCENT)); // 18 decimals newRatePerSec = _targetRate + ((utilization - _targetUtilization) * (newFullUtilizationRate - _targetRate)) / (IrmConstants.UTILIZATION_100_PERCENT - _targetUtilization); } } /// @inheritdoc IIrm function calculateInterest(uint256 deltaTime, uint256 totalLendAssets, uint256 totalBorrowAssets, uint256 fullUtilizationRate) external view returns (uint256 _interestEarnedAssets, uint256 _newRatePerSec, uint256 _newFullUtilizationRate) { // Calculate utilization rate uint256 _utilizationRate = totalLendAssets == 0 ? 0 : (IrmConstants.UTILIZATION_100_PERCENT * totalBorrowAssets) / totalLendAssets; // Get new interest rate and full utilization rate (_newRatePerSec, _newFullUtilizationRate) = _getNewRate(deltaTime, _utilizationRate, fullUtilizationRate); // Calculate accrued interest _interestEarnedAssets = (deltaTime * totalBorrowAssets * _newRatePerSec) / FixedPointMathLib.WAD; } }
// SPDX-License-Identifier: ISC pragma solidity ^0.8.27; library IrmConstants { /// @notice Precision for utilization calculations, using 5 decimal places uint256 public constant UTILIZATION_100_PERCENT = 1e5; // Represents 100% }
// 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 mantissa is too big to fit. error MantissaOverflow(); /// @dev The operation failed, due to an multiplication overflow. error MulWadFailed(); /// @dev The operation failed, due to an multiplication overflow. error SMulWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error DivWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error SDivWadFailed(); /// @dev The 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(); /// @dev The input outside the acceptable domain. error OutOfDomain(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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 gt(x, div(not(0), y)) { if y { mstore(0x00, 0xbac65e5b) // `MulWadFailed()`. revert(0x1c, 0x04) } } z := div(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down. function sMulWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) // Equivalent to `require((x == 0 || z / x == y) && !(x == -1 && y == type(int256).min))`. if iszero(gt(or(iszero(x), eq(sdiv(z, x), y)), lt(not(x), eq(y, shl(255, 1))))) { mstore(0x00, 0xedcd4dd4) // `SMulWadFailed()`. revert(0x1c, 0x04) } z := sdiv(z, WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks. function rawMulWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks. function rawSMulWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(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 { z := mul(x, y) // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`. if iszero(eq(div(z, y), x)) { if y { mstore(0x00, 0xbac65e5b) // `MulWadFailed()`. revert(0x1c, 0x04) } } z := add(iszero(iszero(mod(z, WAD))), div(z, WAD)) } } /// @dev Equivalent to `(x * y) / WAD` rounded up, but without overflow checks. function rawMulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { 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 && x <= type(uint256).max / WAD)`. if iszero(mul(y, lt(x, add(1, div(not(0), WAD))))) { mstore(0x00, 0x7c5f487d) // `DivWadFailed()`. revert(0x1c, 0x04) } z := div(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down. function sDivWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, WAD) // Equivalent to `require(y != 0 && ((x * WAD) / WAD == x))`. if iszero(mul(y, eq(sdiv(z, WAD), x))) { mstore(0x00, 0x5c43740d) // `SDivWadFailed()`. revert(0x1c, 0x04) } z := sdiv(z, y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks. function rawDivWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks. function rawSDivWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(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 && x <= type(uint256).max / WAD)`. if iszero(mul(y, lt(x, add(1, 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 * WAD) / y` rounded up, but without overflow and divide by zero checks. function rawDivWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { 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)`. /// Note: This function is an approximation. 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`. /// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln /// Note: This function is an approximation. Monotonically increasing. function expWad(int256 x) internal pure returns (int256 r) { unchecked { // When the result is less than 0.5 we return zero. // This happens when `x <= (log(1e-18) * 1e18) ~ -4.15e19`. if (x <= -41446531673892822313) return r; /// @solidity memory-safe-assembly assembly { // When the result is greater than `(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`. /// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln /// Note: This function is an approximation. Monotonically increasing. function lnWad(int256 x) internal pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // 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`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`. 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)))) // We place the check here for more optimal stack operations. if iszero(sgt(x, 0)) { mstore(0x00, 0x1615e638) // `LnWadUndefined()`. revert(0x1c, 0x04) } // forgefmt: disable-next-item r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff)) // Reduce range of x to (1, 2) * 2**96 // ln(2^k * x) = k * ln(2) + ln(x) x := shr(159, shl(r, x)) // Evaluate using a (8, 8)-term rational approximation. // `p` is made monic, we will multiply by a scale factor later. // forgefmt: disable-next-item let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir. sar(96, mul(add(43456485725739037958740375743393, sar(96, mul(add(24828157081833163892658089445524, sar(96, mul(add(3273285459638523848632254066296, x), x))), x))), x)), 11111509109440967052023855526967) p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857) p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526) p := sub(mul(p, x), shl(96, 795164235651350426258249787498)) // 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. let q := add(5573035233440673466300451813936, x) q := add(71694874799317883764090561454958, sar(96, mul(x, q))) q := add(283447036172924575727196451306956, sar(96, mul(x, q))) q := add(401686690394027663651624208769553, sar(96, mul(x, q))) q := add(204048457590392012362485061816622, sar(96, mul(x, q))) q := add(31853899698501571402653359427138, sar(96, mul(x, q))) q := add(909429971244387300277376558375, sar(96, mul(x, q))) // `p / q` 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`. // The q polynomial is known not to have zeros in the domain. // No scaling required because p is already `2**96` too large. p := sdiv(p, q) // Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`. p := mul(1677202110996718588342820967067443963516166, p) // Add `ln(2) * k * 5**18 * 2**192`. // forgefmt: disable-next-item p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p) // Add `ln(2**96 / 10**18) * 5**18 * 2**192`. p := add(600920179829731861736702779321621459595472258049074101567377883020018308, p) // Base conversion: mul `2**18 / 2**192`. r := sar(174, p) } } /// @dev Returns `W_0(x)`, denominated in `WAD`. /// See: https://en.wikipedia.org/wiki/Lambert_W_function /// a.k.a. Product log function. This is an approximation of the principal branch. /// Note: This function is an approximation. Monotonically increasing. function lambertW0Wad(int256 x) internal pure returns (int256 w) { // forgefmt: disable-next-item unchecked { if ((w = x) <= -367879441171442322) revert OutOfDomain(); // `x` less than `-1/e`. (int256 wad, int256 p) = (int256(WAD), x); uint256 c; // Whether we need to avoid catastrophic cancellation. uint256 i = 4; // Number of iterations. if (w <= 0x1ffffffffffff) { if (-0x4000000000000 <= w) { i = 1; // Inputs near zero only take one step to converge. } else if (w <= -0x3ffffffffffffff) { i = 32; // Inputs near `-1/e` take very long to converge. } } else if (uint256(w >> 63) == uint256(0)) { /// @solidity memory-safe-assembly assembly { // Inline log2 for more performance, since the range is small. let v := shr(49, w) let l := shl(3, lt(0xff, v)) l := add(or(l, byte(and(0x1f, shr(shr(l, v), 0x8421084210842108cc6318c6db6d54be)), 0x0706060506020504060203020504030106050205030304010505030400000000)), 49) w := sdiv(shl(l, 7), byte(sub(l, 31), 0x0303030303030303040506080c13)) c := gt(l, 60) i := add(2, add(gt(l, 53), c)) } } else { int256 ll = lnWad(w = lnWad(w)); /// @solidity memory-safe-assembly assembly { // `w = ln(x) - ln(ln(x)) + b * ln(ln(x)) / ln(x)`. w := add(sdiv(mul(ll, 1023715080943847266), w), sub(w, ll)) i := add(3, iszero(shr(68, x))) c := iszero(shr(143, x)) } if (c == uint256(0)) { do { // If `x` is big, use Newton's so that intermediate values won't overflow. int256 e = expWad(w); /// @solidity memory-safe-assembly assembly { let t := mul(w, div(e, wad)) w := sub(w, sdiv(sub(t, x), div(add(e, t), wad))) } if (p <= w) break; p = w; } while (--i != uint256(0)); /// @solidity memory-safe-assembly assembly { w := sub(w, sgt(w, 2)) } return w; } } do { // Otherwise, use Halley's for faster convergence. int256 e = expWad(w); /// @solidity memory-safe-assembly assembly { let t := add(w, wad) let s := sub(mul(w, e), mul(x, wad)) w := sub(w, sdiv(mul(s, wad), sub(mul(e, t), sdiv(mul(add(t, wad), s), add(t, t))))) } if (p <= w) break; p = w; } while (--i != c); /// @solidity memory-safe-assembly assembly { w := sub(w, sgt(w, 2)) } // For certain ranges of `x`, we'll use the quadratic-rate recursive formula of // R. Iacono and J.P. Boyd for the last iteration, to avoid catastrophic cancellation. if (c == uint256(0)) return w; int256 t = w | 1; /// @solidity memory-safe-assembly assembly { x := sdiv(mul(x, wad), t) } x = (t * (wad + lnWad(x))); /// @solidity memory-safe-assembly assembly { w := sdiv(x, add(wad, t)) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* GENERAL NUMBER UTILITIES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns `a * b == x * y`, with full precision. function fullMulEq(uint256 a, uint256 b, uint256 x, uint256 y) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := and(eq(mul(a, b), mul(x, y)), eq(mulmod(x, y, not(0)), mulmod(a, b, not(0)))) } } /// @dev Calculates `floor(x * y / 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 z) { /// @solidity memory-safe-assembly assembly { // 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`. // Temporarily use `z` as `p0` to save gas. z := mul(x, y) // Lower 256 bits of `x * y`. for {} 1 {} { // If overflows. if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) { let mm := mulmod(x, y, not(0)) let p1 := sub(mm, add(z, lt(mm, z))) // Upper 256 bits of `x * y`. /*------------------- 512 by 256 division --------------------*/ // Make division exact by subtracting the remainder from `[p1 p0]`. let r := mulmod(x, y, d) // Compute remainder using mulmod. let t := and(d, sub(0, d)) // The least significant bit of `d`. `t >= 1`. // Make sure `z` is less than `2**256`. Also prevents `d == 0`. // Placing the check here seems to give more optimal stack operations. if iszero(gt(d, p1)) { mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } d := div(d, t) // Divide `d` by `t`, which is a power of two. // 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(2, mul(3, d)) // 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 z := 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, z)), add(div(sub(0, t), t), 1)), div(sub(z, r), t)), mul(sub(2, mul(d, inv)), inv) // inverse mod 2**256 ) break } z := div(z, d) break } } } /// @dev Calculates `floor(x * y / d)` with full precision. /// Behavior is undefined if `d` is zero or the final result cannot fit in 256 bits. /// Performs the full 512 bit calculation regardless. function fullMulDivUnchecked(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) let mm := mulmod(x, y, not(0)) let p1 := sub(mm, add(z, lt(mm, z))) let t := and(d, sub(0, d)) let r := mulmod(x, y, d) d := div(d, t) let inv := xor(2, mul(3, d)) inv := mul(inv, sub(2, mul(d, inv))) inv := mul(inv, sub(2, mul(d, inv))) inv := mul(inv, sub(2, mul(d, inv))) inv := mul(inv, sub(2, mul(d, inv))) inv := mul(inv, sub(2, mul(d, inv))) z := mul( or(mul(sub(p1, gt(r, z)), add(div(sub(0, t), t), 1)), div(sub(z, r), t)), mul(sub(2, mul(d, inv)), inv) ) } } /// @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/main/contracts/libraries/FullMath.sol function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { z = fullMulDiv(x, y, d); /// @solidity memory-safe-assembly assembly { if mulmod(x, y, d) { z := add(z, 1) if iszero(z) { mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } } } } /// @dev Calculates `floor(x * y / 2 ** n)` with full precision. /// Throws if result overflows a uint256. /// Credit to Philogy under MIT license: /// https://github.com/SorellaLabs/angstrom/blob/main/contracts/src/libraries/X128MathLib.sol function fullMulDivN(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Temporarily use `z` as `p0` to save gas. z := mul(x, y) // Lower 256 bits of `x * y`. We'll call this `z`. for {} 1 {} { if iszero(or(iszero(x), eq(div(z, x), y))) { let k := and(n, 0xff) // `n`, cleaned. let mm := mulmod(x, y, not(0)) let p1 := sub(mm, add(z, lt(mm, z))) // Upper 256 bits of `x * y`. // | p1 | z | // Before: | p1_0 ¦ p1_1 | z_0 ¦ z_1 | // Final: | 0 ¦ p1_0 | p1_1 ¦ z_0 | // Check that final `z` doesn't overflow by checking that p1_0 = 0. if iszero(shr(k, p1)) { z := add(shl(sub(256, k), p1), shr(k, z)) break } mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } z := shr(and(n, 0xff), z) break } } } /// @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 { z := mul(x, y) // Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`. if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) { mstore(0x00, 0xad251c27) // `MulDivFailed()`. revert(0x1c, 0x04) } z := div(z, 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 { z := mul(x, y) // Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`. if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) { mstore(0x00, 0xad251c27) // `MulDivFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(z, d))), div(z, d)) } } /// @dev Returns `x`, the modular multiplicative inverse of `a`, such that `(a * x) % n == 1`. function invMod(uint256 a, uint256 n) internal pure returns (uint256 x) { /// @solidity memory-safe-assembly assembly { let g := n let r := mod(a, n) for { let y := 1 } 1 {} { let q := div(g, r) let t := g g := r r := sub(t, mul(r, q)) let u := x x := y y := sub(u, mul(y, q)) if iszero(r) { break } } x := mul(eq(g, 1), add(x, mul(slt(x, 0), n))) } } /// @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 Returns `condition ? x : y`, without branching. function ternary(bool condition, uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), iszero(condition))) } } /// @dev Returns `condition ? x : y`, without branching. function ternary(bool condition, bytes32 x, bytes32 y) internal pure returns (bytes32 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), iszero(condition))) } } /// @dev Returns `condition ? x : y`, without branching. function ternary(bool condition, address x, address y) internal pure returns (address z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), iszero(condition))) } } /// @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 x { mstore(0x00, 0x49f7642b) // `RPowOverflow()`. revert(0x1c, 0x04) } } z := div(zxRound, b) // Return properly scaled `zxRound`. } } } } } /// @dev Returns the square root of `x`, rounded down. 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`, rounded down. /// Credit to bout3fiddy and pcaversaccio under AGPLv3 license: /// https://github.com/pcaversaccio/snekmate/blob/main/src/utils/Math.vy /// Formally verified by xuwinnie: /// https://github.com/vectorized/solady/blob/main/audits/xuwinnie-solady-cbrt-proof.pdf 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)))) // Makeshift lookup table to nudge the approximate log2 result. z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3))) // Newton-Raphson's. 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) // Round down. z := sub(z, lt(div(x, mul(z, z)), z)) } } /// @dev Returns the square root of `x`, denominated in `WAD`, rounded down. function sqrtWad(uint256 x) internal pure returns (uint256 z) { unchecked { if (x <= type(uint256).max / 10 ** 18) return sqrt(x * 10 ** 18); z = (1 + sqrt(x)) * 10 ** 9; z = (fullMulDivUnchecked(x, 10 ** 18, z) + z) >> 1; } /// @solidity memory-safe-assembly assembly { z := sub(z, gt(999999999999999999, sub(mulmod(z, z, x), 1))) // Round down. } } /// @dev Returns the cube root of `x`, denominated in `WAD`, rounded down. /// Formally verified by xuwinnie: /// https://github.com/vectorized/solady/blob/main/audits/xuwinnie-solady-cbrt-proof.pdf function cbrtWad(uint256 x) internal pure returns (uint256 z) { unchecked { if (x <= type(uint256).max / 10 ** 36) return cbrt(x * 10 ** 36); z = (1 + cbrt(x)) * 10 ** 12; z = (fullMulDivUnchecked(x, 10 ** 36, z * z) + z + z) / 3; } /// @solidity memory-safe-assembly assembly { let p := x for {} 1 {} { if iszero(shr(229, p)) { if iszero(shr(199, p)) { p := mul(p, 100000000000000000) // 10 ** 17. break } p := mul(p, 100000000) // 10 ** 8. break } if iszero(shr(249, p)) { p := mul(p, 100) } break } let t := mulmod(mul(z, z), z, p) z := sub(z, gt(lt(t, shr(1, p)), iszero(t))) // Round down. } } /// @dev Returns the factorial of `x`. function factorial(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := 1 if iszero(lt(x, 58)) { mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`. revert(0x1c, 0x04) } for {} x { x := sub(x, 1) } { z := mul(z, 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)))) // forgefmt: disable-next-item r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0x0706060506020504060203020504030106050205030304010505030400000000)) } } /// @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 scientific notation format `mantissa * 10 ** exponent` of `x`. /// Useful for compressing prices (e.g. using 25 bit mantissa and 7 bit exponent). function sci(uint256 x) internal pure returns (uint256 mantissa, uint256 exponent) { /// @solidity memory-safe-assembly assembly { mantissa := x if mantissa { if iszero(mod(mantissa, 1000000000000000000000000000000000)) { mantissa := div(mantissa, 1000000000000000000000000000000000) exponent := 33 } if iszero(mod(mantissa, 10000000000000000000)) { mantissa := div(mantissa, 10000000000000000000) exponent := add(exponent, 19) } if iszero(mod(mantissa, 1000000000000)) { mantissa := div(mantissa, 1000000000000) exponent := add(exponent, 12) } if iszero(mod(mantissa, 1000000)) { mantissa := div(mantissa, 1000000) exponent := add(exponent, 6) } if iszero(mod(mantissa, 10000)) { mantissa := div(mantissa, 10000) exponent := add(exponent, 4) } if iszero(mod(mantissa, 100)) { mantissa := div(mantissa, 100) exponent := add(exponent, 2) } if iszero(mod(mantissa, 10)) { mantissa := div(mantissa, 10) exponent := add(exponent, 1) } } } } /// @dev Convenience function for packing `x` into a smaller number using `sci`. /// The `mantissa` will be in bits [7..255] (the upper 249 bits). /// The `exponent` will be in bits [0..6] (the lower 7 bits). /// Use `SafeCastLib` to safely ensure that the `packed` number is small /// enough to fit in the desired unsigned integer type: /// ``` /// uint32 packed = SafeCastLib.toUint32(FixedPointMathLib.packSci(777 ether)); /// ``` function packSci(uint256 x) internal pure returns (uint256 packed) { (x, packed) = sci(x); // Reuse for `mantissa` and `exponent`. /// @solidity memory-safe-assembly assembly { if shr(249, x) { mstore(0x00, 0xce30380c) // `MantissaOverflow()`. revert(0x1c, 0x04) } packed := or(shl(7, x), packed) } } /// @dev Convenience function for unpacking a packed number from `packSci`. function unpackSci(uint256 packed) internal pure returns (uint256 unpacked) { unchecked { unpacked = (packed >> 7) * 10 ** (packed & 0x7f); } } /// @dev Returns the average of `x` and `y`. Rounds towards zero. 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`. Rounds towards negative infinity. function avg(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = (x >> 1) + (y >> 1) + (x & y & 1); } } /// @dev Returns the absolute value of `x`. function abs(int256 x) internal pure returns (uint256 z) { unchecked { z = (uint256(x) + uint256(x >> 255)) ^ uint256(x >> 255); } } /// @dev Returns the absolute distance between `x` and `y`. function dist(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(xor(sub(0, gt(x, y)), sub(y, x)), gt(x, y)) } } /// @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 := add(xor(sub(0, sgt(x, y)), sub(y, x)), sgt(x, y)) } } /// @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 } } } /// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`, /// with `t` clamped between `begin` and `end` (inclusive). /// Agnostic to the order of (`a`, `b`) and (`end`, `begin`). /// If `begins == end`, returns `t <= begin ? a : b`. function lerp(uint256 a, uint256 b, uint256 t, uint256 begin, uint256 end) internal pure returns (uint256) { if (begin > end) (t, begin, end) = (~t, ~begin, ~end); if (t <= begin) return a; if (t >= end) return b; unchecked { if (b >= a) return a + fullMulDiv(b - a, t - begin, end - begin); return a - fullMulDiv(a - b, t - begin, end - begin); } } /// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`. /// with `t` clamped between `begin` and `end` (inclusive). /// Agnostic to the order of (`a`, `b`) and (`end`, `begin`). /// If `begins == end`, returns `t <= begin ? a : b`. function lerp(int256 a, int256 b, int256 t, int256 begin, int256 end) internal pure returns (int256) { if (begin > end) (t, begin, end) = (~t, ~begin, ~end); if (t <= begin) return a; if (t >= end) return b; // forgefmt: disable-next-item unchecked { if (b >= a) return int256(uint256(a) + fullMulDiv(uint256(b - a), uint256(t - begin), uint256(end - begin))); return int256(uint256(a) - fullMulDiv(uint256(a - b), uint256(t - begin), uint256(end - begin))); } } /// @dev Returns if `x` is an even number. Some people may need this. function isEven(uint256 x) internal pure returns (bool) { return x & uint256(1) == uint256(0); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Safe integer casting library that reverts on overflow. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeCastLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol) /// @dev Optimized for runtime gas for very high number of optimizer runs (i.e. >= 1000000). library SafeCastLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Unable to cast to the target type due to overflow. error Overflow(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* UNSIGNED INTEGER SAFE CASTING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Casts `x` to a uint8. Reverts on overflow. function toUint8(uint256 x) internal pure returns (uint8) { if (x >= 1 << 8) _revertOverflow(); return uint8(x); } /// @dev Casts `x` to a uint16. Reverts on overflow. function toUint16(uint256 x) internal pure returns (uint16) { if (x >= 1 << 16) _revertOverflow(); return uint16(x); } /// @dev Casts `x` to a uint24. Reverts on overflow. function toUint24(uint256 x) internal pure returns (uint24) { if (x >= 1 << 24) _revertOverflow(); return uint24(x); } /// @dev Casts `x` to a uint32. Reverts on overflow. function toUint32(uint256 x) internal pure returns (uint32) { if (x >= 1 << 32) _revertOverflow(); return uint32(x); } /// @dev Casts `x` to a uint40. Reverts on overflow. function toUint40(uint256 x) internal pure returns (uint40) { if (x >= 1 << 40) _revertOverflow(); return uint40(x); } /// @dev Casts `x` to a uint48. Reverts on overflow. function toUint48(uint256 x) internal pure returns (uint48) { if (x >= 1 << 48) _revertOverflow(); return uint48(x); } /// @dev Casts `x` to a uint56. Reverts on overflow. function toUint56(uint256 x) internal pure returns (uint56) { if (x >= 1 << 56) _revertOverflow(); return uint56(x); } /// @dev Casts `x` to a uint64. Reverts on overflow. function toUint64(uint256 x) internal pure returns (uint64) { if (x >= 1 << 64) _revertOverflow(); return uint64(x); } /// @dev Casts `x` to a uint72. Reverts on overflow. function toUint72(uint256 x) internal pure returns (uint72) { if (x >= 1 << 72) _revertOverflow(); return uint72(x); } /// @dev Casts `x` to a uint80. Reverts on overflow. function toUint80(uint256 x) internal pure returns (uint80) { if (x >= 1 << 80) _revertOverflow(); return uint80(x); } /// @dev Casts `x` to a uint88. Reverts on overflow. function toUint88(uint256 x) internal pure returns (uint88) { if (x >= 1 << 88) _revertOverflow(); return uint88(x); } /// @dev Casts `x` to a uint96. Reverts on overflow. function toUint96(uint256 x) internal pure returns (uint96) { if (x >= 1 << 96) _revertOverflow(); return uint96(x); } /// @dev Casts `x` to a uint104. Reverts on overflow. function toUint104(uint256 x) internal pure returns (uint104) { if (x >= 1 << 104) _revertOverflow(); return uint104(x); } /// @dev Casts `x` to a uint112. Reverts on overflow. function toUint112(uint256 x) internal pure returns (uint112) { if (x >= 1 << 112) _revertOverflow(); return uint112(x); } /// @dev Casts `x` to a uint120. Reverts on overflow. function toUint120(uint256 x) internal pure returns (uint120) { if (x >= 1 << 120) _revertOverflow(); return uint120(x); } /// @dev Casts `x` to a uint128. Reverts on overflow. function toUint128(uint256 x) internal pure returns (uint128) { if (x >= 1 << 128) _revertOverflow(); return uint128(x); } /// @dev Casts `x` to a uint136. Reverts on overflow. function toUint136(uint256 x) internal pure returns (uint136) { if (x >= 1 << 136) _revertOverflow(); return uint136(x); } /// @dev Casts `x` to a uint144. Reverts on overflow. function toUint144(uint256 x) internal pure returns (uint144) { if (x >= 1 << 144) _revertOverflow(); return uint144(x); } /// @dev Casts `x` to a uint152. Reverts on overflow. function toUint152(uint256 x) internal pure returns (uint152) { if (x >= 1 << 152) _revertOverflow(); return uint152(x); } /// @dev Casts `x` to a uint160. Reverts on overflow. function toUint160(uint256 x) internal pure returns (uint160) { if (x >= 1 << 160) _revertOverflow(); return uint160(x); } /// @dev Casts `x` to a uint168. Reverts on overflow. function toUint168(uint256 x) internal pure returns (uint168) { if (x >= 1 << 168) _revertOverflow(); return uint168(x); } /// @dev Casts `x` to a uint176. Reverts on overflow. function toUint176(uint256 x) internal pure returns (uint176) { if (x >= 1 << 176) _revertOverflow(); return uint176(x); } /// @dev Casts `x` to a uint184. Reverts on overflow. function toUint184(uint256 x) internal pure returns (uint184) { if (x >= 1 << 184) _revertOverflow(); return uint184(x); } /// @dev Casts `x` to a uint192. Reverts on overflow. function toUint192(uint256 x) internal pure returns (uint192) { if (x >= 1 << 192) _revertOverflow(); return uint192(x); } /// @dev Casts `x` to a uint200. Reverts on overflow. function toUint200(uint256 x) internal pure returns (uint200) { if (x >= 1 << 200) _revertOverflow(); return uint200(x); } /// @dev Casts `x` to a uint208. Reverts on overflow. function toUint208(uint256 x) internal pure returns (uint208) { if (x >= 1 << 208) _revertOverflow(); return uint208(x); } /// @dev Casts `x` to a uint216. Reverts on overflow. function toUint216(uint256 x) internal pure returns (uint216) { if (x >= 1 << 216) _revertOverflow(); return uint216(x); } /// @dev Casts `x` to a uint224. Reverts on overflow. function toUint224(uint256 x) internal pure returns (uint224) { if (x >= 1 << 224) _revertOverflow(); return uint224(x); } /// @dev Casts `x` to a uint232. Reverts on overflow. function toUint232(uint256 x) internal pure returns (uint232) { if (x >= 1 << 232) _revertOverflow(); return uint232(x); } /// @dev Casts `x` to a uint240. Reverts on overflow. function toUint240(uint256 x) internal pure returns (uint240) { if (x >= 1 << 240) _revertOverflow(); return uint240(x); } /// @dev Casts `x` to a uint248. Reverts on overflow. function toUint248(uint256 x) internal pure returns (uint248) { if (x >= 1 << 248) _revertOverflow(); return uint248(x); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SIGNED INTEGER SAFE CASTING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Casts `x` to a int8. Reverts on overflow. function toInt8(int256 x) internal pure returns (int8) { unchecked { if (((1 << 7) + uint256(x)) >> 8 == uint256(0)) return int8(x); _revertOverflow(); } } /// @dev Casts `x` to a int16. Reverts on overflow. function toInt16(int256 x) internal pure returns (int16) { unchecked { if (((1 << 15) + uint256(x)) >> 16 == uint256(0)) return int16(x); _revertOverflow(); } } /// @dev Casts `x` to a int24. Reverts on overflow. function toInt24(int256 x) internal pure returns (int24) { unchecked { if (((1 << 23) + uint256(x)) >> 24 == uint256(0)) return int24(x); _revertOverflow(); } } /// @dev Casts `x` to a int32. Reverts on overflow. function toInt32(int256 x) internal pure returns (int32) { unchecked { if (((1 << 31) + uint256(x)) >> 32 == uint256(0)) return int32(x); _revertOverflow(); } } /// @dev Casts `x` to a int40. Reverts on overflow. function toInt40(int256 x) internal pure returns (int40) { unchecked { if (((1 << 39) + uint256(x)) >> 40 == uint256(0)) return int40(x); _revertOverflow(); } } /// @dev Casts `x` to a int48. Reverts on overflow. function toInt48(int256 x) internal pure returns (int48) { unchecked { if (((1 << 47) + uint256(x)) >> 48 == uint256(0)) return int48(x); _revertOverflow(); } } /// @dev Casts `x` to a int56. Reverts on overflow. function toInt56(int256 x) internal pure returns (int56) { unchecked { if (((1 << 55) + uint256(x)) >> 56 == uint256(0)) return int56(x); _revertOverflow(); } } /// @dev Casts `x` to a int64. Reverts on overflow. function toInt64(int256 x) internal pure returns (int64) { unchecked { if (((1 << 63) + uint256(x)) >> 64 == uint256(0)) return int64(x); _revertOverflow(); } } /// @dev Casts `x` to a int72. Reverts on overflow. function toInt72(int256 x) internal pure returns (int72) { unchecked { if (((1 << 71) + uint256(x)) >> 72 == uint256(0)) return int72(x); _revertOverflow(); } } /// @dev Casts `x` to a int80. Reverts on overflow. function toInt80(int256 x) internal pure returns (int80) { unchecked { if (((1 << 79) + uint256(x)) >> 80 == uint256(0)) return int80(x); _revertOverflow(); } } /// @dev Casts `x` to a int88. Reverts on overflow. function toInt88(int256 x) internal pure returns (int88) { unchecked { if (((1 << 87) + uint256(x)) >> 88 == uint256(0)) return int88(x); _revertOverflow(); } } /// @dev Casts `x` to a int96. Reverts on overflow. function toInt96(int256 x) internal pure returns (int96) { unchecked { if (((1 << 95) + uint256(x)) >> 96 == uint256(0)) return int96(x); _revertOverflow(); } } /// @dev Casts `x` to a int104. Reverts on overflow. function toInt104(int256 x) internal pure returns (int104) { unchecked { if (((1 << 103) + uint256(x)) >> 104 == uint256(0)) return int104(x); _revertOverflow(); } } /// @dev Casts `x` to a int112. Reverts on overflow. function toInt112(int256 x) internal pure returns (int112) { unchecked { if (((1 << 111) + uint256(x)) >> 112 == uint256(0)) return int112(x); _revertOverflow(); } } /// @dev Casts `x` to a int120. Reverts on overflow. function toInt120(int256 x) internal pure returns (int120) { unchecked { if (((1 << 119) + uint256(x)) >> 120 == uint256(0)) return int120(x); _revertOverflow(); } } /// @dev Casts `x` to a int128. Reverts on overflow. function toInt128(int256 x) internal pure returns (int128) { unchecked { if (((1 << 127) + uint256(x)) >> 128 == uint256(0)) return int128(x); _revertOverflow(); } } /// @dev Casts `x` to a int136. Reverts on overflow. function toInt136(int256 x) internal pure returns (int136) { unchecked { if (((1 << 135) + uint256(x)) >> 136 == uint256(0)) return int136(x); _revertOverflow(); } } /// @dev Casts `x` to a int144. Reverts on overflow. function toInt144(int256 x) internal pure returns (int144) { unchecked { if (((1 << 143) + uint256(x)) >> 144 == uint256(0)) return int144(x); _revertOverflow(); } } /// @dev Casts `x` to a int152. Reverts on overflow. function toInt152(int256 x) internal pure returns (int152) { unchecked { if (((1 << 151) + uint256(x)) >> 152 == uint256(0)) return int152(x); _revertOverflow(); } } /// @dev Casts `x` to a int160. Reverts on overflow. function toInt160(int256 x) internal pure returns (int160) { unchecked { if (((1 << 159) + uint256(x)) >> 160 == uint256(0)) return int160(x); _revertOverflow(); } } /// @dev Casts `x` to a int168. Reverts on overflow. function toInt168(int256 x) internal pure returns (int168) { unchecked { if (((1 << 167) + uint256(x)) >> 168 == uint256(0)) return int168(x); _revertOverflow(); } } /// @dev Casts `x` to a int176. Reverts on overflow. function toInt176(int256 x) internal pure returns (int176) { unchecked { if (((1 << 175) + uint256(x)) >> 176 == uint256(0)) return int176(x); _revertOverflow(); } } /// @dev Casts `x` to a int184. Reverts on overflow. function toInt184(int256 x) internal pure returns (int184) { unchecked { if (((1 << 183) + uint256(x)) >> 184 == uint256(0)) return int184(x); _revertOverflow(); } } /// @dev Casts `x` to a int192. Reverts on overflow. function toInt192(int256 x) internal pure returns (int192) { unchecked { if (((1 << 191) + uint256(x)) >> 192 == uint256(0)) return int192(x); _revertOverflow(); } } /// @dev Casts `x` to a int200. Reverts on overflow. function toInt200(int256 x) internal pure returns (int200) { unchecked { if (((1 << 199) + uint256(x)) >> 200 == uint256(0)) return int200(x); _revertOverflow(); } } /// @dev Casts `x` to a int208. Reverts on overflow. function toInt208(int256 x) internal pure returns (int208) { unchecked { if (((1 << 207) + uint256(x)) >> 208 == uint256(0)) return int208(x); _revertOverflow(); } } /// @dev Casts `x` to a int216. Reverts on overflow. function toInt216(int256 x) internal pure returns (int216) { unchecked { if (((1 << 215) + uint256(x)) >> 216 == uint256(0)) return int216(x); _revertOverflow(); } } /// @dev Casts `x` to a int224. Reverts on overflow. function toInt224(int256 x) internal pure returns (int224) { unchecked { if (((1 << 223) + uint256(x)) >> 224 == uint256(0)) return int224(x); _revertOverflow(); } } /// @dev Casts `x` to a int232. Reverts on overflow. function toInt232(int256 x) internal pure returns (int232) { unchecked { if (((1 << 231) + uint256(x)) >> 232 == uint256(0)) return int232(x); _revertOverflow(); } } /// @dev Casts `x` to a int240. Reverts on overflow. function toInt240(int256 x) internal pure returns (int240) { unchecked { if (((1 << 239) + uint256(x)) >> 240 == uint256(0)) return int240(x); _revertOverflow(); } } /// @dev Casts `x` to a int248. Reverts on overflow. function toInt248(int256 x) internal pure returns (int248) { unchecked { if (((1 << 247) + uint256(x)) >> 248 == uint256(0)) return int248(x); _revertOverflow(); } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* OTHER SAFE CASTING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Casts `x` to a int8. Reverts on overflow. function toInt8(uint256 x) internal pure returns (int8) { if (x >= 1 << 7) _revertOverflow(); return int8(int256(x)); } /// @dev Casts `x` to a int16. Reverts on overflow. function toInt16(uint256 x) internal pure returns (int16) { if (x >= 1 << 15) _revertOverflow(); return int16(int256(x)); } /// @dev Casts `x` to a int24. Reverts on overflow. function toInt24(uint256 x) internal pure returns (int24) { if (x >= 1 << 23) _revertOverflow(); return int24(int256(x)); } /// @dev Casts `x` to a int32. Reverts on overflow. function toInt32(uint256 x) internal pure returns (int32) { if (x >= 1 << 31) _revertOverflow(); return int32(int256(x)); } /// @dev Casts `x` to a int40. Reverts on overflow. function toInt40(uint256 x) internal pure returns (int40) { if (x >= 1 << 39) _revertOverflow(); return int40(int256(x)); } /// @dev Casts `x` to a int48. Reverts on overflow. function toInt48(uint256 x) internal pure returns (int48) { if (x >= 1 << 47) _revertOverflow(); return int48(int256(x)); } /// @dev Casts `x` to a int56. Reverts on overflow. function toInt56(uint256 x) internal pure returns (int56) { if (x >= 1 << 55) _revertOverflow(); return int56(int256(x)); } /// @dev Casts `x` to a int64. Reverts on overflow. function toInt64(uint256 x) internal pure returns (int64) { if (x >= 1 << 63) _revertOverflow(); return int64(int256(x)); } /// @dev Casts `x` to a int72. Reverts on overflow. function toInt72(uint256 x) internal pure returns (int72) { if (x >= 1 << 71) _revertOverflow(); return int72(int256(x)); } /// @dev Casts `x` to a int80. Reverts on overflow. function toInt80(uint256 x) internal pure returns (int80) { if (x >= 1 << 79) _revertOverflow(); return int80(int256(x)); } /// @dev Casts `x` to a int88. Reverts on overflow. function toInt88(uint256 x) internal pure returns (int88) { if (x >= 1 << 87) _revertOverflow(); return int88(int256(x)); } /// @dev Casts `x` to a int96. Reverts on overflow. function toInt96(uint256 x) internal pure returns (int96) { if (x >= 1 << 95) _revertOverflow(); return int96(int256(x)); } /// @dev Casts `x` to a int104. Reverts on overflow. function toInt104(uint256 x) internal pure returns (int104) { if (x >= 1 << 103) _revertOverflow(); return int104(int256(x)); } /// @dev Casts `x` to a int112. Reverts on overflow. function toInt112(uint256 x) internal pure returns (int112) { if (x >= 1 << 111) _revertOverflow(); return int112(int256(x)); } /// @dev Casts `x` to a int120. Reverts on overflow. function toInt120(uint256 x) internal pure returns (int120) { if (x >= 1 << 119) _revertOverflow(); return int120(int256(x)); } /// @dev Casts `x` to a int128. Reverts on overflow. function toInt128(uint256 x) internal pure returns (int128) { if (x >= 1 << 127) _revertOverflow(); return int128(int256(x)); } /// @dev Casts `x` to a int136. Reverts on overflow. function toInt136(uint256 x) internal pure returns (int136) { if (x >= 1 << 135) _revertOverflow(); return int136(int256(x)); } /// @dev Casts `x` to a int144. Reverts on overflow. function toInt144(uint256 x) internal pure returns (int144) { if (x >= 1 << 143) _revertOverflow(); return int144(int256(x)); } /// @dev Casts `x` to a int152. Reverts on overflow. function toInt152(uint256 x) internal pure returns (int152) { if (x >= 1 << 151) _revertOverflow(); return int152(int256(x)); } /// @dev Casts `x` to a int160. Reverts on overflow. function toInt160(uint256 x) internal pure returns (int160) { if (x >= 1 << 159) _revertOverflow(); return int160(int256(x)); } /// @dev Casts `x` to a int168. Reverts on overflow. function toInt168(uint256 x) internal pure returns (int168) { if (x >= 1 << 167) _revertOverflow(); return int168(int256(x)); } /// @dev Casts `x` to a int176. Reverts on overflow. function toInt176(uint256 x) internal pure returns (int176) { if (x >= 1 << 175) _revertOverflow(); return int176(int256(x)); } /// @dev Casts `x` to a int184. Reverts on overflow. function toInt184(uint256 x) internal pure returns (int184) { if (x >= 1 << 183) _revertOverflow(); return int184(int256(x)); } /// @dev Casts `x` to a int192. Reverts on overflow. function toInt192(uint256 x) internal pure returns (int192) { if (x >= 1 << 191) _revertOverflow(); return int192(int256(x)); } /// @dev Casts `x` to a int200. Reverts on overflow. function toInt200(uint256 x) internal pure returns (int200) { if (x >= 1 << 199) _revertOverflow(); return int200(int256(x)); } /// @dev Casts `x` to a int208. Reverts on overflow. function toInt208(uint256 x) internal pure returns (int208) { if (x >= 1 << 207) _revertOverflow(); return int208(int256(x)); } /// @dev Casts `x` to a int216. Reverts on overflow. function toInt216(uint256 x) internal pure returns (int216) { if (x >= 1 << 215) _revertOverflow(); return int216(int256(x)); } /// @dev Casts `x` to a int224. Reverts on overflow. function toInt224(uint256 x) internal pure returns (int224) { if (x >= 1 << 223) _revertOverflow(); return int224(int256(x)); } /// @dev Casts `x` to a int232. Reverts on overflow. function toInt232(uint256 x) internal pure returns (int232) { if (x >= 1 << 231) _revertOverflow(); return int232(int256(x)); } /// @dev Casts `x` to a int240. Reverts on overflow. function toInt240(uint256 x) internal pure returns (int240) { if (x >= 1 << 239) _revertOverflow(); return int240(int256(x)); } /// @dev Casts `x` to a int248. Reverts on overflow. function toInt248(uint256 x) internal pure returns (int248) { if (x >= 1 << 247) _revertOverflow(); return int248(int256(x)); } /// @dev Casts `x` to a int256. Reverts on overflow. function toInt256(uint256 x) internal pure returns (int256) { if (int256(x) >= 0) return int256(x); _revertOverflow(); } /// @dev Casts `x` to a uint256. Reverts on overflow. function toUint256(int256 x) internal pure returns (uint256) { if (x >= 0) return uint256(x); _revertOverflow(); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function _revertOverflow() private pure { /// @solidity memory-safe-assembly assembly { // Store the function selector of `Overflow()`. mstore(0x00, 0x35278d12) // Revert with (offset, size). revert(0x1c, 0x04) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.27; /// @title Interest Rate Model Interface /// @notice Interface for the interest rate model. interface IIrm { /// @notice Get the current zero utilization rate. /// @dev Use this to set the initial interest rate in the constructor. function zeroUtilizationRate() external view returns (uint256); /// @notice Get the rate when the market is fully utilized. /// @dev Use this to set the initial interest rate at 100% utilization. function minFullUtilizationRate() external view returns (uint256); /// @notice Get the name of the Interest Rate Model. function name() external view returns (string memory); /// @notice Get the version of the Interest Rate Model. /// @dev It's a single-digit number. function version() external view returns (uint256); /// @notice Calculate new interest rates based on utilization. /// @param deltaTime Time since the last update in seconds. /// @param utilization Utilization percentage with 5 decimal precision. /// @param oldFullUtilizationRate Interest rate at 100% utilization, 18 decimals. /// @return newRatePerSec New interest rate per second, 18 decimals. /// @return newFullUtilizationRate New max interest rate, 18 decimals. function getNewRate(uint256 deltaTime, uint256 utilization, uint256 oldFullUtilizationRate) external view returns (uint256 newRatePerSec, uint256 newFullUtilizationRate); /// @notice Calculate interest based on elapsed time and utilization. /// @param deltaTime Time elapsed in seconds. /// @param totalLendAssets Total assets lent. /// @param totalBorrowAssets Total assets borrowed. /// @param oldFullUtilizationRate Previous full utilization rate. /// @return interestEarnedAssets Interest earned in assets. /// @return newRatePerSec New interest rate per second. /// @return newFullUtilizationRate New max interest rate. function calculateInterest(uint256 deltaTime, uint256 totalLendAssets, uint256 totalBorrowAssets, uint256 oldFullUtilizationRate) external view returns (uint256 interestEarnedAssets, uint256 newRatePerSec, uint256 newFullUtilizationRate); }
{ "remappings": [ "@chainlink/contracts/=lib/chainlink-brownie-contracts/contracts/src/", "@forge-std/=lib/forge-std/src/", "@royco/=lib/royco/src/", "@solady/=lib/solady/src/", "@solmate/=lib/solmate/src/", "@uniswap/v3-core/=lib/v3-core/", "@uniswap-v3-oracle/=lib/uniswap-v3-oracle/", "@pythnetwork/pyth-sdk-solidity/=lib/pyth-sdk-solidity/", "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "chainlink-brownie-contracts/=lib/chainlink-brownie-contracts/", "clones-with-immutable-args/=lib/royco/lib/clones-with-immutable-args/src/", "ds-test/=lib/solmate/lib/ds-test/src/", "enso-weiroll/=lib/royco/lib/enso-weiroll/contracts/", "erc4626-tests/=lib/royco/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "pyth-sdk-solidity/=lib/pyth-sdk-solidity/", "royco/=lib/royco/", "solady/=lib/solady/src/", "solmate/=lib/solmate/src/", "uniswap-v3-oracle/=lib/uniswap-v3-oracle/", "v3-core/=lib/v3-core/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "cancun", "viaIR": true, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"FullUtilizationRateRangeInvalid","type":"error"},{"inputs":[],"name":"IrmNameIsNotSet","type":"error"},{"inputs":[],"name":"MaxUtilizationTooHigh","type":"error"},{"inputs":[],"name":"MinUtilizationOutOfRange","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"irmAddress","type":"address"}],"name":"VariableIrmCreated","type":"event"},{"inputs":[{"components":[{"internalType":"uint256","name":"minTargetUtilization","type":"uint256"},{"internalType":"uint256","name":"maxTargetUtilization","type":"uint256"},{"internalType":"uint256","name":"targetUtilization","type":"uint256"},{"internalType":"uint256","name":"rateHalfLife","type":"uint256"},{"internalType":"uint256","name":"minFullUtilizationRate","type":"uint256"},{"internalType":"uint256","name":"maxFullUtilizationRate","type":"uint256"},{"internalType":"uint256","name":"zeroUtilizationRate","type":"uint256"},{"internalType":"uint256","name":"targetRatePercent","type":"uint256"},{"internalType":"string","name":"name","type":"string"}],"internalType":"struct VariableIrm.Config","name":"config","type":"tuple"}],"name":"createVariableIrm","outputs":[{"internalType":"address","name":"irm","type":"address"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6080806040523460155761103e908161001a8239f35b5f80fdfe6080806040526004361015610012575f80fd5b5f3560e01c6344adbce714610025575f80fd5b3461037e57602036600319011261037e5760043567ffffffffffffffff811161037e57610120600319823603011261037e57610120820182811067ffffffffffffffff821117610382576040528060040135825260208201916024820135835260408101906044830135825260608101906064840135825260808101926084850135845260a082019460a4810135865260c083019060c4810135825260e084019060e481013582526101048101359067ffffffffffffffff821161037e5701913660238401121561037e57600483013567ffffffffffffffff8111610382576040519361011c601f8301601f191660200186610396565b818552366024828401011161037e57815f9260246020930183880137850101526101008501928352620186a08951101561036f578451895111156103605786518851106103515782515115610342576020976101f097610180978a966040519c8d99898b019d8e525160408b01525160608a01525160808901525160a08801525160c08701525160e0860152516101008501525161012084015251610120610140840152805191829182610160860152018484015e5f838284010152601f801991011681010301601f198101845283610396565b8151812090604051305f5260ff600b53826020527f21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f6040526055600b2060145260405261d6945f5260016034536017601e2091823b1561025f575b6040516001600160a01b0384168152602090f35b9091506102b7610c5060206040519461027a82840187610396565b828652818601926103b9843960405196879383850197518091895e840190838201905f8252519283915e01015f815203601f198101855284610396565b6f67363d3d37363d34f03d5260086018f35f526010805ff590811561033557815f9291839260145261d69483526001603453826017601e209551925af1813b0215610335576020906001600160a01b038116337fe82fd762fd04340596bee536c43a18a495ecec61e51a07ce06ffb4f8914962a45f80a35f8061024b565b63301164255f526004601cfd5b636b93ca5f60e11b5f5260045ffd5b630fd4eba360e11b5f5260045ffd5b632d7ab62b60e01b5f5260045ffd5b63a49ede6d60e01b5f5260045ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff8211176103825760405256fe6101806040523461041257610c508038038061001a81610416565b928339810190602081830312610412578051906001600160401b038211610412570190610120828203126104125760405161012081016001600160401b038111828210176103fe5760405282518152602083015191602082019283526040840151936040830194855260608101516060840190815260808201516080850190815260a08301519060a0860191825260c08401519260c0870193845260e08501519460e088019586526101008101519060018060401b038211610412570186601f82011215610412578051906001600160401b0382116103fe57610106601f8301601f1916602001610416565b978289526020838301011161041257815f926020809301838b015e8801015261010087019586528151608052825160a052835160c052845160e05261014b875161043b565b61010052610159885161043b565b61012052610167895161043b565b61014052610175815161043b565b61016052855180519099906001600160401b0381116103fe575f54600181811c911680156103f4575b60208210146103e057601f811161037e575b506020601f82116001146103015791816020989694926101609b9a9896945f516020610c305f395f51905f529e5f926102f6575b50508160011b915f199060031b1c1916175f555b6040519a8b99898b5251898b01525160408a01525160608901525160808801525160a08701525160c08601525160e0850152516101008401525161012080840152805191829182610140860152018484015e5f828201840152601f01601f19168101030190a16040516107d3908161045d823960805181818161017301526105c1015260a0518181816101ad015261059f015260c0518181816102e30152610507015260e05181818160fa015261066b015261010051818181610360015261055401526101205181818160bb015261057b015261014051818181610138015261052d0152610160518181816103210152818161060d01526107330152f35b015190505f806101e4565b601f1982169b5f8052815f209c5f5b8181106103665750925f516020610c305f395f51905f529d6101609c9b999795936001938360209d9b99971061034e575b505050811b015f556101f8565b01515f1960f88460031b161c191690555f8080610341565b838301518f556001909e019d60209384019301610310565b5f80527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563601f830160051c810191602084106103d6575b601f0160051c01905b8181106103cb57506101b0565b5f81556001016103be565b90915081906103b5565b634e487b7160e01b5f52602260045260245ffd5b90607f169061019e565b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176103fe57604052565b630100000081101561044f5762ffffff1690565b6335278d125f526004601cfdfe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde031461038457508063093b5a99146103455780633d561339146103065780634a2afcf9146102cc57806354fd4d50146102b15780635be4cb4214610281578063724dfc92146101d0578063b8039fd614610196578063b96fd4801461015c578063d22cedc01461011d578063d72636e2146100e35763ffaf5c06146100a0575f80fd5b346100df575f3660031901126100df57602060405162ffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b5f80fd5b346100df575f3660031901126100df5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100df575f3660031901126100df57602060405162ffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100df575f3660031901126100df5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100df575f3660031901126100df5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100df5760803660031901126100df57604435600435602435806102355750606091670de0b6b3a764000061022161021c936102125f5b6064359083610503565b94819691926104b8565b6104b8565b049160405192835260208301526040820152f35b9180620186a00292620186a08404820361026d5761022161021c93610212610268670de0b6b3a7640000946060986104cb565b610208565b634e487b7160e01b5f52601160045260245ffd5b346100df5760603660031901126100df5760406102a5604435602435600435610503565b82519182526020820152f35b346100df575f3660031901126100df57602060405160018152f35b346100df575f3660031901126100df5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100df575f3660031901126100df57602060405162ffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100df575f3660031901126100df57602060405162ffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100df575f3660031901126100df575f5f54908160011c600183169283156104ae575b60208210841461049a578185526020850193908115610481575060011461042d575b50829003601f01601f191682019167ffffffffffffffff831181841017610419576040918391828452602083525180918160208501528484015e5f828201840152601f01601f19168101030190f35b634e487b7160e01b5f52604160045260245ffd5b90505f80527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635f905b82821061046b575060209150830101836103ca565b6001816020925483858901015201910190610456565b60ff1916845250151560051b83016020019050836103ca565b634e487b7160e01b5f52602260045260245ffd5b90607f16906103a8565b8181029291811591840414171561026d57565b81156104d5570490565b634e487b7160e01b5f52601260045260245ffd5b9190820391821161026d57565b9190820180921161026d57565b90917f00000000000000000000000000000000000000000000000000000000000000009062ffffff7f0000000000000000000000000000000000000000000000000000000000000000169262ffffff7f0000000000000000000000000000000000000000000000000000000000000000169062ffffff7f00000000000000000000000000000000000000000000000000000000000000001692867f0000000000000000000000000000000000000000000000000000000000000000937f0000000000000000000000000000000000000000000000000000000000000000958183105f1461072257509061064561063f8361063a61063a9561063a61064b9961021c61063462ffffff7f00000000000000000000000000000000000000000000000000000000000000001699856104e9565b806104b8565b6104cb565b826104f6565b926104b8565b905b81811090821802189081811190821802189261066982856104e9565b7f000000000000000000000000000000000000000000000000000000000000000090815f1904811161070f575b6106ac91670de0b6b3a7640000910204836104f6565b838210156106d8579261063a6106cf926106c9856106d5976104e9565b906104b8565b906104f6565b91565b91506106e7836106f1926104e9565b6106c983866104e9565b91620186a00391620186a0831161026d576106d5926106cf916104cb565b81156106965763bac65e5b5f526004601cfd5b91829150115f146107945762ffffff7f0000000000000000000000000000000000000000000000000000000000000000169181620186a00391620186a0831161026d576107888361063a61063a9561063a61078e998f6106346106c99861021c926104e9565b846104f6565b9061064d565b5090509061064d56fea26469706673582212201231368def133c9834dfba2138c56519fa4498806af56053091912d3af380ad364736f6c634300081b0033a623cf96b492ab5d3e4d34f7ddbf8d035c16666d260ee0636f33b97df726ce56a2646970667358221220ab0dccd22b9019dde76f46d4fa6541bb626d9636a7cb4a886093794275535dd864736f6c634300081b0033
Deployed Bytecode
0x6080806040526004361015610012575f80fd5b5f3560e01c6344adbce714610025575f80fd5b3461037e57602036600319011261037e5760043567ffffffffffffffff811161037e57610120600319823603011261037e57610120820182811067ffffffffffffffff821117610382576040528060040135825260208201916024820135835260408101906044830135825260608101906064840135825260808101926084850135845260a082019460a4810135865260c083019060c4810135825260e084019060e481013582526101048101359067ffffffffffffffff821161037e5701913660238401121561037e57600483013567ffffffffffffffff8111610382576040519361011c601f8301601f191660200186610396565b818552366024828401011161037e57815f9260246020930183880137850101526101008501928352620186a08951101561036f578451895111156103605786518851106103515782515115610342576020976101f097610180978a966040519c8d99898b019d8e525160408b01525160608a01525160808901525160a08801525160c08701525160e0860152516101008501525161012084015251610120610140840152805191829182610160860152018484015e5f838284010152601f801991011681010301601f198101845283610396565b8151812090604051305f5260ff600b53826020527f21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f6040526055600b2060145260405261d6945f5260016034536017601e2091823b1561025f575b6040516001600160a01b0384168152602090f35b9091506102b7610c5060206040519461027a82840187610396565b828652818601926103b9843960405196879383850197518091895e840190838201905f8252519283915e01015f815203601f198101855284610396565b6f67363d3d37363d34f03d5260086018f35f526010805ff590811561033557815f9291839260145261d69483526001603453826017601e209551925af1813b0215610335576020906001600160a01b038116337fe82fd762fd04340596bee536c43a18a495ecec61e51a07ce06ffb4f8914962a45f80a35f8061024b565b63301164255f526004601cfd5b636b93ca5f60e11b5f5260045ffd5b630fd4eba360e11b5f5260045ffd5b632d7ab62b60e01b5f5260045ffd5b63a49ede6d60e01b5f5260045ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff8211176103825760405256fe6101806040523461041257610c508038038061001a81610416565b928339810190602081830312610412578051906001600160401b038211610412570190610120828203126104125760405161012081016001600160401b038111828210176103fe5760405282518152602083015191602082019283526040840151936040830194855260608101516060840190815260808201516080850190815260a08301519060a0860191825260c08401519260c0870193845260e08501519460e088019586526101008101519060018060401b038211610412570186601f82011215610412578051906001600160401b0382116103fe57610106601f8301601f1916602001610416565b978289526020838301011161041257815f926020809301838b015e8801015261010087019586528151608052825160a052835160c052845160e05261014b875161043b565b61010052610159885161043b565b61012052610167895161043b565b61014052610175815161043b565b61016052855180519099906001600160401b0381116103fe575f54600181811c911680156103f4575b60208210146103e057601f811161037e575b506020601f82116001146103015791816020989694926101609b9a9896945f516020610c305f395f51905f529e5f926102f6575b50508160011b915f199060031b1c1916175f555b6040519a8b99898b5251898b01525160408a01525160608901525160808801525160a08701525160c08601525160e0850152516101008401525161012080840152805191829182610140860152018484015e5f828201840152601f01601f19168101030190a16040516107d3908161045d823960805181818161017301526105c1015260a0518181816101ad015261059f015260c0518181816102e30152610507015260e05181818160fa015261066b015261010051818181610360015261055401526101205181818160bb015261057b015261014051818181610138015261052d0152610160518181816103210152818161060d01526107330152f35b015190505f806101e4565b601f1982169b5f8052815f209c5f5b8181106103665750925f516020610c305f395f51905f529d6101609c9b999795936001938360209d9b99971061034e575b505050811b015f556101f8565b01515f1960f88460031b161c191690555f8080610341565b838301518f556001909e019d60209384019301610310565b5f80527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563601f830160051c810191602084106103d6575b601f0160051c01905b8181106103cb57506101b0565b5f81556001016103be565b90915081906103b5565b634e487b7160e01b5f52602260045260245ffd5b90607f169061019e565b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176103fe57604052565b630100000081101561044f5762ffffff1690565b6335278d125f526004601cfdfe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde031461038457508063093b5a99146103455780633d561339146103065780634a2afcf9146102cc57806354fd4d50146102b15780635be4cb4214610281578063724dfc92146101d0578063b8039fd614610196578063b96fd4801461015c578063d22cedc01461011d578063d72636e2146100e35763ffaf5c06146100a0575f80fd5b346100df575f3660031901126100df57602060405162ffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b5f80fd5b346100df575f3660031901126100df5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100df575f3660031901126100df57602060405162ffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100df575f3660031901126100df5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100df575f3660031901126100df5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100df5760803660031901126100df57604435600435602435806102355750606091670de0b6b3a764000061022161021c936102125f5b6064359083610503565b94819691926104b8565b6104b8565b049160405192835260208301526040820152f35b9180620186a00292620186a08404820361026d5761022161021c93610212610268670de0b6b3a7640000946060986104cb565b610208565b634e487b7160e01b5f52601160045260245ffd5b346100df5760603660031901126100df5760406102a5604435602435600435610503565b82519182526020820152f35b346100df575f3660031901126100df57602060405160018152f35b346100df575f3660031901126100df5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100df575f3660031901126100df57602060405162ffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100df575f3660031901126100df57602060405162ffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100df575f3660031901126100df575f5f54908160011c600183169283156104ae575b60208210841461049a578185526020850193908115610481575060011461042d575b50829003601f01601f191682019167ffffffffffffffff831181841017610419576040918391828452602083525180918160208501528484015e5f828201840152601f01601f19168101030190f35b634e487b7160e01b5f52604160045260245ffd5b90505f80527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635f905b82821061046b575060209150830101836103ca565b6001816020925483858901015201910190610456565b60ff1916845250151560051b83016020019050836103ca565b634e487b7160e01b5f52602260045260245ffd5b90607f16906103a8565b8181029291811591840414171561026d57565b81156104d5570490565b634e487b7160e01b5f52601260045260245ffd5b9190820391821161026d57565b9190820180921161026d57565b90917f00000000000000000000000000000000000000000000000000000000000000009062ffffff7f0000000000000000000000000000000000000000000000000000000000000000169262ffffff7f0000000000000000000000000000000000000000000000000000000000000000169062ffffff7f00000000000000000000000000000000000000000000000000000000000000001692867f0000000000000000000000000000000000000000000000000000000000000000937f0000000000000000000000000000000000000000000000000000000000000000958183105f1461072257509061064561063f8361063a61063a9561063a61064b9961021c61063462ffffff7f00000000000000000000000000000000000000000000000000000000000000001699856104e9565b806104b8565b6104cb565b826104f6565b926104b8565b905b81811090821802189081811190821802189261066982856104e9565b7f000000000000000000000000000000000000000000000000000000000000000090815f1904811161070f575b6106ac91670de0b6b3a7640000910204836104f6565b838210156106d8579261063a6106cf926106c9856106d5976104e9565b906104b8565b906104f6565b91565b91506106e7836106f1926104e9565b6106c983866104e9565b91620186a00391620186a0831161026d576106d5926106cf916104cb565b81156106965763bac65e5b5f526004601cfd5b91829150115f146107945762ffffff7f0000000000000000000000000000000000000000000000000000000000000000169181620186a00391620186a0831161026d576107888361063a61063a9561063a61078e998f6106346106c99861021c926104e9565b846104f6565b9061064d565b5090509061064d56fea26469706673582212201231368def133c9834dfba2138c56519fa4498806af56053091912d3af380ad364736f6c634300081b0033a623cf96b492ab5d3e4d34f7ddbf8d035c16666d260ee0636f33b97df726ce56a2646970667358221220ab0dccd22b9019dde76f46d4fa6541bb626d9636a7cb4a886093794275535dd864736f6c634300081b0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.