// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// MM MM
// MM ^ ##### ##### #### # ###### #### ##### # # # # # # #### MM
// MM | # # # # # # # # # # # # # ## # # # # MM
// MM | # # # # # # # ##### # # # # # # # #### #### MM
// MM ^ ##### ##### # # # # # # # # # # # # # # MM
// MM | # # # # # # # # # # # # # # ## # # # # MM
// MM | # # # #### #### ###### #### # ###### # # # # # #### MM
// MM ^ MM
// MM | MM
// MM |________ Click 'Read Contract', then select: MM
// MM * _1___website MM
// MM * _2___twitter (or X...) MM
// MM * _3___telegram MM
// MM * _4___discord MM
// MM MM
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWNNWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXKXWMMMMM
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMN0dccdKMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMN0d:,;dXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWKxc,.,xNMMMM
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXOo;.. .oWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWNOo;.. .kMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMN0d:.. ;KMMMM
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXkl,. .lNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXkl,.. .kMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNOo;.. ;KMMMM
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWKxc'. .lNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXkl,. .kMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXkl,. ;KMMMM
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMN0d:'. .lNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWKxc'. .kMMMMMMMMMMMMMMMMMMMMMMMMMMMMWKxc'. ;KMMMM
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMN0d:.. .lNMMMMMMMMMMMMMMMMMMMMMMMMMMN0d:.. .kMMMMMMMMMMMMMMMMMMMMMMMMMWKxc'. ;KMMMM
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMWXOo;.. .lNMMMMMMMMMMMMMMMMMMMMMMNOxo;.. .kMMMMMMMMMMMMMMMMMMMMMMN0d:.. ;KMMMM
// MMMMMMMMMMMMMMMMMMMMMMMMMWXkl,. .lNMMMMMMMMMMMMMMMMMMWXOo,... .kMMMMMMMMMMMMMMMMMMMNOo;.. ;KMMMM
// MMMMMMMMMMMMMMMMMMMMMMWKxc'. .lNMMMMMMMMMMMMMMMWXkl,. .kMMMMMMMMMMMMMMMWXkl,. ;KMMMM
// MMMMMMMMMMMMMMMMMMMW0d:'. .lNMMMMMMMMMMMMWKxc'. .kMMMMMMMMMMMMWKkc'. ;KMMMM
// MMMMMMMMMMMMMMMMN0d:.. .cXMMMMMMMMMN0d:.. .oWMMMMMMMMWKxc'. ;KMMMM
// MMMMMMMMMMMMWNOo;.. .lKWMMMWNOo;.. .oKWMMWN0d:.. ;KMMMM
// MMMMMMMMMWXkl,. .'codol,.. ..;clc,.. ;KMMMM
// MMMMMMWKxc'. :XMMMM
// MMMMXxc'. 'kWMMMM
// MMW0:. ..:OWMMMMM
// MMK:. ..;o0NMMMMMMM
// MMO' ..... ..''.. ..:d0NMMMMMMMMMM
// MMO' ..,lxO0Oxc.. .'cx0XXKkc.. .'cxKWMMMMMMMMMMMMM
// MMO' ..;oOXWMMMMMWO, ..,lkXWMMMMMMWx. .,lkXWMMMMMMMMMMMMMMMM
// MMO' ..:d0NMMMMMMMMMMNo. ..;oONWMMMMMMMMMMK; .,oOXWMMMMMMMMMMMMMMMMMMM
// MMO' ..:d0NMMMMMMMMMMMMMWo. ..:d0NMMMMMMMMMMMMMMX: ..;oONMMMMMMMMMMMMMMMMMMMMMMM
// MMO' .'cxKWMMMMMMMMMMMMMMMMWo. .';cxKWMMMMMMMMMMMMMMMMMX: ..:d0NMMMMMMMMMMMMMMMMMMMMMMMMMM
// MMO' .,lkXWMMMMMMMMMMMMMMMMMMMWo. .,ckKNWMMMMMMMMMMMMMMMMMMMMX: .'cxKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// MMO' ..;oOXMMMMMMMMMMMMMMMMMMMMMMMWo. ..,lkXWMMMMMMMMMMMMMMMMMMMMMMMMX: .,lkXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// MMO' ..:d0NMMMMMMMMMMMMMMMMMMMMMMMMMMWo. ..;oONWMMMMMMMMMMMMMMMMMMMMMMMMMMMX: ..,oOXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// MMO' ..:d0NMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWo. ..:d0NMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMX: ..;oONMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// MMO' .'cxKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWo. .'cxKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMX: ..:d0NMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// MMO' .,lkXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWo. .'ckKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMX: .'cxKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// MM0, ..;oOXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWk'. .,lkXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNd...,lkXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// MMW0dld0NMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMW0xxONWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWKO0XWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// MMMWX00000XWMMMMMMWX00000KWMNK000000000000KWNK0000000000000KXWMMWX0000KNMMMMMMMNKK00000000KKNWMMMMMWX000000000KKXWMMMMMMMMMWXK0OO0KXWMMMMMMNK000000000KXNMMMMMMM
// MMMK:..''.;OMMMMMMK:..'..;0M0;............:00;..............oNMWO;.''..lXMMMMMWd'..........',:d0WMMNl...........':dKMMMMNOo;'......';oONMMMO;..........';lOWMMMM
// MMMK; .;;..cXMMMMNo..,;. 'OMO' .,looooooookXXxooooc. .,looodOWM0;..:o' .oNMMMMWo.. .:oooooo:'. .lXMXc. .cdddddo:. .;0MW0:...;lddddl;...:OWMO' .,loooool,. .dNMMM
// MMMK; :d, .xWMMMO, .dc. 'OMO' .lNMMMMMMMMMMMMMMMMO' .lNMMMMMMXc. 'kNo. .xWMMMWo.. .kMMMMMMWKl. .lNXc. ,0MMMMMMNo. .xWO,..;kNMMMMMMNk;. 'kWO' .lNMMMMMM0, ;KMMM
// MMMK; :0o. ;KMMXc..cKl. 'OMO' .'looooooo0MMMMMMMMO' .lNMMMMMNo. .dWMK:. 'OMMMWo.. .kMMMMMMMMX:. ,OXc. 'xXKXXK0d,..:0Nl. 'kMMMMMMMMMMO' .cXO' .cKXXXXX0o. .lXMMM
// MMMK; :XK: .oNWx. ,ONl. 'OMO' .''''''',xWMMMMMMMO' .lNMMMMWx. .:0NNNk' .;0MMWo.. .kMMMMMMMMNl. 'OXc. ..........:xXMXc. ,0MMMMMMMMMM0; :XO' .'''''....'oXMMMM
// MMMK; :XWx. ,OK:..oNNl. 'OMO' .cKXXXXXXXWMMMMMMMMO' .lNMMMWO, ..,,,,,. .cXMWo.. .kMMMMMMMWk, .:KXc. .:ooool:..;oKMWd. .lXMMMMMMMMNo. .oWO' .,looooooxOXWMMMMM
// MMMK; :KMXl..co..:KMNl. 'OMO' .:0KKKKKKKKXWMMMMMMO' .lNMMMK:. .:ccccccc,. .oNWo.. .oKKKKK0kl'..,OWXc. ,0MMMMMNx. .cXMXo. .;d0XXXX0x:. .lXMO' .lNMMMMMMMMMMMMMMM
// MMMK; :XMMO, ....kWMNl. 'OMO' ..........:KMMMMMMO' .lNMMXc. .oNMMMMMMMK:. .xNo.. ...........,oKWMXc. ,0MMMMMMXc. .dNMWOc'....''....'cONMMk' .lNMMMMMMMMMMMMMMM
// MMMNkookNMMWOooookNMMWOooxXMXxooooooooooooxXMMMMMMXxooOWMMKdooxXMMMMMMMMM0dookN0doloooooooodx0NWMMMWOooxXMMMMMMMKdookNMMMWXOxolcclodOXWMMMMXdooOWMMMMMMMMMMMMMMM
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// SPDX-License-Identifier: BUSL 1.0
// Metadrop Contracts (v2.1.0)
// File @openzeppelin/contracts/token/ERC20/IERC20.sol@v4.9.1
//
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @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 amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` 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 amount) external returns (bool);
}
// File @openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol@v4.9.1
//
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
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);
}
// File @openzeppelin/contracts/utils/structs/EnumerableSet.sol@v4.9.1
//
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}
// File @openzeppelin/contracts/utils/structs/EnumerableMap.sol@v4.9.1
//
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableMap.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing an enumerable variant of Solidity's
* https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
* type.
*
* Maps have the following properties:
*
* - Entries are added, removed, and checked for existence in constant time
* (O(1)).
* - Entries are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableMap for EnumerableMap.UintToAddressMap;
*
* // Declare a set state variable
* EnumerableMap.UintToAddressMap private myMap;
* }
* ```
*
* The following map types are supported:
*
* - `uint256 -> address` (`UintToAddressMap`) since v3.0.0
* - `address -> uint256` (`AddressToUintMap`) since v4.6.0
* - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0
* - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0
* - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableMap.
* ====
*/
library EnumerableMap {
using EnumerableSet for EnumerableSet.Bytes32Set;
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Map type with
// bytes32 keys and values.
// The Map implementation uses private functions, and user-facing
// implementations (such as Uint256ToAddressMap) are just wrappers around
// the underlying Map.
// This means that we can only create new EnumerableMaps for types that fit
// in bytes32.
struct Bytes32ToBytes32Map {
// Storage of keys
EnumerableSet.Bytes32Set _keys;
mapping(bytes32 => bytes32) _values;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) {
map._values[key] = value;
return map._keys.add(key);
}
/**
* @dev Removes a key-value pair from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) {
delete map._values[key];
return map._keys.remove(key);
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) {
return map._keys.contains(key);
}
/**
* @dev Returns the number of key-value pairs in the map. O(1).
*/
function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) {
return map._keys.length();
}
/**
* @dev Returns the key-value pair stored at position `index` in the map. O(1).
*
* Note that there are no guarantees on the ordering of entries inside the
* array, and it may change when more entries are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) {
bytes32 key = map._keys.at(index);
return (key, map._values[key]);
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) {
bytes32 value = map._values[key];
if (value == bytes32(0)) {
return (contains(map, key), bytes32(0));
} else {
return (true, value);
}
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) {
bytes32 value = map._values[key];
require(value != 0 || contains(map, key), "EnumerableMap: nonexistent key");
return value;
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
Bytes32ToBytes32Map storage map,
bytes32 key,
string memory errorMessage
) internal view returns (bytes32) {
bytes32 value = map._values[key];
require(value != 0 || contains(map, key), errorMessage);
return value;
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) {
return map._keys.values();
}
// UintToUintMap
struct UintToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) {
return set(map._inner, bytes32(key), bytes32(value));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(UintToUintMap storage map, uint256 key) internal returns (bool) {
return remove(map._inner, bytes32(key));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) {
return contains(map._inner, bytes32(key));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(UintToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (uint256(key), uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(key)));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(UintToUintMap storage map, uint256 key, string memory errorMessage) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(key), errorMessage));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(UintToUintMap storage map) internal view returns (uint256[] memory) {
bytes32[] memory store = keys(map._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintToAddressMap
struct UintToAddressMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {
return set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
return remove(map._inner, bytes32(key));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
return contains(map._inner, bytes32(key));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(UintToAddressMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (uint256(key), address(uint160(uint256(value))));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
return (success, address(uint160(uint256(value))));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
return address(uint160(uint256(get(map._inner, bytes32(key)))));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
UintToAddressMap storage map,
uint256 key,
string memory errorMessage
) internal view returns (address) {
return address(uint160(uint256(get(map._inner, bytes32(key), errorMessage))));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) {
bytes32[] memory store = keys(map._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressToUintMap
struct AddressToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) {
return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(AddressToUintMap storage map, address key) internal returns (bool) {
return remove(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(AddressToUintMap storage map, address key) internal view returns (bool) {
return contains(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(AddressToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (address(uint160(uint256(key))), uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key))));
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(AddressToUintMap storage map, address key) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(uint256(uint160(key)))));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
AddressToUintMap storage map,
address key,
string memory errorMessage
) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(uint256(uint160(key))), errorMessage));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(AddressToUintMap storage map) internal view returns (address[] memory) {
bytes32[] memory store = keys(map._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// Bytes32ToUintMap
struct Bytes32ToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) {
return set(map._inner, key, bytes32(value));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) {
return remove(map._inner, key);
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) {
return contains(map._inner, key);
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(Bytes32ToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (key, uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, key);
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) {
return uint256(get(map._inner, key));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
Bytes32ToUintMap storage map,
bytes32 key,
string memory errorMessage
) internal view returns (uint256) {
return uint256(get(map._inner, key, errorMessage));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) {
bytes32[] memory store = keys(map._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}
// File @uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router01.sol@v1.1.0-beta.0
pragma solidity >=0.6.2;
interface IUniswapV2Router01 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external payable returns (uint amountToken, uint amountETH, uint liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountA, uint amountB);
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountToken, uint amountETH);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}
// File @uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol@v1.1.0-beta.0
pragma solidity >=0.6.2;
interface IUniswapV2Router02 is IUniswapV2Router01 {
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountETH);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
}
// File @openzeppelin/contracts/utils/Context.sol@v4.9.1
//
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @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;
}
}
// File @uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol@v1.0.0
pragma solidity >=0.5.0;
interface IUniswapV2Factory {
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function getPair(address tokenA, address tokenB) external view returns (address pair);
function allPairs(uint) external view returns (address pair);
function allPairsLength() external view returns (uint);
function createPair(address tokenA, address tokenB) external returns (address pair);
function setFeeTo(address) external;
function setFeeToSetter(address) external;
}
// File contracts/ERC20FactoryV1/ERC20/IERC20ConfigByMetadropV1.sol
//
// Metadrop Contracts (v2.1.0)
/**
*
* @title IERC20ByMetadrop.sol. Interface for metadrop ERC20 standard
*
* @author metadrop https://metadrop.com/
*
*/
pragma solidity 0.8.19;
interface IERC20ConfigByMetadropV1 {
struct ERC20Config {
bytes baseParameters;
bytes supplyParameters;
bytes taxParameters;
}
struct ERC20BaseParameters {
string name;
string symbol;
string website;
string twitter;
string telegram;
string otherSocials;
}
struct ERC20SupplyParameters {
uint256 maxSupply;
uint256 lpSupply;
uint256 projectSupply;
uint256 maxTokensPerWallet;
uint256 maxTokensPerTxn;
uint256 lpLockupInDays;
bool addLiquidityOnCreate;
address projectTreasury;
address metadropTreasury;
}
struct ERC20TaxParameters {
uint256 projectBuyTaxBasisPoints;
uint256 projectSellTaxBasisPoints;
uint256 maxProjectBuyTaxBasisPoints;
uint256 maxProjectSellTaxBasisPoints;
uint256 taxSwapThresholdBasisPoints;
uint256 metadropBuyTaxBasisPoints;
uint256 metadropSellTaxBasisPoints;
uint256 maxMetadropBuyTaxBasisPoints;
uint256 maxMetadropSellTaxBasisPoints;
uint256 metadropTaxPeriodInDays;
}
}
// File contracts/Global/IConfigStructures.sol
//
// Metadrop Contracts (v2.1.0)
/**
*
* @title IConfigStructures.sol. Interface for common config structures used accross the platform
*
* @author metadrop https://metadrop.com/
*
*/
pragma solidity 0.8.19;
interface IConfigStructures {
enum DropStatus {
approved,
deployed,
cancelled
}
enum TemplateStatus {
live,
terminated
}
// The current status of the mint:
// - notEnabled: This type of mint is not part of this drop
// - notYetOpen: This type of mint is part of the drop, but it hasn't started yet
// - open: it's ready for ya, get in there.
// - finished: been and gone.
// - unknown: theoretically impossible.
enum MintStatus {
notEnabled,
notYetOpen,
open,
finished,
unknown
}
struct SubListConfig {
uint256 start;
uint256 end;
uint256 phaseMaxSupply;
}
struct PrimarySaleModuleInstance {
address instanceAddress;
string instanceDescription;
}
struct NFTModuleConfig {
uint256 templateId;
bytes configData;
bytes vestingData;
}
struct PrimarySaleModuleConfig {
uint256 templateId;
bytes configData;
}
struct ProjectBeneficiary {
address payable payeeAddress;
uint256 payeeShares;
}
struct VestingConfig {
uint256 start;
uint256 projectUpFrontShare;
uint256 projectVestedShare;
uint256 vestingPeriodInDays;
uint256 vestingCliff;
ProjectBeneficiary[] projectPayees;
}
struct RoyaltySplitterModuleConfig {
uint256 templateId;
bytes configData;
}
struct InLifeModuleConfig {
uint256 templateId;
bytes configData;
}
struct InLifeModules {
InLifeModuleConfig[] modules;
}
struct NFTConfig {
uint256 supply;
string name;
string symbol;
bytes32 positionProof;
bool includePriorPhasesInMintTracking;
bool singleMetadataCollection;
uint256 reservedAllocation;
uint256 assistanceRequestWindowInSeconds;
}
struct Template {
TemplateStatus status;
uint16 templateNumber;
uint32 loadedDate;
address payable templateAddress;
string templateDescription;
}
struct RoyaltyDetails {
address newRoyaltyPaymentSplitterInstance;
uint96 royaltyFromSalesInBasisPoints;
}
struct SignedDropMessageDetails {
uint256 messageTimeStamp;
bytes32 messageHash;
bytes messageSignature;
}
}
// File contracts/ERC20FactoryV1/ERC20/IERC20ByMetadropV1.sol
//
// Metadrop Contracts (v2.1.0)
pragma solidity 0.8.19;
/**
* @dev Metadrop core ERC-20 contract, interface
*/
interface IERC20ByMetadropV1 is
IERC20,
IERC20ConfigByMetadropV1,
IERC20Metadata,
IConfigStructures
{
struct SocialLinks {
string linkType;
string link;
}
event AutoSwapThresholdUpdated(uint256 oldThreshold, uint256 newThreshold);
event ProjectTaxBasisPointsChanged(
uint256 oldBuyBasisPoints,
uint256 newBuyBasisPoints,
uint256 oldSellBasisPoints,
uint256 newSellBasisPoints
);
event MetadropTaxBasisPointsChanged(
uint256 oldBuyBasisPoints,
uint256 newBuyBasisPoints,
uint256 oldSellBasisPoints,
uint256 newSellBasisPoints
);
event LiquidityPoolCreated(address addedPool);
event LiquidityPoolAdded(address addedPool);
event LiquidityPoolRemoved(address removedPool);
event InitialLiquidityAdded(uint256 tokenA, uint256 tokenB, uint256 lpToken);
event LiquidityLocked();
event RevenueAutoSwap();
event SetLimitsEnabled(bool enabled);
event TreasuryUpdated(address treasury);
event UnlimitedAddressAdded(address addedUnlimted);
event UnlimitedAddressRemoved(address removedUnlimted);
/**
* @dev function {addInitialLiquidity}
*
* Add initial liquidity to the uniswap pair
*
* @param lockerFee_ The locker fee in wei. This must match the required fee from the external locker contract.
*/
function addInitialLiquidity(uint256 lockerFee_) external payable;
/**
* @dev function {isLiquidityPool}
*
* Return if an address is a liquidity pool
*
* @param queryAddress_ The address being queried
* @return bool The address is / isn't a liquidity pool
*/
function isLiquidityPool(address queryAddress_) external view returns (bool);
/**
* @dev function {addLiquidityPool} onlyTaxAdmin
*
* Allows the tax admin to add a liquidity pool to the pool enumerable set
*
* @param newLiquidityPool_ The address of the new liquidity pool
*/
function addLiquidityPool(address newLiquidityPool_) external;
/**
* @dev function {removeLiquidityPool} onlyTaxAdmin
*
* Allows the tax admin to remove a liquidity pool
*
* @param removedLiquidityPool_ The address of the old removed liquidity pool
*/
function removeLiquidityPool(address removedLiquidityPool_) external;
/**
* @dev function {isUnlimited}
*
* Return if an address is unlimited (is not subject to per txn and per wallet limits)
*
* @param queryAddress_ The address being queried
* @return bool The address is / isn't unlimited
*/
function isUnlimited(address queryAddress_) external view returns (bool);
/**
* @dev function {addUnlimited} onlyTaxAdmin
*
* Allows the tax admin to add an unlimited address
*
* @param newUnlimited_ The address of the new unlimited address
*/
function addUnlimited(address newUnlimited_) external;
/**
* @dev function {removeUnlimited} onlyTaxAdmin
*
* Allows the tax admin to remove an unlimited address
*
* @param removedUnlimited_ The address of the old removed unlimited address
*/
function removeUnlimited(address removedUnlimited_) external;
/**
* @dev function {setLimitsEnabledStatus} onlyTaxAdmin
*
* Allows the tax admin to enable / disable tokens per txn and per holder validation.
*
* @param enabled_ Should limits be on?
*/
function setLimitsEnabledStatus(bool enabled_) external;
/**
* @dev function {setProjectTreasury} onlyTaxAdmin
*
* Allows the tax admin to set the treasury address
*
* @param projectTreasury_ New treasury address
*/
function setProjectTreasury(address projectTreasury_) external;
/**
* @dev function {setSwapThresholdBasisPoints} onlyTaxAdmin
*
* Allows the tax admin to set the autoswap threshold
*
* @param swapThresholdBasisPoints_ New swap threshold in basis points
*/
function setSwapThresholdBasisPoints(
uint16 swapThresholdBasisPoints_
) external;
/**
* @dev function {withdrawETH} onlyOwner
*
* Allows the owner to withdraw ETH
*
* @param amount_ The amount to withdraw
*/
function withdrawETH(uint256 amount_) external;
/**
* @dev function {withdrawERC20} onlyOwner
*
* A withdraw function to allow ERC20s to be withdrawn.
*
* @param token_ The address of the token being withdrawn
* @param amount_ The amount to withdraw
*/
function withdrawERC20(IERC20 token_, uint256 amount_) external;
/**
* @dev function {setProjectTaxRates} onlyTaxAdmin
*
* Change the tax rates, subject to max rate
*
* @param newProjectBuyTaxBasisPoints_ The new buy tax rate
* @param newProjectSellTaxBasisPoints_ The new sell tax rate
*/
function setProjectTaxRates(
uint16 newProjectBuyTaxBasisPoints_,
uint16 newProjectSellTaxBasisPoints_
) external;
/**
* @dev function {setMetadropTaxRates} onlyTaxAdmin
*
* Change the tax rates, subject to max rate and minimum tax period.
*
* @param newMetadropBuyTaxBasisPoints_ The new buy tax rate
* @param newMetadropSellTaxBasisPoints_ The new sell tax rate
*/
function setMetadropTaxRates(
uint16 newMetadropBuyTaxBasisPoints_,
uint16 newMetadropSellTaxBasisPoints_
) external;
}
// File contracts/Global/IErrors.sol
//
// Metadrop Contracts (v2.1.0)
/**
*
* @title IErrors.sol. Interface for error definitions used across the platform
*
* @author metadrop https://metadrop.com/
*
*/
pragma solidity 0.8.19;
interface IErrors {
enum BondingCurveErrorType {
OK, // No error
INVALID_NUMITEMS, // The numItem value is 0
SPOT_PRICE_OVERFLOW // The updated spot price doesn't fit into 128 bits
}
error AdapterParamsMustBeEmpty(); // The adapter parameters on this LZ call must be empty.
error AddressAlreadySet(); // The address being set can only be set once, and is already non-0.
error AllowanceDecreasedBelowZero(); // You cannot decrease the allowance below zero.
error AlreadyInitialised(); // The contract is already initialised: it cannot be initialised twice!
error ApprovalCallerNotOwnerNorApproved(); // The caller must own the token or be an approved operator.
error ApproveFromTheZeroAddress(); // Approval cannot be called from the zero address (indeed, how have you??).
error ApproveToTheZeroAddress(); // Approval cannot be given to the zero address.
error ApprovalQueryForNonexistentToken(); // The token does not exist.
error AuctionStatusIsNotEnded(); // Throw if the action required the auction to be closed, and it isn't.
error AuctionStatusIsNotOpen(); // Throw if the action requires the auction to be open, and it isn't.
error AuxCallFailed(
address[] modules,
uint256 value,
bytes data,
uint256 txGas
); // An auxilliary call from the drop factory failed.
error BalanceQueryForZeroAddress(); // Cannot query the balance for the zero address.
error BidMustBeBelowTheFloorWhenReducingQuantity(); // Only bids that are below the floor can reduce the quantity of the bid.
error BidMustBeBelowTheFloorForRefundDuringAuction(); // Only bids that are below the floor can be refunded during the auction.
error BondingCurveError(BondingCurveErrorType error); // An error of the type specified has occured in bonding curve processing.
error BurnExceedsBalance(); // The amount you have selected to burn exceeds the addresses balance.
error BurnFromTheZeroAddress(); // Tokens cannot be burned from the zero address. (Also, how have you called this!?!)
error CallerIsNotFactory(); // The caller of this function must match the factory address in storage.
error CallerIsNotFactoryOrProjectOwner(); // The caller of this function must match the factory address OR project owner address.
error CallerIsNotTheOwner(); // The caller is not the owner of this contract.
error CallerIsNotTheTaxAdmin(); // The caller is not the tax admin of this contract.
error CallerMustBeLzApp(); // The caller must be an LZ application.
error CallerIsNotPlatformAdmin(address caller); // The caller of this function must be part of the platformAdmin group.
error CallerIsNotSuperAdmin(address caller); // The caller of this function must match the superAdmin address in storage.
error CannotSetNewOwnerToTheZeroAddress(); // You can't set the owner of this contract to the zero address (address(0)).
error CannotSetToZeroAddress(); // The corresponding address cannot be set to the zero address (address(0)).
error CannotSetNewTaxAdminToTheZeroAddress(); // Cannot transfer the tax admin to the zero address (address(0)).
error CollectionAlreadyRevealed(); // The collection is already revealed; you cannot call reveal again.
error ContractIsPaused(); // The call requires the contract to be unpaused, and it is paused.
error ContractIsNotPaused(); // The call required the contract to be paused, and it is NOT paused.
error DecreasedAllowanceBelowZero(); // The request would decrease the allowance below zero, and that is not allowed.
error DestinationIsNotTrustedSource(); // The destination that is being called through LZ has not been set as trusted.
error GasLimitIsTooLow(); // The gas limit for the LayerZero call is too low.
error IncorrectConfirmationValue(); // You need to enter the right confirmation value to call this funtion (usually 69420).
error IncorrectPayment(); // The function call did not include passing the correct payment.
error InitialLiquidityAlreadyAdded(); // Initial liquidity has already been added. You can't do it again.
error InsufficientAllowance(); // There is not a high enough allowance for this operation.
error InvalidAdapterParams(); // The current adapter params for LayerZero on this contract won't work :(.
error InvalidAddress(); // An address being processed in the function is not valid.
error InvalidEndpointCaller(); // The calling address is not a valid LZ endpoint. The LZ endpoint was set at contract creation
// and cannot be altered after. Check the address LZ endpoint address on the contract.
error InvalidMinGas(); // The minimum gas setting for LZ in invalid.
error InvalidOracleSignature(); // The signature provided with the contract call is not valid, either in format or signer.
error InvalidPayload(); // The LZ payload is invalid
error InvalidReceiver(); // The address used as a target for funds is not valid.
error InvalidSourceSendingContract(); // The LZ message is being related from a source contract on another chain that is NOT trusted.
error InvalidTotalShares(); // Total shares must equal 100 percent in basis points.
error ListLengthMismatch(); // Two or more lists were compared and they did not match length.
error LiquidityPoolMustBeAContractAddress(); // Cannot add a non-contract as a liquidity pool.
error LiquidityPoolCannotBeAddressZero(); // Cannot add a liquidity pool from the zero address.
error LPLockUpMustFitUint96(); // LP lockup is held in a uint96, so must fit.
error NoTrustedPathRecord(); // LZ needs a trusted path record for this to work. What's that, you ask?
error MaxBidQuantityIs255(); // Validation: as we use a uint8 array to track bid positions the max bid quantity is 255.
error MaxPublicMintAllowanceExceeded(
uint256 requested,
uint256 alreadyMinted,
uint256 maxAllowance
); // The calling address has requested a quantity that would exceed the max allowance.
error MaxSupplyTooHigh(); // Max supply must fit in a uint128.
error MaxTokensPerWalletExceeded(); // The transfer would exceed the max tokens per wallet limit.
error MaxTokensPerTxnExceeded(); // The transfer would exceed the max tokens per transaction limit.
error MetadataIsLocked(); // The metadata on this contract is locked; it cannot be altered!
error MetadropFactoryOnlyOncePerReveal(); // This function can only be called (a) by the factory and, (b) just one time!
error MetadropModulesOnly(); // Can only be called from a metadrop contract.
error MetadropOracleCannotBeAddressZero(); // The metadrop Oracle cannot be the zero address (address(0)).
error MinGasLimitNotSet(); // The minimum gas limit for LayerZero has not been set.
error MintERC2309QuantityExceedsLimit(); // The `quantity` minted with ERC2309 exceeds the safety limit.
error MintingIsClosedForever(); // Minting is, as the error suggests, so over (and locked forever).
error MintToZeroAddress(); // Cannot mint to the zero address.
error MintZeroQuantity(); // The quantity of tokens minted must be more than zero.
error NewBuyTaxBasisPointsExceedsMaximum(); // Project owner trying to set the tax rate too high.
error NewSellTaxBasisPointsExceedsMaximum(); // Project owner trying to set the tax rate too high.
error NoETHForLiquidityPair(); // No ETH has been provided for the liquidity pair.
error TaxPeriodStillInForce(); // The minimum tax period has not yet expired.
error NoPaymentDue(); // No payment is due for this address.
error NoRefundForCaller(); // Error thrown when the calling address has no refund owed.
error NoStoredMessage(); // There is no stored message matching the passed parameters.
error NoTokenForLiquidityPair(); // There is no token to add to the LP.
error OperationDidNotSucceed(); // The operation failed (vague much?).
error OracleSignatureHasExpired(); // A signature has been provided but it is too old.
error OwnershipNotInitializedForExtraData(); // The `extraData` cannot be set on an uninitialized ownership slot.
error OwnerQueryForNonexistentToken(); // The token does not exist.
error ParametersDoNotMatchSignedMessage(); // The parameters passed with the signed message do not match the message itself.
error PassedConfigDoesNotMatchApproved(); // The config provided on the call does not match the approved config.
error PauseCutOffHasPassed(); // The time period in which we can pause has passed; this contract can no longer be paused.
error PaymentMustCoverPerMintFee(); // The payment passed must at least cover the per mint fee for the quantity requested.
error PermitDidNotSucceed(); // The safeERC20 permit failed.
error PlatformAdminCannotBeAddressZero(); // We cannot use the zero address (address(0)) as a platformAdmin.
error PlatformTreasuryCannotBeAddressZero(); // The treasury address cannot be set to the zero address.
error ProjectOwnerCannotBeAddressZero(); // The project owner has to be a non zero address.
error ProofInvalid(); // The provided proof is not valid with the provided arguments.
error QuantityExceedsRemainingCollectionSupply(); // The requested quantity would breach the collection supply.
error QuantityExceedsRemainingPhaseSupply(); // The requested quantity would breach the phase supply.
error QuantityExceedsMaxPossibleCollectionSupply(); // The requested quantity would breach the maximum trackable supply
error ReferralIdAlreadyUsed(); // This referral ID has already been used; they are one use only.
error RequestingMoreThanRemainingAllocation(
uint256 previouslyMinted,
uint256 requested,
uint256 remainingAllocation
); // Number of tokens requested for this mint exceeds the remaining allocation (taking the
// original allocation from the list and deducting minted tokens).
error RoyaltyFeeWillExceedSalePrice(); // The ERC2981 royalty specified will exceed the sale price.
error ShareTotalCannotBeZero(); // The total of all the shares cannot be nothing.
error SliceOutOfBounds(); // The bytes slice operation was out of bounds.
error SliceOverflow(); // The bytes slice operation overlowed.
error SuperAdminCannotBeAddressZero(); // The superAdmin cannot be the sero address (address(0)).
error SupplyTotalMismatch(); // The sum of the team supply and lp supply does not match.
error SupportWindowIsNotOpen(); // The project owner has not requested support within the support request expiry window.
error TaxFreeAddressCannotBeAddressZero(); // A tax free address cannot be address(0)
error TemplateCannotBeAddressZero(); // The address for a template cannot be address zero (address(0)).
error TemplateNotFound(); // There is no template that matches the passed template Id.
error ThisMintIsClosed(); // It's over (well, this mint is, anyway).
error TotalSharesMustMatchDenominator(); // The total of all shares must equal the denominator value.
error TransferAmountExceedsBalance(); // The transfer amount exceeds the accounts available balance.
error TransferCallerNotOwnerNorApproved(); // The caller must own the token or be an approved operator.
error TransferFailed(); // The transfer has failed.
error TransferFromIncorrectOwner(); // The token must be owned by `from`.
error TransferToNonERC721ReceiverImplementer(); // Cannot safely transfer to a contract that does not implement the ERC721Receiver interface.
error TransferFromZeroAddress(); // Cannot transfer from the zero address. Indeed, this surely is impossible, and likely a waste to check??
error TransferToZeroAddress(); // Cannot transfer to the zero address.
error UnrecognisedVRFMode(); // Currently supported VRF modes are 0: chainlink and 1: arrng
error URIQueryForNonexistentToken(); // The token does not exist.
error ValueExceedsMaximum(); // The value sent exceeds the maximum allowed (super useful explanation huh?).
error VRFCoordinatorCannotBeAddressZero(); // The VRF coordinator cannot be the zero address (address(0)).
}
// File contracts/ERC20FactoryV1/ERC20Factory/IERC20FactoryByMetadropV1.sol
//
// Metadrop Contracts (v2.1.0)
pragma solidity 0.8.19;
/**
* @dev Metadrop ERC-20 factory, interface
*/
interface IERC20FactoryByMetadropV1 is
IConfigStructures,
IErrors,
IERC20ConfigByMetadropV1
{
event ERC20Created(
string metaId,
address indexed deployer,
address contractInstance,
string symbol,
string name
);
/**
* @dev function {setMetadropOracleAddress} onlyPlatformAdmin
*
* Set the metadrop trusted oracle address
*
* @param metadropOracleAddress_ Trusted metadrop oracle address
*/
function setMetadropOracleAddress(address metadropOracleAddress_) external;
/**
* @dev function {setMessageValidityInSeconds} onlyPlatformAdmin
*
* Set the validity period of signed messages
*
* @param messageValidityInSeconds_ Validity period in seconds for messages signed by the trusted oracle
*/
function setMessageValidityInSeconds(
uint256 messageValidityInSeconds_
) external;
/**
* @dev function {setPlatformTreasury} onlySuperAdmin
*
* Set the address that platform fees will be paid to / can be withdrawn to.
* Note that this is restricted to the highest authority level, the super
* admin. Platform admins can trigger a withdrawal to the treasury, but only
* the default admin can set or alter the treasury address. It is recommended
* that the default admin is highly secured and restrited e.g. a multi-sig.
*
* @param platformTreasury_ New treasury address
*/
function setPlatformTreasury(address platformTreasury_) external;
/**
* @dev function {withdrawETH} onlyPlatformAdmin
*
* A withdraw function to allow ETH to be withdrawn to the treasury
*
* @param amount_ The amount to withdraw
*/
function withdrawETH(uint256 amount_) external;
/**
* @dev function {withdrawERC20} onlyPlatformAdmin
*
* A withdraw function to allow ERC20s to be withdrawn to the treasury
*
* @param token_ The contract address of the token being withdrawn
* @param amount_ The amount to withdraw
*/
function withdrawERC20(IERC20 token_, uint256 amount_) external;
/**
* @dev function {createERC20}
*
* Create an ERC-20
*
* @param metaId_ The drop Id being approved
* @param salt_ Salt for create2
* @param erc20Config_ ERC20 configuration
* @param signedMessage_ The signed message object
* @param lockerFee_ The fee for the unicrypt locker
* @param deploymentFee_ The fee for deployment, if any
* @return deployedAddress_ The deployed ERC20 contract address
*/
function createERC20(
string calldata metaId_,
bytes32 salt_,
ERC20Config calldata erc20Config_,
SignedDropMessageDetails calldata signedMessage_,
uint256 lockerFee_,
uint256 deploymentFee_
) external payable returns (address deployedAddress_);
/**
* @dev function {createConfigHash}
*
* Create the config hash
*
* @param metaId_ The drop Id being approved
* @param salt_ Salt for create2
* @param erc20Config_ ERC20 configuration
* @param messageTimeStamp_ When the message for this config hash was signed
* @param lockerFee_ The fee for the unicrypt locker
* @param deploymentFee_ The fee for deployment, if any
* @param deployer_ Address performing the deployment
* @return configHash_ The bytes32 config hash
*/
function createConfigHash(
string calldata metaId_,
bytes32 salt_,
ERC20Config calldata erc20Config_,
uint256 messageTimeStamp_,
uint256 lockerFee_,
uint256 deploymentFee_,
address deployer_
) external pure returns (bytes32 configHash_);
}
// File contracts/Global/Revert.sol
//
// Metadrop Contracts (v2.1.0)
/**
*
* @title Revert.sol. For efficient reverts
*
* @author metadrop https://metadrop.com/
*
*/
pragma solidity 0.8.19;
abstract contract Revert {
/**
* @dev For more efficient reverts.
*/
function _revert(bytes4 errorSelector) internal pure {
assembly {
mstore(0x00, errorSelector)
revert(0x00, 0x04)
}
}
}
// File contracts/Global/OZ/Ownable.sol
//
// Metadrop Contracts (v2.1.0)
// Metadrop based on OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity 0.8.19;
/**
* @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.
*
* By default, the owner account will be the one that deploys the contract. 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 IErrors, Revert, Context {
address private _owner;
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @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(CallerIsNotTheOwner.selector);
}
}
/**
* @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(CannotSetNewOwnerToTheZeroAddress.selector);
}
_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);
}
}
// File @openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol@v4.9.1
//
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
// File @openzeppelin/contracts/utils/Address.sol@v4.9.1
//
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @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.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @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, it is bubbled up by this
* function (like regular Solidity function calls).
*
* 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.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @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`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) 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(errorMessage);
}
}
}
// File contracts/Global/OZ/SafeERC20.sol
//
// Metadrop Contracts (v2.1.0)
// Metadrop based on OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity 0.8.19;
/**
* @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 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 `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
if (oldAllowance < value) {
revert IErrors.DecreasedAllowanceBelowZero();
}
forceApprove(token, spender, oldAllowance - value);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to
* 0 before setting it to a non-zero value.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
if (nonceAfter != (nonceBefore + 1)) {
revert IErrors.PermitDidNotSucceed();
}
}
/**
* @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, "call fail");
if ((returndata.length != 0) && !abi.decode(returndata, (bool))) {
revert IErrors.OperationDidNotSucceed();
}
}
/**
* @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;
}
}
// File contracts/Global/TaxAdmin.sol
//
// Metadrop Contracts (v2.1.0)
// Metadrop based on OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity 0.8.19;
/**
* @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.
*
* By default, the owner account will be the one that deploys the contract. 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 TaxAdmin is IErrors, Revert, Context {
address private _taxAdmin;
event TaxAdminTransferred(
address indexed previousTaxAdmin,
address indexed newTaxAdmin
);
constructor() {}
/**
* @dev Throws if called by any account other than the tax admin.
*/
modifier onlyTaxAdmin() {
_checkTaxAdmin();
_;
}
/**
* @dev Returns the address of the current tax admin.
*/
function taxAdmin() public view virtual returns (address) {
return _taxAdmin;
}
/**
* @dev Throws if the sender is not the tax admin.
*/
function _checkTaxAdmin() internal view virtual {
if (taxAdmin() != _msgSender()) {
_revert(CallerIsNotTheTaxAdmin.selector);
}
}
/**
* @dev Leaves the contract without a tax admin. It will not be possible to call
* `onlyTaxAdmin` functions. Can only be called by the current tax admin.
*
* NOTE: Renouncing taxAdmin will leave the contract without an tax admim,
* thereby disabling any functionality that is only available to the tax admin.
*/
function renounceTaxAdmin() public virtual onlyTaxAdmin {
_transferTaxAdmin(address(0));
}
/**
* @dev Transfers the tax admin of the contract to a new account (`newTaxAdmin`).
* Can only be called by the current tax admin.
*/
function transferTaxAdmin(address newTaxAdmin) public virtual onlyTaxAdmin {
if (newTaxAdmin == address(0)) {
_revert(CannotSetNewTaxAdminToTheZeroAddress.selector);
}
_transferTaxAdmin(newTaxAdmin);
}
/**
* @dev Transfers the tax admin of the contract to a new account (`newTaxAdmin`).
* Internal function without access restriction.
*/
function _transferTaxAdmin(address newTaxAdmin) internal virtual {
address oldTaxAdmin = _taxAdmin;
_taxAdmin = newTaxAdmin;
emit TaxAdminTransferred(oldTaxAdmin, newTaxAdmin);
}
}
// File contracts/ThirdParty/omnus/ERC20Spendable/IERC20Spendable.sol
//
// Omnus Contracts v3
// https://omn.us/spendable
// https://github.com/omnus/ERC20Spendable
// npm: @omnus/ERC20Spendable
pragma solidity ^0.8.19;
/**
* @title ERC-7492 IERC20Spendable.sol
*
* @author omnus
* https://omn.us
*
* @dev Implementation of {IERC20Spendable} interface.
*
* {ERC-7492 ERC20Spendable} allows ERC20s to operate as 'spendable' items, i.e. an ERC20 token that
* can trigger an action on another contract at the same time as being transfered. Similar to ERC677
* and the hooks in ERC777, but with more of an empasis on interoperability (returned values) than
* ERC677 and specifically scoped interaction rather than the general hooks of ERC777.
*
* For more detailed notes please see our guide https://omn.us/how-to-implement-erc20-spendable
*/
interface IERC20Spendable {
/// @dev Error {ERC20SpendableInvalidReveiver} The called contract does not support ERC20Spendable.
error ERC20SpendableInvalidReveiver(address receiver);
/// @dev Event {SpendReceipt} issued on successful return from the {ERC20SpendableReceiver} call.
event SpendReceipt(
address spender,
address receiver,
uint256 amount,
bytes sentArguments,
bytes returnedArguments
);
/**
* @dev {spend} Allows the transfer of the owners token to the receiver, a call on the receiver,
* and then the return of information from the receiver back up the call stack.
*
* Overloaded method - call this if you are not specifying any arguments.
*
* @param receiver_ The receiving address for this token spend. Contracts must implement
* ERCSpendableReceiver to receive spendadle tokens. For more detail see {ERC20SpendableReceiver}.
* @param spent_ The amount of token being spent. This will be transfered as part of this call and
* provided as an argument on the call to {onERC20SpendableReceived} on the {ERC20SpendableReceiver}.
*/
function spend(address receiver_, uint256 spent_) external;
/**
* @dev {spend} Allows the transfer of the owners token to the receiver, a call on the receiver, and
* the return of information from the receiver back up the call stack.
*
* Overloaded method - call this to specify a bytes argument.
*
* @param receiver_ The receiving address for this token spend. Contracts must implement
* ERCSpendableReceiver to receive spendadle tokens. For more detail see {ERC20SpendableReceiver}.
* @param spent_ The amount of token being spent. This will be transfered as part of this call and
* provided as an argument on the call to {onERC20SpendableReceived} on the {ERC20SpendableReceiver}.
* @param arguments_ Bytes argument to send with the call. See {mock} contracts for details on encoding
* and decoding arguments from bytes.
*/
function spend(
address receiver_,
uint256 spent_,
bytes memory arguments_
) external;
}
// File contracts/ThirdParty/omnus/ERC20Spendable/IERC20SpendableReceiver.sol
//
// Omnus Contracts v3
// https://omn.us/spendable
// https://github.com/omnus/ERC20Spendable
// npm: @omnus/ERC20Spendable
pragma solidity ^0.8.19;
/**
* @title ERC-7492 IERC20SpendableReceiver.sol
*
* @author omnus
* https://omn.us
*
* @dev Implementation of {IERC20SpendableReceiver} interface.
*
* {ERC-7492 ERC20Spendable} allows ERC20s to operate as 'spendable' items, i.e. an ERC20 token that
* can trigger an action on another contract at the same time as being transfered. Similar to ERC677
* and the hooks in ERC777, but with more of an empasis on interoperability (returned values) than
* ERC677 and specifically scoped interaction rather than the general hooks of ERC777.
*
* For more detailed notes please see our guide https://omn.us/how-to-implement-erc20-spendable
*/
interface IERC20SpendableReceiver {
/// @dev Error {CallMustBeFromSpendableToken}. The call to this method can only be from a designated spendable token.
error CallMustBeFromSpendableToken();
/**
* @dev {onERC20SpendableReceived} External function called by ERC20SpendableTokens. This
* validates that the token is valid and then calls the internal {_handleSpend} method.
* You must overried {_handleSpend} in your contract to perform processing you wish to occur
* on token spend.
*
* This method will pass back the valid bytes4 selector and any bytes argument passed from
* {_handleSpend}.
*
* @param spender_ The address spending the ERC20Spendable
* @param spent_ The amount of token spent
* @param arguments_ Bytes sent with the call
*/
function onERC20SpendableReceived(
address spender_,
uint256 spent_,
bytes memory arguments_
) external returns (bytes4 retval_, bytes memory returnArguments_);
}
// File contracts/ThirdParty/omnus/ERC20Spendable/ERC20Spendable.sol
//
// Omnus Contracts v3
// https://omn.us/spendable
// https://github.com/omnus/ERC20Spendable
// npm: @omnus/ERC20Spendable
pragma solidity 0.8.19;
/**
* @title ERC-7492 ERC20Spendable.sol
*
* @author omnus
* https://omn.us
*
* @dev Implementation of {ERC20Spendable}.
*
* {ERC-7492 ERC20Spendable} allows ERC20s to operate as 'spendable' items, i.e. an ERC20 token that
* can trigger an action on another contract at the same time as being transfered. Similar to ERC677
* and the hooks in ERC777, but with more of an empasis on interoperability (returned values) than
* ERC677 and specifically scoped interaction rather than the general hooks of ERC777.
*
* For more detailed notes please see our guide https://omn.us/how-to-implement-erc20-spendable
*/
abstract contract ERC20Spendable is Context, IERC20Spendable {
/**
* @dev {spend} Allows the transfer of the owners token to the receiver, a call on the receiver,
* and then the return of information from the receiver back up the call stack.
*
* Overloaded method - call this if you are not specifying any arguments.
*
* @param receiver_ The receiving address for this token spend. Contracts must implement
* ERCSpendableReceiver to receive spendadle tokens. For more detail see {ERC20SpendableReceiver}.
* @param spent_ The amount of token being spent. This will be transfered as part of this call and
* provided as an argument on the call to {onERC20SpendableReceived} on the {ERC20SpendableReceiver}.
*/
function spend(address receiver_, uint256 spent_) public virtual {
spend(receiver_, spent_, "");
}
/**
* @dev {spend} Allows the transfer of the owners token to the receiver, a call on the receiver, and
* the return of information from the receiver back up the call stack.
*
* Overloaded method - call this to specify a bytes argument.
*
* @param receiver_ The receiving address for this token spend. Contracts must implement
* ERCSpendableReceiver to receive spendadle tokens. For more detail see {ERC20SpendableReceiver}.
* @param spent_ The amount of token being spent. This will be transfered as part of this call and
* provided as an argument on the call to {onERC20SpendableReceived} on the {ERC20SpendableReceiver}.
* @param arguments_ Bytes argument to send with the call. See {mock} contracts for details on encoding
* and decoding arguments from bytes.
*/
function spend(
address receiver_,
uint256 spent_,
bytes memory arguments_
) public virtual {
/**
* @dev Transfer tokens to the receiver contract IF this is a non-0 amount. Don't try and transfer 0,
* which leavesopen the possibility that the call is free. If not, the function call after will fail
* and revert. Why would a {spend} method call ever be free? For example, a service provider may be
* taking their ERC20 token as payment for a service. But they want to offer it for free, perhaps for a
* limited time. Under this situation the spend callcan be used in all cases, but sending 0 token while
* it is free, removing the need for different interfaces.
*
* We use the standard ERC20 public transfer method for the transfer, which means two things:
* 1) This can only be called by the token owner (but that is the entire point!)
* 2) We inherit all of the security checks in this method (e.g. owner has sufficient balance etc.)
*/
if (spent_ != 0) {
transfer(receiver_, spent_);
}
/**
* @dev Perform actions on the receiver and return arguments back up the callstack. In addition to allowing
* the execution of the hook within the receiver, this call provides the same feature as onERC721Received
* in the ERC721 standard.
*/
if (receiver_.code.length > 0) {
try
IERC20SpendableReceiver(receiver_).onERC20SpendableReceived(
_msgSender(),
spent_,
arguments_
)
returns (bytes4 retval, bytes memory returnedArguments) {
if (
retval != IERC20SpendableReceiver.onERC20SpendableReceived.selector
) {
revert ERC20SpendableInvalidReveiver(receiver_);
}
emit SpendReceipt(
_msgSender(),
receiver_,
spent_,
arguments_,
returnedArguments
);
/// @dev Handle returned values. Specify an override {_handleReceipt} method in your ERC20 contract if
/// you wish to handle returned arguments.
_handleReceipt(returnedArguments);
} catch (bytes memory reason) {
if (reason.length == 0) {
revert ERC20SpendableInvalidReveiver(receiver_);
} else {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
}
/**
* @dev {_handleReceipt} Internal function called on completion of a call to {onERC20SpendableReceived}
* on the {ERC20SpendableReceiver}.
*
* When making a token {ERC20Spendable} if you wish to process receipts you need to override
* {_handleReceipt} in your contract. For an example, see {mock} contract {MockSpendableERC20ReturnedArgs}.
*
* @param returnedArguments_ Bytes argument to returned from the call. See {mock} contracts for details on
* encoding and decoding arguments from bytes.
*/
function _handleReceipt(bytes memory returnedArguments_) internal virtual {}
/**
* @dev See {IERC165-supportsInterface}. This can be used to determine if an ERC20 is ERC20Spendable. For
* example, a DEX may check this value, and make use of a single {spend} transaction (rather than the current
* model of [approve -> pull]) if the ERC20Spendable interface is supported.
*
* @param interfaceId_ The bytes4 interface identifier being checked.
*/
function supportsInterface(
bytes4 interfaceId_
) public view virtual returns (bool) {
// The interface IDs are constants representing the first 4 bytes
// of the XOR of all function selectors in the interface.
// See: [ERC165](https://eips.ethereum.org/EIPS/eip-165)
// (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`)
return interfaceId_ == type(IERC20Spendable).interfaceId;
}
/**
* @dev override this in your implementation
*
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual returns (bool) {}
}
// File contracts/ThirdParty/Unicrypt/IUniswapV2Locker.sol
// Interface definition for UniswapV2Locker.sol
pragma solidity 0.8.19;
interface IERCBurn {
function burn(uint256 _amount) external;
function approve(address spender, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external returns (uint256);
function balanceOf(address account) external view returns (uint256);
}
interface IMigrator {
function migrate(
address lpToken,
uint256 amount,
uint256 unlockDate,
address owner
) external returns (bool);
}
interface IUniswapV2Locker {
struct UserInfo {
EnumerableSet.AddressSet lockedTokens; // records all tokens the user has locked
mapping(address => uint256[]) locksForToken; // map erc20 address to lock id for that token
}
struct TokenLock {
uint256 lockDate; // the date the token was locked
uint256 amount; // the amount of tokens still locked (initialAmount minus withdrawls)
uint256 initialAmount; // the initial lock amount
uint256 unlockDate; // the date the token can be withdrawn
uint256 lockID; // lockID nonce per uni pair
address owner;
}
struct FeeStruct {
uint256 ethFee; // Small eth fee to prevent spam on the platform
IERCBurn secondaryFeeToken; // UNCX or UNCL
uint256 secondaryTokenFee; // optional, UNCX or UNCL
uint256 secondaryTokenDiscount; // discount on liquidity fee for burning secondaryToken
uint256 liquidityFee; // fee on univ2 liquidity tokens
uint256 referralPercent; // fee for referrals
IERCBurn referralToken; // token the refferer must hold to qualify as a referrer
uint256 referralHold; // balance the referrer must hold to qualify as a referrer
uint256 referralDiscount; // discount on flatrate fees for using a valid referral address
}
function setDev(address payable _devaddr) external;
/**
* @notice set the migrator contract which allows locked lp tokens to be migrated to uniswap v3
*/
function setMigrator(IMigrator _migrator) external;
function setSecondaryFeeToken(address _secondaryFeeToken) external;
/**
* @notice referrers need to hold the specified token and hold amount to be elegible for referral fees
*/
function setReferralTokenAndHold(
IERCBurn _referralToken,
uint256 _hold
) external;
function setFees(
uint256 _referralPercent,
uint256 _referralDiscount,
uint256 _ethFee,
uint256 _secondaryTokenFee,
uint256 _secondaryTokenDiscount,
uint256 _liquidityFee
) external;
/**
* @notice whitelisted accounts dont pay flatrate fees on locking
*/
function whitelistFeeAccount(address _user, bool _add) external;
/**
* @notice Creates a new lock
* @param _lpToken the univ2 token address
* @param _amount amount of LP tokens to lock
* @param _unlock_date the unix timestamp (in seconds) until unlock
* @param _referral the referrer address if any or address(0) for none
* @param _fee_in_eth fees can be paid in eth or in a secondary token such as UNCX with a discount on univ2 tokens
* @param _withdrawer the user who can withdraw liquidity once the lock expires.
*/
function lockLPToken(
address _lpToken,
uint256 _amount,
uint256 _unlock_date,
address payable _referral,
bool _fee_in_eth,
address payable _withdrawer
) external payable;
/**
* @notice extend a lock with a new unlock date, _index and _lockID ensure the correct lock is changed
* this prevents errors when a user performs multiple tx per block possibly with varying gas prices
*/
function relock(
address _lpToken,
uint256 _index,
uint256 _lockID,
uint256 _unlock_date
) external;
/**
* @notice withdraw a specified amount from a lock. _index and _lockID ensure the correct lock is changed
* this prevents errors when a user performs multiple tx per block possibly with varying gas prices
*/
function withdraw(
address _lpToken,
uint256 _index,
uint256 _lockID,
uint256 _amount
) external;
/**
* @notice increase the amount of tokens per a specific lock, this is preferable to creating a new lock, less fees, and faster loading on our live block explorer
*/
function incrementLock(
address _lpToken,
uint256 _index,
uint256 _lockID,
uint256 _amount
) external;
/**
* @notice split a lock into two seperate locks, useful when a lock is about to expire and youd like to relock a portion
* and withdraw a smaller portion
*/
function splitLock(
address _lpToken,
uint256 _index,
uint256 _lockID,
uint256 _amount
) external payable;
/**
* @notice transfer a lock to a new owner, e.g. presale project -> project owner
*/
function transferLockOwnership(
address _lpToken,
uint256 _index,
uint256 _lockID,
address payable _newOwner
) external;
/**
* @notice migrates liquidity to uniswap v3
*/
function migrate(
address _lpToken,
uint256 _index,
uint256 _lockID,
uint256 _amount
) external;
function getNumLocksForToken(
address _lpToken
) external view returns (uint256);
function getNumLockedTokens() external view returns (uint256);
function getLockedTokenAtIndex(
uint256 _index
) external view returns (address);
// user functions
function getUserNumLockedTokens(
address _user
) external view returns (uint256);
function getUserLockedTokenAtIndex(
address _user,
uint256 _index
) external view returns (address);
function getUserNumLocksForToken(
address _user,
address _lpToken
) external view returns (uint256);
function getUserLockForTokenAtIndex(
address _user,
address _lpToken,
uint256 _index
)
external
view
returns (uint256, uint256, uint256, uint256, uint256, address);
// whitelist
function getWhitelistedUsersLength() external view returns (uint256);
function getWhitelistedUserAtIndex(
uint256 _index
) external view returns (address);
function getUserWhitelistStatus(address _user) external view returns (bool);
}
// File contracts/ERC20FactoryV1/ERC20/ERC20ByMetadropV1.sol
pragma solidity 0.8.19;
/**
* @dev Metadrop core ERC-20 contract
*
* @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}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* 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.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20ByMetadropV1 is
Context,
ERC20Spendable,
IERC20ByMetadropV1,
Ownable,
TaxAdmin
{
using EnumerableSet for EnumerableSet.AddressSet;
using SafeERC20 for IERC20;
uint256 public constant version = 100010001000000000;
uint256 internal constant BP_DENOM = 10000;
uint256 internal constant ROUND_DEC = 100000000000;
IUniswapV2Locker internal immutable unicryptLocker;
IUniswapV2Router02 internal immutable uniswapRouter;
uint256 public immutable lpSupply;
uint256 public immutable projectSupply;
uint256 public immutable maxTokensPerTransaction;
uint256 public immutable maxTokensPerWallet;
uint256 public immutable maxProjectBuyTaxBasisPoints;
uint256 public immutable maxProjectSellTaxBasisPoints;
uint256 public immutable maxMetadropBuyTaxBasisPoints;
uint256 public immutable maxMetadropSellTaxBasisPoints;
uint256 public immutable lpLockupInDays;
address public immutable metadropTreasury;
address public immutable uniswapV2Pair;
address internal immutable metadropV1Factory;
uint256 internal immutable metadropTaxPeriodInDays;
bool internal immutable tokenHasTax;
bool internal immutable tokenHasLimits;
/** @dev {Storage Slot 1} Vars read / written as part of transfers packed to a single
* slot for warm reads / writes.
* Slot 1:
* 128
* 32
* 16 * 5
* 8 * 2
* ------
* 256
* ------ */
uint128 public projectTaxPendingSwap;
uint32 public fundedDate;
uint16 public projectBuyTaxBasisPoints;
uint16 public projectSellTaxBasisPoints;
uint16 public metadropBuyTaxBasisPoints;
uint16 public metadropSellTaxBasisPoints;
uint16 public swapThresholdBasisPoints;
/** @dev {autoSwapEnabled} We start with {autoSwapEnabled} OFF, as we don't want to
* call this when processing initial liquidity from this address. We turn this on when
* liquidity has been loaded, and use this bool to control processing during auto-swaps
* from that point onwards. */
bool private autoSwapEnabled = false;
/** @dev {limitsEnabled} Similarly, we don't validate txn limits during liquidity loading. This is
* automatically set to true when liquidity loading is complete.
*
* This can be set back to false by the tax admin. This is a neccesary fallback
* position where on-chain actions cannot meet the validation and need to occur.
* For example, someone may stake token into a staking contract over a number
* of transactions until the staked balance is higher than the per txn limit.
* If the developer of the staking contract has not considered the per txn
* limit, and the 'unstake' method simply remits the entire user balance in
* one txn, then this token would now be trapped in the staking contract. Under
* these circumstances the limit can be turned off to allow the transaction to
* proceed.
*
* After a given amount of time any successful token will have
* become distributed such that a per transaction limit is less relevant. */
bool private limitsEnabled = false;
/** @dev {Storage Slot 2} Not read in transfers etc:
* 160
* ------
* 160
* ------ */
address public projectTreasury;
/** @dev {Storage Slot 3} Only written to if metadrop tax applies, otherwise no writes occur.
* Note that although a uint128 supply limit applies to this contract we store this
* as a uint256. As the evm uses uint256 for all vars we save the gas cost of the
* implicit cast by using uint256, given there are no other vars we can sensibly
* pack with. For the project tax we pack a uint128 with other vars read and written
* as part of transfer processing, allowing a warm write.
* Slot 3:
* 256
* ------
* 256
* ------ */
uint256 public metadropTaxPendingSwap;
/** @dev {Storage Slot 4} Not read as part of transfers etc.
* 256
* ------
* 256
* ------ */
uint256 private _totalSupply;
/** @dev {Storage Slot 5 to n} Not read as part of transfers etc. */
string private _name;
string private _symbol;
/** @dev {Social Links} These shouldn't have _ prefix as they are public, but we want these at the top */
string public _1___website;
string public _2___twitter;
string public _3___telegram;
string public _4___discord;
/** @dev {_balances} Addresses balances */
mapping(address => uint256) private _balances;
/** @dev {_allowances} Addresses allocance details */
mapping(address => mapping(address => uint256)) private _allowances;
/** @dev {_liquidityPools} Enumerable set for liquidity pool addresses */
EnumerableSet.AddressSet private _liquidityPools;
/** @dev {_liquidityPools} Enumerable set for addresses where limits do not apply */
EnumerableSet.AddressSet private _unlimited;
/**
* @dev {constructor}
*
* @param integrationAddresses_ The project owner, uniswap router and unicrypt locker.
* @param baseParams_ configuration of this ERC20.
* @param supplyParams_ Supply configuration of this ERC20.
* @param taxParams_ Tax configuration of this ERC20
*/
constructor(
address[3] memory integrationAddresses_,
bytes memory baseParams_,
bytes memory supplyParams_,
bytes memory taxParams_
) {
_decodeBaseParams(integrationAddresses_[0], baseParams_);
uniswapRouter = IUniswapV2Router02(integrationAddresses_[1]);
unicryptLocker = IUniswapV2Locker(integrationAddresses_[2]);
ERC20SupplyParameters memory supplyParams = abi.decode(
supplyParams_,
(ERC20SupplyParameters)
);
ERC20TaxParameters memory taxParams = abi.decode(
taxParams_,
(ERC20TaxParameters)
);
tokenHasLimits = _processSupplyParams(supplyParams);
projectTreasury = supplyParams.projectTreasury;
metadropTreasury = supplyParams.metadropTreasury;
lpSupply = supplyParams.lpSupply * (10 ** decimals());
projectSupply = supplyParams.projectSupply * (10 ** decimals());
maxTokensPerWallet = supplyParams.maxTokensPerWallet * (10 ** decimals());
maxTokensPerTransaction = supplyParams.maxTokensPerTxn * (10 ** decimals());
lpLockupInDays = supplyParams.lpLockupInDays;
tokenHasTax = _processTaxParams(taxParams);
maxProjectBuyTaxBasisPoints = taxParams.maxProjectBuyTaxBasisPoints;
maxProjectSellTaxBasisPoints = taxParams.maxProjectSellTaxBasisPoints;
maxMetadropBuyTaxBasisPoints = taxParams.maxMetadropBuyTaxBasisPoints;
maxMetadropSellTaxBasisPoints = taxParams.maxMetadropSellTaxBasisPoints;
metadropTaxPeriodInDays = taxParams.metadropTaxPeriodInDays;
swapThresholdBasisPoints = uint16(taxParams.taxSwapThresholdBasisPoints);
metadropV1Factory = _msgSender();
_mintBalances(lpSupply, projectSupply);
uniswapV2Pair = _createPair();
}
/**
* @dev {onlyOwnerOrFactory}
*
* Throws if called by any account other than the owner OR factory.
*/
modifier onlyOwnerOrFactory() {
if (metadropV1Factory != _msgSender() && owner() != _msgSender()) {
_revert(CallerIsNotFactoryOrProjectOwner.selector);
}
_;
}
/**
* @dev function {_decodeBaseParams}
*
* Decode NFT Parameters
*
* @param projectOwner_ The owner of this contract
* @param encodedBaseParams_ The base params encoded into a bytes array
*/
function _decodeBaseParams(
address projectOwner_,
bytes memory encodedBaseParams_
) internal {
_transferOwnership(projectOwner_);
_transferTaxAdmin(projectOwner_);
(
_name,
_symbol,
_1___website,
_2___twitter,
_3___telegram,
_4___discord
) = abi.decode(
encodedBaseParams_,
(string, string, string, string, string, string)
);
}
/**
* @dev function {_processSupplyParams}
*
* Process provided supply params
*
* @param erc20SupplyParameters_ The supply params encoded into a bytes array
*/
function _processSupplyParams(
ERC20SupplyParameters memory erc20SupplyParameters_
) internal returns (bool tokenHasLimits_) {
if (
erc20SupplyParameters_.maxSupply !=
(erc20SupplyParameters_.lpSupply + erc20SupplyParameters_.projectSupply)
) {
_revert(SupplyTotalMismatch.selector);
}
if (erc20SupplyParameters_.maxSupply > type(uint128).max) {
_revert(MaxSupplyTooHigh.selector);
}
if (erc20SupplyParameters_.lpLockupInDays > type(uint96).max) {
_revert(LPLockUpMustFitUint96.selector);
}
_unlimited.add(erc20SupplyParameters_.projectTreasury);
_unlimited.add(address(this));
_unlimited.add(address(0));
if (
erc20SupplyParameters_.maxTokensPerTxn == 0 &&
erc20SupplyParameters_.maxTokensPerWallet == 0
) {
return false;
} else {
return true;
}
}
/**
* @dev function {_processTaxParams}
*
* Process provided tax params
*
* @param erc20TaxParameters_ The tax params encoded into a bytes array
*/
function _processTaxParams(
ERC20TaxParameters memory erc20TaxParameters_
) internal returns (bool tokenHasTax_) {
/**
* @dev We use the immutable var {tokenHasTax} to avoid unneccesary storage writes and reads. If this
* token does NOT have tax applied then there is no need to store or read these parameters, and we can
* avoid this simply by checking the immutable var. Pass back the value for this var from this method.
*/
if (
erc20TaxParameters_.projectBuyTaxBasisPoints == 0 &&
erc20TaxParameters_.projectSellTaxBasisPoints == 0 &&
erc20TaxParameters_.metadropBuyTaxBasisPoints == 0 &&
erc20TaxParameters_.metadropSellTaxBasisPoints == 0 &&
erc20TaxParameters_.maxProjectBuyTaxBasisPoints == 0 &&
erc20TaxParameters_.maxProjectSellTaxBasisPoints == 0 &&
erc20TaxParameters_.maxMetadropBuyTaxBasisPoints == 0 &&
erc20TaxParameters_.maxMetadropSellTaxBasisPoints == 0
) {
return false;
} else {
projectBuyTaxBasisPoints = uint16(
erc20TaxParameters_.projectBuyTaxBasisPoints
);
projectSellTaxBasisPoints = uint16(
erc20TaxParameters_.projectSellTaxBasisPoints
);
metadropBuyTaxBasisPoints = uint16(
erc20TaxParameters_.metadropBuyTaxBasisPoints
);
metadropSellTaxBasisPoints = uint16(
erc20TaxParameters_.metadropSellTaxBasisPoints
);
return true;
}
}
/**
* @dev function {_mintBalances}
*
* Mint initial balances
*
* @param lpMint_ The number of tokens for liquidity
* @param projectMint_ The number of tokens for the project treasury
*/
function _mintBalances(uint256 lpMint_, uint256 projectMint_) internal {
if (lpMint_ > 0) {
_mint(address(this), lpMint_);
}
if (projectMint_ > 0) {
_mint(projectTreasury, projectMint_);
}
}
/**
* @dev function {_createPair}
*
* Create the uniswap pair
*
* @return uniswapV2Pair_ The pair address
*/
function _createPair() internal returns (address uniswapV2Pair_) {
if (_totalSupply > 0) {
uniswapV2Pair_ = IUniswapV2Factory(uniswapRouter.factory()).createPair(
address(this),
uniswapRouter.WETH()
);
_liquidityPools.add(uniswapV2Pair_);
emit LiquidityPoolCreated(uniswapV2Pair_);
}
_unlimited.add(address(uniswapRouter));
_unlimited.add(uniswapV2Pair_);
return (uniswapV2Pair_);
}
/**
* @dev function {addInitialLiquidity}
*
* Add initial liquidity to the uniswap pair
*
* @param lockerFee_ The locker fee in wei. This must match the required fee from the external locker contract.
*/
function addInitialLiquidity(
uint256 lockerFee_
) public payable onlyOwnerOrFactory {
if (lockerFee_ >= msg.value) {
// The amount of ETH MUST exceed the locker fee, otherwise what liquidity are we adding?
_revert(NoETHForLiquidityPair.selector);
}
_addInitialLiquidity((msg.value - lockerFee_), lockerFee_);
}
/**
* @dev function {_addInitialLiquidity}
*
* Add initial liquidity to the uniswap pair (internal function that does the work)
*
* @param ethAmount_ The amount of ETH passed into the call
* @param lockerFee_ The locker fee in wei. This must match the required fee from the external locker contract.
*/
function _addInitialLiquidity(
uint256 ethAmount_,
uint256 lockerFee_
) internal {
// Funded date is the date of first funding. We can only add initial liquidity once. If this date is set,
// we cannot proceed
if (fundedDate == 0) {
fundedDate = uint32(block.timestamp);
} else {
_revert(InitialLiquidityAlreadyAdded.selector);
}
// Can only do this if this contract holds tokens:
if (balanceOf(address(this)) == 0) {
_revert(NoTokenForLiquidityPair.selector);
}
// Approve the uniswap router for an inifinite amount (max uint256)
// This means that we don't need to worry about later incrememtal
// approvals on tax swaps, as the uniswap router allowance will never
// be decreased (see code in decreaseAllowance for reference)
_approve(address(this), address(uniswapRouter), type(uint256).max);
// Add the liquidity:
(uint256 amountA, uint256 amountB, uint256 lpTokens) = uniswapRouter
.addLiquidityETH{value: ethAmount_}(
address(this),
balanceOf(address(this)),
0,
0,
address(this),
block.timestamp
);
emit InitialLiquidityAdded(amountA, amountB, lpTokens);
autoSwapEnabled = true;
limitsEnabled = true;
// Lock the liqidity:
_lockInitialLiquidity(lockerFee_, lpTokens);
}
/**
* @dev function {_lockInitialLiquidity}
*
* Lock initial liquidity on locker contract
*
* @param lockerFee_ The locker fee in wei. This must match the required fee from the external locker contract.
* @param lpTokens_ The amount of LP tokens to be locked
*/
function _lockInitialLiquidity(
uint256 lockerFee_,
uint256 lpTokens_
) internal {
IERC20(uniswapV2Pair).approve(address(unicryptLocker), lpTokens_);
unicryptLocker.lockLPToken{value: lockerFee_}(
uniswapV2Pair,
IERC20(uniswapV2Pair).balanceOf(address(this)),
block.timestamp + (lpLockupInDays * 1 days),
payable(address(0)),
true,
payable(projectTreasury)
);
emit LiquidityLocked();
}
/**
* @dev function {isLiquidityPool}
*
* Return if an address is a liquidity pool
*
* @param queryAddress_ The address being queried
* @return bool The address is / isn't a liquidity pool
*/
function isLiquidityPool(address queryAddress_) public view returns (bool) {
/** @dev We check the uniswapV2Pair address first as this is an immutable variable and therefore does not need
* to be fetched from storage, saving gas if this address IS the uniswapV2Pool. We also add this address
* to the enumerated set for ease of reference (for example it is returned in the getter), and it does
* not add gas to any other calls, that still complete in 0(1) time.
*/
return (queryAddress_ == uniswapV2Pair ||
_liquidityPools.contains(queryAddress_));
}
/**
* @dev function {addLiquidityPool} onlyTaxAdmin
*
* Allows the tax admin to add a liquidity pool to the pool enumerable set
*
* @param newLiquidityPool_ The address of the new liquidity pool
*/
function addLiquidityPool(address newLiquidityPool_) public onlyTaxAdmin {
// Don't allow calls that didn't pass an address:
if (newLiquidityPool_ == address(0)) {
_revert(LiquidityPoolCannotBeAddressZero.selector);
}
// Only allow smart contract addresses to be added, as only these can be pools:
if (newLiquidityPool_.code.length == 0) {
_revert(LiquidityPoolMustBeAContractAddress.selector);
}
// Add this to the enumerated list:
_liquidityPools.add(newLiquidityPool_);
emit LiquidityPoolAdded(newLiquidityPool_);
}
/**
* @dev function {removeLiquidityPool} onlyTaxAdmin
*
* Allows the tax admin to remove a liquidity pool
*
* @param removedLiquidityPool_ The address of the old removed liquidity pool
*/
function removeLiquidityPool(
address removedLiquidityPool_
) public onlyTaxAdmin {
// Remove this from the enumerated list:
_liquidityPools.remove(removedLiquidityPool_);
emit LiquidityPoolRemoved(removedLiquidityPool_);
}
/**
* @dev function {isUnlimited}
*
* Return if an address is unlimited (is not subject to per txn and per wallet limits)
*
* @param queryAddress_ The address being queried
* @return bool The address is / isn't unlimited
*/
function isUnlimited(address queryAddress_) public view returns (bool) {
return (_unlimited.contains(queryAddress_));
}
/**
* @dev function {addUnlimited} onlyTaxAdmin
*
* Allows the tax admin to add an unlimited address
*
* @param newUnlimited_ The address of the new unlimited address
*/
function addUnlimited(address newUnlimited_) public onlyTaxAdmin {
// Add this to the enumerated list:
_unlimited.add(newUnlimited_);
emit UnlimitedAddressAdded(newUnlimited_);
}
/**
* @dev function {removeUnlimited} onlyTaxAdmin
*
* Allows the tax admin to remove an unlimited address
*
* @param removedUnlimited_ The address of the old removed unlimited address
*/
function removeUnlimited(address removedUnlimited_) public onlyTaxAdmin {
// Remove this from the enumerated list:
_unlimited.remove(removedUnlimited_);
emit UnlimitedAddressRemoved(removedUnlimited_);
}
/**
* @dev function {setLimitsEnabledStatus} onlyTaxAdmin
*
* Allows the tax admin to enable / disable tokens per txn and per holder validation.
*
* @param enabled_ Should limits be on?
*/
function setLimitsEnabledStatus(bool enabled_) public onlyTaxAdmin {
limitsEnabled = enabled_;
emit SetLimitsEnabled(enabled_);
}
/**
* @dev function {setProjectTreasury} onlyTaxAdmin
*
* Allows the tax admin to set the treasury address
*
* @param projectTreasury_ New treasury address
*/
function setProjectTreasury(address projectTreasury_) public onlyTaxAdmin {
projectTreasury = projectTreasury_;
emit TreasuryUpdated(projectTreasury_);
}
/**
* @dev function {setSwapThresholdBasisPoints} onlyTaxAdmin
*
* Allows the tax admin to set the autoswap threshold
*
* @param swapThresholdBasisPoints_ New swap threshold in basis points
*/
function setSwapThresholdBasisPoints(
uint16 swapThresholdBasisPoints_
) public onlyTaxAdmin {
uint256 oldswapThresholdBasisPoints = swapThresholdBasisPoints;
swapThresholdBasisPoints = swapThresholdBasisPoints_;
emit AutoSwapThresholdUpdated(
oldswapThresholdBasisPoints,
swapThresholdBasisPoints_
);
}
/**
* @dev function {withdrawETH} onlyOwner
*
* Allows the owner to withdraw ETH
*
* @param amount_ The amount to withdraw
*/
function withdrawETH(uint256 amount_) external onlyOwner {
(bool success, ) = owner().call{value: amount_}("");
if (!success) {
_revert(TransferFailed.selector);
}
}
/**
* @dev function {withdrawERC20} onlyOwner
*
* A withdraw function to allow ERC20s to be withdrawn.
*
* @param token_ The address of the token being withdrawn
* @param amount_ The amount to withdraw
*/
function withdrawERC20(IERC20 token_, uint256 amount_) external onlyOwner {
token_.safeTransfer(owner(), amount_);
}
/**
* @dev function {setProjectTaxRates} onlyTaxAdmin
*
* Change the tax rates, subject to max rate
*
* @param newProjectBuyTaxBasisPoints_ The new buy tax rate
* @param newProjectSellTaxBasisPoints_ The new sell tax rate
*/
function setProjectTaxRates(
uint16 newProjectBuyTaxBasisPoints_,
uint16 newProjectSellTaxBasisPoints_
) external onlyTaxAdmin {
// Cannot increase above the maximum:
if (newProjectBuyTaxBasisPoints_ > maxProjectBuyTaxBasisPoints) {
_revert(NewBuyTaxBasisPointsExceedsMaximum.selector);
}
// Cannot increase above the maximum:
if (newProjectSellTaxBasisPoints_ > maxProjectSellTaxBasisPoints) {
_revert(NewSellTaxBasisPointsExceedsMaximum.selector);
}
uint16 oldBuyTaxBasisPoints = projectBuyTaxBasisPoints;
projectBuyTaxBasisPoints = newProjectBuyTaxBasisPoints_;
uint16 oldSellTaxBasisPoints = projectSellTaxBasisPoints;
projectSellTaxBasisPoints = newProjectSellTaxBasisPoints_;
emit ProjectTaxBasisPointsChanged(
oldBuyTaxBasisPoints,
newProjectBuyTaxBasisPoints_,
oldSellTaxBasisPoints,
newProjectSellTaxBasisPoints_
);
}
/**
* @dev function {setMetadropTaxRates} onlyTaxAdmin
*
* Change the tax rates, subject to max rate and minimum tax period.
*
* @param newMetadropBuyTaxBasisPoints_ The new buy tax rate
* @param newMetadropSellTaxBasisPoints_ The new sell tax rate
*/
function setMetadropTaxRates(
uint16 newMetadropBuyTaxBasisPoints_,
uint16 newMetadropSellTaxBasisPoints_
) external onlyTaxAdmin {
// Cannot increase above the maximum:
if (newMetadropBuyTaxBasisPoints_ > maxMetadropBuyTaxBasisPoints) {
_revert(NewBuyTaxBasisPointsExceedsMaximum.selector);
}
// Cannot increase above the maximum:
if (newMetadropSellTaxBasisPoints_ > maxMetadropSellTaxBasisPoints) {
_revert(NewSellTaxBasisPointsExceedsMaximum.selector);
}
// Reducing the basis points can only occur after the tax period:
if (
(newMetadropBuyTaxBasisPoints_ < metadropBuyTaxBasisPoints ||
newMetadropSellTaxBasisPoints_ < metadropSellTaxBasisPoints) &&
block.timestamp < (fundedDate + (metadropTaxPeriodInDays * 1 days))
) {
_revert(TaxPeriodStillInForce.selector);
}
uint16 oldBuyTaxBasisPoints = metadropBuyTaxBasisPoints;
uint16 oldSellTaxBasisPoints = metadropSellTaxBasisPoints;
metadropBuyTaxBasisPoints = newMetadropBuyTaxBasisPoints_;
metadropSellTaxBasisPoints = newMetadropSellTaxBasisPoints_;
emit MetadropTaxBasisPointsChanged(
oldBuyTaxBasisPoints,
newMetadropBuyTaxBasisPoints_,
oldSellTaxBasisPoints,
newMetadropSellTaxBasisPoints_
);
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override 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 override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev Provide easy to view tax total:
*/
function _totalBuyTaxBasisPoints() internal view returns (uint256) {
return projectBuyTaxBasisPoints + metadropBuyTaxBasisPoints;
}
/**
* @dev Provide easy to view tax total:
*/
function _totalSellTaxBasisPoints() internal view returns (uint256) {
return projectSellTaxBasisPoints + metadropSellTaxBasisPoints;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(
address account
) public view virtual override 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 `amount`.
*/
function transfer(
address to,
uint256 amount
) public virtual override(ERC20Spendable, IERC20) returns (bool) {
address owner = _msgSender();
_transfer(
owner,
to,
amount,
(isLiquidityPool(owner) || isLiquidityPool(to))
);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(
address owner,
address spender
) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` 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 amount
) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
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 `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount, (isLiquidityPool(from) || isLiquidityPool(to)));
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(
address spender,
uint256 addedValue
) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(
address spender,
uint256 subtractedValue
) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance < subtractedValue) {
_revert(AllowanceDecreasedBelowZero.selector);
}
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `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.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(
address from,
address to,
uint256 amount,
bool applyTax
) internal virtual {
_beforeTokenTransfer(from, to, amount);
// Perform pre-tax validation (e.g. amount doesn't exceed balance, max txn amount)
uint256 fromBalance = _pretaxValidationAndLimits(from, to, amount);
// Perform autoswap if eligible
_autoSwap(from, to);
// Process taxes
uint256 amountMinusTax = _taxProcessing(applyTax, to, from, amount);
// Perform post-tax validation (e.g. total balance after post-tax amount applied)
_posttaxValidationAndLimits(from, to, amountMinusTax);
_balances[from] = fromBalance - amount;
_balances[to] += amountMinusTax;
emit Transfer(from, to, amountMinusTax);
_afterTokenTransfer(from, to, amount);
}
/**
* @dev function {_pretaxValidationAndLimits}
*
* Perform validation on pre-tax amounts
*
* @param from_ From address for the transaction
* @param to_ To address for the transaction
* @param amount_ Amount of the transaction
*/
function _pretaxValidationAndLimits(
address from_,
address to_,
uint256 amount_
) internal view returns (uint256 fromBalance_) {
if (from_ == address(0)) {
_revert(TransferFromZeroAddress.selector);
}
if (to_ == address(0)) {
_revert(TransferToZeroAddress.selector);
}
fromBalance_ = _balances[from_];
if (fromBalance_ < amount_) {
_revert(TransferAmountExceedsBalance.selector);
}
// Liquidity pools aren't always going to round cleanly. This can (and does)
// mean that a limit of 5,000 tokens (for example) will trigger on a transfer
// of 5,000 tokens, as the transfer is actually for 5,000.00000000000000213.
// While 4,999 will work fine, it isn't hugely user friendly. So we buffer
// the limit with rounding decimals, which in all cases are considerably less
// than one whole token:
uint256 roundedLimited;
unchecked {
roundedLimited = maxTokensPerTransaction + ROUND_DEC;
}
if (
tokenHasLimits &&
limitsEnabled &&
(maxTokensPerTransaction != 0) &&
(amount_ > roundedLimited) &&
((isLiquidityPool(from_) && !isUnlimited(to_)) ||
(isLiquidityPool(to_) && !isUnlimited(from_)))
) {
_revert(MaxTokensPerTxnExceeded.selector);
}
return (fromBalance_);
}
/**
* @dev function {_posttaxValidationAndLimits}
*
* Perform validation on post-tax amounts
*
* @param to_ To address for the transaction
* @param amount_ Amount of the transaction
*/
function _posttaxValidationAndLimits(
address from_,
address to_,
uint256 amount_
) internal view returns (uint256 fromBalance_) {
// Liquidity pools aren't always going to round cleanly. This can (and does)
// mean that a limit of 5,000 tokens (for example) will trigger on a max holding
// of 5,000 tokens, as the transfer to achieve that is actually for
// 5,000.00000000000000213. While 4,999 will work fine, it isn't hugely user friendly.
// So we buffer the limit with rounding decimals, which in all cases are considerably
// less than one whole token:
uint256 roundedLimited;
unchecked {
roundedLimited = maxTokensPerWallet + ROUND_DEC;
}
if (
tokenHasLimits &&
limitsEnabled &&
(maxTokensPerWallet != 0) &&
(amount_ + balanceOf(to_) > roundedLimited) &&
// If this is a buy (from a liquidity pool), we apply if the to_
// address isn't noted as unlimited:
(isLiquidityPool(from_) && !isUnlimited(to_))
) {
_revert(MaxTokensPerWalletExceeded.selector);
}
return (fromBalance_);
}
/**
* @dev function {_taxProcessing}
*
* Perform tax processing
*
* @param applyTax_ Do we apply tax to this transaction?
* @param to_ The reciever of the token
* @param from_ The sender of the token
* @param sentAmount_ The amount being send
* @return amountLessTax_ The amount that will be recieved, i.e. the send amount minus tax
*/
function _taxProcessing(
bool applyTax_,
address to_,
address from_,
uint256 sentAmount_
) internal returns (uint256 amountLessTax_) {
amountLessTax_ = sentAmount_;
unchecked {
if (tokenHasTax && applyTax_ && autoSwapEnabled) {
uint256 tax;
// on sell
if (isLiquidityPool(to_) && _totalSellTaxBasisPoints() > 0) {
if (projectSellTaxBasisPoints > 0) {
uint256 projectTax = ((sentAmount_ * projectSellTaxBasisPoints) /
BP_DENOM);
projectTaxPendingSwap += uint128(projectTax);
tax += projectTax;
}
if (metadropSellTaxBasisPoints > 0) {
uint256 metadropTax = ((sentAmount_ * metadropSellTaxBasisPoints) /
BP_DENOM);
metadropTaxPendingSwap += uint128(metadropTax);
tax += metadropTax;
}
}
// on buy
else if (isLiquidityPool(from_) && _totalBuyTaxBasisPoints() > 0) {
if (projectBuyTaxBasisPoints > 0) {
uint256 projectTax = ((sentAmount_ * projectBuyTaxBasisPoints) /
BP_DENOM);
projectTaxPendingSwap += uint128(projectTax);
tax += projectTax;
}
if (metadropBuyTaxBasisPoints > 0) {
uint256 metadropTax = ((sentAmount_ * metadropBuyTaxBasisPoints) /
BP_DENOM);
metadropTaxPendingSwap += uint128(metadropTax);
tax += metadropTax;
}
}
if (tax > 0) {
_balances[address(this)] += tax;
emit Transfer(from_, address(this), tax);
amountLessTax_ -= tax;
}
}
}
return (amountLessTax_);
}
/**
* @dev function {_autoSwap}
*
* Automate the swap of accumulated tax fees to native token
*
* @param from_ The sender of the token
*/
function _autoSwap(address from_, address to_) internal {
if (tokenHasTax) {
uint256 taxBalance = balanceOf(address(this));
if (_eligibleForSwap(from_, to_, taxBalance)) {
// Store that a swap back is in progress:
autoSwapEnabled = false;
// Perform the auto swap to native token:
_swapTaxForNative(taxBalance);
// Flag that the autoswap is complete:
autoSwapEnabled = true;
}
}
}
/**
* @dev function {_eligibleForSwap}
*
* Is the current transfer eligible for autoswap
*
* @param from_ The sender of the token
* @param taxBalance_ The current accumulated tax balance
*/
function _eligibleForSwap(
address from_,
address to_,
uint256 taxBalance_
) internal view returns (bool) {
return (taxBalance_ >=
((_totalSupply * swapThresholdBasisPoints) / BP_DENOM) &&
autoSwapEnabled &&
!isLiquidityPool(from_) &&
from_ != address(uniswapRouter) &&
to_ != address(uniswapRouter));
}
/**
* @dev function {_swapTaxForNative}
*
* Swap tokens taken as tax for native token
*
* @param taxBalance_ The current accumulated tax balance
*/
function _swapTaxForNative(uint256 taxBalance_) internal {
uint256 preSwapBalance = address(this).balance;
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = uniswapRouter.WETH();
uniswapRouter.swapExactTokensForETHSupportingFeeOnTransferTokens(
taxBalance_,
0,
path,
address(this),
block.timestamp
);
uint256 postSwapBalance = address(this).balance;
uint256 balanceToDistribute = postSwapBalance - preSwapBalance;
uint256 projectBalanceToDistribute = (balanceToDistribute *
projectTaxPendingSwap) / (projectTaxPendingSwap + metadropTaxPendingSwap);
uint256 metadropBalanceToDistribute = (balanceToDistribute *
metadropTaxPendingSwap) /
(projectTaxPendingSwap + metadropTaxPendingSwap);
(projectTaxPendingSwap, metadropTaxPendingSwap) = (0, 0);
// Distribute to treasuries:
bool success;
(success, ) = projectTreasury.call{value: projectBalanceToDistribute}("");
if (!success) {
_revert(TransferFailed.selector);
}
(success, ) = metadropTreasury.call{value: metadropBalanceToDistribute}("");
if (!success) {
_revert(TransferFailed.selector);
}
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
if (account == address(0)) {
_revert(MintToZeroAddress.selector);
}
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
// Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
if (account == address(0)) {
_revert(BurnFromTheZeroAddress.selector);
}
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
if (accountBalance < amount) {
_revert(BurnExceedsBalance.selector);
}
unchecked {
_balances[account] = accountBalance - amount;
// Overflow not possible: amount <= accountBalance <= totalSupply.
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` 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.
*/
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
if (owner == address(0)) {
_revert(ApproveFromTheZeroAddress.selector);
}
if (spender == address(0)) {
_revert(ApproveToTheZeroAddress.selector);
}
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < amount) {
_revert(InsufficientAllowance.selector);
}
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Destroys a `value` amount of tokens from the caller.
*
* See {ERC20-_burn}.
*/
function burn(uint256 value) public virtual {
_burn(_msgSender(), value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, deducting from
* the caller's allowance.
*
* See {ERC20-_burn} and {ERC20-allowance}.
*
* Requirements:
*
* - the caller must have allowance for ``accounts``'s tokens of at least
* `value`.
*/
function burnFrom(address account, uint256 value) public virtual {
_spendAllowance(account, _msgSender(), value);
_burn(account, value);
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
receive() external payable {}
}
{
"compilationTarget": {
"ERC20ByMetadropV1.sol": "ERC20ByMetadropV1"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address[3]","name":"integrationAddresses_","type":"address[3]"},{"internalType":"bytes","name":"baseParams_","type":"bytes"},{"internalType":"bytes","name":"supplyParams_","type":"bytes"},{"internalType":"bytes","name":"taxParams_","type":"bytes"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdapterParamsMustBeEmpty","type":"error"},{"inputs":[],"name":"AddressAlreadySet","type":"error"},{"inputs":[],"name":"AllowanceDecreasedBelowZero","type":"error"},{"inputs":[],"name":"AlreadyInitialised","type":"error"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"ApproveFromTheZeroAddress","type":"error"},{"inputs":[],"name":"ApproveToTheZeroAddress","type":"error"},{"inputs":[],"name":"AuctionStatusIsNotEnded","type":"error"},{"inputs":[],"name":"AuctionStatusIsNotOpen","type":"error"},{"inputs":[{"internalType":"address[]","name":"modules","type":"address[]"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"txGas","type":"uint256"}],"name":"AuxCallFailed","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"BidMustBeBelowTheFloorForRefundDuringAuction","type":"error"},{"inputs":[],"name":"BidMustBeBelowTheFloorWhenReducingQuantity","type":"error"},{"inputs":[{"internalType":"enum IErrors.BondingCurveErrorType","name":"error","type":"uint8"}],"name":"BondingCurveError","type":"error"},{"inputs":[],"name":"BurnExceedsBalance","type":"error"},{"inputs":[],"name":"BurnFromTheZeroAddress","type":"error"},{"inputs":[],"name":"CallerIsNotFactory","type":"error"},{"inputs":[],"name":"CallerIsNotFactoryOrProjectOwner","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotPlatformAdmin","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotSuperAdmin","type":"error"},{"inputs":[],"name":"CallerIsNotTheOwner","type":"error"},{"inputs":[],"name":"CallerIsNotTheTaxAdmin","type":"error"},{"inputs":[],"name":"CallerMustBeLzApp","type":"error"},{"inputs":[],"name":"CannotSetNewOwnerToTheZeroAddress","type":"error"},{"inputs":[],"name":"CannotSetNewTaxAdminToTheZeroAddress","type":"error"},{"inputs":[],"name":"CannotSetToZeroAddress","type":"error"},{"inputs":[],"name":"CollectionAlreadyRevealed","type":"error"},{"inputs":[],"name":"ContractIsNotPaused","type":"error"},{"inputs":[],"name":"ContractIsPaused","type":"error"},{"inputs":[],"name":"DecreasedAllowanceBelowZero","type":"error"},{"inputs":[],"name":"DestinationIsNotTrustedSource","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20SpendableInvalidReveiver","type":"error"},{"inputs":[],"name":"GasLimitIsTooLow","type":"error"},{"inputs":[],"name":"IncorrectConfirmationValue","type":"error"},{"inputs":[],"name":"IncorrectPayment","type":"error"},{"inputs":[],"name":"InitialLiquidityAlreadyAdded","type":"error"},{"inputs":[],"name":"InsufficientAllowance","type":"error"},{"inputs":[],"name":"InvalidAdapterParams","type":"error"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidEndpointCaller","type":"error"},{"inputs":[],"name":"InvalidMinGas","type":"error"},{"inputs":[],"name":"InvalidOracleSignature","type":"error"},{"inputs":[],"name":"InvalidPayload","type":"error"},{"inputs":[],"name":"InvalidReceiver","type":"error"},{"inputs":[],"name":"InvalidSourceSendingContract","type":"error"},{"inputs":[],"name":"InvalidTotalShares","type":"error"},{"inputs":[],"name":"LPLockUpMustFitUint96","type":"error"},{"inputs":[],"name":"LiquidityPoolCannotBeAddressZero","type":"error"},{"inputs":[],"name":"LiquidityPoolMustBeAContractAddress","type":"error"},{"inputs":[],"name":"ListLengthMismatch","type":"error"},{"inputs":[],"name":"MaxBidQuantityIs255","type":"error"},{"inputs":[{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"uint256","name":"alreadyMinted","type":"uint256"},{"internalType":"uint256","name":"maxAllowance","type":"uint256"}],"name":"MaxPublicMintAllowanceExceeded","type":"error"},{"inputs":[],"name":"MaxSupplyTooHigh","type":"error"},{"inputs":[],"name":"MaxTokensPerTxnExceeded","type":"error"},{"inputs":[],"name":"MaxTokensPerWalletExceeded","type":"error"},{"inputs":[],"name":"MetadataIsLocked","type":"error"},{"inputs":[],"name":"MetadropFactoryOnlyOncePerReveal","type":"error"},{"inputs":[],"name":"MetadropModulesOnly","type":"error"},{"inputs":[],"name":"MetadropOracleCannotBeAddressZero","type":"error"},{"inputs":[],"name":"MinGasLimitNotSet","type":"error"},{"inputs":[],"name":"MintERC2309QuantityExceedsLimit","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[],"name":"MintingIsClosedForever","type":"error"},{"inputs":[],"name":"NewBuyTaxBasisPointsExceedsMaximum","type":"error"},{"inputs":[],"name":"NewSellTaxBasisPointsExceedsMaximum","type":"error"},{"inputs":[],"name":"NoETHForLiquidityPair","type":"error"},{"inputs":[],"name":"NoPaymentDue","type":"error"},{"inputs":[],"name":"NoRefundForCaller","type":"error"},{"inputs":[],"name":"NoStoredMessage","type":"error"},{"inputs":[],"name":"NoTokenForLiquidityPair","type":"error"},{"inputs":[],"name":"NoTrustedPathRecord","type":"error"},{"inputs":[],"name":"OperationDidNotSucceed","type":"error"},{"inputs":[],"name":"OracleSignatureHasExpired","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"OwnershipNotInitializedForExtraData","type":"error"},{"inputs":[],"name":"ParametersDoNotMatchSignedMessage","type":"error"},{"inputs":[],"name":"PassedConfigDoesNotMatchApproved","type":"error"},{"inputs":[],"name":"PauseCutOffHasPassed","type":"error"},{"inputs":[],"name":"PaymentMustCoverPerMintFee","type":"error"},{"inputs":[],"name":"PermitDidNotSucceed","type":"error"},{"inputs":[],"name":"PlatformAdminCannotBeAddressZero","type":"error"},{"inputs":[],"name":"PlatformTreasuryCannotBeAddressZero","type":"error"},{"inputs":[],"name":"ProjectOwnerCannotBeAddressZero","type":"error"},{"inputs":[],"name":"ProofInvalid","type":"error"},{"inputs":[],"name":"QuantityExceedsMaxPossibleCollectionSupply","type":"error"},{"inputs":[],"name":"QuantityExceedsRemainingCollectionSupply","type":"error"},{"inputs":[],"name":"QuantityExceedsRemainingPhaseSupply","type":"error"},{"inputs":[],"name":"ReferralIdAlreadyUsed","type":"error"},{"inputs":[{"internalType":"uint256","name":"previouslyMinted","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"uint256","name":"remainingAllocation","type":"uint256"}],"name":"RequestingMoreThanRemainingAllocation","type":"error"},{"inputs":[],"name":"RoyaltyFeeWillExceedSalePrice","type":"error"},{"inputs":[],"name":"ShareTotalCannotBeZero","type":"error"},{"inputs":[],"name":"SliceOutOfBounds","type":"error"},{"inputs":[],"name":"SliceOverflow","type":"error"},{"inputs":[],"name":"SuperAdminCannotBeAddressZero","type":"error"},{"inputs":[],"name":"SupplyTotalMismatch","type":"error"},{"inputs":[],"name":"SupportWindowIsNotOpen","type":"error"},{"inputs":[],"name":"TaxFreeAddressCannotBeAddressZero","type":"error"},{"inputs":[],"name":"TaxPeriodStillInForce","type":"error"},{"inputs":[],"name":"TemplateCannotBeAddressZero","type":"error"},{"inputs":[],"name":"TemplateNotFound","type":"error"},{"inputs":[],"name":"ThisMintIsClosed","type":"error"},{"inputs":[],"name":"TotalSharesMustMatchDenominator","type":"error"},{"inputs":[],"name":"TransferAmountExceedsBalance","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferFromZeroAddress","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"URIQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"UnrecognisedVRFMode","type":"error"},{"inputs":[],"name":"VRFCoordinatorCannotBeAddressZero","type":"error"},{"inputs":[],"name":"ValueExceedsMaximum","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldThreshold","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newThreshold","type":"uint256"}],"name":"AutoSwapThresholdUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenA","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenB","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lpToken","type":"uint256"}],"name":"InitialLiquidityAdded","type":"event"},{"anonymous":false,"inputs":[],"name":"LiquidityLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addedPool","type":"address"}],"name":"LiquidityPoolAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addedPool","type":"address"}],"name":"LiquidityPoolCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"removedPool","type":"address"}],"name":"LiquidityPoolRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldBuyBasisPoints","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBuyBasisPoints","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldSellBasisPoints","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newSellBasisPoints","type":"uint256"}],"name":"MetadropTaxBasisPointsChanged","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":"uint256","name":"oldBuyBasisPoints","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBuyBasisPoints","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldSellBasisPoints","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newSellBasisPoints","type":"uint256"}],"name":"ProjectTaxBasisPointsChanged","type":"event"},{"anonymous":false,"inputs":[],"name":"RevenueAutoSwap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"SetLimitsEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"sentArguments","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"returnedArguments","type":"bytes"}],"name":"SpendReceipt","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousTaxAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"newTaxAdmin","type":"address"}],"name":"TaxAdminTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"treasury","type":"address"}],"name":"TreasuryUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addedUnlimted","type":"address"}],"name":"UnlimitedAddressAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"removedUnlimted","type":"address"}],"name":"UnlimitedAddressRemoved","type":"event"},{"inputs":[],"name":"_1___website","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_2___twitter","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_3___telegram","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_4___discord","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"lockerFee_","type":"uint256"}],"name":"addInitialLiquidity","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newLiquidityPool_","type":"address"}],"name":"addLiquidityPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newUnlimited_","type":"address"}],"name":"addUnlimited","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fundedDate","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"queryAddress_","type":"address"}],"name":"isLiquidityPool","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"queryAddress_","type":"address"}],"name":"isUnlimited","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpLockupInDays","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxMetadropBuyTaxBasisPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxMetadropSellTaxBasisPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxProjectBuyTaxBasisPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxProjectSellTaxBasisPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTokensPerTransaction","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTokensPerWallet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadropBuyTaxBasisPoints","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadropSellTaxBasisPoints","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadropTaxPendingSwap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadropTreasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"projectBuyTaxBasisPoints","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"projectSellTaxBasisPoints","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"projectSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"projectTaxPendingSwap","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"projectTreasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"removedLiquidityPool_","type":"address"}],"name":"removeLiquidityPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"removedUnlimited_","type":"address"}],"name":"removeUnlimited","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceTaxAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"enabled_","type":"bool"}],"name":"setLimitsEnabledStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"newMetadropBuyTaxBasisPoints_","type":"uint16"},{"internalType":"uint16","name":"newMetadropSellTaxBasisPoints_","type":"uint16"}],"name":"setMetadropTaxRates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"newProjectBuyTaxBasisPoints_","type":"uint16"},{"internalType":"uint16","name":"newProjectSellTaxBasisPoints_","type":"uint16"}],"name":"setProjectTaxRates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"projectTreasury_","type":"address"}],"name":"setProjectTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"swapThresholdBasisPoints_","type":"uint16"}],"name":"setSwapThresholdBasisPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver_","type":"address"},{"internalType":"uint256","name":"spent_","type":"uint256"},{"internalType":"bytes","name":"arguments_","type":"bytes"}],"name":"spend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver_","type":"address"},{"internalType":"uint256","name":"spent_","type":"uint256"}],"name":"spend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId_","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapThresholdBasisPoints","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"taxAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTaxAdmin","type":"address"}],"name":"transferTaxAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uniswapV2Pair","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"withdrawERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"withdrawETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]