ERC20与ERC721标准及案例

ERC20与ERC721标准及案例,第1张

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) 可选单元: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) 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); 可选单元 描述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); 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://outofmemory.cn/zaji/1498773.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-25
下一篇 2022-06-25

发表评论

登录后才能评论

评论列表(0条)

保存