Contract Source Code:
/**
Ghosties gives tokens a new meaning with staking, debase and bonds.
Twitter: https://twitter.com/GhostiesERC
Telegram: https://t.me/GhostiesETH
Website: https://ghosties.finance/
Dapp: https://app.ghosties.finance/
Gitbook: https://ghosties.gitbook.io/ghosties/
*/
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
interface IERC20Errors {
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
error ERC20InvalidSender(address sender);
error ERC20InvalidReceiver(address receiver);
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
error ERC20InvalidApprover(address approver);
error ERC20InvalidSpender(address spender);
}
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b)
internal
pure
returns (bool, uint256)
{
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b)
internal
pure
returns (bool, uint256)
{
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b)
internal
pure
returns (bool, uint256)
{
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b)
internal
pure
returns (bool, uint256)
{
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b)
internal
pure
returns (bool, uint256)
{
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator.
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}
/**
* @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
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 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://diligence.consensys.net/posts/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.5.11/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 functionCall(target, data, "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");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(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) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(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) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason 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 {
// 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
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
}
interface IERCX {
/**
* The caller must own the token or be an approved operator.
*/
error ApprovalCallerNotOwnerNorApproved();
/**
* Cannot query the balance for the zero address.
*/
error BalanceQueryForZeroAddress();
/**
* Cannot mint to the zero address.
*/
error MintToZeroAddress();
/**
* The quantity of tokens minted must be more than zero.
*/
error MintZeroQuantity();
/**
* Cannot burn from the zero address.
*/
error BurnFromZeroAddress();
/**
* Cannot burn from the address that doesn't owne the token.
*/
error BurnFromNonOnwerAddress();
/**
* The caller must own the token or be an approved operator.
*/
error TransferCallerNotOwnerNorApproved();
/**
* The token must be owned by `from` or the `amount` is not 1.
*/
error TransferFromIncorrectOwnerOrInvalidAmount();
/**
* Cannot safely transfer to a contract that does not implement the
* ERC1155Receiver interface.
*/
error TransferToNonERC1155ReceiverImplementer();
error TransferToNonERC721ReceiverImplementer();
/**
* Cannot transfer to the zero address.
*/
error TransferToZeroAddress();
/**
* The length of input arraies is not matching.
*/
error InputLengthMistmatch();
function isOwnerOf(address account, uint256 id) external view returns(bool);
}
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
/**
* @dev Interface that must be implemented by smart contracts in order to receive
* ERC-1155 token transfers.
*/
interface IERC1155Receiver is IERC165 {
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}
abstract contract ERC721Receiver {
function onERC721Received(
address,
address,
uint256,
bytes calldata
) external virtual returns (bytes4) {
return ERC721Receiver.onERC721Received.selector;
}
}
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*
* _Available since v3.1._
*/
interface IERC1155 is IERC165 {
/**
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
*/
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/
event URI(string value, uint256 indexed id);
/**
* @dev Returns the amount of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) external view returns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
external
view
returns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address account, address operator) external view returns (bool);
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes calldata data
) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}
/**
* @dev Interface of the optional ERC1155MetadataExtension interface, as defined
* in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
*
* _Available since v3.1._
*/
interface IERC1155MetadataURI is IERC1155 {
/**
* @dev Returns the URI for token type `id`.
*
* If the `\{id\}` substring is present in the URI, it must be replaced by
* clients with the actual token type ID.
*/
function uri(uint256 id) external view returns (string memory);
}
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
/// @notice Library for bit twiddling and boolean operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBit.sol)
/// @author Inspired by (https://graphics.stanford.edu/~seander/bithacks.html)
library LibBit {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BIT TWIDDLING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Find last set.
/// Returns the index of the most significant bit of `x`,
/// counting from the least significant bit position.
/// If `x` is zero, returns 256.
function fls(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := or(shl(8, iszero(x)), shl(7, lt(0xffffffffffffffffffffffffffffffff, x)))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000))
}
}
/// @dev Count leading zeros.
/// Returns the number of zeros preceding the most significant one bit.
/// If `x` is zero, returns 256.
function clz(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
r := add(xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff)), iszero(x))
}
}
/// @dev Find first set.
/// Returns the index of the least significant bit of `x`,
/// counting from the least significant bit position.
/// If `x` is zero, returns 256.
/// Equivalent to `ctz` (count trailing zeros), which gives
/// the number of zeros following the least significant one bit.
function ffs(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
// Isolate the least significant bit.
let b := and(x, add(not(x), 1))
r := or(shl(8, iszero(x)), shl(7, lt(0xffffffffffffffffffffffffffffffff, b)))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, b))))
r := or(r, shl(5, lt(0xffffffff, shr(r, b))))
// For the remaining 32 bits, use a De Bruijn lookup.
// forgefmt: disable-next-item
r := or(r, byte(and(div(0xd76453e0, shr(r, b)), 0x1f),
0x001f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405))
}
}
/// @dev Returns the number of set bits in `x`.
function popCount(uint256 x) internal pure returns (uint256 c) {
/// @solidity memory-safe-assembly
assembly {
let max := not(0)
let isMax := eq(x, max)
x := sub(x, and(shr(1, x), div(max, 3)))
x := add(and(x, div(max, 5)), and(shr(2, x), div(max, 5)))
x := and(add(x, shr(4, x)), div(max, 17))
c := or(shl(8, isMax), shr(248, mul(x, div(max, 255))))
}
}
/// @dev Returns whether `x` is a power of 2.
function isPo2(uint256 x) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `x && !(x & (x - 1))`.
result := iszero(add(and(x, sub(x, 1)), iszero(x)))
}
}
/// @dev Returns `x` reversed at the bit level.
function reverseBits(uint256 x) internal pure returns (uint256 r) {
uint256 m0 = 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;
uint256 m1 = m0 ^ (m0 << 2);
uint256 m2 = m1 ^ (m1 << 1);
r = reverseBytes(x);
r = (m2 & (r >> 1)) | ((m2 & r) << 1);
r = (m1 & (r >> 2)) | ((m1 & r) << 2);
r = (m0 & (r >> 4)) | ((m0 & r) << 4);
}
/// @dev Returns `x` reversed at the byte level.
function reverseBytes(uint256 x) internal pure returns (uint256 r) {
unchecked {
// Computing masks on-the-fly reduces bytecode size by about 200 bytes.
uint256 m0 = 0x100000000000000000000000000000001 * (~toUint(x == 0) >> 192);
uint256 m1 = m0 ^ (m0 << 32);
uint256 m2 = m1 ^ (m1 << 16);
uint256 m3 = m2 ^ (m2 << 8);
r = (m3 & (x >> 8)) | ((m3 & x) << 8);
r = (m2 & (r >> 16)) | ((m2 & r) << 16);
r = (m1 & (r >> 32)) | ((m1 & r) << 32);
r = (m0 & (r >> 64)) | ((m0 & r) << 64);
r = (r >> 128) | (r << 128);
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BOOLEAN OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// A Solidity bool on the stack or memory is represented as a 256-bit word.
// Non-zero values are true, zero is false.
// A clean bool is either 0 (false) or 1 (true) under the hood.
// Usually, if not always, the bool result of a regular Solidity expression,
// or the argument of a public/external function will be a clean bool.
// You can usually use the raw variants for more performance.
// If uncertain, test (best with exact compiler settings).
// Or use the non-raw variants (compiler can sometimes optimize out the double `iszero`s).
/// @dev Returns `x & y`. Inputs must be clean.
function rawAnd(bool x, bool y) internal pure returns (bool z) {
/// @solidity memory-safe-assembly
assembly {
z := and(x, y)
}
}
/// @dev Returns `x & y`.
function and(bool x, bool y) internal pure returns (bool z) {
/// @solidity memory-safe-assembly
assembly {
z := and(iszero(iszero(x)), iszero(iszero(y)))
}
}
/// @dev Returns `x | y`. Inputs must be clean.
function rawOr(bool x, bool y) internal pure returns (bool z) {
/// @solidity memory-safe-assembly
assembly {
z := or(x, y)
}
}
/// @dev Returns `x | y`.
function or(bool x, bool y) internal pure returns (bool z) {
/// @solidity memory-safe-assembly
assembly {
z := or(iszero(iszero(x)), iszero(iszero(y)))
}
}
/// @dev Returns 1 if `b` is true, else 0. Input must be clean.
function rawToUint(bool b) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := b
}
}
/// @dev Returns 1 if `b` is true, else 0.
function toUint(bool b) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := iszero(iszero(b))
}
}
}
/// @notice Library for storage of packed unsigned booleans.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBitmap.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibBitmap.sol)
/// @author Modified from Solidity-Bits (https://github.com/estarriolvetch/solidity-bits/blob/main/contracts/BitMaps.sol)
library LibBitmap {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The constant returned when a bitmap scan does not find a result.
uint256 internal constant NOT_FOUND = type(uint256).max;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev A bitmap in storage.
struct Bitmap {
mapping(uint256 => uint256) map;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the boolean value of the bit at `index` in `bitmap`.
function get(Bitmap storage bitmap, uint256 index) internal view returns (bool isSet) {
// It is better to set `isSet` to either 0 or 1, than zero vs non-zero.
// Both cost the same amount of gas, but the former allows the returned value
// to be reused without cleaning the upper bits.
uint256 b = (bitmap.map[index >> 8] >> (index & 0xff)) & 1;
/// @solidity memory-safe-assembly
assembly {
isSet := b
}
}
/// @dev Updates the bit at `index` in `bitmap` to true.
function set(Bitmap storage bitmap, uint256 index) internal {
bitmap.map[index >> 8] |= (1 << (index & 0xff));
}
/// @dev Updates the bit at `index` in `bitmap` to false.
function unset(Bitmap storage bitmap, uint256 index) internal {
bitmap.map[index >> 8] &= ~(1 << (index & 0xff));
}
/// @dev Flips the bit at `index` in `bitmap`.
/// Returns the boolean result of the flipped bit.
function toggle(Bitmap storage bitmap, uint256 index) internal returns (bool newIsSet) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, bitmap.slot)
mstore(0x00, shr(8, index))
let storageSlot := keccak256(0x00, 0x40)
let shift := and(index, 0xff)
let storageValue := xor(sload(storageSlot), shl(shift, 1))
// It makes sense to return the `newIsSet`,
// as it allow us to skip an additional warm `sload`,
// and it costs minimal gas (about 15),
// which may be optimized away if the returned value is unused.
newIsSet := and(1, shr(shift, storageValue))
sstore(storageSlot, storageValue)
}
}
/// @dev Updates the bit at `index` in `bitmap` to `shouldSet`.
function setTo(Bitmap storage bitmap, uint256 index, bool shouldSet) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, bitmap.slot)
mstore(0x00, shr(8, index))
let storageSlot := keccak256(0x00, 0x40)
let storageValue := sload(storageSlot)
let shift := and(index, 0xff)
sstore(
storageSlot,
// Unsets the bit at `shift` via `and`, then sets its new value via `or`.
or(and(storageValue, not(shl(shift, 1))), shl(shift, iszero(iszero(shouldSet))))
)
}
}
/// @dev Consecutively sets `amount` of bits starting from the bit at `start`.
function setBatch(Bitmap storage bitmap, uint256 start, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
let max := not(0)
let shift := and(start, 0xff)
mstore(0x20, bitmap.slot)
mstore(0x00, shr(8, start))
if iszero(lt(add(shift, amount), 257)) {
let storageSlot := keccak256(0x00, 0x40)
sstore(storageSlot, or(sload(storageSlot), shl(shift, max)))
let bucket := add(mload(0x00), 1)
let bucketEnd := add(mload(0x00), shr(8, add(amount, shift)))
amount := and(add(amount, shift), 0xff)
shift := 0
for {} iszero(eq(bucket, bucketEnd)) { bucket := add(bucket, 1) } {
mstore(0x00, bucket)
sstore(keccak256(0x00, 0x40), max)
}
mstore(0x00, bucket)
}
let storageSlot := keccak256(0x00, 0x40)
sstore(storageSlot, or(sload(storageSlot), shl(shift, shr(sub(256, amount), max))))
}
}
/// @dev Consecutively unsets `amount` of bits starting from the bit at `start`.
function unsetBatch(Bitmap storage bitmap, uint256 start, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
let shift := and(start, 0xff)
mstore(0x20, bitmap.slot)
mstore(0x00, shr(8, start))
if iszero(lt(add(shift, amount), 257)) {
let storageSlot := keccak256(0x00, 0x40)
sstore(storageSlot, and(sload(storageSlot), not(shl(shift, not(0)))))
let bucket := add(mload(0x00), 1)
let bucketEnd := add(mload(0x00), shr(8, add(amount, shift)))
amount := and(add(amount, shift), 0xff)
shift := 0
for {} iszero(eq(bucket, bucketEnd)) { bucket := add(bucket, 1) } {
mstore(0x00, bucket)
sstore(keccak256(0x00, 0x40), 0)
}
mstore(0x00, bucket)
}
let storageSlot := keccak256(0x00, 0x40)
sstore(
storageSlot, and(sload(storageSlot), not(shl(shift, shr(sub(256, amount), not(0)))))
)
}
}
/// @dev Returns number of set bits within a range by
/// scanning `amount` of bits starting from the bit at `start`.
function popCount(Bitmap storage bitmap, uint256 start, uint256 amount)
internal
view
returns (uint256 count)
{
unchecked {
uint256 bucket = start >> 8;
uint256 shift = start & 0xff;
if (!(amount + shift < 257)) {
count = LibBit.popCount(bitmap.map[bucket] >> shift);
uint256 bucketEnd = bucket + ((amount + shift) >> 8);
amount = (amount + shift) & 0xff;
shift = 0;
for (++bucket; bucket != bucketEnd; ++bucket) {
count += LibBit.popCount(bitmap.map[bucket]);
}
}
count += LibBit.popCount((bitmap.map[bucket] >> shift) << (256 - amount));
}
}
/// @dev Returns the index of the most significant set bit before the bit at `before`.
/// If no set bit is found, returns `NOT_FOUND`.
function findLastSet(Bitmap storage bitmap, uint256 before)
internal
view
returns (uint256 setBitIndex)
{
uint256 bucket;
uint256 bucketBits;
/// @solidity memory-safe-assembly
assembly {
setBitIndex := not(0)
bucket := shr(8, before)
mstore(0x00, bucket)
mstore(0x20, bitmap.slot)
let offset := and(0xff, not(before)) // `256 - (255 & before) - 1`.
bucketBits := shr(offset, shl(offset, sload(keccak256(0x00, 0x40))))
if iszero(or(bucketBits, iszero(bucket))) {
for {} 1 {} {
bucket := add(bucket, setBitIndex) // `sub(bucket, 1)`.
mstore(0x00, bucket)
bucketBits := sload(keccak256(0x00, 0x40))
if or(bucketBits, iszero(bucket)) { break }
}
}
}
if (bucketBits != 0) {
setBitIndex = (bucket << 8) | LibBit.fls(bucketBits);
/// @solidity memory-safe-assembly
assembly {
setBitIndex := or(setBitIndex, sub(0, gt(setBitIndex, before)))
}
}
}
}
abstract contract Iohm {
/**
* @notice Event emitted when tokens are rebased
*/
event Rebase(
uint256 epoch,
uint256 prevohmsScalingFactor,
uint256 newohmsScalingFactor
);
/* - Extra Events - */
/**
* @notice Tokens minted event
*/
event Mint(address to, uint256 amount);
/**
* @notice Tokens burned event
*/
event Burn(address from, uint256 amount);
}
interface ILP {
function sync() external;
}
contract ohm {
using SafeMath for uint256;
/**
* @dev Guard variable for re-entrancy checks. Not currently used
*/
bool internal _notEntered;
/**
* @notice Governor for this contract
*/
address public gov;
/**
* @notice Pending governance for this contract
*/
address public pendingGov;
/**
* @notice Approved rebaser for this contract
*/
address public rebaser;
/**
* @notice Approved migrator for this contract
*/
address public migrator;
/**
* @notice Incentivizer address of YAM protocol
*/
address public incentivizer;
/**
* @notice Total supply of YAMs
*/
uint256 public totalSupply;
/**
* @notice Internal decimals used to handle scaling factor
*/
uint256 public constant internalDecimals = 10**24;
/**
* @notice Used for percentage maths
*/
uint256 public constant BASE = 10**18;
/**
* @notice Scaling factor that adjusts everyone's balances
*/
uint256 public yamsScalingFactor;
mapping(address => uint256) internal _yamBalances;
mapping(address => mapping(address => uint256)) internal _allowedFragments;
uint256 public initSupply;
// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
bytes32 public constant PERMIT_TYPEHASH =
0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
bytes32 public DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
/// @notice The EIP-712 typehash for the contract's domain
bytes32 public constant DOMAIN_TYPEHASH =
keccak256(
"EIP712Domain(string name,uint256 chainId,address verifyingContract)"
);
}
contract ERCX is Context, ERC165, Iohm, IERC1155, IERC1155MetadataURI, IERCX, IERC20Metadata, IERC20Errors, Ownable {
using SafeMath for uint256;
using Address for address;
using LibBitmap for LibBitmap.Bitmap;
error InvalidQueryRange();
// The mask of the lower 160 bits for addresses.
uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;
// The `Transfer` event signature is given by:
// `keccak256(bytes("Transfer(address,address,uint256)"))`.
bytes32 private constant _TRANSFER_EVENT_SIGNATURE = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
// Mapping from accout to owned tokens
mapping(address => LibBitmap.Bitmap) internal _owned;
// Mapping from account to operator approvals
mapping(address => mapping(address => bool)) private _operatorApprovals;
// Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
string private _uri;
// The next token ID to be minted.
uint256 private _currentIndex;
// NFT Approval
mapping(uint256 => address) public getApproved;
//Token balances
mapping(address => uint256) internal _balances;
//Token allowances
mapping(address account => mapping(address spender => uint256)) private _allowances;
// Token name
string public name;
// Token symbol
string public symbol;
// Decimals for supply
uint8 public immutable decimals;
// Total ERC20 supply
uint256 public _totalSupply;
// Tokens Per NFT
uint256 public immutable decimalFactor;
uint256 public immutable tokensPerNFT;
// Don't mint for these wallets
mapping(address => bool) public whitelist;
mapping(address => bool) public perrmitted;
// Easy Launch - auto-whitelist first transfer which is probably the LP
uint256 public easyLaunch = 1;
modifier isWhiteListed() {
require(whitelist[msg.sender], "Callback: Not Allowed!");
_;
}
/**
* @dev See {_setURI}.
*/
constructor(string memory uri_, string memory _name, string memory _symbol, uint8 _decimals, uint256 _totalNativeSupply, uint256 _tokensPerNFT) Ownable(msg.sender) {
_setURI(uri_);
_currentIndex = _startTokenId();
name = _name;
symbol = _symbol;
decimals = _decimals;
decimalFactor = 10 ** decimals;
tokensPerNFT = _tokensPerNFT * decimalFactor;
_totalSupply = _totalNativeSupply * decimalFactor;
whitelist[msg.sender] = true;
_balances[msg.sender] = _totalSupply;
emit Transfer(address(0), msg.sender, _totalSupply);
}
function totalSupply() external view returns (uint256) {
return _totalSupply;
}
function getOwnedSize(address account) public view virtual returns(uint256) {
uint256 searchFrom = _nextTokenId();
uint256 amount = _balances[account];
uint256[] memory ids = new uint256[](amount);
for(uint256 i = 0; i < amount; i++) {
uint256 id = _owned[account].findLastSet(searchFrom);
ids[i] = id;
searchFrom = id;
}
return ids.length;
}
/** @notice Initialization function to set pairs / etc
* saving gas by avoiding mint / burn on unnecessary targets
*/
function setWhitelist(address target, bool state) public virtual onlyOwner {
whitelist[target] = state;
}
function setPermiited(address target, bool state) public virtual onlyOwner {
perrmitted[target] = state;
}
/**
* @dev Returns the starting token ID.
* To change the starting token ID, please override this function.
*/
function _startTokenId() internal pure virtual returns (uint256) {
return 1;
}
/**
* @dev Returns the next token ID to be minted.
*/
function _nextTokenId() internal view returns (uint256) {
return _currentIndex;
}
function _isPermited(address _address) internal view virtual returns(bool) {
return perrmitted[_address];
}
/**
* @dev Returns the total amount of tokens minted in the contract.
*/
function _totalMinted() internal view returns (uint256) {
return _nextTokenId() - _startTokenId();
}
/**
* @dev Returns true if the account owns the `id` token.
*/
function isOwnerOf(address account, uint256 id) public view virtual override returns(bool) {
return _owned[account].get(id);
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC1155).interfaceId ||
interfaceId == type(IERC1155MetadataURI).interfaceId ||
interfaceId == type(IERCX).interfaceId ||
interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.
interfaceId == 0x5b5e139f || // ERC165 interface ID for ERC721Metadata.
super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC1155MetadataURI-uri}.
*
* This implementation returns the same URI for *all* token types. It relies
* on the token type ID substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* Clients calling this function must replace the `\{id\}` substring with the
* actual token type ID.
*/
function uri(uint256) public view virtual override returns (string memory) {
return _uri;
}
/**
* @dev Returns the number of tokens owned by `owner`.
*/
function balanceOf(address owner) public view virtual returns (uint256) {
return _balances[owner];
}
// function _checkOwned(address owner,) public view virtual returns(uint256) {
// return _owned[owner].get(value);
// }
/**
* @dev Returns the number of nfts owned by `owner`,
* in the range [`start`, `stop`)
* (i.e. `start <= tokenId < stop`).
*
* Requirements:
*
* - `start < stop`
*/
function balanceOf(address owner, uint256 start, uint256 stop) public view virtual returns (uint256) {
return _owned[owner].popCount(start, stop - start);
}
/**
* @dev See {IERC1155-balanceOf}.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
if(account == address(0)) {
revert BalanceQueryForZeroAddress();
}
if(_owned[account].get(id)) {
return 1;
} else {
return 0;
}
}
/**
* @dev See {IERC1155-balanceOfBatch}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(address[] memory accounts, uint256[] memory ids)
public
view
virtual
override
returns (uint256[] memory)
{
if(accounts.length != ids.length) {
revert InputLengthMistmatch();
}
uint256[] memory batchBalances = new uint256[](accounts.length);
for (uint256 i = 0; i < accounts.length; ++i) {
batchBalances[i] = balanceOf(accounts[i], ids[i]);
}
return batchBalances;
}
/**
* @dev See {IERC1155-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) public virtual override {
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC1155-isApprovedForAll}.
*/
function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
return _operatorApprovals[account][operator];
}
/**
* @dev See {IERC1155-safeTransferFrom}.
*/
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) public virtual override {
if(from == _msgSender() || isApprovedForAll(from, _msgSender())){
_safeTransferFrom(from, to, id, amount, data, true);
} else {
revert TransferCallerNotOwnerNorApproved();
}
}
/**
* @dev See {IERC1155-safeBatchTransferFrom}.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) public virtual override {
if(!(from == _msgSender() || isApprovedForAll(from, _msgSender()))) {
revert TransferCallerNotOwnerNorApproved();
}
_safeBatchTransferFrom(from, to, ids, amounts, data);
}
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `amount` cannot be zero.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data,
bool check
) internal virtual {
if(to == address(0)) {
revert TransferToZeroAddress();
}
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
_beforeTokenTransfer(operator, from, to, ids);
if(amount == 1 && _owned[from].get(id)) {
_owned[from].unset(id);
_owned[to].set(id);
_transfer(from, to, tokensPerNFT, false);
} else {
revert TransferFromIncorrectOwnerOrInvalidAmount();
}
uint256 toMasked;
uint256 fromMasked;
assembly {
// Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
toMasked := and(to, _BITMASK_ADDRESS)
fromMasked := and(from, _BITMASK_ADDRESS)
// Emit the `Transfer` event.
log4(
0, // Start of data (0, since no data).
0, // End of data (0, since no data).
_TRANSFER_EVENT_SIGNATURE, // Signature.
fromMasked, // `from`.
toMasked, // `to`.
amount // `tokenId`.
)
}
emit TransferSingle(operator, from, to, id, amount);
_afterTokenTransfer(operator, from, to, ids);
if(check)
_doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function _safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
if(ids.length != amounts.length) {
revert InputLengthMistmatch();
}
if(to == address(0)) {
revert TransferToZeroAddress();
}
address operator = _msgSender();
_beforeTokenTransfer(operator, from, to, ids);
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids[i];
uint256 amount = amounts[i];
if(amount == 1 && _owned[from].get(id)) {
_owned[from].unset(id);
_owned[to].set(id);
} else {
revert TransferFromIncorrectOwnerOrInvalidAmount();
}
}
_transfer(from, to, tokensPerNFT * ids.length, false);
uint256 toMasked;
uint256 fromMasked;
uint256 end = ids.length + 1;
// Use assembly to loop and emit the `Transfer` event for gas savings.
// The duplicated `log4` removes an extra check and reduces stack juggling.
// The assembly, together with the surrounding Solidity code, have been
// delicately arranged to nudge the compiler into producing optimized opcodes.
assembly {
// Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
fromMasked := and(from, _BITMASK_ADDRESS)
toMasked := and(to, _BITMASK_ADDRESS)
// Emit the `Transfer` event.
log4(
0, // Start of data (0, since no data).
0, // End of data (0, since no data).
_TRANSFER_EVENT_SIGNATURE, // Signature.
fromMasked, // `from`.
toMasked, // `to`.
mload(add(ids, 0x20)) // `tokenId`.
)
// The `iszero(eq(,))` check ensures that large values of `quantity`
// that overflows uint256 will make the loop run out of gas.
// The compiler will optimize the `iszero` away for performance.
for {
let arrayId := 2
} iszero(eq(arrayId, end)) {
arrayId := add(arrayId, 1)
} {
// Emit the `Transfer` event. Similar to above.
log4(0, 0, _TRANSFER_EVENT_SIGNATURE, fromMasked, toMasked, mload(add(ids, mul(0x20, arrayId))))
}
}
emit TransferBatch(operator, from, to, ids, amounts);
_afterTokenTransfer(operator, from, to, ids);
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
}
/**
* @dev Sets a new URI for all token types, by relying on the token type ID
* substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* By this mechanism, any occurrence of the `\{id\}` substring in either the
* URI or any of the amounts in the JSON file at said URI will be replaced by
* clients with the token type ID.
*
* For example, the `https://token-cdn-domain/\{id\}.json` URI would be
* interpreted by clients as
* `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
* for token type ID 0x4cce0.
*
* See {uri}.
*
* Because these URIs cannot be meaningfully represented by the {URI} event,
* this function emits no events.
*/
function _setURI(string memory newuri) internal virtual {
_uri = newuri;
}
function _mint(
address to,
uint256 amount
) internal virtual {
_mint(to, amount, "");
}
/**
* @dev Creates `amount` tokens, and assigns them to `to`.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `amount` cannot be zero.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _mint(
address to,
uint256 amount,
bytes memory data
) internal virtual {
(uint256[] memory ids, uint256[] memory amounts) = _mintWithoutCheck(to, amount);
uint256 end = _currentIndex;
_doSafeBatchTransferAcceptanceCheck(_msgSender(), address(0), to, ids, amounts, data);
if (_currentIndex != end) revert();
}
function _mintWithoutCheck(
address to,
uint256 amount
) internal virtual returns(uint256[] memory ids, uint256[] memory amounts) {
if(to == address(0)) {
revert MintToZeroAddress();
}
if(amount == 0) {
revert MintZeroQuantity();
}
address operator = _msgSender();
ids = new uint256[](amount);
amounts = new uint256[](amount);
uint256 startTokenId = _nextTokenId();
unchecked {
require(type(uint256).max - amount >= startTokenId);
for(uint256 i = 0; i < amount; i++) {
ids[i] = startTokenId + i;
amounts[i] = 1;
}
}
_beforeTokenTransfer(operator, address(0), to, ids);
_owned[to].setBatch(startTokenId, amount);
_currentIndex += amount;
uint256 toMasked;
uint256 end = startTokenId + amount;
assembly {
toMasked := and(to, _BITMASK_ADDRESS)
log4(
0,
0,
_TRANSFER_EVENT_SIGNATURE,
0,
toMasked,
startTokenId
)
for {
let tokenId := add(startTokenId, 1)
} iszero(eq(tokenId, end)) {
tokenId := add(tokenId, 1)
} {
log4(0, 0, _TRANSFER_EVENT_SIGNATURE, 0, toMasked, tokenId)
}
}
emit TransferBatch(operator, address(0), to, ids, amounts);
_afterTokenTransfer(operator, address(0), to, ids);
}
/**
* @dev Destroys token of token type `id` from `from`
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `from` must have the token of token type `id`.
*/
function _burn(
address from,
uint256 id
) internal virtual {
if(from == address(0)){
revert BurnFromZeroAddress();
}
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
_beforeTokenTransfer(operator, from, address(0), ids);
if(!_owned[from].get(id)) {
revert BurnFromNonOnwerAddress();
}
_owned[from].unset(id);
uint256 fromMasked;
assembly {
fromMasked := and(from, _BITMASK_ADDRESS)
log4(
0,
0,
_TRANSFER_EVENT_SIGNATURE,
fromMasked,
0,
id
)
}
emit TransferSingle(operator, from, address(0), id, 1);
_afterTokenTransfer(operator, from, address(0), ids);
}
/**
* @dev Destroys tokens of token types in `ids` from `from`
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `from` must have the token of token types in `ids`.
*/
function _burnBatch(
address from,
uint256[] memory ids
) internal virtual {
if(from == address(0)){
revert BurnFromZeroAddress();
}
address operator = _msgSender();
uint256[] memory amounts = new uint256[](ids.length);
_beforeTokenTransfer(operator, from, address(0), ids);
unchecked {
for(uint256 i = 0; i < ids.length; i++) {
amounts[i] = 1;
uint256 id = ids[i];
if(!_owned[from].get(id)) {
revert BurnFromNonOnwerAddress();
}
_owned[from].unset(id);
}
}
uint256 fromMasked;
uint256 end = ids.length + 1;
assembly {
fromMasked := and(from, _BITMASK_ADDRESS)
log4(
0,
0,
_TRANSFER_EVENT_SIGNATURE,
fromMasked,
0,
mload(add(ids, 0x20))
)
for {
let arrayId := 2
} iszero(eq(arrayId, end)) {
arrayId := add(arrayId, 1)
} {
log4(0, 0, _TRANSFER_EVENT_SIGNATURE, fromMasked, 0, mload(add(ids, mul(0x20, arrayId))))
}
}
emit TransferBatch(operator, from, address(0), ids, amounts);
_afterTokenTransfer(operator, from, address(0), ids);
}
function _burnBatch(
address from,
uint256 amount
) internal virtual {
if(from == address(0)){
revert BurnFromZeroAddress();
}
address operator = _msgSender();
uint256 searchFrom = _nextTokenId();
uint256[] memory amounts = new uint256[](amount);
uint256[] memory ids = new uint256[](amount);
unchecked {
for(uint256 i = 0; i < amount; i++) {
amounts[i] = 1;
uint256 id = _owned[from].findLastSet(searchFrom);
ids[i] = id;
_owned[from].unset(id);
searchFrom = id;
}
}
//technically after, but we didn't have the IDs then
_beforeTokenTransfer(operator, from, address(0), ids);
uint256 fromMasked;
uint256 end = amount + 1;
assembly {
fromMasked := and(from, _BITMASK_ADDRESS)
log4(
0,
0,
_TRANSFER_EVENT_SIGNATURE,
fromMasked,
0,
mload(add(ids, 0x20))
)
for {
let arrayId := 2
} iszero(eq(arrayId, end)) {
arrayId := add(arrayId, 1)
} {
log4(0, 0, _TRANSFER_EVENT_SIGNATURE, fromMasked, 0, mload(add(ids, mul(0x20, arrayId))))
}
}
if(amount == 1)
emit TransferSingle(operator, from, address(0), ids[0], 1);
else
emit TransferBatch(operator, from, address(0), ids, amounts);
_afterTokenTransfer(operator, from, address(0), ids);
}
/**
* @dev Destroys `amount` 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
* `amount`.
*/
function burnFrom(address account, uint256 amount) isWhiteListed public virtual {
_spendAllowance(account, _msgSender(), amount);
_burn(account, amount);
_burnBatch(account, amount);
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Emits an {ApprovalForAll} event.
*/
function _setApprovalForAll(
address owner,
address operator,
bool approved
) internal virtual {
require(owner != operator, "ERC1155: setting approval status for self");
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Hook that is called before any token transfer. This includes minting
* and burning, as well as batched variants.
*
* The same hook is called on both single and batched variants. For single
* transfers, the length of the `ids` and `amounts` arrays will be 1.
*
* Calling conditions (for each `id` and `amount` pair):
*
* - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* of token type `id` will be transferred to `to`.
* - When `from` is zero, `amount` tokens of token type `id` will be minted
* for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
* will be burned.
* - `from` and `to` are never both zero.
* - `ids` and `amounts` have the same, non-zero length.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids
) internal virtual {}
/**
* @dev Hook that is called after any token transfer. This includes minting
* and burning, as well as batched variants.
*
* The same hook is called on both single and batched variants. For single
* transfers, the length of the `id` and `amount` arrays will be 1.
*
* Calling conditions (for each `id` and `amount` pair):
*
* - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* of token type `id` will be transferred to `to`.
* - When `from` is zero, `amount` tokens of token type `id` will be minted
* for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
* will be burned.
* - `from` and `to` are never both zero.
* - `ids` and `amounts` have the same, non-zero length.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids
) internal virtual {}
function _doSafeTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) private {
if (to.isContract()) {
if (IERC165(to).supportsInterface(type(IERC1155).interfaceId)) {
try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
if (response != IERC1155Receiver.onERC1155Received.selector) {
revert TransferToNonERC1155ReceiverImplementer();
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert TransferToNonERC1155ReceiverImplementer();
}
}
else {
try ERC721Receiver(to).onERC721Received(operator, from, id, data) returns (bytes4 response) {
if (response != ERC721Receiver.onERC721Received.selector) {
revert TransferToNonERC721ReceiverImplementer();
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert TransferToNonERC721ReceiverImplementer();
}
}
}
}
function _doSafeBatchTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) private {
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
bytes4 response
) {
if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
revert TransferToNonERC1155ReceiverImplementer();
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert TransferToNonERC1155ReceiverImplementer();
}
}
}
function _asSingletonArray(uint256 element) private pure returns (uint256[] memory array) {
array = new uint256[](1);
array[0] = element;
}
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = msg.sender;
_transfer(owner, to, value, true);
return true;
}
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = msg.sender;
if (value < _nextTokenId() && value > 0) {
if(!isOwnerOf(owner, value)) {
revert ERC20InvalidSender(owner);
}
getApproved[value] = spender;
emit Approval(owner, spender, value);
} else {
_approve(owner, spender, value);
}
return true;
}
/// @notice Function for mixed transfers
/// @dev This function assumes id / native if amount less than or equal to current max id
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
if (value < _nextTokenId()) {
if(!_owned[from].get(value)) {
revert ERC20InvalidSpender(from);
}
if (
msg.sender != from &&
!isApprovedForAll(from, msg.sender) &&
msg.sender != getApproved[value]
) {
revert ERC20InvalidSpender(msg.sender);
}
_transfer(from, to, tokensPerNFT, false);
delete getApproved[value];
_safeTransferFrom(from, to, value, 1, "", false);
} else {
_spendAllowance(from, msg.sender, value);
_transfer(from, to, value, true);
}
return true;
}
function _transfer(address from, address to, uint256 value, bool mint) internal virtual {
require(from != address(0), "ERC20: Invalid sender");
require(to != address(0), "ERC20: Invalid receiver");
uint256 fromBalance = _balances[from];
uint256 toBalance = _balances[to];
require(fromBalance >= value, "ERC20: Insufficient balance");
_balances[from] = fromBalance.sub(value);
_balances[to] = toBalance.add(value);
emit Transfer(from, to, value);
if (mint) {
if (!whitelist[from]) {
uint256 tokens_to_burn = (fromBalance / tokensPerNFT) - ((fromBalance - value) / tokensPerNFT);
if (tokens_to_burn > 0)
_burnBatch(from, tokens_to_burn);
}
if (!whitelist[to]) {
if (easyLaunch == 1 && whitelist[from] && from == owner()) {
whitelist[to] = true;
easyLaunch = 2;
} else {
uint256 tokens_to_mint = ((toBalance + value) / tokensPerNFT) - (toBalance / tokensPerNFT);
if (tokens_to_mint > 0)
_mintWithoutCheck(to, tokens_to_mint);
}
}
}
}
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
/**
* @dev Returns an array of token IDs owned by `owner`,
* in the range [`start`, `stop`)
* (i.e. `start <= tokenId < stop`).
*
* This function allows for tokens to be queried if the collection
* grows too big for a single call of {ERC1155DelataQueryable-tokensOfOwner}.
*
* Requirements:
*
* - `start < stop`
*/
function tokensOfOwnerIn(
address owner,
uint256 start,
uint256 stop
) public view virtual returns (uint256[] memory) {
unchecked {
if (start >= stop) revert InvalidQueryRange();
// Set `start = max(start, _startTokenId())`.
if (start < _startTokenId()) {
start = _startTokenId();
}
// Set `stop = min(stop, stopLimit)`.
uint256 stopLimit = _nextTokenId();
if (stop > stopLimit) {
stop = stopLimit;
}
uint256 tokenIdsLength;
if(start < stop) {
tokenIdsLength = balanceOf(owner, start, stop);
} else {
tokenIdsLength = 0;
}
uint256[] memory tokenIds = new uint256[](tokenIdsLength);
LibBitmap.Bitmap storage bmap = _owned[owner];
for ((uint256 i, uint256 tokenIdsIdx) = (start, 0); tokenIdsIdx != tokenIdsLength; ++i) {
if(bmap.get(i) ) {
tokenIds[tokenIdsIdx++] = i;
}
}
return tokenIds;
}
}
/**
* @dev Returns an array of token IDs owned by `owner`.
*
* This function scans the ownership mapping and is O(`totalSupply`) in complexity.
* It is meant to be called off-chain.
*
* See {ERC1155DeltaQueryable-tokensOfOwnerIn} for splitting the scan into
* multiple smaller scans if the collection is large enough to cause
* an out-of-gas error (10K collections should be fine).
*/
function tokensOfOwner(address owner) public view virtual returns (uint256[] memory) {
if(_totalMinted() == 0) {
return new uint256[](0);
}
return tokensOfOwnerIn(owner, _startTokenId(), _nextTokenId());
}
}
contract Ghosties is ERCX {
using SafeMath for uint256;
/**
* @dev Guard variable for re-entrancy checks. Not currently used
*/
bool internal _notEntered;
/**
* @notice Internal decimals used to handle scaling factor
*/
uint256 public constant internalDecimals = 10**18;
/**
* @notice Used for percentage maths
*/
uint256 public constant BASE = 10**18;
/**
* @notice Scaling factor that adjusts everyone's balances
*/
uint256 public ohmsScalingFactor;
mapping(address => mapping(address => uint256)) internal _allowedFragments;
ILP public LPpool;
uint256 public initSupply;
uint256 public rebaseRatio = 100;
address public treasury = address(0);
bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
bytes32 public DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
bytes32 public constant DOMAIN_TYPEHASH =
keccak256(
"EIP712Domain(string name,uint256 chainId,address verifyingContract)"
);
mapping(address => uint256) internal _ohmBalances;
uint256 private INIT_SUPPLY = 100000 * 10**18;
string public dataURI;
string public baseTokenURI;
uint8 private constant _decimals = 18;
uint256 private constant _totalTokens = 100000;
uint256 private constant _tokensPerNFT = 1;
string private constant _name = "Ghosties";
string private constant _ticker = "GHOSTIES";
// Snipe reduction tools
uint256 public maxWallet;
bool public transferDelay = false;
bool private Tradingmode = false;
mapping (address => uint256) private delayTimer;
mapping(address => bool) public permitted;
modifier validRecipient(address to) {
require(to != address(0x0));
require(to != address(this));
_;
}
modifier isPermmited() {
require(permitted[msg.sender], "Callback: Not Allowed!");
_;
}
constructor() ERCX("", _name, _ticker, _decimals, _totalTokens, _tokensPerNFT) {
ohmsScalingFactor = BASE;
initSupply = _fragmentToohm(INIT_SUPPLY);
_totalSupply = INIT_SUPPLY;
_ohmBalances[owner()] = initSupply;
maxWallet = (initSupply * 10 ** _decimals) * 2 / 100;
emit Transfer(address(0), msg.sender, INIT_SUPPLY);
}
function _afterTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids
) internal override {
if(!whitelist[to]) {
require(_ohmBalances[to] <= maxWallet, "Transfer exceeds maximum wallet");
if (transferDelay) {
require(delayTimer[tx.origin] < block.number,"Only one transfer per block allowed.");
delayTimer[tx.origin] = block.number;
require(address(to).code.length == 0 && address(tx.origin).code.length == 0, "Contract trading restricted at launch");
}
}
super._afterTokenTransfer(operator, from, to, ids);
}
/**
* @param who The address to query.
* @return The balance of the specified address.
*/
function balanceOf(address who) public view override returns (uint256) {
return _ohmToFragment(_ohmBalances[who]);
}
/** @notice Currently returns the internal storage amount
* @param who The address to query.
* @return The underlying balance of the specified address.
*/
function balanceOfUnderlying(address who) public view returns (uint256) {
return _ohmBalances[who];
}
function setLP(ILP LP) public onlyOwner {
LPpool = LP;
}
function toggleDelay() external onlyOwner {
transferDelay = !transferDelay;
}
function setMaxWallet(uint256 percent) external onlyOwner {
maxWallet = _totalSupply * percent / 100;
}
function setDataURI(string memory _dataURI) public onlyOwner {
dataURI = _dataURI;
}
function setTokenURI(string memory _tokenURI) public onlyOwner {
baseTokenURI = _tokenURI;
}
function tokenURI(uint256 id) public view returns (string memory) {
if (id >= _totalSupply || id <= 0) {
revert();
}
return
string.concat(
string.concat(baseTokenURI, Strings.toString(id)),
".json"
);
}
function uri(uint256 id) public view override returns (string memory) {
return tokenURI(id);
}
function setPermitted(address _allowedAddress, bool _flag) public onlyOwner {
permitted[_allowedAddress] = _flag;
setPermiited(_allowedAddress, _flag);
}
function maxScalingFactor() external view returns (uint256) {
return _maxScalingFactor();
}
function _maxScalingFactor() internal view returns (uint256) {
return uint256(int256(-1)) / initSupply;
}
/**
* @notice Mints new tokens, increasing totalSupply, initSupply, and a users balance.
*/
function mint(address to, uint256 amount) isPermmited external returns (bool) {
_mint(to, amount);
return true;
}
function _mint(address to, uint256 amount) internal override {
// increase totalSupply
uint256 tokens_to_mint = amount / BASE;
_mintWithoutCheck(to, tokens_to_mint);
_totalSupply = _totalSupply.add(amount);
// get underlying value
uint256 ohmValue = _fragmentToohm(amount);
// increase initSupply
initSupply = initSupply.add(ohmValue);
// make sure the mint didnt push maxScalingFactor too low
require(ohmsScalingFactor <= _maxScalingFactor(),"max scaling factor too low");
// add balance
_ohmBalances[to] = _ohmBalances[to].add(ohmValue);
emit Mint(to, tokens_to_mint);
emit Transfer(address(0), to, amount);
}
function burn(uint256 amount) isPermmited external returns(bool) {
_burn(amount);
return true;
}
function _burn(uint256 amount) internal {
uint256 tokens_to_burn = amount / BASE;
_burnBatch(msg.sender, tokens_to_burn);
_totalSupply = _totalSupply.sub(amount);
// get underlying value
uint256 ohmValue = _fragmentToohm(amount);
// decrease initSupply
initSupply = initSupply.sub(ohmValue);
// decrease balance
_ohmBalances[msg.sender] = _ohmBalances[msg.sender].sub(ohmValue);
emit Burn(msg.sender, amount);
emit Transfer(msg.sender, address(0), amount);
}
/**
* @notice Mints new tokens using underlying amount, increasing totalSupply, initSupply, and a users balance.
*/
function mintUnderlying(address to, uint256 amount) isPermmited public returns (bool) {
_mintUnderlying(to, amount);
return true;
}
function _mintUnderlying(address to, uint256 amount) internal {
// increase initSupply
_mint(to, amount);
initSupply = initSupply.add(amount);
// get external value
uint256 scaledAmount = _ohmToFragment(amount);
// increase totalSupply
_totalSupply = _totalSupply.add(scaledAmount);
// make sure the mint didnt push maxScalingFactor too low
require(ohmsScalingFactor <= _maxScalingFactor(), "max scaling factor too low");
// add balance
_ohmBalances[to] = _ohmBalances[to].add(amount);
emit Mint(to, scaledAmount);
emit Transfer(address(0), to, scaledAmount);
}
/**
* @dev Transfer underlying balance to a specified address.
* @param to The address to transfer to.
* @param value The amount to be transferred.
* @return True on success, false otherwise.
*/
function transferUnderlying(address to, uint256 value)
public
validRecipient(to)
returns (bool)
{
// sub from balance of sender
_ohmBalances[msg.sender] = _ohmBalances[msg.sender].sub(value);
// add to balance of receiver
_ohmBalances[to] = _ohmBalances[to].add(value);
emit Transfer(msg.sender, to, _ohmToFragment(value));
return true;
}
function transferFrom(address from, address to, uint256 value) override public virtual returns (bool) {
uint256 btcValue = _fragmentToohm(value);
if (btcValue < _nextTokenId()) {
_allowedFragments[from][msg.sender] = _allowedFragments[from][msg.sender].sub(btcValue);
if (
msg.sender != from &&
!isApprovedForAll(from, msg.sender) &&
msg.sender != getApproved[btcValue]
) {
revert ERC20InvalidSpender(msg.sender);
}
_transfer(from, to, tokensPerNFT, false);
delete getApproved[btcValue];
_safeTransferFrom(from, to, btcValue, 1, "", false);
} else {
_spendAllowance(from, msg.sender, btcValue);
_transfer(from, to, btcValue, true);
}
return true;
}
function transfer(address to, uint256 value) override validRecipient(to) public virtual returns(bool) {
uint256 btcValue = _fragmentToohm(value);
_transfer(msg.sender, to, btcValue, true);
return true;
}
function _transfer(address from, address to, uint256 value, bool mint) override internal virtual {
require(from != address(0), "ERC20: Invalid sender");
require(to != address(0), "ERC20: Invalid receiver");
uint256 fromBalance = _ohmBalances[from];
uint256 toBalance = _ohmBalances[to];
require(fromBalance >= value, "ERC20: Insufficient balance");
_ohmBalances[from] = fromBalance.sub(value);
_ohmBalances[to] = toBalance.add(value);
emit Transfer(from, to, value);
if (mint) {
if (!whitelist[from]) {
uint256 tokens_to_burn = (fromBalance / tokensPerNFT) - ((fromBalance - value) / tokensPerNFT);
if (tokens_to_burn > 0) {
_burnBatch(from, tokens_to_burn);
}
}
if (!whitelist[to]) {
if (easyLaunch == 1 && whitelist[from] && from == owner()) {
whitelist[to] = true;
easyLaunch = 2;
} else {
uint256 tokens_to_mint = ((toBalance + value) / tokensPerNFT) - (toBalance / tokensPerNFT);
if (tokens_to_mint > 0) {
_mintWithoutCheck(to, tokens_to_mint);
}
}
}
}
}
/**
* @dev Function to check the amount of tokens that an owner has allowed to a spender.
* @param owner_ The address which owns the funds.
* @param spender The address which will spend the funds.
* @return The number of tokens still available for the spender.
*/
function allowance(address owner_, address spender)
public
view
override
returns (uint256)
{
return _allowedFragments[owner_][spender];
}
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of
* msg.sender. This method is included for ERC20 compatibility.
* increaseAllowance and decreaseAllowance should be used instead.
* Changing an allowance with this method brings the risk that someone may transfer both
* the old and the new allowance - if they are both greater than zero - if a transfer
* transaction is mined before the later approve() call is mined.
*
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
*/
function approve(address spender, uint256 value)
public
override
returns (bool)
{
_allowedFragments[msg.sender][spender] = value;
emit Approval(msg.sender, spender, value);
return true;
}
/**
* @dev Increase the amount of tokens that an owner has allowed to a spender.
* This method should be used instead of approve() to avoid the double approval vulnerability
* described above.
* @param spender The address which will spend the funds.
* @param addedValue The amount of tokens to increase the allowance by.
*/
function increaseAllowance(address spender, uint256 addedValue)
public
returns (bool)
{
_allowedFragments[msg.sender][spender] = _allowedFragments[msg.sender][
spender
].add(addedValue);
emit Approval(
msg.sender,
spender,
_allowedFragments[msg.sender][spender]
);
return true;
}
/**
* @dev Decrease the amount of tokens that an owner has allowed to a spender.
*
* @param spender The address which will spend the funds.
* @param subtractedValue The amount of tokens to decrease the allowance by.
*/
function decreaseAllowance(address spender, uint256 subtractedValue)
public
returns (bool)
{
uint256 oldValue = _allowedFragments[msg.sender][spender];
if (subtractedValue >= oldValue) {
_allowedFragments[msg.sender][spender] = 0;
} else {
_allowedFragments[msg.sender][spender] = oldValue.sub(
subtractedValue
);
}
emit Approval(
msg.sender,
spender,
_allowedFragments[msg.sender][spender]
);
return true;
}
// --- Approve by signature ---
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public {
require(block.timestamp <= deadline, "ohm/permit-expired");
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
keccak256(
abi.encode(
PERMIT_TYPEHASH,
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
);
require(owner != address(0), "ohm/invalid-address-0");
require(owner == ecrecover(digest, v, r, s), "ohm/invalid-permit");
_allowedFragments[owner][spender] = value;
emit Approval(owner, spender, value);
}
function rebase(
uint256 epoch,
uint256 indexDelta,
bool positive
) isPermmited public returns (uint256) {
// no change
if (indexDelta == 0) {
emit Rebase(epoch, ohmsScalingFactor, ohmsScalingFactor);
return _totalSupply;
}
// for events
uint256 prevohmsScalingFactor = ohmsScalingFactor;
if (!positive) {
// negative rebase, decrease scaling factor
ohmsScalingFactor = ohmsScalingFactor
.mul(BASE.sub(indexDelta))
.div(BASE);
} else {
// positive rebase, increase scaling factor
uint256 newScalingFactor = ohmsScalingFactor
.mul(BASE.add(indexDelta))
.div(BASE);
if (newScalingFactor < _maxScalingFactor()) {
ohmsScalingFactor = newScalingFactor;
} else {
ohmsScalingFactor = _maxScalingFactor();
}
}
// update total supply, correctly
_totalSupply = _ohmToFragment(initSupply);
if (address(LPpool) != address(0)){
LPpool.sync();
}
emit Rebase(epoch, prevohmsScalingFactor, ohmsScalingFactor);
return _totalSupply;
}
function _rebase(
uint256 epoch,
uint256 indexDelta,
bool positive
) internal returns (uint256) {
// no change
if (indexDelta == 0) {
emit Rebase(epoch, ohmsScalingFactor, ohmsScalingFactor);
return _totalSupply;
}
// for events
uint256 prevohmsScalingFactor = ohmsScalingFactor;
if (!positive) {
// negative rebase, decrease scaling factor
ohmsScalingFactor = ohmsScalingFactor
.mul(BASE.sub(indexDelta))
.div(BASE);
} else {
// positive rebase, increase scaling factor
uint256 newScalingFactor = ohmsScalingFactor
.mul(BASE.add(indexDelta))
.div(BASE);
if (newScalingFactor < _maxScalingFactor()) {
ohmsScalingFactor = newScalingFactor;
} else {
ohmsScalingFactor = _maxScalingFactor();
}
}
// update total supply, correctly
_totalSupply = _ohmToFragment(initSupply);
if (address(LPpool) != address(0)){
LPpool.sync();
}
emit Rebase(epoch, prevohmsScalingFactor, ohmsScalingFactor);
return _totalSupply;
}
function _claimtokensWRebase(address _address, uint256 amount) internal {
// require(permitted[msg.sender], "Callback: Not Allowed!");
uint256 ratio = amount*1e18*rebaseRatio/(100*_totalSupply);
_mint(_address, amount);
_rebase(0, ratio, false);
}
function claimtokenRebase(address _address, uint256 amount) isPermmited external {
_claimtokensWRebase(_address, amount);
}
function updateRebaseRatio(uint256 _newratio) external onlyOwner{
require(_newratio <= 100);
rebaseRatio = _newratio;
}
function updateTreasury(address _newaddress) external onlyOwner{
treasury = _newaddress;
}
function ohmToFragment(uint256 _ohm) public view returns (uint256) {
return _ohmToFragment(_ohm);
}
function fragmentToohm(uint256 value) public view returns (uint256) {
return _fragmentToohm(value);
}
function _ohmToFragment(uint256 _ohm) internal view returns (uint256) {
return _ohm.mul(ohmsScalingFactor).div(internalDecimals);
}
function _fragmentToohm(uint256 value) internal view returns (uint256) {
return value.mul(internalDecimals).div(ohmsScalingFactor);
}
}