Roadmap › Solidity & Smart Contract Development › Module: Object-Oriented Solidity
Lessons in this course (11)
6. ERC-20 and ERC-721 with OpenZeppelin
Intermediate★ Must knowLesson 6 of 11
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
contract DivakarToken is ERC20, ERC20Permit, Ownable {
constructor(address initialOwner) ERC20("Divakar Token", "DVK") ERC20Permit("Divakar Token") Ownable(initialOwner) {
_mint(initialOwner, 1_000_000 * 10 ** decimals()); // 18 decimals by default
}
function mint(address to, uint256 amount) external onlyOwner { _mint(to, amount); }
}solidity
import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
contract CourseCertificate is ERC721, AccessControl {
bytes32 public constant ISSUER_ROLE = keccak256("ISSUER_ROLE");
uint256 private _nextId = 1;
string private _base;
constructor(string memory baseUri) ERC721("Course Certificate", "CERT") {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(ISSUER_ROLE, msg.sender);
_base = baseUri; // e.g. ipfs://<CID>/
}
function issue(address student) external onlyRole(ISSUER_ROLE) returns (uint256 id) {
id = _nextId++;
_safeMint(student, id);
}
function _baseURI() internal view override returns (string memory) { return _base; }
function supportsInterface(bytes4 id) public view override(ERC721, AccessControl) returns (bool) {
return super.supportsInterface(id);
}
}Use OpenZeppelin instead of writing token logic yourself — audited, standard-compliant. Ownable (single owner) vs AccessControl (roles) vs AccessManager (centralised permissions, OZ 5).