Skip to content
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
bcdd5be
new contracts
wolfy-nft Dec 5, 2024
6473f8f
lint
wolfy-nft Dec 5, 2024
4a672f0
forge install: ERC721A
wolfy-nft Dec 5, 2024
159ec2f
add cloneables
wolfy-nft Dec 5, 2024
5a6110f
fmt
wolfy-nft Dec 5, 2024
4ad4cdc
cloneable
wolfy-nft Dec 5, 2024
3df1b0a
move contract version to another branch
wolfy-nft Dec 6, 2024
61a9e14
add old version back
wolfy-nft Dec 6, 2024
6dd656b
fix
wolfy-nft Dec 6, 2024
b5e3f9f
add docs
wolfy-nft Dec 9, 2024
2eff675
stage logic
wolfy-nft Dec 9, 2024
8d9bd49
docs and tests
wolfy-nft Dec 10, 2024
2ed0306
cleanup
wolfy-nft Dec 10, 2024
1b7861c
enforce private before public, and transfer proceeds on mint
wolfy-nft Dec 10, 2024
d6387cf
updates
wolfy-nft Dec 12, 2024
96e5a6b
updates
wolfy-nft Dec 17, 2024
c3c2f02
add file end newline
wolfy-nft Dec 17, 2024
e5ac063
updates
wolfy-nft Dec 18, 2024
fd3fc3b
updates
wolfy-nft Dec 18, 2024
fb00eab
fix
wolfy-nft Dec 18, 2024
2185a94
add royalties to config
wolfy-nft Dec 19, 2024
1cca4f6
fmt
wolfy-nft Dec 19, 2024
44f2849
add config function
wolfy-nft Jan 2, 2025
c04f419
emit contract uri event
wolfy-nft Jan 6, 2025
763b1d5
add heading
wolfy-nft Jan 7, 2025
bcd2e66
zero protocol fee
wolfy-nft Jan 8, 2025
fe7cb9b
add missing events
wolfy-nft Jan 14, 2025
2da14ea
add mint event
wolfy-nft Jan 14, 2025
ace522b
update merkle tree impl
wolfy-nft Jan 16, 2025
4a35232
fmt
wolfy-nft Jan 16, 2025
2bbe7f5
rm
wolfy-nft Jan 16, 2025
b91e8b8
remove unused imports
wolfy-nft Jan 20, 2025
0c297e0
fix required payment
wolfy-nft Jan 20, 2025
cf2ad60
rename error
wolfy-nft Jan 20, 2025
b0d1509
fix
wolfy-nft Jan 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,292 changes: 1,292 additions & 0 deletions contracts/nft/erc721m/clones/ERC721ACloneable.sol

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {ERC721AQueryableCloneable} from "./ERC721AQueryableCloneable.sol";
import {ERC721ACloneable} from "./ERC721ACloneable.sol";
import {IERC721A} from "erc721a/contracts/IERC721A.sol";

/// @title ERC721AConduitPreapprovedCloneable
/// @notice ERC721A with the MagicEden conduit preapproved.
abstract contract ERC721AConduitPreapprovedCloneable is ERC721AQueryableCloneable {
/// @dev The canonical MagicEden conduit.
address internal constant _CONDUIT = 0x2052f8A2Ff46283B30084e5d84c89A2fdBE7f74b;

/// @dev Returns if the `operator` is allowed to manage all of the
/// assets of `owner`. Always returns true for the conduit.
function isApprovedForAll(address owner, address operator)
public
view
virtual
override(ERC721ACloneable, IERC721A)
returns (bool)
{
if (operator == _CONDUIT) {
return true;
}

return ERC721ACloneable.isApprovedForAll(owner, operator);
}
}
237 changes: 237 additions & 0 deletions contracts/nft/erc721m/clones/ERC721AQueryableCloneable.sol
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a direct copy of 721AQueryable with added Initialization

Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.3.0
// Creator: Chiru Labs

pragma solidity ^0.8.4;

