Skip to main content

One post tagged with "Web3 Development"

View All Tags

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

· 6 min read

Bootcamp Blockchain Mastery

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

  1. Pack structs: Giảm storage slots
  2. Use uint256: Cheaper than smaller uints
  3. Cache storage reads: Read once, use multiple times
  4. Use events: Cheaper than storage for logs
  5. 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!