日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

以太坊开发入门-ERC20合约

發布時間:2023/12/20 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 以太坊开发入门-ERC20合约 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在上一章節中完成了一個非常簡單的合約,本節中將按照ERC20協議完成一個合約, 本章部分源代碼參考于網絡開源代碼,詳細了解:openzeppelin-contracts/contracts/token/ERC20 at master · OpenZeppelin/openzeppelin-contracts · GitHub。

開始之前先介紹一下什么是ERC20:

ERC-20指的是以太坊網絡的一種代幣合約標準。ERC-20是現在最出名的標準,ERC-20標準里無價值的差別,Token之間是能夠進行互換的。意思就是在ERC-20標準下,你的100塊“錢”和我的100塊“錢”相同,沒什么區別。ERC-20標準里規定了Token要有它的名字、符號、總供應量以及包含轉賬、匯款等其他功能。這個標準的優勢就是:只要Token符合ERC-20標準,這樣的話它就會兼容以太坊錢包。也就是說,就可以太坊錢包里加入這個Token,還能通過錢包把它發給別人。由于ERC-20標準的存在,發行Token就會更加簡單。現在以太坊上ERC-20 Token的數量超過了180000種。

ERC2.0是一套接口定義,定義了合約的基本功能,其定義如下:

// SPDX-License-Identifier: MIT //file IERC20.sol pragma solidity ^0.8.0;interface IERC20 {// 總發行量function totalSupply() external view returns (uint256);// 查看地址余額function balanceOf(address account) external view returns (uint256);/// 從自己帳戶給指定地址轉賬function transfer(address account, uint256 amount) external returns (bool);// 查看被授權人還可以使用的代幣余額function allowance(address owner, address spender) external view returns (uint256);// 授權指定帳戶使用你擁有的代幣function approve(address spender, uint256 amount) external returns (bool);// 從一個地址轉賬至另一個地址,該函數只能是通過approver授權的用戶可以調用function transferFrom(address from,address to,uint256 amount) external returns (bool);/// 定義事件,發生代幣轉移時觸發event Transfer(address indexed from, address indexed to, uint256 value);/// 定義事件 授權時觸發event Approval(address indexed owner, address indexed spender, uint256 value); }

詳細說明參考代碼注釋。

// SPDX-License-Identifier: MIT //file IERC20Metadata.sol pragma solidity ^0.8.0; import "./IERC20.sol"; interface IERC20Metadata is IERC20 {// 代幣名稱, 如:BitCoinfunction name() external view returns (string memory);// 代幣符號或簡稱, 如:BTCfunction symbol() external view returns (string memory);// 代幣支持的小數點后位數,若無特別需求,我們一般默認采用18位。function decimals() external view returns (uint8); }

MetaData數據定義,該部分比較簡單,定義三個函數,分別對應代幣名稱,代幣簡稱和代幣小數點位數。

具體代碼實現:

