A Foundry-based template for all things NFT Smart Contracts.
Click the Use this template
button at the top of the page to
create a new repository with this repo as the initial state.
Or, if you prefer to install the template manually:
mkdir my-project
cd my-project
forge init --template ninfa-labs/ninfa-contracts
pnpm install # install Solhint, Prettier, and other Node.js deps
Alternatively, install the contracts package into your existing Solidity project:
forge install https://github.com/thirdweb-dev/contracts
If this is your first time with Foundry, check out the installation instructions.
Run the following command to install all dependencies found in package.json
:
pnpm install
Foundry typically uses git submodules to manage dependencies, but this template uses Node.js packages because submodules don't scale.
This is how to install dependencies:
- Install the dependency using your preferred package manager, e.g.
pnpm install dependency-name
- Use this syntax to install from GitHub:
pnpm install github:username/repo-name
- Use this syntax to install from GitHub:
- Add a remapping for the dependency in remappings.txt, e.g.
dependency-name=node_modules/dependency-name
The following dependencies are included in package.json
:
- Forge Std: collection of helpful contracts and cheatcodes for testing
- Solhint: linter for Solidity code
- Prettier Plugin Solidity: code formatter for non-Solidity files
The Solidity smart contracts are located in the src
directory.
access
├── AccessControl.sol - "Role-based access control mechanism"
└── Owned.sol - "Simple single owner authorization"
factory
├── CuratedFactory.sol - "Factory for creating curated NFTs with specific rules"
├── OpenFactory.sol - "Factory for creating open NFTs with flexible rules"
└── PayableFactory.sol - "Factory for creating NFTs with integrated payment options"
token
├── common
│ ├── DecodeTokenURI.sol - "Decodes token URI for metadata retrieval"
│ ├── EIP712.sol - "Implements EIP712 standard for structured data hashing and signing"
│ ├── ERC2981.sol - "Implements ERC2981 standard for NFT royalties"
│ └── Metadata.sol - "Handles metadata related operations for tokens"
├── ERC1155
│ ├── ERC1155.sol - "Implements ERC1155 standard for multi-token contracts"
│ ├── extensions
│ │ ├── ERC1155Burnable.sol - "Extension that allows ERC1155 tokens to be burned"
│ │ ├── ERC1155Metadata_URI.sol - "Handles ERC1155 token metadata URI"
│ │ ├── ERC1155Royalty.sol - "Handles ERC1155 token royalties"
│ │ └── ERC1155Supply.sol - "Tracks and controls ERC1155 token supply"
│ ├── IERC1155Receiver.sol - "Interface for contracts that support safeTransfers from ERC1155 asset contracts"
│ └── presets
│ ├── ERC1155Base.sol - "Base implementation of ERC1155 standard"
│ ├── ERC1155OpenEdition.sol - "Open edition implementation of ERC1155 standard"
│ └── ERC1155LazyMint.sol - "Lazy minting implementation of ERC1155 standard"
└── ERC721
├── ERC721.sol - "Implements ERC721 standard for NFT contracts"
├── extensions
│ ├── ERC721Burnable.sol - "Extension that allows ERC721 tokens to be burned"
│ ├── ERC721Enumerable.sol - "Adds enumeration functionality to ERC721 tokens"
│ ├── ERC721Metadata_URI_autoIncrementID.sol - "Handles ERC721 token metadata URI with auto-incremented ID"
│ ├── ERC721Metadata_URI.sol - "Handles ERC721 token metadata URI"
│ └── ERC721Royalty.sol - "Handles ERC721 token royalties"
├── IERC721Receiver.sol - "Interface for contracts that support safeTransfers from ERC721 asset contracts"
└── presets
├── ERC721Base.sol - "Base implementation of ERC721 standard"
├── ERC721Generative.sol - "Generative art implementation of ERC721 standard"
└── ERC721LazyMint.sol - "Lazy minting implementation of ERC721 standard"
utils
├── Address.sol - "Collection of functions related to address type"
├── Counters.sol - "Provides counting functions"
├── cryptography
│ ├── ECDSA.sol - "Provides functions related to ECDSA signatures"
│ ├── MerkleProofLib.sol - "Provides functions to verify Merkle proofs"
│ ├── SignatureChecker.sol - "Provides functions to check signatures"
│ └── SSTORE2.sol - "Provides functions related to Ethereum's SSTORE operation"
├── math
│ └── Math.sol - "Provides math functions"
├── proxy
│ └── Clones.sol - "Provides functions to create clone contracts"
├── RoyaltyEngineV1.sol - "Handles royalty payments"
├── interfaces
│ ├── IArtBlocksOverride.sol - "Interface for ArtBlocks override"
│ ├── IEIP2981.sol - "Interface for EIP2981 royalties standard"
│ ├── IFoundation.sol - "Interface for Foundation platform"
│ ├── IKODAV2Override.sol - "Interface for KODA V2 override"
│ ├── IManifold.sol - "Interface for Manifold platform"
│ ├── IRarible.sol - "Interface for Rarible platform"
│ ├── ISuperRare.sol - "Interface for SuperRare platform"
│ └── IZoraOverride.sol - "Interface for Zora override"
└── Strings.sol - "Provides string functions"
EnglishAuction.sol - "Implements English auction mechanism"
OnChainMarketplace.sol - "Implements on-chain marketplace for NFTs"
Pre-built contracts (presets) are written by the Ninfa Labs team, and cover the most common use cases for smart contracts.
Extensions provide a way for you to pick and choose which individual pieces you want to put into your contract; with
full customization of how those features work. These are available at src/token/ERC721/extensions/
and
src/token/ERC1155/extensions/
depending on the token standard.
Extensions are simply contracts that are meant to be inherited by implementations and their functions either called or
overridden by the child implementation. Token preset contracts are an example of how exentions should be implemented,
see src/token/ERC721/presets
and src/token/ERC1155/presets
.
src — "Solidity smart contracts"
test — "Foundry Forge tests"
script — "Deployment scripts"
This template comes with a set of sensible default configurations for you to use. These defaults can be found in the following files:
├── .editorconfig
├── .gitignore
├── .prettierignore
├── .prettierrc.yml
├── .solhint.json
├── foundry.toml
└── remappings.txt
All NFT preset contracts in ./src/token
are compatible with both upgradeable and regular deployment patterns. All
initial state changes are written inside the initialize()
function, rather than the constructor, this is so that
contract specific parameters can be set when deploying new sovereign contracts (clones) from a factory contract.
To run tests:
forge test
This template comes with GitHub Actions pre-configured. Your contracts will be linted and tested on every push and pull
request made to the main
branch.
You can edit the CI script in .github/workflows/ci.yml.
Found a security issue with our smart contracts? Send bug reports to [email protected] and we'll continue communicating with you from there.
If you have any feedback, please reach out to us at [email protected].