编译器
0.8.24+commit.e11b9ed9
文件 1 的 18:BC404.sol
pragma solidity ^0.8.20;
import './ERC404V2.sol';
import './interfaces/ITokenURIRenderer.sol';
import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/utils/Strings.sol';
contract BC404 is ERC404V2, Ownable {
string public baseTokenURI;
ITokenURIRenderer public renderer;
uint256 public immutable maxMintedCount = type(uint256).max;
error TokenInvalid();
mapping(address => bool) public whitelist;
constructor(
string memory __name,
string memory __symbol,
uint8 __decimals,
uint256 __minted
) ERC404V2(__name, __symbol, __decimals) Ownable(msg.sender) {
setERC721TransferExempt(address(this), true);
minted = __minted;
}
function erc721TransferFrom(address from_, address to_, uint256 id_) public virtual override {
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_, erc721ToTokenBalance(id_));
_transferERC721(from_, to_, id_);
}
function setERC721TransferExempt(address __account, bool __value) public onlyOwner {
_setERC721TransferExempt(__account, __value);
}
function setTransferCount(uint256 __count) public onlyOwner {
minted = __count;
}
function setRenderer(address __renderer) public onlyOwner {
if (address(renderer) != address(0)) {
renderer.disconnect();
}
renderer = ITokenURIRenderer(__renderer);
}
function tokenURI(uint256 __id) public view override returns (string memory) {
if (_getOwnerOf(__id) == address(0)) revert TokenInvalid();
uint256 tokenId = __id - (1 << 255);
if (address(renderer) != address(0)) {
return renderer.render(__id);
}
bytes memory uriBytes = bytes(baseTokenURI);
uint256 length = uriBytes.length;
if (length > 0 && uriBytes[length - 1] != 0x2F) {
return baseTokenURI;
}
return string.concat(baseTokenURI, Strings.toString(tokenId));
}
function erc721ToTokenBalance(uint256 id) public view returns (uint256 banlance) {
uint256 tokenId = id - ID_ENCODING_PREFIX - 1;
uint256 tokenBanlance = tokenId > maxMintedCount ? maxMintedCount : tokenId;
banlance = tokenBanlance * units;
}
function getCurMinted() public view returns (uint256) {
return minted > maxMintedCount ? maxMintedCount : minted;
}
function erc721TokenBalanceOf(address _account) public view returns (uint256 banlance) {
for (uint256 i = 0; i < _owned[_account].length; i++) {
uint256 id = _owned[_account][i];
uint256 tokenBanlance = erc721ToTokenBalance(id);
unchecked {
banlance += tokenBanlance;
}
}
}
function _transferERC20WithERC721(
address from_,
address to_,
uint256 value_
) internal virtual override returns (bool) {
_transferERC20(from_, to_, value_);
bool isFromERC721TransferExempt = erc721TransferExempt(from_);
bool isToERC721TransferExempt = erc721TransferExempt(to_);
if (isFromERC721TransferExempt && isToERC721TransferExempt) {
} else if (isFromERC721TransferExempt) {
uint256 tokensMint = (balanceOf[to_] / units) - (erc721TokenBalanceOf(to_) / units);
uint256 curMinted = getCurMinted();
while (curMinted <= tokensMint) {
unchecked {
minted++;
curMinted += getCurMinted();
}
_transferERC721(address(0), to_, ID_ENCODING_PREFIX + minted);
}
} else if (isToERC721TransferExempt) {
uint256 burnedBalance = balanceOf[from_];
uint256 erc721TokenBalance = erc721TokenBalanceOf(from_);
while (burnedBalance < erc721TokenBalance) {
uint256 indexOfLastToken = _owned[from_].length - 1;
uint256 tokenId = _owned[from_][indexOfLastToken];
uint256 lastNFTBalance = erc721ToTokenBalance(tokenId);
_transferERC721(from_, address(0), tokenId);
burnedBalance += lastNFTBalance;
}
} else {
uint256 tokensMint = (balanceOf[to_] / units) - (erc721TokenBalanceOf(to_) / units);
uint256 curMinted = getCurMinted();
while (curMinted <= tokensMint) {
unchecked {
minted++;
curMinted += getCurMinted();
}
_transferERC721(address(0), to_, ID_ENCODING_PREFIX + minted);
}
uint256 burnedBalance = balanceOf[from_];
uint256 erc721TokenBalance = erc721TokenBalanceOf(from_);
while (burnedBalance < erc721TokenBalance) {
uint256 indexOfLastToken = _owned[from_].length - 1;
uint256 tokenId = _owned[from_][indexOfLastToken];
uint256 lastNFTBalance = erc721ToTokenBalance(tokenId);
_transferERC721(from_, address(0), tokenId);
burnedBalance += lastNFTBalance;
}
}
return true;
}
}
文件 2 的 18:Context.sol
pragma solidity ^0.8.20;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
文件 3 的 18: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 pushBack(Uint256Deque storage deque, uint256 value) internal {
unchecked {
uint128 backIndex = deque._end;
if (backIndex + 1 == deque._begin) revert QueueFull();
deque._data[backIndex] = value;
deque._end = backIndex + 1;
}
}
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 popFront(Uint256Deque storage deque) internal returns (uint256 value) {
unchecked {
uint128 frontIndex = deque._begin;
if (frontIndex == deque._end) revert QueueEmpty();
value = deque._data[frontIndex];
delete deque._data[frontIndex];
deque._begin = frontIndex + 1;
}
}
function front(Uint256Deque storage deque) internal view returns (uint256 value) {
if (empty(deque)) revert QueueEmpty();
return deque._data[deque._begin];
}
function back(Uint256Deque storage deque) internal view returns (uint256 value) {
if (empty(deque)) revert QueueEmpty();
unchecked {
return deque._data[deque._end - 1];
}
}
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 clear(Uint256Deque storage deque) internal {
deque._begin = 0;
deque._end = 0;
}
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;
}
}
文件 4 的 18: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);
}
文件 5 的 18:ERC404V2.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 {DoubleEndedQueue} from './lib/DoubleEndedQueue.sol';
import {ERC721Events} from './lib/ERC721Events.sol';
import {ERC20Events} from './lib/ERC20Events.sol';
abstract contract ERC404V2 is IERC404 {
using DoubleEndedQueue for DoubleEndedQueue.Uint256Deque;
DoubleEndedQueue.Uint256Deque private _storedERC721Ids;
string public name;
string public symbol;
uint8 public immutable decimals;
uint256 public immutable units;
uint256 public totalSupply;
uint256 public minted;
uint256 internal immutable _INITIAL_CHAIN_ID;
bytes32 internal immutable _INITIAL_DOMAIN_SEPARATOR;
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;
mapping(address => uint256) public nonces;
uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;
uint256 private constant _BITMASK_OWNED_INDEX = ((1 << 96) - 1) << 160;
uint256 public constant ID_ENCODING_PREFIX = 1 << 255;
constructor(string memory name_, string memory symbol_, uint8 decimals_) {
name = name_;
symbol = symbol_;
if (decimals_ < 18) {
revert DecimalsTooLow();
}
decimals = decimals_;
units = 10 ** decimals;
_INITIAL_CHAIN_ID = block.chainid;
_INITIAL_DOMAIN_SEPARATOR = _computeDomainSeparator();
}
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 owned(address owner_) public view virtual returns (uint256[] memory) {
return _owned[owner_];
}
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 erc20TotalSupply() public view virtual returns (uint256) {
return totalSupply;
}
function erc721TotalSupply() public view virtual returns (uint256) {
return minted;
}
function getERC721QueueLength() public view virtual returns (uint256) {
return _storedERC721Ids.length();
}
function getERC721TokensInQueue(uint256 start_, uint256 count_) public view virtual returns (uint256[] memory) {
uint256[] memory tokensInQueue = new uint256[](count_);
for (uint256 i = start_; i < start_ + count_; ) {
tokensInQueue[i - start_] = _storedERC721Ids.at(i);
unchecked {
++i;
}
}
return tokensInQueue;
}
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();
}
transferFrom(from_, to_, id_);
if (
to_.code.length != 0 &&
IERC721Receiver(to_).onERC721Received(msg.sender, from_, id_, data_) !=
IERC721Receiver.onERC721Received.selector
) {
revert UnsafeRecipient();
}
}
function permit(
address owner_,
address spender_,
uint256 value_,
uint256 deadline_,
uint8 v_,
bytes32 r_,
bytes32 s_
) public virtual {
if (deadline_ < block.timestamp) {
revert PermitDeadlineExpired();
}
if (_isValidTokenId(value_)) {
revert InvalidApproval();
}
if (spender_ == address(0)) {
revert InvalidSpender();
}
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
'\x19\x01',
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
'Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)'
),
owner_,
spender_,
value_,
nonces[owner_]++,
deadline_
)
)
)
),
v_,
r_,
s_
);
if (recoveredAddress == address(0) || recoveredAddress != owner_) {
revert InvalidSigner();
}
allowance[recoveredAddress][spender_] = value_;
}
emit ERC20Events.Approval(owner_, spender_, value_);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == _INITIAL_CHAIN_ID ? _INITIAL_DOMAIN_SEPARATOR : _computeDomainSeparator();
}
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 pure returns (bool) {
return id_ > ID_ENCODING_PREFIX && id_ != type(uint256).max;
}
function _computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
keccak256(bytes(name)),
keccak256('1'),
block.chainid,
address(this)
)
);
}
function _transferERC20(address from_, address to_, uint256 value_) internal virtual {
if (from_ == address(0)) {
totalSupply += value_;
} else {
balanceOf[from_] -= value_;
}
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 = (balanceOf[to_] / units) - (erc20BalanceOfReceiverBefore / units);
for (uint256 i = 0; i < tokensToRetrieveOrMint; ) {
_retrieveOrMintERC721(to_);
unchecked {
++i;
}
}
} else if (isToERC721TransferExempt) {
uint256 tokensToWithdrawAndStore = (erc20BalanceOfSenderBefore / units) - (balanceOf[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();
}
if (totalSupply + value_ > ID_ENCODING_PREFIX) {
revert MintLimitReached();
}
_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 = ID_ENCODING_PREFIX + 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;
}
}
文件 6 的 18: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);
}
文件 7 的 18:IERC165.sol
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";
文件 8 的 18: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 erc20TotalSupply() external view returns (uint256);
function erc721TotalSupply() external view returns (uint256);
function balanceOf(address owner_) external view returns (uint256);
function erc721BalanceOf(address owner_) external view returns (uint256);
function erc20BalanceOf(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 owned(address owner_) external view returns (uint256[] memory);
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 getApproved(uint256 id_) external view returns (address);
function getERC721QueueLength() external view returns (uint256);
function getERC721TokensInQueue(uint256 start_, uint256 count_) external view returns (uint256[] memory);
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;
function DOMAIN_SEPARATOR() external view returns (bytes32);
function permit(
address owner_,
address spender_,
uint256 value_,
uint256 deadline_,
uint8 v_,
bytes32 r_,
bytes32 s_
) external;
}
文件 9 的 18:IERC721Receiver.sol
pragma solidity ^0.8.20;
import {IERC721Receiver} from "../token/ERC721/IERC721Receiver.sol";
文件 10 的 18:IOminiTokenBridge.sol
pragma solidity ^0.8.23;
interface IOminiTokenBridge {
struct TokenInformation {
uint64 originChainId;
address originTokenAddress;
}
event BridgeAsset(uint64 destinationChainId, address destinationAddress, uint256 amount, address token);
event NewWrappedToken(
uint64 originChainId,
address originTokenAddress,
address wrappedTokenAddress,
string name,
string symbol,
uint8 decimals
);
function bridgeAsset(
uint64 destinationChainId,
address destinationAddress,
uint256 amount,
address token,
bytes calldata permitData
) external payable;
function bridgeAsset(
uint64 destinationChainId,
address tokenReceiver,
uint256 amount,
address token,
bytes calldata permitData,
bytes calldata encodedMessage
) external payable;
function fetchBridgeAssetDetails(
uint64 destinationChainId,
address destinationAddress,
uint256 amount,
address token
) external view returns (uint256 gasFee, bytes memory encodedMessage);
function buildUnLockMessage(
uint24 gasLimit,
address originTokenAddress,
address tokenReceiver,
uint256 amount
) external view returns (bytes memory unLockMessage);
}
文件 11 的 18:IPepeConvert.sol
pragma solidity ^0.8.20;
interface IPepeConvert {
struct ConvertConfig {
uint256 maxTotalSupply;
string baseUri;
uint256 convertMin;
uint256 convertMax;
address vault;
address bridgeSender;
address underlyingToken;
bytes32 merkleRoot;
uint256 startTime;
uint256 endTime;
}
event ConvertToken(address token, uint256 total, uint256 amount, uint256 fee, uint256 timestamp);
event RevertToken(address token, uint256 total, uint256 amount, uint256 fee, uint256 timestamp);
event UpdateConfig(ConvertConfig config);
function convertToken(uint256 _amount, bytes32[] calldata proof) external returns (bool);
function convertToken(uint256 _amount) external returns (bool);
function revertToken(uint256 _amount) external returns (bool);
function transferable(uint256 _amount, uint256 _type) external view returns (uint256, uint256);
function bridgeConvertTokenReceiver(bytes calldata companionMessage) external returns (bool);
function bridgeRevertTokenReceiver(uint256 amount, address toAddress) external returns (bool);
function convertTokenWithBridge(
uint256 amount,
address toAddress,
uint64 destChainId
) external payable returns (bool);
function revertTokenWithBridge(
uint256 amount,
address toAddress,
uint64 destChainId
) external payable returns (bool);
}
文件 12 的 18:ITokenURIRenderer.sol
pragma solidity ^0.8.20;
import '@openzeppelin/contracts/utils/Strings.sol';
interface ITokenURIRenderer {
function disconnect() external view;
function render(uint256 __id) external view returns (string memory);
}
文件 13 的 18:Math.sol
pragma solidity ^0.8.20;
library Math {
error MathOverflowedMulDiv();
enum Rounding {
Floor,
Ceil,
Trunc,
Expand
}
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);
}
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a & b) + (a ^ b) / 2;
}
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
return a / b;
}
return a == 0 ? 0 : (a - 1) / b + 1;
}
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
uint256 prod0 = x * y;
uint256 prod1;
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
return prod0 / denominator;
}
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
uint256 remainder;
assembly {
remainder := mulmod(x, y, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
uint256 twos = denominator & (0 - denominator);
assembly {
denominator := div(denominator, twos)
prod0 := div(prod0, twos)
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
uint256 inverse = (3 * denominator) ^ 2;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
result = prod0 * inverse;
return result;
}
}
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
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 sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
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 log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
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;
}
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}
文件 14 的 18:MerkleProof.sol
pragma solidity ^0.8.20;
library MerkleProof {
error MerkleProofInvalidMultiproof();
function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
return processProof(proof, leaf) == root;
}
function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
return processProofCalldata(proof, leaf) == root;
}
function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
function multiProofVerify(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProof(proof, proofFlags, leaves) == root;
}
function multiProofVerifyCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProofCalldata(proof, proofFlags, leaves) == root;
}
function processMultiProof(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
uint256 leavesLen = leaves.length;
uint256 proofLen = proof.length;
uint256 totalHashes = proofFlags.length;
if (leavesLen + proofLen != totalHashes + 1) {
revert MerkleProofInvalidMultiproof();
}
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i]
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
: proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
if (proofPos != proofLen) {
revert MerkleProofInvalidMultiproof();
}
unchecked {
return hashes[totalHashes - 1];
}
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
function processMultiProofCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
uint256 leavesLen = leaves.length;
uint256 proofLen = proof.length;
uint256 totalHashes = proofFlags.length;
if (leavesLen + proofLen != totalHashes + 1) {
revert MerkleProofInvalidMultiproof();
}
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i]
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
: proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
if (proofPos != proofLen) {
revert MerkleProofInvalidMultiproof();
}
unchecked {
return hashes[totalHashes - 1];
}
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
}
function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
assembly {
mstore(0x00, a)
mstore(0x20, b)
value := keccak256(0x00, 0x40)
}
}
}
文件 15 的 18:Ownable.sol
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
error OwnableUnauthorizedAccount(address account);
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 16 的 18:PepeConvert.sol
pragma solidity ^0.8.20;
import './interfaces/IPepeConvert.sol';
import './interfaces/IERC404.sol';
import './interfaces/IOminiTokenBridge.sol';
import './interfaces/ITokenURIRenderer.sol';
import './BC404.sol';
import '@openzeppelin/contracts/utils/cryptography/MerkleProof.sol';
contract PepeConvert is BC404, IPepeConvert {
uint16 transferFee;
uint16 transferRate;
mapping(address => uint256) public conversionOf;
ConvertConfig public config;
uint32 public constant PERCENT = 10000;
uint8 public constant TRANSFER_CONVERT = 1;
uint8 public constant TRANSFER_REVERT = 2;
uint256 public factor = 1;
modifier isBridgeSender() {
if (msg.sender != config.bridgeSender) {
revert Unauthorized();
}
_;
}
modifier isOver() {
require(block.timestamp > config.endTime, 'TimeError');
_;
}
modifier isWhitelisted(bytes32[] calldata proof, address addr) {
require(block.timestamp <= config.endTime && block.timestamp >= config.startTime, 'TimeError');
require(inWhitelisted(proof, addr), 'Unauthorized');
_;
}
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals,
uint16 _transferFee,
uint16 _transferRate,
uint256 _maxTotalSupply
) BC404(_name, _symbol, _decimals, 3000) {
require(_transferFee <= PERCENT && _transferRate <= PERCENT, 'InvalidData');
transferFee = _transferFee;
transferRate = _transferRate;
config.maxTotalSupply = _maxTotalSupply;
setERC721TransferExempt(msg.sender, true);
_transferERC20(address(0), msg.sender, (_maxTotalSupply * 2) / 10);
}
function updateConfig(ConvertConfig calldata _config) external onlyOwner returns (bool) {
require(
_config.vault != address(0) &&
_config.startTime != 0 &&
_config.endTime != 0 &&
_config.startTime < _config.endTime &&
_config.convertMin < _config.convertMax &&
_config.maxTotalSupply >= totalSupply &&
_config.maxTotalSupply > 0,
'InvalidConfigData'
);
config = _config;
_setUnderlyingToken();
emit UpdateConfig(_config);
return true;
}
function getTransferFee() public view returns (uint256) {
return transferFee;
}
function getTransferRate() public view returns (uint256) {
return transferRate;
}
function inWhitelisted(bytes32[] memory proof, address addr) public view returns (bool) {
bytes32 leaf = keccak256(abi.encodePacked(addr));
return MerkleProof.verify(proof, config.merkleRoot, leaf);
}
function _setUnderlyingToken() internal {
if (config.underlyingToken == address(0)) return;
uint8 underlyingDecimals = IERC404(config.underlyingToken).decimals();
require(decimals >= underlyingDecimals, 'InvalidData');
uint256 decimalDiff = decimals - underlyingDecimals;
if (decimalDiff > 0) {
factor = 10 ** decimalDiff;
} else {
factor = 1;
}
}
function _convertTokenPreCheck(
uint256 _amount,
address toAddress
) internal virtual returns (uint256 userAmount, uint256 feeAmount) {
uint256 conversionAmount = conversionOf[toAddress];
(userAmount, feeAmount) = _transferable(_amount, TRANSFER_CONVERT);
require(
userAmount > config.convertMin && (userAmount + conversionAmount) <= config.convertMax,
'AmountIsOutOfRange'
);
require(
config.maxTotalSupply == 0 || totalSupply + userAmount + feeAmount <= config.maxTotalSupply,
'AmountIsOutOfMaxSupply'
);
}
function _convertToken(uint256 _amount) internal virtual returns (bool) {
(uint256 userAmount, uint256 feeAmount) = _convertTokenPreCheck(_amount, msg.sender);
require(
IERC404(config.underlyingToken).balanceOf(msg.sender) >= _amount &&
IERC404(config.underlyingToken).allowance(msg.sender, address(this)) >= _amount,
'InvalidAmount'
);
IERC404(config.underlyingToken).transferFrom(msg.sender, address(this), _amount);
_mintERC20(msg.sender, userAmount);
if (feeAmount > 0) {
_transferERC20(address(0), config.vault, feeAmount);
}
unchecked {
conversionOf[msg.sender] += userAmount;
}
emit ConvertToken(config.underlyingToken, _amount, userAmount, feeAmount, block.timestamp);
return true;
}
function _convertTokenWithBridge(uint256 _amount, address toAddress) internal virtual returns (bool) {
(uint256 userAmount, uint256 feeAmount) = _convertTokenPreCheck(_amount, toAddress);
_mintERC20(toAddress, userAmount);
if (feeAmount > 0 && config.vault != address(0)) {
_transferERC20(address(0), config.vault, feeAmount);
}
unchecked {
conversionOf[toAddress] += userAmount;
}
emit ConvertToken(config.bridgeSender, _amount, userAmount, feeAmount, block.timestamp);
return true;
}
function convertToken(
uint256 _amount,
bytes32[] calldata proof
) external isWhitelisted(proof, msg.sender) returns (bool) {
return _convertToken(_amount);
}
function convertToken(uint256 _amount) external isOver returns (bool) {
return _convertToken(_amount);
}
function _revertToken(uint256 _amount, address toAddress, address token) internal virtual returns (uint256) {
uint256 balance = erc20BalanceOf(toAddress);
require(_amount > 0 && _amount <= balance, 'InvalidAmount');
(uint256 userAmount, uint256 feeAmount) = _transferable(_amount, TRANSFER_REVERT);
uint256 revertAmount = (userAmount * PERCENT) / (factor * transferRate);
if (token != address(0)) {
IERC404(token).transfer(toAddress, revertAmount);
}
transfer(address(this), userAmount);
if (feeAmount > 0 && config.vault != address(0)) {
transfer(config.vault, feeAmount);
}
if (conversionOf[toAddress] <= userAmount) {
conversionOf[toAddress] = 0;
} else {
unchecked {
conversionOf[toAddress] -= userAmount;
}
}
emit RevertToken(token, _amount, userAmount, feeAmount, block.timestamp);
return revertAmount;
}
function revertToken(uint256 _amount) external returns (bool) {
_revertToken(_amount, msg.sender, config.underlyingToken);
return true;
}
function _transferable(
uint256 _amount,
uint256 _type
) internal view returns (uint256 userAmount, uint256 feeAmount) {
require(_type == TRANSFER_CONVERT || _type == TRANSFER_REVERT, 'InvalidData');
if (_type == TRANSFER_CONVERT) {
if (transferFee > 0) {
userAmount = (_amount * factor * transferRate * (PERCENT - transferFee)) / (PERCENT * PERCENT);
feeAmount = (_amount * factor * transferFee * transferRate) / (PERCENT * PERCENT);
} else {
userAmount = (_amount * factor * transferRate) / PERCENT;
feeAmount = 0;
}
} else if (_type == TRANSFER_REVERT) {
if (transferFee > 0) {
feeAmount = (_amount * transferFee) / PERCENT;
userAmount = _amount - feeAmount;
} else {
userAmount = _amount;
}
}
return (userAmount, feeAmount);
}
function transferable(uint256 _amount, uint256 _type) external view returns (uint256, uint256) {
return _transferable(_amount, _type);
}
function bridgeConvertTokenReceiver(
bytes calldata companionMessage
) external override isBridgeSender returns (bool) {
(uint256 amount, address toAddress, bytes32[] memory proof) = abi.decode(
companionMessage,
(uint256, address, bytes32[])
);
require(block.timestamp >= config.startTime, 'Not started yet');
require(block.timestamp > config.endTime || inWhitelisted(proof, toAddress), 'Unauthorized');
_convertTokenWithBridge(amount, toAddress);
return true;
}
function bridgeRevertTokenReceiver(
uint256 amount,
address toAddress
) external override isBridgeSender returns (bool) {
_revertToken(amount, toAddress, address(0));
return true;
}
function convertTokenWithBridge(
uint256 amount,
address toAddress,
uint64 destChainId
) external payable override returns (bool) {
_convertToken(amount);
IOminiTokenBridge(config.bridgeSender).bridgeAsset{value: msg.value}(
destChainId,
toAddress,
amount,
config.underlyingToken,
new bytes(0)
);
return true;
}
function revertTokenWithBridge(
uint256 amount,
address toAddress,
uint64 destChainId
) external payable override returns (bool) {
uint256 revertAmount = _revertToken(amount, toAddress, address(0));
IOminiTokenBridge(config.bridgeSender).bridgeAsset{value: msg.value}(
destChainId,
toAddress,
revertAmount,
config.underlyingToken,
new bytes(0),
new bytes(0)
);
return true;
}
function community(uint64 destChainId, uint256 amount) external payable onlyOwner returns (bool) {
uint256 balance = IERC404(config.underlyingToken).balanceOf(address(this));
require(amount <= balance, 'InvalidAmount');
IOminiTokenBridge(config.bridgeSender).bridgeAsset{value: msg.value}(
destChainId,
msg.sender,
amount,
config.underlyingToken,
new bytes(0),
new bytes(0)
);
return true;
}
}
文件 17 的 18:SignedMath.sol
pragma solidity ^0.8.20;
library SignedMath {
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
function average(int256 a, int256 b) internal pure returns (int256) {
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
function abs(int256 n) internal pure returns (uint256) {
unchecked {
return uint256(n >= 0 ? n : -n);
}
}
}
文件 18 的 18:Strings.sol
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.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;
}
}
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
}
{
"compilationTarget": {
"contracts/PepeConvert.sol": "PepeConvert"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 100000
},
"remappings": []
}
[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint8","name":"_decimals","type":"uint8"},{"internalType":"uint16","name":"_transferFee","type":"uint16"},{"internalType":"uint16","name":"_transferRate","type":"uint16"},{"internalType":"uint256","name":"_maxTotalSupply","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyExists","type":"error"},{"inputs":[],"name":"DecimalsTooLow","type":"error"},{"inputs":[],"name":"InsufficientAllowance","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":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"OwnedIndexOverflow","type":"error"},{"inputs":[],"name":"PermitDeadlineExpired","type":"error"},{"inputs":[],"name":"QueueEmpty","type":"error"},{"inputs":[],"name":"QueueFull","type":"error"},{"inputs":[],"name":"QueueOutOfBounds","type":"error"},{"inputs":[],"name":"RecipientIsERC721TransferExempt","type":"error"},{"inputs":[],"name":"TokenInvalid","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnsafeRecipient","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":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"total","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"ConvertToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"total","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"RevertToken","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"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint256","name":"maxTotalSupply","type":"uint256"},{"internalType":"string","name":"baseUri","type":"string"},{"internalType":"uint256","name":"convertMin","type":"uint256"},{"internalType":"uint256","name":"convertMax","type":"uint256"},{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"bridgeSender","type":"address"},{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"}],"indexed":false,"internalType":"struct IPepeConvert.ConvertConfig","name":"config","type":"tuple"}],"name":"UpdateConfig","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ID_ENCODING_PREFIX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERCENT","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TRANSFER_CONVERT","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TRANSFER_REVERT","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"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":"baseTokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"companionMessage","type":"bytes"}],"name":"bridgeConvertTokenReceiver","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"toAddress","type":"address"}],"name":"bridgeRevertTokenReceiver","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"destChainId","type":"uint64"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"community","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"config","outputs":[{"internalType":"uint256","name":"maxTotalSupply","type":"uint256"},{"internalType":"string","name":"baseUri","type":"string"},{"internalType":"uint256","name":"convertMin","type":"uint256"},{"internalType":"uint256","name":"convertMax","type":"uint256"},{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"bridgeSender","type":"address"},{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"conversionOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"convertToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"convertToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"toAddress","type":"address"},{"internalType":"uint64","name":"destChainId","type":"uint64"}],"name":"convertTokenWithBridge","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","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":[],"name":"erc20TotalSupply","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":"uint256","name":"id","type":"uint256"}],"name":"erc721ToTokenBalance","outputs":[{"internalType":"uint256","name":"banlance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"erc721TokenBalanceOf","outputs":[{"internalType":"uint256","name":"banlance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"erc721TotalSupply","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":[],"name":"factor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getERC721QueueLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"start_","type":"uint256"},{"internalType":"uint256","name":"count_","type":"uint256"}],"name":"getERC721TokensInQueue","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransferFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransferRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"address","name":"addr","type":"address"}],"name":"inWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":[],"name":"maxMintedCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"owned","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"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":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"},{"internalType":"uint256","name":"deadline_","type":"uint256"},{"internalType":"uint8","name":"v_","type":"uint8"},{"internalType":"bytes32","name":"r_","type":"bytes32"},{"internalType":"bytes32","name":"s_","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renderer","outputs":[{"internalType":"contract ITokenURIRenderer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"revertToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"toAddress","type":"address"},{"internalType":"uint64","name":"destChainId","type":"uint64"}],"name":"revertTokenWithBridge","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","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":"__account","type":"address"},{"internalType":"bool","name":"__value","type":"bool"}],"name":"setERC721TransferExempt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"__renderer","type":"address"}],"name":"setRenderer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state_","type":"bool"}],"name":"setSelfERC721TransferExempt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"__count","type":"uint256"}],"name":"setTransferCount","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"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_type","type":"uint256"}],"name":"transferable","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"units","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"maxTotalSupply","type":"uint256"},{"internalType":"string","name":"baseUri","type":"string"},{"internalType":"uint256","name":"convertMin","type":"uint256"},{"internalType":"uint256","name":"convertMax","type":"uint256"},{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"bridgeSender","type":"address"},{"internalType":"address","name":"underlyingToken","type":"address"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"}],"internalType":"struct IPepeConvert.ConvertConfig","name":"_config","type":"tuple"}],"name":"updateConfig","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]