A Step-by-Step Primer on ERC-721 and ERC-1155 Tokens
An Introduction to Token Standards in Ethereum
Token standards are the blueprints that enable developers to create, trade, and manage digital assets on the Ethereum blockchain. Without a common language, each project would need to reinvent the wheel, leading to fragmentation and a higher barrier to adoption. Two of the most influential standards for non‑fungible and semi‑fungible tokens are ERC‑721 and ERC‑1155, which you can read about in detail in our guide on Understanding ERC‑721 and ERC‑1155: A Beginner’s Guide.
They empower creators to build everything from collectible art to game items, and they provide the foundations for more complex financial applications such as lending, staking, and synthetic asset creation.
Below is a step‑by‑step primer that explains the fundamentals of ERC‑721 and ERC‑1155, compares them, and walks you through the process of building and deploying each type of token. Whether you are a Solidity developer, a product manager, or an enthusiast looking to understand how digital scarcity works, this guide will give you a clear roadmap.
ERC‑721: The Classic Non‑Fungible Token
What Is ERC‑721?
ERC‑721 is a token standard that defines a unique, indivisible asset. Each token has its own identifier and can carry metadata that describes its properties, a concept explored in depth in our post on ERC‑721 and ERC‑1155 in Practice: Building Decentralized Assets. Because each token is distinct, ERC‑721 is ideal for collectibles, digital art, certificates, and any asset that needs to be tracked individually.
Core Features
- Uniqueness: Every token ID is distinct.
- Ownership: The standard defines
ownerOf(tokenId)to determine who owns a particular token. - Transferability: Safe transfer functions (
safeTransferFrom) ensure that tokens are only moved to contracts that can handle them. - Metadata: The optional
tokenURI(tokenId)function links to off‑chain data (images, descriptions, etc.).
Essential Functions
| Function | Purpose |
|---|---|
balanceOf(address owner) |
Returns the number of tokens owned by an address. |
ownerOf(uint256 tokenId) |
Returns the address that owns a specific token. |
safeTransferFrom(address from, address to, uint256 tokenId) |
Transfers ownership while ensuring the receiver can accept ERC‑721 tokens. |
transferFrom(address from, address to, uint256 tokenId) |
Basic transfer (less safety checks). |
approve(address to, uint256 tokenId) |
Grants approval to another address to transfer a token. |
setApprovalForAll(address operator, bool approved) |
Grants or revokes operator rights for all tokens of an owner. |
getApproved(uint256 tokenId) |
Returns the approved address for a token. |
isApprovedForAll(address owner, address operator) |
Checks operator approval status. |
tokenURI(uint256 tokenId) |
Retrieves the URI pointing to token metadata. |
Typical Use Cases
- Digital Art: Each artwork is a distinct token that can be sold or displayed.
- Collectibles: Trading cards, virtual pets, or any item with rarity.
- Certificates: Academic diplomas, property deeds, or other official documents that require verifiable ownership.
ERC‑1155: The Multi‑Token Standard
What Is ERC‑1155?
ERC‑1155 expands the token concept by allowing a single contract to manage multiple token types, including both fungible and non‑fungible assets. It supports batch operations, reducing gas costs when transferring many tokens at once. Batch operations, described in detail in our Deep Dive into Decentralized Asset Standards with ERC‑721 and ERC‑1155, are one of its key advantages.
Core Features
- Batch Operations:
safeTransferFromandsafeBatchTransferFromhandle multiple token IDs in one transaction. - Hybrid Asset Types: A contract can hold fungible tokens (like ERC‑20) and unique tokens (like ERC‑721) simultaneously.
- Efficient Metadata: Uses a base URI and appends token IDs, minimizing storage overhead.
Essential Functions
| Function | Purpose |
|---|---|
balanceOf(address account, uint256 id) |
Returns the balance of a specific token type for an account. |
balanceOfBatch(address[] accounts, uint256[] ids) |
Returns balances for multiple accounts/token pairs. |
setApprovalForAll(address operator, bool approved) |
Same as ERC‑721. |
isApprovedForAll(address account, address operator) |
Same as ERC‑721. |
safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes data) |
Transfers a specific amount of a token type. |
safeBatchTransferFrom(address from, address to, uint256[] ids, uint256[] amounts, bytes data) |
Batch transfer. |
uri(uint256 id) |
Returns the metadata URI for a token type. |
Typical Use Cases
- Video Games: In‑game items like weapons (unique) and currency (fungible) managed by a single contract.
- DeFi Platforms: Bundling of various asset types for lending, staking, or synthetic derivatives.
- Batch Minting: Efficient creation of large collections of NFTs (e.g., 10,000 digital trading cards).
Comparing ERC‑721 and ERC‑1155
| Aspect | ERC‑721 | ERC‑1155 |
|---|---|---|
| Token Granularity | One contract per token type | One contract can contain many token types |
| Batch Operations | No native batch support | Built‑in batch transfer and minting |
| Gas Efficiency | Higher gas for many tokens | Lower gas for bulk actions |
| Fungibility | All tokens are unique | Supports both fungible and non‑fungible |
| Complexity | Simpler interface | Slightly more complex but flexible |
| Best For | Pure NFT collections | Mixed asset collections and games |
Choosing between the two often depends on the scope of your project. If you need a collection of distinct, high‑value items, ERC‑721 might be simpler. If you anticipate handling thousands of items, or mixing fungible assets with collectibles, ERC‑1155 can reduce transaction costs and code duplication.
Building an ERC‑721 Token from Scratch
Below is a concrete, step‑by‑step walkthrough that takes you from a blank directory to a deployed ERC‑721 token on the Goerli test network.
1. Set Up Your Development Environment
- Install Node.js (v20 or newer).
- Create a new project folder and initialize it:
mkdir my-erc721 cd my-erc721 npm init -y - Install the Solidity compiler, Truffle, and OpenZeppelin contracts:
npm install --save-dev truffle @openzeppelin/contracts npm install @openzeppelin/contracts
2. Configure Truffle
Create truffle-config.js:
module.exports = {
networks: {
development: {
host: "127.0.0.1",
port: 8545,
network_id: "*"
},
goerli: {
provider: () => new HDWalletProvider({
mnemonic: "YOUR_MNEMONIC_HERE",
providerOrUrl: "https://goerli.infura.io/v3/YOUR_INFURA_KEY"
}),
network_id: 5,
gas: 6000000,
confirmations: 2,
timeoutBlocks: 200,
skipDryRun: true
}
},
compilers: {
solc: {
version: "0.8.20"
}
}
};
Replace the mnemonic and Infura key with your own. Use a testnet wallet that holds some Goerli ETH.
3. Write the ERC‑721 Contract
Create contracts/BasicCollectible.sol:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract BasicCollectible is ERC721, Ownable {
uint256 public nextTokenId;
string private baseTokenURI;
constructor(string memory name_, string memory symbol_, string memory baseURI_) ERC721(name_, symbol_) {
baseTokenURI = baseURI_;
}
function mint(address to) external onlyOwner returns (uint256) {
uint256 tokenId = nextTokenId;
_safeMint(to, tokenId);
nextTokenId++;
return tokenId;
}
function _baseURI() internal view override returns (string memory) {
return baseTokenURI;
}
}
Key points
- The contract inherits from
ERC721andOwnable. mintcan only be called by the contract owner._baseURIis overridden to point to your metadata server.
4. Deploy the Contract
Create a migration script migrations/2_deploy_basic_collectible.js:
const BasicCollectible = artifacts.require("BasicCollectible");
module.exports = function (deployer) {
const name = "MyCollectible";
const symbol = "MC";
const baseURI = "https://api.mycollectible.com/metadata/";
deployer.deploy(BasicCollectible, name, symbol, baseURI);
};
Run:
truffle migrate --network goerli
After deployment, note the contract address for later interactions.
5. Verify the Deployment
Using Truffle or Etherscan, confirm that the contract exists and that the ABI matches.
6. Test Minting
You can test minting through Truffle console:
truffle console --network goerli
> let instance = await BasicCollectible.deployed()
> await instance.mint("0xYourWalletAddress")
> await instance.ownerOf(0)
If you see your address returned, the mint was successful.
Building an ERC‑1155 Token with Batch Capabilities
The ERC‑1155 workflow is similar, but we’ll highlight batch minting and URI handling.
1. Create the Contract
contracts/MultiAsset.sol:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MultiAsset is ERC1155, Ownable {
uint256 public currentTokenId;
constructor(string memory baseURI_) ERC1155(baseURI_) {
currentTokenId = 0;
}
function mintSingle(address to, uint256 amount, bytes memory data) external onlyOwner returns (uint256) {
uint256 tokenId = currentTokenId;
_mint(to, tokenId, amount, data);
currentTokenId++;
return tokenId;
}
function mintBatch(address to, uint256[] memory amounts, bytes memory data) external onlyOwner {
uint256[] memory ids = new uint256[](amounts.length);
for (uint256 i = 0; i < amounts.length; i++) {
ids[i] = currentTokenId + i;
}
_mintBatch(to, ids, amounts, data);
currentTokenId += amounts.length;
}
}
Highlights
mintSingleallows creating one new token type.mintBatchcreates multiple token types in one transaction.- The base URI is shared, and the token ID is appended automatically.
2. Deploy
Create a migration script migrations/2_deploy_multi_asset.js:
const MultiAsset = artifacts.require("MultiAsset");
module.exports = function (deployer) {
const baseURI = "https://api.myasset.com/metadata/{id}.json";
deployer.deploy(MultiAsset, baseURI);
};
Deploy with:
truffle migrate --network goerli
3. Verify Batch Minting
truffle console --network goerli
> let instance = await MultiAsset.deployed()
> await instance.mintBatch("0xYourWalletAddress", [100, 200, 300], "0x")
> await instance.balanceOf("0xYourWalletAddress", 0) // should be 100
> await instance.balanceOf("0xYourWalletAddress", 1) // should be 200
Best Practices
- Security audits: Use OpenZeppelin contracts—an approach outlined in our guide on The Essentials of DeFi Tokens: From ERC‑721 to ERC‑1155.
- Testing: Deploy on a public testnet and thoroughly test edge cases.
- Optimizing Gas: Batch operations (see our Deep Dive into Decentralized Asset Standards with ERC‑721 and ERC‑1155) can save you significant fees.
- Documentation: Keep your smart‑contract documentation up‑to‑date for future developers.
Integrating ERC‑721 and ERC‑1155 Tokens into DeFi
ERC‑721 and ERC‑1155 are foundational building blocks for the next wave of digital ownership and finance. By mastering their core features and learning how to deploy them securely, developers can create products that range from collectible marketplaces to complex DeFi protocols.
Wrapping Tokens for Liquidity
Wrapping a non‑fungible asset into a fungible representation can be explored further in our article on From Tokens to Tradables Navigating ERC‑721 and ERC‑1155 in DeFi.
Staking and Yield Generation
- NFT staking: Lock ERC‑721 tokens to earn rewards or governance tokens.
- Batch staking: Use ERC‑1155’s batch capabilities to stake multiple items in one transaction, saving gas.
Synthetic Assets
- Tokenized derivatives: Create ERC‑1155 tokens that represent fractional ownership of real‑world assets.
- Pegged pools: Combine fungible tokens with NFTs to maintain stable value or to create unique financial instruments.
Marketplace Integration
- Cross‑platform sales: Standardized ERC‑721/1155 APIs allow marketplaces like OpenSea to list and trade assets automatically.
- Royalty standards: ERC‑2981 can be paired with ERC‑721 to enforce creator royalties on secondary sales.
Final Thoughts
ERC‑721 and ERC‑1155 are foundational building blocks for the next wave of digital ownership and finance. By mastering their core features and learning how to deploy them securely, developers can create products that range from collectible marketplaces to complex DeFi protocols. The step‑by‑step guides above show that the barrier to entry is lower than ever. All you need is a text editor, some ETH on a testnet, and a willingness to experiment. As the ecosystem grows, expect new standards and hybrid solutions to emerge, but the principles outlined here will remain relevant.
Whether you’re building a one‑of‑a‑kind masterpiece or a high‑frequency trading token, ERC‑721 and ERC‑1155 give you the tools to turn ideas into immutable, interoperable digital assets. Happy coding!
Lucas Tanaka
Lucas is a data-driven DeFi analyst focused on algorithmic trading and smart contract automation. His background in quantitative finance helps him bridge complex crypto mechanics with practical insights for builders, investors, and enthusiasts alike.
Random Posts
Designing Governance Tokens for Sustainable DeFi Projects
Governance tokens are DeFi’s heartbeat, turning passive liquidity providers into active stewards. Proper design of supply, distribution, delegation and vesting prevents power concentration, fuels voting, and sustains long, term growth.
5 months ago
Formal Verification Strategies to Mitigate DeFi Risk
Discover how formal verification turns DeFi smart contracts into reliable fail proof tools, protecting your capital without demanding deep tech expertise.
7 months ago
Reentrancy Attack Prevention Practical Techniques for Smart Contract Security
Discover proven patterns to stop reentrancy attacks in smart contracts. Learn simple coding tricks, safe libraries, and a complete toolkit to safeguard funds and logic before deployment.
2 weeks ago
Foundations of DeFi Yield Mechanics and Core Primitives Explained
Discover how liquidity, staking, and lending turn token swaps into steady rewards. This guide breaks down APY math, reward curves, and how to spot sustainable DeFi yields.
3 months ago
Mastering DeFi Revenue Models with Tokenomics and Metrics
Learn how tokenomics fuels DeFi revenue, build sustainable models, measure success, and iterate to boost protocol value.
2 months ago
Latest Posts
Foundations Of DeFi Core Primitives And Governance Models
Smart contracts are DeFi’s nervous system: deterministic, immutable, transparent. Governance models let protocols evolve autonomously without central authority.
1 day ago
Deep Dive Into L2 Scaling For DeFi And The Cost Of ZK Rollup Proof Generation
Learn how Layer-2, especially ZK rollups, boosts DeFi with faster, cheaper transactions and uncovering the real cost of generating zk proofs.
1 day ago
Modeling Interest Rates in Decentralized Finance
Discover how DeFi protocols set dynamic interest rates using supply-demand curves, optimize yields, and shield against liquidations, essential insights for developers and liquidity providers.
1 day ago