编译器
0.8.28+commit.7893614a
文件 1 的 8:BT404.sol
pragma solidity ^0.8.28;
import {LibBitmap} from "solady/utils/LibBitmap.sol";
import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol";
abstract contract BT404 {
using LibBitmap for LibBitmap.Bitmap;
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
event SkipNFTSet(address indexed target, bool status);
event ExchangeMarketFeeSet(uint256 feeBips);
event ListMarketFeeSet(uint256 feeBips);
uint256 internal constant _TRANSFER_EVENT_SIGNATURE =
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
uint256 internal constant _APPROVAL_EVENT_SIGNATURE =
0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;
uint256 internal constant _SKIP_NFT_SET_EVENT_SIGNATURE =
0xb5a1de456fff688115a4f75380060c23c8532d14ff85f687cc871456d6420393;
uint256 internal constant _EXCHANGE_MARKET_FEE_SET_EVENT_SIGNATURE =
0xe10129be59d54095da8caee0e01e0b82530bb6275510fbb843816dda3a5921d6;
uint256 internal constant _LIST_MARKET_FEE_SET_EVENT_SIGNATURE =
0xdf10c155355452a496e5ffa2e30708bc26ccb58e654d0b145ec6056bce9af822;
error DNAlreadyInitialized();
error InsufficientBalance();
error InsufficientAllowance();
error TotalSupplyOverflow();
error InvalidUnit();
error SenderNotMirror();
error TransferToZeroAddress();
error MirrorAddressIsZero();
error LinkMirrorContractFailed();
error ApprovalCallerNotOwnerNorApproved();
error TransferCallerNotOwnerNorApproved();
error TransferFromIncorrectOwner();
error TokenDoesNotExist();
error TokenIdExceedsLimit();
error ExchangeTokenLocked();
error TokenLockStatusNoChange();
error InsufficientBalanceToMaintainLockedTokens();
error InvalidSalePrice();
error InvalidOrderToken();
error TokenNotLocked();
error InvalidSellerOrBuyer();
uint8 internal constant _ADDRESS_DATA_INITIALIZED_FLAG = 1 << 0;
uint8 internal constant _ADDRESS_DATA_SKIP_NFT_FLAG = 1 << 1;
uint32 internal constant _ADDRESS_ALIAS_BURNED_POOL = type(uint32).max;
struct AddressData {
uint56 aux;
uint8 flags;
uint32 addressAlias;
uint32 lockedLength;
uint32 ownedLength;
uint96 balance;
uint96 feePerNFTSnap;
}
struct NFTOffer {
uint32 seller;
uint32 sellTo;
uint96 minTokens;
address offerToken;
}
struct NFTBid {
uint96 tokens;
address bidToken;
}
struct Uint32Map {
mapping(uint256 => uint256) map;
}
struct Uint256Ref {
uint256 value;
}
struct BT404Storage {
uint32 numAliases;
uint32 nextTokenId;
uint32 burnedPoolSize;
uint32 totalNFTSupply;
uint96 totalSupply;
address mirrorERC721;
mapping(uint32 => address) aliasToAddress;
mapping(address => mapping(address => Uint256Ref)) operatorApprovals;
mapping(uint256 => address) nftApprovals;
LibBitmap.Bitmap mayHaveNFTApproval;
mapping(address => mapping(address => Uint256Ref)) allowance;
mapping(address => Uint32Map) owned;
mapping(address => Uint32Map) locked;
Uint32Map burnedPool;
Uint32Map oo;
mapping(address => AddressData) addressData;
LibBitmap.Bitmap tokenLocks;
uint32 numLockedNFT;
uint32 numExchangableNFT;
uint16 exchangeNFTFeeBips;
uint96 accFeePerNFT;
uint80 __gap;
uint16 listMarketFeeBips;
mapping(uint256 => NFTOffer) offers;
mapping(uint256 => mapping(address => NFTBid)) bids;
mapping(address => Uint256Ref) accountedFees;
}
function _getBT404Storage() internal pure virtual returns (BT404Storage storage $) {
assembly {
$.slot := 0xa20d6e21d0e5255308
}
}
function _initializeBT404(
uint256 initialTokenSupply,
address initialSupplyOwner,
address mirror,
address deployer
) internal virtual {
BT404Storage storage $ = _getBT404Storage();
if ($.mirrorERC721 != address(0)) revert DNAlreadyInitialized();
if (mirror == address(0)) revert MirrorAddressIsZero();
assembly {
mstore(0x00, 0x0f4599e5)
mstore(0x20, deployer)
if iszero(and(eq(mload(0x00), 1), call(gas(), mirror, 0, 0x1c, 0x24, 0x00, 0x20))) {
mstore(0x00, 0xd125259c)
revert(0x1c, 0x04)
}
}
$.mirrorERC721 = mirror;
if (_unit() < 10 ** decimals() || _unit() > 10 ** 24) revert InvalidUnit();
if (initialTokenSupply != 0) {
if (initialSupplyOwner == address(0)) {
revert TransferToZeroAddress();
}
if (_totalSupplyOverflows(initialTokenSupply)) {
revert TotalSupplyOverflow();
}
$.totalSupply = uint96(initialTokenSupply);
AddressData storage initialOwnerAddressData = _addressData(initialSupplyOwner);
initialOwnerAddressData.balance = uint96(initialTokenSupply);
assembly {
mstore(0x00, initialTokenSupply)
log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, shl(96, initialSupplyOwner)))
}
_setSkipNFT(initialSupplyOwner, true);
}
}
function _unit() internal view virtual returns (uint256) {
return 10 ** 18;
}
function name() public view virtual returns (string memory);
function symbol() public view virtual returns (string memory);
function tokenURI(uint256 id) public view virtual returns (string memory);
function decimals() public pure returns (uint8) {
return 18;
}
function totalSupply() public view virtual returns (uint256) {
return uint256(_getBT404Storage().totalSupply);
}
function balanceOf(address owner) public view virtual returns (uint256) {
return _getBT404Storage().addressData[owner].balance;
}
function allowance(address owner, address spender) public view returns (uint256) {
return _getBT404Storage().allowance[owner][spender].value;
}
function approve(address spender, uint256 amount) public virtual returns (bool) {
_approve(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
BT404Storage storage $ = _getBT404Storage();
_pullFeeForTwo($, msg.sender, to);
_transfer(msg.sender, to, amount);
return true;
}
function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {
BT404Storage storage $ = _getBT404Storage();
Uint256Ref storage a = $.allowance[from][msg.sender];
uint256 allowed = a.value;
if (allowed != type(uint256).max) {
if (amount > allowed) revert InsufficientAllowance();
unchecked {
a.value = allowed - amount;
}
}
_pullFeeForTwo($, from, to);
_transfer(from, to, amount);
return true;
}
function _transfer(address from, address to, uint256 amount) internal virtual {
if (to == address(0)) revert TransferToZeroAddress();
BT404Storage storage $ = _getBT404Storage();
AddressData storage fromAddressData = _addressData(from);
AddressData storage toAddressData = _addressData(to);
_TransferTemps memory t;
t.fromOwnedLength = fromAddressData.ownedLength;
t.toOwnedLength = toAddressData.ownedLength;
if (amount > (t.fromBalance = fromAddressData.balance)) {
revert InsufficientBalance();
}
unchecked {
t.fromBalance -= amount;
t.fromLockedLength = fromAddressData.lockedLength;
if (t.fromBalance < t.fromLockedLength * _unit()) {
revert InsufficientBalanceToMaintainLockedTokens();
}
fromAddressData.balance = uint96(t.fromBalance);
toAddressData.balance = uint96(t.toBalance = toAddressData.balance + amount);
t.numNFTBurns =
_zeroFloorSub(t.fromOwnedLength + t.fromLockedLength, t.fromBalance / _unit());
if (toAddressData.flags & _ADDRESS_DATA_SKIP_NFT_FLAG == 0) {
if (from == to) t.toOwnedLength = t.fromOwnedLength - t.numNFTBurns;
t.numNFTMints = _zeroFloorSub(
t.toBalance / _unit(),
t.toOwnedLength + toAddressData.lockedLength
);
}
{
mapping(address => Uint256Ref) storage thisOperatorApprovals =
$.operatorApprovals[address(this)];
if (thisOperatorApprovals[from].value != 0) {
$.numExchangableNFT -= uint32(t.numNFTBurns);
}
if (thisOperatorApprovals[to].value != 0) {
$.numExchangableNFT += uint32(t.numNFTMints);
}
}
$.totalNFTSupply = uint32(uint256($.totalNFTSupply) + t.numNFTMints - t.numNFTBurns);
Uint32Map storage oo = $.oo;
{
uint256 n = _min(t.numNFTBurns, t.numNFTMints);
if (n != 0) {
t.numNFTBurns -= n;
t.numNFTMints -= n;
if (from == to) {
t.toOwnedLength += n;
} else {
_DNDirectLogs memory directLogs = _directLogsMalloc(n, from, to);
Uint32Map storage fromOwned = $.owned[from];
Uint32Map storage toOwned = $.owned[to];
uint32 toAlias = _registerAndResolveAlias(toAddressData, to);
do {
uint256 id = _get(fromOwned, --t.fromOwnedLength);
_set(toOwned, t.toOwnedLength, uint32(id));
_setOwnerAliasAndOwnedIndex(oo, id, toAlias, uint32(t.toOwnedLength++));
_removeNFTApproval($, id);
_directLogsAppend(directLogs, id);
} while (--n != 0);
_directLogsSend(directLogs, $.mirrorERC721);
fromAddressData.ownedLength = uint32(t.fromOwnedLength);
toAddressData.ownedLength = uint32(t.toOwnedLength);
}
}
}
_PackedLogs memory packedLogs = _packedLogsMalloc(t.numNFTBurns + t.numNFTMints);
uint256 burnedPoolSize = $.burnedPoolSize;
if (t.numNFTBurns != 0) {
_packedLogsSet(packedLogs, from, 1);
Uint32Map storage fromOwned = $.owned[from];
uint256 fromIndex = t.fromOwnedLength;
uint256 fromEnd = fromIndex - t.numNFTBurns;
fromAddressData.ownedLength = uint32(fromEnd);
do {
uint256 id = _get(fromOwned, --fromIndex);
_setOwnerAliasAndOwnedIndex(
oo, id, _ADDRESS_ALIAS_BURNED_POOL, uint32(burnedPoolSize)
);
_set($.burnedPool, burnedPoolSize++, uint32(id));
_removeNFTApproval($, id);
_packedLogsAppend(packedLogs, id);
} while (fromIndex != fromEnd);
}
if (t.numNFTMints != 0) {
_packedLogsSet(packedLogs, to, 0);
Uint32Map storage toOwned = $.owned[to];
uint256 toIndex = t.toOwnedLength;
uint256 toEnd = toIndex + t.numNFTMints;
t.toAlias = _registerAndResolveAlias(toAddressData, to);
toAddressData.ownedLength = uint32(toEnd);
do {
uint256 randomIndex = uint256(
keccak256(abi.encodePacked(block.prevrandao, msg.sender))
) % burnedPoolSize;
uint256 id = _get($.burnedPool, randomIndex);
if (randomIndex != (--burnedPoolSize)) {
_set($.burnedPool, randomIndex, _get($.burnedPool, burnedPoolSize));
}
_set(toOwned, toIndex, uint32(id));
_setOwnerAliasAndOwnedIndex(oo, id, t.toAlias, uint32(toIndex++));
_packedLogsAppend(packedLogs, id);
} while (toIndex != toEnd);
}
if (packedLogs.logs.length != 0) {
$.burnedPoolSize = uint32(burnedPoolSize);
_packedLogsSend(packedLogs, $.mirrorERC721);
}
assembly {
mstore(0x00, amount)
log3(
0x00,
0x20,
_TRANSFER_EVENT_SIGNATURE,
shr(96, shl(96, from)),
shr(96, shl(96, to))
)
}
}
}
function _transferFromNFT(address from, address to, uint256 id, address msgSender)
internal
virtual
{
if (to == address(0)) revert TransferToZeroAddress();
BT404Storage storage $ = _getBT404Storage();
Uint32Map storage oo = $.oo;
if (from != $.aliasToAddress[_get(oo, _ownershipIndex(id))]) {
revert TransferFromIncorrectOwner();
}
if (msgSender != from) {
if ($.operatorApprovals[msgSender][from].value == 0) {
if (msgSender != $.nftApprovals[id]) {
revert TransferCallerNotOwnerNorApproved();
}
}
}
AddressData storage fromAddressData = _addressData(from);
AddressData storage toAddressData = _addressData(to);
uint256 unit = _unit();
fromAddressData.balance -= uint96(unit);
unchecked {
toAddressData.balance += uint96(unit);
_removeNFTApproval($, id);
_clearNFTOffer($, id);
uint32 toTransferIdx = _get(oo, _ownedIndex(id));
if (LibBitmap.get($.tokenLocks, id)) {
_delNFTAt($.locked[from], oo, toTransferIdx, --fromAddressData.lockedLength);
} else {
if ($.operatorApprovals[address(this)][from].value != 0) {
_pullFeeForTwo($, from, from);
--$.numExchangableNFT;
}
_delNFTAt($.owned[from], oo, toTransferIdx, --fromAddressData.ownedLength);
LibBitmap.setTo($.tokenLocks, id, true);
++$.numLockedNFT;
}
uint256 n = toAddressData.lockedLength++;
_set($.locked[to], n, uint32(id));
_setOwnerAliasAndOwnedIndex(
oo, id, _registerAndResolveAlias(toAddressData, to), uint32(n)
);
}
assembly {
mstore(0x00, unit)
log3(
0x00,
0x20,
_TRANSFER_EVENT_SIGNATURE,
shr(96, shl(96, from)),
shr(96, shl(96, to))
)
}
}
function _exchangeNFT(uint256 idX, uint256 idY, address msgSender)
internal
virtual
returns (address x, address y, uint256 exchangeFee)
{
BT404Storage storage $ = _getBT404Storage();
if (
_toUint(LibBitmap.get($.tokenLocks, idX)) | _toUint(LibBitmap.get($.tokenLocks, idY))
!= 0
) {
revert ExchangeTokenLocked();
}
x = _ownerOf(idX);
y = _ownerAt(idY);
if (msgSender != x) {
if ($.operatorApprovals[msgSender][x].value == 0) {
if (msgSender != $.nftApprovals[idX]) {
revert TransferCallerNotOwnerNorApproved();
}
}
}
Uint32Map storage oo = $.oo;
bool exchangeBurned = _get(oo, _ownershipIndex(idY)) == _ADDRESS_ALIAS_BURNED_POOL;
mapping(address => Uint256Ref) storage thisOperatorApprovals =
$.operatorApprovals[address(this)];
if (!exchangeBurned && thisOperatorApprovals[y].value == 0) {
revert ApprovalCallerNotOwnerNorApproved();
}
_removeNFTApproval($, idX);
if (!exchangeBurned) _removeNFTApproval($, idY);
_pullFeeForTwo($, x, exchangeBurned ? x : y);
uint256 yIndex;
unchecked {
uint256 xIndex = _get(oo, _ownedIndex(idX));
AddressData storage xAddressData = _addressData(x);
_delNFTAt($.owned[x], oo, xIndex, --xAddressData.ownedLength);
yIndex = idX == idY ? xIndex : _get(oo, _ownedIndex(idY));
uint256 n = xAddressData.lockedLength++;
_set($.locked[x], n, uint32(idY));
_setOwnerAliasAndOwnedIndex(oo, idY, xAddressData.addressAlias, uint32(n));
LibBitmap.setTo($.tokenLocks, idY, true);
++$.numLockedNFT;
}
if (idX != idY) {
uint32 yAlias =
exchangeBurned ? _ADDRESS_ALIAS_BURNED_POOL : _addressData(y).addressAlias;
_setOwnerAliasAndOwnedIndex(oo, idX, yAlias, uint32(yIndex));
Uint32Map storage ownedMap = exchangeBurned ? $.burnedPool : $.owned[y];
_set(ownedMap, yIndex, uint32(idX));
}
exchangeFee = $.exchangeNFTFeeBips;
if (exchangeFee > 0) {
if (msgSender != x) _pullFeeForTwo($, msgSender, msgSender);
unchecked {
exchangeFee *= _unit() / 10000;
_transfer(msgSender, address(this), exchangeFee);
uint256 num = $.numExchangableNFT;
if (num > 0) $.accFeePerNFT += uint96(exchangeFee / $.numExchangableNFT);
}
}
if (msgSender != x) _transferFromNFT(x, msgSender, idY, x);
if (!exchangeBurned && thisOperatorApprovals[x].value != 0) {
unchecked {
--$.numExchangableNFT;
}
}
}
function _pullFeeForTwo(BT404Storage storage $, address account1, address account2)
internal
virtual
{
mapping(address => Uint256Ref) storage thisOperatorApprovals =
$.operatorApprovals[address(this)];
uint256 accFeePerNFT;
uint256 accruedFee1;
if (thisOperatorApprovals[account1].value > 0) {
accFeePerNFT = $.accFeePerNFT;
AddressData storage addressData = $.addressData[account1];
accruedFee1 = accFeePerNFT - addressData.feePerNFTSnap;
if (accruedFee1 > 0) addressData.feePerNFTSnap = uint96(accFeePerNFT);
accruedFee1 *= addressData.ownedLength;
}
if (account2 != account1) {
if (thisOperatorApprovals[account2].value > 0) {
if (accFeePerNFT == 0) {
accFeePerNFT = $.accFeePerNFT;
}
AddressData storage addressData = $.addressData[account2];
uint256 accrued = (accFeePerNFT - addressData.feePerNFTSnap);
if (accrued > 0) addressData.feePerNFTSnap = uint96(accFeePerNFT);
accrued *= (addressData.ownedLength);
if (accrued > 0) {
_transfer(address(this), account2, accrued);
}
}
}
if (accruedFee1 > 0) {
_transfer(address(this), account1, accruedFee1);
}
}
function _mintNFT(address, uint256[] memory, bool) internal virtual {
}
function _burnNFT(address, uint256[] memory) internal virtual {
}
function _approve(address owner, address spender, uint256 amount) internal virtual {
Uint256Ref storage ref = _getBT404Storage().allowance[owner][spender];
if (amount > 0 && ref.value > 0) revert();
ref.value = amount;
assembly {
mstore(0x00, amount)
log3(
0x00,
0x20,
_APPROVAL_EVENT_SIGNATURE,
shr(96, shl(96, owner)),
shr(96, shl(96, spender))
)
}
}
function _getAux(address owner) internal view virtual returns (uint56) {
return _getBT404Storage().addressData[owner].aux;
}
function _setAux(address owner, uint56 value) internal virtual {
_getBT404Storage().addressData[owner].aux = value;
}
function _setExchangeNFTFeeRate(uint256 feeBips) internal virtual {
if (feeBips > 10000) revert();
_getBT404Storage().exchangeNFTFeeBips = uint16(feeBips);
assembly {
mstore(0x00, feeBips)
log1(0x00, 0x20, _EXCHANGE_MARKET_FEE_SET_EVENT_SIGNATURE)
}
}
function _setListMarketFeeRate(uint256 feeBips) internal virtual {
if (feeBips > 10000) revert();
_getBT404Storage().listMarketFeeBips = uint16(feeBips);
assembly {
mstore(0x00, feeBips)
log1(0x00, 0x20, _LIST_MARKET_FEE_SET_EVENT_SIGNATURE)
}
}
function getSkipNFT(address owner) public view virtual returns (bool) {
AddressData storage d = _getBT404Storage().addressData[owner];
if (d.flags & _ADDRESS_DATA_INITIALIZED_FLAG == 0) {
return true;
}
return d.flags & _ADDRESS_DATA_SKIP_NFT_FLAG != 0;
}
function setSkipNFT(bool skipNFT) public virtual returns (bool) {
_setSkipNFT(msg.sender, skipNFT);
return true;
}
function _setSkipNFT(address owner, bool state) internal virtual {
AddressData storage d = _addressData(owner);
if ((d.flags & _ADDRESS_DATA_SKIP_NFT_FLAG != 0) != state) {
d.flags ^= _ADDRESS_DATA_SKIP_NFT_FLAG;
}
assembly {
mstore(0x00, iszero(iszero(state)))
log2(0x00, 0x20, _SKIP_NFT_SET_EVENT_SIGNATURE, shr(96, shl(96, owner)))
}
}
function _addressData(address owner) internal virtual returns (AddressData storage d) {
d = _getBT404Storage().addressData[owner];
unchecked {
if (d.flags & _ADDRESS_DATA_INITIALIZED_FLAG == 0) {
d.flags = uint8(_ADDRESS_DATA_SKIP_NFT_FLAG | _ADDRESS_DATA_INITIALIZED_FLAG);
}
}
}
function _registerAndResolveAlias(AddressData storage toAddressData, address to)
internal
virtual
returns (uint32 addressAlias)
{
addressAlias = toAddressData.addressAlias;
if (addressAlias == 0) {
BT404Storage storage $ = _getBT404Storage();
unchecked {
addressAlias = ++$.numAliases;
}
toAddressData.addressAlias = addressAlias;
$.aliasToAddress[addressAlias] = to;
if (addressAlias == _ADDRESS_ALIAS_BURNED_POOL) revert();
}
}
function mirrorERC721() public view virtual returns (address) {
return _getBT404Storage().mirrorERC721;
}
function _totalNFTSupply() internal view virtual returns (uint256) {
return _getBT404Storage().totalNFTSupply;
}
function _balanceOfNFT(address owner) internal view virtual returns (uint256) {
AddressData storage addressData = _getBT404Storage().addressData[owner];
unchecked {
return addressData.ownedLength + addressData.lockedLength;
}
}
function _ownerAt(uint256 id) internal view virtual returns (address) {
BT404Storage storage $ = _getBT404Storage();
return $.aliasToAddress[_get($.oo, _ownershipIndex(id))];
}
function _ownerOf(uint256 id) internal view virtual returns (address) {
address owner = _ownerAt(id);
if (owner == address(0)) revert TokenDoesNotExist();
return owner;
}
function _exists(uint256 id) internal view virtual returns (bool) {
return _ownerAt(id) != address(0);
}
function _getApproved(uint256 id) internal view virtual returns (address) {
if (!_exists(id)) revert TokenDoesNotExist();
return _getBT404Storage().nftApprovals[id];
}
function _approveNFT(address spender, uint256 id, address msgSender)
internal
virtual
returns (address owner)
{
BT404Storage storage $ = _getBT404Storage();
owner = $.aliasToAddress[_get($.oo, _ownershipIndex(id))];
if (msgSender != owner) {
if ($.operatorApprovals[msgSender][owner].value == 0) {
revert ApprovalCallerNotOwnerNorApproved();
}
}
$.nftApprovals[id] = spender;
LibBitmap.setTo($.mayHaveNFTApproval, id, spender != address(0));
}
function _removeNFTApproval(BT404Storage storage $, uint256 id) internal virtual {
if (LibBitmap.get($.mayHaveNFTApproval, id)) {
LibBitmap.setTo($.mayHaveNFTApproval, id, false);
delete $.nftApprovals[id];
}
}
function _setApprovalForAll(address operator, bool approved, address msgSender)
internal
virtual
{
BT404Storage storage $ = _getBT404Storage();
Uint256Ref storage ref = $.operatorApprovals[operator][msgSender];
if (operator == address(this)) {
bool status = ref.value != 0;
AddressData storage senderAddressData = $.addressData[msgSender];
if (_toUint(approved) & _toUint(!status) != 0) {
senderAddressData.feePerNFTSnap = $.accFeePerNFT;
unchecked {
$.numExchangableNFT += senderAddressData.ownedLength;
}
} else if (_toUint(!approved) & _toUint(status) != 0) {
_pullFeeForTwo($, msgSender, msgSender);
unchecked {
$.numExchangableNFT -= senderAddressData.ownedLength;
}
}
}
ref.value = _toUint(approved);
}
function _setNFTLockState(uint256[] memory ids, bool lock, address msgSender)
internal
virtual
{
BT404Storage storage $ = _getBT404Storage();
_pullFeeForTwo($, msgSender, msgSender);
Uint32Map storage oo = $.oo;
LibBitmap.Bitmap storage tokenLocks = $.tokenLocks;
AddressData storage ownerAddressData = _addressData(msgSender);
Uint32Map storage ownerLocked = $.locked[msgSender];
Uint32Map storage ownerOwned = $.owned[msgSender];
uint32 ownerAlias = _registerAndResolveAlias(ownerAddressData, msgSender);
uint256 idLen = ids.length;
unchecked {
for (uint256 i; i < idLen; ++i) {
uint256 id = ids[i];
if (_get(oo, _ownershipIndex(id)) != ownerAlias) {
revert ApprovalCallerNotOwnerNorApproved();
}
uint32 ownedIndex = _get(oo, _ownedIndex(id));
if (LibBitmap.get(tokenLocks, id) == lock) revert TokenLockStatusNoChange();
if (!lock) {
LibBitmap.setTo(tokenLocks, id, false);
_delNFTAt(ownerLocked, oo, ownedIndex, --ownerAddressData.lockedLength);
_clearNFTOffer($, id);
uint256 n = ownerAddressData.ownedLength++;
_set(ownerOwned, n, uint32(id));
_set(oo, _ownedIndex(id), uint32(n));
} else {
LibBitmap.setTo(tokenLocks, id, true);
_delNFTAt(ownerOwned, oo, ownedIndex, --ownerAddressData.ownedLength);
uint256 n = ownerAddressData.lockedLength++;
_set(ownerLocked, n, uint32(id));
_set(oo, _ownedIndex(id), uint32(n));
}
}
}
unchecked {
if (lock) $.numLockedNFT += uint32(idLen);
else $.numLockedNFT -= uint32(idLen);
if ($.operatorApprovals[address(this)][msgSender].value != 0) {
if (lock) $.numExchangableNFT -= uint32(ids.length);
else $.numExchangableNFT += uint32(ids.length);
}
}
}
function _ownedIds(address owner, uint256 begin, uint256 end, bool locked)
internal
view
virtual
returns (uint256[] memory ids)
{
BT404Storage storage $ = _getBT404Storage();
(Uint32Map storage owned, uint256 n) = locked
? ($.locked[owner], $.addressData[owner].lockedLength)
: ($.owned[owner], $.addressData[owner].ownedLength);
n = _min(n, end);
assembly {
ids := mload(0x40)
mstore(0x20, owned.slot)
let i := begin
for {} lt(i, n) { i := add(i, 1) } {
mstore(0x00, shr(3, i))
let s := keccak256(0x00, 0x40)
let id := and(0xffffffff, shr(shl(5, and(i, 7)), sload(s)))
mstore(add(add(ids, 0x20), shl(5, sub(i, begin))), id)
}
mstore(ids, sub(i, begin))
mstore(0x40, add(add(ids, 0x20), shl(5, sub(i, begin))))
}
}
struct NFTOrder {
uint256 id;
uint256 tokenUnits;
address token;
address trader;
}
function _offerForSale(address msgSender, NFTOrder[] memory orders) internal {
BT404Storage storage $ = _getBT404Storage();
mapping(uint256 => NFTOffer) storage offers = $.offers;
uint32 senderAlias = _registerAndResolveAlias(_addressData(msgSender), msgSender);
for (uint256 i; i < orders.length;) {
uint256 id;
uint256 minTokenUnits;
address token;
address saleTo;
{
NFTOrder memory order = orders[i];
(id, minTokenUnits, token, saleTo) =
(order.id, order.tokenUnits, order.token, order.trader);
}
uint32 ownerAlias = _get($.oo, _ownershipIndex(id));
if (senderAlias != ownerAlias) revert ApprovalCallerNotOwnerNorApproved();
if (!LibBitmap.get($.tokenLocks, id)) revert TokenNotLocked();
if (minTokenUnits == 0 || minTokenUnits > type(uint96).max) revert InvalidSalePrice();
offers[id] = NFTOffer({
seller: ownerAlias,
sellTo: saleTo == address(0)
? 0
: _registerAndResolveAlias($.addressData[saleTo], saleTo),
minTokens: uint96(minTokenUnits),
offerToken: token
});
unchecked {
++i;
}
}
}
function _acceptOffer(address msgSender, NFTOrder[] memory orders) internal {
BT404Storage storage $ = _getBT404Storage();
mapping(uint256 => NFTOffer) storage offers = $.offers;
uint32 senderAlias = _registerAndResolveAlias(_addressData(msgSender), msgSender);
uint256 nativeOfferTokens;
uint256 feeBips = $.listMarketFeeBips;
for (uint256 i; i < orders.length;) {
uint256 id;
uint256 tokenUnits;
address token;
address seller;
{
NFTOrder memory order = orders[i];
(id, tokenUnits, token, seller) =
(order.id, order.tokenUnits, order.token, order.trader);
}
{
NFTOffer memory offer = offers[id];
{
uint32 sellerAlias = offer.seller;
if (
sellerAlias == 0 || sellerAlias != _get($.oo, _ownershipIndex(id))
|| sellerAlias != $.addressData[seller].addressAlias
) {
revert InvalidSellerOrBuyer();
}
}
uint32 sellToAlias = offer.sellTo;
if (sellToAlias != 0 && sellToAlias != senderAlias) {
revert InvalidSellerOrBuyer();
}
if (offer.minTokens > tokenUnits) revert InvalidSalePrice();
if (!LibBitmap.get($.tokenLocks, id)) revert TokenNotLocked();
if (token != offer.offerToken) revert InvalidOrderToken();
}
{
uint256 fee = tokenUnits * feeBips / 10000;
_transferFromNFT(seller, msgSender, id, seller);
_transferToken(token, msgSender, seller, tokenUnits - fee);
if (fee > 0) {
$.accountedFees[token].value += fee;
_transferToken(token, msgSender, address(this), fee);
}
if (token == address(0)) nativeOfferTokens += tokenUnits;
}
NFTBid memory bid = $.bids[id][msgSender];
if (bid.tokens > 0) {
delete $.bids[id][msgSender];
_transferToken(bid.bidToken, address(this), msgSender, bid.tokens);
}
unchecked {
++i;
}
}
if (nativeOfferTokens != msg.value) revert InvalidSalePrice();
}
function _cancelOffer(address msgSender, uint256[] memory ids) internal {
BT404Storage storage $ = _getBT404Storage();
mapping(uint256 => NFTOffer) storage offers = $.offers;
uint32 senderAlias = _registerAndResolveAlias(_addressData(msgSender), msgSender);
for (uint256 i; i < ids.length;) {
uint256 id = ids[i];
if (senderAlias != _get($.oo, _ownershipIndex(id))) {
revert InvalidSellerOrBuyer();
}
delete offers[id];
unchecked {
++i;
}
}
}
function _clearNFTOffer(BT404Storage storage $, uint256 id) internal {
if ($.offers[id].seller != 0) delete $.offers[id];
}
function _bidForBuy(address msgSender, NFTOrder[] memory orders) internal {
BT404Storage storage $ = _getBT404Storage();
mapping(uint256 => mapping(address => NFTBid)) storage bids = $.bids;
uint32 senderAlias = _registerAndResolveAlias($.addressData[msgSender], msgSender);
uint256 nativeBidTokens;
for (uint256 i; i < orders.length;) {
uint256 id;
uint256 tokenUnits;
address token;
{
NFTOrder memory order = orders[i];
(id, tokenUnits, token) = (order.id, order.tokenUnits, order.token);
}
{
if (senderAlias == _get($.oo, _ownershipIndex(id))) revert InvalidSellerOrBuyer();
if (tokenUnits == 0 || tokenUnits > type(uint96).max) revert InvalidSalePrice();
}
{
NFTBid memory bid = bids[id][msgSender];
if (tokenUnits == bid.tokens && bid.bidToken == token) revert InvalidSalePrice();
bids[id][msgSender] = NFTBid({tokens: uint96(tokenUnits), bidToken: token});
_transferToken(bid.bidToken, address(this), msgSender, bid.tokens);
_transferToken(token, msgSender, address(this), tokenUnits);
if (token == address(0)) nativeBidTokens += tokenUnits;
}
unchecked {
++i;
}
}
if (nativeBidTokens != msg.value) revert InvalidSalePrice();
}
function _acceptBid(address msgSender, NFTOrder[] memory orders) internal {
BT404Storage storage $ = _getBT404Storage();
mapping(uint256 => mapping(address => NFTBid)) storage bids = $.bids;
uint32 senderAlias = _registerAndResolveAlias(_addressData(msgSender), msgSender);
uint256 feeBips = $.listMarketFeeBips;
for (uint256 i; i < orders.length;) {
uint256 id;
uint256 tokenUnits;
address token;
address bidder;
{
NFTOrder memory order = orders[i];
(id, tokenUnits, token, bidder) =
(order.id, order.tokenUnits, order.token, order.trader);
}
{
if (senderAlias != _get($.oo, _ownershipIndex(id))) revert InvalidSellerOrBuyer();
NFTBid memory bid = bids[id][bidder];
if (tokenUnits == 0 || bid.tokens < tokenUnits) revert InvalidSalePrice();
if (token != bid.bidToken) revert InvalidOrderToken();
delete bids[id][bidder];
tokenUnits = bid.tokens;
}
_transferFromNFT(msgSender, bidder, id, msgSender);
uint256 fee = tokenUnits * feeBips / 10000;
_transferToken(token, address(this), msgSender, tokenUnits - fee);
if (fee > 0) $.accountedFees[token].value += fee;
unchecked {
++i;
}
}
}
function _cancelBid(address msgSender, uint256[] memory ids) internal {
BT404Storage storage $ = _getBT404Storage();
mapping(uint256 => mapping(address => NFTBid)) storage bids = $.bids;
for (uint256 i; i < ids.length;) {
uint256 id = ids[i];
NFTBid memory bid = bids[id][msgSender];
if (bid.tokens == 0) revert InvalidSellerOrBuyer();
delete bids[id][msgSender];
_transferToken(bid.bidToken, address(this), msgSender, bid.tokens);
unchecked {
++i;
}
}
}
function _transferToken(address token, address from, address to, uint256 amount) private {
if (token == address(0)) {
if (to != address(this)) {
SafeTransferLib.safeTransferETH(to, amount);
}
} else if (token == address(this)) {
_pullFeeForTwo(
_getBT404Storage(),
from == address(this) ? to : from,
to == address(this) ? from : to
);
_transfer(from, to, amount);
} else {
if (from == address(this)) {
SafeTransferLib.safeTransfer(token, to, amount);
} else {
SafeTransferLib.safeTransferFrom(token, from, to, amount);
}
}
}
modifier bt404Fallback() virtual {
BT404Storage storage $ = _getBT404Storage();
uint256 fnSelector = _calldataload(0x00) >> 224;
if (fnSelector == 0xe5eb36c8) {
if (msg.sender != $.mirrorERC721) revert SenderNotMirror();
_transferFromNFT(
address(uint160(_calldataload(0x04))),
address(uint160(_calldataload(0x24))),
_calldataload(0x44),
address(uint160(_calldataload(0x64)))
);
_return(1);
}
if (fnSelector == 0x813500fc) {
if (msg.sender != $.mirrorERC721) revert SenderNotMirror();
_setApprovalForAll(
address(uint160(_calldataload(0x04))),
_calldataload(0x24) != 0,
address(uint160(_calldataload(0x44)))
);
_return(1);
}
if (fnSelector == 0x2c5966af) {
if (msg.sender != $.mirrorERC721) revert SenderNotMirror();
(address x, address y, uint256 fee) = _exchangeNFT(
_calldataload(0x04),
_calldataload(0x24),
address(uint160(_calldataload(0x44)))
);
assembly {
mstore(0x00, x)
mstore(0x20, y)
mstore(0x40, fee)
return(0x00, 0x60)
}
}
if (fnSelector == 0xb79cc1bd) {
if (msg.sender != $.mirrorERC721) revert SenderNotMirror();
uint256 senderAndLockFlag = _calldataload(0x04);
_setNFTLockState(
_calldatacopyArray(_calldataload(0x24) + 0x04),
uint8(senderAndLockFlag) != 0,
address(uint160(senderAndLockFlag >> 96))
);
_return(1);
}
if (fnSelector == 0x3e0446a1) {
if (msg.sender != $.mirrorERC721) revert SenderNotMirror();
uint256 senderAndLockFlag = _calldataload(0x04);
_mintNFT(
address(uint160(senderAndLockFlag >> 96)),
_calldatacopyArray(_calldataload(0x24) + 0x04),
uint8(senderAndLockFlag) != 0
);
_return(1);
}
if (fnSelector == 0x86529a61) {
if (msg.sender != $.mirrorERC721) revert SenderNotMirror();
_burnNFT(
address(uint160(_calldataload(0x04))),
_calldatacopyArray(_calldataload(0x24) + 0x04)
);
_return(1);
}
if (fnSelector == 0x73e63d89) {
if (msg.sender != $.mirrorERC721) revert SenderNotMirror();
_offerForSale(
address(uint160(_calldataload(0x04))),
_calldatacopyOrders(_calldataload(0x24) + 0x04)
);
_return(1);
}
if (fnSelector == 0x53ffa071) {
if (msg.sender != $.mirrorERC721) revert SenderNotMirror();
_acceptOffer(
address(uint160(_calldataload(0x04))),
_calldatacopyOrders(_calldataload(0x24) + 0x04)
);
_return(1);
}
if (fnSelector == 0x2da2a859) {
if (msg.sender != $.mirrorERC721) revert SenderNotMirror();
_cancelOffer(
address(uint160(_calldataload(0x04))),
_calldatacopyArray(_calldataload(0x24) + 0x04)
);
_return(1);
}
if (fnSelector == 0xb5a1305b) {
if (msg.sender != $.mirrorERC721) revert SenderNotMirror();
_bidForBuy(
address(uint160(_calldataload(0x04))),
_calldatacopyOrders(_calldataload(0x24) + 0x04)
);
_return(1);
}
if (fnSelector == 0xb6ebe103) {
if (msg.sender != $.mirrorERC721) revert SenderNotMirror();
_acceptBid(
address(uint160(_calldataload(0x04))),
_calldatacopyOrders(_calldataload(0x24) + 0x04)
);
_return(1);
}
if (fnSelector == 0xa38beee1) {
if (msg.sender != $.mirrorERC721) revert SenderNotMirror();
_cancelBid(
address(uint160(_calldataload(0x04))),
_calldatacopyArray(_calldataload(0x24) + 0x04)
);
_return(1);
}
if (fnSelector == 0xe985e9c5) {
address owner = address(uint160(_calldataload(0x04)));
address spender = address(uint160(_calldataload(0x24)));
Uint256Ref storage ref = $.operatorApprovals[spender][owner];
_return(ref.value);
}
if (fnSelector == 0x6352211e) {
_return(uint160(_ownerOf(_calldataload(0x04))));
}
if (fnSelector == 0x24359879) {
_return(uint160(_ownerAt(_calldataload(0x04))));
}
if (fnSelector == 0xd10b6e0c) {
if (msg.sender != $.mirrorERC721) revert SenderNotMirror();
address owner = _approveNFT(
address(uint160(_calldataload(0x04))),
_calldataload(0x24),
address(uint160(_calldataload(0x44)))
);
_return(uint160(owner));
}
if (fnSelector == 0xf9b4b328) {
uint256 addrAndFlag = _calldataload(0x04);
assembly {
mstore(0x40, add(mload(0x40), 0x20))
}
uint256[] memory ids = _ownedIds(
address(uint160(addrAndFlag >> 96)),
_calldataload(0x24),
_calldataload(0x44),
uint8(addrAndFlag) != 0
);
assembly {
let p := sub(ids, 0x20)
mstore(p, 0x20)
return(p, add(0x40, shl(5, mload(ids))))
}
}
if (fnSelector == 0x081812fc) {
_return(uint160(_getApproved(_calldataload(0x04))));
}
if (fnSelector == 0xf5b100ea) {
_return(_balanceOfNFT(address(uint160(_calldataload(0x04)))));
}
if (fnSelector == 0xe2c79281) {
_return(_totalNFTSupply());
}
if (fnSelector == 0xc89e2ab1 || fnSelector == 0xb7a94eb8) {
_return(1);
}
_;
}
fallback() external payable virtual bt404Fallback {}
receive() external payable virtual {}
function _ownershipIndex(uint256 i) internal pure returns (uint256) {
unchecked {
return i << 1;
}
}
function _ownedIndex(uint256 i) internal pure returns (uint256) {
unchecked {
return (i << 1) + 1;
}
}
function _delNFTAt(
Uint32Map storage owned,
Uint32Map storage oo,
uint256 toDelIndex,
uint256 lastIndex
) internal {
if (toDelIndex != lastIndex) {
uint256 updatedId = _get(owned, lastIndex);
_set(owned, toDelIndex, uint32(updatedId));
_set(oo, _ownedIndex(updatedId), uint32(toDelIndex));
}
}
function _totalSupplyOverflows(uint256 amount) internal view returns (bool result) {
uint256 unit = _unit();
assembly {
result := iszero(iszero(or(shr(96, amount), lt(0xfffffffe, div(amount, unit)))))
}
}
struct _DNDirectLogs {
uint256 offset;
address from;
address to;
uint256[] logs;
}
function _directLogsMalloc(uint256 n, address from, address to)
private
pure
returns (_DNDirectLogs memory p)
{
assembly {
let logs := mload(0x40)
mstore(logs, n)
let offset := add(0x20, logs)
mstore(0x40, add(offset, shl(5, n)))
mstore(add(0x60, p), logs)
mstore(add(0x40, p), shr(96, shl(96, to)))
mstore(add(0x20, p), shr(96, shl(96, from)))
mstore(p, offset)
}
}
function _directLogsAppend(_DNDirectLogs memory p, uint256 id) private pure {
assembly {
let offset := mload(p)
mstore(offset, id)
mstore(p, add(offset, 0x20))
}
}
function _directLogsSend(_DNDirectLogs memory p, address mirror) private {
assembly {
let logs := mload(add(p, 0x60))
let n := add(0x84, shl(5, mload(logs)))
let o := sub(logs, 0x80)
mstore(o, 0x144027d3)
mstore(add(o, 0x20), mload(add(0x20, p)))
mstore(add(o, 0x40), mload(add(0x40, p)))
mstore(add(o, 0x60), 0x60)
if iszero(and(eq(mload(o), 1), call(gas(), mirror, 0, add(o, 0x1c), n, o, 0x20))) {
revert(o, 0x00)
}
}
}
struct _PackedLogs {
uint256 offset;
uint256 addressAndBit;
uint256[] logs;
}
function _packedLogsMalloc(uint256 n) internal pure returns (_PackedLogs memory p) {
assembly {
let logs := mload(0x40)
mstore(logs, n)
let offset := add(0x20, logs)
mstore(0x40, add(offset, shl(5, n)))
mstore(add(0x40, p), logs)
mstore(p, offset)
}
}
function _packedLogsSet(_PackedLogs memory p, address a, uint256 burnBit) internal pure {
assembly {
mstore(add(p, 0x20), or(shl(96, a), burnBit))
}
}
function _packedLogsAppend(_PackedLogs memory p, uint256 id) internal pure {
assembly {
let offset := mload(p)
mstore(offset, or(mload(add(p, 0x20)), shl(8, id)))
mstore(p, add(offset, 0x20))
}
}
function _packedLogsSend(_PackedLogs memory p, address mirror) internal {
assembly {
let logs := mload(add(p, 0x40))
let o := sub(logs, 0x40)
mstore(o, 0x263c69d6)
mstore(add(o, 0x20), 0x20)
let n := add(0x44, shl(5, mload(logs)))
if iszero(and(eq(mload(o), 1), call(gas(), mirror, 0, add(o, 0x1c), n, o, 0x20))) {
revert(o, 0x00)
}
}
}
struct _TransferTemps {
uint256 numNFTBurns;
uint256 numNFTMints;
uint256 fromBalance;
uint256 toBalance;
uint256 fromOwnedLength;
uint256 toOwnedLength;
uint256 totalSupply;
uint256 fromLockedLength;
uint256 toLockedLength;
uint256 maxNFTId;
uint32 toAlias;
}
function _calldataload(uint256 offset) internal pure returns (uint256 value) {
assembly {
value := calldataload(offset)
}
}
function _calldatacopyArray(uint256 offset) private pure returns (uint256[] memory value) {
assembly {
let length := calldataload(offset)
value := mload(0x40)
mstore(0x40, add(add(value, 0x20), shl(5, length)))
mstore(value, length)
calldatacopy(add(value, 0x20), add(offset, 0x20), shl(5, length))
}
}
function _calldatacopyOrders(uint256 offset) private pure returns (NFTOrder[] memory orders) {
uint256 length;
assembly {
length := calldataload(offset)
offset := add(offset, 0x20)
}
orders = new NFTOrder[](length);
for (uint256 i; i < length;) {
NFTOrder memory tmp;
assembly {
calldatacopy(tmp, offset, 0x80)
offset := add(offset, 0x80)
mstore(add(tmp, 0x40), shr(96, shl(96, mload(add(tmp, 0x40)))))
mstore(add(tmp, 0x60), shr(96, shl(96, mload(add(tmp, 0x60)))))
}
orders[i] = tmp;
unchecked {
++i;
}
}
}
function _return(uint256 x) internal pure {
assembly {
mstore(0x00, x)
return(0x00, 0x20)
}
}
function _zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly {
z := mul(gt(x, y), sub(x, y))
}
}
function _min(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly {
z := xor(x, mul(xor(x, y), lt(y, x)))
}
}
function _toUint(bool b) internal pure returns (uint256 result) {
assembly {
result := iszero(iszero(b))
}
}
function _get(Uint32Map storage map, uint256 index) internal view returns (uint32 result) {
result = uint32(map.map[index >> 3] >> ((index & 7) << 5));
}
function _set(Uint32Map storage map, uint256 index, uint32 value) internal {
assembly {
mstore(0x20, map.slot)
mstore(0x00, shr(3, index))
let s := keccak256(0x00, 0x40)
let o := shl(5, and(index, 7))
let v := sload(s)
let m := 0xffffffff
sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value)))))
}
}
function _setOwnerAliasAndOwnedIndex(
Uint32Map storage map,
uint256 id,
uint32 ownership,
uint32 ownedIndex
) internal {
assembly {
let value := or(shl(32, ownedIndex), and(0xffffffff, ownership))
mstore(0x20, map.slot)
mstore(0x00, shr(2, id))
let s := keccak256(0x00, 0x40)
let o := shl(6, and(id, 3))
let v := sload(s)
let m := 0xffffffffffffffff
sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value)))))
}
}
}
文件 2 的 8:BitmapBT404.sol
pragma solidity ^0.8.28;
import {BT404} from "../bt404/BT404.sol";
abstract contract BitmapBT404 is BT404 {
function tokenURI(uint256 tokenId) public view override returns (string memory result) {
address mirror = mirrorERC721();
assembly ("memory-safe") {
result := mload(0x40)
mstore(0x00, 0xc87b56dd)
mstore(0x20, tokenId)
if iszero(staticcall(gas(), mirror, 0x1c, 0x24, 0x00, 0x00)) {
returndatacopy(result, 0x00, returndatasize())
revert(result, returndatasize())
}
returndatacopy(0x00, 0x00, 0x20)
returndatacopy(result, mload(0x00), 0x20)
returndatacopy(add(result, 0x20), add(mload(0x00), 0x20), mload(result))
mstore(0x40, add(add(result, 0x20), mload(result)))
}
}
function _mint(address to, uint256 amount) internal virtual {
require(to != address(0), TransferToZeroAddress());
BT404Storage storage $ = _getBT404Storage();
AddressData storage toAddressData = $.addressData[to];
_MintTemps memory t;
uint256 toIndex = toAddressData.ownedLength;
unchecked {
{
uint256 toBalance = uint256(toAddressData.balance) + amount;
toAddressData.balance = uint96(toBalance);
t.toEnd = toIndex + amount / _unit();
}
uint256 idLimit;
{
uint256 newTotalSupply = uint256($.totalSupply) + amount;
$.totalSupply = uint96(newTotalSupply);
uint256 overflows = _toUint(_totalSupplyOverflows(newTotalSupply));
require((overflows | _toUint(newTotalSupply < amount)) == 0, TotalSupplyOverflow());
idLimit = newTotalSupply / _unit();
}
while (true) {
Uint32Map storage toOwned = $.owned[to];
Uint32Map storage oo = $.oo;
if ((t.numNFTMints = _zeroFloorSub(t.toEnd, toIndex)) == uint256(0)) break;
_PackedLogs memory packedLogs = _packedLogsMalloc(t.numNFTMints);
_packedLogsSet(packedLogs, to, 0);
$.totalNFTSupply += uint32(t.numNFTMints);
toAddressData.ownedLength = uint32(t.toEnd);
uint32 toAlias = _registerAndResolveAlias(toAddressData, to);
t.fromTokenId = $.nextTokenId;
t.toTokenId = t.fromTokenId;
do {
uint256 id = t.toTokenId++;
_set(toOwned, toIndex, uint32(id));
_setOwnerAliasAndOwnedIndex(oo, id, toAlias, uint32(toIndex++));
_packedLogsAppend(packedLogs, id);
} while (toIndex != t.toEnd);
require(t.toTokenId <= idLimit, TokenIdExceedsLimit());
$.nextTokenId = uint32(t.toTokenId);
_packedLogsSend(packedLogs, $.mirrorERC721);
break;
}
}
assembly ("memory-safe") {
mstore(0x00, amount)
log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, shl(96, to)))
}
if (t.numNFTMints > 0) {
_afterConsecutiveMints(to, t.fromTokenId, t.toTokenId - 1);
}
}
function _afterConsecutiveMints(address to, uint256 fromTokenId, uint256 toTokenId) internal {
address mirror = mirrorERC721();
assembly ("memory-safe") {
let m := mload(0x40)
mstore(0x00, 0x778e1229)
mstore(0x20, to)
mstore(0x40, fromTokenId)
mstore(0x60, toTokenId)
if iszero(
and(eq(mload(0x00), 1), call(gas(), mirror, callvalue(), 0x1c, 0x64, 0x00, 0x20))
) {
returndatacopy(m, 0x00, returndatasize())
revert(m, returndatasize())
}
mstore(0x40, m)
mstore(0x60, 0)
}
}
struct _MintTemps {
uint256 toEnd;
uint256 numNFTMints;
uint256 fromTokenId;
uint256 toTokenId;
}
}
文件 3 的 8:BitmapPunks.sol
pragma solidity ^0.8.28;
import {OwnableRoles} from "solady/auth/OwnableRoles.sol";
import {BitmapBT404} from "../bt404/BitmapBT404.sol";
contract BitmapPunks is BitmapBT404, OwnableRoles {
uint256 private constant _FEE_MANAGER_ROLE = _ROLE_101;
uint32 public constant MAX_SUPPLY = 2_100_000;
uint32 public constant MAX_PER_WALLET = 100;
uint32 public constant MAX_PER_WALLET_SEND_TO = 5;
error Locked();
error InvalidMint();
error TotalSupplyReached();
string private _name;
string private _symbol;
uint32 public totalMinted;
bool public nameAndSymbolLocked;
bool public mintable;
mapping(address sender => mapping(address receiver => uint256 nftAmount)) private _sendAmount;
mapping(address sender => uint256 walletAmount) private _sendWallets;
constructor(address mirror) {
_initializeOwner(tx.origin);
_name = "BitmapPunks";
_symbol = "BMP";
_initializeBT404(0, address(0), mirror, tx.origin);
}
modifier checkAndUpdateTotalMinted(uint256 nftAmount) {
uint256 newTotalMinted = uint256(totalMinted) + nftAmount;
require(newTotalMinted <= MAX_SUPPLY, TotalSupplyReached());
totalMinted = uint32(newTotalMinted);
_;
}
modifier checkAndUpdateBuyerMintCount(uint256 nftAmount) {
uint256 currentMintCount = _getAux(msg.sender);
uint256 newMintCount = currentMintCount + nftAmount;
require(newMintCount <= MAX_PER_WALLET, InvalidMint());
_setAux(msg.sender, uint56(newMintCount));
_;
}
modifier checkMintable() {
require(mintable, InvalidMint());
_;
}
function name() public view override returns (string memory) {
return _name;
}
function symbol() public view override returns (string memory) {
return _symbol;
}
function mint(uint256 nftAmount)
public
payable
checkMintable
checkAndUpdateBuyerMintCount(nftAmount)
checkAndUpdateTotalMinted(nftAmount)
{
_mint(msg.sender, nftAmount * _unit());
}
function mint(address to, uint256 nftAmount)
public
payable
checkMintable
checkAndUpdateTotalMinted(nftAmount)
{
uint256 minted = _sendAmount[msg.sender][to];
require(minted + nftAmount <= MAX_PER_WALLET / MAX_PER_WALLET_SEND_TO, InvalidMint());
if (minted == 0) {
require(_sendWallets[msg.sender] < MAX_PER_WALLET_SEND_TO, InvalidMint());
_sendWallets[msg.sender] += 1;
}
_sendAmount[msg.sender][to] += nftAmount;
_mint(to, nftAmount * _unit());
}
function setExchangeNFTFeeRate(uint256 feeBips) public onlyOwnerOrRoles(_FEE_MANAGER_ROLE) {
_setExchangeNFTFeeRate(feeBips);
}
function setNameAndSymbol(string memory name_, string memory symbol_) public onlyOwner {
require(!nameAndSymbolLocked, Locked());
_name = name_;
_symbol = symbol_;
}
function lockNameAndSymbol() public onlyOwner {
nameAndSymbolLocked = true;
}
function setMintable(bool mintable_) public onlyOwner {
mintable = mintable_;
}
}
文件 4 的 8:LibBit.sol
pragma solidity ^0.8.4;
library LibBit {
function fls(uint256 x) internal pure returns (uint256 r) {
assembly {
r := or(shl(8, iszero(x)), shl(7, lt(0xffffffffffffffffffffffffffffffff, x)))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000))
}
}
function clz(uint256 x) internal pure returns (uint256 r) {
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
r := add(xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff)), iszero(x))
}
}
function ffs(uint256 x) internal pure returns (uint256 r) {
assembly {
x := and(x, add(not(x), 1))
r := shl(5, shr(252, shl(shl(2, shr(250, mul(x,
0xb6db6db6ddddddddd34d34d349249249210842108c6318c639ce739cffffffff))),
0x8040405543005266443200005020610674053026020000107506200176117077)))
r := or(r, byte(and(div(0xd76453e0, shr(r, x)), 0x1f),
0x001f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405))
}
}
function popCount(uint256 x) internal pure returns (uint256 c) {
assembly {
let max := not(0)
let isMax := eq(x, max)
x := sub(x, and(shr(1, x), div(max, 3)))
x := add(and(x, div(max, 5)), and(shr(2, x), div(max, 5)))
x := and(add(x, shr(4, x)), div(max, 17))
c := or(shl(8, isMax), shr(248, mul(x, div(max, 255))))
}
}
function isPo2(uint256 x) internal pure returns (bool result) {
assembly {
result := iszero(add(and(x, sub(x, 1)), iszero(x)))
}
}
function reverseBits(uint256 x) internal pure returns (uint256 r) {
uint256 m0 = 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;
uint256 m1 = m0 ^ (m0 << 2);
uint256 m2 = m1 ^ (m1 << 1);
r = reverseBytes(x);
r = (m2 & (r >> 1)) | ((m2 & r) << 1);
r = (m1 & (r >> 2)) | ((m1 & r) << 2);
r = (m0 & (r >> 4)) | ((m0 & r) << 4);
}
function reverseBytes(uint256 x) internal pure returns (uint256 r) {
unchecked {
uint256 m0 = 0x100000000000000000000000000000001 * (~toUint(x == uint256(0)) >> 192);
uint256 m1 = m0 ^ (m0 << 32);
uint256 m2 = m1 ^ (m1 << 16);
uint256 m3 = m2 ^ (m2 << 8);
r = (m3 & (x >> 8)) | ((m3 & x) << 8);
r = (m2 & (r >> 16)) | ((m2 & r) << 16);
r = (m1 & (r >> 32)) | ((m1 & r) << 32);
r = (m0 & (r >> 64)) | ((m0 & r) << 64);
r = (r >> 128) | (r << 128);
}
}
function rawAnd(bool x, bool y) internal pure returns (bool z) {
assembly {
z := and(x, y)
}
}
function and(bool x, bool y) internal pure returns (bool z) {
assembly {
z := and(iszero(iszero(x)), iszero(iszero(y)))
}
}
function rawOr(bool x, bool y) internal pure returns (bool z) {
assembly {
z := or(x, y)
}
}
function or(bool x, bool y) internal pure returns (bool z) {
assembly {
z := or(iszero(iszero(x)), iszero(iszero(y)))
}
}
function rawToUint(bool b) internal pure returns (uint256 z) {
assembly {
z := b
}
}
function toUint(bool b) internal pure returns (uint256 z) {
assembly {
z := iszero(iszero(b))
}
}
}
文件 5 的 8:LibBitmap.sol
pragma solidity ^0.8.4;
import {LibBit} from "./LibBit.sol";
library LibBitmap {
uint256 internal constant NOT_FOUND = type(uint256).max;
struct Bitmap {
mapping(uint256 => uint256) map;
}
function get(Bitmap storage bitmap, uint256 index) internal view returns (bool isSet) {
uint256 b = (bitmap.map[index >> 8] >> (index & 0xff)) & 1;
assembly {
isSet := b
}
}
function set(Bitmap storage bitmap, uint256 index) internal {
bitmap.map[index >> 8] |= (1 << (index & 0xff));
}
function unset(Bitmap storage bitmap, uint256 index) internal {
bitmap.map[index >> 8] &= ~(1 << (index & 0xff));
}
function toggle(Bitmap storage bitmap, uint256 index) internal returns (bool newIsSet) {
assembly {
mstore(0x20, bitmap.slot)
mstore(0x00, shr(8, index))
let storageSlot := keccak256(0x00, 0x40)
let shift := and(index, 0xff)
let storageValue := xor(sload(storageSlot), shl(shift, 1))
newIsSet := and(1, shr(shift, storageValue))
sstore(storageSlot, storageValue)
}
}
function setTo(Bitmap storage bitmap, uint256 index, bool shouldSet) internal {
assembly {
mstore(0x20, bitmap.slot)
mstore(0x00, shr(8, index))
let storageSlot := keccak256(0x00, 0x40)
let storageValue := sload(storageSlot)
let shift := and(index, 0xff)
sstore(
storageSlot,
or(and(storageValue, not(shl(shift, 1))), shl(shift, iszero(iszero(shouldSet))))
)
}
}
function setBatch(Bitmap storage bitmap, uint256 start, uint256 amount) internal {
assembly {
let max := not(0)
let shift := and(start, 0xff)
mstore(0x20, bitmap.slot)
mstore(0x00, shr(8, start))
if iszero(lt(add(shift, amount), 257)) {
let storageSlot := keccak256(0x00, 0x40)
sstore(storageSlot, or(sload(storageSlot), shl(shift, max)))
let bucket := add(mload(0x00), 1)
let bucketEnd := add(mload(0x00), shr(8, add(amount, shift)))
amount := and(add(amount, shift), 0xff)
shift := 0
for {} iszero(eq(bucket, bucketEnd)) { bucket := add(bucket, 1) } {
mstore(0x00, bucket)
sstore(keccak256(0x00, 0x40), max)
}
mstore(0x00, bucket)
}
let storageSlot := keccak256(0x00, 0x40)
sstore(storageSlot, or(sload(storageSlot), shl(shift, shr(sub(256, amount), max))))
}
}
function unsetBatch(Bitmap storage bitmap, uint256 start, uint256 amount) internal {
assembly {
let shift := and(start, 0xff)
mstore(0x20, bitmap.slot)
mstore(0x00, shr(8, start))
if iszero(lt(add(shift, amount), 257)) {
let storageSlot := keccak256(0x00, 0x40)
sstore(storageSlot, and(sload(storageSlot), not(shl(shift, not(0)))))
let bucket := add(mload(0x00), 1)
let bucketEnd := add(mload(0x00), shr(8, add(amount, shift)))
amount := and(add(amount, shift), 0xff)
shift := 0
for {} iszero(eq(bucket, bucketEnd)) { bucket := add(bucket, 1) } {
mstore(0x00, bucket)
sstore(keccak256(0x00, 0x40), 0)
}
mstore(0x00, bucket)
}
let storageSlot := keccak256(0x00, 0x40)
sstore(
storageSlot, and(sload(storageSlot), not(shl(shift, shr(sub(256, amount), not(0)))))
)
}
}
function popCount(Bitmap storage bitmap, uint256 start, uint256 amount)
internal
view
returns (uint256 count)
{
unchecked {
uint256 bucket = start >> 8;
uint256 shift = start & 0xff;
if (!(amount + shift < 257)) {
count = LibBit.popCount(bitmap.map[bucket] >> shift);
uint256 bucketEnd = bucket + ((amount + shift) >> 8);
amount = (amount + shift) & 0xff;
shift = 0;
for (++bucket; bucket != bucketEnd; ++bucket) {
count += LibBit.popCount(bitmap.map[bucket]);
}
}
count += LibBit.popCount((bitmap.map[bucket] >> shift) << (256 - amount));
}
}
function findLastSet(Bitmap storage bitmap, uint256 upTo)
internal
view
returns (uint256 setBitIndex)
{
setBitIndex = NOT_FOUND;
uint256 bucket = upTo >> 8;
uint256 bits;
assembly {
mstore(0x00, bucket)
mstore(0x20, bitmap.slot)
let offset := and(0xff, not(upTo))
bits := shr(offset, shl(offset, sload(keccak256(0x00, 0x40))))
if iszero(or(bits, iszero(bucket))) {
for {} 1 {} {
bucket := add(bucket, setBitIndex)
mstore(0x00, bucket)
bits := sload(keccak256(0x00, 0x40))
if or(bits, iszero(bucket)) { break }
}
}
}
if (bits != 0) {
setBitIndex = (bucket << 8) | LibBit.fls(bits);
assembly {
setBitIndex := or(setBitIndex, sub(0, gt(setBitIndex, upTo)))
}
}
}
function findFirstUnset(Bitmap storage bitmap, uint256 begin, uint256 upTo)
internal
view
returns (uint256 unsetBitIndex)
{
unsetBitIndex = NOT_FOUND;
uint256 bucket = begin >> 8;
uint256 negBits;
assembly {
mstore(0x00, bucket)
mstore(0x20, bitmap.slot)
let offset := and(0xff, begin)
negBits := shl(offset, shr(offset, not(sload(keccak256(0x00, 0x40)))))
if iszero(negBits) {
let lastBucket := shr(8, upTo)
for {} 1 {} {
bucket := add(bucket, 1)
mstore(0x00, bucket)
negBits := not(sload(keccak256(0x00, 0x40)))
if or(negBits, gt(bucket, lastBucket)) { break }
}
if gt(bucket, lastBucket) {
negBits := shl(and(0xff, not(upTo)), shr(and(0xff, not(upTo)), negBits))
}
}
}
if (negBits != 0) {
uint256 r = (bucket << 8) | LibBit.ffs(negBits);
assembly {
unsetBitIndex := or(r, sub(0, or(gt(r, upTo), lt(r, begin))))
}
}
}
}
文件 6 的 8:Ownable.sol
pragma solidity ^0.8.4;
abstract contract Ownable {
error Unauthorized();
error NewOwnerIsZeroAddress();
error NoHandoverRequest();
error AlreadyInitialized();
event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
event OwnershipHandoverRequested(address indexed pendingOwner);
event OwnershipHandoverCanceled(address indexed pendingOwner);
uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;
uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;
uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;
bytes32 internal constant _OWNER_SLOT =
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927;
uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;
function _guardInitializeOwner() internal pure virtual returns (bool guard) {}
function _initializeOwner(address newOwner) internal virtual {
if (_guardInitializeOwner()) {
assembly {
let ownerSlot := _OWNER_SLOT
if sload(ownerSlot) {
mstore(0x00, 0x0dc149f0)
revert(0x1c, 0x04)
}
newOwner := shr(96, shl(96, newOwner))
sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
}
} else {
assembly {
newOwner := shr(96, shl(96, newOwner))
sstore(_OWNER_SLOT, newOwner)
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
}
}
}
function _setOwner(address newOwner) internal virtual {
if (_guardInitializeOwner()) {
assembly {
let ownerSlot := _OWNER_SLOT
newOwner := shr(96, shl(96, newOwner))
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
}
} else {
assembly {
let ownerSlot := _OWNER_SLOT
newOwner := shr(96, shl(96, newOwner))
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
sstore(ownerSlot, newOwner)
}
}
}
function _checkOwner() internal view virtual {
assembly {
if iszero(eq(caller(), sload(_OWNER_SLOT))) {
mstore(0x00, 0x82b42900)
revert(0x1c, 0x04)
}
}
}
function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
return 48 * 3600;
}
function transferOwnership(address newOwner) public payable virtual onlyOwner {
assembly {
if iszero(shl(96, newOwner)) {
mstore(0x00, 0x7448fbae)
revert(0x1c, 0x04)
}
}
_setOwner(newOwner);
}
function renounceOwnership() public payable virtual onlyOwner {
_setOwner(address(0));
}
function requestOwnershipHandover() public payable virtual {
unchecked {
uint256 expires = block.timestamp + _ownershipHandoverValidFor();
assembly {
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x20), expires)
log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
}
}
}
function cancelOwnershipHandover() public payable virtual {
assembly {
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x20), 0)
log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
}
}
function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
assembly {
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, pendingOwner)
let handoverSlot := keccak256(0x0c, 0x20)
if gt(timestamp(), sload(handoverSlot)) {
mstore(0x00, 0x6f5e8818)
revert(0x1c, 0x04)
}
sstore(handoverSlot, 0)
}
_setOwner(pendingOwner);
}
function owner() public view virtual returns (address result) {
assembly {
result := sload(_OWNER_SLOT)
}
}
function ownershipHandoverExpiresAt(address pendingOwner)
public
view
virtual
returns (uint256 result)
{
assembly {
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, pendingOwner)
result := sload(keccak256(0x0c, 0x20))
}
}
modifier onlyOwner() virtual {
_checkOwner();
_;
}
}
文件 7 的 8:OwnableRoles.sol
pragma solidity ^0.8.4;
import {Ownable} from "./Ownable.sol";
abstract contract OwnableRoles is Ownable {
event RolesUpdated(address indexed user, uint256 indexed roles);
uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE =
0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26;
uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8;
function _setRoles(address user, uint256 roles) internal virtual {
assembly {
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, user)
sstore(keccak256(0x0c, 0x20), roles)
log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles)
}
}
function _updateRoles(address user, uint256 roles, bool on) internal virtual {
assembly {
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, user)
let roleSlot := keccak256(0x0c, 0x20)
let current := sload(roleSlot)
let updated := or(current, roles)
if iszero(on) { updated := xor(current, and(current, roles)) }
sstore(roleSlot, updated)
log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated)
}
}
function _grantRoles(address user, uint256 roles) internal virtual {
_updateRoles(user, roles, true);
}
function _removeRoles(address user, uint256 roles) internal virtual {
_updateRoles(user, roles, false);
}
function _checkRoles(uint256 roles) internal view virtual {
assembly {
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, caller())
if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
mstore(0x00, 0x82b42900)
revert(0x1c, 0x04)
}
}
}
function _checkOwnerOrRoles(uint256 roles) internal view virtual {
assembly {
if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) {
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, caller())
if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
mstore(0x00, 0x82b42900)
revert(0x1c, 0x04)
}
}
}
}
function _checkRolesOrOwner(uint256 roles) internal view virtual {
assembly {
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, caller())
if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) {
mstore(0x00, 0x82b42900)
revert(0x1c, 0x04)
}
}
}
}
function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) {
assembly {
for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } {
roles := or(shl(mload(add(ordinals, i)), 1), roles)
}
}
}
function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) {
assembly {
ordinals := mload(0x40)
let ptr := add(ordinals, 0x20)
let o := 0
for { let t := roles } 1 {} {
mstore(ptr, o)
ptr := add(ptr, shl(5, and(t, 1)))
o := add(o, 1)
t := shr(o, roles)
if iszero(t) { break }
}
mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20))))
mstore(0x40, ptr)
}
}
function grantRoles(address user, uint256 roles) public payable virtual onlyOwner {
_grantRoles(user, roles);
}
function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner {
_removeRoles(user, roles);
}
function renounceRoles(uint256 roles) public payable virtual {
_removeRoles(msg.sender, roles);
}
function rolesOf(address user) public view virtual returns (uint256 roles) {
assembly {
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, user)
roles := sload(keccak256(0x0c, 0x20))
}
}
function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) {
return rolesOf(user) & roles != 0;
}
function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) {
return rolesOf(user) & roles == roles;
}
modifier onlyRoles(uint256 roles) virtual {
_checkRoles(roles);
_;
}
modifier onlyOwnerOrRoles(uint256 roles) virtual {
_checkOwnerOrRoles(roles);
_;
}
modifier onlyRolesOrOwner(uint256 roles) virtual {
_checkRolesOrOwner(roles);
_;
}
uint256 internal constant _ROLE_0 = 1 << 0;
uint256 internal constant _ROLE_1 = 1 << 1;
uint256 internal constant _ROLE_2 = 1 << 2;
uint256 internal constant _ROLE_3 = 1 << 3;
uint256 internal constant _ROLE_4 = 1 << 4;
uint256 internal constant _ROLE_5 = 1 << 5;
uint256 internal constant _ROLE_6 = 1 << 6;
uint256 internal constant _ROLE_7 = 1 << 7;
uint256 internal constant _ROLE_8 = 1 << 8;
uint256 internal constant _ROLE_9 = 1 << 9;
uint256 internal constant _ROLE_10 = 1 << 10;
uint256 internal constant _ROLE_11 = 1 << 11;
uint256 internal constant _ROLE_12 = 1 << 12;
uint256 internal constant _ROLE_13 = 1 << 13;
uint256 internal constant _ROLE_14 = 1 << 14;
uint256 internal constant _ROLE_15 = 1 << 15;
uint256 internal constant _ROLE_16 = 1 << 16;
uint256 internal constant _ROLE_17 = 1 << 17;
uint256 internal constant _ROLE_18 = 1 << 18;
uint256 internal constant _ROLE_19 = 1 << 19;
uint256 internal constant _ROLE_20 = 1 << 20;
uint256 internal constant _ROLE_21 = 1 << 21;
uint256 internal constant _ROLE_22 = 1 << 22;
uint256 internal constant _ROLE_23 = 1 << 23;
uint256 internal constant _ROLE_24 = 1 << 24;
uint256 internal constant _ROLE_25 = 1 << 25;
uint256 internal constant _ROLE_26 = 1 << 26;
uint256 internal constant _ROLE_27 = 1 << 27;
uint256 internal constant _ROLE_28 = 1 << 28;
uint256 internal constant _ROLE_29 = 1 << 29;
uint256 internal constant _ROLE_30 = 1 << 30;
uint256 internal constant _ROLE_31 = 1 << 31;
uint256 internal constant _ROLE_32 = 1 << 32;
uint256 internal constant _ROLE_33 = 1 << 33;
uint256 internal constant _ROLE_34 = 1 << 34;
uint256 internal constant _ROLE_35 = 1 << 35;
uint256 internal constant _ROLE_36 = 1 << 36;
uint256 internal constant _ROLE_37 = 1 << 37;
uint256 internal constant _ROLE_38 = 1 << 38;
uint256 internal constant _ROLE_39 = 1 << 39;
uint256 internal constant _ROLE_40 = 1 << 40;
uint256 internal constant _ROLE_41 = 1 << 41;
uint256 internal constant _ROLE_42 = 1 << 42;
uint256 internal constant _ROLE_43 = 1 << 43;
uint256 internal constant _ROLE_44 = 1 << 44;
uint256 internal constant _ROLE_45 = 1 << 45;
uint256 internal constant _ROLE_46 = 1 << 46;
uint256 internal constant _ROLE_47 = 1 << 47;
uint256 internal constant _ROLE_48 = 1 << 48;
uint256 internal constant _ROLE_49 = 1 << 49;
uint256 internal constant _ROLE_50 = 1 << 50;
uint256 internal constant _ROLE_51 = 1 << 51;
uint256 internal constant _ROLE_52 = 1 << 52;
uint256 internal constant _ROLE_53 = 1 << 53;
uint256 internal constant _ROLE_54 = 1 << 54;
uint256 internal constant _ROLE_55 = 1 << 55;
uint256 internal constant _ROLE_56 = 1 << 56;
uint256 internal constant _ROLE_57 = 1 << 57;
uint256 internal constant _ROLE_58 = 1 << 58;
uint256 internal constant _ROLE_59 = 1 << 59;
uint256 internal constant _ROLE_60 = 1 << 60;
uint256 internal constant _ROLE_61 = 1 << 61;
uint256 internal constant _ROLE_62 = 1 << 62;
uint256 internal constant _ROLE_63 = 1 << 63;
uint256 internal constant _ROLE_64 = 1 << 64;
uint256 internal constant _ROLE_65 = 1 << 65;
uint256 internal constant _ROLE_66 = 1 << 66;
uint256 internal constant _ROLE_67 = 1 << 67;
uint256 internal constant _ROLE_68 = 1 << 68;
uint256 internal constant _ROLE_69 = 1 << 69;
uint256 internal constant _ROLE_70 = 1 << 70;
uint256 internal constant _ROLE_71 = 1 << 71;
uint256 internal constant _ROLE_72 = 1 << 72;
uint256 internal constant _ROLE_73 = 1 << 73;
uint256 internal constant _ROLE_74 = 1 << 74;
uint256 internal constant _ROLE_75 = 1 << 75;
uint256 internal constant _ROLE_76 = 1 << 76;
uint256 internal constant _ROLE_77 = 1 << 77;
uint256 internal constant _ROLE_78 = 1 << 78;
uint256 internal constant _ROLE_79 = 1 << 79;
uint256 internal constant _ROLE_80 = 1 << 80;
uint256 internal constant _ROLE_81 = 1 << 81;
uint256 internal constant _ROLE_82 = 1 << 82;
uint256 internal constant _ROLE_83 = 1 << 83;
uint256 internal constant _ROLE_84 = 1 << 84;
uint256 internal constant _ROLE_85 = 1 << 85;
uint256 internal constant _ROLE_86 = 1 << 86;
uint256 internal constant _ROLE_87 = 1 << 87;
uint256 internal constant _ROLE_88 = 1 << 88;
uint256 internal constant _ROLE_89 = 1 << 89;
uint256 internal constant _ROLE_90 = 1 << 90;
uint256 internal constant _ROLE_91 = 1 << 91;
uint256 internal constant _ROLE_92 = 1 << 92;
uint256 internal constant _ROLE_93 = 1 << 93;
uint256 internal constant _ROLE_94 = 1 << 94;
uint256 internal constant _ROLE_95 = 1 << 95;
uint256 internal constant _ROLE_96 = 1 << 96;
uint256 internal constant _ROLE_97 = 1 << 97;
uint256 internal constant _ROLE_98 = 1 << 98;
uint256 internal constant _ROLE_99 = 1 << 99;
uint256 internal constant _ROLE_100 = 1 << 100;
uint256 internal constant _ROLE_101 = 1 << 101;
uint256 internal constant _ROLE_102 = 1 << 102;
uint256 internal constant _ROLE_103 = 1 << 103;
uint256 internal constant _ROLE_104 = 1 << 104;
uint256 internal constant _ROLE_105 = 1 << 105;
uint256 internal constant _ROLE_106 = 1 << 106;
uint256 internal constant _ROLE_107 = 1 << 107;
uint256 internal constant _ROLE_108 = 1 << 108;
uint256 internal constant _ROLE_109 = 1 << 109;
uint256 internal constant _ROLE_110 = 1 << 110;
uint256 internal constant _ROLE_111 = 1 << 111;
uint256 internal constant _ROLE_112 = 1 << 112;
uint256 internal constant _ROLE_113 = 1 << 113;
uint256 internal constant _ROLE_114 = 1 << 114;
uint256 internal constant _ROLE_115 = 1 << 115;
uint256 internal constant _ROLE_116 = 1 << 116;
uint256 internal constant _ROLE_117 = 1 << 117;
uint256 internal constant _ROLE_118 = 1 << 118;
uint256 internal constant _ROLE_119 = 1 << 119;
uint256 internal constant _ROLE_120 = 1 << 120;
uint256 internal constant _ROLE_121 = 1 << 121;
uint256 internal constant _ROLE_122 = 1 << 122;
uint256 internal constant _ROLE_123 = 1 << 123;
uint256 internal constant _ROLE_124 = 1 << 124;
uint256 internal constant _ROLE_125 = 1 << 125;
uint256 internal constant _ROLE_126 = 1 << 126;
uint256 internal constant _ROLE_127 = 1 << 127;
uint256 internal constant _ROLE_128 = 1 << 128;
uint256 internal constant _ROLE_129 = 1 << 129;
uint256 internal constant _ROLE_130 = 1 << 130;
uint256 internal constant _ROLE_131 = 1 << 131;
uint256 internal constant _ROLE_132 = 1 << 132;
uint256 internal constant _ROLE_133 = 1 << 133;
uint256 internal constant _ROLE_134 = 1 << 134;
uint256 internal constant _ROLE_135 = 1 << 135;
uint256 internal constant _ROLE_136 = 1 << 136;
uint256 internal constant _ROLE_137 = 1 << 137;
uint256 internal constant _ROLE_138 = 1 << 138;
uint256 internal constant _ROLE_139 = 1 << 139;
uint256 internal constant _ROLE_140 = 1 << 140;
uint256 internal constant _ROLE_141 = 1 << 141;
uint256 internal constant _ROLE_142 = 1 << 142;
uint256 internal constant _ROLE_143 = 1 << 143;
uint256 internal constant _ROLE_144 = 1 << 144;
uint256 internal constant _ROLE_145 = 1 << 145;
uint256 internal constant _ROLE_146 = 1 << 146;
uint256 internal constant _ROLE_147 = 1 << 147;
uint256 internal constant _ROLE_148 = 1 << 148;
uint256 internal constant _ROLE_149 = 1 << 149;
uint256 internal constant _ROLE_150 = 1 << 150;
uint256 internal constant _ROLE_151 = 1 << 151;
uint256 internal constant _ROLE_152 = 1 << 152;
uint256 internal constant _ROLE_153 = 1 << 153;
uint256 internal constant _ROLE_154 = 1 << 154;
uint256 internal constant _ROLE_155 = 1 << 155;
uint256 internal constant _ROLE_156 = 1 << 156;
uint256 internal constant _ROLE_157 = 1 << 157;
uint256 internal constant _ROLE_158 = 1 << 158;
uint256 internal constant _ROLE_159 = 1 << 159;
uint256 internal constant _ROLE_160 = 1 << 160;
uint256 internal constant _ROLE_161 = 1 << 161;
uint256 internal constant _ROLE_162 = 1 << 162;
uint256 internal constant _ROLE_163 = 1 << 163;
uint256 internal constant _ROLE_164 = 1 << 164;
uint256 internal constant _ROLE_165 = 1 << 165;
uint256 internal constant _ROLE_166 = 1 << 166;
uint256 internal constant _ROLE_167 = 1 << 167;
uint256 internal constant _ROLE_168 = 1 << 168;
uint256 internal constant _ROLE_169 = 1 << 169;
uint256 internal constant _ROLE_170 = 1 << 170;
uint256 internal constant _ROLE_171 = 1 << 171;
uint256 internal constant _ROLE_172 = 1 << 172;
uint256 internal constant _ROLE_173 = 1 << 173;
uint256 internal constant _ROLE_174 = 1 << 174;
uint256 internal constant _ROLE_175 = 1 << 175;
uint256 internal constant _ROLE_176 = 1 << 176;
uint256 internal constant _ROLE_177 = 1 << 177;
uint256 internal constant _ROLE_178 = 1 << 178;
uint256 internal constant _ROLE_179 = 1 << 179;
uint256 internal constant _ROLE_180 = 1 << 180;
uint256 internal constant _ROLE_181 = 1 << 181;
uint256 internal constant _ROLE_182 = 1 << 182;
uint256 internal constant _ROLE_183 = 1 << 183;
uint256 internal constant _ROLE_184 = 1 << 184;
uint256 internal constant _ROLE_185 = 1 << 185;
uint256 internal constant _ROLE_186 = 1 << 186;
uint256 internal constant _ROLE_187 = 1 << 187;
uint256 internal constant _ROLE_188 = 1 << 188;
uint256 internal constant _ROLE_189 = 1 << 189;
uint256 internal constant _ROLE_190 = 1 << 190;
uint256 internal constant _ROLE_191 = 1 << 191;
uint256 internal constant _ROLE_192 = 1 << 192;
uint256 internal constant _ROLE_193 = 1 << 193;
uint256 internal constant _ROLE_194 = 1 << 194;
uint256 internal constant _ROLE_195 = 1 << 195;
uint256 internal constant _ROLE_196 = 1 << 196;
uint256 internal constant _ROLE_197 = 1 << 197;
uint256 internal constant _ROLE_198 = 1 << 198;
uint256 internal constant _ROLE_199 = 1 << 199;
uint256 internal constant _ROLE_200 = 1 << 200;
uint256 internal constant _ROLE_201 = 1 << 201;
uint256 internal constant _ROLE_202 = 1 << 202;
uint256 internal constant _ROLE_203 = 1 << 203;
uint256 internal constant _ROLE_204 = 1 << 204;
uint256 internal constant _ROLE_205 = 1 << 205;
uint256 internal constant _ROLE_206 = 1 << 206;
uint256 internal constant _ROLE_207 = 1 << 207;
uint256 internal constant _ROLE_208 = 1 << 208;
uint256 internal constant _ROLE_209 = 1 << 209;
uint256 internal constant _ROLE_210 = 1 << 210;
uint256 internal constant _ROLE_211 = 1 << 211;
uint256 internal constant _ROLE_212 = 1 << 212;
uint256 internal constant _ROLE_213 = 1 << 213;
uint256 internal constant _ROLE_214 = 1 << 214;
uint256 internal constant _ROLE_215 = 1 << 215;
uint256 internal constant _ROLE_216 = 1 << 216;
uint256 internal constant _ROLE_217 = 1 << 217;
uint256 internal constant _ROLE_218 = 1 << 218;
uint256 internal constant _ROLE_219 = 1 << 219;
uint256 internal constant _ROLE_220 = 1 << 220;
uint256 internal constant _ROLE_221 = 1 << 221;
uint256 internal constant _ROLE_222 = 1 << 222;
uint256 internal constant _ROLE_223 = 1 << 223;
uint256 internal constant _ROLE_224 = 1 << 224;
uint256 internal constant _ROLE_225 = 1 << 225;
uint256 internal constant _ROLE_226 = 1 << 226;
uint256 internal constant _ROLE_227 = 1 << 227;
uint256 internal constant _ROLE_228 = 1 << 228;
uint256 internal constant _ROLE_229 = 1 << 229;
uint256 internal constant _ROLE_230 = 1 << 230;
uint256 internal constant _ROLE_231 = 1 << 231;
uint256 internal constant _ROLE_232 = 1 << 232;
uint256 internal constant _ROLE_233 = 1 << 233;
uint256 internal constant _ROLE_234 = 1 << 234;
uint256 internal constant _ROLE_235 = 1 << 235;
uint256 internal constant _ROLE_236 = 1 << 236;
uint256 internal constant _ROLE_237 = 1 << 237;
uint256 internal constant _ROLE_238 = 1 << 238;
uint256 internal constant _ROLE_239 = 1 << 239;
uint256 internal constant _ROLE_240 = 1 << 240;
uint256 internal constant _ROLE_241 = 1 << 241;
uint256 internal constant _ROLE_242 = 1 << 242;
uint256 internal constant _ROLE_243 = 1 << 243;
uint256 internal constant _ROLE_244 = 1 << 244;
uint256 internal constant _ROLE_245 = 1 << 245;
uint256 internal constant _ROLE_246 = 1 << 246;
uint256 internal constant _ROLE_247 = 1 << 247;
uint256 internal constant _ROLE_248 = 1 << 248;
uint256 internal constant _ROLE_249 = 1 << 249;
uint256 internal constant _ROLE_250 = 1 << 250;
uint256 internal constant _ROLE_251 = 1 << 251;
uint256 internal constant _ROLE_252 = 1 << 252;
uint256 internal constant _ROLE_253 = 1 << 253;
uint256 internal constant _ROLE_254 = 1 << 254;
uint256 internal constant _ROLE_255 = 1 << 255;
}
文件 8 的 8:SafeTransferLib.sol
pragma solidity ^0.8.4;
library SafeTransferLib {
error ETHTransferFailed();
error TransferFromFailed();
error TransferFailed();
error ApproveFailed();
error Permit2Failed();
error Permit2AmountOverflow();
uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;
uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;
bytes32 internal constant DAI_DOMAIN_SEPARATOR =
0xdbb8cf42e1ecb028be3f3dbc922e1d878b963f411dc388ced501601c60f7c6f7;
address internal constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address internal constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
function safeTransferETH(address to, uint256 amount) internal {
assembly {
if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb)
revert(0x1c, 0x04)
}
}
}
function safeTransferAllETH(address to) internal {
assembly {
if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb)
revert(0x1c, 0x04)
}
}
}
function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb)
revert(0x1c, 0x04)
}
if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to)
mstore8(0x0b, 0x73)
mstore8(0x20, 0xff)
if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) }
}
}
}
function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
assembly {
if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to)
mstore8(0x0b, 0x73)
mstore8(0x20, 0xff)
if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) }
}
}
}
function forceSafeTransferETH(address to, uint256 amount) internal {
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb)
revert(0x1c, 0x04)
}
if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to)
mstore8(0x0b, 0x73)
mstore8(0x20, 0xff)
if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) }
}
}
}
function forceSafeTransferAllETH(address to) internal {
assembly {
if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to)
mstore8(0x0b, 0x73)
mstore8(0x20, 0xff)
if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) }
}
}
}
function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
internal
returns (bool success)
{
assembly {
success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)
}
}
function trySafeTransferAllETH(address to, uint256 gasStipend)
internal
returns (bool success)
{
assembly {
success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)
}
}
function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
assembly {
let m := mload(0x40)
mstore(0x60, amount)
mstore(0x40, to)
mstore(0x2c, shl(96, from))
mstore(0x0c, 0x23b872dd000000000000000000000000)
let success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x7939f424)
revert(0x1c, 0x04)
}
}
mstore(0x60, 0)
mstore(0x40, m)
}
}
function trySafeTransferFrom(address token, address from, address to, uint256 amount)
internal
returns (bool success)
{
assembly {
let m := mload(0x40)
mstore(0x60, amount)
mstore(0x40, to)
mstore(0x2c, shl(96, from))
mstore(0x0c, 0x23b872dd000000000000000000000000)
success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
success := lt(or(iszero(extcodesize(token)), returndatasize()), success)
}
mstore(0x60, 0)
mstore(0x40, m)
}
}
function safeTransferAllFrom(address token, address from, address to)
internal
returns (uint256 amount)
{
assembly {
let m := mload(0x40)
mstore(0x40, to)
mstore(0x2c, shl(96, from))
mstore(0x0c, 0x70a08231000000000000000000000000)
if iszero(
and(
gt(returndatasize(), 0x1f),
staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
)
) {
mstore(0x00, 0x7939f424)
revert(0x1c, 0x04)
}
mstore(0x00, 0x23b872dd)
amount := mload(0x60)
let success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x7939f424)
revert(0x1c, 0x04)
}
}
mstore(0x60, 0)
mstore(0x40, m)
}
}
function safeTransfer(address token, address to, uint256 amount) internal {
assembly {
mstore(0x14, to)
mstore(0x34, amount)
mstore(0x00, 0xa9059cbb000000000000000000000000)
let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x90b8ec18)
revert(0x1c, 0x04)
}
}
mstore(0x34, 0)
}
}
function safeTransferAll(address token, address to) internal returns (uint256 amount) {
assembly {
mstore(0x00, 0x70a08231)
mstore(0x20, address())
if iszero(
and(
gt(returndatasize(), 0x1f),
staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
)
) {
mstore(0x00, 0x90b8ec18)
revert(0x1c, 0x04)
}
mstore(0x14, to)
amount := mload(0x34)
mstore(0x00, 0xa9059cbb000000000000000000000000)
let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x90b8ec18)
revert(0x1c, 0x04)
}
}
mstore(0x34, 0)
}
}
function safeApprove(address token, address to, uint256 amount) internal {
assembly {
mstore(0x14, to)
mstore(0x34, amount)
mstore(0x00, 0x095ea7b3000000000000000000000000)
let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x3e3f8f73)
revert(0x1c, 0x04)
}
}
mstore(0x34, 0)
}
}
function safeApproveWithRetry(address token, address to, uint256 amount) internal {
assembly {
mstore(0x14, to)
mstore(0x34, amount)
mstore(0x00, 0x095ea7b3000000000000000000000000)
let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x34, 0)
mstore(0x00, 0x095ea7b3000000000000000000000000)
pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00))
mstore(0x34, amount)
success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x3e3f8f73)
revert(0x1c, 0x04)
}
}
}
}
mstore(0x34, 0)
}
}
function balanceOf(address token, address account) internal view returns (uint256 amount) {
assembly {
mstore(0x14, account)
mstore(0x00, 0x70a08231000000000000000000000000)
amount :=
mul(
mload(0x20),
and(
gt(returndatasize(), 0x1f),
staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
)
)
}
}
function safeTransferFrom2(address token, address from, address to, uint256 amount) internal {
if (!trySafeTransferFrom(token, from, to, amount)) {
permit2TransferFrom(token, from, to, amount);
}
}
function permit2TransferFrom(address token, address from, address to, uint256 amount)
internal
{
assembly {
let m := mload(0x40)
mstore(add(m, 0x74), shr(96, shl(96, token)))
mstore(add(m, 0x54), amount)
mstore(add(m, 0x34), to)
mstore(add(m, 0x20), shl(96, from))
mstore(m, 0x36c78516000000000000000000000000)
let p := PERMIT2
let exists := eq(chainid(), 1)
if iszero(exists) { exists := iszero(iszero(extcodesize(p))) }
if iszero(
and(
call(gas(), p, 0, add(m, 0x10), 0x84, codesize(), 0x00),
lt(iszero(extcodesize(token)), exists)
)
) {
mstore(0x00, 0x7939f4248757f0fd)
revert(add(0x18, shl(2, iszero(iszero(shr(160, amount))))), 0x04)
}
}
}
function permit2(
address token,
address owner,
address spender,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
bool success;
assembly {
for {} shl(96, xor(token, WETH9)) {} {
mstore(0x00, 0x3644e515)
if iszero(
and(
lt(iszero(mload(0x00)), eq(returndatasize(), 0x20)),
staticcall(5000, token, 0x1c, 0x04, 0x00, 0x20)
)
) { break }
let m := mload(0x40)
mstore(add(m, 0x34), spender)
mstore(add(m, 0x20), shl(96, owner))
mstore(add(m, 0x74), deadline)
if eq(mload(0x00), DAI_DOMAIN_SEPARATOR) {
mstore(0x14, owner)
mstore(0x00, 0x7ecebe00000000000000000000000000)
mstore(add(m, 0x94), staticcall(gas(), token, 0x10, 0x24, add(m, 0x54), 0x20))
mstore(m, 0x8fcbaf0c000000000000000000000000)
mstore(add(m, 0xb4), and(0xff, v))
mstore(add(m, 0xd4), r)
mstore(add(m, 0xf4), s)
success := call(gas(), token, 0, add(m, 0x10), 0x104, codesize(), 0x00)
break
}
mstore(m, 0xd505accf000000000000000000000000)
mstore(add(m, 0x54), amount)
mstore(add(m, 0x94), and(0xff, v))
mstore(add(m, 0xb4), r)
mstore(add(m, 0xd4), s)
success := call(gas(), token, 0, add(m, 0x10), 0xe4, codesize(), 0x00)
break
}
}
if (!success) simplePermit2(token, owner, spender, amount, deadline, v, r, s);
}
function simplePermit2(
address token,
address owner,
address spender,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
assembly {
let m := mload(0x40)
mstore(m, 0x927da105)
{
let addressMask := shr(96, not(0))
mstore(add(m, 0x20), and(addressMask, owner))
mstore(add(m, 0x40), and(addressMask, token))
mstore(add(m, 0x60), and(addressMask, spender))
mstore(add(m, 0xc0), and(addressMask, spender))
}
let p := mul(PERMIT2, iszero(shr(160, amount)))
if iszero(
and(
gt(returndatasize(), 0x5f),
staticcall(gas(), p, add(m, 0x1c), 0x64, add(m, 0x60), 0x60)
)
) {
mstore(0x00, 0x6b836e6b8757f0fd)
revert(add(0x18, shl(2, iszero(p))), 0x04)
}
mstore(m, 0x2b67b570)
mstore(add(m, 0x60), amount)
mstore(add(m, 0x80), 0xffffffffffff)
mstore(add(m, 0xe0), deadline)
mstore(add(m, 0x100), 0x100)
mstore(add(m, 0x120), 0x41)
mstore(add(m, 0x140), r)
mstore(add(m, 0x160), s)
mstore(add(m, 0x180), shl(248, v))
if iszero(
mul(extcodesize(token), call(gas(), p, 0, add(m, 0x1c), 0x184, codesize(), 0x00))) {
mstore(0x00, 0x6b836e6b)
revert(0x1c, 0x04)
}
}
}
}
{
"compilationTarget": {
"src/bitmap-punk/BitmapPunks.sol": "BitmapPunks"
},
"evmVersion": "cancun",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 1000
},
"remappings": [
":@openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
":@openzeppelin/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/",
":@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
":@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/",
":ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/",
":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
":forge-std/=lib/forge-std/src/",
":halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
":openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/",
":solady/=lib/solady/src/"
]
}
[{"inputs":[{"internalType":"address","name":"mirror","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"DNAlreadyInitialized","type":"error"},{"inputs":[],"name":"ExchangeTokenLocked","type":"error"},{"inputs":[],"name":"InsufficientAllowance","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InsufficientBalanceToMaintainLockedTokens","type":"error"},{"inputs":[],"name":"InvalidMint","type":"error"},{"inputs":[],"name":"InvalidOrderToken","type":"error"},{"inputs":[],"name":"InvalidSalePrice","type":"error"},{"inputs":[],"name":"InvalidSellerOrBuyer","type":"error"},{"inputs":[],"name":"InvalidUnit","type":"error"},{"inputs":[],"name":"LinkMirrorContractFailed","type":"error"},{"inputs":[],"name":"Locked","type":"error"},{"inputs":[],"name":"MirrorAddressIsZero","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"SenderNotMirror","type":"error"},{"inputs":[],"name":"TokenDoesNotExist","type":"error"},{"inputs":[],"name":"TokenIdExceedsLimit","type":"error"},{"inputs":[],"name":"TokenLockStatusNoChange","type":"error"},{"inputs":[],"name":"TokenNotLocked","type":"error"},{"inputs":[],"name":"TotalSupplyOverflow","type":"error"},{"inputs":[],"name":"TotalSupplyReached","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"Unauthorized","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":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"feeBips","type":"uint256"}],"name":"ExchangeMarketFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"feeBips","type":"uint256"}],"name":"ListMarketFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"roles","type":"uint256"}],"name":"RolesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"SkipNFTSet","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"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"MAX_PER_WALLET","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PER_WALLET_SEND_TO","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SUPPLY","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"getSkipNFT","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"grantRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAllRoles","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAnyRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockNameAndSymbol","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"nftAmount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nftAmount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"mintable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mirrorERC721","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nameAndSymbolLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"renounceRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"revokeRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rolesOf","outputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"feeBips","type":"uint256"}],"name":"setExchangeNFTFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"mintable_","type":"bool"}],"name":"setMintable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"}],"name":"setNameAndSymbol","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"skipNFT","type":"bool"}],"name":"setSkipNFT","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"result","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalMinted","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]