Phát triển Smart Contracts với Solidity - Lập trình Blockchain
· 6 min read

Phát triển Smart Contracts với Solidity
Solidity là ngôn ngữ lập trình chính để phát triển smart contracts trên Ethereum và các EVM-compatible blockchains. Bài viết này sẽ hướng dẫn bạn từ cơ bản đến nâng cao về Solidity.
Giới thiệu Solidity
Solidity là gì?
Solidity là một statically-typed, contract-oriented programming language được thiết kế để phát triển smart contracts trên EVM.
Tính năng
- Object-oriented: Hỗ trợ classes, inheritance
- Static typing: Type checking tại compile time
- Libraries: Reusable code
- Events: Logging và notifications
Version và Evolution
- Current: 0.8.x series
- Breaking changes: 0.5.0, 0.6.0, 0.8.0
- Recommend: Sử dụng ^0.8.0 hoặc mới hơn
Cú pháp cơ bản
Contract Structure
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract MyContract {
// State variables
uint256 public value;
// Constructor
constructor(uint256 _initialValue) {
value = _initialValue;
}
// Functions
function setValue(uint256 _newValue) public {
value = _newValue;
}
}
Data Types
Value Types
bool public isActive = true;
uint256 public count = 100;
int256 public temperature = -10;
address public owner = msg.sender;
bytes32 public hash;
Reference Types
// Arrays
uint256[] public numbers;
uint256[5] public fixedArray;
// Structs
struct User {
string name;
uint256 age;
address wallet;
}
// Mappings
mapping(address => uint256) public balances;
Functions
// Public - có thể gọi từ bên ngoài
function publicFunction() public returns (uint256) {
return 100;
}
// Private - chỉ trong contract
function privateFunction() private returns (uint256) {
return 50;
}
// Internal - contract và children
function internalFunction() internal returns (uint256) {
return 25;
}
// External - chỉ từ bên ngoài
function externalFunction() external returns (uint256) {
return 10;
}
// View - không modify state
function viewFunction() public view returns (uint256) {
return value;
}
// Pure - không đọc/modify state
function pureFunction(uint256 x) public pure returns (uint256) {
return x * 2;
}
// Payable - nhận Ether
function payableFunction() public payable {
// Can receive Ether
}
Advanced Concepts
Modifiers
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_; // Execute function body
}
function changeOwner(address _newOwner) public onlyOwner {
owner = _newOwner;
}
Events
event Transfer(address indexed from, address indexed to, uint256 value);
function transfer(address _to, uint256 _amount) public {
// Transfer logic
emit Transfer(msg.sender, _to, _amount);
}
Inheritance
contract Ownable {
address public owner;
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
}
contract MyContract is Ownable {
constructor() {
owner = msg.sender;
}
}
Interfaces
interface IERC20 {
function transfer(address to, uint256 amount) external returns (bool);
function balanceOf(address account) external view returns (uint256);
}
contract MyContract {
IERC20 public token;
function useToken() public {
token.transfer(msg.sender, 100);
}
}
Security Patterns
Reentrancy Protection
// VULNERABLE ❌
function withdraw() public {
(bool success, ) = msg.sender.call{value: balances[msg.sender]}("");
balances[msg.sender] = 0;
}
// SAFE ✅
function withdraw() public {
uint256 amount = balances[msg.sender];
balances[msg.sender] = 0; // Checks-Effects-Interactions
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
}
Access Control
import "@openzeppelin/contracts/access/Ownable.sol";
contract MyContract is Ownable {
function adminFunction() public onlyOwner {
// Only owner can call
}
}
Integer Overflow Protection
// Solidity 0.8.0+ tự động kiểm tra overflow
uint256 public total;
function add(uint256 amount) public {
total += amount; // Auto checked for overflow
}
Input Validation
function transfer(address _to, uint256 _amount) public {
require(_to != address(0), "Invalid address");
require(_amount > 0, "Amount must be positive");
require(balances[msg.sender] >= _amount, "Insufficient balance");
// Transfer logic
}
Common Patterns
Withdrawal Pattern
mapping(address => uint256) public pendingWithdrawals;
function withdraw() public {
uint256 amount = pendingWithdrawals[msg.sender];
require(amount > 0, "Nothing to withdraw");
pendingWithdrawals[msg.sender] = 0;
payable(msg.sender).transfer(amount);
}
Pull vs Push Payments
// Pull pattern (safer)
mapping(address => uint256) public credits;
function withdraw() public {
uint256 amount = credits[msg.sender];
credits[msg.sender] = 0;
payable(msg.sender).transfer(amount);
}
Circuit Breaker
bool public stopped = false;
modifier stopInEmergency() {
require(!stopped, "Contract is stopped");
_;
}
function emergencyStop() public onlyOwner {
stopped = true;
}
Testing Smart Contracts
Hardhat Testing
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("MyContract", function () {
it("Should set and get value", async function () {
const MyContract = await ethers.getContractFactory("MyContract");
const contract = await MyContract.deploy();
await contract.setValue(100);
expect(await contract.getValue()).to.equal(100);
});
});
Test Coverage
- Unit tests cho từng function
- Integration tests cho workflows
- Edge cases và error handling
- Gas optimization tests
Deployment
Hardhat Deploy Script
async function main() {
const [deployer] = await ethers.getSigners();
const MyContract = await ethers.getContractFactory("MyContract");
const contract = await MyContract.deploy();
await contract.deployed();
console.log("Deployed to:", contract.address);
}
Verification
npx hardhat verify --network mainnet CONTRACT_ADDRESS
Gas Optimization
Tips để giảm gas
- Pack structs: Giảm storage slots
- Use uint256: Cheaper than smaller uints
- Cache storage reads: Read once, use multiple times
- Use events: Cheaper than storage for logs
- Batch operations: Process multiple items at once
Example
// Expensive ❌
for(uint i = 0; i < array.length; i++) {
doSomething(array[i]);
}
// Cheaper ✅
uint length = array.length; // Cache
for(uint i = 0; i < length; i++) {
doSomething(array[i]);
}
Best Practices
Code Organization
- Separate logic vào libraries
- Use interfaces cho contracts khác
- Modular design
- Clear naming conventions
Documentation
/// @title A simple storage contract
/// @author Your Name
/// @notice Stores a uint256 value
contract SimpleStorage {
/// @notice The stored value
/// @dev This is stored in slot 0
uint256 public value;
/// @notice Sets the value
/// @param _value The new value to store
function setValue(uint256 _value) public {
value = _value;
}
}
Error Handling
error InsufficientBalance(uint256 required, uint256 available);
function withdraw(uint256 amount) public {
if (balances[msg.sender] < amount) {
revert InsufficientBalance(amount, balances[msg.sender]);
}
// ...
}
Kết luận
Solidity là ngôn ngữ mạnh mẽ để phát triển smart contracts. Nắm vững các patterns, security best practices và optimization techniques sẽ giúp bạn xây dựng các smart contracts an toàn và hiệu quả.
Tiếp tục học về DApp Development trong Bootcamp Blockchain Mastery!
