Skip to content

Commit

Permalink
Feat: Add Interface (#243)
Browse files Browse the repository at this point in the history
* Add interfaces

* Use interfaces in main contracts

* change structure similar to OZ

* move errors in interfaces class level

* run prettier
  • Loading branch information
ahbanavi authored Apr 26, 2022
1 parent b738004 commit 0f88c36
Show file tree
Hide file tree
Showing 10 changed files with 175 additions and 47 deletions.
45 changes: 3 additions & 42 deletions contracts/ERC721A.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,13 @@

pragma solidity ^0.8.4;

import '@openzeppelin/contracts/token/ERC721/IERC721.sol';
import './IERC721A.sol';
import '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol';
import '@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol';
import '@openzeppelin/contracts/utils/Address.sol';
import '@openzeppelin/contracts/utils/Context.sol';
import '@openzeppelin/contracts/utils/Strings.sol';
import '@openzeppelin/contracts/utils/introspection/ERC165.sol';

error ApprovalCallerNotOwnerNorApproved();
error ApprovalQueryForNonexistentToken();
error ApproveToCaller();
error ApprovalToCurrentOwner();
error BalanceQueryForZeroAddress();
error MintToZeroAddress();
error MintZeroQuantity();
error OwnerQueryForNonexistentToken();
error TransferCallerNotOwnerNorApproved();
error TransferFromIncorrectOwner();
error TransferToNonERC721ReceiverImplementer();
error TransferToZeroAddress();
error URIQueryForNonexistentToken();

/**
* @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
* the Metadata extension. Built to optimize for lower gas during batch mints.
Expand All @@ -35,34 +20,10 @@ error URIQueryForNonexistentToken();
*
* Assumes that the maximum token id cannot exceed 2**256 - 1 (max value of uint256).
*/
contract ERC721A is Context, ERC165, IERC721, IERC721Metadata {
contract ERC721A is Context, ERC165, IERC721A {
using Address for address;
using Strings for uint256;

// Compiler will pack this into a single 256bit word.
struct TokenOwnership {
// The address of the owner.
address addr;
// Keeps track of the start time of ownership with minimal overhead for tokenomics.
uint64 startTimestamp;
// Whether the token has been burned.
bool burned;
}

// Compiler will pack this into a single 256bit word.
struct AddressData {
// Realistically, 2**64-1 is more than enough.
uint64 balance;
// Keeps track of mint count with minimal overhead for tokenomics.
uint64 numberMinted;
// Keeps track of burn count with minimal overhead for tokenomics.
uint64 numberBurned;
// For miscellaneous variable(s) pertaining to the address
// (e.g. number of whitelist mint slots used).
// If there are multiple variables, please pack them into a uint64.
uint64 aux;
}

// The tokenId of the next token to be minted.
uint256 internal _currentIndex;

Expand Down Expand Up @@ -341,7 +302,7 @@ contract ERC721A is Context, ERC165, IERC721, IERC721Metadata {
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
* - `quantity` must be greater than 0.
*
Expand Down
56 changes: 56 additions & 0 deletions contracts/IERC721A.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// SPDX-License-Identifier: MIT
// Creator: Chiru Labs

pragma solidity ^0.8.4;

import '@openzeppelin/contracts/token/ERC721/IERC721.sol';
import '@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol';

/**
* @dev Interface of an ERC721A compliant contract.
*/
interface IERC721A is IERC721, IERC721Metadata {
error ApprovalCallerNotOwnerNorApproved();
error ApprovalQueryForNonexistentToken();
error ApproveToCaller();
error ApprovalToCurrentOwner();
error BalanceQueryForZeroAddress();
error MintToZeroAddress();
error MintZeroQuantity();
error OwnerQueryForNonexistentToken();
error TransferCallerNotOwnerNorApproved();
error TransferFromIncorrectOwner();
error TransferToNonERC721ReceiverImplementer();
error TransferToZeroAddress();
error URIQueryForNonexistentToken();

// Compiler will pack this into a single 256bit word.
struct TokenOwnership {
// The address of the owner.
address addr;
// Keeps track of the start time of ownership with minimal overhead for tokenomics.
uint64 startTimestamp;
// Whether the token has been burned.
bool burned;
}

// Compiler will pack this into a single 256bit word.
struct AddressData {
// Realistically, 2**64-1 is more than enough.
uint64 balance;
// Keeps track of mint count with minimal overhead for tokenomics.
uint64 numberMinted;
// Keeps track of burn count with minimal overhead for tokenomics.
uint64 numberBurned;
// For miscellaneous variable(s) pertaining to the address
// (e.g. number of whitelist mint slots used).
// If there are multiple variables, please pack them into a uint64.
uint64 aux;
}

/**
* @dev Returns the total amount of tokens stored by the contract.
* @dev Burned tokens are calculated here, use _totalMinted() if you want to count just minted tokens.
*/
function totalSupply() external view returns (uint256);
}
3 changes: 2 additions & 1 deletion contracts/extensions/ERC721ABurnable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@

pragma solidity ^0.8.4;

import './IERC721ABurnable.sol';
import '../ERC721A.sol';

/**
* @title ERC721A Burnable Token
* @dev ERC721A Token that can be irreversibly burned (destroyed).
*/
abstract contract ERC721ABurnable is ERC721A {
abstract contract ERC721ABurnable is ERC721A, IERC721ABurnable {
/**
* @dev Burns `tokenId`. See {ERC721A-_burn}.
*
Expand Down
5 changes: 2 additions & 3 deletions contracts/extensions/ERC721AQueryable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@

pragma solidity ^0.8.4;

import './IERC721AQueryable.sol';
import '../ERC721A.sol';

error InvalidQueryRange();

/**
* @title ERC721A Queryable
* @dev ERC721A subclass with convenience query functions.
*/
abstract contract ERC721AQueryable is ERC721A {
abstract contract ERC721AQueryable is ERC721A, IERC721AQueryable {
/**
* @dev Returns the `TokenOwnership` struct at `tokenId` without reverting.
*
Expand Down
20 changes: 20 additions & 0 deletions contracts/extensions/IERC721ABurnable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: MIT
// Creator: Chiru Labs

pragma solidity ^0.8.4;

import '../IERC721A.sol';

/**
* @dev Interface of an ERC721ABurnable compliant contract.
*/
interface IERC721ABurnable is IERC721A {
/**
* @dev Burns `tokenId`. See {ERC721A-_burn}.
*
* Requirements:
*
* - The caller must own `tokenId` or be an approved operator.
*/
function burn(uint256 tokenId) external;
}
69 changes: 69 additions & 0 deletions contracts/extensions/IERC721AQueryable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// SPDX-License-Identifier: MIT
// Creator: Chiru Labs

pragma solidity ^0.8.4;

import '../IERC721A.sol';

/**
* @dev Interface of an ERC721AQueryable compliant contract.
*/
interface IERC721AQueryable is IERC721A {
error InvalidQueryRange();

/**
* @dev Returns the `TokenOwnership` struct at `tokenId` without reverting.
*
* If the `tokenId` is out of bounds:
* - `addr` = `address(0)`
* - `startTimestamp` = `0`
* - `burned` = `false`
*
* If the `tokenId` is burned:
* - `addr` = `<Address of owner before token was burned>`
* - `startTimestamp` = `<Timestamp when token was burned>`
* - `burned = `true`
*
* Otherwise:
* - `addr` = `<Address of owner>`
* - `startTimestamp` = `<Timestamp of start of ownership>`
* - `burned = `false`
*/
function explicitOwnershipOf(uint256 tokenId) external view returns (TokenOwnership memory);

/**
* @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order.
* See {ERC721AQueryable-explicitOwnershipOf}
*/
function explicitOwnershipsOf(uint256[] memory tokenIds) external view returns (TokenOwnership[] memory);

/**
* @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 returns (uint256[] memory);

/**
* @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 pfp collections should be fine).
*/
function tokensOfOwner(address owner) external view returns (uint256[] memory);
}
6 changes: 6 additions & 0 deletions contracts/interfaces/IERC721A.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: MIT
// Creator: Chiru Labs

pragma solidity ^0.8.4;

import '../IERC721A.sol';
6 changes: 6 additions & 0 deletions contracts/interfaces/IERC721ABurnable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: MIT
// Creator: Chiru Labs

pragma solidity ^0.8.4;

import '../extensions/IERC721ABurnable.sol';
6 changes: 6 additions & 0 deletions contracts/interfaces/IERC721AQueryable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: MIT
// Creator: Chiru Labs

pragma solidity ^0.8.4;

import '../extensions/IERC721AQueryable.sol';
6 changes: 5 additions & 1 deletion contracts/mocks/ERC721AMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ contract ERC721AMock is ERC721A {
_safeMint(to, quantity);
}

function safeMint(address to, uint256 quantity, bytes memory _data) public {
function safeMint(
address to,
uint256 quantity,
bytes memory _data
) public {
_safeMint(to, quantity, _data);
}

Expand Down

0 comments on commit 0f88c36

Please sign in to comment.