import {IERC721AQueryable} from "erc721a/contracts/extensions/IERC721AQueryable.sol";
import {ERC721ACloneable} from "./ERC721ACloneable.sol";

/**
* @title ERC721AQueryableCloneable.
*
* @dev ERC721A subclass with convenience query functions.
*/
abstract contract ERC721AQueryableCloneable is ERC721ACloneable, IERC721AQueryable {
/**
* @dev Returns the `TokenOwnership` struct at `tokenId` without reverting.
*
* If the `tokenId` is out of bounds:
*
* - `addr = address(0)`
* - `startTimestamp = 0`
* - `burned = false`
* - `extraData = 0`
*
* If the `tokenId` is burned:
*
* - `addr = <Address of owner before token was burned>`
* - `startTimestamp = <Timestamp when token was burned>`
* - `burned = true`
* - `extraData = <Extra data when token was burned>`
*
* Otherwise:
*
* - `addr = <Address of owner>`
* - `startTimestamp = <Timestamp of start of ownership>`
* - `burned = false`
* - `extraData = <Extra data at start of ownership>`
*/
function explicitOwnershipOf(uint256 tokenId)
public
view
virtual
override
returns (TokenOwnership memory ownership)
{
unchecked {
if (tokenId >= _startTokenId()) {
if (tokenId > _sequentialUpTo()) return _ownershipAt(tokenId);

if (tokenId < _nextTokenId()) {
// If the `tokenId` is within bounds,
// scan backwards for the initialized ownership slot.
while (!_ownershipIsInitialized(tokenId)) --tokenId;
return _ownershipAt(tokenId);
}
}
}
}

/**
* @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order.
* See {ERC721AQueryable-explicitOwnershipOf}
*/
function explicitOwnershipsOf(uint256[] calldata tokenIds)
external
view
virtual
override
returns (TokenOwnership[] memory)
{
TokenOwnership[] memory ownerships;
uint256 i = tokenIds.length;
assembly {
// Grab the free memory pointer.
ownerships := mload(0x40)
// Store the length.
mstore(ownerships, i)
// Allocate one word for the length,
// `tokenIds.length` words for the pointers.
i := shl(5, i) // Multiply `i` by 32.
mstore(0x40, add(add(ownerships, 0x20), i))
}
while (i != 0) {
uint256 tokenId;
assembly {
i := sub(i, 0x20)
tokenId := calldataload(add(tokenIds.offset, i))
}
TokenOwnership memory ownership = explicitOwnershipOf(tokenId);
assembly {
// Store the pointer of `ownership` in the `ownerships` array.
mstore(add(add(ownerships, 0x20), i), ownership)
}
}
return ownerships;
}

/**
* @dev Returns an array of token IDs owned by `owner`,
* in the range [`start`, `stop`)
* (i.e. `start <= tokenId < stop`).
*
* This function allows for tokens to be queried if the collection
* grows too big for a single call of {ERC721AQueryable-tokensOfOwner}.
*
* Requirements:
*
* - `start < stop`
*/
function tokensOfOwnerIn(address owner, uint256 start, uint256 stop)
external
view
virtual
override
returns (uint256[] memory)
{
return _tokensOfOwnerIn(owner, start, stop);
}

/**
* @dev Returns an array of token IDs owned by `owner`.
*
* This function scans the ownership mapping and is O(`totalSupply`) in complexity.
* It is meant to be called off-chain.
*
* See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into
* multiple smaller scans if the collection is large enough to cause
* an out-of-gas error (10K collections should be fine).
*/
function tokensOfOwner(address owner) external view virtual override returns (uint256[] memory) {
// If spot mints are enabled, full-range scan is disabled.
if (_sequentialUpTo() != type(uint256).max) {
_revert(NotCompatibleWithSpotMints.selector);
}
uint256 start = _startTokenId();
uint256 stop = _nextTokenId();
uint256[] memory tokenIds;
if (start != stop) tokenIds = _tokensOfOwnerIn(owner, start, stop);
return tokenIds;
}

/**
* @dev Helper function for returning an array of token IDs owned by `owner`.
*
* Note that this function is optimized for smaller bytecode size over runtime gas,
* since it is meant to be called off-chain.
*/
function _tokensOfOwnerIn(address owner, uint256 start, uint256 stop)
private
view
returns (uint256[] memory tokenIds)
{
unchecked {
if (start >= stop) _revert(InvalidQueryRange.selector);
// Set `start = max(start, _startTokenId())`.
if (start < _startTokenId()) start = _startTokenId();
uint256 nextTokenId = _nextTokenId();
// If spot mints are enabled, scan all the way until the specified `stop`.
uint256 stopLimit = _sequentialUpTo() != type(uint256).max ? stop : nextTokenId;
// Set `stop = min(stop, stopLimit)`.
if (stop >= stopLimit) stop = stopLimit;
// Number of tokens to scan.
uint256 tokenIdsMaxLength = balanceOf(owner);
// Set `tokenIdsMaxLength` to zero if the range contains no tokens.
if (start >= stop) tokenIdsMaxLength = 0;
// If there are one or more tokens to scan.
if (tokenIdsMaxLength != 0) {
// Set `tokenIdsMaxLength = min(balanceOf(owner), tokenIdsMaxLength)`.
if (stop - start <= tokenIdsMaxLength) {
tokenIdsMaxLength = stop - start;
}
uint256 m; // Start of available memory.
assembly {
// Grab the free memory pointer.
tokenIds := mload(0x40)
// Allocate one word for the length, and `tokenIdsMaxLength` words
// for the data. `shl(5, x)` is equivalent to `mul(32, x)`.
m := add(tokenIds, shl(5, add(tokenIdsMaxLength, 1)))
mstore(0x40, m)
}
// We need to call `explicitOwnershipOf(start)`,
// because the slot at `start` may not be initialized.
TokenOwnership memory ownership = explicitOwnershipOf(start);
address currOwnershipAddr;
// If the starting slot exists (i.e. not burned),
// initialize `currOwnershipAddr`.
// `ownership.address` will not be zero,
// as `start` is clamped to the valid token ID range.
if (!ownership.burned) currOwnershipAddr = ownership.addr;
uint256 tokenIdsIdx;
// Use a do-while, which is slightly more efficient for this case,
// as the array will at least contain one element.
do {
if (_sequentialUpTo() != type(uint256).max) {
// Skip the remaining unused sequential slots.
if (start == nextTokenId) start = _sequentialUpTo() + 1;
// Reset `currOwnershipAddr`, as each spot-minted token is a batch of one.
if (start > _sequentialUpTo()) {
currOwnershipAddr = address(0);
}
}
ownership = _ownershipAt(start); // This implicitly allocates memory.
assembly {
switch mload(add(ownership, 0x40))
// if `ownership.burned == false`.
case 0 {
// if `ownership.addr != address(0)`.
// The `addr` already has it's upper 96 bits clearned,
// since it is written to memory with regular Solidity.
if mload(ownership) { currOwnershipAddr := mload(ownership) }
// if `currOwnershipAddr == owner`.
// The `shl(96, x)` is to make the comparison agnostic to any
// dirty upper 96 bits in `owner`.
if iszero(shl(96, xor(currOwnershipAddr, owner))) {
tokenIdsIdx := add(tokenIdsIdx, 1)
mstore(add(tokenIds, shl(5, tokenIdsIdx)), start)
}
}
// Otherwise, reset `currOwnershipAddr`.
// This handles the case of batch burned tokens
// (burned bit of first slot set, remaining slots left uninitialized).
default { currOwnershipAddr := 0 }
start := add(start, 1)
// Free temporary memory implicitly allocated for ownership
// to avoid quadratic memory expansion costs.
mstore(0x40, m)
}
} while (!(start == stop || tokenIdsIdx == tokenIdsMaxLength));
// Store the length of the array.
assembly {
mstore(tokenIds, tokenIdsIdx)
}
}
}
}
}
Loading