// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.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();
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/Checkpoints.sol)
// This file was procedurally generated from scripts/generate/templates/Checkpoints.js.
pragma solidity ^0.8.20;
import {Math} from "../math/Math.sol";
/**
* @dev This library defines the `Trace*` struct, for checkpointing values as they change at different points in
* time, and later looking up past values by block number. See {Votes} as an example.
*
* To create a history of checkpoints define a variable type `Checkpoints.Trace*` in your contract, and store a new
* checkpoint for the current transaction block using the {push} function.
*/
library Checkpoints {
/**
* @dev A value was attempted to be inserted on a past checkpoint.
*/
error CheckpointUnorderedInsertion();
struct Trace224 {
Checkpoint224[] _checkpoints;
}
struct Checkpoint224 {
uint32 _key;
uint224 _value;
}
/**
* @dev Pushes a (`key`, `value`) pair into a Trace224 so that it is stored as the checkpoint.
*
* Returns previous value and new value.
*
* IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint32).max` key set will disable the
* library.
*/
function push(Trace224 storage self, uint32 key, uint224 value) internal returns (uint224, uint224) {
return _insert(self._checkpoints, key, value);
}
/**
* @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if
* there is none.
*/
function lowerLookup(Trace224 storage self, uint32 key) internal view returns (uint224) {
uint256 len = self._checkpoints.length;
uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
}
/**
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
* if there is none.
*/
function upperLookup(Trace224 storage self, uint32 key) internal view returns (uint224) {
uint256 len = self._checkpoints.length;
uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
* if there is none.
*
* NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high
* keys).
*/
function upperLookupRecent(Trace224 storage self, uint32 key) internal view returns (uint224) {
uint256 len = self._checkpoints.length;
uint256 low = 0;
uint256 high = len;
if (len > 5) {
uint256 mid = len - Math.sqrt(len);
if (key < _unsafeAccess(self._checkpoints, mid)._key) {
high = mid;
} else {
low = mid + 1;
}
}
uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high);
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
*/
function latest(Trace224 storage self) internal view returns (uint224) {
uint256 pos = self._checkpoints.length;
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
* in the most recent checkpoint.
*/
function latestCheckpoint(Trace224 storage self) internal view returns (bool exists, uint32 _key, uint224 _value) {
uint256 pos = self._checkpoints.length;
if (pos == 0) {
return (false, 0, 0);
} else {
Checkpoint224 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
return (true, ckpt._key, ckpt._value);
}
}
/**
* @dev Returns the number of checkpoint.
*/
function length(Trace224 storage self) internal view returns (uint256) {
return self._checkpoints.length;
}
/**
* @dev Returns checkpoint at given position.
*/
function at(Trace224 storage self, uint32 pos) internal view returns (Checkpoint224 memory) {
return self._checkpoints[pos];
}
/**
* @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
* or by updating the last one.
*/
function _insert(Checkpoint224[] storage self, uint32 key, uint224 value) private returns (uint224, uint224) {
uint256 pos = self.length;
if (pos > 0) {
// Copying to memory is important here.
Checkpoint224 memory last = _unsafeAccess(self, pos - 1);
// Checkpoint keys must be non-decreasing.
if (last._key > key) {
revert CheckpointUnorderedInsertion();
}
// Update or push new checkpoint
if (last._key == key) {
_unsafeAccess(self, pos - 1)._value = value;
} else {
self.push(Checkpoint224({_key: key, _value: value}));
}
return (last._value, value);
} else {
self.push(Checkpoint224({_key: key, _value: value}));
return (0, value);
}
}
/**
* @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high`
* if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive
* `high`.
*
* WARNING: `high` should not be greater than the array's length.
*/
function _upperBinaryLookup(
Checkpoint224[] storage self,
uint32 key,
uint256 low,
uint256 high
) private view returns (uint256) {
while (low < high) {
uint256 mid = Math.average(low, high);
if (_unsafeAccess(self, mid)._key > key) {
high = mid;
} else {
low = mid + 1;
}
}
return high;
}
/**
* @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or
* `high` if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and
* exclusive `high`.
*
* WARNING: `high` should not be greater than the array's length.
*/
function _lowerBinaryLookup(
Checkpoint224[] storage self,
uint32 key,
uint256 low,
uint256 high
) private view returns (uint256) {
while (low < high) {
uint256 mid = Math.average(low, high);
if (_unsafeAccess(self, mid)._key < key) {
low = mid + 1;
} else {
high = mid;
}
}
return high;
}
/**
* @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
*/
function _unsafeAccess(
Checkpoint224[] storage self,
uint256 pos
) private pure returns (Checkpoint224 storage result) {
assembly {
mstore(0, self.slot)
result.slot := add(keccak256(0, 0x20), pos)
}
}
struct Trace208 {
Checkpoint208[] _checkpoints;
}
struct Checkpoint208 {
uint48 _key;
uint208 _value;
}
/**
* @dev Pushes a (`key`, `value`) pair into a Trace208 so that it is stored as the checkpoint.
*
* Returns previous value and new value.
*
* IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint48).max` key set will disable the
* library.
*/
function push(Trace208 storage self, uint48 key, uint208 value) internal returns (uint208, uint208) {
return _insert(self._checkpoints, key, value);
}
/**
* @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if
* there is none.
*/
function lowerLookup(Trace208 storage self, uint48 key) internal view returns (uint208) {
uint256 len = self._checkpoints.length;
uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
}
/**
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
* if there is none.
*/
function upperLookup(Trace208 storage self, uint48 key) internal view returns (uint208) {
uint256 len = self._checkpoints.length;
uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
* if there is none.
*
* NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high
* keys).
*/
function upperLookupRecent(Trace208 storage self, uint48 key) internal view returns (uint208) {
uint256 len = self._checkpoints.length;
uint256 low = 0;
uint256 high = len;
if (len > 5) {
uint256 mid = len - Math.sqrt(len);
if (key < _unsafeAccess(self._checkpoints, mid)._key) {
high = mid;
} else {
low = mid + 1;
}
}
uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high);
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
*/
function latest(Trace208 storage self) internal view returns (uint208) {
uint256 pos = self._checkpoints.length;
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
* in the most recent checkpoint.
*/
function latestCheckpoint(Trace208 storage self) internal view returns (bool exists, uint48 _key, uint208 _value) {
uint256 pos = self._checkpoints.length;
if (pos == 0) {
return (false, 0, 0);
} else {
Checkpoint208 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
return (true, ckpt._key, ckpt._value);
}
}
/**
* @dev Returns the number of checkpoint.
*/
function length(Trace208 storage self) internal view returns (uint256) {
return self._checkpoints.length;
}
/**
* @dev Returns checkpoint at given position.
*/
function at(Trace208 storage self, uint32 pos) internal view returns (Checkpoint208 memory) {
return self._checkpoints[pos];
}
/**
* @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
* or by updating the last one.
*/
function _insert(Checkpoint208[] storage self, uint48 key, uint208 value) private returns (uint208, uint208) {
uint256 pos = self.length;
if (pos > 0) {
// Copying to memory is important here.
Checkpoint208 memory last = _unsafeAccess(self, pos - 1);
// Checkpoint keys must be non-decreasing.
if (last._key > key) {
revert CheckpointUnorderedInsertion();
}
// Update or push new checkpoint
if (last._key == key) {
_unsafeAccess(self, pos - 1)._value = value;
} else {
self.push(Checkpoint208({_key: key, _value: value}));
}
return (last._value, value);
} else {
self.push(Checkpoint208({_key: key, _value: value}));
return (0, value);
}
}
/**
* @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high`
* if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive
* `high`.
*
* WARNING: `high` should not be greater than the array's length.
*/
function _upperBinaryLookup(
Checkpoint208[] storage self,
uint48 key,
uint256 low,
uint256 high
) private view returns (uint256) {
while (low < high) {
uint256 mid = Math.average(low, high);
if (_unsafeAccess(self, mid)._key > key) {
high = mid;
} else {
low = mid + 1;
}
}
return high;
}
/**
* @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or
* `high` if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and
* exclusive `high`.
*
* WARNING: `high` should not be greater than the array's length.
*/
function _lowerBinaryLookup(
Checkpoint208[] storage self,
uint48 key,
uint256 low,
uint256 high
) private view returns (uint256) {
while (low < high) {
uint256 mid = Math.average(low, high);
if (_unsafeAccess(self, mid)._key < key) {
low = mid + 1;
} else {
high = mid;
}
}
return high;
}
/**
* @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
*/
function _unsafeAccess(
Checkpoint208[] storage self,
uint256 pos
) private pure returns (Checkpoint208 storage result) {
assembly {
mstore(0, self.slot)
result.slot := add(keccak256(0, 0x20), pos)
}
}
struct Trace160 {
Checkpoint160[] _checkpoints;
}
struct Checkpoint160 {
uint96 _key;
uint160 _value;
}
/**
* @dev Pushes a (`key`, `value`) pair into a Trace160 so that it is stored as the checkpoint.
*
* Returns previous value and new value.
*
* IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint96).max` key set will disable the
* library.
*/
function push(Trace160 storage self, uint96 key, uint160 value) internal returns (uint160, uint160) {
return _insert(self._checkpoints, key, value);
}
/**
* @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if
* there is none.
*/
function lowerLookup(Trace160 storage self, uint96 key) internal view returns (uint160) {
uint256 len = self._checkpoints.length;
uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
}
/**
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
* if there is none.
*/
function upperLookup(Trace160 storage self, uint96 key) internal view returns (uint160) {
uint256 len = self._checkpoints.length;
uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
* if there is none.
*
* NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high
* keys).
*/
function upperLookupRecent(Trace160 storage self, uint96 key) internal view returns (uint160) {
uint256 len = self._checkpoints.length;
uint256 low = 0;
uint256 high = len;
if (len > 5) {
uint256 mid = len - Math.sqrt(len);
if (key < _unsafeAccess(self._checkpoints, mid)._key) {
high = mid;
} else {
low = mid + 1;
}
}
uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high);
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
*/
function latest(Trace160 storage self) internal view returns (uint160) {
uint256 pos = self._checkpoints.length;
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
* in the most recent checkpoint.
*/
function latestCheckpoint(Trace160 storage self) internal view returns (bool exists, uint96 _key, uint160 _value) {
uint256 pos = self._checkpoints.length;
if (pos == 0) {
return (false, 0, 0);
} else {
Checkpoint160 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
return (true, ckpt._key, ckpt._value);
}
}
/**
* @dev Returns the number of checkpoint.
*/
function length(Trace160 storage self) internal view returns (uint256) {
return self._checkpoints.length;
}
/**
* @dev Returns checkpoint at given position.
*/
function at(Trace160 storage self, uint32 pos) internal view returns (Checkpoint160 memory) {
return self._checkpoints[pos];
}
/**
* @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
* or by updating the last one.
*/
function _insert(Checkpoint160[] storage self, uint96 key, uint160 value) private returns (uint160, uint160) {
uint256 pos = self.length;
if (pos > 0) {
// Copying to memory is important here.
Checkpoint160 memory last = _unsafeAccess(self, pos - 1);
// Checkpoint keys must be non-decreasing.
if (last._key > key) {
revert CheckpointUnorderedInsertion();
}
// Update or push new checkpoint
if (last._key == key) {
_unsafeAccess(self, pos - 1)._value = value;
} else {
self.push(Checkpoint160({_key: key, _value: value}));
}
return (last._value, value);
} else {
self.push(Checkpoint160({_key: key, _value: value}));
return (0, value);
}
}
/**
* @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high`
* if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive
* `high`.
*
* WARNING: `high` should not be greater than the array's length.
*/
function _upperBinaryLookup(
Checkpoint160[] storage self,
uint96 key,
uint256 low,
uint256 high
) private view returns (uint256) {
while (low < high) {
uint256 mid = Math.average(low, high);
if (_unsafeAccess(self, mid)._key > key) {
high = mid;
} else {
low = mid + 1;
}
}
return high;
}
/**
* @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or
* `high` if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and
* exclusive `high`.
*
* WARNING: `high` should not be greater than the array's length.
*/
function _lowerBinaryLookup(
Checkpoint160[] storage self,
uint96 key,
uint256 low,
uint256 high
) private view returns (uint256) {
while (low < high) {
uint256 mid = Math.average(low, high);
if (_unsafeAccess(self, mid)._key < key) {
low = mid + 1;
} else {
high = mid;
}
}
return high;
}
/**
* @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
*/
function _unsafeAccess(
Checkpoint160[] storage self,
uint256 pos
) private pure returns (Checkpoint160 storage result) {
assembly {
mstore(0, self.slot)
result.slot := add(keccak256(0, 0x20), pos)
}
}
}
// SPDX-License-Identifier: GPL-2.0-or-later
// As the copyright holder of this work, Ubiquity Labs retains
// the right to distribute, use, and modify this code under any license of
// their choosing, in addition to the terms of the GPL-v2 or later.
pragma solidity ^0.8.25;
// factory contraints on pools
uint8 constant MAX_PROTOCOL_FEE_RATIO_D3 = 0.25e3; // 25%
uint256 constant MAX_PROTOCOL_LENDING_FEE_RATE_D18 = 0.02e18; // 2%
uint64 constant MAX_POOL_FEE_D18 = 0.9e18; // 90%
uint64 constant MIN_LOOKBACK = 1 seconds;
uint64 constant MAX_TICK_SPACING = 10_000;
// pool constraints
uint8 constant NUMBER_OF_KINDS = 4;
int32 constant NUMBER_OF_KINDS_32 = int32(int8(NUMBER_OF_KINDS));
uint256 constant MAX_TICK = 322_378; // max price 1e14 in D18 scale
int32 constant MAX_TICK_32 = int32(int256(MAX_TICK));
int32 constant MIN_TICK_32 = int32(-int256(MAX_TICK));
uint256 constant MAX_BINS_TO_MERGE = 3;
uint128 constant MINIMUM_LIQUIDITY = 1e8;
// accessor named constants
uint8 constant ALL_KINDS_MASK = 0xF; // 0b1111
uint8 constant PERMISSIONED_LIQUIDITY_MASK = 0x10; // 0b010000
uint8 constant PERMISSIONED_SWAP_MASK = 0x20; // 0b100000
uint8 constant OPTIONS_MASK = ALL_KINDS_MASK | PERMISSIONED_LIQUIDITY_MASK | PERMISSIONED_SWAP_MASK; // 0b111111
// named values
address constant MERGED_LP_BALANCE_ADDRESS = address(0);
uint256 constant MERGED_LP_BALANCE_SUBACCOUNT = 0;
uint128 constant ONE = 1e18;
uint128 constant ONE_SQUARED = 1e36;
int256 constant INT256_ONE = 1e18;
uint256 constant ONE_D8 = 1e8;
uint256 constant ONE_D3 = 1e3;
int40 constant INT_ONE_D8 = 1e8;
int40 constant HALF_TICK_D8 = 0.5e8;
uint8 constant DEFAULT_DECIMALS = 18;
uint256 constant DEFAULT_SCALE = 1;
bytes constant EMPTY_PRICE_BREAKS = hex"010000000000000000000000";
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*/
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
* ```
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import "./EntropyStructs.sol";
interface EntropyEvents {
event Registered(EntropyStructs.ProviderInfo provider);
event Requested(EntropyStructs.Request request);
event RequestedWithCallback(
address indexed provider,
address indexed requestor,
uint64 indexed sequenceNumber,
bytes32 userRandomNumber,
EntropyStructs.Request request
);
event Revealed(
EntropyStructs.Request request,
bytes32 userRevelation,
bytes32 providerRevelation,
bytes32 blockHash,
bytes32 randomNumber
);
event RevealedWithCallback(
EntropyStructs.Request request,
bytes32 userRandomNumber,
bytes32 providerRevelation,
bytes32 randomNumber
);
event ProviderFeeUpdated(address provider, uint128 oldFee, uint128 newFee);
event ProviderUriUpdated(address provider, bytes oldUri, bytes newUri);
event ProviderFeeManagerUpdated(
address provider,
address oldFeeManager,
address newFeeManager
);
event Withdrawal(
address provider,
address recipient,
uint128 withdrawnAmount
);
}
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
contract EntropyStructs {
struct ProviderInfo {
uint128 feeInWei;
uint128 accruedFeesInWei;
// The commitment that the provider posted to the blockchain, and the sequence number
// where they committed to this. This value is not advanced after the provider commits,
// and instead is stored to help providers track where they are in the hash chain.
bytes32 originalCommitment;
uint64 originalCommitmentSequenceNumber;
// Metadata for the current commitment. Providers may optionally use this field to help
// manage rotations (i.e., to pick the sequence number from the correct hash chain).
bytes commitmentMetadata;
// Optional URI where clients can retrieve revelations for the provider.
// Client SDKs can use this field to automatically determine how to retrieve random values for each provider.
// TODO: specify the API that must be implemented at this URI
bytes uri;
// The first sequence number that is *not* included in the current commitment (i.e., an exclusive end index).
// The contract maintains the invariant that sequenceNumber <= endSequenceNumber.
// If sequenceNumber == endSequenceNumber, the provider must rotate their commitment to add additional random values.
uint64 endSequenceNumber;
// The sequence number that will be assigned to the next inbound user request.
uint64 sequenceNumber;
// The current commitment represents an index/value in the provider's hash chain.
// These values are used to verify requests for future sequence numbers. Note that
// currentCommitmentSequenceNumber < sequenceNumber.
//
// The currentCommitment advances forward through the provider's hash chain as values
// are revealed on-chain.
bytes32 currentCommitment;
uint64 currentCommitmentSequenceNumber;
// An address that is authorized to set / withdraw fees on behalf of this provider.
address feeManager;
}
struct Request {
// Storage slot 1 //
address provider;
uint64 sequenceNumber;
// The number of hashes required to verify the provider revelation.
uint32 numHashes;
// Storage slot 2 //
// The commitment is keccak256(userCommitment, providerCommitment). Storing the hash instead of both saves 20k gas by
// eliminating 1 store.
bytes32 commitment;
// Storage slot 3 //
// The number of the block where this request was created.
// Note that we're using a uint64 such that we have an additional space for an address and other fields in
// this storage slot. Although block.number returns a uint256, 64 bits should be plenty to index all of the
// blocks ever generated.
uint64 blockNumber;
// The address that requested this random number.
address requester;
// If true, incorporate the blockhash of blockNumber into the generated random value.
bool useBlockhash;
// If true, the requester will be called back with the generated random value.
bool isRequestWithCallback;
// There are 2 remaining bytes of free space in this slot.
}
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IFeeVault} from "./interfaces/IFeeVault.sol";
/**
* @notice Simple vault that holds ERC20 tokens. USers can escrow tokens on
* this vault and then retrieve that any point in the future.
*/
contract FeeVault is IFeeVault {
using SafeERC20 for IERC20;
/// @inheritdoc IFeeVault
mapping(IERC20 token => mapping(address user => uint256 balance)) public tokenUserToBalance;
/// @inheritdoc IFeeVault
function claim(IERC20 token) external returns (uint256 amount) {
address account = msg.sender;
amount = tokenUserToBalance[token][account];
if (amount > 0) {
tokenUserToBalance[token][account] = 0;
token.safeTransfer(account, amount);
emit Claim(token, account, amount);
}
}
function _depositAmount(IERC20 token, address account, uint256 amount) internal {
if (amount > 0) {
tokenUserToBalance[token][account] += amount;
emit DepositAmount(token, account, amount);
}
}
/// @inheritdoc IFeeVault
function depositAmount(IERC20 token, address addr1, uint256 amount1) external {
if (amount1 > 0) {
token.transferFrom(msg.sender, address(this), amount1);
_depositAmount(token, addr1, amount1);
}
}
/// @inheritdoc IFeeVault
function depositAmounts(
IERC20 token,
address addr1,
uint256 amount1,
address addr2,
uint256 amount2,
address addr3,
uint256 amount3,
address addr4,
uint256 amount4
) external {
if (amount1 + amount2 + amount3 + amount4 > 0) {
token.transferFrom(msg.sender, address(this), amount1 + amount2 + amount3 + amount4);
_depositAmount(token, addr1, amount1);
_depositAmount(token, addr2, amount2);
_depositAmount(token, addr3, amount3);
_depositAmount(token, addr4, amount4);
}
}
/// @inheritdoc IFeeVault
function depositAmounts(IERC20 token, address addr1, uint256 amount1, address addr2, uint256 amount2) external {
if (amount1 + amount2 > 0) {
token.transferFrom(msg.sender, address(this), amount1 + amount2);
_depositAmount(token, addr1, amount1);
_depositAmount(token, addr2, amount2);
}
}
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;
import {ERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {Time} from "@openzeppelin/contracts/utils/types/Time.sol";
import {Checkpoints} from "@openzeppelin/contracts/utils/structs/Checkpoints.sol";
import {IHistoricalBalanceNonTransferableERC20} from "./interfaces/IHistoricalBalanceNonTransferableERC20.sol";
/**
* @notice Adds support for tracking historical balance on ERC20Votes (not just
* historical voting power) and adds support for contributing and retrieving
* incentives pro-rata of historical balanceOf.
*
* @notice Uses a timestamp-based clock for checkpoints as opposed to the
* default OZ implementation that is blocknumber based.
*/
contract HistoricalBalanceNonTransferableERC20 is ERC20, IHistoricalBalanceNonTransferableERC20 {
using Checkpoints for Checkpoints.Trace208;
mapping(address account => Checkpoints.Trace208) private _balanceOfCheckpoints;
Checkpoints.Trace208 private _totalCheckpoints;
/// @inheritdoc IHistoricalBalanceNonTransferableERC20
address public immutable minter;
/// @inheritdoc IHistoricalBalanceNonTransferableERC20
IERC20 public immutable trackerToken;
/// @inheritdoc IHistoricalBalanceNonTransferableERC20
AddressBalance public topAccount;
/// @inheritdoc IHistoricalBalanceNonTransferableERC20
mapping(uint256 dayNumber => AddressBalance account) public topAccountByDay;
constructor(string memory name_, string memory symbol_, IERC20 _trackerToken) ERC20(name_, symbol_) {
minter = msg.sender;
trackerToken = _trackerToken;
}
function mint(address recipient, uint256 amount) public {
if (msg.sender != minter) revert OnlyMinter(msg.sender, minter);
_mint(recipient, amount);
}
function topAccountCurrentDay() external view returns (address account, uint256 balance) {
AddressBalance memory thisDayData = topAccountByDay[_dayNumber()];
if (thisDayData.holder != address(0)) return (thisDayData.holder, thisDayData.balance);
return (topAccount.holder, topAccount.balance);
}
function _dayNumber() internal view returns (uint256) {
return block.timestamp / (1 days);
}
//////////////////////
// Past Balance
//////////////////////
/// @inheritdoc IHistoricalBalanceNonTransferableERC20
function getPastBalanceOf(address account, uint256 timepoint) public view returns (uint256 balance) {
uint48 currentTimepoint = clock();
if (timepoint > currentTimepoint) {
revert ERC5805FutureLookup(timepoint, currentTimepoint);
} else if (timepoint == currentTimepoint) {
return balanceOf(account);
}
// cast is safe because of conditional above
return _balanceOfCheckpoints[account].upperLookupRecent(uint48(timepoint));
}
/// @inheritdoc IHistoricalBalanceNonTransferableERC20
function getPastTotalSupply(uint256 timepoint) public view virtual returns (uint256) {
uint48 currentTimepoint = clock();
if (timepoint > currentTimepoint) {
revert ERC5805FutureLookup(timepoint, currentTimepoint);
} else if (timepoint == currentTimepoint) {
return totalSupply();
}
return _totalCheckpoints.upperLookupRecent(SafeCast.toUint48(timepoint));
}
/**
* @dev Returns the current total supply of votes.
*/
function _getTotalSupply() internal view virtual returns (uint256) {
return _totalCheckpoints.latest();
}
function _updateTopAccount(address to) internal {
// update all-time top account
uint256 newBalance = balanceOf(to);
if (newBalance >= topAccount.balance) {
topAccount.holder = to;
topAccount.balance = newBalance;
emit NewTopHolder(to, newBalance);
}
// update this day top account
uint256 dayNumber = _dayNumber();
AddressBalance storage dayAccount = topAccountByDay[dayNumber];
uint256 beginningOfDayBalance = getPastBalanceOf(to, dayNumber * (1 days));
uint256 newBalanceThisDay = newBalance - beginningOfDayBalance;
if (newBalanceThisDay >= dayAccount.balance) {
dayAccount.holder = to;
dayAccount.balance = newBalanceThisDay;
emit NewTopDayHolder(dayNumber, to, newBalanceThisDay);
}
}
//////////////////////
// Overrides
//////////////////////
function _update(address from, address to, uint256 amount) internal virtual override {
ERC20._update(from, to, amount);
_updateTopAccount(to);
// there are only mints, not transfers or burns
// update totals
if (from == address(0)) {
_push(_totalCheckpoints, _add, SafeCast.toUint208(amount));
}
// update user balance
if (from != to && amount > 0) {
if (to != address(0)) {
_push(_balanceOfCheckpoints[to], _add, SafeCast.toUint208(amount));
}
}
}
function transfer(address, uint256) public pure override(ERC20, IERC20) returns (bool) {
revert TransferNotAllowed();
}
function transferFrom(address, address, uint256) public pure override(ERC20, IERC20) returns (bool) {
revert TransferNotAllowed();
}
//////////////////////
// Clock
//////////////////////
function clock() public view returns (uint48) {
return Time.timestamp();
}
/**
* @dev Machine-readable description of the clock as specified in ERC-6372.
*/
// solhint-disable-next-line func-name-mixedcase
function CLOCK_MODE() public pure returns (string memory) {
return "mode=timestamp";
}
//////////////////////
// Helpers
//////////////////////
function _push(
Checkpoints.Trace208 storage store,
function(uint208, uint208) view returns (uint208) op,
uint208 delta
) private returns (uint208, uint208) {
return store.push(clock(), op(store.latest(), delta));
}
function _add(uint208 a, uint208 b) private pure returns (uint208) {
return a + b;
}
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IHistoricalBalanceNonTransferableERC20, HistoricalBalanceNonTransferableERC20} from "./HistoricalBalanceNonTransferableERC20.sol";
library HistoricalBalanceNonTransferableERC20Deployer {
function deploy(
string memory _name,
string memory _symbol,
IERC20 _trackerToken
) external returns (IHistoricalBalanceNonTransferableERC20 token) {
token = new HistoricalBalanceNonTransferableERC20(_name, _symbol, _trackerToken);
}
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;
interface IDistribution {
error InvalidTick(int32 tick);
error InvalidBinId(uint32 binId);
error CurveIndexNotSupported(uint256 curveIndex);
function lastTick() external returns (int32);
function binIdToTick(bool tokenIsA, uint32 binId) external pure returns (int32);
function ticks(bool tokenIsA) external pure returns (int32[] memory _ticks);
function tickToBinId(bool tokenIsA, int32 _tick) external pure returns (uint32 binId);
function amount(bool tokenIsA, uint256 k, uint256 curveIndex) external pure returns (uint128);
function amounts(bool tokenIsA, uint256 curveIndex) external pure returns (uint128[] memory _amounts);
function quoteBaseline(bool tokenIsA, uint256 k, uint256 curveIndex) external pure returns (uint256 quoteAmount);
function quoteBaselineAtTick(
bool tokenIsA,
int32 tick,
uint256 curveIndex
) external pure returns (uint256 quoteAmount);
function tailAmounts() external pure returns (uint128[] memory _amounts);
function swappedTick(bool tokenIsA) external pure returns (int32);
function amountBaselines() external pure returns (uint256[6] memory baselines);
function tailBaseline() external pure returns (uint256 baseline);
function tailTicks(bool tokenIsA) external pure returns (int32[] memory _ticks);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.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);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.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.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
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].
*
* CAUTION: See Security Considerations above.
*/
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);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5805.sol)
pragma solidity ^0.8.20;
import {IVotes} from "../governance/utils/IVotes.sol";
import {IERC6372} from "./IERC6372.sol";
interface IERC5805 is IERC6372, IVotes {}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC6372.sol)
pragma solidity ^0.8.20;
interface IERC6372 {
/**
* @dev Clock used for flagging checkpoints. Can be overridden to implement timestamp based checkpoints (and voting).
*/
function clock() external view returns (uint48);
/**
* @dev Description of the clock
*/
// solhint-disable-next-line func-name-mixedcase
function CLOCK_MODE() external view returns (string memory);
}
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "./EntropyEvents.sol";
interface IEntropy is EntropyEvents {
// Register msg.sender as a randomness provider. The arguments are the provider's configuration parameters
// and initial commitment. Re-registering the same provider rotates the provider's commitment (and updates
// the feeInWei).
//
// chainLength is the number of values in the hash chain *including* the commitment, that is, chainLength >= 1.
function register(
uint128 feeInWei,
bytes32 commitment,
bytes calldata commitmentMetadata,
uint64 chainLength,
bytes calldata uri
) external;
// Withdraw a portion of the accumulated fees for the provider msg.sender.
// Calling this function will transfer `amount` wei to the caller (provided that they have accrued a sufficient
// balance of fees in the contract).
function withdraw(uint128 amount) external;
// Withdraw a portion of the accumulated fees for provider. The msg.sender must be the fee manager for this provider.
// Calling this function will transfer `amount` wei to the caller (provided that they have accrued a sufficient
// balance of fees in the contract).
function withdrawAsFeeManager(address provider, uint128 amount) external;
// As a user, request a random number from `provider`. Prior to calling this method, the user should
// generate a random number x and keep it secret. The user should then compute hash(x) and pass that
// as the userCommitment argument. (You may call the constructUserCommitment method to compute the hash.)
//
// This method returns a sequence number. The user should pass this sequence number to
// their chosen provider (the exact method for doing so will depend on the provider) to retrieve the provider's
// number. The user should then call fulfillRequest to construct the final random number.
//
// This method will revert unless the caller provides a sufficient fee (at least getFee(provider)) as msg.value.
// Note that excess value is *not* refunded to the caller.
function request(
address provider,
bytes32 userCommitment,
bool useBlockHash
) external payable returns (uint64 assignedSequenceNumber);
// Request a random number. The method expects the provider address and a secret random number
// in the arguments. It returns a sequence number.
//
// The address calling this function should be a contract that inherits from the IEntropyConsumer interface.
// The `entropyCallback` method on that interface will receive a callback with the generated random number.
//
// This method will revert unless the caller provides a sufficient fee (at least getFee(provider)) as msg.value.
// Note that excess value is *not* refunded to the caller.
function requestWithCallback(
address provider,
bytes32 userRandomNumber
) external payable returns (uint64 assignedSequenceNumber);
// Fulfill a request for a random number. This method validates the provided userRandomness and provider's proof
// against the corresponding commitments in the in-flight request. If both values are validated, this function returns
// the corresponding random number.
//
// Note that this function can only be called once per in-flight request. Calling this function deletes the stored
// request information (so that the contract doesn't use a linear amount of storage in the number of requests).
// If you need to use the returned random number more than once, you are responsible for storing it.
function reveal(
address provider,
uint64 sequenceNumber,
bytes32 userRevelation,
bytes32 providerRevelation
) external returns (bytes32 randomNumber);
// Fulfill a request for a random number. This method validates the provided userRandomness
// and provider's revelation against the corresponding commitment in the in-flight request. If both values are validated
// and the requestor address is a contract address, this function calls the requester's entropyCallback method with the
// sequence number, provider address and the random number as arguments. Else if the requestor is an EOA, it won't call it.
//
// Note that this function can only be called once per in-flight request. Calling this function deletes the stored
// request information (so that the contract doesn't use a linear amount of storage in the number of requests).
// If you need to use the returned random number more than once, you are responsible for storing it.
//
// Anyone can call this method to fulfill a request, but the callback will only be made to the original requester.
function revealWithCallback(
address provider,
uint64 sequenceNumber,
bytes32 userRandomNumber,
bytes32 providerRevelation
) external;
function getProviderInfo(
address provider
) external view returns (EntropyStructs.ProviderInfo memory info);
function getDefaultProvider() external view returns (address provider);
function getRequest(
address provider,
uint64 sequenceNumber
) external view returns (EntropyStructs.Request memory req);
function getFee(address provider) external view returns (uint128 feeAmount);
function getAccruedPythFees()
external
view
returns (uint128 accruedPythFeesInWei);
function setProviderFee(uint128 newFeeInWei) external;
function setProviderFeeAsFeeManager(
address provider,
uint128 newFeeInWei
) external;
function setProviderUri(bytes calldata newUri) external;
// Set manager as the fee manager for the provider msg.sender.
// After calling this function, manager will be able to set the provider's fees and withdraw them.
// Only one address can be the fee manager for a provider at a time -- calling this function again with a new value
// will override the previous value. Call this function with the all-zero address to disable the fee manager role.
function setFeeManager(address manager) external;
function constructUserCommitment(
bytes32 userRandomness
) external pure returns (bytes32 userCommitment);
function combineRandomValues(
bytes32 userRandomness,
bytes32 providerRandomness,
bytes32 blockHash
) external pure returns (bytes32 combinedRandomness);
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IFeeVault {
event DepositAmount(IERC20 indexed token, address indexed account, uint256 amount);
event Claim(IERC20 indexed token, address indexed account, uint256 amount);
/**
* @notice View the balance of a given address for a given token.
*/
function tokenUserToBalance(IERC20 token, address user) external view returns (uint256 balance);
/**
* @notice Transfers any fee set aside for sender to the sender.
*/
function claim(IERC20 token) external returns (uint256 amount);
/**
* @notice Deposit token amounts to addresses. This function will
* transfer the sum amounts to the FeeVault. The amounts can later be
* `claim`ed at any time by the respective deposited address.
*/
function depositAmount(IERC20 token, address addr1, uint256 amount1) external;
/**
* @notice Deposit token amounts to addresses. This function will
* transfer the sum amounts to the FeeVault. The amounts can later be
* `claim`ed at any time by the respective deposited address.
*/
function depositAmounts(
IERC20 token,
address addr1,
uint256 amount1,
address addr2,
uint256 amount2,
address addr3,
uint256 amount3,
address addr4,
uint256 amount4
) external;
/**
* @notice Deposit token amounts to addresses. This function will
* transfer the sum amounts to the FeeVault. The amounts can later be
* `claim`ed at any time by the respective deposited address.
*/
function depositAmounts(IERC20 token, address addr1, uint256 amount1, address addr2, uint256 amount2) external;
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;
interface IHistoricalBalance {
/**
* @notice This function retrieves the historical balance of an account at
* a specific point in time.
* @param account The address of the account for which to retrieve the
* historical balance.
* @param timepoint The timepoint (block number or timestamp depending on
* implementation) at which to query the balance (uint256).
* @return balance The balance of the account at the specified timepoint.
*/
function getPastBalanceOf(address account, uint256 timepoint) external view returns (uint256 balance);
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/**
* @notice Adds support for tracking historical balance on ERC20 and adds
* support for contributing and retrieving incentives pro-rata of historical
* balanceOf.
*
* @notice Uses a timestamp-based clock for checkpoints as opposed to the
* default OZ implementation that is blocknumber based.
*/
interface IHistoricalBalanceNonTransferableERC20 is IERC20 {
error ERC5805FutureLookup(uint256 timepoint, uint48 clock);
error TransferNotAllowed();
error OnlyMinter(address sender, address minter);
event NewTopHolder(address topHolder, uint256 topHolderBalance);
event NewTopDayHolder(uint256 dayNumber, address topHolder, uint256 topHolderBalance);
struct AddressBalance {
address holder;
uint256 balance;
}
/**
* @notice This function retrieves the historical balance of an account at
* a specific point in time.
* @param account The address of the account for which to retrieve the
* historical balance.
* @param timepoint The timepoint (block number or timestamp depending on
* implementation) at which to query the balance (uint256).
* @return balance The balance of the account at the specified timepoint.
*/
function getPastBalanceOf(address account, uint256 timepoint) external view returns (uint256 balance);
/**
* @notice Returns the total supply of votes available at a specific moment in the past. If the `clock()` is
* configured to use block numbers, this will return the value at the end of the corresponding block.
*
* NOTE: This value is the sum of all available balance.
*/
function getPastTotalSupply(uint256 timepoint) external view returns (uint256);
/**
* @notice Token units this trackers tracks
*/
function trackerToken() external view returns (IERC20);
/**
* @notice Account that can mint tokens
*/
function minter() external view returns (address);
/**
* @notice Mint token
*/
function mint(address recipient, uint256 amount) external;
/**
* @notice Account/Balance that has the highest balance
*/
function topAccount() external view returns (address, uint256);
/**
* @notice Account/Balance of the top holder for given day
*/
function topAccountByDay(uint256 dayNumber) external view returns (address, uint256);
/**
* @notice Account/Balance of the top holder for given day
*/
function topAccountCurrentDay() external view returns (address, uint256);
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ITokenManager} from "./ITokenManager.sol";
import {ITokenManagerLens} from "./ITokenManagerLens.sol";
import {ISwapper} from "./ISwapper.sol";
import {IMaverickV2Pool} from "../v2-common/interfaces/IMaverickV2Pool.sol";
import {IMaverickV2Factory} from "../v2-common/interfaces/IMaverickV2Factory.sol";
interface ILaunchFactory {
error InvalidLaunchFee(uint256 valueSent, uint256 valueRequired);
error InvalidPoolFee(uint256 fee, uint256 feeMinAllowed, uint256 feeMaxAllowed);
error InvalidBorrowFeeRate();
error AllLiquidityDeployed();
error MainLiquidityDeployed();
error MainLiquidityNotDeployed();
error NameSymbolAlreadyDeployed();
struct TokenData {
string name;
string symbol;
string imageHash;
string metadataHash;
}
struct BorrowFeeRates {
uint64 proportionToVotingDistributorD18;
uint64 proportionToCreatorD18;
uint64 proportionToVoterD18;
}
struct PoolData {
uint64 buyFee;
uint64 sellFee;
uint8 curveIndex;
}
struct TempLaunchData {
TokenData tokenData;
IERC20 token;
IMaverickV2Pool pool;
bool borrowingEnabled;
address feeRecipient;
PoolData poolData;
}
event CreateTokenManager(
IERC20 indexed token,
IMaverickV2Pool indexed pool,
ITokenManager indexed tokenManager,
address feeRecipient,
bool borrowingEnabled,
TokenData tokenData,
PoolData poolData,
IERC20 quoteToken,
bool tokenIsA,
uint256 ethLaunchFeePaid
);
event SetProtocolFeeCollector(address protocolFeeCollector, bool notifyFeeCollector);
event SetLaunchFeeCollector(address launchFeeCollector);
event SetSwapper(ISwapper swapper);
event SetBorrowFeeRateD18(uint256 borrowFeeRate);
event SetEthLaunchFee(uint128 ethLaunchFee);
event SetProtocolFee(uint128 protocolFeeProportionD18);
event SetBorrowFeeRates(BorrowFeeRates rates);
event DeployTailLiqudiity(IERC20 indexed token, IMaverickV2Pool indexed pool, ITokenManager indexed tokenManager);
event DeployMainLiqudiity(IERC20 indexed token, IMaverickV2Pool indexed pool, ITokenManager indexed tokenManager);
event AddFreeMinter(address user);
event RemoveFreeMinter(address user);
function tempLaunchData() external view returns (TempLaunchData memory);
/**
* @notice Indicator of whether an address can mint a token without paying
* the eth fee
*/
function freeMinter(address) external view returns (bool);
/**
* @notice Gets the ratio of fees going to voter/creator/protocol
*/
function borrowFeeRates()
external
view
returns (uint64 proportionToVotingDistributorD18, uint64 proportionToCreatorD18, uint64 proportionToVoterD18);
/**
* @notice Gets the ETH launch fee for creating a new token manager
*/
function ethLaunchFee() external view returns (uint128);
/**
* @notice Gets Borrowing fee rate
*/
function borrowFeeRateD18() external view returns (uint256);
/**
* @notice Gets the quote contract address
*/
function quoteToken() external view returns (IERC20);
/**
* @notice Gets the Token Manager Lens contract
*/
function lens() external view returns (ITokenManagerLens);
/**
* @notice Gets the Maverick V2 Factory contract
*/
function factory() external view returns (IMaverickV2Factory);
/**
* @notice Gets the launch fee collector address
*/
function launchFeeCollector() external view returns (address);
/**
* @notice Checks if a given Token Manager is managed by this factory
*/
function isFactoryManager(ITokenManager tokenManager) external view returns (bool);
/**
* @notice Checks if a given token has been created by this factory
*/
function isFactoryToken(IERC20 token) external view returns (bool);
/**
* @notice Checks if a given pool has been created by this factory
*/
function isFactoryPool(IMaverickV2Pool pool) external view returns (bool);
/**
* @notice Indicates if symbol hash has already been deployed
*/
function symbolHashDeployed(bytes32 spaceStrippedLowerCaseSymbolHash) external view returns (bool);
/**
* @notice Gets the Token Manager associated with a given ERC20 token
*/
function managerFromToken(IERC20 token) external view returns (ITokenManager tokenManager);
/**
* @notice True if tail liquidity has been deployed
*/
function tailLiquidityDeployed(IERC20 token) external view returns (bool);
/**
* @notice True if main liquidity has been deployed
*/
function mainLiquidityDeployed(IERC20 token) external view returns (bool);
/**
* @notice Gets the Token Manager associated with a given pool
*/
function managerFromPool(IMaverickV2Pool pool) external view returns (ITokenManager tokenManager);
/**
* @notice Gets the total number of Token Managers created by this factory
*/
function managerCount() external view returns (uint256 _managerCount);
/**
* @notice Gets the factory swapper which is also the permissioned pool accessor
*/
function swapper() external view returns (ISwapper swapper);
/**
* @notice Gets a list of Token Managers within a specified range
* @param startIndex The starting index of the range (inclusive)
* @param endIndex The ending index of the range (exclusive)
of Token Manager contracts
*/
function managers(uint256 startIndex, uint256 endIndex) external view returns (ITokenManager[] memory);
/**
* @notice Creates a new Token Manager contract
* @param tokenData The name/symbol and ipfs data of the new token
* @param poolData The pool fee/distribution parameters
* @param feeRecipient The address that will receive the fees
* @param borrowingEnabled Whether borrowing is enabled for the new token
* @param tokenSalt Salt for token create2
* @return tokenManager The newly created Token Manager contract
*/
function createTokenManager(
TokenData memory tokenData,
PoolData memory poolData,
address feeRecipient,
bool borrowingEnabled,
string memory tokenSalt
) external payable returns (ITokenManager tokenManager);
/**
* @notice Creates a new Token Manager contract but does not add liquidity to pool.
* @param tokenData The name/symbol and ipfs data of the new token
* @param poolData The pool fee/distribution parameters
* @param feeRecipient The address that will receive the fees
* @param borrowingEnabled Whether borrowing is enabled for the new token
* @param tokenSalt Salt for token create2
* @return tokenManager The newly created Token Manager contract
*/
function createTokenManagerWithoutLiquidity(
TokenData memory tokenData,
PoolData memory poolData,
address feeRecipient,
bool borrowingEnabled,
string memory tokenSalt
) external payable returns (ITokenManager tokenManager);
/**
* @notice Creates a new Token Manager contract
* @param tokenData The name/symbol and ipfs data of the new token
* @param poolData The pool fee/distribution parameters
* @param feeRecipient The address that will receive the fees
* @param borrowingEnabled Whether borrowing is enabled for the new token
* @param tokenSalt Salt for token create2
* @param tokenRecipient The address to receive the purchased tokens
* @param ethToQuotePool The Maverick pool that can swap eth for quote token
* @param amountOutMinimum The minimum amount of tokens to receive
* @param deployTail True to deploy all supply; false to only deploy main supply
* @return tokenManager The newly created Token Manager contract
* @return amountOut Amount sent with buy
*/
function createTokenManagerAndBuy(
TokenData memory tokenData,
PoolData memory poolData,
address feeRecipient,
bool borrowingEnabled,
string memory tokenSalt,
address tokenRecipient,
IMaverickV2Pool ethToQuotePool,
uint256 amountOutMinimum,
bool deployTail
) external payable returns (ITokenManager tokenManager, uint256 amountOut);
/**
* @notice Deploys a thin layer of liquidity 100 ticks past the end of the
* initial distribution. This is effectively prices the supply out to
* price = inifinity meaning that the launch pool will always have supply to
* sell.
*/
function deployTailLiquidity(IERC20 token) external;
/**
* @notice Deploys main liquidity to a token's pool.
*/
function deployMainLiquidity(IERC20 token) external;
/**
* @notice Init code hash of launch token. Useful for computing create2
* addresses of tokens. Address can be computed in solidity with:
*
* ```
* Create2.computeAddress(
* keccak256(abi.encode(symbol, salt)),
* factory.tokenCreationCodeHash(),
* address(_factory)
* )
*```
*/
function tokenCreationCodeHash() external pure returns (bytes32);
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;
import {ILaunchFactory} from "./ILaunchFactory.sol";
import {IHistoricalBalance} from "./external/IHistoricalBalance.sol";
interface ILaunchToken is IHistoricalBalance {
error SupplyAlreadyMinted();
/**
* @notice Returns the hash of the token image.
*/
function getImageHash() external view returns (string memory);
/**
* @notice Returns the hash of the token metadata.
*/
function getMetadataHash() external view returns (string memory);
/**
* @notice Returns the hash of the token metadata.
*/
function getLaunchFactory() external view returns (ILaunchFactory);
}
// SPDX-License-Identifier: GPL-2.0-or-later
// As the copyright holder of this work, Ubiquity Labs retains
// the right to distribute, use, and modify this code under any license of
// their choosing, in addition to the terms of the GPL-v2 or later.
pragma solidity ^0.8.25;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IMaverickV2Pool} from "./IMaverickV2Pool.sol";
interface IMaverickV2Factory {
error FactoryInvalidProtocolFeeRatio(uint8 protocolFeeRatioD3);
error FactoryInvalidLendingFeeRate(uint256 protocolLendingFeeRateD18);
error FactoryProtocolFeeOnRenounce(uint8 protocolFeeRatioD3);
error FactorAlreadyInitialized();
error FactorNotInitialized();
error FactoryInvalidTokenOrder(IERC20 _tokenA, IERC20 _tokenB);
error FactoryInvalidFee();
error FactoryInvalidKinds(uint8 kinds);
error FactoryInvalidTickSpacing(uint256 tickSpacing);
error FactoryInvalidLookback(uint256 lookback);
error FactoryInvalidTokenDecimals(uint8 decimalsA, uint8 decimalsB);
error FactoryPoolAlreadyExists(
uint256 feeAIn,
uint256 feeBIn,
uint256 tickSpacing,
uint256 lookback,
IERC20 tokenA,
IERC20 tokenB,
uint8 kinds,
address accessor
);
error FactoryAccessorMustBeNonZero();
event PoolCreated(
IMaverickV2Pool poolAddress,
uint8 protocolFeeRatio,
uint256 feeAIn,
uint256 feeBIn,
uint256 tickSpacing,
uint256 lookback,
int32 activeTick,
IERC20 tokenA,
IERC20 tokenB,
uint8 kinds,
address accessor
);
event SetFactoryProtocolFeeRatio(uint8 protocolFeeRatioD3);
event SetFactoryProtocolLendingFeeRate(uint256 lendingFeeRateD18);
event SetFactoryProtocolFeeReceiver(address receiver);
struct DeployParameters {
uint64 feeAIn;
uint64 feeBIn;
uint32 lookback;
int32 activeTick;
uint64 tokenAScale;
uint64 tokenBScale;
// slot
IERC20 tokenA;
// slot
IERC20 tokenB;
// slot
uint16 tickSpacing;
uint8 options;
address accessor;
}
/**
* @notice Called by deployer library to initialize a pool.
*/
function deployParameters()
external
view
returns (
uint64 feeAIn,
uint64 feeBIn,
uint32 lookback,
int32 activeTick,
uint64 tokenAScale,
uint64 tokenBScale,
// slot
IERC20 tokenA,
// slot
IERC20 tokenB,
// slot
uint16 tickSpacing,
uint8 options,
address accessor
);
/**
* @notice Create a new MaverickV2Pool with symmetric swap fees.
* @param fee Fraction of the pool swap amount that is retained as an LP in
* D18 scale.
* @param tickSpacing Tick spacing of pool where 1.0001^tickSpacing is the
* bin width.
* @param lookback Pool lookback in seconds.
* @param tokenA Address of tokenA.
* @param tokenB Address of tokenB.
* @param activeTick Tick position that contains the active bins.
* @param kinds 1-15 number to represent the active kinds
* 0b0001 = static;
* 0b0010 = right;
* 0b0100 = left;
* 0b1000 = both.
* E.g. a pool with all 4 modes will have kinds = b1111 = 15
*/
function create(
uint64 fee,
uint16 tickSpacing,
uint32 lookback,
IERC20 tokenA,
IERC20 tokenB,
int32 activeTick,
uint8 kinds
) external returns (IMaverickV2Pool);
/**
* @notice Create a new MaverickV2Pool.
* @param feeAIn Fraction of the pool swap amount for tokenA-input swaps
* that is retained as an LP in D18 scale.
* @param feeBIn Fraction of the pool swap amount for tokenB-input swaps
* that is retained as an LP in D18 scale.
* @param tickSpacing Tick spacing of pool where 1.0001^tickSpacing is the
* bin width.
* @param lookback Pool lookback in seconds.
* @param tokenA Address of tokenA.
* @param tokenB Address of tokenB.
* @param activeTick Tick position that contains the active bins.
* @param kinds 1-15 number to represent the active kinds
* 0b0001 = static;
* 0b0010 = right;
* 0b0100 = left;
* 0b1000 = both.
* e.g. a pool with all 4 modes will have kinds = b1111 = 15
*/
function create(
uint64 feeAIn,
uint64 feeBIn,
uint16 tickSpacing,
uint32 lookback,
IERC20 tokenA,
IERC20 tokenB,
int32 activeTick,
uint8 kinds
) external returns (IMaverickV2Pool);
/**
* @notice Create a new MaverickV2PoolPermissioned with symmetric swap fees
* with all functions permissioned. Set fee to zero to make the pool fee settable by the accessor.
* @param fee Fraction of the pool swap amount that is retained as an LP in
* D18 scale.
* @param tickSpacing Tick spacing of pool where 1.0001^tickSpacing is the
* bin width.
* @param lookback Pool lookback in seconds.
* @param tokenA Address of tokenA.
* @param tokenB Address of tokenB.
* @param activeTick Tick position that contains the active bins.
* @param kinds 1-15 number to represent the active kinds
* 0b0001 = static;
* 0b0010 = right;
* 0b0100 = left;
* 0b1000 = both.
* E.g. a pool with all 4 modes will have kinds = b1111 = 15
* @param accessor Only address that can access the pool's public write functions.
*/
function createPermissioned(
uint64 fee,
uint16 tickSpacing,
uint32 lookback,
IERC20 tokenA,
IERC20 tokenB,
int32 activeTick,
uint8 kinds,
address accessor
) external returns (IMaverickV2Pool);
/**
* @notice Create a new MaverickV2PoolPermissioned with all functions
* permissioned. Set fees to zero to make the pool fee settable by the
* accessor.
* @param feeAIn Fraction of the pool swap amount for tokenA-input swaps
* that is retained as an LP in D18 scale.
* @param feeBIn Fraction of the pool swap amount for tokenB-input swaps
* that is retained as an LP in D18 scale.
* @param tickSpacing Tick spacing of pool where 1.0001^tickSpacing is the
* bin width.
* @param lookback Pool lookback in seconds.
* @param tokenA Address of tokenA.
* @param tokenB Address of tokenB.
* @param activeTick Tick position that contains the active bins.
* @param kinds 1-15 number to represent the active kinds
* 0b0001 = static;
* 0b0010 = right;
* 0b0100 = left;
* 0b1000 = both.
* E.g. a pool with all 4 modes will have kinds = b1111 = 15
* @param accessor only address that can access the pool's public write functions.
*/
function createPermissioned(
uint64 feeAIn,
uint64 feeBIn,
uint16 tickSpacing,
uint32 lookback,
IERC20 tokenA,
IERC20 tokenB,
int32 activeTick,
uint8 kinds,
address accessor
) external returns (IMaverickV2Pool);
/**
* @notice Create a new MaverickV2PoolPermissioned with the option to make
* a subset of function permissionless. Set fee to zero to make the pool
* fee settable by the accessor.
* @param feeAIn Fraction of the pool swap amount for tokenA-input swaps
* that is retained as an LP in D18 scale.
* @param feeBIn Fraction of the pool swap amount for tokenB-input swaps
* that is retained as an LP in D18 scale.
* @param tickSpacing Tick spacing of pool where 1.0001^tickSpacing is the
* bin width.
* @param lookback Pool lookback in seconds.
* @param tokenA Address of tokenA.
* @param tokenB Address of tokenB.
* @param activeTick Tick position that contains the active bins.
* @param kinds 1-15 number to represent the active kinds
* 0b0001 = static;
* 0b0010 = right;
* 0b0100 = left;
* 0b1000 = both.
* E.g. a pool with all 4 modes will have kinds = b1111 = 15
* @param accessor only address that can access the pool's public permissioned write functions.
* @param permissionedLiquidity If true, then only accessor can call
* pool's liquidity management functions: `flashLoan`,
* `migrateBinsUpstack`, `addLiquidity`, `removeLiquidity`.
* @param permissionedSwap If true, then only accessor can call
* pool's swap function.
*/
function createPermissioned(
uint64 feeAIn,
uint64 feeBIn,
uint16 tickSpacing,
uint32 lookback,
IERC20 tokenA,
IERC20 tokenB,
int32 activeTick,
uint8 kinds,
address accessor,
bool permissionedLiquidity,
bool permissionedSwap
) external returns (IMaverickV2Pool pool);
/**
* @notice Update the protocol fee ratio for a pool. Can be called
* permissionlessly allowing any user to sync the pool protocol fee value
* with the factory protocol fee value.
* @param pool The pool for which to update.
*/
function updateProtocolFeeRatioForPool(IMaverickV2Pool pool) external;
/**
* @notice Update the protocol lending fee rate for a pool. Can be called
* permissionlessly allowing any user to sync the pool protocol lending fee
* rate value with the factory value.
* @param pool The pool for which to update.
*/
function updateProtocolLendingFeeRateForPool(IMaverickV2Pool pool) external;
/**
* @notice Claim protocol fee for a pool and transfer it to the protocolFeeReceiver.
* @param pool The pool from which to claim the protocol fee.
* @param isTokenA A boolean indicating whether tokenA (true) or tokenB
* (false) is being collected.
*/
function claimProtocolFeeForPool(IMaverickV2Pool pool, bool isTokenA) external;
/**
* @notice Claim protocol fee for a pool and transfer it to the protocolFeeReceiver.
* @param pool The pool from which to claim the protocol fee.
*/
function claimProtocolFeeForPool(IMaverickV2Pool pool) external;
/**
* @notice Bool indicating whether the pool was deployed from this factory.
*/
function isFactoryPool(IMaverickV2Pool pool) external view returns (bool);
/**
* @notice Address that receives the protocol fee when users call
* `claimProtocolFeeForPool`.
*/
function protocolFeeReceiver() external view returns (address);
/**
* @notice Lookup a pool for given parameters.
*
* @dev options bit map of kinds and function permissions
* 0b000001 = static;
* 0b000010 = right;
* 0b000100 = left;
* 0b001000 = both;
* 0b010000 = liquidity functions are permissioned
* 0b100000 = swap function is permissioned
*/
function lookupPermissioned(
uint256 feeAIn,
uint256 feeBIn,
uint256 tickSpacing,
uint256 lookback,
IERC20 tokenA,
IERC20 tokenB,
uint8 options,
address accessor
) external view returns (IMaverickV2Pool);
/**
* @notice Lookup a pool for given parameters.
*/
function lookupPermissioned(
IERC20 _tokenA,
IERC20 _tokenB,
address accessor,
uint256 startIndex,
uint256 endIndex
) external view returns (IMaverickV2Pool[] memory pools);
/**
* @notice Lookup a pool for given parameters.
*/
function lookupPermissioned(
uint256 startIndex,
uint256 endIndex
) external view returns (IMaverickV2Pool[] memory pools);
/**
* @notice Lookup a pool for given parameters.
*/
function lookup(
uint256 feeAIn,
uint256 feeBIn,
uint256 tickSpacing,
uint256 lookback,
IERC20 tokenA,
IERC20 tokenB,
uint8 kinds
) external view returns (IMaverickV2Pool);
/**
* @notice Lookup a pool for given parameters.
*/
function lookup(
IERC20 _tokenA,
IERC20 _tokenB,
uint256 startIndex,
uint256 endIndex
) external view returns (IMaverickV2Pool[] memory pools);
/**
* @notice Lookup a pool for given parameters.
*/
function lookup(uint256 startIndex, uint256 endIndex) external view returns (IMaverickV2Pool[] memory pools);
/**
* @notice Count of permissionless pools.
*/
function poolCount() external view returns (uint256 _poolCount);
/**
* @notice Count of permissioned pools.
*/
function poolPermissionedCount() external view returns (uint256 _poolCount);
/**
* @notice Count of pools for a given accessor and token pair. For
* permissionless pools, pass `accessor = address(0)`.
*/
function poolByTokenCount(
IERC20 _tokenA,
IERC20 _tokenB,
address accessor
) external view returns (uint256 _poolCount);
/**
* @notice Get the current factory owner.
*/
function owner() external view returns (address);
/**
* @notice Proportion of protocol fee to collect on each swap. Value is in
* 3-decimal format with a maximum value of 0.25e3.
*/
function protocolFeeRatioD3() external view returns (uint8);
/**
* @notice Fee rate charged by the protocol for flashloans. Value is in
* 18-decimal format with a maximum value of 0.02e18.
*/
function protocolLendingFeeRateD18() external view returns (uint256);
}
// SPDX-License-Identifier: GPL-2.0-or-later
// As the copyright holder of this work, Ubiquity Labs retains
// the right to distribute, use, and modify this code under any license of
// their choosing, in addition to the terms of the GPL-v2 or later.
pragma solidity ^0.8.25;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IMaverickV2Factory} from "./IMaverickV2Factory.sol";
interface IMaverickV2Pool {
error PoolZeroLiquidityAdded();
error PoolMinimumLiquidityNotMet();
error PoolLocked();
error PoolInvalidFee();
error PoolTicksNotSorted(uint256 index, int256 previousTick, int256 tick);
error PoolTicksAmountsLengthMismatch(uint256 ticksLength, uint256 amountsLength);
error PoolBinIdsAmountsLengthMismatch(uint256 binIdsLength, uint256 amountsLength);
error PoolKindNotSupported(uint256 kinds, uint256 kind);
error PoolInsufficientBalance(uint256 deltaLpAmount, uint256 accountBalance);
error PoolReservesExceedMaximum(uint256 amount);
error PoolValueExceedsBits(uint256 amount, uint256 bits);
error PoolTickMaxExceeded(uint256 tick);
error PoolMigrateBinFirst();
error PoolCurrentTickBeyondSwapLimit(int32 startingTick);
error PoolSenderNotAccessor(address sender_, address accessor);
error PoolSenderNotFactory(address sender_, address accessor);
error PoolFunctionNotImplemented();
error PoolTokenNotSolvent(uint256 internalReserve, uint256 tokenBalance, IERC20 token);
event PoolSwap(address sender, address recipient, SwapParams params, uint256 amountIn, uint256 amountOut);
event PoolAddLiquidity(
address sender,
address recipient,
uint256 subaccount,
AddLiquidityParams params,
uint256 tokenAAmount,
uint256 tokenBAmount,
uint32[] binIds
);
event PoolMigrateBinsUpStack(address sender, uint32 binId, uint32 maxRecursion);
event PoolRemoveLiquidity(
address sender,
address recipient,
uint256 subaccount,
RemoveLiquidityParams params,
uint256 tokenAOut,
uint256 tokenBOut
);
event PoolSetVariableFee(uint256 newFeeAIn, uint256 newFeeBIn);
/**
* @notice Tick state parameters.
*/
struct TickState {
uint128 reserveA;
uint128 reserveB;
uint128 totalSupply;
uint32[4] binIdsByTick;
}
/**
* @notice Tick data parameters.
* @param currentReserveA Current reserve of token A.
* @param currentReserveB Current reserve of token B.
* @param currentLiquidity Current liquidity amount.
*/
struct TickData {
uint256 currentReserveA;
uint256 currentReserveB;
uint256 currentLiquidity;
}
/**
* @notice Bin state parameters.
* @param mergeBinBalance LP token balance that this bin possesses of the merge bin.
* @param mergeId Bin ID of the bin that this bin has merged into.
* @param totalSupply Total amount of LP tokens in this bin.
* @param kind One of the 4 kinds (0=static, 1=right, 2=left, 3=both).
* @param tick The lower price tick of the bin in its current state.
* @param tickBalance Balance of the tick.
*/
struct BinState {
uint128 mergeBinBalance;
uint128 tickBalance;
uint128 totalSupply;
uint8 kind;
int32 tick;
uint32 mergeId;
}
/**
* @notice Parameters for swap.
* @param amount Amount of the token that is either the input if exactOutput is false
* or the output if exactOutput is true.
* @param tokenAIn Boolean indicating whether tokenA is the input.
* @param exactOutput Boolean indicating whether the amount specified is
* the exact output amount (true).
* @param tickLimit The furthest tick a swap will execute in. If no limit
* is desired, value should be set to type(int32).max for a tokenAIn swap
* and type(int32).min for a swap where tokenB is the input.
*/
struct SwapParams {
uint256 amount;
bool tokenAIn;
bool exactOutput;
int32 tickLimit;
}
/**
* @notice Parameters associated with adding liquidity.
* @param kind One of the 4 kinds (0=static, 1=right, 2=left, 3=both).
* @param ticks Array of ticks to add liquidity to.
* @param amounts Array of bin LP amounts to add.
*/
struct AddLiquidityParams {
uint8 kind;
int32[] ticks;
uint128[] amounts;
}
/**
* @notice Parameters for each bin that will have liquidity removed.
* @param binIds Index array of the bins losing liquidity.
* @param amounts Array of bin LP amounts to remove.
*/
struct RemoveLiquidityParams {
uint32[] binIds;
uint128[] amounts;
}
/**
* @notice State of the pool.
* @param reserveA Pool tokenA balanceOf at end of last operation
* @param reserveB Pool tokenB balanceOf at end of last operation
* @param lastTwaD8 Value of log time weighted average price at last block.
* Value is 8-decimal scale and is in the fractional tick domain. E.g. a
* value of 12.3e8 indicates the TWAP was 3/10ths of the way into the 12th
* tick.
* @param lastLogPriceD8 Value of log price at last block. Value is
* 8-decimal scale and is in the fractional tick domain. E.g. a value of
* 12.3e8 indicates the price was 3/10ths of the way into the 12th tick.
* @param lastTimestamp Last block.timestamp value in seconds for latest
* swap transaction.
* @param activeTick Current tick position that contains the active bins.
* @param isLocked Pool isLocked, E.g., locked or unlocked; isLocked values
* defined in Pool.sol.
* @param binCounter Index of the last bin created.
* @param protocolFeeRatioD3 Ratio of the swap fee that is kept for the
* protocol.
*/
struct State {
uint128 reserveA;
uint128 reserveB;
int64 lastTwaD8;
int64 lastLogPriceD8;
uint40 lastTimestamp;
int32 activeTick;
bool isLocked;
uint32 binCounter;
uint8 protocolFeeRatioD3;
}
/**
* @notice Internal data used for data passing between Pool and Bin code.
*/
struct BinDelta {
uint128 deltaA;
uint128 deltaB;
}
/**
* @notice 1-15 number to represent the active kinds.
* @notice 0b0001 = static;
* @notice 0b0010 = right;
* @notice 0b0100 = left;
* @notice 0b1000 = both;
*
* E.g. a pool with all 4 modes will have kinds = b1111 = 15
*/
function kinds() external view returns (uint8 _kinds);
/**
* @notice Returns whether a pool has permissioned functions. If true, the
* `accessor()` of the pool can set the pool fees. Other functions in the
* pool may also be permissioned; whether or not they are can be determined
* through calls to `permissionedLiquidity()` and `permissionedSwap()`.
*/
function permissionedPool() external view returns (bool _permissionedPool);
/**
* @notice Returns whether a pool has permissioned liquidity management
* functions. If true, the pool is incompatible with permissioned pool
* liquidity management infrastructure.
*/
function permissionedLiquidity() external view returns (bool _permissionedLiquidity);
/**
* @notice Returns whether a pool has a permissioned swap functions. If
* true, the pool is incompatible with permissioned pool swap router
* infrastructure.
*/
function permissionedSwap() external view returns (bool _permissionedSwap);
/**
* @notice Pool swap fee for the given direction (A-in or B-in swap) in
* 18-decimal format. E.g. 0.01e18 is a 1% swap fee.
*/
function fee(bool tokenAIn) external view returns (uint256);
/**
* @notice TickSpacing of pool where 1.0001^tickSpacing is the bin width.
*/
function tickSpacing() external view returns (uint256);
/**
* @notice Lookback period of pool in seconds.
*/
function lookback() external view returns (uint256);
/**
* @notice Address of Pool accessor. This is Zero address for
* permissionless pools.
*/
function accessor() external view returns (address);
/**
* @notice Pool tokenA. Address of tokenA is such that tokenA < tokenB.
*/
function tokenA() external view returns (IERC20);
/**
* @notice Pool tokenB.
*/
function tokenB() external view returns (IERC20);
/**
* @notice Deploying factory of the pool and also contract that has ability
* to set and collect protocol fees for the pool.
*/
function factory() external view returns (IMaverickV2Factory);
/**
* @notice Most significant bit of scale value is a flag to indicate whether
* tokenA has more or less than 18 decimals. Scale is used in conjuction
* with Math.toScale/Math.fromScale functions to convert from token amounts
* to D18 scale internal pool accounting.
*/
function tokenAScale() external view returns (uint256);
/**
* @notice Most significant bit of scale value is a flag to indicate whether
* tokenA has more or less than 18 decimals. Scale is used in conjuction
* with Math.toScale/Math.fromScale functions to convert from token amounts
* to D18 scale internal pool accounting.
*/
function tokenBScale() external view returns (uint256);
/**
* @notice ID of bin at input tick position and kind.
*/
function binIdByTickKind(int32 tick, uint256 kind) external view returns (uint32);
/**
* @notice Accumulated tokenA protocol fee.
*/
function protocolFeeA() external view returns (uint128);
/**
* @notice Accumulated tokenB protocol fee.
*/
function protocolFeeB() external view returns (uint128);
/**
* @notice Lending fee rate on flash loans.
*/
function lendingFeeRateD18() external view returns (uint256);
/**
* @notice External function to get the current time-weighted average price.
*/
function getCurrentTwa() external view returns (int256);
/**
* @notice External function to get the state of the pool.
*/
function getState() external view returns (State memory);
/**
* @notice Return state of Bin at input binId.
*/
function getBin(uint32 binId) external view returns (BinState memory bin);
/**
* @notice Return state of Tick at input tick position.
*/
function getTick(int32 tick) external view returns (TickState memory tickState);
/**
* @notice Retrieves the balance of a user within a bin.
* @param user The user's address.
* @param subaccount The subaccount for the user.
* @param binId The ID of the bin.
*/
function balanceOf(address user, uint256 subaccount, uint32 binId) external view returns (uint128 lpToken);
/**
* @notice Add liquidity to a pool. This function allows users to deposit
* tokens into a liquidity pool.
* @dev This function will call `maverickV2AddLiquidityCallback` on the
* calling contract to collect the tokenA/tokenB payment.
* @param recipient The account that will receive credit for the added liquidity.
* @param subaccount The account that will receive credit for the added liquidity.
* @param params Parameters containing the details for adding liquidity,
* such as token types and amounts.
* @param data Bytes information that gets passed to the callback.
* @return tokenAAmount The amount of token A added to the pool.
* @return tokenBAmount The amount of token B added to the pool.
* @return binIds An array of bin IDs where the liquidity is stored.
*/
function addLiquidity(
address recipient,
uint256 subaccount,
AddLiquidityParams calldata params,
bytes calldata data
) external returns (uint256 tokenAAmount, uint256 tokenBAmount, uint32[] memory binIds);
/**
* @notice Removes liquidity from the pool.
* @dev Liquidy can only be removed from a bin that is either unmerged or
* has a mergeId of an unmerged bin. If a bin is merged more than one
* level deep, it must be migrated up the merge stack to the root bin
* before liquidity removal.
* @param recipient The address to receive the tokens.
* @param subaccount The subaccount for the recipient.
* @param params The parameters for removing liquidity.
* @return tokenAOut The amount of token A received.
* @return tokenBOut The amount of token B received.
*/
function removeLiquidity(
address recipient,
uint256 subaccount,
RemoveLiquidityParams calldata params
) external returns (uint256 tokenAOut, uint256 tokenBOut);
/**
* @notice Migrate bins up the linked list of merged bins so that its
* mergeId is the currrent active bin.
* @dev Liquidy can only be removed from a bin that is either unmerged or
* has a mergeId of an unmerged bin. If a bin is merged more than one
* level deep, it must be migrated up the merge stack to the root bin
* before liquidity removal.
* @param binId The ID of the bin to migrate.
* @param maxRecursion The maximum recursion depth for the migration.
*/
function migrateBinUpStack(uint32 binId, uint32 maxRecursion) external;
/**
* @notice Swap tokenA/tokenB assets in the pool. The swap user has two
* options for funding their swap.
* - The user can push the input token amount to the pool before calling
* the swap function. In order to avoid having the pool call the callback,
* the user should pass a zero-length `data` bytes object with the swap
* call.
* - The user can send the input token amount to the pool when the pool
* calls the `maverickV2SwapCallback` function on the calling contract.
* That callback has input parameters that specify the token address of the
* input token, the input and output amounts, and the bytes data sent to
* the swap function.
* @dev If the users elects to do a callback-based swap, the output
* assets will be sent before the callback is called, allowing the user to
* execute flash swaps. However, the pool does have reentrancy protection,
* so a swapper will not be able to interact with the same pool again
* while they are in the callback function.
* @param recipient The address to receive the output tokens.
* @param params Parameters containing the details of the swap
* @param data Bytes information that gets passed to the callback.
*/
function swap(
address recipient,
SwapParams memory params,
bytes calldata data
) external returns (uint256 amountIn, uint256 amountOut);
/**
* @notice Loan tokenA/tokenB assets from the pool to recipient. The fee
* rate of a loan is determined by `lendingFeeRateD18`, which is set at the
* protocol level by the factory. This function calls
* `maverickV2FlashLoanCallback` on the calling contract. At the end of
* the callback, the caller must pay back the loan with fee (if there is a
* fee).
* @param recipient The address to receive the loaned tokens.
* @param amountB Loan amount of tokenA sent to recipient.
* @param amountB Loan amount of tokenB sent to recipient.
* @param data Bytes information that gets passed to the callback.
*/
function flashLoan(
address recipient,
uint256 amountA,
uint256 amountB,
bytes calldata data
) external returns (uint128 lendingFeeA, uint128 lendingFeeB);
/**
* @notice Sets fee for permissioned pools. May only be called by the
* accessor.
*/
function setFee(uint256 newFeeAIn, uint256 newFeeBIn) external;
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;
import {IMaverickV2Pool} from "../../v2-common/interfaces/IMaverickV2Pool.sol";
interface IMaverickV2Quoter {
error QuoterInvalidSwap();
error QuoterInvalidAddLiquidity();
/**
* @notice Calculates a swap on a MaverickV2Pool and returns the resulting
* amount and estimated gas. The gas estimate is only a rough estimate and
* may not match a swap's gas.
* @param pool The MaverickV2Pool to swap on.
* @param amount The input amount.
* @param tokenAIn Indicates if token A is the input token.
* @param exactOutput Indicates if the amount is the output amount (true)
* or input amount (false). If the tickLimit is reached, the full value of
* the exactOutput may not be returned because the pool will stop swapping
* before the whole order is filled.
* @param tickLimit The tick limit for the swap. Once the swap lands in
* this tick, it will stop and return the output amount swapped up to that
* tick.
*/
function calculateSwap(
IMaverickV2Pool pool,
uint128 amount,
bool tokenAIn,
bool exactOutput,
int32 tickLimit
) external returns (uint256 amountIn, uint256 amountOut, uint256 gasEstimate);
/**
* @notice Calculates a multihop swap and returns the resulting amount and
* estimated gas. The gas estimate is only a rough estimate and
* may not match a swap's gas.
* @param path The path of pools to swap through. Path is given by an
* packed array of (pool, tokenAIn) tuples. So each step in the path is 160
* + 8 = 168 bits of data. e.g. path = abi.encodePacked(pool1, true, pool2, false);
* @param amount The input amount.
* @param exactOutput A boolean indicating if exact output is required.
*/
function calculateMultiHopSwap(
bytes memory path,
uint256 amount,
bool exactOutput
) external returns (uint256 returnAmount, uint256 gasEstimate);
/**
* @notice Computes the token amounts required for a given set of
* addLiquidity parameters. The gas estimate is only a rough estimate and
* may not match a add's gas.
*/
function calculateAddLiquidity(
IMaverickV2Pool pool,
IMaverickV2Pool.AddLiquidityParams calldata params
) external returns (uint256 amountA, uint256 amountB, uint256 gasEstimate);
/**
* @notice Pool's sqrt price.
*/
function poolSqrtPrice(IMaverickV2Pool pool) external view returns (uint256 sqrtPrice);
}
// SPDX-License-Identifier: GPL-2.0-or-later
// As the copyright holder of this work, Ubiquity Labs retains
// the right to distribute, use, and modify this code under any license of
// their choosing, in addition to the terms of the GPL-v2 or later.
pragma solidity ^0.8.25;
interface IMulticall {
function multicall(bytes[] calldata data) external returns (bytes[] memory results);
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IHistoricalBalanceNonTransferableERC20} from "./IHistoricalBalanceNonTransferableERC20.sol";
import {ISwapper} from "./ISwapper.sol";
interface IRaffleVault {
error NoLootBoxesToOpen();
error RaffleBuyTooLittleReceived(uint256 amountOutMinimum, uint256 amountOut);
error EpochHasNotEnded(uint256 currentTimestamp, uint256 endEpochTimestamp);
error InvalidEndEpochTimestamp(uint256 inputTimstamp);
error OutputTokenDoesNotMatch(IERC20 outputToken, IERC20 expectedOutputToken);
error InsufficientEthForFee(uint256 amountAvailable, uint256 amountRequired);
struct LootBoxData {
address user;
uint8 count;
uint64 sequenceNumber;
uint256 endEpochTimestamp;
}
struct LootBoxUserData {
uint32 countOfLootBoxesOpened;
uint32 countOfEpochsWithLootBoxOpened;
uint32 minRandomNumber;
uint160 totalQuoteTokenPrizes;
}
event OpenLootBoxes(IERC20 indexed quoteToken, LootBoxData lootBoxData);
event SpendPrizeEscrow(address user, uint256 amountIn, uint256 amountOut, IERC20 inputToken, IERC20 outputToken);
event RevealLoot(
IERC20 indexed quoteToken,
uint256 nextMultiplier,
uint256 prizeAmount,
uint256 randomNumber,
uint256 boxNumber,
LootBoxData lootBoxData
);
/**
* @notice Returns buy fee tracker token
*/
function buyTracker() external view returns (IHistoricalBalanceNonTransferableERC20);
/**
* @notice Returns Swapper contract that created this vault
*/
function swapper() external view returns (ISwapper);
/**
* @notice Returns quote token that this vault holds
*/
function quoteToken() external view returns (IERC20);
/**
* @notice Returns total amount of quote token escrowed by users who have
* claimed their loot boxes. This escrow is spent when the users call
* `spendPrizeEscrow`
*/
function totalEscrow() external view returns (uint256);
/**
* @notice Returns epoch-end timestamp of the epoch that that `timestamp` is in
* offset by `epochOffset`. For instance, to find yesterepoch's
* `epochEndTimestamp`, set timestamp to any timestamp toepoch ,like
* `block.timestamp`, and set `epochOffset` to `-1`.
*/
function endEpochTimestampAtOffset(
uint256 timestamp,
int256 epochOffset
) external view returns (uint256 endEpochTimestamp);
/**
* @notice Returns epoch-end timestamp of toepoch. This `endEpochTimestamp` will
* not yet be claimable.
*/
function currentEndEpochTimestamp() external view returns (uint256 endEpochTimestamp);
/**
* @notice Returns lootbox user data
*/
function lootBoxUserData(
address user
)
external
returns (
uint32 countOfLootBoxesOpened,
uint32 countOfEpochsWithLootBoxOpened,
uint32 minRandomNumber,
uint160 totalQuoteTokenPrizes
);
/**
* @notice Returns multiplier that will applied to the next loot box open
* for this user (0 is equivilent to a "multiplier" of 1)
*/
function multiplierByUser(address user) external view returns (uint256);
/**
* @notice Returns an indicator of whether this user has already collected
* for a given epoch
*/
function hasCollectedByUserEpoch(address user, uint256 datTs) external view returns (bool);
/**
* @notice Returns escrowed prize for a user; users can spend this escrow
* to collect their prize with `spendPrizeEscrow`
*/
function escrowByUser(address user) external view returns (uint256);
/**
* @notice Returns number of loot boxes the user can claim for that epoch
*/
function newLootBoxCount(
address user,
uint256 endEpochTimestamp
) external view returns (uint256 numberOfNewLootBoxes);
/**
* @notice Returns fractional number of loot boxes for a given epoch.
*/
function lootBoxRawData(
address user,
uint256 endEpochTimestamp
) external view returns (uint256 numberOfNewLootBoxes, uint256 epochBalanceChange, uint256 balancePerLootBox);
/**
* @notice Claims and "Opens" loot boxes for user to realize the random prize result;
* the result with either by a probability multiplier for the next loot box
* the user opens or it will be a portion of the vault's quote token assets
* which will be escrowed until the user calls `spendPrizeEscrow`.
*
* @notice Caller needs to get the eth call fee from `getOpenLootBoxFee`
* and send that much value.
*/
function openLootBoxes(uint256 endEpochTimestamp) external payable returns (uint256 numberOfNewLootBoxes);
/**
* @notice Amount of gas token value that must be sent when calling
* `openLootBoxes`.
*/
function getOpenLootBoxFee() external view returns (uint256 fee);
/**
* @notice Buys the Swapper-specified token with the user's prize escrow.
* Caller passes in the expected token they will receive which is
* `swapper.getTopToken(quoteToken)`, but the top token may change as the
* call is being submitted. In the case that the expected token does not
* match the output token, this call will revert.
*/
function spendPrizeEscrow(
IERC20 expectedOutputToken,
uint256 amountOutMinimum
) external returns (IERC20 outputToken, uint256 amountOut);
/**
* @notice Estimates the amount of token a user will get if they spend
* their escrow
*/
function estimatePrize(address user) external returns (IERC20 outputToken, uint256 amountOut);
/**
* @notice Interval in seconds between raffles (1 epoch)
*/
// solhint-disable-next-line func-name-mixedcase
function RAFFLE_INTERVAL() external view returns (uint256);
/**
* @notice Move tokens from fee vault to raffle contract.
*/
function pullTokensFromFeeVault() external returns (uint256 amount);
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;
import {ISwapper} from "./ISwapper.sol";
interface IReferralRegistry {
event Refer(address referee, address referer, uint256 timestamp);
error SenderAlreadyRefered();
error OnlySwapperOwner();
/**
* @notice Registers caller to the given referer
*/
function refer(address referer) external;
/**
* @notice Registers specific refer pair. Only callable by swapper owner.
*/
function setReferer(address user, address referer) external;
/**
* @notice User lookup
*/
function userToRefererData(address user) external view returns (address referer, uint96 timestamp);
/**
* @notice Paginated lookup of referees
*/
function referees(uint256 startIndex, uint256 endIndex, address referer) external view returns (address[] memory);
/**
* @notice Swapper
*/
function swapper() external view returns (ISwapper);
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IEntropy} from "@pythnetwork/entropy-sdk-solidity/IEntropy.sol";
import {IMaverickV2Pool} from "../v2-common/interfaces/IMaverickV2Pool.sol";
import {IMaverickV2Factory} from "../v2-common/interfaces/IMaverickV2Factory.sol";
import {IWETH9} from "./external/IWETH9.sol";
import {IMaverickV2Quoter} from "./external/IMaverickV2Quoter.sol";
import {IHistoricalBalanceNonTransferableERC20} from "./IHistoricalBalanceNonTransferableERC20.sol";
import {IRaffleVault} from "./IRaffleVault.sol";
import {ILaunchFactory} from "./ILaunchFactory.sol";
import {IFeeVault} from "./IFeeVault.sol";
import {IVotingDistributor} from "./IVotingDistributor.sol";
import {IReferralRegistry} from "./IReferralRegistry.sol";
interface ISwapper {
error SenderNotWETH();
error InvalidFeeParameter();
error TooLittleReceived(uint256 amountOutMinimumExcludingFee, uint256 amountOut);
error TokenNotFromLaunchFactory();
error IncorrectEthValueSent(uint256 amountQuoteIn, uint256 valueSent);
error QuoteTokenIsNotEth(IERC20 quoteToken);
error NoTracker();
error QuoteTokenAlreadyRegistered(IERC20 quoteToken);
error ValueSentForNonEthQuoteToken(IERC20 quoteToken, uint256 valueSent);
error NotFactoryPool(IMaverickV2Pool ethToQuotePool);
struct Trackers {
IHistoricalBalanceNonTransferableERC20 sell;
IHistoricalBalanceNonTransferableERC20 buy;
IHistoricalBalanceNonTransferableERC20 token;
IHistoricalBalanceNonTransferableERC20 creator;
IHistoricalBalanceNonTransferableERC20 referer;
}
struct FeeRates {
uint64 proportionToRaffleVaultD18;
uint64 proportionToRefererD18;
uint64 proportionToVotingDistributorD18;
uint64 proportionToCreatorD18;
uint64 proportionToVoterD18;
}
struct Amounts {
uint256 amountToProtocol;
uint256 amountToCreator;
uint256 amountToReferer;
uint256 amountToRaffleVault;
uint256 amountToSwapper;
uint256 amountToVoteDistribution;
uint256 amountToVoters;
}
struct Recipients {
address protocol;
address creator;
address referer;
address raffleVault;
address votingDistributor;
address swapper;
}
event SetFeeVault(IFeeVault feeVault);
event NewTrackers(
IERC20 quoteToken,
ILaunchFactory factory,
IHistoricalBalanceNonTransferableERC20 sellTracker,
IHistoricalBalanceNonTransferableERC20 buyTracker,
IHistoricalBalanceNonTransferableERC20 tokenTracker,
IHistoricalBalanceNonTransferableERC20 creatorTracker,
IHistoricalBalanceNonTransferableERC20 refererTracker
);
event SetFeeRates(FeeRates feeRates);
event SetFeeRate(uint64 feeRateD18);
event SetProtocolRecipient(address protocolRecipient);
event SetReferralRegistry(IReferralRegistry registry);
event SetEntropy(IEntropy entropy);
event FeeEmission(IERC20 indexed token, Recipients recipients, Amounts amounts, uint256 rawAmount, bool isBuy);
event NewRaffleVault(IERC20 quoteToken, IRaffleVault raffleVault);
event SetBalancePerLootBox(IERC20 quoteToken, uint256 balanceRequirement);
event SetPrizesAndThresholds(uint24[8] thresholds, uint64[8] prizes, uint8 boxBonus);
event SetVotingDistributor(IERC20 quoteToken, IVotingDistributor votingDistributor);
event BuyToken(
address recipient,
IERC20 token,
uint256 amountQuoteIn,
uint256 amountOutMinimum,
address referer,
address raffleRecipient,
uint256 amountOut,
IMaverickV2Pool pool,
uint256 poolSqrtPrice
);
event SellToken(
address recipient,
IERC20 token,
uint256 amountTokenIn,
uint256 amountOutMinimum,
address referer,
address raffleRecipient,
uint256 amountOut,
IMaverickV2Pool pool,
uint256 poolSqrtPrice
);
/**
* @notice Buys tokens using quote token.
* @param recipient The address to receive the purchased tokens
* @param token The ERC20 token to buy
* @param amountQuoteIn The amount of quote to spend
* @param amountOutMinimum The minimum amount of tokens to receive
* @param referer The address of the referrer (adddress(0) should be used if there is no referer)
* @param raffleRecipient The address that gets credit for the buy volume in the tracker token
* @return amountOut The actual amount of tokens received
* @return pool The Maverick V2 pool used for the swap
*/
function buyTokenSpecifyRaffleRecipient(
address recipient,
IERC20 token,
uint256 amountQuoteIn,
uint256 amountOutMinimum,
address referer,
address raffleRecipient
) external payable returns (uint256 amountOut, IMaverickV2Pool pool);
/**
* @notice Buys tokens using eth where the quote token is not ETH. The
* token is bought through a two-pool swap: ethToQuote -> quoteToToken.
* @param recipient The address to receive the purchased tokens
* @param token The ERC20 token to buy
* @param ethToQuotePool The Maverick pool that can swap eth for quote token
* @param amountEthIn The amount of ETH to spend
* @param amountOutMinimum The minimum amount of tokens to receive
* @param referer The address of the referrer (adddress(0) should be used if there is no referer)
* @param raffleRecipient The address that gets credit for the buy volume in the tracker token
* @return amountOut The actual amount of tokens received
* @return pool The Maverick V2 pool used for the swap
*/
function buyTokenTwoHopSpecifyRaffleRecipient(
address recipient,
IERC20 token,
IMaverickV2Pool ethToQuotePool,
uint256 amountEthIn,
uint256 amountOutMinimum,
address referer,
address raffleRecipient
) external payable returns (uint256 amountOut, IMaverickV2Pool pool);
/**
* @notice Sells tokens for quote token.
* @param recipient The address to receive the quote
* @param token The ERC20 token to sell
* @param amountTokenIn The amount of tokens to sell
* @param amountOutMinimum The minimum amount of ETH to receive
* @param referer The address of the referrer (adddress(0) should be used if there is no referer)
* @param raffleRecipient The address that gets credit for the buy volume in the tracker token
* @return amountOut The actual amount of quote token received
* @return pool The Maverick V2 pool used for the swap
*/
function sellTokenSpecifyRaffleRecipient(
address recipient,
IERC20 token,
uint256 amountTokenIn,
uint256 amountOutMinimum,
address referer,
address raffleRecipient
) external returns (uint256 amountOut, IMaverickV2Pool pool);
/**
* @notice Sells tokens for quote token and then swaps the quote token for eth.
* @param recipient The address to receive the quote
* @param token The ERC20 token to sell
* @param ethToQuotePool The Maverick pool that can swap quote token for eth
* @param amountTokenIn The amount of tokens to sell
* @param amountOutMinimum The minimum amount of ETH to receive
* @param referer The address of the referrer (adddress(0) should be used if there is no referer)
* @param raffleRecipient The address that gets credit for the buy volume in the tracker token
* @return amountOut The actual amount of ETH received
* @return pool The Maverick V2 pool used for the swap
*/
function sellTokenTwoHopSpecifyRaffleRecipient(
address recipient,
IERC20 token,
IMaverickV2Pool ethToQuotePool,
uint256 amountTokenIn,
uint256 amountOutMinimum,
address referer,
address raffleRecipient
) external returns (uint256 amountOut, IMaverickV2Pool pool);
/**
* @notice Buys tokens using quote token. Credits msg.sender with the buy volume on the tracker token.
* @param recipient The address to receive the purchased tokens
* @param token The ERC20 token to buy
* @param amountQuoteIn The amount of quote to spend
* @param amountOutMinimum The minimum amount of tokens to receive
* @param referer The address of the referrer (adddress(0) should be used if there is no referer)
* @return amountOut The actual amount of tokens received
* @return pool The Maverick V2 pool used for the swap
*/
function buyToken(
address recipient,
IERC20 token,
uint256 amountQuoteIn,
uint256 amountOutMinimum,
address referer
) external payable returns (uint256 amountOut, IMaverickV2Pool pool);
/**
* @notice Buys tokens using eth where the quote token is not eth. The
* token is bought through a two-pool swap: ethToQuote -> quoteToToken.
* Credits msg.sender with the buy volume on the tracker token.
* @param recipient The address to receive the purchased tokens
* @param token The ERC20 token to buy
* @param ethToQuotePool The Maverick pool that can swap eth for quote token
* @param amountEthIn The amount of ETH to spend
* @param amountOutMinimum The minimum amount of tokens to receive
* @param referer The address of the referrer (adddress(0) should be used if there is no referer)
* @return amountOut The actual amount of tokens received
* @return pool The Maverick V2 pool used for the swap
*/
function buyTokenTwoHop(
address recipient,
IERC20 token,
IMaverickV2Pool ethToQuotePool,
uint256 amountEthIn,
uint256 amountOutMinimum,
address referer
) external payable returns (uint256 amountOut, IMaverickV2Pool pool);
/**
* @notice Sells tokens for quote token. Credits msg.sender with the sell volume on the tracker token.
* @param recipient The address to receive the ETH
* @param token The ERC20 token to sell
* @param amountTokenIn The amount of tokens to sell
* @param amountOutMinimum The minimum amount of ETH to receive
* @param referer The address of the referrer (adddress(0) should be used if there is no referer)
* @return amountOut The actual amount of ETH received
* @return pool The Maverick V2 pool used for the swap
*/
function sellToken(
address recipient,
IERC20 token,
uint256 amountTokenIn,
uint256 amountOutMinimum,
address referer
) external returns (uint256 amountOut, IMaverickV2Pool pool);
/**
* @notice Sells tokens for quote token and then swaps the quote token for eth.
* @param recipient The address to receive the quote
* @param token The ERC20 token to sell
* @param ethToQuotePool The Maverick pool that can swap quote token for eth
* @param amountTokenIn The amount of tokens to sell
* @param amountOutMinimum The minimum amount of ETH to receive
* @param referer The address of the referrer (adddress(0) should be used if there is no referer)
* @return amountOut The actual amount of ETH received
* @return pool The Maverick V2 pool used for the swap
*/
function sellTokenTwoHop(
address recipient,
IERC20 token,
IMaverickV2Pool ethToQuotePool,
uint256 amountTokenIn,
uint256 amountOutMinimum,
address referer
) external returns (uint256 amountOut, IMaverickV2Pool pool);
/**
* @notice Gets an output estimate for buying tokens with quote token
* @param token The ERC20 token to buy
* @param amountQuoteIn The amount of quote to spend
* @return amountOut The estimated amount of tokens that would be received inclusive of all fees
*/
function buyTokenQuote(IERC20 token, uint256 amountQuoteIn) external returns (uint256 amountOut);
/**
* @notice Gets an output estimate for buying tokens with ETH via an intermediate eth-to-quote pool
* @param token The ERC20 token to buy
* @param ethToQuotePool The Maverick pool that can swap eth for quote token
* @param amountEthIn The amount of ETH to spend
* @return amountOut The estimated amount of tokens that would be received inclusive of all fees
*/
function buyTokenTwoHopQuote(
IERC20 token,
IMaverickV2Pool ethToQuotePool,
uint256 amountEthIn
) external returns (uint256 amountOut);
/**
* @notice Gets a quote for selling tokens for ETH
* @param token The ERC20 token to sell
* @param amountTokenIn The amount of tokens to sell
* @return amountOut The estimated amount of ETH that would be received inclusive of all fees
*/
function sellTokenQuote(IERC20 token, uint256 amountTokenIn) external returns (uint256 amountOut);
/**
* @notice Gets a quote for selling tokens for ETH
* @param token The ERC20 token to sell
* @param ethToQuotePool The Maverick pool that can swap quote for eth
* @param amountTokenIn The amount of tokens to sell
* @return amountOut The estimated amount of ETH that would be received inclusive of all fees
*/
function sellTokenTwoHopQuote(
IERC20 token,
IMaverickV2Pool ethToQuotePool,
uint256 amountTokenIn
) external returns (uint256 amountOut);
/**
* @notice Gets the entropy contract address
*/
function entropy() external view returns (IEntropy);
/**
* @notice Gets prize, threshold values and box bonus
*/
function getPrizesAndThresholdsAndBonus()
external
view
returns (uint24[8] memory thresholds, uint64[8] memory prizes, uint8 boxBonus);
/**
* @notice Gets top meme token for given quote token
*/
function getTopToken(IERC20 quoteToken) external view returns (IERC20 topToken);
/**
* @notice Gets the WETH contract address
*/
function weth() external view returns (IWETH9);
/**
* @notice Gets the feeRecipient address
*/
function protocolRecipient() external view returns (address);
/**
* @notice Gets the fee rate in D18 format
*/
function feeRateD18() external view returns (uint64);
/**
* @notice Gets the fee rate in D18 format
*/
function feeRates()
external
view
returns (
uint64 proportionToRaffleVaultD18,
uint64 proportionToRefererD18,
uint64 proportionToVotingDistributorD18,
uint64 proportionToCreatorD18,
uint64 proportionToVoterD18
);
/**
* @notice Gets the Maverick V2 price quoter
*/
function quoter() external view returns (IMaverickV2Quoter);
function feeVault() external view returns (IFeeVault);
function referralRegistry() external view returns (IReferralRegistry);
function poolFactory() external view returns (IMaverickV2Factory);
function quoteToRaffleVault(IERC20) external view returns (IRaffleVault);
function quoteToVotingDistributor(IERC20) external view returns (IVotingDistributor);
function quoteToFactory(IERC20) external view returns (ILaunchFactory);
function quoteToTrackers(
IERC20
)
external
view
returns (
IHistoricalBalanceNonTransferableERC20 sell,
IHistoricalBalanceNonTransferableERC20 buy,
IHistoricalBalanceNonTransferableERC20 token,
IHistoricalBalanceNonTransferableERC20 creator,
IHistoricalBalanceNonTransferableERC20 referer
);
/**
* @notice Gets fee balance requirement needed to claim a lootbox
*/
function balancePerLootBox(IERC20 quoteToken) external view returns (uint256);
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IMaverickV2Pool} from "../v2-common/interfaces/IMaverickV2Pool.sol";
import {ILaunchFactory} from "./ILaunchFactory.sol";
interface ITokenManager {
error NotFactoryPool();
error OnlyCurrentRecipientAllowed(address existingRecipient, address newRecipient);
error BorrowingNotEnabled();
error NoLiquidityToBorrow();
error NothingToRedeem();
error TooMuchQuoteInRedeem(uint256 amountRequested, uint256 maxAmount);
error NotInClosePeriod(uint256 lastPoolSwap, uint256 closePeriodThreshold);
error AddressZeroNotValidFeeRecipient();
error MinTimeNotElaspedSinceLastFeeChange(uint256 timeDifference, uint256 minTimeDifference);
error FeeChangeNotEnabled();
error SenderNotWETH();
error MinRedeemNotMet(uint256 totalTokenRedeemed, uint256 minRedeemTokenAmount);
error MinBorrowNotMet(uint256 amountToBorrow, uint256 minAmountToBorrower);
error InsufficientEthSentByUser(uint256 amountToPay, uint256 amountRecived);
event ExtractFee(
int32[] ticks,
IMaverickV2Pool.RemoveLiquidityParams params,
uint256 amountToProtocol,
uint256 amountToRecipient,
address recipient
);
event ChangeFeeRecipient(address existingRecipient, address newRecipient);
event ClosePool(IMaverickV2Pool.RemoveLiquidityParams params, uint256 quoteAmount, uint256 tokenAmount);
event BorrowQuote(
address borrower,
uint128 inputTokenBorrowAmount,
uint128 inputMinSent,
int32[] ticks,
uint128[] tokenAmounts,
uint128[] quoteToRepayAmounts,
uint128 tokenCollateralAmount,
uint128 quoteToRepayAmount,
uint128 quoteToBorrowerAmount,
uint128 ethToBorrowerAmount
);
event RedeemTokenCollateral(
address borrower,
uint128 inputRedeemTokenAmount,
int32[] ticks,
uint128[] tokenAmounts,
uint128[] quoteToRepayAmounts,
uint128 totalQuoteSpent,
uint128 totalEthSpent,
uint128 totalTokenRedeemed
);
event ChangeFees(uint256 newBuyFee, uint256 newSellFee, uint256 timestamp);
event BorrowFeeEmission(IERC20 quoteToken, IERC20 token, Recipients recipients, Amounts amounts);
struct DebtData {
uint128 quoteAmount;
uint128 tokenAmount;
}
struct Recipients {
address protocol;
address creator;
address votingDistributor;
}
struct Amounts {
uint256 amountToCreator;
uint256 amountToProtocol;
uint256 amountToVoters;
uint256 amountToVoteDistribution;
}
/**
* @notice Gets the Maverick V2 fairlaunch pool
*/
function pool() external view returns (IMaverickV2Pool);
/**
* @notice Gets the index of the curve which corresponds to the liquidity
* distribution exponent. Valid values are 0 to 5.
*/
function curveIndex() external view returns (uint8);
/**
* @notice Gets the launch factory
*/
function launchFactory() external view returns (ILaunchFactory);
/**
* @notice Gets the ERC20 token that was launched
*/
function token() external view returns (IERC20);
/**
* @notice Checks if the token is tokenA in the pool
*/
function tokenIsA() external view returns (bool);
/**
* @notice Gets the address that receives fees
*/
function feeRecipient() external view returns (address);
/**
* @notice Checks if borrowing is enabled
*/
function borrowingEnabled() external view returns (bool);
/**
* @notice Returns pool swap fees.
*/
function fees() external view returns (uint64 _buyFee, uint64 _sellFee);
/**
* @notice Returns pool swap sell fee.
*/
function sellFee() external view returns (uint64);
/**
* @notice Returns pool swap sell fee.
*/
function buyFee() external view returns (uint64);
/**
* @notice Returns timestamp of last fee change.
*/
function lastFeeChangeTimestamp() external view returns (uint64);
/**
* @notice Borrows QUOTE from the pool. This function may create a loan for
* less token collateral than the user specifies if there is not enough quote
* in the pool to be borrowed. Users can specify the minimum amount of
* QUOTE they will accept in the loan.
* @param tokenBorrowAmount The desired amount of tokens to send as collateral
* @param minQuoteSent The minimum amount of QUOTE that can be sent to the user
* @return ticks The ticks involved in the borrowing operation
* @return tokenAmounts The token amounts at each tick
* @return quoteToRepayAmounts The QUOTE amounts to repay at each tick
* @return tokenCollateralAmount The amount of tokens used as collateral
* @return quoteToRepayAmount The total amount of QUOTE to repay
* @return quoteToBorrowerAmount The amount of QUOTE sent to the borrower
*/
function borrowQuote(
uint128 tokenBorrowAmount,
uint128 minQuoteSent
)
external
returns (
int32[] memory ticks,
uint128[] memory tokenAmounts,
uint128[] memory quoteToRepayAmounts,
uint128 tokenCollateralAmount,
uint128 quoteToRepayAmount,
uint128 quoteToBorrowerAmount
);
/**
* @notice Borrows QUOTE from the pool and swap to ETH. This function may
* create a loan for less token collateral than the user specifies if there
* is not enough quote in the pool to be borrowed. Users can specify the
* minimum amount of ETH they will accept in the loan.
* @param ethToQuotePool The maverick pool that has eth and quote.
* @param tokenBorrowAmount The desired amount of tokens to send as collateral
* @param minEthSent The minimum amount of ETH that can be sent to the user
* @return ticks The ticks involved in the borrowing operation
* @return tokenAmounts The token amounts at each tick
* @return quoteToRepayAmounts The QUOTE amounts to repay at each tick
* @return tokenCollateralAmount The amount of tokens used as collateral
* @return quoteToRepayAmount The total amount of QUOTE to repay
* @return quoteToBorrowerAmount The amount of QUOTE sent to the borrower
* @return ethToBorrowerAmount The amount of ETH sent to the borrower
*/
function borrowQuoteToEth(
IMaverickV2Pool ethToQuotePool,
uint128 tokenBorrowAmount,
uint128 minEthSent
)
external
returns (
int32[] memory ticks,
uint128[] memory tokenAmounts,
uint128[] memory quoteToRepayAmounts,
uint128 tokenCollateralAmount,
uint128 quoteToRepayAmount,
uint128 quoteToBorrowerAmount,
uint128 ethToBorrowerAmount
);
/**
* @notice Redeems token collateral; The caller needs to approve this
* TokenManager to `transferFrom` amount.
* @param maxRedeemTokenAmount The max amount of tokens to redeem
* @param minRedeemTokenAmount The min amount of tokens to redeem
* @param maxQuoteAmount The max amount of quote tokens to spend in redemption
* @return ticks The ticks involved in the redemption operation
* @return tokenAmounts The token amounts at each tick
* @return quoteToRepayAmounts The QUOTE amounts to repay at each tick
* @return totalQuoteSpent The total amount of QUOTE spent
* @return totalTokenRedeemed The total amount of tokens redeemed
*/
function redeemTokenCollateral(
uint128 maxRedeemTokenAmount,
uint128 minRedeemTokenAmount,
uint128 maxQuoteAmount
)
external
returns (
int32[] memory ticks,
uint128[] memory tokenAmounts,
uint128[] memory quoteToRepayAmounts,
uint128 totalQuoteSpent,
uint128 totalTokenRedeemed
);
/**
* @notice Redeems token collateral at specified ticks which have to be
* passed in sorted order. The caller needs to approve this TokenManager to
* `transferFrom` amount.
* @param ticks The ticks involved in the redemption operation
* @param tokenAmounts The token amounts at each tick
* @return quoteToRepayAmounts The QUOTE amounts to repay at each tick
* @return totalQuoteSpent The total amount of QUOTE spent
* @return totalTokenRedeemed The total amount of tokens redeemed
*/
function redeemTokenCollateralByTick(
int32[] memory ticks,
uint128[] memory tokenAmounts
) external returns (uint128[] memory quoteToRepayAmounts, uint128 totalQuoteSpent, uint128 totalTokenRedeemed);
/**
* @notice Redeems token collateral at specified ticks which have to be
* passed in sorted order. caller needs to send ETH with the call equal to
* the repay amount. Any excess ETH will be sent back to the caller. The
* ETH will be swapped in the input pool for quote token.
* @param ethToQuotePool The maverick pool that has eth and quote.
* @param ticks The ticks involved in the redemption operation
* @param tokenAmounts The token amounts at each tick
* @return quoteToRepayAmounts The QUOTE amounts to repay at each tick
* @return totalQuoteSpent The total amount of QUOTE spent
* @return totalEthSpent The total amount of QUOTE spent
* @return totalTokenRedeemed The total amount of tokens redeemed
*/
function redeemTokenCollateralWithEthByTick(
IMaverickV2Pool ethToQuotePool,
int32[] memory ticks,
uint128[] memory tokenAmounts
)
external
payable
returns (
uint128[] memory quoteToRepayAmounts,
uint128 totalQuoteSpent,
uint128 totalEthSpent,
uint128 totalTokenRedeemed
);
/**
* @notice Redeems token collateral; The caller needs to send ETH with the
* call equal to the repay amount. Any excess ETH will be sent back to the
* caller. The ETH will be swapped in the input pool for quote token.
* @param ethToQuotePool The maverick pool that has eth and quote.
* @param maxRedeemTokenAmount The max amount of tokens to redeem
* @param minRedeemTokenAmount The min amount of tokens to redeem
* @return ticks The ticks involved in the redemption operation
* @return tokenAmounts The token amounts at each tick
* @return quoteToRepayAmounts The QUOTE amounts to repay at each tick
* @return totalQuoteSpent The total amount of QUOTE spent
* @return totalEthSpent The total amount of QUOTE spent
* @return totalTokenRedeemed The total amount of tokens redeemed
*/
function redeemTokenCollateralWithEth(
IMaverickV2Pool ethToQuotePool,
uint128 maxRedeemTokenAmount,
uint128 minRedeemTokenAmount
)
external
payable
returns (
int32[] memory ticks,
uint128[] memory tokenAmounts,
uint128[] memory quoteToRepayAmounts,
uint128 totalQuoteSpent,
uint128 totalEthSpent,
uint128 totalTokenRedeemed
);
/**
* @notice Gets the borrowed amounts for a user at a specific tick
* @param user The user address
* @param tick The tick
* @return amounts The debt data (token collateral amount and QUOTE amount)
*/
function userBorrowedAmounts(address user, int32 tick) external view returns (DebtData memory amounts);
/**
* @notice Gets the total borrowed amounts across all users at a specific tick
* @param tick The tick
* @return amounts The debt data (token collateral amount and QUOTE amount)
*/
function borrowedAmounts(int32 tick) external view returns (DebtData memory amounts);
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;
import {IMaverickV2Pool} from "../v2-common/interfaces/IMaverickV2Pool.sol";
import {ITokenManager} from "./ITokenManager.sol";
import {IDistribution} from "./IDistribution.sol";
interface ITokenManagerLens {
error BorrowingNotSupported(int32 startTick, int32 endTick);
error RedeemNotSupported(int32 startTick, int32 endTick);
error NonQuoteBin(IMaverickV2Pool pool, uint32 binId);
error TickIsNotAllQuote(int32 tick, int32 activeTick);
error TryingToRedeemMoreThanDebt(uint256 index, int32 tick, uint256 debtDataTokenAmount, uint256 inputTokenAmount);
/**
* @notice Gets information about redeeming tokens for a specific user
* @param manager The token manager contract
* @param user The user address
* @param tokenRedeemAmount The amount of tokens to redeem
* @return tokenAmounts The amount of tokens to redeems at each tick
* @return quoteToRepayAmounts The QUOTE amounts to repay at each tick
* @return totalQuoteSpent The total amount of QUOTE spent
* @return totalTokenRedeemed The total amount of tokens redeemed
* @return params The parameters for adding liquidity to the pool
*/
function redeemInformation(
ITokenManager manager,
address user,
uint128 tokenRedeemAmount
)
external
view
returns (
uint128[] memory tokenAmounts,
uint128[] memory quoteToRepayAmounts,
uint128 totalQuoteSpent,
uint128 totalTokenRedeemed,
IMaverickV2Pool.AddLiquidityParams memory params
);
/**
* @notice Gets information about redeeming tokens for a specific user
* where the user inputs the ticks and token amounts they want to redeem.
* @param manager The token manager contract
* @param user The user address
* @param ticks The ticks to redeem from
* @param tokenAmounts The amount of token to redeem from each tick
* @return quoteToRepayAmounts The QUOTE amounts to repay at each tick
* @return totalQuoteSpent The total amount of QUOTE spent
* @return totalTokenRedeemed The total amount of tokens redeemed
* @return params The parameters for adding liquidity to the pool
*/
function redeemInformationByTick(
ITokenManager manager,
address user,
int32[] memory ticks,
uint128[] memory tokenAmounts
)
external
view
returns (
uint128[] memory quoteToRepayAmounts,
uint128 totalQuoteSpent,
uint128 totalTokenRedeemed,
IMaverickV2Pool.AddLiquidityParams memory params
);
/**
* @notice Estimates output from borrowing QUOTE from the pool and swap to ETH
* @param manager Token manager to estimate
* @param ethToQuotePool The maverick pool that has eth and quote.
* @param tokenBorrowAmount The desired amount of tokens to send as collateral
* @return ticks The ticks involved in the borrowing operation
* @return tokenAmounts The token amounts at each tick
* @return quoteToRepayAmounts The QUOTE amounts to repay at each tick
* @return tokenCollateralAmount The amount of tokens used as collateral
* @return quoteToRepayAmount The total amount of QUOTE to repay
* @return quoteToBorrowerAmount The amount of QUOTE sent to the borrower
* @return ethToBorrowerAmount The amount of ETH sent to the borrower
*/
function estimateBorrowQuoteToEth(
ITokenManager manager,
IMaverickV2Pool ethToQuotePool,
uint128 tokenBorrowAmount
)
external
returns (
int32[] memory ticks,
uint128[] memory tokenAmounts,
uint128[] memory quoteToRepayAmounts,
uint128 tokenCollateralAmount,
uint128 quoteToRepayAmount,
uint128 quoteToBorrowerAmount,
uint256 ethToBorrowerAmount
);
/**
* @notice Estimates the output of the redeem token collateral
* @param manager Token manager to estimate
* @param ethToQuotePool The maverick pool that has eth and quote.
* @param maxRedeemTokenAmount The max amount of tokens to redeem
* @return ticks The ticks involved in the redemption operation
* @return tokenAmounts The token amounts at each tick
* @return quoteToRepayAmounts The QUOTE amounts to repay at each tick
* @return totalQuoteSpent The total amount of QUOTE spent
* @return totalEthSpent The total amount of QUOTE spent
* @return totalTokenRedeemed The total amount of tokens redeemed
*/
function estimateRedeemTokenCollateralWithEth(
ITokenManager manager,
IMaverickV2Pool ethToQuotePool,
uint128 maxRedeemTokenAmount
)
external
returns (
int32[] memory ticks,
uint128[] memory tokenAmounts,
uint128[] memory quoteToRepayAmounts,
uint128 totalQuoteSpent,
uint256 totalEthSpent,
uint128 totalTokenRedeemed
);
/**
* @notice Estimates the output of the redeem token collateral
* @param manager Token manager to estimate
* @param ethToQuotePool The maverick pool that has eth and quote.
* @param ticks The ticks involved in the redemption operation
* @param tokenAmounts The token amounts at each tick
* @return quoteToRepayAmounts The QUOTE amounts to repay at each tick
* @return totalQuoteSpent The total amount of QUOTE spent
* @return totalEthSpent The total amount of QUOTE spent
* @return totalTokenRedeemed The total amount of tokens redeemed
*/
function estimateRedeemTokenCollateralWithEthByTick(
ITokenManager manager,
IMaverickV2Pool ethToQuotePool,
int32[] memory ticks,
uint128[] memory tokenAmounts
)
external
returns (
uint128[] memory quoteToRepayAmounts,
uint128 totalQuoteSpent,
uint256 totalEthSpent,
uint128 totalTokenRedeemed
);
/**
* @notice Gets information about borrowing tokens
* @param manager The token manager contract
* @param tokenBorrowAmount The amount of tokens to borrow
* @return ticks The ticks borrowed from
* @return tokenAmounts The token amounts at each tick
* @return quoteToRepayAmounts The QUOTE amounts to repay at each tick
* @return totalTokenCollateralAmount The total amount of tokens used as collateral
* @return params The parameters for removing liquidity from the pool
*/
function borrowInformation(
ITokenManager manager,
uint128 tokenBorrowAmount
)
external
view
returns (
int32[] memory ticks,
uint128[] memory tokenAmounts,
uint128[] memory quoteToRepayAmounts,
uint128 totalTokenCollateralAmount,
IMaverickV2Pool.RemoveLiquidityParams memory params
);
/**
* @notice Gets the tick and total number of ticks for a token manager's pool
* @param manager The token manager contract
* @return tick The current tick of the pool
*/
function ticksIntoPool(ITokenManager manager) external view returns (uint256 tick);
/**
* @notice Gets the borrowed amounts for a specific user in a token manager
* @param manager The token manager contract
* @param user The user address
* @return ticks The ticks where the user has borrowed amounts
* @return quoteAmounts The QUOTE amounts borrowed at each tick
* @return tokenAmounts The token amounts borrowed at each tick
* @return totalQuoteAmount The total QUOTE amount borrowed by the user
* @return totalTokenAmount The total token amount borrowed by the user
*/
function userBorrowedAmounts(
ITokenManager manager,
address user
)
external
view
returns (
int32[] memory ticks,
uint128[] memory quoteAmounts,
uint128[] memory tokenAmounts,
uint128 totalQuoteAmount,
uint128 totalTokenAmount
);
/**
* @notice Gets the total borrowed amounts in a token manager
* @param manager The token manager contract
* @return ticks The ticks where there are borrowed amounts
* @return quoteAmounts The total QUOTE amounts borrowed at each tick
* @return tokenAmounts The total token amounts borrowed at each tick
* @return totalQuoteAmount The total QUOTE amount borrowed
* @return totalTokenAmount The total token amount borrowed
*/
function totalBorrowedAmounts(
ITokenManager manager
)
external
view
returns (
int32[] memory ticks,
uint128[] memory quoteAmounts,
uint128[] memory tokenAmounts,
uint128 totalQuoteAmount,
uint128 totalTokenAmount
);
function lastTick() external view returns (int32);
function distribution() external view returns (IDistribution);
function borrowAllowed(bool tokenIsA, int32 tick, uint256 tickIntoPool) external view returns (bool);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (governance/utils/IVotes.sol)
pragma solidity ^0.8.20;
/**
* @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts.
*/
interface IVotes {
/**
* @dev The signature used has expired.
*/
error VotesExpiredSignature(uint256 expiry);
/**
* @dev Emitted when an account changes their delegate.
*/
event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
/**
* @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of voting units.
*/
event DelegateVotesChanged(address indexed delegate, uint256 previousVotes, uint256 newVotes);
/**
* @dev Returns the current amount of votes that `account` has.
*/
function getVotes(address account) external view returns (uint256);
/**
* @dev Returns the amount of votes that `account` had at a specific moment in the past. If the `clock()` is
* configured to use block numbers, this will return the value at the end of the corresponding block.
*/
function getPastVotes(address account, uint256 timepoint) external view returns (uint256);
/**
* @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is
* configured to use block numbers, this will return the value at the end of the corresponding block.
*
* NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.
* Votes that have not been delegated are still part of total supply, even though they would not participate in a
* vote.
*/
function getPastTotalSupply(uint256 timepoint) external view returns (uint256);
/**
* @dev Returns the delegate that `account` has chosen.
*/
function delegates(address account) external view returns (address);
/**
* @dev Delegates votes from the sender to `delegatee`.
*/
function delegate(address delegatee) external;
/**
* @dev Delegates votes from signer to `delegatee`.
*/
function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) external;
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC5805} from "@openzeppelin/contracts/interfaces/IERC5805.sol";
import {ILaunchFactory} from "./ILaunchFactory.sol";
import {ISwapper} from "./ISwapper.sol";
import {IMulticall} from "../v2-common/base/IMulticall.sol";
interface IVotingDistributor is IMulticall {
error InvalidEpoch(uint256 epoch);
error InvalidVeToken();
error InvalidVote(IERC20 token, uint256 weight, uint256 totalWeight, uint256 vote);
error NotFactoryToken(IERC20 token);
error SenderHasNoVotingPower(address sender, uint256 epoch);
error InvalidTargetOrder(IERC20 lastToken, IERC20 currentToken);
error SenderHasAlreadyVoted();
error TokenAlreadyDistributed(IERC20 token, uint256 epoch);
error VoterAlreadyCollected(address user, IERC20 token, uint256 epoch);
error NothingToDistribute();
error ZeroAmount();
error RolloverNotAllowed(uint256 voteForThisToken);
error PoolTwapGapTooBig(int256 tickDiffD8, int256 maxTickDiffD8);
error VotePeriodNotActive(uint256 timestamp, uint256 epochStart, uint256 epochEnd);
error VotePeriodNotEnded(uint256 timestamp, uint256 epochStart, uint256 epochEnd);
error EpochEnded(uint256 timestamp, uint256 epochStart, uint256 epochEnd);
error UseCollectVoteFee();
error MustCallFromEOA(address txOrigin, address msgSender);
event Vote(IERC20 indexed quoteToken, uint256 indexed epoch, address indexed voter, IERC20 token, uint256 vote);
event AddDistributionBudget(
IERC20 indexed quoteToken,
uint256 indexed epoch,
address indexed sender,
uint256 amount
);
event AddVoteIncentive(
IERC20 indexed quoteToken,
uint256 indexed epoch,
address indexed sender,
IERC20 token,
uint256 amount,
IERC20 incentiveToken
);
event RollUnvotedIncentive(
IERC20 indexed quoteToken,
uint256 indexed epoch,
IERC20 tokenToIncentivize,
IERC20 incentiveToken,
uint256 amount,
uint256 newEpoch
);
event Distribute(
IERC20 indexed quoteToken,
uint256 indexed epoch,
address indexed sender,
IERC20 token,
uint256 quoteTokenAmountDistributed,
uint256 tokenAmountBurned
);
event CollectVoteIncentive(
IERC20 indexed quoteToken,
uint256 indexed epoch,
address indexed voter,
IERC20 token,
uint256 amount,
IERC20 incentiveToken
);
event CollectVoteFee(
IERC20 indexed quoteToken,
uint256 indexed epoch,
address indexed voter,
IERC20 token,
uint256 quoteTokenAmount,
uint256 tokenAmount
);
/**
* @param startIndex The start index of the tokens to get.
* @param endIndex The end index of the tokens to get.
* @param incentiveStartIndex The start index of the incentive tokens to get.
* @param incentiveEndIndex The end index of the incentive tokens to get.
*/
struct IndexBounds {
uint256 startIndex;
uint256 endIndex;
uint256 incentiveStartIndex;
uint256 incentiveEndIndex;
}
struct ClaimData {
IERC20 token;
uint256 incentiveTokenCount;
IERC20[] incentiveTokens;
uint256[] incentiveAmounts;
uint256[] tokenBoughtAmounts;
bool[] hasCollected;
}
struct VoterData {
bool hasVoted;
uint128[] votes;
IERC20[] tokens;
}
struct TokenView {
IERC20 token;
uint256 votes;
bool hasDistributed;
IERC20[] incentiveTokens;
uint256[] voteIncentives;
uint256 incentiveTokenCount;
}
/**
* @notice Get the quote token used for distributions.
* @return The quote token.
*/
function quoteToken() external view returns (IERC20);
/**
* @notice Get the launch factory associated with this distributor.
* @return The launch factory.
*/
function factory() external view returns (ILaunchFactory);
/**
* @notice Get the voting escrow token used for voting power.
* @return The voting escrow token.
*/
function veToken() external view returns (IERC5805);
/**
* @notice Get the swapper contract used for token operations.
* @return The swapper contract.
*/
function swapper() external view returns (ISwapper);
/////////////////////////////////////
/// Voting
/////////////////////////////////////
/**
* @notice Vote for the given tokens with the given weights.
* @param voteTargets The tokens to vote for.
* @param weights The relative weight of each token.
*/
function vote(IERC20[] memory voteTargets, uint256[] memory weights) external;
/////////////////////////////////////
/// Epoch Budgets
/////////////////////////////////////
/**
* @notice Add a distribution budget for the given epoch. Function
* performs a transferFrom from msg.sender, so the send must first approve
* this contract for the amount.
* @param amount The amount of the budget.
* @param epoch The epoch to add the budget to.
*/
function addDistributionBudget(uint256 amount, uint256 epoch) external;
/**
* @notice Add a distribution budget for the current epoch. Function
* performs a transferFrom from msg.sender, so the send must first approve
* this contract for the amount.
* @param amount The amount of the budget.
*/
function addDistributionBudgetCurrentEpoch(uint256 amount) external;
/**
* @notice Add a vote incentive for the given token and epoch.
* @param tokenToIncentivize The token to incentivize.
* @param incentiveToken The incentive token.
* @param amount The amount of the incentive.
* @param epoch The epoch to add the incentive to.
*/
function addVoteIncentive(IERC20 tokenToIncentivize, IERC20 incentiveToken, uint256 amount, uint256 epoch) external;
/**
* @notice Add a vote incentive for the given token and current epoch.
* @param tokenToIncentivize The token to incentivize.
* @param incentiveToken The incentive token.
* @param amount The amount of the incentive.
*/
function addVoteIncentiveToCurrentEpoch(IERC20 tokenToIncentivize, IERC20 incentiveToken, uint256 amount) external;
/**
* @notice Rollover a vote incentive for the given token and epoch to the next epoch.
* @param tokenToIncentivize The token to incentivize.
* @param incentiveToken The incentive token.
* @param epoch The epoch the incentives were added to.
* @return amount The amount of the incentive.
* @return newEpoch The new epoch where the incentives will be distributed.
*/
function rollUnvotedIncentive(
IERC20 tokenToIncentivize,
IERC20 incentiveToken,
uint256 epoch
) external returns (uint256 amount, uint256 newEpoch);
/////////////////////////////////////
/// Post-Epoch Collections
/////////////////////////////////////
/**
* @notice Distribute the incentives for the given token and epoch.
* @param token The token to distribute incentives for.
* @param epoch The epoch to distribute incentives for.
* @return amountDistributed The amount of incentives distributed.
* @return amountBurned The amount of incentives burned.
*/
function distribute(IERC20 token, uint256 epoch) external returns (uint256 amountDistributed, uint256 amountBurned);
/**
* @notice Distribute the incentives for the given token and epoch.
* @param token The token to distribute incentives for.
* @param epoch The epoch to distribute incentives for.
* @return amountDistributed The amount of incentives distributed.
* @return amountBurned The amount of incentives burned.
* @return twaGapPasses Indicator of whether the pool twa is such that a
* swap will be executed.
*/
function distributeAmount(
IERC20 token,
uint256 epoch
) external returns (uint256 amountDistributed, uint256 amountBurned, bool twaGapPasses);
/**
* @notice Collect the vote incentive for the given token, incentive
* token, and epoch.
* @param token The token to collect the incentive for.
* @param incentiveToken The incentive token to collect.
* @param epoch The epoch to collect the incentive for.
* @return amount The amount of the incentive collected.
*/
function collectVoteIncentive(IERC20 token, IERC20 incentiveToken, uint256 epoch) external returns (uint256 amount);
/**
* @notice Collect the vote incentive for the given token, incentive
* token, and epoch when the incentive token is the quoteToken.
* @param token The token to collect the incentive for.
* @param epoch The epoch to collect the incentive for.
* @return amount The amount of the incentive.
* @return amountToken The amount of the token bought and send to sender.
*/
function collectVoteFee(
IERC20 token,
uint256 amountOutMinimum,
uint256 epoch
) external returns (uint256 amount, uint256 amountToken);
/**
* @notice View the vote incentive for the given token, incentive
* token, and epoch.
* @param user Address of user to check amounts for.
* @param token The token to collect the incentive for.
* @param incentiveToken The incentive token to collect.
* @param epoch The epoch to collect the incentive for.
* @return amount The amount of the incentive collected.
*/
function collectVoteIncentiveAmount(
address user,
IERC20 token,
IERC20 incentiveToken,
uint256 epoch
) external view returns (uint256 amount);
/**
* @notice View the vote incentive for the given token, incentive
* token, and epoch when the incentive token is the quoteToken.
* @param user Address of user to check amounts for.
* @param token The token to collect the incentive for.
* @param epoch The epoch to collect the incentive for.
* @return amount The amount of the incentive collected.
* @return amountToken The amount of the token bought and send to sender.
*/
function collectVoteFeeAmount(
address user,
IERC20 token,
uint256 epoch
) external returns (uint256 amount, uint256 amountToken);
/////////////////////////////////////
/// Epoch State Viewers
/////////////////////////////////////
/**
* @notice Get the checkpoint data for the given epoch.
* @param epoch The epoch to get the checkpoint data for.
* @param bounds Index bounds to search.
* @return budget The budget for the epoch.
* @return totalVote The total vote for the epoch.
* @return tokens The tokens for the epoch.
*/
function getCheckpointData(
uint256 epoch,
IndexBounds memory bounds
) external view returns (uint128 budget, uint128 totalVote, TokenView[] memory tokens, uint256 totalCount);
/**
* @notice Get the incentive data for the given epoch and token.
* @param epoch The epoch to get the incentive data for.
* @param token The token to get the incentive data for.
* @param startIndex The start index of the incentive tokens to get.
* @param endIndex The end index of the incentive tokens to get.
* @return incentiveTokens The incentive tokens for the epoch and token.
* @return voteIncentives The vote incentives for the epoch and token.
* @return totalCount The total count of incentive tokens for the epoch and token.
*/
function getIncentiveData(
IERC20 token,
uint256 epoch,
uint256 startIndex,
uint256 endIndex
) external view returns (IERC20[] memory incentiveTokens, uint256[] memory voteIncentives, uint256 totalCount);
/**
* @notice Get the claim data for the given user/epoch. Performs a pool
* quote so is not a view function, but does not alter state.
* @param user account to check
* @param epoch The epoch to get the checkpoint data for.
* @param bounds Index bounds to search.
*/
function getVoterClaimData(
address user,
uint256 epoch,
IndexBounds memory bounds
) external returns (ClaimData[] memory claimData, uint256 totalCount);
/**
* @notice Check if the given user has voted in the given epoch.
* @param user The user to check.
* @param epoch The epoch to check.
* @return hasVoted True if the user has voted, false otherwise.
*/
function hasVoted(address user, uint256 epoch) external view returns (bool);
/**
* @notice Get the voter data for the given user and epoch.
* @param user The user to get the voter data for.
* @param epoch The epoch to get the voter data for.
* @return voterData The voter data for the user and epoch.
*/
function getVoterData(address user, uint256 epoch) external view returns (VoterData memory voterData);
/////////////////////////////////////
/// Epoch Checkers and Helpers
/////////////////////////////////////
/**
* @notice Check if the given epoch is a valid epoch.
* @param epoch The epoch to check.
* @return _isEpoch True if the epoch is a valid epoch, false otherwise.
*/
function isEpoch(uint256 epoch) external pure returns (bool _isEpoch);
/**
* @notice Check if the given epoch is over.
* @param epoch The epoch to check.
* @return isOver True if the epoch is over, false otherwise.
*/
function epochIsOver(uint256 epoch) external view returns (bool isOver);
/**
* @notice Check if voting is active in the given epoch.
* @param epoch The epoch to check.
* @return isActive True if voting is active, false otherwise.
*/
function votingIsActive(uint256 epoch) external view returns (bool isActive);
/**
* @notice Get the end timestamp of the given epoch.
* @param epoch The epoch to get the end timestamp for.
* @return end The end timestamp of the epoch.
*/
function epochEnd(uint256 epoch) external pure returns (uint256 end);
/**
* @notice Get the current epoch.
*/
function currentEpoch() external view returns (uint256 epoch);
/**
* @notice Get the last epoch.
*/
function lastEpoch() external view returns (uint256 epoch);
/**
* @notice Get the next epoch.
*/
function nextEpoch() external view returns (uint256 epoch);
/**
* @notice Get the epoch period.
*/
// solhint-disable-next-line func-name-mixedcase
function EPOCH_PERIOD() external view returns (uint256);
/**
* @notice Get the pool TWA gap for the given token.
* @param token The token to get the pool TWA gap for.
* @return tickDiffD8 Tick difference in 8-decimal scale.
* @return isReady Bool indicator of whether the blocktimestamp is valid.
*/
function poolTwaGap(IERC20 token) external view returns (int256 tickDiffD8, bool isReady);
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWETH9 is IERC20 {
event Deposit(address indexed dst, uint256 wad);
event Withdrawal(address indexed src, uint256 wad);
function deposit() external payable;
function withdraw(uint256) external;
}
// SPDX-License-Identifier: GPL-2.0-or-later
// As the copyright holder of this work, Ubiquity Labs retains
// the right to distribute, use, and modify this code under any license of
// their choosing, in addition to the terms of the GPL-v2 or later.
pragma solidity ^0.8.25;
import {Math as OzMath} from "@openzeppelin/contracts/utils/math/Math.sol";
import {ONE, DEFAULT_SCALE, DEFAULT_DECIMALS, INT_ONE_D8, ONE_SQUARED} from "./Constants.sol";
/**
* @notice Math functions.
*/
library Math {
/**
* @notice Returns the lesser of two values.
* @param x First uint256 value.
* @param y Second uint256 value.
*/
function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly ("memory-safe") {
z := xor(x, mul(xor(x, y), lt(y, x)))
}
}
/**
* @notice Returns the lesser of two uint128 values.
* @param x First uint128 value.
* @param y Second uint128 value.
*/
function min128(uint128 x, uint128 y) internal pure returns (uint128 z) {
assembly ("memory-safe") {
z := xor(x, mul(xor(x, y), lt(y, x)))
}
}
/**
* @notice Returns the lesser of two int256 values.
* @param x First int256 value.
* @param y Second int256 value.
*/
function min(int256 x, int256 y) internal pure returns (int256 z) {
assembly ("memory-safe") {
z := xor(x, mul(xor(x, y), slt(y, x)))
}
}
/**
* @notice Returns the greater of two uint256 values.
* @param x First uint256 value.
* @param y Second uint256 value.
*/
function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly ("memory-safe") {
z := xor(x, mul(xor(x, y), gt(y, x)))
}
}
/**
* @notice Returns the greater of two int256 values.
* @param x First int256 value.
* @param y Second int256 value.
*/
function max(int256 x, int256 y) internal pure returns (int256 z) {
assembly ("memory-safe") {
z := xor(x, mul(xor(x, y), sgt(y, x)))
}
}
/**
* @notice Returns the greater of two uint128 values.
* @param x First uint128 value.
* @param y Second uint128 value.
*/
function max128(uint128 x, uint128 y) internal pure returns (uint128 z) {
assembly ("memory-safe") {
z := xor(x, mul(xor(x, y), gt(y, x)))
}
}
/**
* @notice Thresholds a value to be within the specified bounds.
* @param value The value to bound.
* @param lowerLimit The minimum allowable value.
* @param upperLimit The maximum allowable value.
*/
function boundValue(
uint256 value,
uint256 lowerLimit,
uint256 upperLimit
) internal pure returns (uint256 outputValue) {
outputValue = min(max(value, lowerLimit), upperLimit);
}
/**
* @notice Returns the difference between two uint128 values or zero if the result would be negative.
* @param x The minuend.
* @param y The subtrahend.
*/
function clip128(uint128 x, uint128 y) internal pure returns (uint128) {
unchecked {
return x < y ? 0 : x - y;
}
}
/**
* @notice Returns the difference between two uint256 values or zero if the result would be negative.
* @param x The minuend.
* @param y The subtrahend.
*/
function clip(uint256 x, uint256 y) internal pure returns (uint256) {
unchecked {
return x < y ? 0 : x - y;
}
}
/**
* @notice Divides one uint256 by another, rounding down to the nearest
* integer.
* @param x The dividend.
* @param y The divisor.
*/
function divFloor(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivFloor(x, ONE, y);
}
/**
* @notice Divides one uint256 by another, rounding up to the nearest integer.
* @param x The dividend.
* @param y The divisor.
*/
function divCeil(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivCeil(x, ONE, y);
}
/**
* @notice Multiplies two uint256 values and then divides by ONE, rounding down.
* @param x The multiplicand.
* @param y The multiplier.
*/
function mulFloor(uint256 x, uint256 y) internal pure returns (uint256) {
return OzMath.mulDiv(x, y, ONE);
}
/**
* @notice Multiplies two uint256 values and then divides by ONE, rounding up.
* @param x The multiplicand.
* @param y The multiplier.
*/
function mulCeil(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivCeil(x, y, ONE);
}
/**
* @notice Calculates the multiplicative inverse of a uint256, rounding down.
* @param x The value to invert.
*/
function invFloor(uint256 x) internal pure returns (uint256) {
unchecked {
return ONE_SQUARED / x;
}
}
/**
* @notice Calculates the multiplicative inverse of a uint256, rounding up.
* @param denominator The value to invert.
*/
function invCeil(uint256 denominator) internal pure returns (uint256 z) {
assembly ("memory-safe") {
// divide z - 1 by the denominator and add 1.
z := add(div(sub(ONE_SQUARED, 1), denominator), 1)
}
}
/**
* @notice Multiplies two uint256 values and divides by a third, rounding down.
* @param x The multiplicand.
* @param y The multiplier.
* @param k The divisor.
*/
function mulDivFloor(uint256 x, uint256 y, uint256 k) internal pure returns (uint256 result) {
result = OzMath.mulDiv(x, y, max(1, k));
}
/**
* @notice Multiplies two uint256 values and divides by a third, rounding up if there's a remainder.
* @param x The multiplicand.
* @param y The multiplier.
* @param k The divisor.
*/
function mulDivCeil(uint256 x, uint256 y, uint256 k) internal pure returns (uint256 result) {
result = mulDivFloor(x, y, k);
if (mulmod(x, y, max(1, k)) != 0) result = result + 1;
}
/**
* @notice Multiplies two uint256 values and divides by a third, rounding
* down. Will revert if `x * y` is larger than `type(uint256).max`.
* @param x The first operand for multiplication.
* @param y The second operand for multiplication.
* @param denominator The divisor after multiplication.
*/
function mulDivDown(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 z) {
assembly ("memory-safe") {
// Store x * y in z for now.
z := mul(x, y)
if iszero(denominator) {
denominator := 1
}
if iszero(or(iszero(x), eq(div(z, x), y))) {
revert(0, 0)
}
// Divide z by the denominator.
z := div(z, denominator)
}
}
/**
* @notice Multiplies two uint256 values and divides by a third, rounding
* up. Will revert if `x * y` is larger than `type(uint256).max`.
* @param x The first operand for multiplication.
* @param y The second operand for multiplication.
* @param denominator The divisor after multiplication.
*/
function mulDivUp(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 z) {
assembly ("memory-safe") {
// Store x * y in z for now.
z := mul(x, y)
if iszero(denominator) {
denominator := 1
}
if iszero(or(iszero(x), eq(div(z, x), y))) {
revert(0, 0)
}
// First, divide z - 1 by the denominator and add 1.
// We allow z - 1 to underflow if z is 0, because we multiply the
// end result by 0 if z is zero, ensuring we return 0 if z is zero.
z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1))
}
}
/**
* @notice Multiplies a uint256 by another and divides by a constant,
* rounding down. Will revert if `x * y` is larger than
* `type(uint256).max`.
* @param x The multiplicand.
* @param y The multiplier.
*/
function mulDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, y, ONE);
}
/**
* @notice Divides a uint256 by another, rounding down the result. Will
* revert if `x * 1e18` is larger than `type(uint256).max`.
* @param x The dividend.
* @param y The divisor.
*/
function divDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, ONE, y);
}
/**
* @notice Divides a uint256 by another, rounding up the result. Will
* revert if `x * 1e18` is larger than `type(uint256).max`.
* @param x The dividend.
* @param y The divisor.
*/
function divUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, ONE, y);
}
/**
* @notice Scales a number based on a difference in decimals from a default.
* @param decimals The new decimal precision.
*/
function scale(uint8 decimals) internal pure returns (uint256) {
unchecked {
if (decimals == DEFAULT_DECIMALS) {
return DEFAULT_SCALE;
} else {
return 10 ** (DEFAULT_DECIMALS - decimals);
}
}
}
/**
* @notice Adjusts a scaled amount to the token decimal scale.
* @param amount The scaled amount.
* @param scaleFactor The scaling factor to adjust by.
* @param ceil Whether to round up (true) or down (false).
*/
function ammScaleToTokenScale(uint256 amount, uint256 scaleFactor, bool ceil) internal pure returns (uint256 z) {
unchecked {
if (scaleFactor == DEFAULT_SCALE || amount == 0) {
return amount;
} else {
if (!ceil) return amount / scaleFactor;
assembly ("memory-safe") {
z := add(div(sub(amount, 1), scaleFactor), 1)
}
}
}
}
/**
* @notice Adjusts a token amount to the D18 AMM scale.
* @param amount The amount in token scale.
* @param scaleFactor The scale factor for adjustment.
*/
function tokenScaleToAmmScale(uint256 amount, uint256 scaleFactor) internal pure returns (uint256) {
if (scaleFactor == DEFAULT_SCALE) {
return amount;
} else {
return amount * scaleFactor;
}
}
/**
* @notice Returns the absolute value of a signed 32-bit integer.
* @param x The integer to take the absolute value of.
*/
function abs32(int32 x) internal pure returns (uint32) {
unchecked {
return uint32(x < 0 ? -x : x);
}
}
/**
* @notice Returns the absolute value of a signed 256-bit integer.
* @param x The integer to take the absolute value of.
*/
function abs(int256 x) internal pure returns (uint256) {
unchecked {
return uint256(x < 0 ? -x : x);
}
}
/**
* @notice Calculates the integer square root of a uint256 rounded down.
* @param x The number to take the square root of.
*/
function sqrt(uint256 x) internal pure returns (uint256 z) {
// from https://github.com/transmissions11/solmate/blob/e8f96f25d48fe702117ce76c79228ca4f20206cb/src/utils/FixedPointMathLib.sol
assembly ("memory-safe") {
let y := x
z := 181
if iszero(lt(y, 0x10000000000000000000000000000000000)) {
y := shr(128, y)
z := shl(64, z)
}
if iszero(lt(y, 0x1000000000000000000)) {
y := shr(64, y)
z := shl(32, z)
}
if iszero(lt(y, 0x10000000000)) {
y := shr(32, y)
z := shl(16, z)
}
if iszero(lt(y, 0x1000000)) {
y := shr(16, y)
z := shl(8, z)
}
z := shr(18, mul(z, add(y, 65536)))
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)))
z := sub(z, lt(div(x, z), z))
}
}
/**
* @notice Computes the floor of a D8-scaled number as an int32, ignoring
* potential overflow in the cast.
* @param val The D8-scaled number.
*/
function floorD8Unchecked(int256 val) internal pure returns (int32) {
int32 val32;
bool check;
unchecked {
val32 = int32(val / INT_ONE_D8);
check = (val < 0 && val % INT_ONE_D8 != 0);
}
return check ? val32 - 1 : val32;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.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 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;
}
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.25;
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {SafeCast as Cast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {IEntropy} from "@pythnetwork/entropy-sdk-solidity/IEntropy.sol";
import {IMaverickV2Pool} from "./v2-common/interfaces/IMaverickV2Pool.sol";
import {IMaverickV2Factory} from "./v2-common/interfaces/IMaverickV2Factory.sol";
import {Math} from "./v2-common/libraries/Math.sol";
import {ITokenManager} from "./interfaces/ITokenManager.sol";
import {IWETH9} from "./interfaces/external/IWETH9.sol";
import {IMaverickV2Quoter} from "./interfaces/external/IMaverickV2Quoter.sol";
import {ILaunchFactory} from "./interfaces/ILaunchFactory.sol";
import {ILaunchToken} from "./interfaces/ILaunchToken.sol";
import {IVotingDistributor} from "./interfaces/IVotingDistributor.sol";
import {IReferralRegistry} from "./interfaces/IReferralRegistry.sol";
import {ISwapper} from "./interfaces/ISwapper.sol";
import {IHistoricalBalanceNonTransferableERC20} from "./interfaces/IHistoricalBalanceNonTransferableERC20.sol";
import {HistoricalBalanceNonTransferableERC20Deployer} from "./HistoricalBalanceNonTransferableERC20Deployer.sol";
import {IRaffleVault} from "./interfaces/IRaffleVault.sol";
import {IFeeVault} from "./interfaces/IFeeVault.sol";
import {FeeVault} from "./FeeVault.sol";
/**
* @notice Token swap router for buying and selling tokens. All fee
* disbursement is handled by this contract.
*
* @notice Fee Details. There are two components of the swap fee: 1) a fixed
* component and 2) a creator-defined component. The fixed component of fee is
* defined by `feeRateD18` and that is split between the swap fee raffle, a
* referer if one exists, and the protocol. The creator-defined fee is split
* between the creator, the voting distributor, and the protocol. In each swap,
* the fee for all components except the voting distributor is pushed to the
* FeeVault and can be claimed at any point by the fee reciever. The
* component of the fee for the voting distributor is sent directly to the
* distributor and registered as a voting incentive for this epoch.
*
* @notice Trackers. This contract also generates fee tracker non-transferable
* tokens. The balance of these tokens can be used to determine the fee
* generated by a token, referer, swapper, or creator.
*/
contract Swapper is Ownable, ReentrancyGuard, ISwapper {
using Cast for *;
using SafeERC20 for IERC20;
/// @inheritdoc ISwapper
IWETH9 public immutable weth;
/// @inheritdoc ISwapper
IMaverickV2Quoter public immutable quoter;
/// @inheritdoc ISwapper
address public protocolRecipient;
/// @inheritdoc ISwapper
IMaverickV2Factory public immutable poolFactory;
/// @inheritdoc ISwapper
IReferralRegistry public referralRegistry;
/// @inheritdoc ISwapper
IEntropy public entropy;
/// @inheritdoc ISwapper
FeeRates public feeRates;
/// @inheritdoc ISwapper
uint64 public feeRateD18;
IFeeVault public immutable feeVault;
mapping(IERC20 quote => Trackers) public quoteToTrackers;
mapping(IERC20 quote => IRaffleVault) public quoteToRaffleVault;
mapping(IERC20 quote => IVotingDistributor) public quoteToVotingDistributor;
mapping(IERC20 quote => ILaunchFactory factory) public quoteToFactory;
mapping(IERC20 quote => uint256 balanceRequirement) public balancePerLootBox;
uint24[8] private _thresholds = [4, 3_000, 3_000_000, 3_800_000, 4_800_000, 5_500_000, 6_200_000, 7_500_000];
uint64[8] private _prizes = [0.3e18, 0.01e18, 0.00002e18, 2e18, 1.5e18, 1.35e18, 1.2e18, 1.1e18];
uint8 private _boxBonus = 2;
constructor(
IMaverickV2Quoter _quoter,
IMaverickV2Factory _poolFactory,
address initialOwner,
IWETH9 _weth,
IEntropy _entropy
) Ownable(initialOwner) {
quoter = _quoter;
poolFactory = _poolFactory;
weth = _weth;
feeVault = new FeeVault();
emit SetFeeVault(feeVault);
_setFeeRates(
FeeRates({
proportionToRaffleVaultD18: 0.94e18,
proportionToRefererD18: 0.05e18,
proportionToVotingDistributorD18: 0.94e18,
proportionToCreatorD18: 0.05e18,
proportionToVoterD18: 0.5e18
})
);
_setFeeRateD18(0.009e18);
_setEntropy(_entropy);
_setProtocolRecipient(initialOwner);
}
receive() external payable {
if (IWETH9(msg.sender) != weth) revert SenderNotWETH();
}
///////////////////////
// Only Owner
///////////////////////
function setEntropy(IEntropy _entropy) public onlyOwner {
_setEntropy(_entropy);
}
function _setEntropy(IEntropy _entropy) private {
entropy = _entropy;
emit SetEntropy(_entropy);
}
function setReferralRegistry(IReferralRegistry _registry) public onlyOwner {
referralRegistry = _registry;
emit SetReferralRegistry(_registry);
}
function setPrizesAndThresholdsAndBonus(
uint24[8] memory thresholds,
uint64[8] memory prizes,
uint8 boxBonus
) public onlyOwner {
_thresholds = thresholds;
_prizes = prizes;
_boxBonus = boxBonus;
emit SetPrizesAndThresholds(thresholds, prizes, boxBonus);
}
function setFeeRateD18(uint64 _feeRateD18) public onlyOwner {
_setFeeRateD18(_feeRateD18);
}
function setFeeRates(FeeRates memory _feeRates) public onlyOwner {
_setFeeRates(_feeRates);
}
function _setFeeRateD18(uint64 _feeRateD18) private {
if (_feeRateD18 > .1e18) revert InvalidFeeParameter();
feeRateD18 = _feeRateD18;
emit SetFeeRate(_feeRateD18);
}
function _setFeeRates(FeeRates memory _feeRates) private {
if (_feeRates.proportionToRefererD18 > .1e18) revert InvalidFeeParameter();
if (_feeRates.proportionToRefererD18 + _feeRates.proportionToRaffleVaultD18 > 0.999e18)
revert InvalidFeeParameter();
if (_feeRates.proportionToCreatorD18 > .5e18) revert InvalidFeeParameter();
if (_feeRates.proportionToCreatorD18 + _feeRates.proportionToVotingDistributorD18 > 0.999e18)
revert InvalidFeeParameter();
if (_feeRates.proportionToVoterD18 > 1e18) revert InvalidFeeParameter();
feeRates = _feeRates;
emit SetFeeRates(_feeRates);
}
function setProtocolRecipient(address _protocolRecipient) public onlyOwner {
_setProtocolRecipient(_protocolRecipient);
}
function _setProtocolRecipient(address _protocolRecipient) private {
protocolRecipient = _protocolRecipient;
emit SetProtocolRecipient(_protocolRecipient);
}
function registerQuoteToken(ILaunchFactory factory, uint256 _balancePerLootBox) public onlyOwner {
IERC20 quoteToken = factory.quoteToken();
Trackers storage trackers = quoteToTrackers[quoteToken];
if (address(trackers.sell) != address(0)) revert QuoteTokenAlreadyRegistered(quoteToken);
_setBalancePerLootBox(quoteToken, _balancePerLootBox);
quoteToFactory[quoteToken] = factory;
string memory tokenSymbol = IERC20Metadata(address(quoteToken)).symbol();
trackers.sell = HistoricalBalanceNonTransferableERC20Deployer.deploy(
string.concat("Goose Swapper Sell Fee Tracker - ", tokenSymbol),
string.concat("GSSFT-", tokenSymbol),
quoteToken
);
trackers.buy = HistoricalBalanceNonTransferableERC20Deployer.deploy(
string.concat("Goose Swapper Buy Fee Tracker - ", tokenSymbol),
string.concat("GSBFT-", tokenSymbol),
quoteToken
);
trackers.token = HistoricalBalanceNonTransferableERC20Deployer.deploy(
string.concat("Goose Token Fee Tracker - ", tokenSymbol),
string.concat("GTFT-", tokenSymbol),
quoteToken
);
trackers.creator = HistoricalBalanceNonTransferableERC20Deployer.deploy(
string.concat("Goose Creator Fee Tracker - ", tokenSymbol),
string.concat("GCFT-", tokenSymbol),
quoteToken
);
trackers.referer = HistoricalBalanceNonTransferableERC20Deployer.deploy(
string.concat("Goose Referer Fee Tracker - ", tokenSymbol),
string.concat("GRFT-", tokenSymbol),
quoteToken
);
emit NewTrackers(
quoteToken,
factory,
trackers.sell,
trackers.buy,
trackers.token,
trackers.creator,
trackers.referer
);
}
function setRaffleVault(IERC20 quoteToken, IRaffleVault _raffle) public onlyOwner {
quoteToRaffleVault[quoteToken] = _raffle;
emit NewRaffleVault(quoteToken, _raffle);
}
function setVotingDistributor(IERC20 quoteToken, IVotingDistributor _voting) public onlyOwner {
quoteToVotingDistributor[quoteToken] = _voting;
emit SetVotingDistributor(quoteToken, _voting);
}
function setBalancePerLootBox(IERC20 quoteToken, uint256 _balancePerLootBox) public onlyOwner {
_setBalancePerLootBox(quoteToken, _balancePerLootBox);
}
function _setBalancePerLootBox(IERC20 quoteToken, uint256 _balancePerLootBox) private {
balancePerLootBox[quoteToken] = _balancePerLootBox;
emit SetBalancePerLootBox(quoteToken, _balancePerLootBox);
}
///////////////////////
// View Functions
///////////////////////
/// @inheritdoc ISwapper
function getPrizesAndThresholdsAndBonus()
public
view
returns (uint24[8] memory thresholds, uint64[8] memory prizes, uint8 boxBonus)
{
thresholds = _thresholds;
prizes = _prizes;
boxBonus = _boxBonus;
}
/// @inheritdoc ISwapper
function getTopToken(IERC20 quoteToken) public view returns (IERC20 topToken) {
IHistoricalBalanceNonTransferableERC20 tracker = quoteToTrackers[quoteToken].token;
if (address(tracker) == address(0)) revert NoTracker();
(address _token, ) = tracker.topAccountCurrentDay();
topToken = IERC20(_token);
}
///////////////////////
// Swap Functions
///////////////////////
struct PoolInfo {
IMaverickV2Pool pool;
IERC20 quoteToken;
bool tokenAInForBuy;
uint64 buyFee;
uint64 sellFee;
address creator;
}
/// @inheritdoc ISwapper
function buyToken(
address recipient,
IERC20 token,
uint256 amountQuoteIn,
uint256 amountOutMinimum,
address referer
) public payable returns (uint256 amountOut, IMaverickV2Pool pool) {
return buyTokenSpecifyRaffleRecipient(recipient, token, amountQuoteIn, amountOutMinimum, referer, msg.sender);
}
/// @inheritdoc ISwapper
function buyTokenTwoHop(
address recipient,
IERC20 token,
IMaverickV2Pool ethToQuotePool,
uint256 amountEthIn,
uint256 amountOutMinimum,
address referer
) public payable returns (uint256 amountOut, IMaverickV2Pool pool) {
return
buyTokenTwoHopSpecifyRaffleRecipient(
recipient,
token,
ethToQuotePool,
amountEthIn,
amountOutMinimum,
referer,
msg.sender
);
}
/// @inheritdoc ISwapper
function sellToken(
address recipient,
IERC20 token,
uint256 amountTokenIn,
uint256 amountOutMinimum,
address referer
) public returns (uint256 amountOut, IMaverickV2Pool pool) {
return sellTokenSpecifyRaffleRecipient(recipient, token, amountTokenIn, amountOutMinimum, referer, msg.sender);
}
/// @inheritdoc ISwapper
function sellTokenTwoHop(
address recipient,
IERC20 token,
IMaverickV2Pool ethToQuotePool,
uint256 amountTokenIn,
uint256 amountOutMinimum,
address referer
) public returns (uint256 amountOut, IMaverickV2Pool pool) {
return
sellTokenTwoHopSpecifyRaffleRecipient(
recipient,
token,
ethToQuotePool,
amountTokenIn,
amountOutMinimum,
referer,
msg.sender
);
}
function _buyToken(
address recipient,
IERC20 token,
uint256 amountQuoteIn,
uint256 amountOutMinimum,
address referer,
address raffleRecipient,
bool checkQuote
) internal returns (uint256 amountOut, IMaverickV2Pool pool) {
PoolInfo memory info = _getPool(token);
// sent value and weth is not quote; revert
if (checkQuote && msg.value != 0 && address(info.quoteToken) != address(weth))
revert ValueSentForNonEthQuoteToken(info.quoteToken, msg.value);
// sent wrong value; revert
// if zero sent, transferFrom approved weth;
if (checkQuote && msg.value != amountQuoteIn && msg.value != 0 && address(info.quoteToken) == address(weth))
revert IncorrectEthValueSent(amountQuoteIn, msg.value);
// if user sent correct amount of eth, wrap it
if (msg.value == amountQuoteIn && address(info.quoteToken) == address(weth)) {
weth.deposit{value: amountQuoteIn}();
} else if (info.quoteToken.balanceOf(address(this)) < amountQuoteIn) {
// did not send value and token balance is too low; transferfrom
info.quoteToken.safeTransferFrom(msg.sender, address(this), amountQuoteIn);
}
// if balance is sufficient, no transfer needed
// extract fee
uint256 netQuoteForUser = _extractFee(info, amountQuoteIn, referer, true, token, raffleRecipient);
// pay for token; function takes care of wrapping input eth value if eth is quote
amountOut = _exactInputSingle(recipient, info.pool, info.tokenAInForBuy, netQuoteForUser);
// check slippage
if (amountOut < amountOutMinimum) revert TooLittleReceived(amountOutMinimum, amountOut);
pool = info.pool;
emit BuyToken(
recipient,
token,
amountQuoteIn,
amountOutMinimum,
referer,
raffleRecipient,
amountOut,
pool,
quoter.poolSqrtPrice(pool)
);
}
/// @inheritdoc ISwapper
function buyTokenSpecifyRaffleRecipient(
address recipient,
IERC20 token,
uint256 amountQuoteIn,
uint256 amountOutMinimum,
address referer,
address raffleRecipient
) public payable nonReentrant returns (uint256 amountOut, IMaverickV2Pool pool) {
return _buyToken(recipient, token, amountQuoteIn, amountOutMinimum, referer, raffleRecipient, true);
}
/// @inheritdoc ISwapper
function buyTokenTwoHopSpecifyRaffleRecipient(
address recipient,
IERC20 token,
IMaverickV2Pool ethToQuotePool,
uint256 amountEthIn,
uint256 amountOutMinimum,
address referer,
address raffleRecipient
) public payable nonReentrant returns (uint256 amountOut, IMaverickV2Pool pool) {
if (!poolFactory.isFactoryPool(ethToQuotePool)) revert NotFactoryPool(ethToQuotePool);
// if user sent wrong amount of eth, revert
if (msg.value != amountEthIn) revert IncorrectEthValueSent(amountEthIn, msg.value);
// swap eth for quote
weth.deposit{value: amountEthIn}();
bool tokenAIn = address(ethToQuotePool.tokenA()) == address(weth);
uint256 quoteAmount = _exactInputSingle(address(this), ethToQuotePool, tokenAIn, amountEthIn);
(amountOut, pool) = _buyToken(recipient, token, quoteAmount, amountOutMinimum, referer, raffleRecipient, false);
}
function _sellToken(
address recipient,
IERC20 token,
uint256 amountTokenIn,
uint256 amountOutMinimum,
address referer,
address raffleRecipient
) internal returns (uint256 amountOut, IMaverickV2Pool pool) {
// quote out
PoolInfo memory info = _getPool(token);
// swap token for quote
uint256 amountOutBeforeFee = _exactInputSingle(address(this), info.pool, !info.tokenAInForBuy, amountTokenIn);
// take fee
_extractFee(info, amountOutBeforeFee, referer, false, token, raffleRecipient);
// send output to user
amountOut = _sweepToken(info.quoteToken, recipient);
// check slippage
if (amountOut < amountOutMinimum) revert TooLittleReceived(amountOutMinimum, amountOut);
pool = info.pool;
emit SellToken(
recipient,
token,
amountTokenIn,
amountOutMinimum,
referer,
raffleRecipient,
amountOut,
pool,
quoter.poolSqrtPrice(pool)
);
}
/// @inheritdoc ISwapper
function sellTokenSpecifyRaffleRecipient(
address recipient,
IERC20 token,
uint256 amountTokenIn,
uint256 amountOutMinimum,
address referer,
address raffleRecipient
) public nonReentrant returns (uint256 amountOut, IMaverickV2Pool pool) {
(amountOut, pool) = _sellToken(recipient, token, amountTokenIn, amountOutMinimum, referer, raffleRecipient);
}
/// @inheritdoc ISwapper
function sellTokenTwoHopSpecifyRaffleRecipient(
address recipient,
IERC20 token,
IMaverickV2Pool ethToQuotePool,
uint256 amountTokenIn,
uint256 amountOutMinimum,
address referer,
address raffleRecipient
) public nonReentrant returns (uint256 amountOut, IMaverickV2Pool pool) {
if (!poolFactory.isFactoryPool(ethToQuotePool)) revert NotFactoryPool(ethToQuotePool);
uint256 amountNotEthIn;
(amountNotEthIn, pool) = _sellToken(
address(this),
token,
amountTokenIn,
amountOutMinimum,
referer,
raffleRecipient
);
// amountNonEthIn is non-eth quote sitting on this contract
bool tokenAIn = address(ethToQuotePool.tokenA()) != address(weth);
_exactInputSingle(address(this), ethToQuotePool, tokenAIn, amountNotEthIn);
amountOut = _sweepToken(IERC20(address(weth)), recipient);
}
///////////////////////
// Quote Functions
///////////////////////
/// @inheritdoc ISwapper
function buyTokenQuote(IERC20 token, uint256 amountQuoteIn) public returns (uint256 amountOut) {
// quote in
PoolInfo memory info = _getPool(token);
// extract fee; raw eth at this point
uint256 fee1 = Math.mulDown(feeRateD18, amountQuoteIn);
uint256 fee2 = Math.mulDown(info.buyFee, amountQuoteIn);
uint256 netQuoteForUser = amountQuoteIn - fee1 - fee2;
// pay for token; function takes care of wrapping input eth value
amountOut = _exactInputSingleQuote(info.pool, info.tokenAInForBuy, netQuoteForUser);
}
/// @inheritdoc ISwapper
function buyTokenTwoHopQuote(
IERC20 token,
IMaverickV2Pool ethToQuotePool,
uint256 amountEthIn
) public returns (uint256 amountOut) {
bool tokenAIn = address(ethToQuotePool.tokenA()) == address(weth);
uint256 amountQuoteIn = _exactInputSingleQuote(ethToQuotePool, tokenAIn, amountEthIn);
amountOut = buyTokenQuote(token, amountQuoteIn);
}
/// @inheritdoc ISwapper
function sellTokenQuote(IERC20 token, uint256 amountTokenIn) public returns (uint256 amountOut) {
// quote out
PoolInfo memory info = _getPool(token);
// swap token for weth
uint256 rawAmount = _exactInputSingleQuote(info.pool, !info.tokenAInForBuy, amountTokenIn);
// take fee
uint256 fee1 = Math.mulDown(feeRateD18, rawAmount);
uint256 fee2 = Math.mulDown(info.sellFee, rawAmount);
amountOut = rawAmount - fee1 - fee2;
}
/// @inheritdoc ISwapper
function sellTokenTwoHopQuote(
IERC20 token,
IMaverickV2Pool ethToQuotePool,
uint256 amountTokenIn
) public returns (uint256 amountOut) {
uint256 amountNonEthIn = sellTokenQuote(token, amountTokenIn);
bool tokenAIn = address(ethToQuotePool.tokenA()) != address(weth);
amountOut = _exactInputSingleQuote(ethToQuotePool, tokenAIn, amountNonEthIn);
}
///////////////////////
// Internal Helper Functions
///////////////////////
function _sweepToken(IERC20 token, address recipient) internal returns (uint256 amount) {
amount = token.balanceOf(address(this));
if (amount == 0) return 0;
if (address(token) == address(weth)) {
weth.withdraw(amount);
Address.sendValue(payable(recipient), amount);
} else {
token.safeTransfer(recipient, amount);
}
}
function _getReferer(address inputReferer) internal view returns (address) {
if (address(referralRegistry) == address(0)) return inputReferer;
(address registryValue, ) = referralRegistry.userToRefererData(msg.sender);
if (registryValue == address(0)) return inputReferer;
return registryValue;
}
function _extractFee(
PoolInfo memory info,
uint256 rawAmount,
address referer,
bool isBuy,
IERC20 token,
address raffleRecipient
) internal returns (uint256 amountRemaining) {
IVotingDistributor vote = quoteToVotingDistributor[info.quoteToken];
Recipients memory recipients = Recipients({
protocol: protocolRecipient,
creator: info.creator,
referer: _getReferer(referer),
raffleVault: address(quoteToRaffleVault[info.quoteToken]),
votingDistributor: address(vote),
swapper: msg.sender
});
bool hasVoting = address(vote) != address(0) && address(vote) != msg.sender;
uint256 poolFee = isBuy ? info.buyFee : info.sellFee;
Amounts memory amounts = _computeFees(rawAmount, recipients, poolFee, hasVoting);
_trackAmounts(info.quoteToken, token, isBuy, amounts, recipients, raffleRecipient);
// feeVault does transfer from
info.quoteToken.forceApprove(
address(feeVault),
amounts.amountToCreator + amounts.amountToReferer + amounts.amountToRaffleVault + amounts.amountToProtocol
);
feeVault.depositAmounts(
info.quoteToken,
recipients.creator,
amounts.amountToCreator,
recipients.referer,
amounts.amountToReferer,
recipients.raffleVault,
amounts.amountToRaffleVault,
recipients.protocol,
amounts.amountToProtocol
);
if (hasVoting) _chopForVoting(vote, token, info.quoteToken, amounts);
amountRemaining = amounts.amountToSwapper;
emit FeeEmission(info.quoteToken, recipients, amounts, rawAmount, isBuy);
}
function _chopForVoting(IVotingDistributor vote, IERC20 token, IERC20 quoteToken, Amounts memory amounts) internal {
// voting distributor does transfer from
if (amounts.amountToVoters + amounts.amountToVoteDistribution > 0)
quoteToken.forceApprove(address(vote), amounts.amountToVoters + amounts.amountToVoteDistribution);
if (amounts.amountToVoters > 0) vote.addVoteIncentiveToCurrentEpoch(token, quoteToken, amounts.amountToVoters);
if (amounts.amountToVoteDistribution > 0)
vote.addDistributionBudgetCurrentEpoch(amounts.amountToVoteDistribution);
}
function _trackAmounts(
IERC20 quoteToken,
IERC20 token,
bool isBuy,
Amounts memory amounts,
Recipients memory recipients,
address raffleRecipient
) internal {
Trackers storage trackers = quoteToTrackers[quoteToken];
// track swapper fee amount
IHistoricalBalanceNonTransferableERC20 tracker = isBuy ? trackers.buy : trackers.sell;
tracker.mint(raffleRecipient, amounts.amountToRaffleVault);
// track token fee amount
trackers.token.mint(address(token), amounts.amountToRaffleVault);
trackers.creator.mint(recipients.creator, amounts.amountToCreator);
if (recipients.referer != address(0)) trackers.referer.mint(recipients.referer, amounts.amountToReferer);
}
function _computeFees(
uint256 rawAmount,
Recipients memory recipients,
uint256 poolFeeRate,
bool hasVoting
) internal view returns (Amounts memory amounts) {
// swapper fixed swap fee
uint256 fee = Math.mulDown(feeRateD18, rawAmount);
amounts.amountToReferer = recipients.referer == address(0)
? 0
: Math.mulDown(feeRates.proportionToRefererD18, fee);
amounts.amountToRaffleVault = recipients.raffleVault == address(0)
? 0
: Math.mulDown(feeRates.proportionToRaffleVaultD18, fee);
amounts.amountToProtocol = fee - amounts.amountToReferer - amounts.amountToRaffleVault;
// pool fees
uint256 poolFee = Math.mulDown(rawAmount, poolFeeRate);
uint256 amountToVotingDistributor = hasVoting
? Math.mulDown(feeRates.proportionToVotingDistributorD18, poolFee)
: 0;
amounts.amountToCreator = Math.mulDown(feeRates.proportionToCreatorD18, poolFee);
amounts.amountToProtocol += poolFee - amounts.amountToCreator - amountToVotingDistributor;
amounts.amountToSwapper = rawAmount - fee - poolFee;
amounts.amountToVoters = Math.mulDown(feeRates.proportionToVoterD18, amountToVotingDistributor);
amounts.amountToVoteDistribution = Math.mulDown(
1e18 - feeRates.proportionToVoterD18,
amountToVotingDistributor
);
}
function _getPool(IERC20 token) internal view returns (PoolInfo memory info) {
// gather pool data
ILaunchFactory factory = ILaunchToken(address(token)).getLaunchFactory();
ITokenManager tokenManager = factory.managerFromToken(token);
(info.buyFee, info.sellFee) = tokenManager.fees();
if (address(tokenManager) == address(0)) revert TokenNotFromLaunchFactory();
info.pool = tokenManager.pool();
info.quoteToken = factory.quoteToken();
// ensure this token is from the factory
if (quoteToFactory[info.quoteToken] != factory) revert TokenNotFromLaunchFactory();
info.tokenAInForBuy = info.pool.tokenA() != token;
info.creator = tokenManager.feeRecipient();
}
function _exactInputSingleQuote(
IMaverickV2Pool pool,
bool tokenAIn,
uint256 amountIn
) internal returns (uint256 amountOut) {
(, amountOut, ) = quoter.calculateSwap(
pool,
amountIn.toUint128(),
tokenAIn,
false,
tokenAIn ? type(int32).max : type(int32).min
);
}
function _exactInputSingle(
address recipient,
IMaverickV2Pool pool,
bool tokenAIn,
uint256 amountIn
) internal returns (uint256 amountOut) {
// pay pool
_pay(tokenAIn ? pool.tokenA() : pool.tokenB(), address(pool), amountIn);
// swap
IMaverickV2Pool.SwapParams memory swapParams = IMaverickV2Pool.SwapParams({
amount: amountIn,
tokenAIn: tokenAIn,
exactOutput: false,
tickLimit: tokenAIn ? type(int32).max : type(int32).min
});
(, amountOut) = pool.swap(recipient, swapParams, "");
}
/**
* @notice Internal function to pay tokens.
* @param token ERC20 token to pay.
* @param pool Address of the pool to pay.
* @param value Amount of tokens to pay.
*/
function _pay(IERC20 token, address pool, uint256 value) internal {
if (address(token) == address(weth)) {
// buying and user sent eth was already wrapped
weth.transfer(pool, value);
} else if (token.balanceOf(address(this)) >= value) {
// buying and already did a transferfrom to here
token.safeTransfer(pool, value);
} else {
// selling, so send value straight from user to pool
token.safeTransferFrom(msg.sender, pool, value);
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/types/Time.sol)
pragma solidity ^0.8.20;
import {Math} from "../math/Math.sol";
import {SafeCast} from "../math/SafeCast.sol";
/**
* @dev This library provides helpers for manipulating time-related objects.
*
* It uses the following types:
* - `uint48` for timepoints
* - `uint32` for durations
*
* While the library doesn't provide specific types for timepoints and duration, it does provide:
* - a `Delay` type to represent duration that can be programmed to change value automatically at a given point
* - additional helper functions
*/
library Time {
using Time for *;
/**
* @dev Get the block timestamp as a Timepoint.
*/
function timestamp() internal view returns (uint48) {
return SafeCast.toUint48(block.timestamp);
}
/**
* @dev Get the block number as a Timepoint.
*/
function blockNumber() internal view returns (uint48) {
return SafeCast.toUint48(block.number);
}
// ==================================================== Delay =====================================================
/**
* @dev A `Delay` is a uint32 duration that can be programmed to change value automatically at a given point in the
* future. The "effect" timepoint describes when the transitions happens from the "old" value to the "new" value.
* This allows updating the delay applied to some operation while keeping some guarantees.
*
* In particular, the {update} function guarantees that if the delay is reduced, the old delay still applies for
* some time. For example if the delay is currently 7 days to do an upgrade, the admin should not be able to set
* the delay to 0 and upgrade immediately. If the admin wants to reduce the delay, the old delay (7 days) should
* still apply for some time.
*
*
* The `Delay` type is 112 bits long, and packs the following:
*
* ```
* | [uint48]: effect date (timepoint)
* | | [uint32]: value before (duration)
* ↓ ↓ ↓ [uint32]: value after (duration)
* 0xAAAAAAAAAAAABBBBBBBBCCCCCCCC
* ```
*
* NOTE: The {get} and {withUpdate} functions operate using timestamps. Block number based delays are not currently
* supported.
*/
type Delay is uint112;
/**
* @dev Wrap a duration into a Delay to add the one-step "update in the future" feature
*/
function toDelay(uint32 duration) internal pure returns (Delay) {
return Delay.wrap(duration);
}
/**
* @dev Get the value at a given timepoint plus the pending value and effect timepoint if there is a scheduled
* change after this timepoint. If the effect timepoint is 0, then the pending value should not be considered.
*/
function _getFullAt(Delay self, uint48 timepoint) private pure returns (uint32, uint32, uint48) {
(uint32 valueBefore, uint32 valueAfter, uint48 effect) = self.unpack();
return effect <= timepoint ? (valueAfter, 0, 0) : (valueBefore, valueAfter, effect);
}
/**
* @dev Get the current value plus the pending value and effect timepoint if there is a scheduled change. If the
* effect timepoint is 0, then the pending value should not be considered.
*/
function getFull(Delay self) internal view returns (uint32, uint32, uint48) {
return _getFullAt(self, timestamp());
}
/**
* @dev Get the current value.
*/
function get(Delay self) internal view returns (uint32) {
(uint32 delay, , ) = self.getFull();
return delay;
}
/**
* @dev Update a Delay object so that it takes a new duration after a timepoint that is automatically computed to
* enforce the old delay at the moment of the update. Returns the updated Delay object and the timestamp when the
* new delay becomes effective.
*/
function withUpdate(
Delay self,
uint32 newValue,
uint32 minSetback
) internal view returns (Delay updatedDelay, uint48 effect) {
uint32 value = self.get();
uint32 setback = uint32(Math.max(minSetback, value > newValue ? value - newValue : 0));
effect = timestamp() + setback;
return (pack(value, newValue, effect), effect);
}
/**
* @dev Split a delay into its components: valueBefore, valueAfter and effect (transition timepoint).
*/
function unpack(Delay self) internal pure returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) {
uint112 raw = Delay.unwrap(self);
valueAfter = uint32(raw);
valueBefore = uint32(raw >> 32);
effect = uint48(raw >> 64);
return (valueBefore, valueAfter, effect);
}
/**
* @dev pack the components into a Delay object.
*/
function pack(uint32 valueBefore, uint32 valueAfter, uint48 effect) internal pure returns (Delay) {
return Delay.wrap((uint112(effect) << 64) | (uint112(valueBefore) << 32) | uint112(valueAfter));
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}
{
"compilationTarget": {
"@fairlaunch/contracts/src/Swapper.sol": "Swapper"
},
"evmVersion": "paris",
"libraries": {
"@fairlaunch/contracts/src/HistoricalBalanceNonTransferableERC20Deployer.sol:HistoricalBalanceNonTransferableERC20Deployer": "0x2cb1f21415dc527a4fc9ffcfa131ff2a1a9f3565"
},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 10
},
"remappings": []
}
[{"inputs":[{"internalType":"contract IMaverickV2Quoter","name":"_quoter","type":"address"},{"internalType":"contract IMaverickV2Factory","name":"_poolFactory","type":"address"},{"internalType":"address","name":"initialOwner","type":"address"},{"internalType":"contract IWETH9","name":"_weth","type":"address"},{"internalType":"contract IEntropy","name":"_entropy","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountQuoteIn","type":"uint256"},{"internalType":"uint256","name":"valueSent","type":"uint256"}],"name":"IncorrectEthValueSent","type":"error"},{"inputs":[],"name":"InvalidFeeParameter","type":"error"},{"inputs":[],"name":"NoTracker","type":"error"},{"inputs":[{"internalType":"contract IMaverickV2Pool","name":"ethToQuotePool","type":"address"}],"name":"NotFactoryPool","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"contract IERC20","name":"quoteToken","type":"address"}],"name":"QuoteTokenAlreadyRegistered","type":"error"},{"inputs":[{"internalType":"contract IERC20","name":"quoteToken","type":"address"}],"name":"QuoteTokenIsNotEth","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SenderNotWETH","type":"error"},{"inputs":[],"name":"TokenNotFromLaunchFactory","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountOutMinimumExcludingFee","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"TooLittleReceived","type":"error"},{"inputs":[{"internalType":"contract IERC20","name":"quoteToken","type":"address"},{"internalType":"uint256","name":"valueSent","type":"uint256"}],"name":"ValueSentForNonEthQuoteToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"contract IERC20","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountQuoteIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOutMinimum","type":"uint256"},{"indexed":false,"internalType":"address","name":"referer","type":"address"},{"indexed":false,"internalType":"address","name":"raffleRecipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"},{"indexed":false,"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"},{"indexed":false,"internalType":"uint256","name":"poolSqrtPrice","type":"uint256"}],"name":"BuyToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"referer","type":"address"},{"internalType":"address","name":"raffleVault","type":"address"},{"internalType":"address","name":"votingDistributor","type":"address"},{"internalType":"address","name":"swapper","type":"address"}],"indexed":false,"internalType":"struct ISwapper.Recipients","name":"recipients","type":"tuple"},{"components":[{"internalType":"uint256","name":"amountToProtocol","type":"uint256"},{"internalType":"uint256","name":"amountToCreator","type":"uint256"},{"internalType":"uint256","name":"amountToReferer","type":"uint256"},{"internalType":"uint256","name":"amountToRaffleVault","type":"uint256"},{"internalType":"uint256","name":"amountToSwapper","type":"uint256"},{"internalType":"uint256","name":"amountToVoteDistribution","type":"uint256"},{"internalType":"uint256","name":"amountToVoters","type":"uint256"}],"indexed":false,"internalType":"struct ISwapper.Amounts","name":"amounts","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"rawAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isBuy","type":"bool"}],"name":"FeeEmission","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20","name":"quoteToken","type":"address"},{"indexed":false,"internalType":"contract IRaffleVault","name":"raffleVault","type":"address"}],"name":"NewRaffleVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20","name":"quoteToken","type":"address"},{"indexed":false,"internalType":"contract ILaunchFactory","name":"factory","type":"address"},{"indexed":false,"internalType":"contract IHistoricalBalanceNonTransferableERC20","name":"sellTracker","type":"address"},{"indexed":false,"internalType":"contract IHistoricalBalanceNonTransferableERC20","name":"buyTracker","type":"address"},{"indexed":false,"internalType":"contract IHistoricalBalanceNonTransferableERC20","name":"tokenTracker","type":"address"},{"indexed":false,"internalType":"contract IHistoricalBalanceNonTransferableERC20","name":"creatorTracker","type":"address"},{"indexed":false,"internalType":"contract IHistoricalBalanceNonTransferableERC20","name":"refererTracker","type":"address"}],"name":"NewTrackers","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"contract IERC20","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountTokenIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOutMinimum","type":"uint256"},{"indexed":false,"internalType":"address","name":"referer","type":"address"},{"indexed":false,"internalType":"address","name":"raffleRecipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"},{"indexed":false,"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"},{"indexed":false,"internalType":"uint256","name":"poolSqrtPrice","type":"uint256"}],"name":"SellToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20","name":"quoteToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"balanceRequirement","type":"uint256"}],"name":"SetBalancePerLootBox","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IEntropy","name":"entropy","type":"address"}],"name":"SetEntropy","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"feeRateD18","type":"uint64"}],"name":"SetFeeRate","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint64","name":"proportionToRaffleVaultD18","type":"uint64"},{"internalType":"uint64","name":"proportionToRefererD18","type":"uint64"},{"internalType":"uint64","name":"proportionToVotingDistributorD18","type":"uint64"},{"internalType":"uint64","name":"proportionToCreatorD18","type":"uint64"},{"internalType":"uint64","name":"proportionToVoterD18","type":"uint64"}],"indexed":false,"internalType":"struct ISwapper.FeeRates","name":"feeRates","type":"tuple"}],"name":"SetFeeRates","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IFeeVault","name":"feeVault","type":"address"}],"name":"SetFeeVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint24[8]","name":"thresholds","type":"uint24[8]"},{"indexed":false,"internalType":"uint64[8]","name":"prizes","type":"uint64[8]"},{"indexed":false,"internalType":"uint8","name":"boxBonus","type":"uint8"}],"name":"SetPrizesAndThresholds","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"protocolRecipient","type":"address"}],"name":"SetProtocolRecipient","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IReferralRegistry","name":"registry","type":"address"}],"name":"SetReferralRegistry","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20","name":"quoteToken","type":"address"},{"indexed":false,"internalType":"contract IVotingDistributor","name":"votingDistributor","type":"address"}],"name":"SetVotingDistributor","type":"event"},{"inputs":[{"internalType":"contract IERC20","name":"quote","type":"address"}],"name":"balancePerLootBox","outputs":[{"internalType":"uint256","name":"balanceRequirement","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amountQuoteIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"},{"internalType":"address","name":"referer","type":"address"}],"name":"buyToken","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amountQuoteIn","type":"uint256"}],"name":"buyTokenQuote","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amountQuoteIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"},{"internalType":"address","name":"referer","type":"address"},{"internalType":"address","name":"raffleRecipient","type":"address"}],"name":"buyTokenSpecifyRaffleRecipient","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"contract IMaverickV2Pool","name":"ethToQuotePool","type":"address"},{"internalType":"uint256","name":"amountEthIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"},{"internalType":"address","name":"referer","type":"address"}],"name":"buyTokenTwoHop","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"contract IMaverickV2Pool","name":"ethToQuotePool","type":"address"},{"internalType":"uint256","name":"amountEthIn","type":"uint256"}],"name":"buyTokenTwoHopQuote","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"contract IMaverickV2Pool","name":"ethToQuotePool","type":"address"},{"internalType":"uint256","name":"amountEthIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"},{"internalType":"address","name":"referer","type":"address"},{"internalType":"address","name":"raffleRecipient","type":"address"}],"name":"buyTokenTwoHopSpecifyRaffleRecipient","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"entropy","outputs":[{"internalType":"contract IEntropy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeRateD18","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeRates","outputs":[{"internalType":"uint64","name":"proportionToRaffleVaultD18","type":"uint64"},{"internalType":"uint64","name":"proportionToRefererD18","type":"uint64"},{"internalType":"uint64","name":"proportionToVotingDistributorD18","type":"uint64"},{"internalType":"uint64","name":"proportionToCreatorD18","type":"uint64"},{"internalType":"uint64","name":"proportionToVoterD18","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeVault","outputs":[{"internalType":"contract IFeeVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPrizesAndThresholdsAndBonus","outputs":[{"internalType":"uint24[8]","name":"thresholds","type":"uint24[8]"},{"internalType":"uint64[8]","name":"prizes","type":"uint64[8]"},{"internalType":"uint8","name":"boxBonus","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"quoteToken","type":"address"}],"name":"getTopToken","outputs":[{"internalType":"contract IERC20","name":"topToken","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolFactory","outputs":[{"internalType":"contract IMaverickV2Factory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"quote","type":"address"}],"name":"quoteToFactory","outputs":[{"internalType":"contract ILaunchFactory","name":"factory","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"quote","type":"address"}],"name":"quoteToRaffleVault","outputs":[{"internalType":"contract IRaffleVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"quote","type":"address"}],"name":"quoteToTrackers","outputs":[{"internalType":"contract IHistoricalBalanceNonTransferableERC20","name":"sell","type":"address"},{"internalType":"contract IHistoricalBalanceNonTransferableERC20","name":"buy","type":"address"},{"internalType":"contract IHistoricalBalanceNonTransferableERC20","name":"token","type":"address"},{"internalType":"contract IHistoricalBalanceNonTransferableERC20","name":"creator","type":"address"},{"internalType":"contract IHistoricalBalanceNonTransferableERC20","name":"referer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"quote","type":"address"}],"name":"quoteToVotingDistributor","outputs":[{"internalType":"contract IVotingDistributor","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quoter","outputs":[{"internalType":"contract IMaverickV2Quoter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"referralRegistry","outputs":[{"internalType":"contract IReferralRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ILaunchFactory","name":"factory","type":"address"},{"internalType":"uint256","name":"_balancePerLootBox","type":"uint256"}],"name":"registerQuoteToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amountTokenIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"},{"internalType":"address","name":"referer","type":"address"}],"name":"sellToken","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amountTokenIn","type":"uint256"}],"name":"sellTokenQuote","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amountTokenIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"},{"internalType":"address","name":"referer","type":"address"},{"internalType":"address","name":"raffleRecipient","type":"address"}],"name":"sellTokenSpecifyRaffleRecipient","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"contract IMaverickV2Pool","name":"ethToQuotePool","type":"address"},{"internalType":"uint256","name":"amountTokenIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"},{"internalType":"address","name":"referer","type":"address"}],"name":"sellTokenTwoHop","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"contract IMaverickV2Pool","name":"ethToQuotePool","type":"address"},{"internalType":"uint256","name":"amountTokenIn","type":"uint256"}],"name":"sellTokenTwoHopQuote","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"contract IMaverickV2Pool","name":"ethToQuotePool","type":"address"},{"internalType":"uint256","name":"amountTokenIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"},{"internalType":"address","name":"referer","type":"address"},{"internalType":"address","name":"raffleRecipient","type":"address"}],"name":"sellTokenTwoHopSpecifyRaffleRecipient","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"contract IMaverickV2Pool","name":"pool","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"quoteToken","type":"address"},{"internalType":"uint256","name":"_balancePerLootBox","type":"uint256"}],"name":"setBalancePerLootBox","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IEntropy","name":"_entropy","type":"address"}],"name":"setEntropy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_feeRateD18","type":"uint64"}],"name":"setFeeRateD18","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint64","name":"proportionToRaffleVaultD18","type":"uint64"},{"internalType":"uint64","name":"proportionToRefererD18","type":"uint64"},{"internalType":"uint64","name":"proportionToVotingDistributorD18","type":"uint64"},{"internalType":"uint64","name":"proportionToCreatorD18","type":"uint64"},{"internalType":"uint64","name":"proportionToVoterD18","type":"uint64"}],"internalType":"struct ISwapper.FeeRates","name":"_feeRates","type":"tuple"}],"name":"setFeeRates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint24[8]","name":"thresholds","type":"uint24[8]"},{"internalType":"uint64[8]","name":"prizes","type":"uint64[8]"},{"internalType":"uint8","name":"boxBonus","type":"uint8"}],"name":"setPrizesAndThresholdsAndBonus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_protocolRecipient","type":"address"}],"name":"setProtocolRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"quoteToken","type":"address"},{"internalType":"contract IRaffleVault","name":"_raffle","type":"address"}],"name":"setRaffleVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IReferralRegistry","name":"_registry","type":"address"}],"name":"setReferralRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"quoteToken","type":"address"},{"internalType":"contract IVotingDistributor","name":"_voting","type":"address"}],"name":"setVotingDistributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"contract IWETH9","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]