ERC-20
ERC-20簡介
數字加密貨幣可以分為原生幣和代幣(token),ERC(Etherum Request for Comments)是以太坊開發者針對代幣提交的協議提案,而20表示的是協議的編號,所有符合ERC-20標準的代幣都能立即兼容以太坊錢包,并且降低了token的開發門檻,只要實作ERC-20協議就可以快速開發出一種新的token,除此之外,通過實作ERC標準還增加了合約之間的互操作性、token的安全性,但是ERC-20也有著一些缺陷,比如:發布后不能修改合約、如果向合約中發送的不是ETH,而是其他token,那么智能合約將不能退還你發送的token,
這個網站列舉了所有的ERC協議,可以進行參考:https://eips.ethereum.org/erc
ERC-20代幣標準
- 最小單元:6個函式,2個事件
- totalSupply:獲取token的總發行量
function totalSupply() public view returns (uint256) - balanceOf:獲取_owner代幣token
function balanceOf(address _owner) public view returns (uint256 balance) - transfer:向_to轉入_value的token
function transfer(address _to, uint256 _value) public returns (bool success) - transferFrom:從_from向_to轉入_value的token
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) - approve:授權token
function approve(address _spender, uint256 _value) public returns (bool success) - allowance:回傳剩余token使用的數量
function allowance(address _owner, address _spender) public view returns (uint256 remaining) - Transfer:轉賬事件
event Transfer(address indexed _from, address indexed _to, uint256 _value) - Approval:授權提款事件
event Approval(address indexed _owner, address indexed _spender, uint256 _value)
- totalSupply:獲取token的總發行量
- 可選單元:3個函式
- Name:token的名稱
function name() public view returns (string) - Symbol:token的logo標識
function symbol() public view returns (string) - Decimals:按小數回傳,例如輸入360000000轉化為3.6
function decimals() public view returns (uint8)
- Name:token的名稱
ERC-20案例
//------ERC20.sol
pragma solidity 0.6.0;
abstract contract ERC20{
function totalSupply() virtual public view returns (uint256);
function balanceOf(address _owner) virtual public view returns (uint256 balance);
function transfer(address _to, uint256 _value) virtual public returns (bool success);
function transferFrom(address _from, address _to, uint256 _value) virtual public returns (bool success);
function approve(address _spender, uint256 _value) virtual public returns (bool success);
function allowance(address _owner, address _spender) virtual public view returns (uint256 remaining);
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
//-------myERC20.sol
pragma solidity ^0.6.0;
import "./ERC20.sol";
// 實作安全運算
contract SafeMath {
function safeMul(uint256 a, uint256 b) internal returns (uint256) {
uint256 c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function safeDiv(uint256 a, uint256 b) internal returns (uint256) {
assert(b > 0);
uint256 c = a / b;
assert(a == b * c + a % b);
return c;
}
function safeSub(uint256 a, uint256 b) internal returns (uint256) {
assert(b <= a);
return a - b;
}
function safeAdd(uint256 a, uint256 b) internal returns (uint256) {
uint256 c = a + b;
assert(c>=a && c>=b);
return c;
}
function assert(bool assertion) internal {
if (!assertion) {
revert();
}
}
}
contract SafeMath {
function safeMul(uint256 a, uint256 b) internal returns (uint256) {
uint256 c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function safeDiv(uint256 a, uint256 b) internal returns (uint256) {
assert(b > 0);
uint256 c = a / b;
assert(a == b * c + a % b);
return c;
}
function safeSub(uint256 a, uint256 b) internal returns (uint256) {
assert(b <= a);
return a - b;
}
function safeAdd(uint256 a, uint256 b) internal returns (uint256) {
uint256 c = a + b;
assert(c>=a && c>=b);
return c;
}
function assert(bool assertion) internal {
if (!assertion) {
revert();
}
}
}
contract myERC20 is ERC20, SafeMath{
address public payable owner; // 定義合約擁有者
uint256 _totalSupply; // token發行總量
mapping(address => uint256) _balance; // 地址擁有的token
mapping(address => mapping(address => uint256)) approve; // 地址授權給另一個地址token
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
// 建構式,初始化token總量、合約擁有者,
constructor(uint256 totalSupply) public {
_totalSupply = totalSupply;
_owner = msg.sender;
}
modifier onlyOwner(){
require(msg.sender == _owner);
_;
}
// 向_to中空投_value的token
function airDrop (address _to, uint256 _value) onlyOwer public {
require(_to != address(0));
_balance[_to] = SafeMath.safeAdd(_balance[_to], _value);
_totalSupply = SafeMath.safeAdd(_totalSupply, _value);
}
// 回傳token總量
function totalSupply() override public view returns (uint256) {
return _totalSupply;
}
// 回傳_owner擁有token的數量
function balanceOf(address _owner) override public view returns (uint256 balance) {
require(owner != address(0));
return _balance[_owner];
}
// 向_to中轉入_value的token
function transfer(address _to, uint256 _value) override public returns (bool success) {
require(_to != address(0));
require(_value > 0);
require(_balance[msg.sender] >= _value);
_balance[msg.sender] = SafeMath.safeSub(_balance[msg.sender], _value);
_balance[_to] = SafeMath.safeAdd(_balance[_to], _value);
emit Transfer( msg.sender, _to, _value);
return true;
}
// 從_from向_to轉入_value的token
function transferFrom(address _from, address _to, uint256 _value) override public returns (bool success) {
require(_from != address(0));
require(_to != address(0));
require(_approve[_from][msg.sender] >= _value);
_approve[_from][msg.sender] = SafeMath.safeSub(_approve[_from][msg.sender], _value);
_balance[_to] = SafeMath.safeAdd(_balance[_to], _value);
emit Transfer(_from, _to, _value);
return true;
}
// 授權給_spender _value數量的token
function approve(address _spender, uint256 _value) override public returns (bool success) {
require(_spender != address(0));
require(_balance[msg.sender] >= _value);
_approve[msg.sender][_spender] = SafeMath.safeAdd(_approve[msg.sender][_spender], _value);
_balance[msg.sender] = SafeMath.safeSub(_balance[msg.sender], _value);
emit Approval(msg.sender, _spender, _value);
return true;
}
// 查詢_owner向_spender授權了多少token
function allowance(address _owner, address _spender) override public view returns (uint256 remaining) {
require(_owner != address(0));
require(_spender != address(0));
return _approve[_owner][_spender];
}
// 提取token
function withdrawEther(uint256 _value) public{
require(msg.sender == owner);
owner.transfer(_value);
}
}
ERC-721
ERC-721簡介
ERC-721官方的解釋是:Non-Fungible Tokens(非同質化代幣),簡寫為NFT,實作了ERC-72協議的token,每個都有自己的唯一性和獨特價值,并且不可分割,目前主要適用于收藏品、游戲等需要確定唯一性資產的場景,
ERC-721代幣標準
- 最小單元:9個函式,3個事件
- 獲取分配給owner的所以NFT數量
function balanceOf(address _owner) external view returns (uint256); - 查詢擁有token ID號為tokenid的NFT的所屬者owner地址
function ownerOf(uint256 _tokenId) external view returns (address); - 將token ID號為tokenId的NFT的NFT從_from地址的用戶轉移到_to地址的用戶
function transferFrom(address _from, address _to, uint256 _tokenId) external payable; - 將token ID號為_tokenId的NFT從_from地址的用戶轉移到_to地址的用戶,并攜帶data資料
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable; - 將token ID號為_tokenId的NFT從_from地址的用戶轉移到_to地址的用戶
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable; - 向_approved進行授權
function approve(address _approved, uint256 _tokenId) external payable; - 獲取_tokenId代幣對應的擁有者地址address
function getApproved(uint256 _tokenId) external view returns (address); - 授權給第三方_operate進行管理個人的ERC721代幣token資產
function setApprovalForAll(address _operator, bool _approved) external; - 查看_owner是否授權_operate管理所有的ERC721代幣token資產
function isApprovedForAll(address _owner, address _operator) external view returns (bool); - NFT資產轉移事件
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); - NFT資產授權地址發生變更事件
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); - 所有NFT資產被授權事件
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
- 獲取分配給owner的所以NFT數量
- 可選單元
- 描述NFT收藏品的名稱
function name() external view returns (string _name); - 合約中NTF名稱的縮寫
function symbol() external view returns (string _symbol); - 給定資產唯一資源識別符號(URI)對應的詳細資訊
function tokenURI(uint256 _tokenId) external view returns (string); - 追蹤計數合約中的NFT數量
function totalSupply() external view returns (uint256); - 列舉有效的NFT
function tokenByIndex(uint256 _index) external view returns (uint256); - 列舉分配給擁有者的NFT
function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
- 描述NFT收藏品的名稱
ERC-721案例
//---ERC721.sol
pragma solidity ^0.6.0;
abstract contract ERC721{
function balanceOf(address _owner) virtual external view returns (uint256);
function ownerOf(uint256 _tokenId) virtual external view returns (address);
function transferFrom(address _from, address _to, uint256 _tokenId) virtual external payable;
function safeTransferFrom(address _from, address _to, uint256 _tokenId) virtual external payable;
function safeTransferFrom(address _from, address _to, uint256 _tokenId, byte data) virtual external payable;
function approve(address _approved, uint256 _tokenId) virtual external payable;
function setApprovalForAll(address _operator, bool _approved) virtual external;
function getApproved(uint256 _tokenId) virtual external view returns (address);
function isApprovedForAll(address _owner, address _operator) virtual external view returns (bool);
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
}
//-----myArt.sol
pragma solidity ^0.6.0;
import "./ERC721.sol";
contract pcArtCoin is ERC721{
// 合約擁有者
address public fundation;
// 資產結構體
struct asset{
uint256 _tokenId; // token ID
address owner; // token 擁有者地址
address approver; // token 被授權的地址
uint256 timestamp; // 時間戳
byte data; // token 中包含的資料
}
// 地址擁有的NFT數量
mapping(address => uint256) balances;
// NFT編號對應的資產
mapping(uint256 => asset) tokens;
// 授權
mapping(address => mapping(address => bool)) isAllProved;
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
// 設定資產
function setAssert(uint256 number, address owner, byte data) onlyFundation public{
require(owner != address(0));
// 生產隨機的token ID
uint256 tokenId = uint256(keccak256(abi.encodePacked(number, msg.sender, now, owner, data)));
// 保證token ID不同
require(tokens[tokenId]._tokenId != tokenId);
// 設定資產
asset memory Asset = asset(tokenId, owner, address(0), now, data);
tokens[tokenId] = Asset;
}
modifier onlyFundation(){
require(msg.sender == fundation);
_;
}
// 回傳_owner擁有NFT的數量
function balanceOf(address _owner) override external view returns (uint256){
require(_owner != address(0));
return balances[_owner];
}
// 回傳_tokenId的擁有者
function ownerOf(uint256 _tokenId) override external view returns (address){
require(_tokenId != 0);
return tokens[_tokenId].owner;
}
// 從_from轉到_to, NFT編號為_tokenId
function transferFrom(address _from, address _to, uint256 _tokenId) override external payable{
// 安全檢查
require(tokens[_tokenId].owner == _from);
require(_from != address(0) && _to != address(0) && _tokenId != 0);
require(msg.sender == _from || tokens[_tokenId].approver == msg.sender);
tokens[_tokenId].owner = _to;
tokens[_tokenId].approver = address(0);
tokens[_tokenId].timestamp = now;
tokens[_tokenId].data = byte("");
balances[_from] -= 1;
balances[_to] += 1;
emit Transfer(_from, _to, _tokenId);
}
function safeTransferFrom(address _from, address _to, uint256 _tokenId) override external payable{
require(tokens[_tokenId].approver == _from);
// 判斷_to不為合約地址
require(addrCheck(_to));
require(_from != address(0) && _to != address(0) && _tokenId != 0);
require(msg.sender == _from || tokens[_tokenId].approver == msg.sender);
tokens[_tokenId].owner = _from;
tokens[_tokenId].approver = address(0);
tokens[_tokenId].timestamp = now;
tokens[_tokenId].data = byte("");
balances[_from] -= 1;
balances[_to] += 1;
emit Transfer(_from, _to, _tokenId);
}
function safeTransferFrom(address _from, address _to, uint256 _tokenId, byte data) override external payable{
require(tokens[_tokenId].owner == _from);
require(addrCheck(_to));
require(_from != address(0) && _to != address(0) && _tokenId != 0);
require(msg.sender == _from || tokens[_tokenId].approver == msg.sender);
tokens[_tokenId].owner = _to;
tokens[_tokenId].approver = address(0);
tokens[_tokenId].timestamp = now;
tokens[_tokenId].data = data;
balances[_from] -= 1;
balances[_to] += 1;
emit Transfer(_from, _to, _tokenId);
}
function approve(address _approved, uint256 _tokenId) override external payable{
require(tokens[_tokenId].owner == msg.sender);
require(_tokenId != 0);
tokens[_tokenId].approver = _approved;
emit Approval(msg.sender, _approved, _tokenId);
}
// 向_operator 授權操作
function setApprovalForAll(address _operator, bool _approved) override external{
require(_operator != address(0));
require(isAllProved[msg.sender][_operator] != _approved);
isAllProved[msg.sender][_operator] = _approved;
emit ApprovalForAll(msg.sender, _operator, _approved);
}
// 獲取 _tokenId token的被授權人
function getApproved(uint256 _tokenId) override external view returns (address){
require(_tokenId != 0);
return tokens[_tokenId].approver;
}
function isApprovedForAll(address _owner, address _operator) override external view returns (bool){
require(_owner != address(0) || _operator != address(0));
return isAllProved[_owner][_operator];
}
// 判斷是否為合約地址,是回傳false,不是回傳true
function addrCheck(address _addr) private view returns (bool){
uint256 size;
assembly{
size := extcodesize(_addr)
}
require(size == 0);
return true;
}
}
最后
如果代碼有不足之處,歡迎評論區指出,另外推薦一個github地址,上面有許多區塊鏈學習資源及技術文章,同樣歡迎參觀,一起學習進步:https://github.com/mindcarver,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/299244.html
標籤:區塊鏈
