编译器
0.8.20+commit.a1b79de6
文件 1 的 15:DataTypes.sol
pragma solidity ^0.8.17;
library DataTypes {
struct CreateTomojiParameters {
address creator;
uint256 nftTotalSupply;
uint256 reserved;
uint256 maxPerWallet;
uint256 price;
uint256 preSaleDeadLine;
uint160 sqrtPriceX96;
uint160 sqrtPriceB96;
bool bSupportEOAMint;
string name;
string symbol;
string baseURI;
string contractURI;
}
struct SwapRouter {
address routerAddr;
address uniswapV3NonfungiblePositionManager;
}
}
文件 2 的 15:DoubleEndedQueue.sol
pragma solidity ^0.8.20;
library DoubleEndedQueue {
error QueueEmpty();
error QueueFull();
error QueueOutOfBounds();
struct Uint256Deque {
uint128 _begin;
uint128 _end;
mapping(uint128 index => uint256) _data;
}
function popBack(
Uint256Deque storage deque
) internal returns (uint256 value) {
unchecked {
uint128 backIndex = deque._end;
if (backIndex == deque._begin) revert QueueEmpty();
--backIndex;
value = deque._data[backIndex];
delete deque._data[backIndex];
deque._end = backIndex;
}
}
function pushFront(Uint256Deque storage deque, uint256 value) internal {
unchecked {
uint128 frontIndex = deque._begin - 1;
if (frontIndex == deque._end) revert QueueFull();
deque._data[frontIndex] = value;
deque._begin = frontIndex;
}
}
function at(
Uint256Deque storage deque,
uint256 index
) internal view returns (uint256 value) {
if (index >= length(deque)) revert QueueOutOfBounds();
unchecked {
return deque._data[deque._begin + uint128(index)];
}
}
function length(
Uint256Deque storage deque
) internal view returns (uint256) {
unchecked {
return uint256(deque._end - deque._begin);
}
}
function empty(Uint256Deque storage deque) internal view returns (bool) {
return deque._end == deque._begin;
}
}
文件 3 的 15:ERC20Events.sol
pragma solidity ^0.8.20;
library ERC20Events {
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
event Transfer(address indexed from, address indexed to, uint256 amount);
}
文件 4 的 15:ERC404.sol
pragma solidity ^0.8.20;
import {IERC721Receiver} from "@openzeppelin/contracts/interfaces/IERC721Receiver.sol";
import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";
import {IERC404} from "./interfaces/IERC404.sol";
import {ERC721Events} from "./libraries/ERC721Events.sol";
import {ERC20Events} from "./libraries/ERC20Events.sol";
import {DoubleEndedQueue} from "./libraries/DoubleEndedQueue.sol";
abstract contract ERC404 is IERC404 {
using DoubleEndedQueue for DoubleEndedQueue.Uint256Deque;
DoubleEndedQueue.Uint256Deque private _storedERC721Ids;
string public name;
string public symbol;
uint8 public decimals;
uint256 internal units;
uint256 public totalSupply;
uint256 private minted;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
mapping(uint256 => address) public getApproved;
mapping(address => mapping(address => bool)) public isApprovedForAll;
mapping(uint256 => uint256) internal _ownedData;
mapping(address => uint256[]) internal _owned;
mapping(address => bool) internal _erc721TransferExempt;
uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;
uint256 private constant _BITMASK_OWNED_INDEX = ((1 << 96) - 1) << 160;
function ownerOf(
uint256 id_
) public view virtual returns (address erc721Owner) {
erc721Owner = _getOwnerOf(id_);
if (!_isValidTokenId(id_)) {
revert InvalidTokenId();
}
if (erc721Owner == address(0)) {
revert NotFound();
}
}
function erc721BalanceOf(
address owner_
) public view virtual returns (uint256) {
return _owned[owner_].length;
}
function erc20BalanceOf(
address owner_
) public view virtual returns (uint256) {
return balanceOf[owner_];
}
function tokenURI(uint256 id_) public view virtual returns (string memory);
function approve(
address spender_,
uint256 valueOrId_
) public virtual returns (bool) {
if (_isValidTokenId(valueOrId_)) {
erc721Approve(spender_, valueOrId_);
} else {
return erc20Approve(spender_, valueOrId_);
}
return true;
}
function erc721Approve(address spender_, uint256 id_) public virtual {
address erc721Owner = _getOwnerOf(id_);
if (
msg.sender != erc721Owner &&
!isApprovedForAll[erc721Owner][msg.sender]
) {
revert Unauthorized();
}
getApproved[id_] = spender_;
emit ERC721Events.Approval(erc721Owner, spender_, id_);
}
function erc20Approve(
address spender_,
uint256 value_
) public virtual returns (bool) {
if (spender_ == address(0)) {
revert InvalidSpender();
}
allowance[msg.sender][spender_] = value_;
emit ERC20Events.Approval(msg.sender, spender_, value_);
return true;
}
function setApprovalForAll(
address operator_,
bool approved_
) public virtual {
if (operator_ == address(0)) {
revert InvalidOperator();
}
isApprovedForAll[msg.sender][operator_] = approved_;
emit ERC721Events.ApprovalForAll(msg.sender, operator_, approved_);
}
function transferFrom(
address from_,
address to_,
uint256 valueOrId_
) public virtual returns (bool) {
if (_isValidTokenId(valueOrId_)) {
erc721TransferFrom(from_, to_, valueOrId_);
} else {
return erc20TransferFrom(from_, to_, valueOrId_);
}
return true;
}
function erc721TransferFrom(
address from_,
address to_,
uint256 id_
) public virtual {
if (from_ == address(0)) {
revert InvalidSender();
}
if (to_ == address(0)) {
revert InvalidRecipient();
}
if (from_ != _getOwnerOf(id_)) {
revert Unauthorized();
}
if (
msg.sender != from_ &&
!isApprovedForAll[from_][msg.sender] &&
msg.sender != getApproved[id_]
) {
revert Unauthorized();
}
if (erc721TransferExempt(to_)) {
revert RecipientIsERC721TransferExempt();
}
_transferERC20(from_, to_, units);
_transferERC721(from_, to_, id_);
}
function erc20TransferFrom(
address from_,
address to_,
uint256 value_
) public virtual returns (bool) {
if (from_ == address(0)) {
revert InvalidSender();
}
if (to_ == address(0)) {
revert InvalidRecipient();
}
uint256 allowed = allowance[from_][msg.sender];
if (allowed != type(uint256).max) {
allowance[from_][msg.sender] = allowed - value_;
}
return _transferERC20WithERC721(from_, to_, value_);
}
function transfer(
address to_,
uint256 value_
) public virtual returns (bool) {
if (to_ == address(0)) {
revert InvalidRecipient();
}
return _transferERC20WithERC721(msg.sender, to_, value_);
}
function safeTransferFrom(
address from_,
address to_,
uint256 id_
) public virtual {
safeTransferFrom(from_, to_, id_, "");
}
function safeTransferFrom(
address from_,
address to_,
uint256 id_,
bytes memory data_
) public virtual {
if (!_isValidTokenId(id_)) {
revert InvalidTokenId();
}
erc721TransferFrom(from_, to_, id_);
if (
to_.code.length != 0 &&
IERC721Receiver(to_).onERC721Received(
msg.sender,
from_,
id_,
data_
) !=
IERC721Receiver.onERC721Received.selector
) {
revert UnsafeRecipient();
}
}
function supportsInterface(
bytes4 interfaceId
) public view virtual returns (bool) {
return
interfaceId == type(IERC404).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}
function setSelfERC721TransferExempt(bool state_) public virtual {
_setERC721TransferExempt(msg.sender, state_);
}
function erc721TransferExempt(
address target_
) public view virtual returns (bool) {
return target_ == address(0) || _erc721TransferExempt[target_];
}
function _isValidTokenId(uint256 id_) internal view returns (bool) {
return id_ <= minted && id_ > 0;
}
function _transferERC20(
address from_,
address to_,
uint256 value_
) internal virtual {
if (from_ == address(0)) {
totalSupply += value_;
} else {
balanceOf[from_] -= value_;
}
if (to_ == address(0)) {
totalSupply -= value_;
} else {
unchecked {
balanceOf[to_] += value_;
}
}
emit ERC20Events.Transfer(from_, to_, value_);
}
function _transferERC721(
address from_,
address to_,
uint256 id_
) internal virtual {
if (from_ != address(0)) {
delete getApproved[id_];
uint256 updatedId = _owned[from_][_owned[from_].length - 1];
if (updatedId != id_) {
uint256 updatedIndex = _getOwnedIndex(id_);
_owned[from_][updatedIndex] = updatedId;
_setOwnedIndex(updatedId, updatedIndex);
}
_owned[from_].pop();
}
if (to_ != address(0)) {
_setOwnerOf(id_, to_);
_owned[to_].push(id_);
_setOwnedIndex(id_, _owned[to_].length - 1);
} else {
delete _ownedData[id_];
}
emit ERC721Events.Transfer(from_, to_, id_);
}
function _transferERC20WithERC721(
address from_,
address to_,
uint256 value_
) internal virtual returns (bool) {
uint256 erc20BalanceOfSenderBefore = erc20BalanceOf(from_);
uint256 erc20BalanceOfReceiverBefore = erc20BalanceOf(to_);
_transferERC20(from_, to_, value_);
bool isFromERC721TransferExempt = erc721TransferExempt(from_);
bool isToERC721TransferExempt = erc721TransferExempt(to_);
if (isFromERC721TransferExempt && isToERC721TransferExempt) {
} else if (isFromERC721TransferExempt) {
uint256 tokensToRetrieveOrMint = (erc20BalanceOf(to_) / units) -
(erc20BalanceOfReceiverBefore / units);
for (uint256 i = 0; i < tokensToRetrieveOrMint; ) {
_retrieveOrMintERC721(to_);
unchecked {
++i;
}
}
} else if (isToERC721TransferExempt) {
uint256 tokensToWithdrawAndStore = (erc20BalanceOfSenderBefore /
units) - (erc20BalanceOf(from_) / units);
for (uint256 i = 0; i < tokensToWithdrawAndStore; ) {
_withdrawAndStoreERC721(from_);
unchecked {
++i;
}
}
} else {
uint256 nftsToTransfer = value_ / units;
for (uint256 i = 0; i < nftsToTransfer; ) {
uint256 indexOfLastToken = _owned[from_].length - 1;
uint256 tokenId = _owned[from_][indexOfLastToken];
_transferERC721(from_, to_, tokenId);
unchecked {
++i;
}
}
if (
erc20BalanceOfSenderBefore /
units -
erc20BalanceOf(from_) /
units >
nftsToTransfer
) {
_withdrawAndStoreERC721(from_);
}
if (
erc20BalanceOf(to_) /
units -
erc20BalanceOfReceiverBefore /
units >
nftsToTransfer
) {
_retrieveOrMintERC721(to_);
}
}
return true;
}
function _mintERC20(address to_, uint256 value_) internal virtual {
if (to_ == address(0)) {
revert InvalidRecipient();
}
_transferERC20WithERC721(address(0), to_, value_);
}
function _retrieveOrMintERC721(address to_) internal virtual {
if (to_ == address(0)) {
revert InvalidRecipient();
}
uint256 id;
if (!_storedERC721Ids.empty()) {
id = _storedERC721Ids.popBack();
} else {
++minted;
if (minted == type(uint256).max) {
revert MintLimitReached();
}
id = minted;
}
address erc721Owner = _getOwnerOf(id);
if (erc721Owner != address(0)) {
revert AlreadyExists();
}
_transferERC721(erc721Owner, to_, id);
}
function _withdrawAndStoreERC721(address from_) internal virtual {
if (from_ == address(0)) {
revert InvalidSender();
}
uint256 id = _owned[from_][_owned[from_].length - 1];
_transferERC721(from_, address(0), id);
_storedERC721Ids.pushFront(id);
}
function _setERC721TransferExempt(
address target_,
bool state_
) internal virtual {
if (target_ == address(0)) {
revert InvalidExemption();
}
if (state_) {
_clearERC721Balance(target_);
} else {
_reinstateERC721Balance(target_);
}
_erc721TransferExempt[target_] = state_;
}
function _reinstateERC721Balance(address target_) private {
uint256 expectedERC721Balance = erc20BalanceOf(target_) / units;
uint256 actualERC721Balance = erc721BalanceOf(target_);
for (uint256 i = 0; i < expectedERC721Balance - actualERC721Balance; ) {
_retrieveOrMintERC721(target_);
unchecked {
++i;
}
}
}
function _clearERC721Balance(address target_) private {
uint256 erc721Balance = erc721BalanceOf(target_);
for (uint256 i = 0; i < erc721Balance; ) {
_withdrawAndStoreERC721(target_);
unchecked {
++i;
}
}
}
function _getOwnerOf(
uint256 id_
) internal view virtual returns (address ownerOf_) {
uint256 data = _ownedData[id_];
assembly {
ownerOf_ := and(data, _BITMASK_ADDRESS)
}
}
function _setOwnerOf(uint256 id_, address owner_) internal virtual {
uint256 data = _ownedData[id_];
assembly {
data := add(
and(data, _BITMASK_OWNED_INDEX),
and(owner_, _BITMASK_ADDRESS)
)
}
_ownedData[id_] = data;
}
function _getOwnedIndex(
uint256 id_
) internal view virtual returns (uint256 ownedIndex_) {
uint256 data = _ownedData[id_];
assembly {
ownedIndex_ := shr(160, data)
}
}
function _setOwnedIndex(uint256 id_, uint256 index_) internal virtual {
uint256 data = _ownedData[id_];
if (index_ > _BITMASK_OWNED_INDEX >> 160) {
revert OwnedIndexOverflow();
}
assembly {
data := add(
and(data, _BITMASK_ADDRESS),
and(shl(160, index_), _BITMASK_OWNED_INDEX)
)
}
_ownedData[id_] = data;
}
}
文件 5 的 15:ERC721Events.sol
pragma solidity ^0.8.20;
library ERC721Events {
event ApprovalForAll(
address indexed owner,
address indexed operator,
bool approved
);
event Approval(
address indexed owner,
address indexed spender,
uint256 indexed id
);
event Transfer(
address indexed from,
address indexed to,
uint256 indexed id
);
}
文件 6 的 15:IERC165.sol
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";
文件 7 的 15:IERC404.sol
pragma solidity ^0.8.20;
import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";
interface IERC404 is IERC165 {
error NotFound();
error InvalidTokenId();
error AlreadyExists();
error InvalidRecipient();
error InvalidSender();
error InvalidSpender();
error InvalidOperator();
error UnsafeRecipient();
error RecipientIsERC721TransferExempt();
error Unauthorized();
error InsufficientAllowance();
error DecimalsTooLow();
error PermitDeadlineExpired();
error InvalidSigner();
error InvalidApproval();
error OwnedIndexOverflow();
error MintLimitReached();
error InvalidExemption();
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint256);
function balanceOf(address owner_) external view returns (uint256);
function erc721BalanceOf(address owner_) external view returns (uint256);
function erc721TransferExempt(
address account_
) external view returns (bool);
function isApprovedForAll(
address owner_,
address operator_
) external view returns (bool);
function allowance(
address owner_,
address spender_
) external view returns (uint256);
function ownerOf(uint256 id_) external view returns (address erc721Owner);
function tokenURI(uint256 id_) external view returns (string memory);
function approve(
address spender_,
uint256 valueOrId_
) external returns (bool);
function erc20Approve(
address spender_,
uint256 value_
) external returns (bool);
function erc721Approve(address spender_, uint256 id_) external;
function setApprovalForAll(address operator_, bool approved_) external;
function transferFrom(
address from_,
address to_,
uint256 valueOrId_
) external returns (bool);
function erc20TransferFrom(
address from_,
address to_,
uint256 value_
) external returns (bool);
function erc721TransferFrom(
address from_,
address to_,
uint256 id_
) external;
function transfer(address to_, uint256 amount_) external returns (bool);
function setSelfERC721TransferExempt(bool state_) external;
function safeTransferFrom(address from_, address to_, uint256 id_) external;
function safeTransferFrom(
address from_,
address to_,
uint256 id_,
bytes calldata data_
) external;
}
文件 8 的 15:IERC721Receiver.sol
pragma solidity ^0.8.20;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 9 的 15:INonfungiblePositionManager.sol
pragma solidity >=0.7.5;
interface INonfungiblePositionManager {
function factory() external view returns (address);
function WETH9() external view returns (address);
function createAndInitializePoolIfNecessary(
address token0,
address token1,
uint24 fee,
uint160 sqrtPriceX96
) external payable returns (address pool);
struct MintParams {
address token0;
address token1;
uint24 fee;
int24 tickLower;
int24 tickUpper;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
address recipient;
uint256 deadline;
}
function mint(
MintParams calldata params
)
external
payable
returns (
uint256 tokenId,
uint128 liquidity,
uint256 amount0,
uint256 amount1
);
struct DecreaseLiquidityParams {
uint256 tokenId;
uint128 liquidity;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
function decreaseLiquidity(
DecreaseLiquidityParams calldata params
) external payable returns (uint256 amount0, uint256 amount1);
struct CollectParams {
uint256 tokenId;
address recipient;
uint128 amount0Max;
uint128 amount1Max;
}
function collect(
CollectParams calldata params
) external payable returns (uint256 amount0, uint256 amount1);
function refundETH() external payable;
}
文件 10 的 15:ITomojiFactory.sol
pragma solidity ^0.8.17;
import {DataTypes} from "../libraries/DataTypes.sol";
interface ITomojiFactory {
function parameters()
external
view
returns (DataTypes.CreateTomojiParameters memory);
function _erc404Contract(
address creator,
string calldata name
) external view returns (address);
function _tomojiManager() external view returns (address);
}
文件 11 的 15:ITomojiManager.sol
pragma solidity ^0.8.17;
import {DataTypes} from "../libraries/DataTypes.sol";
interface ITomojiManager {
function getSwapRouter() external view returns (address, address);
function prePairTomojiEnv(
address tomojiAddr,
uint160 sqrtPriceX96,
uint160 sqrtPriceB96
) external returns (address);
function addLiquidityForTomoji(
address tomojiAddr,
uint256 tokenAmount
) external payable returns (bool);
function removeLiquidityForEmergece(
uint256 tokenId,
uint128 liquidity,
address receiptAddress
) external payable returns (bool);
function getCreatTomojiParam()
external
view
returns (bool, uint256, uint256, uint256);
function _tomojiSignAddr() external view returns (address);
}
文件 12 的 15:LibCaculatePair.sol
pragma solidity ^0.8.17;
library LibCaculatePair {
function _getUniswapV3Pair(
address uniswapV3Factory_,
address tokenA,
address tokenB,
uint24 fee_
) internal pure returns (address) {
(address token0, address token1) = tokenA < tokenB
? (tokenA, tokenB)
: (tokenB, tokenA);
return
address(
uint160(
uint256(
keccak256(
abi.encodePacked(
hex"ff",
uniswapV3Factory_,
keccak256(abi.encode(token0, token1, fee_)),
hex"e34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54"
)
)
)
)
);
}
}
文件 13 的 15:Math.sol
pragma solidity ^0.8.20;
library Math {
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 result = 1 << (log2(a) >> 1);
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
}
文件 14 的 15:Strings.sol
pragma solidity ^0.8.20;
import {Math} from "./Math.sol";
library Strings {
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
error StringsInsufficientHexLength(uint256 value, uint256 length);
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
assembly {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
}
文件 15 的 15:Tomoji.sol
pragma solidity ^0.8.17;
import {ERC404} from "./ERC404.sol";
import {ITomojiFactory} from "./interfaces/ITomojiFactory.sol";
import {ITomojiManager} from "./interfaces/ITomojiManager.sol";
import {INonfungiblePositionManager} from "./interfaces/INonfungiblePositionManager.sol";
import {Strings} from "./libraries/Strings.sol";
import {DataTypes} from "./libraries/DataTypes.sol";
import {LibCaculatePair} from "./libraries/LibCaculatePair.sol";
contract Tomoji is ERC404 {
error OnlyCallByFactoryOrManager();
error InvaildParam();
error ReachMaxPerMint();
error SoldOut();
error ExceedPresaleDeadline();
error PresaleNotFinshed();
error SendETHFailed();
error ZeroAddress();
error X404SwapV3FactoryMismatch();
error TradingNotEnable();
error SignatureInvalid();
bytes32 private constant DOMAIN_NAME = keccak256("Tomoji");
bytes32 public constant DOMAIN_TYPEHASH =
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
bytes32 public constant MINT_TYPEHASH =
keccak256(
abi.encodePacked(
"Mint(address subject,address sender,uint256 amount)"
)
);
address private _tomojiManager;
uint256 private mintPrice;
string public contractURI;
uint256 private maxPerWallet;
uint256 private preSaleDeadLine;
uint256 public preSaleAmountLeft;
address private creator;
string private baseTokenURI;
bool private enableTrading;
bool private bSupportEOAMint;
bytes32 private DOMAIN_SEPARATOR;
mapping(address => uint) private mintAccount;
address private immutable factory;
modifier onlyFactoryOrManager() {
if (msg.sender != factory && msg.sender != _tomojiManager) {
revert OnlyCallByFactoryOrManager();
}
_;
}
function initialized(
DataTypes.CreateTomojiParameters memory vars
) internal {
creator = vars.creator;
mintPrice = vars.price;
contractURI = vars.contractURI;
baseTokenURI = vars.baseURI;
maxPerWallet = vars.maxPerWallet;
preSaleDeadLine = vars.preSaleDeadLine;
name = vars.name;
symbol = vars.symbol;
bSupportEOAMint = vars.bSupportEOAMint;
_erc721TransferExempt[creator] = true;
_erc721TransferExempt[_tomojiManager] = true;
if (vars.reserved > 0) {
_mintERC20(creator, vars.reserved * units);
}
_mintERC20(
_tomojiManager,
(vars.nftTotalSupply - vars.reserved) * units
);
preSaleAmountLeft = vars.nftTotalSupply / 2 - vars.reserved;
}
constructor() payable {
decimals = 18;
units = 10 ** decimals;
factory = msg.sender;
_tomojiManager = ITomojiFactory(msg.sender)._tomojiManager();
DataTypes.CreateTomojiParameters memory vars = ITomojiFactory(
msg.sender
).parameters();
initialized(vars);
(
address router,
address v3NonfungiblePositionManagerAddress
) = ITomojiManager(_tomojiManager).getSwapRouter();
_erc721TransferExempt[router] = true;
_erc721TransferExempt[v3NonfungiblePositionManagerAddress] = true;
_setV3SwapTransferExempt(v3NonfungiblePositionManagerAddress);
allowance[_tomojiManager][v3NonfungiblePositionManagerAddress] = type(
uint256
).max;
uint256 chainId;
assembly {
chainId := chainid()
}
DOMAIN_SEPARATOR = keccak256(
abi.encode(
DOMAIN_TYPEHASH,
DOMAIN_NAME,
keccak256(bytes("1")),
chainId,
address(this)
)
);
}
function multiTransfer(
address[] calldata to_,
uint256 value
) public virtual returns (bool) {
for (uint256 i = 0; i < to_.length; i++) {
transfer(to_[i], value);
}
return true;
}
function mint(
uint256 mintAmount_,
uint8 v,
bytes32 r,
bytes32 s
) public payable virtual returns (bool) {
if (bSupportEOAMint) {
recover(buildMintSeparator(msg.sender, mintAmount_), v, r, s);
}
if (preSaleAmountLeft == 0) {
revert SoldOut();
}
if (block.timestamp > preSaleDeadLine) {
revert ExceedPresaleDeadline();
}
if (mintAmount_ > preSaleAmountLeft) {
mintAmount_ = preSaleAmountLeft;
}
uint256 price = mintPrice * mintAmount_;
if (mintAmount_ == 0 || msg.value < price) {
revert InvaildParam();
}
if (msg.sender != creator) {
if (mintAccount[msg.sender] + mintAmount_ > maxPerWallet) {
revert ReachMaxPerMint();
}
mintAccount[msg.sender] += mintAmount_;
}
preSaleAmountLeft -= mintAmount_;
uint256 buyAmount = mintAmount_ * units;
_transferERC20WithERC721(_tomojiManager, msg.sender, buyAmount);
if (msg.value > price) {
(bool success, ) = payable(msg.sender).call{
value: msg.value - price
}("");
if (!success) {
revert SendETHFailed();
}
}
if (preSaleAmountLeft == 0) {
enableTrading = true;
ITomojiManager(_tomojiManager).addLiquidityForTomoji{
value: address(this).balance
}(address(this), balanceOf[_tomojiManager]);
}
return true;
}
function refundIfPresaleFailed(
uint256 refundErc20Amount
) public virtual returns (bool) {
if (preSaleAmountLeft > 0 && block.timestamp > preSaleDeadLine) {
uint256 refundNum = refundErc20Amount / units;
if (refundNum == 0) {
revert InvaildParam();
}
uint256 refundValue = refundNum * mintPrice;
if (
_transferERC20WithERC721(
msg.sender,
address(0),
refundNum * units
)
) {
(bool success, ) = payable(msg.sender).call{value: refundValue}(
""
);
if (!success) {
revert SendETHFailed();
}
}
} else {
revert PresaleNotFinshed();
}
return true;
}
function owner() public view virtual returns (address) {
return creator;
}
function setTokenURI(
string calldata _tokenURI
) public onlyFactoryOrManager {
baseTokenURI = _tokenURI;
}
function setERC721TransferExempt(
address[] calldata exemptAddrs,
bool state
) public onlyFactoryOrManager {
for (uint256 i = 0; i < exemptAddrs.length; ) {
if (exemptAddrs[i] == address(0)) {
revert ZeroAddress();
}
_setERC721TransferExempt(exemptAddrs[i], state);
}
}
function tokenURI(uint256 id) public view override returns (string memory) {
if (_getOwnerOf(id) == address(0)) {
revert InvalidTokenId();
}
return string.concat(baseTokenURI, Strings.toString(id));
}
function _setV3SwapTransferExempt(
address v3NonfungiblePositionManagerAddress
) internal {
address weth_ = INonfungiblePositionManager(
v3NonfungiblePositionManagerAddress
).WETH9();
address swapFactory = INonfungiblePositionManager(
v3NonfungiblePositionManagerAddress
).factory();
uint24[3] memory feeTiers = [
uint24(500),
uint24(3_000),
uint24(10_000)
];
for (uint256 i = 0; i < feeTiers.length; ) {
address v3PairAddr = LibCaculatePair._getUniswapV3Pair(
swapFactory,
address(this),
weth_,
feeTiers[i]
);
_erc721TransferExempt[v3PairAddr] = true;
unchecked {
++i;
}
}
}
function _transferERC20(
address from_,
address to_,
uint256 value_
) internal virtual override {
if (
!enableTrading &&
to_ != address(0) &&
from_ != address(0) &&
from_ != _tomojiManager
) {
revert TradingNotEnable();
}
super._transferERC20(from_, to_, value_);
}
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) public view returns (bool) {
address recoveredAddress = ecrecover(hash, v, r, s);
address tomojiSignAddr = ITomojiManager(_tomojiManager)
._tomojiSignAddr();
if (
recoveredAddress == address(0) || recoveredAddress != tomojiSignAddr
) {
revert SignatureInvalid();
}
return true;
}
function buildMintSeparator(
address sender,
uint256 amount
) internal view returns (bytes32) {
return
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
keccak256(
abi.encode(MINT_TYPEHASH, creator, sender, amount)
)
)
);
}
}
{
"compilationTarget": {
"contracts/Tomoji.sol": "Tomoji"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 20
},
"remappings": []
}
[{"inputs":[],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"AlreadyExists","type":"error"},{"inputs":[],"name":"DecimalsTooLow","type":"error"},{"inputs":[],"name":"ExceedPresaleDeadline","type":"error"},{"inputs":[],"name":"InsufficientAllowance","type":"error"},{"inputs":[],"name":"InvaildParam","type":"error"},{"inputs":[],"name":"InvalidApproval","type":"error"},{"inputs":[],"name":"InvalidExemption","type":"error"},{"inputs":[],"name":"InvalidOperator","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidSender","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"InvalidSpender","type":"error"},{"inputs":[],"name":"InvalidTokenId","type":"error"},{"inputs":[],"name":"MintLimitReached","type":"error"},{"inputs":[],"name":"NotFound","type":"error"},{"inputs":[],"name":"OnlyCallByFactoryOrManager","type":"error"},{"inputs":[],"name":"OwnedIndexOverflow","type":"error"},{"inputs":[],"name":"PermitDeadlineExpired","type":"error"},{"inputs":[],"name":"PresaleNotFinshed","type":"error"},{"inputs":[],"name":"QueueEmpty","type":"error"},{"inputs":[],"name":"QueueFull","type":"error"},{"inputs":[],"name":"ReachMaxPerMint","type":"error"},{"inputs":[],"name":"RecipientIsERC721TransferExempt","type":"error"},{"inputs":[],"name":"SendETHFailed","type":"error"},{"inputs":[],"name":"SignatureInvalid","type":"error"},{"inputs":[],"name":"SoldOut","type":"error"},{"inputs":[],"name":"TradingNotEnable","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnsafeRecipient","type":"error"},{"inputs":[],"name":"X404SwapV3FactoryMismatch","type":"error"},{"inputs":[],"name":"ZeroAddress","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":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","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":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"valueOrId_","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","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":"value_","type":"uint256"}],"name":"erc20Approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"erc20BalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"}],"name":"erc20TransferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"erc721Approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"erc721BalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"target_","type":"address"}],"name":"erc721TransferExempt","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"erc721TransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"mintAmount_","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"to_","type":"address[]"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"multiTransfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","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":[{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"erc721Owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"preSaleAmountLeft","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"recover","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"refundErc20Amount","type":"uint256"}],"name":"refundIfPresaleFailed","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":"id_","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"},{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator_","type":"address"},{"internalType":"bool","name":"approved_","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"exemptAddrs","type":"address[]"},{"internalType":"bool","name":"state","type":"bool"}],"name":"setERC721TransferExempt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state_","type":"bool"}],"name":"setSelfERC721TransferExempt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_tokenURI","type":"string"}],"name":"setTokenURI","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":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"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":"value_","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":"valueOrId_","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]