// SPDX-License-Identifier: MIT pragma solidity ^0.8.0;import "./IERC20.sol"; import "./IERC20Metadata.sol"; contract ERC20 is IERC20, IERC20Metadata {// 地址余額mapping(address => uint256) private _balances;// 授權地址余額mapping(address => mapping(address => uint256)) private _allowances;uint256 private _totalSupply;string private _name;string private _symbol;// 設定代幣名稱符號,并初始化鑄造了10000000000代幣在發布者帳號下。constructor() {_name = "HarryToken";_symbol = "HYT";_mint(msg.sender, 10000000000);}function name() public view virtual override returns (string memory) {return _name;}function symbol() public view virtual override returns (string memory) {return _symbol;}/// 小數點位數一般為 18function decimals() public view virtual override returns (uint8) {return 18;}// 返回當前流通代幣的總量function totalSupply() public view virtual override returns (uint256) {return _totalSupply;}// 查詢指定帳號地址余額function balanceOf(address account) public view virtual override returns (uint256) {return _balances[account];}// 轉帳功能function transfer(address to, uint256 amount) public virtual override returns (bool) {address owner = msg.sender;_transfer(owner, to, amount);return true;}// 獲取被授權者可使用授權帳號的可使用余額function allowance(address owner, address spender) public view virtual override returns (uint256) {return _allowances[owner][spender];}// 授權指定帳事情可使用自己一定額度的帳戶余額。// 授權spender, 可將自己余額。使用可使用的余額的總量為amountfunction approve(address spender, uint256 amount) public virtual override returns (bool) {address owner = msg.sender;_approve(owner, spender, amount);return true;}//approve函數中的spender調用,將授權人 from 帳戶中的代幣轉入to 帳戶中function transferFrom(address from,address to,uint256 amount) public virtual override returns (bool) {address spender = msg.sender;_spendAllowance(from, spender, amount);_transfer(from, to, amount);return true;}function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {address owner = msg.sender;_approve(owner, spender, _allowances[owner][spender] + addedValue);return true;}function decreaseAllowance(address spender, uint256 substractedValue) public virtual returns (bool) {address owner = msg.sender;uint256 currentAllowance = _allowances[owner][spender];require(currentAllowance >= substractedValue, "ERC20: decreased allowance below zero");unchecked {_approve(owner, spender, currentAllowance - substractedValue);}return true;}function _transfer(address from,address to,uint256 amount) internal virtual {require(from != address(0), "ERC20: transfer from the zero address");require(to != address(0), "ERC20: transfer to the zero address");_beforeTokenTransfer(from, to, amount);uint256 fromBalance = _balances[from];require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");unchecked {_balances[from] = fromBalance - amount;}_balances[to] += amount;emit Transfer(from, to, amount);_afterTokenTransfer(from, to, amount);}function _mint(address account, uint256 amount) internal virtual {require(account != address(0), "ERC20: mint to the zero address");_beforeTokenTransfer(address(0), account, amount);_totalSupply += amount;_balances[account] += amount;emit Transfer(address(0), account, amount);_afterTokenTransfer(address(0), account, amount);}function _burn(address account, uint256 amount) internal virtual {require(account != address(0), "ERC20: burn from the zero address");_beforeTokenTransfer(account, address(0), amount);uint256 accountBalance = _balances[account];require(accountBalance >= amount, "ERC20: burn amount exceeds balance");unchecked {_balances[account] = accountBalance - amount;}_totalSupply -= amount;emit Transfer(account, address(0), amount);_afterTokenTransfer(account, address(0), amount);}function _approve(address owner,address spender,uint256 amount) internal virtual {require(owner != address(0), "ERC20: approve from the zero address");require(spender != address(0), "ERC20: approve to the zero address");_allowances[owner][spender] = amount;emit Approval(owner, spender, amount);}function _spendAllowance(address owner,address spender,uint256 amount) internal virtual {uint256 currentAllowance = allowance(owner, spender);if (currentAllowance != type(uint256).max) {require(currentAllowance >= amount, "ERC20: insufficient allowance");unchecked {_approve(owner, spender, currentAllowance - amount);}}}function _beforeTokenTransfer(address from,address to,uint256 amount) internal virtual {}function _afterTokenTransfer(address from,address to,uint256 amount) internal virtual {} } // 地址余額mapping(address => uint256) private _balances;// 授權地址余額mapping(address => mapping(address => uint256)) private _allowances;uint256 private _totalSupply;string private _name;string private _symbol;

ERC20合約中定義了5個變量:

_balances變量以keyv=>value方式存儲帳號和其對應的余額。

_allowances變量是一個兩層mapping,數據值以下結構存儲:0x123456=>[0x123457=>1000, 0x123458=>2000],代表的意思是0x123456帳號授權0x123457和0x123458兩個帳號,分別可以使用0x123456帳號1000和2000余額額度。使用余額的函數為transferFrom。

_totalSupply變量是存儲當成代幣合約發行的代幣總量,一般我們每鑄造一個新代幣,就在其值上+1。

_name變量是代幣的名稱,如比特幣名稱:BitCoin

_symbol變量是代幣的簡稱, 如比特幣簡稱:BTC

// 設定代幣名稱符號,并初始化鑄造了10000000000代幣在發布者帳號下。constructor() {_name = "HarryToken";_symbol = "HYT";_mint(msg.sender, 10000000000);}

構造函數,指令name和symbol。這里我們調用了一個private的函數_mint,給合約創建者新鑄造了10000000000個代幣。因為本合約實現的時候并沒有public的mint函數可以鑄造代幣,所以直接初始化入創建者帳戶,該合約所有的代幣都只能用創建都帳戶轉出。當前也可以將實現一個public的mint函數,關加上權限控制,讓有權限的帳戶可以隨時調mint鑄造新代幣。

