1. Đơn vị
1.1. Những đơn vị thường sử dụng
wei
đơn vị nhỏ nhất (1wei
== 1)gwei
đơn vị thường được sử dụng để diễn tả giá gas hiện tại (1gwei
== 1e9)ether
đơn vị (1ether
== 1e18)
Note:
In Solidity, we will use integers for calculations and the language does not support thefloat
type. The float representation issue causes rounding errors (rounding
) that create logical holes for attack.
1.2. Đơn vị thời gian
- 1 == 1
seconds
- 1
minutes
== 60seconds
- 1
hours
== 60minutes
- 1
days
== 24hours
- 1
weeks
== 7days
Ví dụ
function f(uint start, uint daysAfter) public {
if (block.timestamp >= start + daysAfter * 1 days) {
// ...
}
}
2. Biến toàn cục
2.1. Thuộc tính blockchain
blockhash(uint blockNumber) returns (bytes32)
: hash của khối đã cho khi số khối là một trong 256 khối gần đây nhất; nếu không thì trả về 0.blobhash(uint index) returns (bytes32)
: hash được phiên bản của blob thứ chỉ mục được liên kết với giao dịch hiện tại. Hàm băm được phiên bản bao gồm một byte đơn biểu thị phiên bản (hiện tại là 0x01), theo sau là 31 byte cuối cùng của hàm băm SHA256 của cam kết KZG (EIP-4844).block.basefee (uint)
: phí cơ bản của khối hiện tại (EIP-3198 và EIP-1559)block.blobbasefee (uint)
: Phí cơ sở blob của khối hiện tại (EIP-7516 và EIP-4844)block.chainid (uint)
: id chuỗi hiện tạiblock.coinbase (address payable)
: địa chỉ của người khai thác khối hiện tạiblock.difficulty (uint)
: độ khó khối hiện tại (EVM < Paris). Đối với các phiên bản EVM khác, nó hoạt động như một bí danh không được dùng nữa cho block.prevrandao (EIP-4399)block.gaslimit (uint)
: gaslimit khối hiện tạiblock.number (uint)
: số khối hiện tạiblock.prevrandao (uint)
: số ngẫu nhiên được cung cấp bởi chuỗi beacon (EVM >= Paris)block.timestamp (uint)
: dấu thời gian khối hiện tại tính bằng giây kể từ kỷ nguyên unixgasleft() returns (uint256)
: khí còn lạimsg.data (bytes calldata)
: dữ liệu cuộc gọi hoàn chỉnhmsg.sender (address)
: người gửi tin nhắn (cuộc gọi hiện tại)msg.sig (bytes4)
: bốn byte đầu tiên của calldata (tức là mã định danh hàm)msg.value (uint)
: số wei gửi cùng tin nhắntx.gasprice (uint)
: giá gas của giao dịchtx.origin (address)
: người gửi giao dịch (chuỗi cuộc gọi đầy đủ)
2.2. Xử lý Error
assert
require(bool condition)
require(bool condition, string memory message)
revert()
revert(string memory reason)
2.3. Những method sẵn của address
<address>.balance (uint256)
: số dư của Địa chỉ ở Wei.<address>.code (bytes memory)
: mã tại Địa chỉ (có thể để trống).<address>.codehash (bytes32)
: mã băm của Địa chỉ.<address payable>.transfer(uint256 amount)
: gửi số lượng Wei nhất định đến Địa chỉ, hoàn nguyên nếu thất bại, chuyển tiếp 2300 tiền trợ cấp gas, không thể điều chỉnh.<address payable>.send(uint256 amount) returns (bool)
: gửi số lượng Wei đã cho đến Địa chỉ, trả về sai nếu thất bại, chuyển tiếp 2300 tiền trợ cấp gas, không thể điều chỉnh.<address>.call(bytes memory) returns (bool, bytes memory)
: đưa ra CALL ở mức độ thấp với tải trọng nhất định, trả về điều kiện thành công và trả về dữ liệu, chuyển tiếp tất cả khí có sẵn, có thể điều chỉnh.<address>.delegatecall(bytes memory) returns (bool, bytes memory)
: đưa ra DELEGATECALL cấp thấp với tải trọng nhất định, trả về điều kiện thành công và trả về dữ liệu, chuyển tiếp tất cả gas có sẵn, có thể điều chỉnh<address>.staticcall(bytes memory) returns (bool, bytes memory)
2.4. Keyword liên quan đến contract
this
super
selfdestruct(address payable recipient)
3. Expressions và Control Structures
3.1. Keyword hỗ trợ
Solidity có hỗ trợ if
, else
, while
, do
, for
, break
, continue
, return
, try
/catch
như C hoặc JavaScript.
3.2. Gọi function của contract khác
Chúng ta có thể gọi function
của contract
khác từ 1 contract
. Có 1 ví dụ dưới đây với 2 contract Caller
và Callee
.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Callee {
uint public x;
uint public value;
function setX(uint _x) public returns (uint) {
x = _x;
return x;
}
function setXandSendEther(uint _x) public payable returns (uint, uint) {
x = _x;
value = msg.value;
return (x, value);
}
}
contract Caller {
function setX(Callee _callee, uint _x) public {
uint x = _callee.setX(_x);
}
function setXFromAddress(address _addr, uint _x) public {
Callee callee = Callee(_addr);
callee.setX(_x);
}
function setXandSendEther(Callee _callee, uint _x) public payable {
(uint x, uint value) = _callee.setXandSendEther{value: msg.value}(_x);
}
}
3.3. Tạo contract mới với new
Chúng ta có thể dùng keyword new
để tạo contract mới từ 1 contract. Ví dụ AdvancedStorage.sol
sẽ đi sâu vào phương pháp này.
4. Advanced Storage
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract AdvancedStorage {
// Declare the address of a vault manager
address public vaultManager;
// Declare an error type for unauthorized access
error OwnableUnauthorizedAccount(address account);
// Constructor is a function that runs when the contract is initialized
constructor() {
// Assign the address of the deployer to the vault manager variable
vaultManager = msg.sender;
}
// Declare the InvestmentVault Struct data type
struct InvestmentVault {
uint256 investmentDuration; // Thời gian đầu tư
int256 returnOnInvestment; // % lãi suất trả về
bool initialized; // Đã khởi tạo
address identityCard; // Địa chỉ thẻ thông tin
}
// Declare a variable with the InvestmentVault type
InvestmentVault private investmentVault;
// This function initializes the investment vault
function setInitialInvestmentVault(uint256 daysAfter, int256 _returnOnInvestment, address _vaultOwner) public {
// We check if the initiator is the vaultManager
if (msg.sender != vaultManager) {
// This reverts all actions and reverts the transaction
revert OwnableUnauthorizedAccount(msg.sender);
}
// Declare the investment duration
uint256 _investmentDuration = block.timestamp + daysAfter * 1 days;
// Create a new identity card for the customer
CustomerIdentityCard customerIdentityCard = new CustomerIdentityCard(_vaultOwner);
// Assign the address of the vault owner/customer to the mapping with the vault information
investmentVault = InvestmentVault({investmentDuration: _investmentDuration, returnOnInvestment: _returnOnInvestment, initialized: true, identityCard: address(customerIdentityCard)});
}
// Function to change the return on investment
function editReturnOnInvestment(int256 _newReturnOnInvestment) public {
// require keyword works similarly to if and revert above
require (msg.sender == vaultManager, "Unauthorized Manager");
// Change the value of the interest rate
investmentVault.returnOnInvestment = _newReturnOnInvestment;
}
// Function to return investmentVault information
function retrieveInvestmentVault() public view returns (InvestmentVault memory _investmentVault) {
return investmentVault;
}
// Function to return the address of the IdentityCard
function retrieveCustomerInformation() public view returns (address) {
return CustomerIdentityCard(investmentVault.identityCard).customer();
}
}
// Contract that stores the address of the vault owner
contract CustomerIdentityCard {
// declares a variable to store the address of the customer
address public customer;
// initialize the contract and assign the address of the customer
constructor(address _customer) {
customer = _customer;
}
}
Objectives
By the end of this lesson, you'll understand: