ERC-20 代幣標準
頁面最後更新時間: 2026年2月14日
介紹
什麼是代幣?
代幣幾乎可以代表以太坊中的任何東西:
- 線上平台信譽積分
- 遊戲中角色的技能
- 金融資產,如公司股份
- 法定貨幣,如美元
- 一盎司黃金
- 以及更多...
以太坊這麼強大的功能當然要由一個穩健的標準來處理,對吧? 這正是 ERC-20 發揮作用的地方! 這個標準允許開發者構建與其他產品和服務相互操作的代幣應用程式。 ERC-20 標準也用於為提供額外功能。
什麼是 ERC-20?
ERC-20 引入了同質化代幣的標準,換句話說,這些代幣具有一種屬性,使得每個代幣在類型和值上都與其他代幣完全相同。 例如,ERC-20 代幣就像以太幣一樣,意味著一個代幣會及永遠與其他代幣一樣。
先決條件
主旨
ERC-20(以太坊意見請求 20)由 Fabian Vogelsteller 於 2015 年 11 月提出,是一種在智慧型合約中實作代幣應用程式介面的代幣標準。
ERC-20 的功能範例:
- 將代幣從一個帳戶轉移到另一個帳戶
- 取得帳戶當前代幣餘額
- 取得網路上可用代幣的總供應量
- 批准第三方帳戶是否可以使用帳戶中的一定數量代幣
如果智慧型合約實作以下方法和事件,則可以將其稱為 ERC-20 代幣合約。一旦部署,它將負責追蹤以太坊上創建的代幣。
方法
1function name() public view returns (string)2function symbol() public view returns (string)3function decimals() public view returns (uint8)4function totalSupply() public view returns (uint256)5function balanceOf(address _owner) public view returns (uint256 balance)6function transfer(address _to, uint256 _value) public returns (bool success)7function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)8function approve(address _spender, uint256 _value) public returns (bool success)9function allowance(address _owner, address _spender) public view returns (uint256 remaining)顯示全部Events
1event Transfer(address indexed _from, address indexed _to, uint256 _value)2event Approval(address indexed _owner, address indexed _spender, uint256 _value)範例
讓我們看看為何標準如此重要,去讓我們檢查以太坊上的任何 ERC-20 代幣合約變得簡單。 我們只需要合約應用程式二進位介面 (ABI) 來創建任何 ERC-20 代幣的介面。 如下所示,我們將使用簡化的 ABI,使其成為一個低門檻的範例。
Web3.py 範例
首先,請確認您已安裝 Web3.pyopens in a new tab Python 函式庫:
1pip install web31from web3 import Web3234w3 = Web3(Web3.HTTPProvider("https://cloudflare-eth.com"))56dai_token_addr = "0x6B175474E89094C44Da98b954EedeAC495271d0F" # DAI7weth_token_addr = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" # 包裝以太幣 (WETH)89acc_address = "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11" # Uniswap V2:DAI 21011# 這是 ERC-20 代幣合約的簡化版合約應用程式二進位介面 (ABI)。12# 它只會公開以下方法:balanceOf(address)、decimals()、symbol() 和 totalSupply()13simplified_abi = [14 {15 'inputs': [{'internalType': 'address', 'name': 'account', 'type': 'address'}],16 'name': 'balanceOf',17 'outputs': [{'internalType': 'uint256', 'name': '', 'type': 'uint256'}],18 'stateMutability': 'view', 'type': 'function', 'constant': True19 },20 {21 'inputs': [],22 'name': 'decimals',23 'outputs': [{'internalType': 'uint8', 'name': '', 'type': 'uint8'}],24 'stateMutability': 'view', 'type': 'function', 'constant': True25 },26 {27 'inputs': [],28 'name': 'symbol',29 'outputs': [{'internalType': 'string', 'name': '', 'type': 'string'}],30 'stateMutability': 'view', 'type': 'function', 'constant': True31 },32 {33 'inputs': [],34 'name': 'totalSupply',35 'outputs': [{'internalType': 'uint256', 'name': '', 'type': 'uint256'}],36 'stateMutability': 'view', 'type': 'function', 'constant': True37 }38]3940dai_contract = w3.eth.contract(address=w3.to_checksum_address(dai_token_addr), abi=simplified_abi)41symbol = dai_contract.functions.symbol().call()42decimals = dai_contract.functions.decimals().call()43totalSupply = dai_contract.functions.totalSupply().call() / 10**decimals44addr_balance = dai_contract.functions.balanceOf(acc_address).call() / 10**decimals4546# DAI47print("===== %s =====" % symbol)48print("Total Supply:", totalSupply)49print("Addr Balance:", addr_balance)5051weth_contract = w3.eth.contract(address=w3.to_checksum_address(weth_token_addr), abi=simplified_abi)52symbol = weth_contract.functions.symbol().call()53decimals = weth_contract.functions.decimals().call()54totalSupply = weth_contract.functions.totalSupply().call() / 10**decimals55addr_balance = weth_contract.functions.balanceOf(acc_address).call() / 10**decimals5657# WETH58print("===== %s =====" % symbol)59print("Total Supply:", totalSupply)60print("Addr Balance:", addr_balance)顯示全部已知問題
ERC-20 代幣接收問題
截至 2024 年 6 月 20 日,已有至少價值 83,656,418 美元的 ERC-20 代幣因此問題而遺失。 請注意,除非您在標準之上額外實作下列的一系列限制,否則純粹的 ERC-20 實作很容易發生此問題。
當 ERC-20 代幣被發送到並非用於處理 ERC-20 代幣而設計的智慧型合約時,這些代幣可能會永久丟失。 發生這種情況是因為接收合約不具有識別或回應傳入代幣的功能,且 ERC-20 標準中沒有機制來通知接收合約有關傳入代幣的資訊。 這個問題形成的主要方式是:
- 代幣傳送機制
- ERC-20 代幣使用了 transfer 或 transferFrom 函數傳送
- 當用戶使用這些函數將代幣發送到合約地址時,無論接收合約是否為處理代幣而設,代幣都會被傳送
- 缺乏通知
- 接收的合約沒有收到代幣已發送給它的通知或回調
- 如果接收合約缺乏處理代幣的機制(例如,遞補函數或管理代幣接收的專用函數),則代幣實際上會卡在合約的地址中
- 沒有內建處理
- ERC-20 標準沒有包括強制要求接收合約實作接收代幣的函數,這導致許多合約無法正確管理收到的代幣
可能的解決方案
雖然無法完全透過 ERC-20 避免此問題,但有一些方法可以顯著降低最終用戶代幣損失的可能性:
- 最常見的問題是,當使用者將代幣傳送到代幣合約地址本身時 (例如,將 USDT 存入 USDT 代幣合約的地址)。 建議限制
transfer(..)函式,以還原此類轉帳嘗試。 可考慮在transfer(..)函式的實作中加入require(_to != address(this));檢查。 - 一般而言,
transfer(..)函式並非為將代幣存入合約而設計。approve(..) 而是改用transferFrom(..)模式將 ERC-20 代幣存入合約。 雖然可以限制transfer(..)函式,以禁止將代幣存入任何合約,但這可能會破壞與某些合約的相容性,因為這些合約假定代幣能以transfer(..)` 函式存入合約 (例如 Uniswap 流動性資金池)。 - 請始終假設 ERC-20 代幣會意外地轉入你的合約,即便該合約本不該接收任何代幣。 接收者無法防止或拒絕意外的存款。 建議實現一個功能,允許提取出那些被意外轉入的 ERC-20 代幣。
- 考慮使用替代的代幣標準。
為了解決此問題,出現了一些替代標準,例如 ERC-223 或 ERC-1363。
延伸閱讀
- EIP-20: ERC-20 代幣標準opens in a new tab
- OpenZeppelin - 代幣opens in a new tab
- OpenZeppelin - ERC-20 實作opens in a new tab
- Alchemy - Solidity ERC20 代幣指南opens in a new tab