Back to Learn
applications
ERC-721 NFT
Create a non-fungible token (NFT) contract following the ERC-721 standard.
ERC-721 NFT
ERC-721 is the standard for non-fungible tokens. Each token has a unique ID and owner.
Core Functions
- balanceOf(owner) - Number of tokens owned
- ownerOf(tokenId) - Owner of a specific token
- transferFrom(from, to, tokenId) - Transfer token
- approve(to, tokenId) - Approve transfer
- setApprovalForAll(operator, approved) - Approve all tokens
Storage
``rust
#[storage]
pub struct Erc721 {
owners: StorageMap
balances: StorageMap
, token_approvals: StorageMap
operator_approvals: StorageMap
>,}
``Code Example
#![cfg_attr(not(feature = "export-abi"), no_main)]
extern crate alloc;
use stylus_sdk::prelude::*;
use stylus_sdk::{evm, msg};
use stylus_sdk::storage::{StorageMap, StorageU256, StorageBool};
use alloy_primitives::{Address, U256};
use alloy_sol_types::sol;
sol! {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
}
#[storage]
#[entrypoint]
pub struct Erc721 {
owners: StorageMap<U256, Address>,
balances: StorageMap<Address, U256>,
token_approvals: StorageMap<U256, Address>,
next_token_id: StorageU256,
}
#[public]
impl Erc721 {
pub fn balance_of(&self, owner: Address) -> U256 {
self.balances.get(owner)
}
pub fn owner_of(&self, token_id: U256) -> Address {
self.owners.get(token_id)
}
pub fn mint(&mut self, to: Address) -> U256 {
let token_id = self.next_token_id.get();
self.next_token_id.set(token_id + U256::from(1));
self.owners.insert(token_id, to);
self.balances.insert(to, self.balances.get(to) + U256::from(1));
evm::log(Transfer { from: Address::ZERO, to, tokenId: token_id });
token_id
}
pub fn transfer_from(&mut self, from: Address, to: Address, token_id: U256) {
let owner = self.owners.get(token_id);
assert_eq!(owner, from, "Not owner");
self.balances.insert(from, self.balances.get(from) - U256::from(1));
self.balances.insert(to, self.balances.get(to) + U256::from(1));
self.owners.insert(token_id, to);
self.token_approvals.insert(token_id, Address::ZERO);
evm::log(Transfer { from, to, tokenId: token_id });
}
}