function name() public view virtual override returns (string memory) {return _name;}function symbol() public view virtual override returns (string memory) {return _symbol;}/// 小數點位數一般為 18function decimals() public view virtual override returns (uint8) {return 18;}

IERC20Metadata 接口的實現方法,主要用于獲取代幣名稱,簡稱及支持的小數點位數。

function totalSupply() public view virtual override returns (uint256) {return _totalSupply; }

totalSupply查詢當前代幣的發行總量。

function balanceOf(address account) public view virtual override returns (uint256) {return _balances[account]; }

balanceOf查詢指令帳戶的代幣余額。

// 轉帳功能function transfer(address to, uint256 amount) public virtual override returns (bool) {address owner = msg.sender;_transfer(owner, to, amount);return true;}function _transfer(address from,address to,uint256 amount) internal virtual {require(from != address(0), "ERC20: transfer from the zero address");require(to != address(0), "ERC20: transfer to the zero address");_beforeTokenTransfer(from, to, amount);uint256 fromBalance = _balances[from];require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");unchecked {_balances[from] = fromBalance - amount;}_balances[to] += amount;emit Transfer(from, to, amount);_afterTokenTransfer(from, to, amount);}

transfer轉帳函數,一個比較重要的功能,調用者可以將自己的余額轉給其它帳戶。

_transfer為private的具體實現函數。主要是作了一些必要的檢查,然后從發起帳戶扣減余額,再將余額加到接收帳戶。最后發送了一個轉帳事件,方便開發者監聽轉帳功能。這里的_beforeTokenTransfer和_afterTokenTransfer并沒有實現具體功能,開發中可根據實現需要做一些功能實現。

// 獲取被授權者可使用授權帳號的可使用余額function allowance(address owner, address spender) public view virtual override returns (uint256) {return _allowances[owner][spender];}// 授權指定帳事情可使用自己一定額度的帳戶余額。// 授權spender, 可將自己余額。使用可使用的余額的總量為amountfunction approve(address spender, uint256 amount) public virtual override returns (bool) {address owner = msg.sender;_approve(owner, spender, amount);return true;}function _approve(address owner,address spender,uint256 amount) internal virtual {require(owner != address(0), "ERC20: approve from the zero address");require(spender != address(0), "ERC20: approve to the zero address");_allowances[owner][spender] = amount;emit Approval(owner, spender, amount);}

allowance、approve主要是實現授權其它帳戶可以使用自己的余額,并設定使用上限。相關的授權者存儲在_allowances變量中。

function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {address owner = msg.sender;_approve(owner, spender, _allowances[owner][spender] + addedValue);return true;}function decreaseAllowance(address spender, uint256 substractedValue) public virtual returns (bool) {address owner = msg.sender;uint256 currentAllowance = _allowances[owner][spender];require(currentAllowance >= substractedValue, "ERC20: decreased allowance below zero");unchecked {_approve(owner, spender, currentAllowance - substractedValue);}return true;}

increaseAllowance、decreaseAllowance兩個函數是對approve函數功能的加強,對授權額度進行增減,這兩個函數關不是ERC20協議中的內容。只是作者在參考源碼時覺得有用,就加入了這兩個函數。

function transferFrom(address from,address to,uint256 amount) public virtual override returns (bool) {address spender = msg.sender;_spendAllowance(from, spender, amount);_transfer(from, to, amount);return true;}function _spendAllowance(address owner,address spender,uint256 amount) internal virtual {uint256 currentAllowance = allowance(owner, spender);if (currentAllowance != type(uint256).max) {require(currentAllowance >= amount, "ERC20: insufficient allowance");unchecked {_approve(owner, spender, currentAllowance - amount);}}}

transferFrom,_spendAllowance是在授權額度下,進行轉帳的功能實現。

transferFrom函數的from參數是授權帳戶,to是余額接受帳戶,amount是轉帳余額,該函數的功能是將from帳戶的余額轉移amount個數據至to用戶帳戶中,調用者必須是from帳戶通過_approve對其進行過授權,并且還有剩余的授權額度。該函數與transfer的區別是,transfer只能轉移出調用者自己的帳戶余額。

_spendAllowance是在進行授權轉帳時首先扣減授權額度,保證被授權都在授權額度范圍內使用轉帳功能。

