Contract Name:
EarlyLiquidity
Contract Source Code:
<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IEarlyLiquidity} from "@/interfaces/IEarlyLiquidity.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ABDKMath64x64} from "@/libraries/ABDKMath64x64.sol";
import {IMinerPool} from "@/interfaces/IMinerPool.sol";
interface IDecimals {
error IncorrectDecimals();
function decimals() external view returns (uint8);
}
/**
* @title EarlyLiquidity
* @author @DavidVorick
* @author twitter: @0xSimon github: @0xSimbo
* @notice This contract allows users to buy Glow tokens with USDC
* @dev the cost of glow rises exponentially with the amount of glow sold
* - The price at increment x = 0.003 * 2^((x)/ 100_000_000)
* - if the function above to get price of increment x if f(x)
* - Then, the price to buy y tokens is Σ f(x) from x = the total increments sold, to x = the total increments sold + y
* - For example, to buy the first ten increments, (aka the first .1 tokens), the price is
* - f(0) + f(1) .... + f(9)
* - To buy the next ten increments, or token .1 -> .2, the price is
* - f(10) + f(11) ... + f(19)
* @dev to calculate the price for y tokens in real time, we use the sum of a geometric series which allows us
* - to efficiently calculate the price of y tokens in real time rather than looping through all the increments
*/
contract EarlyLiquidity is IEarlyLiquidity {
using ABDKMath64x64 for int128;
/* -------------------------------------------------------------------------- */
/* constants */
/* -------------------------------------------------------------------------- */
/// @dev Represents 1.0000000069314718 in 64x64 format, or `r` in the geometric series
int128 private constant _RATIO = 18446744201572638720;
/// @dev Represents 0.003 USDC in 64x64 format
int128 private constant _POINT_ZERO_ZERO_THREE = 55340232221128654848000;
/// @dev Represents 1 in 64x64 format
int128 private constant _ONE = 18446744073709551616;
/// @dev Represents ln(r) in 64x64 format
int128 private constant _LN_RATIO = 127863086660;
/// @dev Represents 1e8 in 64x64 format
int128 private constant _ONE_HUNDRED_MILLION = 100_000_000 << 64;
/// @dev Represents ln(2) in 64x64 format
int128 private constant _LN_2 = 12786308645202655659;
/// @dev represents (1-r) in 64x64 format
/// @dev r = 1 - 1.0000000069314718 = 0000000069314718
int128 private constant _DENOMINATOR = -127863086349;
/// @dev The number of decimals for USDC
uint256 public constant USDC_DECIMALS = 6;
/**
* @notice the total amount of .01 increments to sell
* - equals to 12,000,000 GLW total
* @dev The total number of glow tokens to sell
* @dev 12 million GLOW tokens
* @dev .01 * 1_200_000_000 = 12_000_000
*/
uint256 public constant TOTAL_INCREMENTS_TO_SELL = 1_200_000_000;
/**
* @notice the minimum increment that tokens can be bought in .01 GLW
* @dev The minimum increment that tokens can be bought in
* @dev this is essential so our floating point math doesn't break
*/
uint256 public constant MIN_TOKEN_INCREMENT = 1e16;
/* -------------------------------------------------------------------------- */
/* immutables */
/* -------------------------------------------------------------------------- */
/**
* @notice USDC token
* @dev The USDC token
*/
IERC20 public immutable USDC_TOKEN;
/**
* @notice The address of the holding contract
* @dev the holding contract holds all USDC tokens
*/
address public immutable HOLDING_CONTRACT;
/* -------------------------------------------------------------------------- */
/* state vars */
/* -------------------------------------------------------------------------- */
/// @dev tokens are demagnified by 1e18 to make floating point math easier
/// @dev the {totalSold} function returns the total sold in 1e18 (GLW DECIMALS)
uint256 private _totalIncrementsSold;
/// @notice The Glow token
IERC20 public immutable GLOW_TOKEN;
/// @notice The miner pool contract
/// @dev all USDC is donated to the miner pool
IMinerPool public immutable MINER_POOL;
/* -------------------------------------------------------------------------- */
/* constructor */
/* -------------------------------------------------------------------------- */
/**
* @notice Constructs the EarlyLiquidity contract
* @param _usdcAddress The address of the USDC token
* @param _holdingContract The address of the holding contract
* @param _glowToken The address of the glow token
* @param _minerPoolAddress The address of the miner pool
*/
constructor(address _usdcAddress, address _holdingContract, address _glowToken, address _minerPoolAddress)
payable
{
USDC_TOKEN = IERC20(_usdcAddress);
uint256 decimals = uint256(IDecimals(_usdcAddress).decimals());
if (decimals != USDC_DECIMALS) {
_revert(IDecimals.IncorrectDecimals.selector);
}
HOLDING_CONTRACT = _holdingContract;
GLOW_TOKEN = IERC20(_glowToken);
MINER_POOL = IMinerPool(_minerPoolAddress);
}
/* -------------------------------------------------------------------------- */
/* buy glow */
/* -------------------------------------------------------------------------- */
/**
* @inheritdoc IEarlyLiquidity
*/
function buy(uint256 increments, uint256 maxCost) external {
// Cache the minerPool in memory for gas optimization.
IMinerPool pool = MINER_POOL;
address _holdingContract = HOLDING_CONTRACT;
// Calculate the total cost of the desired amount of tokens.
uint256 totalCost = getPrice(increments);
// If the computed total cost is greater than the user's specified max cost, revert the transaction.
if (totalCost > maxCost) {
_revert(IEarlyLiquidity.PriceTooHigh.selector);
}
// Calculate the exact amount of tokens to send to the user. Convert the normalized increments back to its original scale.
// Impossible to overflow since this is equal to {increments} in the function inputs
// 1 increment = .01 (or 1e16) glw
uint256 glowToSend = increments * 1e16;
// Check the balance of USDC in the miner pool before making a transfer.
uint256 balBefore = USDC_TOKEN.balanceOf(_holdingContract);
// Transfer USDC from the user to the miner pool to pay for the tokens.
SafeERC20.safeTransferFrom(USDC_TOKEN, msg.sender, _holdingContract, totalCost);
// Check the balance of USDC in the miner pool after the transfer to find the actual transferred amount.
uint256 balAfter = USDC_TOKEN.balanceOf(_holdingContract);
//Underflow should be impossible, unless the USDC contract is hacked and malicious
//in which case, this transaction will revert
//For almost all cases possible, this should not underflow/revert
uint256 diff = balAfter - balBefore;
// Transfer the desired amount of tokens to the user.
SafeERC20.safeTransfer(GLOW_TOKEN, msg.sender, glowToSend);
// Donate the received USDC to the miner rewards pool, possibly accounting for a tax or fee.
pool.donateToUSDCMinerRewardsPoolEarlyLiquidity(diff);
// Update the total amount of tokens sold by adding the normalized amount to the total.
_totalIncrementsSold += increments;
// Emit an event to log the purchase details.
emit IEarlyLiquidity.Purchase(msg.sender, glowToSend, totalCost);
// End of function; the explicit 'return' here is unnecessary but it indicates the function's conclusion.
return;
}
/* -------------------------------------------------------------------------- */
/* view functions */
/* -------------------------------------------------------------------------- */
/**
* @inheritdoc IEarlyLiquidity
*/
function getPrice(uint256 incrementsToPurchase) public view returns (uint256) {
if (incrementsToPurchase == 0) return 0;
return _getPrice(_totalIncrementsSold, incrementsToPurchase);
}
/**
* @inheritdoc IEarlyLiquidity
*/
function totalSold() public view returns (uint256) {
return _totalIncrementsSold * MIN_TOKEN_INCREMENT;
}
/**
* @inheritdoc IEarlyLiquidity
*/
function getCurrentPrice() external view returns (uint256) {
return _getPrice(_totalIncrementsSold, 1);
}
/* -------------------------------------------------------------------------- */
/* internal view */
/* -------------------------------------------------------------------------- */
/**
* @notice Calculates the price of a given amount of tokens
* @param totalIncrementsSold The total amount of .01 increments sold
* @param incrementsToBuy The amount of .01 increments to buy
* @return price price of the increments to purchase in USDC
* @dev since our increments are in .01, the function evaluates to Σ .003 * 2^((incrementId)/ 100_000_000)
* - for increment id = totalIncrementsSold id: to incrementId = incrementsToBuy
* - rounding errors do occur due to floating point math, but divergence is sub 1e-7
*/
function _getPrice(uint256 totalIncrementsSold, uint256 incrementsToBuy) private pure returns (uint256) {
// Check if the combined total of tokens sold and tokens to buy exceed the allowed amount.
// If it does, revert the transaction.
if (totalIncrementsSold + incrementsToBuy > TOTAL_INCREMENTS_TO_SELL) {
_revert(IEarlyLiquidity.AllSold.selector);
}
// Convert the number of increments to buy into a fixed-point representation.
int128 n = ABDKMath64x64.fromUInt(incrementsToBuy);
// Compute r^n, where 'r' is the common ratio of the geometric series.
// Using logarithmic properties, we compute the exponent as: n * ln(r).
// This step computes the value of r raised to the power of n.
int128 rToTheN = ABDKMath64x64.exp(ABDKMath64x64.mul(n, _LN_RATIO));
// Calculate the numerator for the sum formula of an infinite geometric series:
// numerator = 1 - r^n
int128 numerator = _ONE.sub(rToTheN);
// Divide the numerator by the denominator, where the denominator is typically
// (1 - r) for the sum of an infinite geometric series. Here, the denominator
// the fixed-point representation of (1 - r).
int128 divisionResult = numerator.div(_DENOMINATOR);
// Calculate the first term in the geometric series. The first term is based on
// the total amount of increments already sold.
int128 firstTermInSeries = _getFirstTermInSeries(totalIncrementsSold);
//divisionResult > than geometricSeries, so we convert divisionResult to uint256
uint256 firstTimeInSerieWithFixed = uint256(int256(firstTermInSeries));
//divisionResult is always positive so we can cast it to uint256
uint256 divUint = uint256(int256(divisionResult));
//We do the fixed point math in uint256 domain since we know that the result will be positive
//Below is a fixed point multiplication
uint256 mulResFixed = firstTimeInSerieWithFixed * divUint >> 64;
//convert {mulResFixed} back to uint256
return mulResFixed >> 64;
// The following comments are for the purpose of explaining why the code cannot overflow.
//The maximum value of totalIncrementsSold is 1,200,000,000
//The maximum value of incrementsToBuy is 1,200,000,000
//The max value of n is 1,200,000
// _LN_RATIO = ln(1.0000000069314718)
//The maximum value of rToTheN is e^(1,200,000,000 * ln(r)) = e^8.317766180304424 = 4096.000055644491
//The maximum value of numerator is 1 - 4096 = -4095
//The maximum value of divisionResult is -4095 / -0.0000000069314718 = 590,783,619,721.2834
//The maximum value of firstTermInSeries is 3000 * 2^12 = 12288000
//The maximum value of geometricSeries is 12288000 * 590,783,619,721.2834 = 7.259549119135131e+18
//This cant overflow since it's < 2^63-1
}
/**
* @notice Calculates the first term in the geometric series for the current price of the current token
* @param totalIncrementsSold - the total number of increments that have already been sold
* @return firstTerm - first term to be used in the geometric series
*/
function _getFirstTermInSeries(uint256 totalIncrementsSold) private pure returns (int128) {
// Convert 'totalSold' to a fixed-point representation using ABDKMath64x64.
// This is done to perform mathematical operations with precision.
int128 floatingPointTotalSold = ABDKMath64x64.fromUInt(totalIncrementsSold);
// The goal is to compute the exponent for: 2^(totalIncrements / 100,000,000)
// Using logarithmic properties, this can be re-written using the identity:
// b^c = a^(ln(b)*c) => 2^(totalIncrements / 100,000,000) = e^(ln(2) * totalIncrements / 100,000,000)
// Here, '_LN_2' is the natural logarithm of 2, and '_ONE_HUNDRED_MILLION' represents 100,000,000.
int128 exponent = _LN_2.mul(floatingPointTotalSold).div(_ONE_HUNDRED_MILLION);
// Compute e^(exponent), which effectively calculates 2^(totalIncrements / 100,000,000)
// because of the earlier logarithmic transformation.
int128 baseResult = ABDKMath64x64.exp(exponent);
// Multiply the result by 0.003, where '_POINT_ZERO_ZERO_THREE' is the fixed-point representation of 0.003.
int128 result = _POINT_ZERO_ZERO_THREE.mul(baseResult);
// The following comments are for the purpose of explaining why the code cannot overflow.
//ln(2) = 0.693147......
//floatingPointTotalSold will never be more than 1,200,000,000
//so the maximum value of the exponent will be .693147 * 1,200,000,000 / 100,000,000 = 8.316
//None of those numbers are greater than 2^63-1 (the maximum value of a 64x6x int)
//Max value of baseResult possible is e^8.316 = 4,089 (rounded up)
//The max input that baseResult can take in is 43 since (e^44 > type(64x64).max > e^43)
//We will never cause an overflow in the exponent calculation
//Max value of result is 1,000 * 4,088 = 4088000
//This is well within the range of 2^63-1 = 9,223,372,036,854,775,807 approx 9.223372e+18
// Return the final result.
return result;
}
/* -------------------------------------------------------------------------- */
/* private utils */
/* -------------------------------------------------------------------------- */
/**
* @notice More efficiently reverts with a bytes4 selector
* @param selector The selector to revert with
*/
function _revert(bytes4 selector) private pure {
// solhint-disable-next-line no-inline-assembly
assembly ("memory-safe") {
mstore(0x0, selector)
revert(0x0, 0x04)
}
}
/**
* @dev for more efficient zero address checks
*/
function _isZeroAddress(address a) private pure returns (bool isZero) {
// solhint-disable-next-line no-inline-assembly
assembly ("memory-safe") {
isZero := iszero(a)
}
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
if (nonceAfter != nonceBefore + 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IEarlyLiquidity {
/* -------------------------------------------------------------------------- */
/* errors */
/* -------------------------------------------------------------------------- */
error PriceTooHigh();
error ModNotZero();
error AllSold();
error MinerPoolAlreadySet();
error ZeroAddress();
error TooManyIncrements();
/* -------------------------------------------------------------------------- */
/* events */
/* -------------------------------------------------------------------------- */
/**
* @notice emitted when a purchase is made
* @param buyer The address of the buyer
* @param glwReceived The amount of glow the buyer received
* @param totalUSDCSpent The total amount of USDC the buyer spent to buy the tokens
* @dev emitted when {buy} is successfully called
*/
event Purchase(address indexed buyer, uint256 glwReceived, uint256 totalUSDCSpent);
/**
* @notice Buys tokens with USDC
* @param increments The amount of increments to buy
* - an {increment} is .01 GLW
* @param maxCost The maximum cost to pay for all the increments
*/
function buy(uint256 increments, uint256 maxCost) external;
/**
* @notice Calculates the price of a given amount of tokens
* @param increments The amount of increments to buy
* @return price - the total price in USDC for the given amount of increments
*/
function getPrice(uint256 increments) external view returns (uint256);
/**
* @notice Returns the total amount of GLW tokens sold so far
* @return totalSold - total amount of GLW tokens sold so far (18 decimal value)
*/
function totalSold() external view returns (uint256);
/**
* @notice Returns the current price of the next token.
* @return currentPrice current price of the next token in microdollars
*/
function getCurrentPrice() external view returns (uint256);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: BSD-4-Clause
/*
* ABDK Math 64.64 Smart Contract Library. Copyright © 2019 by ABDK Consulting.
* Author: Mikhail Vladimirov <mikhail.vladimirov@gmail.com>
*/
pragma solidity ^0.8.0;
/**
* Smart contract library of mathematical functions operating with signed
* 64.64-bit fixed point numbers. Signed 64.64-bit fixed point number is
* basically a simple fraction whose numerator is signed 128-bit integer and
* denominator is 2^64. As long as denominator is always the same, there is no
* need to store it, thus in Solidity signed 64.64-bit fixed point numbers are
* represented by int128 type holding only the numerator.
*/
library ABDKMath64x64 {
/*
* Minimum value signed 64.64-bit fixed point number may have.
*/
int128 private constant MIN_64x64 = -0x80000000000000000000000000000000;
/*
* Maximum value signed 64.64-bit fixed point number may have.
*/
int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
/**
* Convert signed 256-bit integer number into signed 64.64-bit fixed point
* number. Revert on overflow.
*
* @param x signed 256-bit integer number
* @return signed 64.64-bit fixed point number
*/
function fromInt(int256 x) internal pure returns (int128) {
unchecked {
require(x >= -0x8000000000000000 && x <= 0x7FFFFFFFFFFFFFFF);
return int128(x << 64);
}
}
/**
* Convert signed 64.64 fixed point number into signed 64-bit integer number
* rounding down.
*
* @param x signed 64.64-bit fixed point number
* @return signed 64-bit integer number
*/
function toInt(int128 x) internal pure returns (int64) {
unchecked {
return int64(x >> 64);
}
}
/**
* Convert unsigned 256-bit integer number into signed 64.64-bit fixed point
* number. Revert on overflow.
*
* @param x unsigned 256-bit integer number
* @return signed 64.64-bit fixed point number
*/
function fromUInt(uint256 x) internal pure returns (int128) {
unchecked {
require(x <= 0x7FFFFFFFFFFFFFFF);
return int128(int256(x << 64));
}
}
/**
* Convert signed 64.64 fixed point number into unsigned 64-bit integer
* number rounding down. Revert on underflow.
*
* @param x signed 64.64-bit fixed point number
* @return unsigned 64-bit integer number
*/
function toUInt(int128 x) internal pure returns (uint64) {
unchecked {
require(x >= 0);
return uint64(uint128(x >> 64));
}
}
/**
* Convert signed 128.128 fixed point number into signed 64.64-bit fixed point
* number rounding down. Revert on overflow.
*
* @param x signed 128.128-bin fixed point number
* @return signed 64.64-bit fixed point number
*/
function from128x128(int256 x) internal pure returns (int128) {
unchecked {
int256 result = x >> 64;
require(result >= MIN_64x64 && result <= MAX_64x64);
return int128(result);
}
}
/**
* Convert signed 64.64 fixed point number into signed 128.128 fixed point
* number.
*
* @param x signed 64.64-bit fixed point number
* @return signed 128.128 fixed point number
*/
function to128x128(int128 x) internal pure returns (int256) {
unchecked {
return int256(x) << 64;
}
}
/**
* Calculate x + y. Revert on overflow.
*
* @param x signed 64.64-bit fixed point number
* @param y signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function add(int128 x, int128 y) internal pure returns (int128) {
unchecked {
int256 result = int256(x) + y;
require(result >= MIN_64x64 && result <= MAX_64x64);
return int128(result);
}
}
/**
* Calculate x - y. Revert on overflow.
*
* @param x signed 64.64-bit fixed point number
* @param y signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function sub(int128 x, int128 y) internal pure returns (int128) {
unchecked {
int256 result = int256(x) - y;
require(result >= MIN_64x64 && result <= MAX_64x64);
return int128(result);
}
}
/**
* Calculate x * y rounding down. Revert on overflow.
*
* @param x signed 64.64-bit fixed point number
* @param y signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function mul(int128 x, int128 y) internal pure returns (int128) {
unchecked {
int256 result = int256(x) * y >> 64;
require(result >= MIN_64x64 && result <= MAX_64x64);
return int128(result);
}
}
/**
* Calculate x * y rounding towards zero, where x is signed 64.64 fixed point
* number and y is signed 256-bit integer number. Revert on overflow.
*
* @param x signed 64.64 fixed point number
* @param y signed 256-bit integer number
* @return signed 256-bit integer number
*/
function muli(int128 x, int256 y) internal pure returns (int256) {
unchecked {
if (x == MIN_64x64) {
require(
y >= -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
&& y <= 0x1000000000000000000000000000000000000000000000000
);
return -y << 63;
} else {
bool negativeResult = false;
if (x < 0) {
x = -x;
negativeResult = true;
}
if (y < 0) {
y = -y; // We rely on overflow behavior here
negativeResult = !negativeResult;
}
uint256 absoluteResult = mulu(x, uint256(y));
if (negativeResult) {
require(absoluteResult <= 0x8000000000000000000000000000000000000000000000000000000000000000);
return -int256(absoluteResult); // We rely on overflow behavior here
} else {
require(absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
return int256(absoluteResult);
}
}
}
}
/**
* Calculate x * y rounding down, where x is signed 64.64 fixed point number
* and y is unsigned 256-bit integer number. Revert on overflow.
*
* @param x signed 64.64 fixed point number
* @param y unsigned 256-bit integer number
* @return unsigned 256-bit integer number
*/
function mulu(int128 x, uint256 y) internal pure returns (uint256) {
unchecked {
if (y == 0) return 0;
require(x >= 0);
uint256 lo = (uint256(int256(x)) * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) >> 64;
uint256 hi = uint256(int256(x)) * (y >> 128);
require(hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
hi <<= 64;
require(hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - lo);
return hi + lo;
}
}
/**
* Calculate x / y rounding towards zero. Revert on overflow or when y is
* zero.
*
* @param x signed 64.64-bit fixed point number
* @param y signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function div(int128 x, int128 y) internal pure returns (int128) {
unchecked {
require(y != 0);
int256 result = (int256(x) << 64) / y;
require(result >= MIN_64x64 && result <= MAX_64x64);
return int128(result);
}
}
/**
* Calculate x / y rounding towards zero, where x and y are signed 256-bit
* integer numbers. Revert on overflow or when y is zero.
*
* @param x signed 256-bit integer number
* @param y signed 256-bit integer number
* @return signed 64.64-bit fixed point number
*/
function divi(int256 x, int256 y) internal pure returns (int128) {
unchecked {
require(y != 0);
bool negativeResult = false;
if (x < 0) {
x = -x; // We rely on overflow behavior here
negativeResult = true;
}
if (y < 0) {
y = -y; // We rely on overflow behavior here
negativeResult = !negativeResult;
}
uint128 absoluteResult = divuu(uint256(x), uint256(y));
if (negativeResult) {
require(absoluteResult <= 0x80000000000000000000000000000000);
return -int128(absoluteResult); // We rely on overflow behavior here
} else {
require(absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
return int128(absoluteResult); // We rely on overflow behavior here
}
}
}
/**
* Calculate x / y rounding towards zero, where x and y are unsigned 256-bit
* integer numbers. Revert on overflow or when y is zero.
*
* @param x unsigned 256-bit integer number
* @param y unsigned 256-bit integer number
* @return signed 64.64-bit fixed point number
*/
function divu(uint256 x, uint256 y) internal pure returns (int128) {
unchecked {
require(y != 0);
uint128 result = divuu(x, y);
require(result <= uint128(MAX_64x64));
return int128(result);
}
}
/**
* Calculate -x. Revert on overflow.
*
* @param x signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function neg(int128 x) internal pure returns (int128) {
unchecked {
require(x != MIN_64x64);
return -x;
}
}
/**
* Calculate |x|. Revert on overflow.
*
* @param x signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function abs(int128 x) internal pure returns (int128) {
unchecked {
require(x != MIN_64x64);
return x < 0 ? -x : x;
}
}
/**
* Calculate 1 / x rounding towards zero. Revert on overflow or when x is
* zero.
*
* @param x signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function inv(int128 x) internal pure returns (int128) {
unchecked {
require(x != 0);
int256 result = int256(0x100000000000000000000000000000000) / x;
require(result >= MIN_64x64 && result <= MAX_64x64);
return int128(result);
}
}
/**
* Calculate arithmetics average of x and y, i.e. (x + y) / 2 rounding down.
*
* @param x signed 64.64-bit fixed point number
* @param y signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function avg(int128 x, int128 y) internal pure returns (int128) {
unchecked {
return int128((int256(x) + int256(y)) >> 1);
}
}
/**
* Calculate geometric average of x and y, i.e. sqrt (x * y) rounding down.
* Revert on overflow or in case x * y is negative.
*
* @param x signed 64.64-bit fixed point number
* @param y signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function gavg(int128 x, int128 y) internal pure returns (int128) {
unchecked {
int256 m = int256(x) * int256(y);
require(m >= 0);
require(m < 0x4000000000000000000000000000000000000000000000000000000000000000);
return int128(sqrtu(uint256(m)));
}
}
/**
* Calculate x^y assuming 0^0 is 1, where x is signed 64.64 fixed point number
* and y is unsigned 256-bit integer number. Revert on overflow.
*
* @param x signed 64.64-bit fixed point number
* @param y uint256 value
* @return signed 64.64-bit fixed point number
*/
function pow(int128 x, uint256 y) internal pure returns (int128) {
unchecked {
bool negative = x < 0 && y & 1 == 1;
uint256 absX = uint128(x < 0 ? -x : x);
uint256 absResult;
absResult = 0x100000000000000000000000000000000;
if (absX <= 0x10000000000000000) {
absX <<= 63;
while (y != 0) {
if (y & 0x1 != 0) {
absResult = absResult * absX >> 127;
}
absX = absX * absX >> 127;
if (y & 0x2 != 0) {
absResult = absResult * absX >> 127;
}
absX = absX * absX >> 127;
if (y & 0x4 != 0) {
absResult = absResult * absX >> 127;
}
absX = absX * absX >> 127;
if (y & 0x8 != 0) {
absResult = absResult * absX >> 127;
}
absX = absX * absX >> 127;
y >>= 4;
}
absResult >>= 64;
} else {
uint256 absXShift = 63;
if (absX < 0x1000000000000000000000000) {
absX <<= 32;
absXShift -= 32;
}
if (absX < 0x10000000000000000000000000000) {
absX <<= 16;
absXShift -= 16;
}
if (absX < 0x1000000000000000000000000000000) {
absX <<= 8;
absXShift -= 8;
}
if (absX < 0x10000000000000000000000000000000) {
absX <<= 4;
absXShift -= 4;
}
if (absX < 0x40000000000000000000000000000000) {
absX <<= 2;
absXShift -= 2;
}
if (absX < 0x80000000000000000000000000000000) {
absX <<= 1;
absXShift -= 1;
}
uint256 resultShift = 0;
while (y != 0) {
require(absXShift < 64);
if (y & 0x1 != 0) {
absResult = absResult * absX >> 127;
resultShift += absXShift;
if (absResult > 0x100000000000000000000000000000000) {
absResult >>= 1;
resultShift += 1;
}
}
absX = absX * absX >> 127;
absXShift <<= 1;
if (absX >= 0x100000000000000000000000000000000) {
absX >>= 1;
absXShift += 1;
}
y >>= 1;
}
require(resultShift < 64);
absResult >>= 64 - resultShift;
}
int256 result = negative ? -int256(absResult) : int256(absResult);
require(result >= MIN_64x64 && result <= MAX_64x64);
return int128(result);
}
}
/**
* Calculate sqrt (x) rounding down. Revert if x < 0.
*
* @param x signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function sqrt(int128 x) internal pure returns (int128) {
unchecked {
require(x >= 0);
return int128(sqrtu(uint256(int256(x)) << 64));
}
}
/**
* Calculate binary logarithm of x. Revert if x <= 0.
*
* @param x signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function log_2(int128 x) internal pure returns (int128) {
unchecked {
require(x > 0);
int256 msb = 0;
int256 xc = x;
if (xc >= 0x10000000000000000) {
xc >>= 64;
msb += 64;
}
if (xc >= 0x100000000) {
xc >>= 32;
msb += 32;
}
if (xc >= 0x10000) {
xc >>= 16;
msb += 16;
}
if (xc >= 0x100) {
xc >>= 8;
msb += 8;
}
if (xc >= 0x10) {
xc >>= 4;
msb += 4;
}
if (xc >= 0x4) {
xc >>= 2;
msb += 2;
}
if (xc >= 0x2) msb += 1; // No need to shift xc anymore
int256 result = msb - 64 << 64;
uint256 ux = uint256(int256(x)) << uint256(127 - msb);
for (int256 bit = 0x8000000000000000; bit > 0; bit >>= 1) {
ux *= ux;
uint256 b = ux >> 255;
ux >>= 127 + b;
result += bit * int256(b);
}
return int128(result);
}
}
/**
* Calculate natural logarithm of x. Revert if x <= 0.
*
* @param x signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function ln(int128 x) internal pure returns (int128) {
unchecked {
require(x > 0);
return int128(int256(uint256(int256(log_2(x))) * 0xB17217F7D1CF79ABC9E3B39803F2F6AF >> 128));
}
}
/**
* Calculate binary exponent of x. Revert on overflow.
*
* @param x signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function exp_2(int128 x) internal pure returns (int128) {
unchecked {
require(x < 0x400000000000000000); // Overflow
if (x < -0x400000000000000000) return 0; // Underflow
uint256 result = 0x80000000000000000000000000000000;
if (x & 0x8000000000000000 > 0) {
result = result * 0x16A09E667F3BCC908B2FB1366EA957D3E >> 128;
}
if (x & 0x4000000000000000 > 0) {
result = result * 0x1306FE0A31B7152DE8D5A46305C85EDEC >> 128;
}
if (x & 0x2000000000000000 > 0) {
result = result * 0x1172B83C7D517ADCDF7C8C50EB14A791F >> 128;
}
if (x & 0x1000000000000000 > 0) {
result = result * 0x10B5586CF9890F6298B92B71842A98363 >> 128;
}
if (x & 0x800000000000000 > 0) {
result = result * 0x1059B0D31585743AE7C548EB68CA417FD >> 128;
}
if (x & 0x400000000000000 > 0) {
result = result * 0x102C9A3E778060EE6F7CACA4F7A29BDE8 >> 128;
}
if (x & 0x200000000000000 > 0) {
result = result * 0x10163DA9FB33356D84A66AE336DCDFA3F >> 128;
}
if (x & 0x100000000000000 > 0) {
result = result * 0x100B1AFA5ABCBED6129AB13EC11DC9543 >> 128;
}
if (x & 0x80000000000000 > 0) {
result = result * 0x10058C86DA1C09EA1FF19D294CF2F679B >> 128;
}
if (x & 0x40000000000000 > 0) {
result = result * 0x1002C605E2E8CEC506D21BFC89A23A00F >> 128;
}
if (x & 0x20000000000000 > 0) {
result = result * 0x100162F3904051FA128BCA9C55C31E5DF >> 128;
}
if (x & 0x10000000000000 > 0) {
result = result * 0x1000B175EFFDC76BA38E31671CA939725 >> 128;
}
if (x & 0x8000000000000 > 0) {
result = result * 0x100058BA01FB9F96D6CACD4B180917C3D >> 128;
}
if (x & 0x4000000000000 > 0) {
result = result * 0x10002C5CC37DA9491D0985C348C68E7B3 >> 128;
}
if (x & 0x2000000000000 > 0) {
result = result * 0x1000162E525EE054754457D5995292026 >> 128;
}
if (x & 0x1000000000000 > 0) {
result = result * 0x10000B17255775C040618BF4A4ADE83FC >> 128;
}
if (x & 0x800000000000 > 0) {
result = result * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB >> 128;
}
if (x & 0x400000000000 > 0) {
result = result * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9 >> 128;
}
if (x & 0x200000000000 > 0) {
result = result * 0x10000162E43F4F831060E02D839A9D16D >> 128;
}
if (x & 0x100000000000 > 0) {
result = result * 0x100000B1721BCFC99D9F890EA06911763 >> 128;
}
if (x & 0x80000000000 > 0) {
result = result * 0x10000058B90CF1E6D97F9CA14DBCC1628 >> 128;
}
if (x & 0x40000000000 > 0) {
result = result * 0x1000002C5C863B73F016468F6BAC5CA2B >> 128;
}
if (x & 0x20000000000 > 0) {
result = result * 0x100000162E430E5A18F6119E3C02282A5 >> 128;
}
if (x & 0x10000000000 > 0) {
result = result * 0x1000000B1721835514B86E6D96EFD1BFE >> 128;
}
if (x & 0x8000000000 > 0) {
result = result * 0x100000058B90C0B48C6BE5DF846C5B2EF >> 128;
}
if (x & 0x4000000000 > 0) {
result = result * 0x10000002C5C8601CC6B9E94213C72737A >> 128;
}
if (x & 0x2000000000 > 0) {
result = result * 0x1000000162E42FFF037DF38AA2B219F06 >> 128;
}
if (x & 0x1000000000 > 0) {
result = result * 0x10000000B17217FBA9C739AA5819F44F9 >> 128;
}
if (x & 0x800000000 > 0) {
result = result * 0x1000000058B90BFCDEE5ACD3C1CEDC823 >> 128;
}
if (x & 0x400000000 > 0) {
result = result * 0x100000002C5C85FE31F35A6A30DA1BE50 >> 128;
}
if (x & 0x200000000 > 0) {
result = result * 0x10000000162E42FF0999CE3541B9FFFCF >> 128;
}
if (x & 0x100000000 > 0) {
result = result * 0x100000000B17217F80F4EF5AADDA45554 >> 128;
}
if (x & 0x80000000 > 0) {
result = result * 0x10000000058B90BFBF8479BD5A81B51AD >> 128;
}
if (x & 0x40000000 > 0) {
result = result * 0x1000000002C5C85FDF84BD62AE30A74CC >> 128;
}
if (x & 0x20000000 > 0) {
result = result * 0x100000000162E42FEFB2FED257559BDAA >> 128;
}
if (x & 0x10000000 > 0) {
result = result * 0x1000000000B17217F7D5A7716BBA4A9AE >> 128;
}
if (x & 0x8000000 > 0) {
result = result * 0x100000000058B90BFBE9DDBAC5E109CCE >> 128;
}
if (x & 0x4000000 > 0) {
result = result * 0x10000000002C5C85FDF4B15DE6F17EB0D >> 128;
}
if (x & 0x2000000 > 0) {
result = result * 0x1000000000162E42FEFA494F1478FDE05 >> 128;
}
if (x & 0x1000000 > 0) {
result = result * 0x10000000000B17217F7D20CF927C8E94C >> 128;
}
if (x & 0x800000 > 0) {
result = result * 0x1000000000058B90BFBE8F71CB4E4B33D >> 128;
}
if (x & 0x400000 > 0) {
result = result * 0x100000000002C5C85FDF477B662B26945 >> 128;
}
if (x & 0x200000 > 0) {
result = result * 0x10000000000162E42FEFA3AE53369388C >> 128;
}
if (x & 0x100000 > 0) {
result = result * 0x100000000000B17217F7D1D351A389D40 >> 128;
}
if (x & 0x80000 > 0) {
result = result * 0x10000000000058B90BFBE8E8B2D3D4EDE >> 128;
}
if (x & 0x40000 > 0) {
result = result * 0x1000000000002C5C85FDF4741BEA6E77E >> 128;
}
if (x & 0x20000 > 0) {
result = result * 0x100000000000162E42FEFA39FE95583C2 >> 128;
}
if (x & 0x10000 > 0) {
result = result * 0x1000000000000B17217F7D1CFB72B45E1 >> 128;
}
if (x & 0x8000 > 0) {
result = result * 0x100000000000058B90BFBE8E7CC35C3F0 >> 128;
}
if (x & 0x4000 > 0) {
result = result * 0x10000000000002C5C85FDF473E242EA38 >> 128;
}
if (x & 0x2000 > 0) {
result = result * 0x1000000000000162E42FEFA39F02B772C >> 128;
}
if (x & 0x1000 > 0) {
result = result * 0x10000000000000B17217F7D1CF7D83C1A >> 128;
}
if (x & 0x800 > 0) {
result = result * 0x1000000000000058B90BFBE8E7BDCBE2E >> 128;
}
if (x & 0x400 > 0) {
result = result * 0x100000000000002C5C85FDF473DEA871F >> 128;
}
if (x & 0x200 > 0) {
result = result * 0x10000000000000162E42FEFA39EF44D91 >> 128;
}
if (x & 0x100 > 0) {
result = result * 0x100000000000000B17217F7D1CF79E949 >> 128;
}
if (x & 0x80 > 0) {
result = result * 0x10000000000000058B90BFBE8E7BCE544 >> 128;
}
if (x & 0x40 > 0) {
result = result * 0x1000000000000002C5C85FDF473DE6ECA >> 128;
}
if (x & 0x20 > 0) {
result = result * 0x100000000000000162E42FEFA39EF366F >> 128;
}
if (x & 0x10 > 0) {
result = result * 0x1000000000000000B17217F7D1CF79AFA >> 128;
}
if (x & 0x8 > 0) {
result = result * 0x100000000000000058B90BFBE8E7BCD6D >> 128;
}
if (x & 0x4 > 0) {
result = result * 0x10000000000000002C5C85FDF473DE6B2 >> 128;
}
if (x & 0x2 > 0) {
result = result * 0x1000000000000000162E42FEFA39EF358 >> 128;
}
if (x & 0x1 > 0) {
result = result * 0x10000000000000000B17217F7D1CF79AB >> 128;
}
result >>= uint256(int256(63 - (x >> 64)));
require(result <= uint256(int256(MAX_64x64)));
return int128(int256(result));
}
}
/**
* Calculate natural exponent of x. Revert on overflow.
*
* @param x signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function exp(int128 x) internal pure returns (int128) {
unchecked {
require(x < 0x400000000000000000); // Overflow
if (x < -0x400000000000000000) return 0; // Underflow
return exp_2(int128(int256(x) * 0x171547652B82FE1777D0FFDA0D23A7D12 >> 128));
}
}
/**
* Calculate x / y rounding towards zero, where x and y are unsigned 256-bit
* integer numbers. Revert on overflow or when y is zero.
*
* @param x unsigned 256-bit integer number
* @param y unsigned 256-bit integer number
* @return unsigned 64.64-bit fixed point number
*/
function divuu(uint256 x, uint256 y) private pure returns (uint128) {
unchecked {
require(y != 0);
uint256 result;
if (x <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {
result = (x << 64) / y;
} else {
uint256 msb = 192;
uint256 xc = x >> 192;
if (xc >= 0x100000000) {
xc >>= 32;
msb += 32;
}
if (xc >= 0x10000) {
xc >>= 16;
msb += 16;
}
if (xc >= 0x100) {
xc >>= 8;
msb += 8;
}
if (xc >= 0x10) {
xc >>= 4;
msb += 4;
}
if (xc >= 0x4) {
xc >>= 2;
msb += 2;
}
if (xc >= 0x2) msb += 1; // No need to shift xc anymore
result = (x << 255 - msb) / ((y - 1 >> msb - 191) + 1);
require(result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
uint256 hi = result * (y >> 128);
uint256 lo = result * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
uint256 xh = x >> 192;
uint256 xl = x << 64;
if (xl < lo) xh -= 1;
xl -= lo; // We rely on overflow behavior here
lo = hi << 128;
if (xl < lo) xh -= 1;
xl -= lo; // We rely on overflow behavior here
result += xh == hi >> 128 ? xl / y : 1;
}
require(result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
return uint128(result);
}
}
/**
* Calculate sqrt (x) rounding down, where x is unsigned 256-bit integer
* number.
*
* @param x unsigned 256-bit integer number
* @return unsigned 128-bit integer number
*/
function sqrtu(uint256 x) private pure returns (uint128) {
unchecked {
if (x == 0) {
return 0;
} else {
uint256 xx = x;
uint256 r = 1;
if (xx >= 0x100000000000000000000000000000000) {
xx >>= 128;
r <<= 64;
}
if (xx >= 0x10000000000000000) {
xx >>= 64;
r <<= 32;
}
if (xx >= 0x100000000) {
xx >>= 32;
r <<= 16;
}
if (xx >= 0x10000) {
xx >>= 16;
r <<= 8;
}
if (xx >= 0x100) {
xx >>= 8;
r <<= 4;
}
if (xx >= 0x10) {
xx >>= 4;
r <<= 2;
}
if (xx >= 0x4) r <<= 1;
r = (r + x / r) >> 1;
r = (r + x / r) >> 1;
r = (r + x / r) >> 1;
r = (r + x / r) >> 1;
r = (r + x / r) >> 1;
r = (r + x / r) >> 1;
r = (r + x / r) >> 1; // Seven iterations should be enough
uint256 r1 = x / r;
return uint128(r < r1 ? r : r1);
}
}
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IMinerPool {
/* -------------------------------------------------------------------------- */
/* errors */
/* -------------------------------------------------------------------------- */
error ElectricityFuturesSignatureExpired();
error ElectricityFuturesAuctionEnded();
error ElectricityFuturesAuctionBidTooLow();
error ElectricityFuturesAuctionAuthorizationTooLong();
error ElectricityFuturesAuctionInvalidSignature();
error ElectricityFutureAuctionBidMustBeGreaterThanMinimumBid();
error CallerNotEarlyLiquidity();
error NotUSDCToken();
error InvalidProof();
error UserAlreadyClaimed();
error AlreadyMintedToCarbonCreditAuction();
error BucketNotFinalized();
error CallerNotVetoCouncilMember();
error CannotDelayEmptyBucket();
error CannotDelayBucketThatNeedsToUpdateSlashNonce();
error BucketAlreadyDelayed();
error SignerNotGCA();
error SignatureDoesNotMatchUser();
error GlowWeightOverflow();
error USDCWeightOverflow();
error GlowWeightGreaterThanTotalWeight();
error USDCWeightGreaterThanTotalWeight();
/* -------------------------------------------------------------------------- */
/* state-changing */
/* -------------------------------------------------------------------------- */
/**
* @notice Allows anyone to donate USDC into the miner USDC rewards pool
* @notice the amount is split across 192 weeks starting at the current week + 16
* @param amount - amount to deposit
*/
function donateToUSDCMinerRewardsPool(uint256 amount) external;
/**
* @notice Allows the early liquidity to donate USDC into the miner USDC rewards pool
* @notice the amount is split across 192 weeks starting at the current week + 16
* @dev the USDC token must be a valid USDC token
* @dev early liquidity will safeTransfer from the user to the miner pool
* - and then call this function directly.
* - we do this to prevent extra transfers.
* @param amount - amount to deposit
*/
function donateToUSDCMinerRewardsPoolEarlyLiquidity(uint256 amount) external;
/**
* @notice allows a user to claim their rewards for a bucket
* @dev It's highly recommended to use a CLI or UI to call this function.
* - the proof can only be generated off-chain with access to the entire tree
* - furthermore, USDC tokens must be correctly input in order to receive rewards
* - the USDC tokens should be kept on record off-chain.
* - failure to input all correct USDC Tokens will result in lost rewards
* @param bucketId - the id of the bucket
* @param glwWeight - the weight of the user's glw rewards
* @param USDCWeight - the weight of the user's USDC rewards
* @param proof - the merkle proof of the user's rewards
* - the leaves are {payoutWallet, glwWeight, USDCWeight}
* @param index - the index of the report in the bucket
* - that contains the merkle root where the user's rewards are stored
* @param user - the address of the user
* @param claimFromInflation - whether or not to claim glow from inflation
* @param signature - the eip712 signature that allows a relayer to execute the action
* - to claim for a user.
* - the relayer is not able to access rewards under any means
* - rewards are always sent to the {user}
*/
function claimRewardFromBucket(
uint256 bucketId,
uint256 glwWeight,
uint256 USDCWeight,
bytes32[] calldata proof,
uint256 index,
address user,
bool claimFromInflation,
bytes memory signature
) external;
/**
* @notice allows a veto council member to delay the finalization of a bucket
* @dev the bucket must already be initialized in order to be delayed
* @dev the bucket cannot be finalized in order to be delayed
* @dev the bucket can be delayed multiple times
* @param bucketId - the id of the bucket to delay
*/
function delayBucketFinalization(uint256 bucketId) external;
/* -------------------------------------------------------------------------- */
/* view */
/* -------------------------------------------------------------------------- */
/**
* @notice returns true if a bucket has been delayed
* @param bucketId - the id of the bucket
* @return true if the bucket has been delayed
*/
function hasBucketBeenDelayed(uint256 bucketId) external view returns (bool);
/**
* @notice returns the bytes32 digest of the claim reward from bucket message
* @param bucketId - the id of the bucket
* @param glwWeight - the weight of the user's glw rewards in the leaf of the report root
* @param USDCWeight - the weight of the user's USDC rewards in the leaf of the report root
* @param index - the index of the report in the bucket
* - that contains the merkle root where the user's rewards are stored
* @param claimFromInflation - whether or not to claim glow from inflation
* @return the bytes32 digest of the claim reward from bucket message
*/
function createClaimRewardFromBucketDigest(
uint256 bucketId,
uint256 glwWeight,
uint256 USDCWeight,
uint256 index,
bool claimFromInflation
) external view returns (bytes32);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}