init
commit
7fb6cb00fd
@ -0,0 +1,34 @@
|
||||
name: test
|
||||
|
||||
on: workflow_dispatch
|
||||
|
||||
env:
|
||||
FOUNDRY_PROFILE: ci
|
||||
|
||||
jobs:
|
||||
check:
|
||||
strategy:
|
||||
fail-fast: true
|
||||
|
||||
name: Foundry project
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install Foundry
|
||||
uses: foundry-rs/foundry-toolchain@v1
|
||||
with:
|
||||
version: nightly
|
||||
|
||||
- name: Run Forge build
|
||||
run: |
|
||||
forge --version
|
||||
forge build --sizes
|
||||
id: build
|
||||
|
||||
- name: Run Forge tests
|
||||
run: |
|
||||
forge test -vvv
|
||||
id: test
|
@ -0,0 +1,15 @@
|
||||
# Compiler files
|
||||
cache/
|
||||
out/
|
||||
|
||||
# Ignores development broadcast logs
|
||||
!/broadcast
|
||||
/broadcast/*/31337/
|
||||
/broadcast/**/dry-run/
|
||||
broadcast
|
||||
|
||||
# Dotenv file
|
||||
.env
|
||||
.venv
|
||||
|
||||
output.txt
|
@ -0,0 +1,9 @@
|
||||
[submodule "lib/forge-std"]
|
||||
path = lib/forge-std
|
||||
url = https://github.com/foundry-rs/forge-std
|
||||
[submodule "lib/erc721a"]
|
||||
path = lib/erc721a
|
||||
url = https://github.com/chiru-labs/erc721a
|
||||
[submodule "lib/openzeppelin-contracts"]
|
||||
path = lib/openzeppelin-contracts
|
||||
url = https://github.com/openzeppelin/openzeppelin-contracts
|
@ -0,0 +1,7 @@
|
||||
## ponzi contracts
|
||||
|
||||
Pretty simple contract
|
||||
|
||||
5000 token supply
|
||||
.01 eth price
|
||||
10 tokens will be randomly selected to win 1 eth
|
@ -0,0 +1,6 @@
|
||||
[profile.default]
|
||||
src = 'src'
|
||||
out = 'out'
|
||||
libs = ['lib']
|
||||
|
||||
# See more config options https://github.com/foundry-rs/foundry/tree/master/config
|
@ -0,0 +1,23 @@
|
||||
{
|
||||
"env": {
|
||||
"node": true,
|
||||
"commonjs": true,
|
||||
"es2021": true,
|
||||
"mocha": true
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest"
|
||||
},
|
||||
"globals": {
|
||||
"ethers": "readonly"
|
||||
},
|
||||
"rules": {
|
||||
"max-len": [
|
||||
"error",
|
||||
{
|
||||
"code": 120
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
name: Code Coverage
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**.md'
|
||||
|
||||
jobs:
|
||||
run-tests:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Run Coverage and Upload to CodeCov
|
||||
run: |
|
||||
npm run coverage; \
|
||||
curl -Os https://uploader.codecov.io/latest/linux/codecov; \
|
||||
chmod +x codecov; \
|
||||
./codecov;
|
@ -0,0 +1,19 @@
|
||||
name: Publish Package to npmjs
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
# Setup .npmrc file to publish to npm
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: "16.x"
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
- run: npm ci
|
||||
- run: npm publish
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
@ -0,0 +1,34 @@
|
||||
name: ERC721A CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**.md'
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**.md'
|
||||
|
||||
jobs:
|
||||
run-tests:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x,16.x,17.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Run linter
|
||||
run: npm run lint
|
||||
- name: Run tests
|
||||
run: npm test
|
@ -0,0 +1,23 @@
|
||||
name: Upgradeable Trigger
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
tags:
|
||||
- 'v*'
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**.md'
|
||||
|
||||
jobs:
|
||||
trigger:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Repository Dispatch
|
||||
uses: peter-evans/repository-dispatch@v2
|
||||
with:
|
||||
token: ${{ secrets.UPGRADEABLE_REPO_ACCESS_TOKEN }}
|
||||
repository: chiru-labs/ERC721A-Upgradeable
|
||||
event-type: Update
|
||||
client-payload: '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}"}'
|
@ -0,0 +1,9 @@
|
||||
node_modules/
|
||||
.env
|
||||
coverage
|
||||
coverage.json
|
||||
typechain
|
||||
|
||||
#Hardhat files
|
||||
cache
|
||||
artifacts
|
@ -0,0 +1,13 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"printWidth": 120,
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.sol",
|
||||
"options": {
|
||||
"printWidth": 120,
|
||||
"explicitTypes": "always"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Chiru Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
@ -0,0 +1,148 @@
|
||||
[![Docs][docs-shield]][docs-url]
|
||||
[![NPM][npm-shield]][npm-url]
|
||||
[![CI][ci-shield]][ci-url]
|
||||
[![Issues][issues-shield]][issues-url]
|
||||
[![MIT License][license-shield]][license-url]
|
||||
[![Coverage][coverage-shield]][coverage-url]
|
||||
<!-- OTHER BADGES -->
|
||||
<!-- [![Contributors][contributors-shield]][contributors-url] -->
|
||||
<!-- [![Forks][forks-shield]][forks-url] -->
|
||||
<!-- [![Stargazers][stars-shield]][stars-url] -->
|
||||
|
||||
<!-- ANNOUNCEMENT -->
|
||||
|
||||
> **📢 Version 4.x introduces several breaking changes. [Please refer to the documentation for more details.](https://chiru-labs.github.io/ERC721A/#/migration)**
|
||||
|
||||
_We highly recommend reading the migration guide_, **especially** _the part on [`supportsInterface`](https://chiru-labs.github.io/ERC721A/#/migration?id=supportsinterface) if you are using with OpenZeppelin extensions_ (e.g. ERC2981).
|
||||
|
||||
<!-- ABOUT THE PROJECT -->
|
||||
|
||||
## About The Project
|
||||
|
||||
The goal of ERC721A is to provide a fully compliant implementation of IERC721 with significant gas savings for minting multiple NFTs in a single transaction. This project and implementation will be updated regularly and will continue to stay up to date with best practices.
|
||||
|
||||
The [Azuki](https://twitter.com/AzukiOfficial) team created ERC721A for its sale on 1/12/22. There was significant demand for 8700 tokens made available to the public, and all were minted within minutes. The network BASEFEE remained low despite huge demand, resulting in low gas costs for minters, while minimizing network disruption for the wider ecosystem as well.
|
||||
|
||||
![Gas Savings](https://pbs.twimg.com/media/FIdILKpVQAEQ_5U?format=jpg&name=medium)
|
||||
|
||||
For more information on how ERC721A works under the hood, please visit our [blog](https://www.azuki.com/erc721a). To find other projects that are using ERC721A, please visit [erc721a.org](https://www.erc721a.org) and our [curated projects list](https://github.com/chiru-labs/ERC721A/blob/main/projects.md).
|
||||
|
||||
**Chiru Labs is not liable for any outcomes as a result of using ERC721A.** DYOR.
|
||||
|
||||
<!-- Docs -->
|
||||
|
||||
## Docs
|
||||
|
||||
https://chiru-labs.github.io/ERC721A/
|
||||
|
||||
<!-- Upgradeable Version -->
|
||||
|
||||
## Upgradeable Version
|
||||
|
||||
https://github.com/chiru-labs/ERC721A-Upgradeable
|
||||
|
||||
<!-- Installation -->
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
|
||||
npm install --save-dev erc721a
|
||||
|
||||
```
|
||||
|
||||
<!-- USAGE EXAMPLES -->
|
||||
|
||||
## Usage
|
||||
|
||||
Once installed, you can use the contracts in the library by importing them:
|
||||
|
||||
```solidity
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
import "erc721a/contracts/ERC721A.sol";
|
||||
|
||||
contract Azuki is ERC721A {
|
||||
constructor() ERC721A("Azuki", "AZUKI") {}
|
||||
|
||||
function mint(uint256 quantity) external payable {
|
||||
// `_mint`'s second argument now takes in a `quantity`, not a `tokenId`.
|
||||
_mint(msg.sender, quantity);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
<!-- ROADMAP -->
|
||||
|
||||
## Roadmap
|
||||
|
||||
- [ ] Improve general repo and code quality (workflows, comments, etc.)
|
||||
- [ ] Add more documentation on benefits of using ERC721A
|
||||
- [ ] Maintain full test coverage
|
||||
|
||||
See the [open issues](https://github.com/chiru-labs/ERC721A/issues) for a full list of proposed features (and known issues).
|
||||
|
||||
<!-- CONTRIBUTING -->
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
|
||||
|
||||
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement".
|
||||
|
||||
Don't forget to give the project a star! Thanks again!
|
||||
|
||||
1. Fork the Project
|
||||
2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
|
||||
3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
|
||||
4. Push to the Branch (`git push origin feature/AmazingFeature`)
|
||||
5. Open a Pull Request
|
||||
|
||||
<!-- ROADMAP -->
|
||||
|
||||
### Running tests locally
|
||||
|
||||
1. `npm install`
|
||||
2. `npm run test`
|
||||
|
||||
<!-- LICENSE -->
|
||||
|
||||
## License
|
||||
|
||||
Distributed under the MIT License. See `LICENSE.txt` for more information.
|
||||
|
||||
<!-- CONTACT -->
|
||||
|
||||
## Contact
|
||||
|
||||
- 2pm.flow (owner) - [@2pmflow](https://twitter.com/2pmflow)
|
||||
- location tba (owner) - [@locationtba](https://twitter.com/locationtba)
|
||||
- cygaar (maintainer) - [@0xCygaar](https://twitter.com/0xCygaar)
|
||||
- vectorized.eth (maintainer) - [@optimizoor](https://twitter.com/optimizoor)
|
||||
|
||||
Project Link: [https://github.com/chiru-labs/ERC721A](https://github.com/chiru-labs/ERC721A)
|
||||
|
||||
<!-- MARKDOWN LINKS & IMAGES -->
|
||||
|
||||
<!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
|
||||
|
||||
[docs-shield]: https://img.shields.io/badge/docs-%F0%9F%93%84-blue?style=for-the-badge
|
||||
[docs-url]: https://chiru-labs.github.io/ERC721A/
|
||||
[npm-shield]: https://img.shields.io/npm/v/erc721a.svg?style=for-the-badge
|
||||
[npm-url]: https://www.npmjs.com/package/erc721a
|
||||
[ci-shield]: https://img.shields.io/github/actions/workflow/status/chiru-labs/ERC721A/run_tests.yml?label=build&style=for-the-badge&branch=main
|
||||
[ci-url]: https://github.com/chiru-labs/ERC721A/actions/workflows/run_tests.yml
|
||||
[contributors-shield]: https://img.shields.io/github/contributors/chiru-labs/ERC721A.svg?style=for-the-badge
|
||||
[contributors-url]: https://github.com/chiru-labs/ERC721A/graphs/contributors
|
||||
[forks-shield]: https://img.shields.io/github/forks/chiru-labs/ERC721A.svg?style=for-the-badge
|
||||
[forks-url]: https://github.com/chiru-labs/ERC721A/network/members
|
||||
[stars-shield]: https://img.shields.io/github/stars/chiru-labs/ERC721A.svg?style=for-the-badge
|
||||
[stars-url]: https://github.com/chiru-labs/ERC721A/stargazers
|
||||
[issues-shield]: https://img.shields.io/github/issues/chiru-labs/ERC721A.svg?style=for-the-badge
|
||||
[issues-url]: https://github.com/chiru-labs/ERC721A/issues
|
||||
[license-shield]: https://img.shields.io/badge/License-MIT-green.svg?style=for-the-badge
|
||||
[license-url]: https://github.com/chiru-labs/ERC721A/blob/main/LICENSE.txt
|
||||
[coverage-shield]: https://img.shields.io/codecov/c/gh/chiru-labs/ERC721A?style=for-the-badge
|
||||
[coverage-url]: https://codecov.io/gh/chiru-labs/ERC721A
|
||||
[product-screenshot]: images/screenshot.png
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,282 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// ERC721A Contracts v4.2.3
|
||||
// Creator: Chiru Labs
|
||||
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
/**
|
||||
* @dev Interface of ERC721A.
|
||||
*/
|
||||
interface IERC721A {
|
||||
/**
|
||||
* The caller must own the token or be an approved operator.
|
||||
*/
|
||||
error ApprovalCallerNotOwnerNorApproved();
|
||||
|
||||
/**
|
||||
* The token does not exist.
|
||||
*/
|
||||
error ApprovalQueryForNonexistentToken();
|
||||
|
||||
/**
|
||||
* Cannot query the balance for the zero address.
|
||||
*/
|
||||
error BalanceQueryForZeroAddress();
|
||||
|
||||
/**
|
||||
* Cannot mint to the zero address.
|
||||
*/
|
||||
error MintToZeroAddress();
|
||||
|
||||
/**
|
||||
* The quantity of tokens minted must be more than zero.
|
||||
*/
|
||||
error MintZeroQuantity();
|
||||
|
||||
/**
|
||||
* The token does not exist.
|
||||
*/
|
||||
error OwnerQueryForNonexistentToken();
|
||||
|
||||
/**
|
||||
* The caller must own the token or be an approved operator.
|
||||
*/
|
||||
error TransferCallerNotOwnerNorApproved();
|
||||
|
||||
/**
|
||||
* The token must be owned by `from`.
|
||||
*/
|
||||
error TransferFromIncorrectOwner();
|
||||
|
||||
/**
|
||||
* Cannot safely transfer to a contract that does not implement the
|
||||
* ERC721Receiver interface.
|
||||
*/
|
||||
error TransferToNonERC721ReceiverImplementer();
|
||||
|
||||
/**
|
||||
* Cannot transfer to the zero address.
|
||||
*/
|
||||
error TransferToZeroAddress();
|
||||
|
||||
/**
|
||||
* The token does not exist.
|
||||
*/
|
||||
error URIQueryForNonexistentToken();
|
||||
|
||||
/**
|
||||
* The `quantity` minted with ERC2309 exceeds the safety limit.
|
||||
*/
|
||||
error MintERC2309QuantityExceedsLimit();
|
||||
|
||||
/**
|
||||
* The `extraData` cannot be set on an unintialized ownership slot.
|
||||
*/
|
||||
error OwnershipNotInitializedForExtraData();
|
||||
|
||||
// =============================================================
|
||||
// STRUCTS
|
||||
// =============================================================
|
||||
|
||||
struct TokenOwnership {
|
||||
// The address of the owner.
|
||||
address addr;
|
||||
// Stores the start time of ownership with minimal overhead for tokenomics.
|
||||
uint64 startTimestamp;
|
||||
// Whether the token has been burned.
|
||||
bool burned;
|
||||
// Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.
|
||||
uint24 extraData;
|
||||
}
|
||||
|
||||
// =============================================================
|
||||
// TOKEN COUNTERS
|
||||
// =============================================================
|
||||
|
||||
/**
|
||||
* @dev Returns the total number of tokens in existence.
|
||||
* Burned tokens will reduce the count.
|
||||
* To get the total number of tokens minted, please see {_totalMinted}.
|
||||
*/
|
||||
function totalSupply() external view returns (uint256);
|
||||
|
||||
// =============================================================
|
||||
// IERC165
|
||||
// =============================================================
|
||||
|
||||
/**
|
||||
* @dev Returns true if this contract implements the interface defined by
|
||||
* `interfaceId`. See the corresponding
|
||||
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
|
||||
* to learn more about how these ids are created.
|
||||
*
|
||||
* This function call must use less than 30000 gas.
|
||||
*/
|
||||
function supportsInterface(bytes4 interfaceId) external view returns (bool);
|
||||
|
||||
// =============================================================
|
||||
// IERC721
|
||||
// =============================================================
|
||||
|
||||
/**
|
||||
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
|
||||
*/
|
||||
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
|
||||
|
||||
/**
|
||||
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
|
||||
*/
|
||||
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
|
||||
|
||||
/**
|
||||
* @dev Emitted when `owner` enables or disables
|
||||
* (`approved`) `operator` to manage all of its assets.
|
||||
*/
|
||||
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
|
||||
|
||||
/**
|
||||
* @dev Returns the number of tokens in `owner`'s account.
|
||||
*/
|
||||
function balanceOf(address owner) external view returns (uint256 balance);
|
||||
|
||||
/**
|
||||
* @dev Returns the owner of the `tokenId` token.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `tokenId` must exist.
|
||||
*/
|
||||
function ownerOf(uint256 tokenId) external view returns (address owner);
|
||||
|
||||
/**
|
||||
* @dev Safely transfers `tokenId` token from `from` to `to`,
|
||||
* checking first that contract recipients are aware of the ERC721 protocol
|
||||
* to prevent tokens from being forever locked.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `from` cannot be the zero address.
|
||||
* - `to` cannot be the zero address.
|
||||
* - `tokenId` token must exist and be owned by `from`.
|
||||
* - If the caller is not `from`, it must be have been allowed to move
|
||||
* this token by either {approve} or {setApprovalForAll}.
|
||||
* - If `to` refers to a smart contract, it must implement
|
||||
* {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
|
||||
*
|
||||
* Emits a {Transfer} event.
|
||||
*/
|
||||
function safeTransferFrom(
|
||||
address from,
|
||||
address to,
|
||||
uint256 tokenId,
|
||||
bytes calldata data
|
||||
) external payable;
|
||||
|
||||
/**
|
||||
* @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
|
||||
*/
|
||||
function safeTransferFrom(
|
||||
address from,
|
||||
address to,
|
||||
uint256 tokenId
|
||||
) external payable;
|
||||
|
||||
/**
|
||||
* @dev Transfers `tokenId` from `from` to `to`.
|
||||
*
|
||||
* WARNING: Usage of this method is discouraged, use {safeTransferFrom}
|
||||
* whenever possible.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `from` cannot be the zero address.
|
||||
* - `to` cannot be the zero address.
|
||||
* - `tokenId` token must be owned by `from`.
|
||||
* - If the caller is not `from`, it must be approved to move this token
|
||||
* by either {approve} or {setApprovalForAll}.
|
||||
*
|
||||
* Emits a {Transfer} event.
|
||||
*/
|
||||
function transferFrom(
|
||||
address from,
|
||||
address to,
|
||||
uint256 tokenId
|
||||
) external payable;
|
||||
|
||||
/**
|
||||
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
|
||||
* The approval is cleared when the token is transferred.
|
||||
*
|
||||
* Only a single account can be approved at a time, so approving the
|
||||
* zero address clears previous approvals.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - The caller must own the token or be an approved operator.
|
||||
* - `tokenId` must exist.
|
||||
*
|
||||
* Emits an {Approval} event.
|
||||
*/
|
||||
function approve(address to, uint256 tokenId) external payable;
|
||||
|
||||
/**
|
||||
* @dev Approve or remove `operator` as an operator for the caller.
|
||||
* Operators can call {transferFrom} or {safeTransferFrom}
|
||||
* for any token owned by the caller.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - The `operator` cannot be the caller.
|
||||
*
|
||||
* Emits an {ApprovalForAll} event.
|
||||
*/
|
||||
function setApprovalForAll(address operator, bool _approved) external;
|
||||
|
||||
/**
|
||||
* @dev Returns the account approved for `tokenId` token.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `tokenId` must exist.
|
||||
*/
|
||||
function getApproved(uint256 tokenId) external view returns (address operator);
|
||||
|
||||
/**
|
||||
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
|
||||
*
|
||||
* See {setApprovalForAll}.
|
||||
*/
|
||||
function isApprovedForAll(address owner, address operator) external view returns (bool);
|
||||
|
||||
// =============================================================
|
||||
// IERC721Metadata
|
||||
// =============================================================
|
||||
|
||||
/**
|
||||
* @dev Returns the token collection name.
|
||||
*/
|
||||
function name() external view returns (string memory);
|
||||
|
||||
/**
|
||||
* @dev Returns the token collection symbol.
|
||||
*/
|
||||
function symbol() external view returns (string memory);
|
||||
|
||||
/**
|
||||
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
|
||||
*/
|
||||
function tokenURI(uint256 tokenId) external view returns (string memory);
|
||||
|
||||
// =============================================================
|
||||
// IERC2309
|
||||
// =============================================================
|
||||
|
||||
/**
|
||||
* @dev Emitted when tokens in `fromTokenId` to `toTokenId`
|
||||
* (inclusive) is transferred from `from` to `to`, as defined in the
|
||||
* [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.
|
||||
*
|
||||
* See {_mintERC2309} for more details.
|
||||
*/
|
||||
event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// ERC721A Contracts v4.2.3
|
||||
// Creator: Chiru Labs
|
||||
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
import './IERC4907A.sol';
|
||||
import '../ERC721A.sol';
|
||||
|
||||
/**
|
||||
* @title ERC4907A
|
||||
*
|
||||
* @dev [ERC4907](https://eips.ethereum.org/EIPS/eip-4907) compliant
|
||||
* extension of ERC721A, which allows owners and authorized addresses
|
||||
* to add a time-limited role with restricted permissions to ERC721 tokens.
|
||||
*/
|
||||
abstract contract ERC4907A is ERC721A, IERC4907A {
|
||||
// The bit position of `expires` in packed user info.
|
||||
uint256 private constant _BITPOS_EXPIRES = 160;
|
||||
|
||||
// Mapping from token ID to user info.
|
||||
//
|
||||
// Bits Layout:
|
||||
// - [0..159] `user`
|
||||
// - [160..223] `expires`
|
||||
mapping(uint256 => uint256) private _packedUserInfo;
|
||||
|
||||
/**
|
||||
* @dev Sets the `user` and `expires` for `tokenId`.
|
||||
* The zero address indicates there is no user.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - The caller must own `tokenId` or be an approved operator.
|
||||
*/
|
||||
function setUser(
|
||||
uint256 tokenId,
|
||||
address user,
|
||||
uint64 expires
|
||||
) public virtual override {
|
||||
// Require the caller to be either the token owner or an approved operator.
|
||||
address owner = ownerOf(tokenId);
|
||||
if (_msgSenderERC721A() != owner)
|
||||
if (!isApprovedForAll(owner, _msgSenderERC721A()))
|
||||
if (getApproved(tokenId) != _msgSenderERC721A()) _revert(SetUserCallerNotOwnerNorApproved.selector);
|
||||
|
||||
_packedUserInfo[tokenId] = (uint256(expires) << _BITPOS_EXPIRES) | uint256(uint160(user));
|
||||
|
||||
emit UpdateUser(tokenId, user, expires);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the user address for `tokenId`.
|
||||
* The zero address indicates that there is no user or if the user is expired.
|
||||
*/
|
||||
function userOf(uint256 tokenId) public view virtual override returns (address) {
|
||||
uint256 packed = _packedUserInfo[tokenId];
|
||||
assembly {
|
||||
// Branchless `packed *= (block.timestamp <= expires ? 1 : 0)`.
|
||||
// If the `block.timestamp == expires`, the `lt` clause will be true
|
||||
// if there is a non-zero user address in the lower 160 bits of `packed`.
|
||||
packed := mul(
|
||||
packed,
|
||||
// `block.timestamp <= expires ? 1 : 0`.
|
||||
lt(shl(_BITPOS_EXPIRES, timestamp()), packed)
|
||||
)
|
||||
}
|
||||
return address(uint160(packed));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the user's expires of `tokenId`.
|
||||
*/
|
||||
function userExpires(uint256 tokenId) public view virtual override returns (uint256) {
|
||||
return _packedUserInfo[tokenId] >> _BITPOS_EXPIRES;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Override of {IERC165-supportsInterface}.
|
||||
*/
|
||||
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721A, IERC721A) returns (bool) {
|
||||
// The interface ID for ERC4907 is `0xad092b5c`,
|
||||
// as defined in [ERC4907](https://eips.ethereum.org/EIPS/eip-4907).
|
||||
return super.supportsInterface(interfaceId) || interfaceId == 0xad092b5c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the user address for `tokenId`, ignoring the expiry status.
|
||||
*/
|
||||
function _explicitUserOf(uint256 tokenId) internal view virtual returns (address) {
|
||||
return address(uint160(_packedUserInfo[tokenId]));
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// ERC721A Contracts v4.2.3
|
||||
// Creator: Chiru Labs
|
||||
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
import './IERC721ABurnable.sol';
|
||||
import '../ERC721A.sol';
|
||||
|
||||
/**
|
||||
* @title ERC721ABurnable.
|
||||
*
|
||||
* @dev ERC721A token that can be irreversibly burned (destroyed).
|
||||
*/
|
||||
abstract contract ERC721ABurnable is ERC721A, IERC721ABurnable {
|
||||
/**
|
||||
* @dev Burns `tokenId`. See {ERC721A-_burn}.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - The caller must own `tokenId` or be an approved operator.
|
||||
*/
|
||||
function burn(uint256 tokenId) public virtual override {
|
||||
_burn(tokenId, true);
|
||||
}
|
||||
}
|
@ -0,0 +1,236 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// ERC721A Contracts v4.2.3
|
||||
// Creator: Chiru Labs
|
||||
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
import './IERC721AQueryable.sol';
|
||||
import '../ERC721A.sol';
|
||||
|
||||
/**
|
||||
* @title ERC721AQueryable.
|
||||
*
|
||||
* @dev ERC721A subclass with convenience query functions.
|
||||
*/
|
||||
abstract contract ERC721AQueryable is ERC721A, 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)
|
||||
{
|
||||
if (tokenId >= _startTokenId()) {
|
||||
if (tokenId < _nextTokenId()) {
|
||||
ownership = _ownershipAt(tokenId);
|
||||
if (!ownership.burned) {
|
||||
ownership = _ownershipOf(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) {
|
||||
unchecked {
|
||||
if (start >= stop) _revert(InvalidQueryRange.selector);
|
||||
// Set `start = max(start, _startTokenId())`.
|
||||
if (start < _startTokenId()) {
|
||||
start = _startTokenId();
|
||||
}
|
||||
uint256 stopLimit = _nextTokenId();
|
||||
// Set `stop = min(stop, stopLimit)`.
|
||||
if (stop >= stopLimit) {
|
||||
stop = stopLimit;
|
||||
}
|
||||
uint256[] memory tokenIds;
|
||||
uint256 tokenIdsMaxLength = balanceOf(owner);
|
||||
bool startLtStop = start < stop;
|
||||
assembly {
|
||||
// Set `tokenIdsMaxLength` to zero if `start` is less than `stop`.
|
||||
tokenIdsMaxLength := mul(tokenIdsMaxLength, startLtStop)
|
||||
}
|
||||
if (tokenIdsMaxLength != 0) {
|
||||
// Set `tokenIdsMaxLength = min(balanceOf(owner), stop - start)`,
|
||||
// to cater for cases where `balanceOf(owner)` is too big.
|
||||
if (stop - start <= tokenIdsMaxLength) {
|
||||
tokenIdsMaxLength = stop - start;
|
||||
}
|
||||
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)`.
|
||||
mstore(0x40, add(tokenIds, shl(5, add(tokenIdsMaxLength, 1))))
|
||||
}
|
||||
// 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 {
|
||||
ownership = _ownershipAt(start);
|
||||
assembly {
|
||||
// if `ownership.burned == false`.
|
||||
if iszero(mload(add(ownership, 0x40))) {
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
start := add(start, 1)
|
||||
}
|
||||
} while (!(start == stop || tokenIdsIdx == tokenIdsMaxLength));
|
||||
// Store the length of the array.
|
||||
assembly {
|
||||
mstore(tokenIds, tokenIdsIdx)
|
||||
}
|
||||
}
|
||||
return tokenIds;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
uint256 tokenIdsLength = balanceOf(owner);
|
||||
uint256[] memory tokenIds;
|
||||
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)`.
|
||||
mstore(0x40, add(tokenIds, shl(5, add(tokenIdsLength, 1))))
|
||||
// Store the length of `tokenIds`.
|
||||
mstore(tokenIds, tokenIdsLength)
|
||||
}
|
||||
address currOwnershipAddr;
|
||||
uint256 tokenIdsIdx;
|
||||
for (uint256 i = _startTokenId(); tokenIdsIdx != tokenIdsLength; ) {
|
||||
TokenOwnership memory ownership = _ownershipAt(i);
|
||||
assembly {
|
||||
// if `ownership.burned == false`.
|
||||
if iszero(mload(add(ownership, 0x40))) {
|
||||
// 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)), i)
|
||||
}
|
||||
}
|
||||
i := add(i, 1)
|
||||
}
|
||||
}
|
||||
return tokenIds;
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// ERC721A Contracts v4.2.3
|
||||
// Creator: Chiru Labs
|
||||
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
import '../IERC721A.sol';
|
||||
|
||||
/**
|
||||
* @dev Interface of ERC4907A.
|
||||
*/
|
||||
interface IERC4907A is IERC721A {
|
||||
/**
|
||||
* The caller must own the token or be an approved operator.
|
||||
*/
|
||||
error SetUserCallerNotOwnerNorApproved();
|
||||
|
||||
/**
|
||||
* @dev Emitted when the `user` of an NFT or the `expires` of the `user` is changed.
|
||||
* The zero address for user indicates that there is no user address.
|
||||
*/
|
||||
event UpdateUser(uint256 indexed tokenId, address indexed user, uint64 expires);
|
||||
|
||||
/**
|
||||
* @dev Sets the `user` and `expires` for `tokenId`.
|
||||
* The zero address indicates there is no user.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - The caller must own `tokenId` or be an approved operator.
|
||||
*/
|
||||
function setUser(
|
||||
uint256 tokenId,
|
||||
address user,
|
||||
uint64 expires
|
||||
) external;
|
||||
|
||||
/**
|
||||
* @dev Returns the user address for `tokenId`.
|
||||
* The zero address indicates that there is no user or if the user is expired.
|
||||
*/
|
||||
function userOf(uint256 tokenId) external view returns (address);
|
||||
|
||||
/**
|
||||
* @dev Returns the user's expires of `tokenId`.
|
||||
*/
|
||||
function userExpires(uint256 tokenId) external view returns (uint256);
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// ERC721A Contracts v4.2.3
|
||||
// Creator: Chiru Labs
|
||||
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
import '../IERC721A.sol';
|
||||
|
||||
/**
|
||||
* @dev Interface of ERC721ABurnable.
|
||||
*/
|
||||
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;
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// ERC721A Contracts v4.2.3
|
||||
// Creator: Chiru Labs
|
||||
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
import '../IERC721A.sol';
|
||||
|
||||
/**
|
||||
* @dev Interface of ERC721AQueryable.
|
||||
*/
|
||||
interface IERC721AQueryable is IERC721A {
|
||||
/**
|
||||
* Invalid query range (`start` >= `stop`).
|
||||
*/
|
||||
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`
|
||||
* - `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) 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 collections should be fine).
|
||||
*/
|
||||
function tokensOfOwner(address owner) external view returns (uint256[] memory);
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// ERC721A Contracts v4.2.3
|
||||
// Creator: Chiru Labs
|
||||
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
import '../extensions/IERC4907A.sol';
|
@ -0,0 +1,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// ERC721A Contracts v4.2.3
|
||||
// Creator: Chiru Labs
|
||||
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
import '../IERC721A.sol';
|
@ -0,0 +1,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// ERC721A Contracts v4.2.3
|
||||
// Creator: Chiru Labs
|
||||
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
import '../extensions/IERC721ABurnable.sol';
|
@ -0,0 +1,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// ERC721A Contracts v4.2.3
|
||||
// Creator: Chiru Labs
|
||||
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
import '../extensions/IERC721AQueryable.sol';
|
@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// ERC721A Contracts v4.2.3
|
||||
// Creators: Chiru Labs
|
||||
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
import '../extensions/ERC4907A.sol';
|
||||
|
||||
contract ERC4907AMock is ERC721A, ERC4907A {
|
||||
constructor(string memory name_, string memory symbol_) ERC721A(name_, symbol_) {}
|
||||
|
||||
function mint(address to, uint256 quantity) public {
|
||||
_mint(to, quantity);
|
||||
}
|
||||
|
||||
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721A, ERC4907A) returns (bool) {
|
||||
return super.supportsInterface(interfaceId);
|
||||
}
|
||||
|
||||
function explicitUserOf(uint256 tokenId) public view returns (address) {
|
||||
return _explicitUserOf(tokenId);
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// ERC721A Contracts v4.2.3
|
||||
// Creators: Chiru Labs
|
||||
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
import '../extensions/ERC721ABurnable.sol';
|
||||
|
||||
contract ERC721ABurnableMock is ERC721A, ERC721ABurnable {
|
||||
constructor(string memory name_, string memory symbol_) ERC721A(name_, symbol_) {}
|
||||
|
||||
function exists(uint256 tokenId) public view returns (bool) {
|
||||
return _exists(tokenId);
|
||||
}
|
||||
|
||||
function safeMint(address to, uint256 quantity) public {
|
||||
_safeMint(to, quantity);
|
||||
}
|
||||
|
||||
function getOwnershipAt(uint256 index) public view returns (TokenOwnership memory) {
|
||||
return _ownershipAt(index);
|
||||
}
|
||||
|
||||
function totalMinted() public view returns (uint256) {
|
||||
return _totalMinted();
|
||||
}
|
||||
|
||||
function totalBurned() public view returns (uint256) {
|
||||
return _totalBurned();
|
||||
}
|
||||
|
||||
function numberBurned(address owner) public view returns (uint256) {
|
||||
return _numberBurned(owner);
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// ERC721A Contracts v4.2.3
|
||||
// Creators: Chiru Labs
|
||||
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
import './ERC721ABurnableMock.sol';
|
||||
import './StartTokenIdHelper.sol';
|
||||
|
||||
contract ERC721ABurnableStartTokenIdMock is StartTokenIdHelper, ERC721ABurnableMock {
|
||||
constructor(
|
||||
string memory name_,
|
||||
string memory symbol_,
|
||||
uint256 startTokenId_
|
||||
) StartTokenIdHelper(startTokenId_) ERC721ABurnableMock(name_, symbol_) {}
|
||||
|
||||
function _startTokenId() internal view override returns (uint256) {
|
||||
return startTokenId;
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// ERC721A Contracts v4.2.3
|
||||
// Creators: Chiru Labs
|
||||
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
import '../ERC721A.sol';
|
||||
|
||||
contract ERC721AGasReporterMock is ERC721A {
|
||||
constructor(string memory name_, string memory symbol_) ERC721A(name_, symbol_) {}
|
||||
|
||||
function safeMintOne(address to) public {
|
||||
_safeMint(to, 1);
|
||||
}
|
||||
|
||||
function mintOne(address to) public {
|
||||
_mint(to, 1);
|
||||
}
|
||||
|
||||
function safeMintTen(address to) public {
|
||||
_safeMint(to, 10);
|
||||
}
|
||||
|
||||
function mintTen(address to) public {
|
||||
_mint(to, 10);
|
||||
}
|
||||
|
||||
function transferTenAsc(address to) public {
|
||||
unchecked {
|
||||
transferFrom(msg.sender, to, 0);
|
||||
transferFrom(msg.sender, to, 1);
|
||||
transferFrom(msg.sender, to, 2);
|
||||
transferFrom(msg.sender, to, 3);
|
||||
transferFrom(msg.sender, to, 4);
|
||||
transferFrom(msg.sender, to, 5);
|
||||
transferFrom(msg.sender, to, 6);
|
||||
transferFrom(msg.sender, to, 7);
|
||||
transferFrom(msg.sender, to, 8);
|
||||
transferFrom(msg.sender, to, 9);
|
||||
}
|
||||
}
|
||||
|
||||
function transferTenDesc(address to) public {
|
||||
unchecked {
|
||||
transferFrom(msg.sender, to, 9);
|
||||
transferFrom(msg.sender, to, 8);
|
||||
transferFrom(msg.sender, to, 7);
|
||||
transferFrom(msg.sender, to, 6);
|
||||
transferFrom(msg.sender, to, 5);
|
||||
transferFrom(msg.sender, to, 4);
|
||||
transferFrom(msg.sender, to, 3);
|
||||
transferFrom(msg.sender, to, 2);
|
||||
transferFrom(msg.sender, to, 1);
|
||||
transferFrom(msg.sender, to, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function transferTenAvg(address to) public {
|
||||
unchecked {
|
||||
transferFrom(msg.sender, to, 4);
|
||||
transferFrom(msg.sender, to, 5);
|
||||
transferFrom(msg.sender, to, 3);
|
||||
transferFrom(msg.sender, to, 6);
|
||||
transferFrom(msg.sender, to, 2);
|
||||
transferFrom(msg.sender, to, 7);
|
||||
transferFrom(msg.sender, to, 1);
|
||||
transferFrom(msg.sender, to, 8);
|
||||
transferFrom(msg.sender, to, 0);
|
||||
transferFrom(msg.sender, to, 9);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// ERC721A Contracts v4.2.3
|
||||
// Creators: Chiru Labs
|
||||
|
||||
pragma solidity ^0.8.4;
|
||||
|
||||
import '../ERC721A.sol';
|
||||
|
||||
contract ERC721AMock is ERC721A {
|
||||
constructor(string memory name_, string memory symbol_) ERC721A(name_, symbol_) {}
|
||||
|
||||
function numberMinted(address owner) public view returns (uint256) {
|
||||
return _numberMinted(owner);
|
||||
}
|
||||
|
||||
function totalMinted() public view returns (uint256) {
|
||||
return _totalMinted();
|
||||
}
|
||||
|
||||
function totalBurned() public view returns (uint256) {
|
||||
return _totalBurned();
|
||||
}
|
||||
|
||||
function nextTokenId() public view returns (uint256) {
|
||||
return _nextTokenId();
|
||||
}
|
||||
|
||||
function getAux(address owner) public view returns (uint64) {
|
||||
return _getAux(owner);
|
||||
}
|
||||
|
||||
function setAux(address owner, uint64 aux) public {
|
||||
_setAux(owner, aux);
|
||||
}
|
||||
|
||||
function directApprove(address to, uint256 tokenId) public {
|
||||
_approve(to, tokenId);
|
||||
}
|
||||
|
||||
function baseURI() public view returns (string memory) {
|
||||
return _baseURI();
|
||||
}
|
||||
|
||||
function exists(uint256 tokenId) public view returns (bool) {
|
||||
return _exists(tokenId);
|
||||
}
|
||||
|
||||
function safeMint(address to, uint256 quantity) public {
|
||||
_safeMint(to, quantity);
|
||||
}
|
||||
|
||||
function safeMint(
|
||||
address to,
|
||||
uint256 quantity,
|
||||
bytes memory _data
|
||||
) public {
|
||||
_safeMint(to, quantity, _data);
|
||||
}
|
||||
|
||||
function mint(address to, uint256 quantity) public {
|
||||