Tools·8 min का पठन·Solingo द्वारा

OpenZeppelin Contracts — Solidity के लिए Standard Library

OpenZeppelin Contracts, secure smart contract development के लिए सबसे trusted library है। सीखें कैसे ERC20, ERC721, Access Control, और अन्य battle-tested components का उपयोग करें।

# OpenZeppelin Contracts — Solidity के लिए Standard Library

जब आप smart contracts बना रहे हों, तो आपको wheel को reinvent नहीं करना चाहिए। OpenZeppelin Contracts industry-standard library है जो common patterns के secure, audited, और gas-optimized implementations provide करती है। ERC20 tokens से लेकर access control, upgradeable contracts से लेकर security utilities तक, OpenZeppelin हजारों production contracts की foundation है जो billions of dollars को secure करती हैं।

OpenZeppelin Contracts क्या है?

OpenZeppelin Contracts, Ethereum और EVM-compatible chains के लिए reusable smart contract components की एक open-source library है। OpenZeppelin द्वारा developed और maintained, हर contract है:

  • Audited multiple security firms द्वारा
  • Battle-tested major protocols द्वारा production में
  • Gas-optimized efficiency के लिए
  • Well-documented comprehensive guides के साथ
  • Actively maintained security updates के साथ

Library modular है — केवल वही उपयोग करें जो आपको चाहिए और small, focused components से contracts compose करें।

Installation

npm का उपयोग करना

npm install @openzeppelin/contracts

Foundry का उपयोग करना

forge install OpenZeppelin/openzeppelin-contracts

foundry.toml में add करें:

[dependencies]

openzeppelin-contracts = "5.2.0"

अपने Contracts में Import करें

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

import "@openzeppelin/contracts/access/Ownable.sol";

Solidity package को node_modules में find करता है।

Token Standards

ERC20 — Fungible Tokens

ERC20, fungible tokens (cryptocurrencies, stablecoins, governance tokens) के लिए standard है।

Basic ERC20 Token:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.26;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract MyToken is ERC20 {

constructor(uint256 initialSupply) ERC20("MyToken", "MTK") {

_mint(msg.sender, initialSupply);

}

}

बस इतना ही! अब आपके पास एक fully functional ERC20 token है:

  • totalSupply()
  • balanceOf(address)
  • transfer(address, uint256)
  • approve(address, uint256)
  • transferFrom(address, address, uint256)
  • allowance(address, address)

Minting और Burning add करना:

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

import "@openzeppelin/contracts/access/Ownable.sol";

contract MyToken is ERC20, Ownable {

constructor() ERC20("MyToken", "MTK") Ownable(msg.sender) {}

function mint(address to, uint256 amount) public onlyOwner {

_mint(to, amount);

}

function burn(uint256 amount) public {

_burn(msg.sender, amount);

}

}

Pausable add करना:

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

import "@openzeppelin/contracts/utils/Pausable.sol";

import "@openzeppelin/contracts/access/Ownable.sol";

contract MyToken is ERC20, Pausable, Ownable {

constructor() ERC20("MyToken", "MTK") Ownable(msg.sender) {}

function pause() public onlyOwner {

_pause();

}

function unpause() public onlyOwner {

_unpause();

}

function _update(address from, address to, uint256 value)

internal

override

whenNotPaused

{

super._update(from, to, value);

}

}

ERC721 — Non-Fungible Tokens (NFTs)

ERC721, unique, non-fungible tokens (NFTs) के लिए standard है।

Basic NFT:

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

import "@openzeppelin/contracts/access/Ownable.sol";

contract MyNFT is ERC721, Ownable {

uint256 private _tokenIdCounter;

constructor() ERC721("MyNFT", "MNFT") Ownable(msg.sender) {}

function mint(address to) public onlyOwner {

uint256 tokenId = _tokenIdCounter++;

_safeMint(to, tokenId);

}

}

Metadata URI add करना:

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";

contract MyNFT is ERC721URIStorage, Ownable {

uint256 private _tokenIdCounter;

constructor() ERC721("MyNFT", "MNFT") Ownable(msg.sender) {}

function mint(address to, string memory uri) public onlyOwner {

uint256 tokenId = _tokenIdCounter++;

_safeMint(to, tokenId);

_setTokenURI(tokenId, uri);

}

}

Enumerable add करना:

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";

contract MyNFT is ERC721Enumerable, Ownable {

constructor() ERC721("MyNFT", "MNFT") Ownable(msg.sender) {}

// अब आपको मिलता है:

// - totalSupply()

// - tokenByIndex(uint256 index)

// - tokenOfOwnerByIndex(address owner, uint256 index)

}

