# OpenZeppelin Contract Patterns ## Installation ```bash npm install @openzeppelin/contracts npm install @openzeppelin/contracts-upgradeable # Upgradeable version ``` ## ERC-20 Token ```solidity import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; contract MyToken is ERC20, Ownable { constructor(uint256 initialSupply) ERC20("MyToken", "MTK") Ownable(msg.sender) { _mint(msg.sender, initialSupply * 10 ** decimals()); } function mint(address to, uint256 amount) public onlyOwner { _mint(to, amount); } } ``` ## ERC-721 NFT ```solidity import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; contract MyNFT is ERC721URIStorage, Ownable { using Counters for Counters.Counter; Counters.Counter private _tokenIds; function mint(address to, string memory tokenURI) public onlyOwner returns (uint256) { _tokenIds.increment(); uint256 newId = _tokenIds.current(); _safeMint(to, newId); _setTokenURI(newId, tokenURI); return newId; } } ``` ## Access Control (Multi-Role) ```solidity import "@openzeppelin/contracts/access/AccessControl.sol"; contract MyContract 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) public onlyRole(MINTER_ROLE) { ... } } ``` ## Upgradeable Contracts (UUPS) ```solidity import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; contract MyContractV1 is UUPSUpgradeable, OwnableUpgradeable { function initialize() public initializer { __Ownable_init(msg.sender); __UUPSUpgradeable_init(); } function _authorizeUpgrade(address) internal override onlyOwner {} } // Deploy: upgrades.deployProxy(MyContractV1, [], { kind: 'uups' }) // Upgrade: upgrades.upgradeProxy(proxyAddress, MyContractV2) ``` ## ReentrancyGuard (Reentrancy Protection) ```solidity import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; contract SafeVault is ReentrancyGuard { function withdraw(uint256 amount) external nonReentrant { // CEI pattern: Check → Effect → Interact require(balances[msg.sender] >= amount); balances[msg.sender] -= amount; // Effect: modify state first payable(msg.sender).transfer(amount); // Interact last } } ``` ## Pausable ```solidity import "@openzeppelin/contracts/utils/Pausable.sol"; contract MyContract is Pausable, Ownable { function pause() public onlyOwner { _pause(); } function unpause() public onlyOwner { _unpause(); } function transfer() public whenNotPaused { ... } } ``` ## Common Pitfalls - Upgradeable contracts **cannot have a constructor**, use `initialize()` instead with the `initializer` modifier - Upgradeable contracts **cannot change storage layout**, only append new variables - Use `_disableInitializers()` to prevent implementation contracts from being initialized directly - AccessControl is more flexible than Ownable, prefer it for multi-person team projects