function _mint(address account, uint256 amount) internal virtual {require(account != address(0), "ERC20: mint to the zero address");_beforeTokenTransfer(address(0), account, amount);_totalSupply += amount;_balances[account] += amount;emit Transfer(address(0), account, amount);_afterTokenTransfer(address(0), account, amount);}function _burn(address account, uint256 amount) internal virtual {require(account != address(0), "ERC20: burn from the zero address");_beforeTokenTransfer(account, address(0), amount);uint256 accountBalance = _balances[account];require(accountBalance >= amount, "ERC20: burn amount exceeds balance");unchecked {_balances[account] = accountBalance - amount;}_totalSupply -= amount;emit Transfer(account, address(0), amount);_afterTokenTransfer(account, address(0), amount);}

_mint和_burn是兩個相反的功能,一個是新鑄造代幣,一個是燃燒(銷毀)代幣。兩個方法都是private,關沒有對外開放。

完成上述三個源文件的代碼就可能編譯部署,選中ERC20.sol文件,完成編譯。部署時要特別注意在選中Contract中的實現合約ERC20,不要誤選了接口合約。

否則會部署后報如下錯誤,很多剛開始接觸合約的讀者都遇到該問題了,所以作者提示一下。

部署成功后,就可以查看并調用合約了。

一個比較健全的ERC20代幣合約就完成了。下一章節給大家分享在ERC721協議下實現NTF相關的功能。

總結

以上是生活随笔為你收集整理的以太坊开发入门-ERC20合约的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 成人aaa| 秋霞成人网 | 久久精品国产亚洲AV无码男同 | 91网站免费视频 | 日韩精品福利视频 | 成人一区在线观看 | 午夜看片福利 | 亚洲一区国产精品 | 国产尤物av尤物在线看 | 日韩黄色片免费看 | 日韩欧美成人一区二区 | 欧美性大战久久久久久 | 国产乱free国语对白 | 国产高清精品软件丝瓜软件 | 中文字幕有码av | 神马午夜电影一区二区三区在线观看 | 大地资源二中文在线影视免费观看 | www.com污| 午夜羞羞羞| 国产无码精品合集 | 日韩成人av一区二区 | 超碰在线国产97 | 午夜精品欧美 | 日韩六九视频 | 欧美在线一二三四区 | 精品欧美激情精品一区 | 久久久久久久久久一区二区三区 | 午夜裸体性播放 | 97国产在线观看 | 黄色中文视频 | 中文字幕一区三区 | 成人小视频免费观看 | 成人啪啪18免费游戏链接 | 一本久草 | 大尺度做爰无遮挡露器官 | 动漫女被黄漫免费视频 | 中文字幕一区二区三区av | 国产午夜不卡 | 午夜你懂的| 久久久久久久久久久电影 | 国产亚洲av片在线观看18女人 | 欧美乱码精品一区二区三区 | 久久久亚洲国产精品 | 一区二区啪啪啪 | 影音先锋成人资源 | 无套白嫩进入乌克兰美女 | 二区三区| 97视频精品| jiizzyou欧美2| 男人的亚洲天堂 | 天天草比 | 成人午夜视频免费 | 亚洲精品国产精品乱码不66 | 超碰神马 | av在线影片 | 一区二区三区啪啪啪 | 住在隔壁的她动漫免费观看全集下载 | 色综合视频在线 | 国产午夜大片 | 靠逼网站在线观看 | 一级做a视频 | 伊人久久大香线蕉综合网站 | 亚洲精品久久久久av无码 | 爆操白虎逼 | 日韩一区二区在线观看 | 国产精品成 | 欧美jizzhd精品欧美18 | 国产黄色大片免费看 | 狠狠躁夜夜躁人 | 国模视频一区二区 | 免费欧美一区 | 影音先锋中文字幕在线 | 香蕉久久久久久久av网站 | 天堂在线观看av | 日韩毛片在线看 | 黄色大片视频 | 欧美大片高清 | 制服师生在线 | 亚洲精品国产熟女久久久 | 激情视频网站在线观看 | 在线观看无遮挡 | 色欲av无码一区二区三区 | 日本在线资源 | 嫦娥性艳史bd | 一级黄色片看看 | 午夜不卡视频 | 女人囗交吞精囗述 | wwwav视频| 欧美日韩精品综合 | 美女福利视频网 | 青娱乐在线免费视频 | 在线免费看黄网站 | 综合久久99| 中文字幕第三页 | 国产高清成人 | 久久经典| 看片国产 | 人体一级片 | 男人的天堂你懂的 |