ERC1155 — Multi-Token Standard

ERC1155 एक single contract में fungible और non-fungible दोनों tokens को support करता है।

import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";

import "@openzeppelin/contracts/access/Ownable.sol";

contract MyMultiToken is ERC1155, Ownable {

uint256 public constant GOLD = 0;

uint256 public constant SILVER = 1;

uint256 public constant SWORD = 2;

constructor() ERC1155("https://game.example/api/item/{id}.json") Ownable(msg.sender) {}

function mint(address to, uint256 id, uint256 amount) public onlyOwner {

_mint(to, id, amount, "");

}

function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts) public onlyOwner {

_mintBatch(to, ids, amounts, "");

}

}

Access Control

Ownable — Single Owner

import "@openzeppelin/contracts/access/Ownable.sol";

contract MyContract is Ownable {

constructor() Ownable(msg.sender) {}

function restrictedFunction() public onlyOwner {

// केवल owner इसे call कर सकता है

}

function transferOwnership(address newOwner) public override onlyOwner {

super.transferOwnership(newOwner);

}

}

AccessControl — Role-Based Access

Multi-role systems (admin, minter, pauser, etc.) के लिए:

import "@openzeppelin/contracts/access/AccessControl.sol";

contract MyToken is AccessControl {

bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");

constructor() {

_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);

_grantRole(MINTER_ROLE, msg.sender);

}

function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) {

_mint(to, amount);

}

function pause() public onlyRole(PAUSER_ROLE) {

_pause();

}

}

Ownable2Step — Safer Ownership Transfer

गलत address में accidental ownership transfer को रोकता है:

import "@openzeppelin/contracts/access/Ownable2Step.sol";

contract MyContract is Ownable2Step {

constructor() Ownable(msg.sender) {}

// Owner transferOwnership(newOwner) को call करता है

// नए owner को confirm करने के लिए acceptOwnership() call करना होगा

}

Security Utilities

ReentrancyGuard — Reentrancy Attacks को रोकें

import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

contract Bank is ReentrancyGuard {

mapping(address => uint256) public balances;

function withdraw(uint256 amount) public nonReentrant {

require(balances[msg.sender] >= amount);

balances[msg.sender] -= amount;

(bool success, ) = msg.sender.call{value: amount}("");

require(success);

}

}

nonReentrant modifier execution के दौरान reentrant calls को रोकता है।

Pausable — Emergency Stop

import "@openzeppelin/contracts/utils/Pausable.sol";

import "@openzeppelin/contracts/access/Ownable.sol";

contract MyContract is Pausable, Ownable {

constructor() Ownable(msg.sender) {}

function criticalFunction() public whenNotPaused {

// Paused होने पर इसे call नहीं किया जा सकता

}

function pause() public onlyOwner {

_pause();

}

function unpause() public onlyOwner {

_unpause();

}

}

SafeERC20 — Safe Token Transfers

कुछ tokens ERC20 standard को correctly follow नहीं करते (USDT bool return नहीं करता)। SafeERC20 इन edge cases को handle करता है:

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

contract Vault {

using SafeERC20 for IERC20;

function deposit(IERC20 token, uint256 amount) public {

token.safeTransferFrom(msg.sender, address(this), amount);

// Transfer fail होने पर revert करता है, भले ही token bool return न करे

}

}

Upgradeable Contracts

OpenZeppelin proxy pattern का उपयोग करके सभी contracts के upgradeable versions provide करता है।

Installation

npm install @openzeppelin/contracts-upgradeable @openzeppelin/hardhat-upgrades

Upgradeable ERC20

import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";

import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

contract MyTokenUpgradeable is Initializable, ERC20Upgradeable, OwnableUpgradeable {

/// @custom:oz-upgrades-unsafe-allow constructor

constructor() {

_disableInitializers();

}

function initialize(uint256 initialSupply) public initializer {

__ERC20_init("MyToken", "MTK");

__Ownable_init(msg.sender);

_mint(msg.sender, initialSupply);

}

}

Key differences:

  • *Upgradeable versions से inherit करें
  • constructor() की जगह initialize() का उपयोग करें
  • Initializer में __ContractName_init() को call करें
  • Constructor में initializers को disable करें

Upgradeable Contracts को Deploy करना

Hardhat के साथ:

const { ethers, upgrades } = require("hardhat");

async function main() {

const MyToken = await ethers.getContractFactory("MyTokenUpgradeable");

const token = await upgrades.deployProxy(MyToken, [1000000], {

initializer: "initialize"

});

await token.waitForDeployment();

console.log("Token deployed to:", await token.getAddress());

}

Upgrading:

