编译器
0.8.28+commit.7893614a
文件 1 的 6:BT404Mirror.sol
pragma solidity ^0.8.28;
contract BT404Mirror {
event Transfer(address indexed from, address indexed to, uint256 indexed id);
event Approval(address indexed owner, address indexed account, uint256 indexed id);
event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved);
event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
event UpdateLockState(address indexed owner, uint256 indexed id, bool lockStatus);
event Exchange(uint256 indexed idX, uint256 indexed idY, uint256 exchangeFee);
event Offer(uint256 indexed id, address indexed to, uint256 minPrice, address offerToken);
event CancelOffer(uint256 indexed id, address indexed owner);
event Bid(uint256 indexed id, address indexed from, uint256 price, address bidToken);
event CancelBid(uint256 indexed id, address indexed from);
event Bought(
uint256 indexed id,
address indexed from,
address indexed to,
uint256 price,
address token,
address maker
);
uint256 internal constant _TRANSFER_EVENT_SIGNATURE =
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
uint256 internal constant _APPROVAL_EVENT_SIGNATURE =
0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;
uint256 internal constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE =
0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31;
uint256 internal constant _UPDATE_LOCK_STATE_EVENT_SIGNATURE =
0xcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac;
uint256 internal constant _EXCHANGE_EVENT_SIGNATURE =
0xbc43d7c0945f5a13a7bfa8ca7309e55f903f01d66c38c6d1353fe7ff9335d776;
uint256 private constant _OFFER_EVENT_SIGNATURE =
0xc56f8610599b5a39311e36563ef3386394748f787ef5efc116d960d77def8050;
uint256 private constant _CANCEL_OFFER_EVENT_SIGNATURE =
0xc4caef7e3533865382e608c341581a5e2a1b0d1ac37b0aaf58023ccd4eedfd8e;
uint256 private constant _BID_EVENT_SIGNATURE =
0xec85e6e86fabc4c703529b570fb5eb567dad69ddbf7901bc0fd28b38b93de7f3;
uint256 private constant _CANCEL_BID_EVENT_SIGNATURE =
0x874afcdd5e90b2329b3c1601e613dcdc6abb6deb62ce61339a8337b48c053e51;
uint256 private constant _BOUGHT_EVENT_SIGNATURE =
0xd9882bc1ac8e78c918b907fa0ff79cc9d866091c5eb450ebed79e9d147541d5b;
error SenderNotBase();
error SenderNotDeployer();
error TransferToNonERC721ReceiverImplementer();
error CannotLink();
error AlreadyLinked();
error NotLinked();
error Unauthorized();
error Reentrancy();
struct BT404NFTStorage {
address baseERC20;
bool locked;
address deployer;
address owner;
}
function _getBT404NFTStorage() internal pure virtual returns (BT404NFTStorage storage $) {
assembly {
$.slot := 0x3602298b8c10b01230
}
}
modifier nonReentrant() virtual {
BT404NFTStorage storage $ = _getBT404NFTStorage();
if ($.locked) revert Reentrancy();
$.locked = true;
_;
$.locked = false;
}
constructor(address deployer) {
_getBT404NFTStorage().deployer = deployer;
}
function _initializeBT404Mirror(address deployer) internal {
_getBT404NFTStorage().deployer = deployer;
}
function name() public view virtual returns (string memory result) {
return _readString(0x06fdde03, 0);
}
function symbol() public view virtual returns (string memory result) {
return _readString(0x95d89b41, 0);
}
function tokenURI(uint256 id) public view virtual returns (string memory result) {
return _readString(0xc87b56dd, id);
}
function totalSupply() public view virtual returns (uint256 result) {
return _readWord(0xe2c79281, 0, 0);
}
function balanceOf(address nftOwner) public view virtual returns (uint256 result) {
return _readWord(0xf5b100ea, uint160(nftOwner), 0);
}
function ownerOf(uint256 id) public view virtual returns (address result) {
return address(uint160(_readWord(0x6352211e, id, 0)));
}
function ownerAt(uint256 id) public view virtual returns (address result) {
return address(uint160(_readWord(0x24359879, id, 0)));
}
function approve(address spender, uint256 id) public virtual {
address base = baseERC20();
assembly {
spender := shr(96, shl(96, spender))
let m := mload(0x40)
mstore(0x00, 0xd10b6e0c)
mstore(0x20, spender)
mstore(0x40, id)
mstore(0x60, caller())
if iszero(
and(
gt(returndatasize(), 0x1f),
call(gas(), base, callvalue(), 0x1c, 0x64, 0x00, 0x20)
)
) {
returndatacopy(m, 0x00, returndatasize())
revert(m, returndatasize())
}
mstore(0x40, m)
mstore(0x60, 0)
log4(codesize(), 0x00, _APPROVAL_EVENT_SIGNATURE, shr(96, mload(0x0c)), spender, id)
}
}
function getApproved(uint256 id) public view virtual returns (address) {
return address(uint160(_readWord(0x081812fc, id, 0)));
}
function setApprovalForAll(address operator, bool approved) public virtual {
address base = baseERC20();
assembly {
operator := shr(96, shl(96, operator))
let m := mload(0x40)
mstore(0x00, 0x813500fc)
mstore(0x20, operator)
mstore(0x40, iszero(iszero(approved)))
mstore(0x60, caller())
if iszero(
and(eq(mload(0x00), 1), call(gas(), base, callvalue(), 0x1c, 0x64, 0x00, 0x20))
) {
returndatacopy(m, 0x00, returndatasize())
revert(m, returndatasize())
}
log3(0x40, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), operator)
mstore(0x40, m)
mstore(0x60, 0)
}
}
function isApprovedForAll(address nftOwner, address operator)
public
view
virtual
returns (bool result)
{
return _readWord(0xe985e9c5, uint160(nftOwner), uint160(operator)) != 0;
}
function ownedIds(address account, uint256 begin, uint256 end)
public
view
virtual
returns (uint256[] memory)
{
return _ownedIds(account, begin, end, false);
}
function lockedIds(address account, uint256 begin, uint256 end)
public
view
virtual
returns (uint256[] memory)
{
return _ownedIds(account, begin, end, true);
}
function transferFrom(address from, address to, uint256 id) public virtual {
address base = baseERC20();
assembly {
from := shr(96, shl(96, from))
to := shr(96, shl(96, to))
let m := mload(0x40)
mstore(m, 0xe5eb36c8)
mstore(add(m, 0x20), from)
mstore(add(m, 0x40), to)
mstore(add(m, 0x60), id)
mstore(add(m, 0x80), caller())
if iszero(
and(eq(mload(m), 1), call(gas(), base, callvalue(), add(m, 0x1c), 0x84, m, 0x20))
) {
returndatacopy(m, 0x00, returndatasize())
revert(m, returndatasize())
}
mstore(m, 0x00)
log3(m, 0x20, _UPDATE_LOCK_STATE_EVENT_SIGNATURE, from, id)
log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id)
mstore(m, 0x01)
log3(m, 0x20, _UPDATE_LOCK_STATE_EVENT_SIGNATURE, to, id)
}
}
function safeTransferFrom(address from, address to, uint256 id) public virtual {
transferFrom(from, to, id);
if (_hasCode(to)) _checkOnERC721Received(from, to, id, "");
}
function safeTransferFrom(address from, address to, uint256 id, bytes calldata data)
public
virtual
{
transferFrom(from, to, id);
if (_hasCode(to)) _checkOnERC721Received(from, to, id, data);
}
function updateLockState(uint256[] memory ids, bool lock) public virtual {
address base = baseERC20();
(bool success, bytes memory result) = base.call(
abi.encodeWithSignature(
"setNFTLockState(uint256,uint256[])",
uint256(uint160(msg.sender)) << 96 | (lock ? 1 : 0),
ids
)
);
assembly {
if iszero(and(eq(mload(add(result, 0x20)), 1), success)) {
revert(add(result, 0x20), mload(result))
}
let idLen := mload(ids)
mstore(0x00, lock)
for {
let s := add(ids, 0x20)
let end := add(s, shl(5, idLen))
} iszero(eq(s, end)) { s := add(s, 0x20) } {
log3(0x00, 0x20, _UPDATE_LOCK_STATE_EVENT_SIGNATURE, caller(), mload(s))
}
}
}
function exchange(uint256 idX, uint256 idY) public virtual returns (uint256 exchangeFee) {
address base = baseERC20();
assembly {
let m := mload(0x40)
mstore(0x00, 0x2c5966af)
mstore(0x20, idX)
mstore(0x40, idY)
mstore(0x60, caller())
if iszero(
and(
gt(returndatasize(), 0x5F),
call(gas(), base, callvalue(), 0x1c, 0x64, 0x00, 0x60)
)
) {
returndatacopy(m, 0x00, returndatasize())
revert(m, returndatasize())
}
let x := mload(0x00)
let y := mload(0x20)
exchangeFee := mload(0x40)
log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, x, y, idX)
log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, y, caller(), idY)
log3(0x40, 0x20, _EXCHANGE_EVENT_SIGNATURE, idX, idY)
mstore(0x40, 0x01)
log3(0x40, 0x20, _UPDATE_LOCK_STATE_EVENT_SIGNATURE, caller(), idY)
mstore(0x40, m)
mstore(0x60, 0)
}
}
struct NFTOrder {
uint256 id;
uint256 price;
address token;
address trader;
}
function offerForSale(NFTOrder[] memory orders) public virtual nonReentrant {
_callBaseRetWord(
abi.encodeWithSignature(
"offerForSale(address,(uint256,uint256,address,address)[])", msg.sender, orders
)
);
assembly {
for {
let s := add(orders, add(0x20, shl(5, mload(orders))))
let end := add(s, mul(0x80, mload(orders)))
} iszero(eq(s, end)) { s := add(s, 0x80) } {
log3(add(s, 0x20), 0x40, _OFFER_EVENT_SIGNATURE, mload(s), mload(add(s, 0x60)))
}
}
}
function acceptOffer(NFTOrder[] memory orders) public payable virtual nonReentrant {
_callBaseRetWord(
abi.encodeWithSignature(
"acceptOffer(address,(uint256,uint256,address,address)[])", msg.sender, orders
)
);
assembly {
for {
let s := add(orders, add(0x20, shl(5, mload(orders))))
let end := add(s, mul(0x80, mload(orders)))
} iszero(eq(s, end)) { s := add(s, 0x80) } {
let from := mload(add(s, 0x60))
mstore(0x00, 0x01)
log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, caller(), mload(s))
log3(0x00, 0x20, _UPDATE_LOCK_STATE_EVENT_SIGNATURE, caller(), mload(s))
log4(add(s, 0x20), 0x60, _BOUGHT_EVENT_SIGNATURE, mload(s), from, caller())
}
}
}
function cancelOffer(uint256[] memory ids) public virtual nonReentrant {
_callBaseRetWord(abi.encodeWithSignature("cancelOffer(address,uint256[])", msg.sender, ids));
assembly {
for {
let s := add(ids, 0x20)
let end := add(s, shl(5, mload(ids)))
} iszero(eq(s, end)) { s := add(s, 0x20) } {
log3(codesize(), 0x00, _CANCEL_OFFER_EVENT_SIGNATURE, mload(s), caller())
}
}
}
function bidForBuy(NFTOrder[] memory orders) public payable virtual nonReentrant {
_callBaseRetWord(
abi.encodeWithSignature(
"bidForBuy(address,(uint256,uint256,address,address)[])", msg.sender, orders
)
);
assembly {
for {
let s := add(orders, add(0x20, shl(5, mload(orders))))
let end := add(s, mul(0x80, mload(orders)))
} iszero(eq(s, end)) { s := add(s, 0x80) } {
log3(add(s, 0x20), 0x40, _BID_EVENT_SIGNATURE, mload(s), caller())
}
}
}
function acceptBid(NFTOrder[] memory orders) public virtual nonReentrant {
_callBaseRetWord(
abi.encodeWithSignature(
"acceptBid(address,(uint256,uint256,address,address)[])", msg.sender, orders
)
);
assembly {
for {
let s := add(orders, add(0x20, shl(5, mload(orders))))
let end := add(s, mul(0x80, mload(orders)))
} iszero(eq(s, end)) { s := add(s, 0x80) } {
let to := mload(add(s, 0x60))
mstore(0x00, 0x01)
log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, caller(), to, mload(s))
log3(0x00, 0x20, _UPDATE_LOCK_STATE_EVENT_SIGNATURE, to, mload(s))
log4(add(s, 0x20), 0x60, _BOUGHT_EVENT_SIGNATURE, mload(s), caller(), to)
}
}
}
function cancelBid(uint256[] memory ids) public virtual nonReentrant {
_callBaseRetWord(abi.encodeWithSignature("cancelBid(address,uint256[])", msg.sender, ids));
assembly {
for {
let s := add(ids, 0x20)
let end := add(s, shl(5, mload(ids)))
} iszero(eq(s, end)) { s := add(s, 0x20) } {
log3(codesize(), 0x00, _CANCEL_BID_EVENT_SIGNATURE, mload(s), caller())
}
}
}
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) {
assembly {
let s := shr(224, interfaceId)
result := or(or(eq(s, 0x01ffc9a7), eq(s, 0x80ac58cd)), eq(s, 0x5b5e139f))
}
}
function owner() public view virtual returns (address) {
return _getBT404NFTStorage().owner;
}
function pullOwner() public virtual {
address newOwner;
address base = baseERC20();
assembly {
mstore(0x00, 0x8da5cb5b)
if and(gt(returndatasize(), 0x1f), staticcall(gas(), base, 0x1c, 0x04, 0x00, 0x20)) {
newOwner := shr(96, mload(0x0c))
}
}
BT404NFTStorage storage $ = _getBT404NFTStorage();
address oldOwner = $.owner;
if (oldOwner != newOwner) {
$.owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
function baseERC20() public view virtual returns (address base) {
base = _getBT404NFTStorage().baseERC20;
if (base == address(0)) revert NotLinked();
}
modifier bt404NFTFallback() virtual {
BT404NFTStorage storage $ = _getBT404NFTStorage();
uint256 fnSelector = _calldataload(0x00) >> 224;
if (fnSelector == 0x263c69d6) {
if (msg.sender != $.baseERC20) revert SenderNotBase();
assembly ("memory-safe") {
let o := add(0x24, calldataload(0x04))
let end := add(o, shl(5, calldataload(sub(o, 0x20))))
for {} iszero(eq(o, end)) { o := add(0x20, o) } {
let d := calldataload(o)
let a := shr(96, d)
let b := and(1, d)
log4(
codesize(),
0x00,
_TRANSFER_EVENT_SIGNATURE,
mul(a, b),
mul(a, iszero(b)),
shr(168, shl(160, d))
)
}
mstore(0x00, 0x01)
return(0x00, 0x20)
}
}
if (fnSelector == 0x144027d3) {
if (msg.sender != $.baseERC20) revert SenderNotBase();
assembly ("memory-safe") {
let from := calldataload(0x04)
let to := calldataload(0x24)
let o := add(0x24, calldataload(0x44))
let end := add(o, shl(5, calldataload(sub(o, 0x20))))
for {} iszero(eq(o, end)) { o := add(0x20, o) } {
log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, calldataload(o))
}
mstore(0x00, 0x01)
return(0x00, 0x20)
}
}
if (fnSelector == 0x0f4599e5) {
if ($.deployer != address(0)) {
if (address(uint160(_calldataload(0x04))) != $.deployer) {
revert SenderNotDeployer();
}
}
if ($.baseERC20 != address(0)) revert AlreadyLinked();
$.baseERC20 = msg.sender;
assembly ("memory-safe") {
mstore(0x00, 0x01)
return(0x00, 0x20)
}
}
_;
}
fallback() external payable virtual bt404NFTFallback {}
receive() external payable virtual {}
function _ownedIds(address account, uint256 begin, uint256 end, bool locked)
private
view
returns (uint256[] memory result)
{
address base = baseERC20();
assembly {
result := mload(0x40)
mstore(0x00, 0xf9b4b328)
mstore(0x20, or(shl(96, account), iszero(iszero(locked))))
mstore(0x40, begin)
mstore(0x60, end)
if iszero(staticcall(gas(), base, 0x1c, 0x64, 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), shl(5, mload(result)))
mstore(0x40, add(add(result, 0x20), shl(5, mload(result))))
mstore(0x60, 0)
}
}
function _readString(uint256 fnSelector, uint256 arg0)
private
view
returns (string memory result)
{
address base = baseERC20();
assembly {
result := mload(0x40)
mstore(0x00, fnSelector)
mstore(0x20, arg0)
if iszero(staticcall(gas(), base, 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 _readWord(uint256 fnSelector, uint256 arg0, uint256 arg1)
private
view
returns (uint256 result)
{
address base = baseERC20();
assembly {
let m := mload(0x40)
mstore(0x00, fnSelector)
mstore(0x20, arg0)
mstore(0x40, arg1)
if iszero(
and(gt(returndatasize(), 0x1f), staticcall(gas(), base, 0x1c, 0x44, 0x00, 0x20))
) {
returndatacopy(m, 0x00, returndatasize())
revert(m, returndatasize())
}
mstore(0x40, m)
result := mload(0x00)
}
}
function _callBaseRetWord(bytes memory _calldata) private returns (uint256 result) {
address base = baseERC20();
assembly {
let m := mload(0x40)
if iszero(
and(
gt(returndatasize(), 0x1f),
call(
gas(), base, callvalue(), add(_calldata, 0x20), mload(_calldata), 0x00, 0x20
)
)
) {
returndatacopy(m, 0x00, returndatasize())
revert(m, returndatasize())
}
mstore(0x40, m)
mstore(0x60, 0)
result := mload(0x00)
}
}
function _calldataload(uint256 offset) internal pure returns (uint256 value) {
assembly {
value := calldataload(offset)
}
}
function _hasCode(address a) private view returns (bool result) {
assembly {
result := extcodesize(a)
}
}
function _checkOnERC721Received(address from, address to, uint256 id, bytes memory data)
private
{
assembly {
let m := mload(0x40)
let onERC721ReceivedSelector := 0x150b7a02
mstore(m, onERC721ReceivedSelector)
mstore(add(m, 0x20), caller())
mstore(add(m, 0x40), shr(96, shl(96, from)))
mstore(add(m, 0x60), id)
mstore(add(m, 0x80), 0x80)
let n := mload(data)
mstore(add(m, 0xa0), n)
if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xc0), n)) }
if iszero(call(gas(), to, 0, add(m, 0x1c), add(n, 0xa4), m, 0x20)) {
if returndatasize() {
returndatacopy(m, 0x00, returndatasize())
revert(m, returndatasize())
}
}
if iszero(eq(mload(m), shl(224, onERC721ReceivedSelector))) {
mstore(0x00, 0xd1a57ed6)
revert(0x1c, 0x04)
}
}
}
}
文件 2 的 6:Base64.sol
pragma solidity ^0.8.4;
library Base64 {
function encode(bytes memory data, bool fileSafe, bool noPadding)
internal
pure
returns (string memory result)
{
assembly {
let dataLength := mload(data)
if dataLength {
let encodedLength := shl(2, div(add(dataLength, 2), 3))
result := mload(0x40)
mstore(0x1f, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef")
mstore(0x3f, xor("ghijklmnopqrstuvwxyz0123456789-_", mul(iszero(fileSafe), 0x0670)))
let ptr := add(result, 0x20)
let end := add(ptr, encodedLength)
let dataEnd := add(add(0x20, data), dataLength)
let dataEndValue := mload(dataEnd)
mstore(dataEnd, 0x00)
for {} 1 {} {
data := add(data, 3)
let input := mload(data)
mstore8(0, mload(and(shr(18, input), 0x3F)))
mstore8(1, mload(and(shr(12, input), 0x3F)))
mstore8(2, mload(and(shr(6, input), 0x3F)))
mstore8(3, mload(and(input, 0x3F)))
mstore(ptr, mload(0x00))
ptr := add(ptr, 4)
if iszero(lt(ptr, end)) { break }
}
mstore(dataEnd, dataEndValue)
mstore(0x40, add(end, 0x20))
let o := div(2, mod(dataLength, 3))
mstore(sub(ptr, o), shl(240, 0x3d3d))
o := mul(iszero(iszero(noPadding)), o)
mstore(sub(ptr, o), 0)
mstore(result, sub(encodedLength, o))
}
}
}
function encode(bytes memory data) internal pure returns (string memory result) {
result = encode(data, false, false);
}
function encode(bytes memory data, bool fileSafe)
internal
pure
returns (string memory result)
{
result = encode(data, fileSafe, false);
}
function decode(string memory data) internal pure returns (bytes memory result) {
assembly {
let dataLength := mload(data)
if dataLength {
let decodedLength := mul(shr(2, dataLength), 3)
for {} 1 {} {
if iszero(and(dataLength, 3)) {
let t := xor(mload(add(data, dataLength)), 0x3d3d)
decodedLength := sub(
decodedLength,
add(iszero(byte(30, t)), iszero(byte(31, t)))
)
break
}
decodedLength := add(decodedLength, sub(and(dataLength, 3), 1))
break
}
result := mload(0x40)
mstore(result, decodedLength)
let ptr := add(result, 0x20)
let end := add(ptr, decodedLength)
let m := 0xfc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc
mstore(0x5b, m)
mstore(0x3b, 0x04080c1014181c2024282c3034383c4044484c5054585c6064)
mstore(0x1a, 0xf8fcf800fcd0d4d8dce0e4e8ecf0f4)
for {} 1 {} {
data := add(data, 4)
let input := mload(data)
mstore(ptr, or(
and(m, mload(byte(28, input))),
shr(6, or(
and(m, mload(byte(29, input))),
shr(6, or(
and(m, mload(byte(30, input))),
shr(6, mload(byte(31, input)))
))
))
))
ptr := add(ptr, 3)
if iszero(lt(ptr, end)) { break }
}
mstore(0x40, add(end, 0x20))
mstore(end, 0)
mstore(0x60, 0)
}
}
}
}
文件 3 的 6:BitmapBT404Mirror.sol
pragma solidity ^0.8.28;
import {TraitsMetadata} from "../TraitsMetadata.sol";
import {BT404Mirror} from "../bt404/BT404Mirror.sol";
contract BitmapBT404Mirror is BT404Mirror, TraitsMetadata {
constructor(address deployer) BT404Mirror(deployer) {}
modifier bitmapFallback() {
BT404NFTStorage storage $ = _getBT404NFTStorage();
uint256 fnSelector = _calldataload(0x00) >> 224;
if (fnSelector == 0x778e1229) {
if (msg.sender != $.baseERC20) revert SenderNotBase();
address to = address(uint160(_calldataload(0x04)));
uint256 fromTokenId = _calldataload(0x24);
uint256 toTokenId = _calldataload(0x44);
_addTokenBatch(to, fromTokenId, toTokenId);
assembly ("memory-safe") {
mstore(0x00, 0x01)
return(0x00, 0x20)
}
}
_;
}
fallback() external payable override bt404NFTFallback bitmapFallback {}
}
文件 4 的 6:BitmapPunks721.sol
pragma solidity ^0.8.28;
import {Base64} from "solady/utils/Base64.sol";
import {LibString} from "solady/utils/LibString.sol";
import {BitmapBT404Mirror} from "../bt404/BitmapBT404Mirror.sol";
contract BitmapPunks721 is BitmapBT404Mirror {
constructor(address _traitRegistry, address _traitOwner) BitmapBT404Mirror(tx.origin) {
_initializeBT404Mirror(tx.origin);
_initializeTraitsMetadata(_traitRegistry, _traitOwner);
}
function tokenURI(uint256 tokenId) public view override returns (string memory) {
string memory _name = name();
(string memory attributesJson, string memory imageURI) =
_getTokenAttributesAndImage(tokenId);
return string.concat(
"data:application/json;base64,",
Base64.encode(
bytes(
string.concat(
'{"external_url":"https://bitmappunks.com","description":"A fully-onchain, ultra-large, hybrid collection.","name":"',
_name,
" #",
LibString.toString(tokenId),
'","attributes":',
attributesJson,
',"image":"',
imageURI,
'"}'
)
)
)
);
}
}
文件 5 的 6:LibString.sol
pragma solidity ^0.8.4;
library LibString {
error HexLengthInsufficient();
error TooBigForSmallString();
error StringNot7BitASCII();
uint256 internal constant NOT_FOUND = type(uint256).max;
uint128 internal constant ALPHANUMERIC_7_BIT_ASCII = 0x7fffffe07fffffe03ff000000000000;
uint128 internal constant LETTERS_7_BIT_ASCII = 0x7fffffe07fffffe0000000000000000;
uint128 internal constant LOWERCASE_7_BIT_ASCII = 0x7fffffe000000000000000000000000;
uint128 internal constant UPPERCASE_7_BIT_ASCII = 0x7fffffe0000000000000000;
uint128 internal constant DIGITS_7_BIT_ASCII = 0x3ff000000000000;
uint128 internal constant HEXDIGITS_7_BIT_ASCII = 0x7e0000007e03ff000000000000;
uint128 internal constant OCTDIGITS_7_BIT_ASCII = 0xff000000000000;
uint128 internal constant PRINTABLE_7_BIT_ASCII = 0x7fffffffffffffffffffffff00003e00;
uint128 internal constant PUNCTUATION_7_BIT_ASCII = 0x78000001f8000001fc00fffe00000000;
uint128 internal constant WHITESPACE_7_BIT_ASCII = 0x100003e00;
function toString(uint256 value) internal pure returns (string memory result) {
assembly {
result := add(mload(0x40), 0x80)
mstore(0x40, add(result, 0x20))
mstore(result, 0)
let end := result
let w := not(0)
for { let temp := value } 1 {} {
result := add(result, w)
mstore8(result, add(48, mod(temp, 10)))
temp := div(temp, 10)
if iszero(temp) { break }
}
let n := sub(end, result)
result := sub(result, 0x20)
mstore(result, n)
}
}
function toString(int256 value) internal pure returns (string memory result) {
if (value >= 0) return toString(uint256(value));
unchecked {
result = toString(~uint256(value) + 1);
}
assembly {
let n := mload(result)
mstore(result, 0x2d)
result := sub(result, 1)
mstore(result, add(n, 1))
}
}
function toHexString(uint256 value, uint256 length)
internal
pure
returns (string memory result)
{
result = toHexStringNoPrefix(value, length);
assembly {
let n := add(mload(result), 2)
mstore(result, 0x3078)
result := sub(result, 2)
mstore(result, n)
}
}
function toHexStringNoPrefix(uint256 value, uint256 length)
internal
pure
returns (string memory result)
{
assembly {
result := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f)))
mstore(0x40, add(result, 0x20))
mstore(result, 0)
let end := result
mstore(0x0f, 0x30313233343536373839616263646566)
let start := sub(result, add(length, length))
let w := not(1)
let temp := value
for {} 1 {} {
result := add(result, w)
mstore8(add(result, 1), mload(and(temp, 15)))
mstore8(result, mload(and(shr(4, temp), 15)))
temp := shr(8, temp)
if iszero(xor(result, start)) { break }
}
if temp {
mstore(0x00, 0x2194895a)
revert(0x1c, 0x04)
}
let n := sub(end, result)
result := sub(result, 0x20)
mstore(result, n)
}
}
function toHexString(uint256 value) internal pure returns (string memory result) {
result = toHexStringNoPrefix(value);
assembly {
let n := add(mload(result), 2)
mstore(result, 0x3078)
result := sub(result, 2)
mstore(result, n)
}
}
function toMinimalHexString(uint256 value) internal pure returns (string memory result) {
result = toHexStringNoPrefix(value);
assembly {
let o := eq(byte(0, mload(add(result, 0x20))), 0x30)
let n := add(mload(result), 2)
mstore(add(result, o), 0x3078)
result := sub(add(result, o), 2)
mstore(result, sub(n, o))
}
}
function toMinimalHexStringNoPrefix(uint256 value)
internal
pure
returns (string memory result)
{
result = toHexStringNoPrefix(value);
assembly {
let o := eq(byte(0, mload(add(result, 0x20))), 0x30)
let n := mload(result)
result := add(result, o)
mstore(result, sub(n, o))
}
}
function toHexStringNoPrefix(uint256 value) internal pure returns (string memory result) {
assembly {
result := add(mload(0x40), 0x80)
mstore(0x40, add(result, 0x20))
mstore(result, 0)
let end := result
mstore(0x0f, 0x30313233343536373839616263646566)
let w := not(1)
for { let temp := value } 1 {} {
result := add(result, w)
mstore8(add(result, 1), mload(and(temp, 15)))
mstore8(result, mload(and(shr(4, temp), 15)))
temp := shr(8, temp)
if iszero(temp) { break }
}
let n := sub(end, result)
result := sub(result, 0x20)
mstore(result, n)
}
}
function toHexStringChecksummed(address value) internal pure returns (string memory result) {
result = toHexString(value);
assembly {
let mask := shl(6, div(not(0), 255))
let o := add(result, 0x22)
let hashed := and(keccak256(o, 40), mul(34, mask))
let t := shl(240, 136)
for { let i := 0 } 1 {} {
mstore(add(i, i), mul(t, byte(i, hashed)))
i := add(i, 1)
if eq(i, 20) { break }
}
mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))
o := add(o, 0x20)
mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))
}
}
function toHexString(address value) internal pure returns (string memory result) {
result = toHexStringNoPrefix(value);
assembly {
let n := add(mload(result), 2)
mstore(result, 0x3078)
result := sub(result, 2)
mstore(result, n)
}
}
function toHexStringNoPrefix(address value) internal pure returns (string memory result) {
assembly {
result := mload(0x40)
mstore(0x40, add(result, 0x80))
mstore(0x0f, 0x30313233343536373839616263646566)
result := add(result, 2)
mstore(result, 40)
let o := add(result, 0x20)
mstore(add(o, 40), 0)
value := shl(96, value)
for { let i := 0 } 1 {} {
let p := add(o, add(i, i))
let temp := byte(i, value)
mstore8(add(p, 1), mload(and(temp, 15)))
mstore8(p, mload(shr(4, temp)))
i := add(i, 1)
if eq(i, 20) { break }
}
}
}
function toHexString(bytes memory raw) internal pure returns (string memory result) {
result = toHexStringNoPrefix(raw);
assembly {
let n := add(mload(result), 2)
mstore(result, 0x3078)
result := sub(result, 2)
mstore(result, n)
}
}
function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory result) {
assembly {
let n := mload(raw)
result := add(mload(0x40), 2)
mstore(result, add(n, n))
mstore(0x0f, 0x30313233343536373839616263646566)
let o := add(result, 0x20)
let end := add(raw, n)
for {} iszero(eq(raw, end)) {} {
raw := add(raw, 1)
mstore8(add(o, 1), mload(and(mload(raw), 15)))
mstore8(o, mload(and(shr(4, mload(raw)), 15)))
o := add(o, 2)
}
mstore(o, 0)
mstore(0x40, add(o, 0x20))
}
}
function runeCount(string memory s) internal pure returns (uint256 result) {
assembly {
if mload(s) {
mstore(0x00, div(not(0), 255))
mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506)
let o := add(s, 0x20)
let end := add(o, mload(s))
for { result := 1 } 1 { result := add(result, 1) } {
o := add(o, byte(0, mload(shr(250, mload(o)))))
if iszero(lt(o, end)) { break }
}
}
}
}
function is7BitASCII(string memory s) internal pure returns (bool result) {
assembly {
result := 1
let mask := shl(7, div(not(0), 255))
let n := mload(s)
if n {
let o := add(s, 0x20)
let end := add(o, n)
let last := mload(end)
mstore(end, 0)
for {} 1 {} {
if and(mask, mload(o)) {
result := 0
break
}
o := add(o, 0x20)
if iszero(lt(o, end)) { break }
}
mstore(end, last)
}
}
}
function is7BitASCII(string memory s, uint128 allowed) internal pure returns (bool result) {
assembly {
result := 1
if mload(s) {
let allowed_ := shr(128, shl(128, allowed))
let o := add(s, 0x20)
for { let end := add(o, mload(s)) } 1 {} {
result := and(result, shr(byte(0, mload(o)), allowed_))
o := add(o, 1)
if iszero(and(result, lt(o, end))) { break }
}
}
}
}
function to7BitASCIIAllowedLookup(string memory s) internal pure returns (uint128 result) {
assembly {
if mload(s) {
let o := add(s, 0x20)
for { let end := add(o, mload(s)) } 1 {} {
result := or(result, shl(byte(0, mload(o)), 1))
o := add(o, 1)
if iszero(lt(o, end)) { break }
}
if shr(128, result) {
mstore(0x00, 0xc9807e0d)
revert(0x1c, 0x04)
}
}
}
}
function replace(string memory subject, string memory needle, string memory replacement)
internal
pure
returns (string memory result)
{
assembly {
result := mload(0x40)
let needleLen := mload(needle)
let replacementLen := mload(replacement)
let d := sub(result, subject)
let i := add(subject, 0x20)
let end := add(i, mload(subject))
if iszero(gt(needleLen, mload(subject))) {
let subjectSearchEnd := add(sub(end, needleLen), 1)
let h := 0
if iszero(lt(needleLen, 0x20)) { h := keccak256(add(needle, 0x20), needleLen) }
let s := mload(add(needle, 0x20))
for { let m := shl(3, sub(0x20, and(needleLen, 0x1f))) } 1 {} {
let t := mload(i)
if iszero(shr(m, xor(t, s))) {
if h {
if iszero(eq(keccak256(i, needleLen), h)) {
mstore(add(i, d), t)
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
for { let j := 0 } 1 {} {
mstore(add(add(i, d), j), mload(add(add(replacement, 0x20), j)))
j := add(j, 0x20)
if iszero(lt(j, replacementLen)) { break }
}
d := sub(add(d, replacementLen), needleLen)
if needleLen {
i := add(i, needleLen)
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
mstore(add(i, d), t)
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
}
}
let n := add(sub(d, add(result, 0x20)), end)
for {} lt(i, end) { i := add(i, 0x20) } { mstore(add(i, d), mload(i)) }
let o := add(i, d)
mstore(o, 0)
mstore(0x40, add(o, 0x20))
mstore(result, n)
}
}
function indexOf(string memory subject, string memory needle, uint256 from)
internal
pure
returns (uint256 result)
{
assembly {
result := not(0)
for { let subjectLen := mload(subject) } 1 {} {
if iszero(mload(needle)) {
result := from
if iszero(gt(from, subjectLen)) { break }
result := subjectLen
break
}
let needleLen := mload(needle)
let subjectStart := add(subject, 0x20)
subject := add(subjectStart, from)
let end := add(sub(add(subjectStart, subjectLen), needleLen), 1)
let m := shl(3, sub(0x20, and(needleLen, 0x1f)))
let s := mload(add(needle, 0x20))
if iszero(and(lt(subject, end), lt(from, subjectLen))) { break }
if iszero(lt(needleLen, 0x20)) {
for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} {
if iszero(shr(m, xor(mload(subject), s))) {
if eq(keccak256(subject, needleLen), h) {
result := sub(subject, subjectStart)
break
}
}
subject := add(subject, 1)
if iszero(lt(subject, end)) { break }
}
break
}
for {} 1 {} {
if iszero(shr(m, xor(mload(subject), s))) {
result := sub(subject, subjectStart)
break
}
subject := add(subject, 1)
if iszero(lt(subject, end)) { break }
}
break
}
}
}
function indexOf(string memory subject, string memory needle)
internal
pure
returns (uint256 result)
{
result = indexOf(subject, needle, 0);
}
function lastIndexOf(string memory subject, string memory needle, uint256 from)
internal
pure
returns (uint256 result)
{
assembly {
for {} 1 {} {
result := not(0)
let needleLen := mload(needle)
if gt(needleLen, mload(subject)) { break }
let w := result
let fromMax := sub(mload(subject), needleLen)
if iszero(gt(fromMax, from)) { from := fromMax }
let end := add(add(subject, 0x20), w)
subject := add(add(subject, 0x20), from)
if iszero(gt(subject, end)) { break }
for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} {
if eq(keccak256(subject, needleLen), h) {
result := sub(subject, add(end, 1))
break
}
subject := add(subject, w)
if iszero(gt(subject, end)) { break }
}
break
}
}
}
function lastIndexOf(string memory subject, string memory needle)
internal
pure
returns (uint256 result)
{
result = lastIndexOf(subject, needle, type(uint256).max);
}
function contains(string memory subject, string memory needle) internal pure returns (bool) {
return indexOf(subject, needle) != NOT_FOUND;
}
function startsWith(string memory subject, string memory needle)
internal
pure
returns (bool result)
{
assembly {
let needleLen := mload(needle)
result := and(
iszero(gt(needleLen, mload(subject))),
eq(
keccak256(add(subject, 0x20), needleLen),
keccak256(add(needle, 0x20), needleLen)
)
)
}
}
function endsWith(string memory subject, string memory needle)
internal
pure
returns (bool result)
{
assembly {
let needleLen := mload(needle)
let inRange := iszero(gt(needleLen, mload(subject)))
result := and(
eq(
keccak256(
add(add(subject, 0x20), mul(inRange, sub(mload(subject), needleLen))),
needleLen
),
keccak256(add(needle, 0x20), needleLen)
),
inRange
)
}
}
function repeat(string memory subject, uint256 times)
internal
pure
returns (string memory result)
{
assembly {
let subjectLen := mload(subject)
if iszero(or(iszero(times), iszero(subjectLen))) {
result := mload(0x40)
subject := add(subject, 0x20)
let o := add(result, 0x20)
for {} 1 {} {
for { let j := 0 } 1 {} {
mstore(add(o, j), mload(add(subject, j)))
j := add(j, 0x20)
if iszero(lt(j, subjectLen)) { break }
}
o := add(o, subjectLen)
times := sub(times, 1)
if iszero(times) { break }
}
mstore(o, 0)
mstore(0x40, add(o, 0x20))
mstore(result, sub(o, add(result, 0x20)))
}
}
}
function slice(string memory subject, uint256 start, uint256 end)
internal
pure
returns (string memory result)
{
assembly {
let subjectLen := mload(subject)
if iszero(gt(subjectLen, end)) { end := subjectLen }
if iszero(gt(subjectLen, start)) { start := subjectLen }
if lt(start, end) {
result := mload(0x40)
let n := sub(end, start)
let i := add(subject, start)
let w := not(0x1f)
for { let j := and(add(n, 0x1f), w) } 1 {} {
mstore(add(result, j), mload(add(i, j)))
j := add(j, w)
if iszero(j) { break }
}
let o := add(add(result, 0x20), n)
mstore(o, 0)
mstore(0x40, add(o, 0x20))
mstore(result, n)
}
}
}
function slice(string memory subject, uint256 start)
internal
pure
returns (string memory result)
{
result = slice(subject, start, type(uint256).max);
}
function indicesOf(string memory subject, string memory needle)
internal
pure
returns (uint256[] memory result)
{
assembly {
let searchLen := mload(needle)
if iszero(gt(searchLen, mload(subject))) {
result := mload(0x40)
let i := add(subject, 0x20)
let o := add(result, 0x20)
let subjectSearchEnd := add(sub(add(i, mload(subject)), searchLen), 1)
let h := 0
if iszero(lt(searchLen, 0x20)) { h := keccak256(add(needle, 0x20), searchLen) }
let s := mload(add(needle, 0x20))
for { let m := shl(3, sub(0x20, and(searchLen, 0x1f))) } 1 {} {
let t := mload(i)
if iszero(shr(m, xor(t, s))) {
if h {
if iszero(eq(keccak256(i, searchLen), h)) {
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
mstore(o, sub(i, add(subject, 0x20)))
o := add(o, 0x20)
i := add(i, searchLen)
if searchLen {
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
}
mstore(result, shr(5, sub(o, add(result, 0x20))))
mstore(0x40, add(o, 0x20))
}
}
}
function split(string memory subject, string memory delimiter)
internal
pure
returns (string[] memory result)
{
uint256[] memory indices = indicesOf(subject, delimiter);
assembly {
let w := not(0x1f)
let indexPtr := add(indices, 0x20)
let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))
mstore(add(indicesEnd, w), mload(subject))
mstore(indices, add(mload(indices), 1))
for { let prevIndex := 0 } 1 {} {
let index := mload(indexPtr)
mstore(indexPtr, 0x60)
if iszero(eq(index, prevIndex)) {
let element := mload(0x40)
let l := sub(index, prevIndex)
mstore(element, l)
for { let o := and(add(l, 0x1f), w) } 1 {} {
mstore(add(element, o), mload(add(add(subject, prevIndex), o)))
o := add(o, w)
if iszero(o) { break }
}
mstore(add(add(element, 0x20), l), 0)
mstore(0x40, add(element, and(add(l, 0x3f), w)))
mstore(indexPtr, element)
}
prevIndex := add(index, mload(delimiter))
indexPtr := add(indexPtr, 0x20)
if iszero(lt(indexPtr, indicesEnd)) { break }
}
result := indices
if iszero(mload(delimiter)) {
result := add(indices, 0x20)
mstore(result, sub(mload(indices), 2))
}
}
}
function concat(string memory a, string memory b)
internal
pure
returns (string memory result)
{
assembly {
result := mload(0x40)
let w := not(0x1f)
let aLen := mload(a)
for { let o := and(add(aLen, 0x20), w) } 1 {} {
mstore(add(result, o), mload(add(a, o)))
o := add(o, w)
if iszero(o) { break }
}
let bLen := mload(b)
let output := add(result, aLen)
for { let o := and(add(bLen, 0x20), w) } 1 {} {
mstore(add(output, o), mload(add(b, o)))
o := add(o, w)
if iszero(o) { break }
}
let totalLen := add(aLen, bLen)
let last := add(add(result, 0x20), totalLen)
mstore(last, 0)
mstore(result, totalLen)
mstore(0x40, add(last, 0x20))
}
}
function toCase(string memory subject, bool toUpper)
internal
pure
returns (string memory result)
{
assembly {
let n := mload(subject)
if n {
result := mload(0x40)
let o := add(result, 0x20)
let d := sub(subject, result)
let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)
for { let end := add(o, n) } 1 {} {
let b := byte(0, mload(add(d, o)))
mstore8(o, xor(and(shr(b, flags), 0x20), b))
o := add(o, 1)
if eq(o, end) { break }
}
mstore(result, n)
mstore(o, 0)
mstore(0x40, add(o, 0x20))
}
}
}
function fromSmallString(bytes32 s) internal pure returns (string memory result) {
assembly {
result := mload(0x40)
let n := 0
for {} byte(n, s) { n := add(n, 1) } {}
mstore(result, n)
let o := add(result, 0x20)
mstore(o, s)
mstore(add(o, n), 0)
mstore(0x40, add(result, 0x40))
}
}
function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) {
assembly {
for {} byte(result, s) { result := add(result, 1) } {}
mstore(0x00, s)
mstore(result, 0x00)
result := mload(0x00)
}
}
function toSmallString(string memory s) internal pure returns (bytes32 result) {
assembly {
result := mload(s)
if iszero(lt(result, 33)) {
mstore(0x00, 0xec92f9a3)
revert(0x1c, 0x04)
}
result := shl(shl(3, sub(32, result)), mload(add(s, result)))
}
}
function lower(string memory subject) internal pure returns (string memory result) {
result = toCase(subject, false);
}
function upper(string memory subject) internal pure returns (string memory result) {
result = toCase(subject, true);
}
function escapeHTML(string memory s) internal pure returns (string memory result) {
assembly {
result := mload(0x40)
let end := add(s, mload(s))
let o := add(result, 0x20)
mstore(0x1f, 0x900094)
mstore(0x08, 0xc0000000a6ab)
mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b))
for {} iszero(eq(s, end)) {} {
s := add(s, 1)
let c := and(mload(s), 0xff)
if iszero(and(shl(c, 1), 0x500000c400000000)) {
mstore8(o, c)
o := add(o, 1)
continue
}
let t := shr(248, mload(c))
mstore(o, mload(and(t, 0x1f)))
o := add(o, shr(5, t))
}
mstore(o, 0)
mstore(result, sub(o, add(result, 0x20)))
mstore(0x40, add(o, 0x20))
}
}
function escapeJSON(string memory s, bool addDoubleQuotes)
internal
pure
returns (string memory result)
{
assembly {
result := mload(0x40)
let o := add(result, 0x20)
if addDoubleQuotes {
mstore8(o, 34)
o := add(1, o)
}
mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672)
let e := or(shl(0x22, 1), shl(0x5c, 1))
for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} {
s := add(s, 1)
let c := and(mload(s), 0xff)
if iszero(lt(c, 0x20)) {
if iszero(and(shl(c, 1), e)) {
mstore8(o, c)
o := add(o, 1)
continue
}
mstore8(o, 0x5c)
mstore8(add(o, 1), c)
o := add(o, 2)
continue
}
if iszero(and(shl(c, 1), 0x3700)) {
mstore8(0x1d, mload(shr(4, c)))
mstore8(0x1e, mload(and(c, 15)))
mstore(o, mload(0x19))
o := add(o, 6)
continue
}
mstore8(o, 0x5c)
mstore8(add(o, 1), mload(add(c, 8)))
o := add(o, 2)
}
if addDoubleQuotes {
mstore8(o, 34)
o := add(1, o)
}
mstore(o, 0)
mstore(result, sub(o, add(result, 0x20)))
mstore(0x40, add(o, 0x20))
}
}
function escapeJSON(string memory s) internal pure returns (string memory result) {
result = escapeJSON(s, false);
}
function encodeURIComponent(string memory s) internal pure returns (string memory result) {
assembly {
result := mload(0x40)
mstore(0x0f, 0x30313233343536373839414243444546)
let o := add(result, 0x20)
for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} {
s := add(s, 1)
let c := and(mload(s), 0xff)
if iszero(and(1, shr(c, 0x47fffffe87fffffe03ff678200000000))) {
mstore8(o, 0x25)
mstore8(add(o, 1), mload(and(shr(4, c), 15)))
mstore8(add(o, 2), mload(and(c, 15)))
o := add(o, 3)
continue
}
mstore8(o, c)
o := add(o, 1)
}
mstore(result, sub(o, add(result, 0x20)))
mstore(o, 0)
mstore(0x40, add(o, 0x20))
}
}
function eq(string memory a, string memory b) internal pure returns (bool result) {
assembly {
result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))
}
}
function eqs(string memory a, bytes32 b) internal pure returns (bool result) {
assembly {
let m := not(shl(7, div(not(iszero(b)), 255)))
let x := not(or(m, or(b, add(m, and(b, m)))))
let r := shl(7, iszero(iszero(shr(128, x))))
r := or(r, shl(6, iszero(iszero(shr(64, 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))))
result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),
xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))
}
}
function packOne(string memory a) internal pure returns (bytes32 result) {
assembly {
result :=
mul(
mload(add(a, 0x1f)),
lt(sub(mload(a), 1), 0x1f)
)
}
}
function unpackOne(bytes32 packed) internal pure returns (string memory result) {
assembly {
result := mload(0x40)
mstore(0x40, add(result, 0x40))
mstore(result, 0)
mstore(add(result, 0x1f), packed)
mstore(add(add(result, 0x20), mload(result)), 0)
}
}
function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) {
assembly {
let aLen := mload(a)
result :=
mul(
or(
shl(shl(3, sub(0x1f, aLen)), mload(add(a, aLen))), mload(sub(add(b, 0x1e), aLen))),
lt(sub(add(aLen, mload(b)), 1), 0x1e)
)
}
}
function unpackTwo(bytes32 packed)
internal
pure
returns (string memory resultA, string memory resultB)
{
assembly {
resultA := mload(0x40)
resultB := add(resultA, 0x40)
mstore(0x40, add(resultB, 0x40))
mstore(resultA, 0)
mstore(resultB, 0)
mstore(add(resultA, 0x1f), packed)
mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA))))
mstore(add(add(resultA, 0x20), mload(resultA)), 0)
mstore(add(add(resultB, 0x20), mload(resultB)), 0)
}
}
function directReturn(string memory a) internal pure {
assembly {
let retStart := sub(a, 0x20)
let retUnpaddedSize := add(mload(a), 0x40)
mstore(add(retStart, retUnpaddedSize), 0)
mstore(retStart, 0x20)
return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize)))
}
}
}
文件 6 的 6:TraitsMetadata.sol
pragma solidity ^0.8.28;
interface ITraitRegistry {
function registerCollection(address owner) external;
function getCollectionTraitTypeCount() external view returns (uint256);
function generateRandomTraits(uint256[] memory randomSeeds)
external
view
returns (uint256[] memory traitIds);
function getAttibutesJson(uint256[] memory traitIds) external view returns (string memory);
function getImageURIOf(uint256[] memory traitIds) external view returns (string memory);
}
abstract contract TraitsMetadata {
event TraitRegistrySet(address traitRegistry);
event TokenBatchAdded(
uint256 batchIndex,
uint256 fromTokenId,
uint256 toTokenId,
address minter,
uint256 timestamp
);
error TokenNotMinted();
struct TokenBatch {
uint32 fromTokenId;
uint32 toTokenId;
address minter;
uint32 timestamp;
}
struct TraitsMetadataStorage {
ITraitRegistry traitRegistry;
uint64 batchCount;
mapping(uint64 batchIndex => TokenBatch batch) mintBatches;
}
function _getTraitsMetadataStorage()
internal
pure
virtual
returns (TraitsMetadataStorage storage $)
{
assembly ("memory-safe") {
$.slot := 0xae051faf52657fcd53347f0e4cbde96efc859c0144969f104459b1251f1e0a00
}
}
function _initializeTraitsMetadata(address _traitRegistry, address _traitOwner) internal {
_getTraitsMetadataStorage().traitRegistry = ITraitRegistry(_traitRegistry);
emit TraitRegistrySet(_traitRegistry);
ITraitRegistry(_traitRegistry).registerCollection(_traitOwner);
}
function tokenTraits(uint256 tokenId) public view returns (uint256[] memory traitIds) {
TraitsMetadataStorage storage $ = _getTraitsMetadataStorage();
ITraitRegistry traitHub = $.traitRegistry;
uint256 traitCount = traitHub.getCollectionTraitTypeCount();
if (traitCount == 0) return traitIds;
TokenBatch memory batch = _findTokenBatch($, tokenId);
uint256[] memory randomSeeds = new uint256[](traitCount);
_getTraitRandomSeeds(
randomSeeds,
tokenId,
keccak256(
abi.encodePacked(batch.fromTokenId, batch.toTokenId, batch.minter, batch.timestamp)
)
);
traitIds = traitHub.generateRandomTraits(randomSeeds);
}
function traitRegistry() public view returns (address) {
return address(_getTraitsMetadataStorage().traitRegistry);
}
function _getTokenAttributesAndImage(uint256 tokenId)
internal
view
virtual
returns (string memory attributesJson, string memory imageURI)
{
TraitsMetadataStorage storage $ = _getTraitsMetadataStorage();
uint256[] memory traitIds = tokenTraits(tokenId);
address _traitRegistry = address($.traitRegistry);
attributesJson = _readStringByArray(_traitRegistry, 0xbc58599a, traitIds);
imageURI = _readStringByArray(_traitRegistry, 0x4c182a01, traitIds);
}
function _addTokenBatch(address minter, uint256 fromTokenId, uint256 toTokenId)
internal
virtual
{
TraitsMetadataStorage storage $ = _getTraitsMetadataStorage();
uint256 batchIndex = $.batchCount++;
$.mintBatches[uint64(batchIndex)] = TokenBatch({
fromTokenId: uint32(fromTokenId),
toTokenId: uint32(toTokenId),
minter: minter,
timestamp: uint32(block.timestamp)
});
emit TokenBatchAdded(batchIndex, fromTokenId, toTokenId, minter, block.timestamp);
}
function _findTokenBatch(TraitsMetadataStorage storage $, uint256 tokenId)
internal
view
returns (TokenBatch memory batch)
{
uint256 start = 0;
uint256 end = $.batchCount;
mapping(uint64 => TokenBatch) storage batches = $.mintBatches;
unchecked {
while (start < end) {
uint256 mid = (start + end) >> 1;
batch = batches[uint64(mid)];
if (batch.fromTokenId <= tokenId && tokenId <= batch.toTokenId) {
return batch;
}
if (tokenId < batch.fromTokenId) {
end = mid;
} else {
start = mid + 1;
}
}
revert TokenNotMinted();
}
}
function _getTraitRandomSeeds(uint256[] memory randomSeeds, uint256 seed, bytes32 salt)
internal
pure
{
unchecked {
uint256 count = randomSeeds.length;
for (uint256 i = 0; i < count; ++i) {
randomSeeds[i] = uint256(keccak256(abi.encodePacked(i, salt, seed)));
}
}
}
function _readStringByArray(address target, uint256 fnSelector, uint256[] memory array)
private
view
returns (string memory result)
{
assembly ("memory-safe") {
let ptr := mload(0x40)
mstore(ptr, fnSelector)
let arrayLen := mload(array)
mstore(add(ptr, 0x20), 0x20)
mstore(add(ptr, 0x40), arrayLen)
let arrayDataSize := mul(arrayLen, 0x20)
mcopy(
add(ptr, 0x60),
add(array, 0x20),
arrayDataSize
)
let encodedSize := add(0x44, arrayDataSize)
if iszero(staticcall(gas(), target, add(ptr, 0x1c), encodedSize, 0x00, 0x00)) {
returndatacopy(ptr, 0x00, returndatasize())
revert(ptr, returndatasize())
}
result := ptr
returndatacopy(0x00, 0x00, 0x20)
returndatacopy(result, mload(0x00), 0x20)
returndatacopy(add(result, 0x20), add(mload(0x00), 0x20), mload(result))
let nextPtr := add(add(result, 0x20), mload(result))
let padding := and(sub(32, and(nextPtr, 31)), 31)
mstore(0x40, add(nextPtr, padding))
}
}
}
{
"compilationTarget": {
"src/bitmap-punk/BitmapPunks721.sol": "BitmapPunks721"
},
"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":"_traitRegistry","type":"address"},{"internalType":"address","name":"_traitOwner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyLinked","type":"error"},{"inputs":[],"name":"CannotLink","type":"error"},{"inputs":[],"name":"NotLinked","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[],"name":"SenderNotBase","type":"error"},{"inputs":[],"name":"SenderNotDeployer","type":"error"},{"inputs":[],"name":"TokenNotMinted","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"isApproved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"address","name":"bidToken","type":"address"}],"name":"Bid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"maker","type":"address"}],"name":"Bought","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"}],"name":"CancelBid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"CancelOffer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"idX","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"idY","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exchangeFee","type":"uint256"}],"name":"Exchange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"minPrice","type":"uint256"},{"indexed":false,"internalType":"address","name":"offerToken","type":"address"}],"name":"Offer","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":false,"internalType":"uint256","name":"batchIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"TokenBatchAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"traitRegistry","type":"address"}],"name":"TraitRegistrySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bool","name":"lockStatus","type":"bool"}],"name":"UpdateLockState","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"trader","type":"address"}],"internalType":"struct BT404Mirror.NFTOrder[]","name":"orders","type":"tuple[]"}],"name":"acceptBid","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"trader","type":"address"}],"internalType":"struct BT404Mirror.NFTOrder[]","name":"orders","type":"tuple[]"}],"name":"acceptOffer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftOwner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseERC20","outputs":[{"internalType":"address","name":"base","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"trader","type":"address"}],"internalType":"struct BT404Mirror.NFTOrder[]","name":"orders","type":"tuple[]"}],"name":"bidForBuy","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"cancelBid","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"cancelOffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"idX","type":"uint256"},{"internalType":"uint256","name":"idY","type":"uint256"}],"name":"exchange","outputs":[{"internalType":"uint256","name":"exchangeFee","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftOwner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"begin","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"}],"name":"lockedIds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"result","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"trader","type":"address"}],"internalType":"struct BT404Mirror.NFTOrder[]","name":"orders","type":"tuple[]"}],"name":"offerForSale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"begin","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"}],"name":"ownedIds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerAt","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pullOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"result","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenTraits","outputs":[{"internalType":"uint256[]","name":"traitIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"traitRegistry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"bool","name":"lock","type":"bool"}],"name":"updateLockState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]