const MyTokenV2 = await ethers.getContractFactory("MyTokenUpgradeableV2");

const upgraded = await upgrades.upgradeProxy(proxyAddress, MyTokenV2);

Utilities

Cryptography

ECDSA signature verification:

import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

import "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";

contract SignatureVerifier {

using ECDSA for bytes32;

using MessageHashUtils for bytes32;

function verify(address signer, bytes32 messageHash, bytes memory signature) public pure returns (bool) {

bytes32 ethSignedHash = messageHash.toEthSignedMessageHash();

address recoveredSigner = ethSignedHash.recover(signature);

return recoveredSigner == signer;

}

}

Merkle proofs:

import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";

contract Whitelist {

bytes32 public merkleRoot;

constructor(bytes32 _merkleRoot) {

merkleRoot = _merkleRoot;

}

function claim(bytes32[] calldata proof) public {

bytes32 leaf = keccak256(abi.encodePacked(msg.sender));

require(MerkleProof.verify(proof, merkleRoot, leaf), "Invalid proof");

// Access grant करें

}

}

Counters (Deprecated, native uint256 का उपयोग करें)

पुराने versions में, Counters को auto-incrementing IDs के लिए उपयोग किया जाता था। Modern Solidity यह natively कर सकता है:

contract NFT {

uint256 private _tokenIdCounter; // Counters से सस्ता

function mint() public {

uint256 tokenId = _tokenIdCounter++;

_safeMint(msg.sender, tokenId);

}

}

Math Utilities

import "@openzeppelin/contracts/utils/math/Math.sol";

contract Calculator {

function average(uint256 a, uint256 b) public pure returns (uint256) {

return Math.average(a, b); // Overflow को रोकता है

}

function sqrt(uint256 x) public pure returns (uint256) {

return Math.sqrt(x);

}

}

Best Practices

1. Latest Stable Version का उपयोग करें

npm install @openzeppelin/contracts@latest

Releases को github.com/OpenZeppelin/openzeppelin-contracts/releases पर check करें

2. जो Import करते हैं उसे समझें

Blindly contracts को inherit न करें। Behavior को समझने के लिए source code पढ़ें, विशेष रूप से:

  • Tokens में _update() hooks
  • Virtual functions जिन्हें आप override कर सकते हैं
  • Internal functions जिन्हें आप call कर सकते हैं

3. सावधानी से Override करें

Functions को override करते समय, हमेशा super को call करें:

function _update(address from, address to, uint256 value) internal override {

super._update(from, to, value); // Parent implementation को call करें

// आपका custom logic

}

4. Compose करें, Modify न करें

OpenZeppelin code को modify करने की जगह, contracts को compose करें:

// Good

contract MyToken is ERC20, Ownable, Pausable {

// Existing contracts को compose करें

}

// Bad - OZ internals को modify करना

contract MyToken is ERC20 {

function transfer() public override {

// Transfer logic को rewrite करना = खतरनाक

}

}

5. Updates के लिए Check करें

OpenZeppelin security advisories को subscribe करें और regularly update करें।

Wizard — Visually Contracts Generate करें

OpenZeppelin Contracts Wizard ready-to-deploy contracts generate करता है:

wizard.openzeppelin.com पर visit करें

  • Contract type select करें (ERC20, ERC721, ERC1155, Governor, Custom)
  • Features choose करें (Mintable, Burnable, Pausable, Votes, etc.)
  • Settings configure करें
  • Generated code को copy करें
  • Wizard perfect है:

    • यह सीखने के लिए कि कौन से contracts को combine करें
    • नए projects को bootstrap करने के लिए
    • Contract composition को समझने के लिए

    Conclusion

    OpenZeppelin Contracts secure smart contract development की foundation है। Battle-tested, audited implementations का leverage करके, आप common vulnerabilities से बचते हैं और अपने unique business logic पर focus कर सकते हैं। Simple tokens से लेकर complex governance systems तक, OpenZeppelin आपको वे building blocks provide करता है जो आपको चाहिए।

    Confidence के साथ building शुरू करें — OpenZeppelin Contracts install करें और library को explore करें। फिर Solingo के smart contract challenges के साथ अपनी skills को sharp करें ताकि secure development patterns में master बन सकें।

    अगले steps:

    • OpenZeppelin का उपयोग करके अपना पहला ERC20 token deploy करें
    • Multi-role systems के लिए AccessControl pattern को explore करें
    • Upgradeable contracts और proxy pattern के बारे में सीखें

    Practice में लगाने के लिए तैयार हैं?

    Solingo पर interactive exercises के साथ इन concepts को apply करें।

    मुफ्त में शुरू करें