主页 > imtoken有usdt钱包地址吗 > 以太坊代币系列的非同质化代币ERC721

以太坊代币系列的非同质化代币ERC721

imtoken有usdt钱包地址吗 2023-12-08 05:11:51

0x00写在前面

2013年7月,一个名为MasterCoin的项目通过数字货币论坛Bitcointalk筹集了5000多枚比特币,从而开启了区块链行业新一轮的众筹。 后来跃升至数字货币市值榜单第二位的以太坊网络,在主网上线后推出了发行代币的功能。 而这一特性更是将区块链行业的募资推向了一个高峰。

为了更快地发行代币,以太坊社区制定了代币标准规范ERC20,直接将代币发行时间缩短到10分钟以内。

最近火热的猫狗游戏,本质上就是基于以太坊网络的代币。 每只猫或狗都是以太坊上的一个代币,每个代币都是独一无二的,无法交换。 改变。 而这种代币极受社区看好,所以社区制定了非同质化代币的标准。 这个标准就是我们今天说的ERC721。

与ERC20相比,ERC721具有更大的想象空间。 由于其独特的属性,每一个代币都是独一无二的,不仅是虚拟资产,现实生活中的汽车、房子也是如此。 当资产可以被证明时,我们就可以实现资产的上链。

0x01 ERC721标准制定动机

为了让任何人都可以在以太坊上发行ERC721等非同质代币,并让钱包/拍卖应用/交易所等应用能够快速方便地接入此类非同质代币以太坊链可以转erc20吗,以太坊社区制定了ERC721代币标准。

ERC721代币称为非同质代币,应该是不可替代的代币,简称NFT。

0x02 ERC721标准规范

在ERC721规范中,为了让代币非同质化,每一个NFT都有一个唯一的ID,ID在智能合约中是不可变的,这个NFT将能够标记现实中的一种资产,包括房子,汽车,收藏品, ETC。

在ERC20代币中,每个代币的转账都是一样的,并且可以拆分代币,最多支持18位小数,而在ERC721中,每个代币不能拆分,一个代币就是一个资产,所有的转账和兑换都是交易所一个标记,因为当映射到现实时,我们的房子和汽车不能分成很多份。

我们在转ERC20代币的时候,只需要标注我们转的数量,不需要具体说明我转的是我的100个代币中的哪一个,因为它们是同质代币,转哪一个的价值是一样的的。 在ERC721中,我们每次转账token时,都需要指定转账token的ID,因为每个token代表着不同的数字资产,或者现实中映射的某种实物资产。

每个实现 ERC721 标准代币的合约都需要满足以下方法:

A.方法Method1,balanceOf()获取balance函数的原型

  1. function balanceOf(address _owner) external view returns (uint256);

该方法获取_owner地址的余额,external修饰符表示该方法只能在合约外访问。

2. ownerOf() 获取token的owner函数原型

  1. function ownerOf(uint256 _tokenId) external view returns (address);

该方法获取具有指定 _tokenId 的令牌的所有者,该令牌只能在合约之外访问。

因为ERC721代币有自己的唯一标识,我们可以通过唯一标识识别代币的拥有者,而ERC20做不到这一点,这也说明ERC721可以用来确权。

3. transferFrom()转账token函数原型

  1. function transferFrom(address _from, address _to, uint256 _tokenId) external payable;

该方法将 _tokenId 令牌从 _from 地址传输到 _to 地址。

要以 ERC721 转账,您必须标记您要转账的代币的唯一 ID。

4. safeTransferFrom() 安全转账令牌函数原型

  1. function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;

该方法将 _tokenId 令牌从 _from 地址传输到 _to 地址。

5. approve()授权token操作权函数原型

  1. function approve(address _approved, uint256 _tokenId) external payable;

该方法授权批准_approved地址有权操作_tokenId token。

授权人必须是_tokenId token 的拥有者或者是被批准拥有token 操作权限的地址。

6. setApprovalForAll() 设置代币操作权函数原型

  1. function setApprovalForAll(address _operator, bool _approved) external;

该方法授权并批准添加或删除_operator 成为所有代币的操作者。 合约必须支持代币存在多个运营商。

7、getApproved()获取审批人函数原型

  1. function getApproved(uint256 _tokenId) external view returns (address);

获取 _tokenId 令牌的授权操作员的方法

8、isApprovedForAll()是否为授权函数原型

  1. function isApprovedForAll(address _owner, address _operator) external view returns (bool);

判断_operator是否被_owner授权为所有token的操作者的方法

B. EventEvent1、Transfer() 传输事件事件原型

  1. event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);

事件 当令牌被转移时触发该事件。

2.Approval()授权事件事件原型

  1. event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId);

当使用单个令牌授权事件时,将触发此事件。

3、ApprovalForAll()授权所有token事件事件原型

  1. event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);

调用事件 setApprovalForAll 方法时触发

0x03 ERC721标准接口

ERC721代币合约实现时,必须实现ERC721接口和ERC165接口。 以下是接口:

  1. pragma solidity ^0.4.20;

  2. interface ERC721 {

  3.    // 转移事件,记录转出,转入,以及被转移代币的ID

  4.    event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);

  5.    // 授权,记录授权者,被授权者,被授权代币ID

  6.    event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId);

  7.    // 授权所有代币,记录授权者,被授权者

  8.    event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);

  9.    // 获取代币余额

  10.    // @params address _owner 代币所有者

  11.    // @return uint256 返回数量

  12.    function balanceOf(address _owner) external view returns (uint256);

  13.    // 获取nft代币所有者

  14.    // @params uint256 _tokenId 代币ID

  15.    // @return address 拥有者地址

  16.    function ownerOf(uint256 _tokenId) external view returns (address);

  17.    // 安全转移代币

  18.    // @params address _from 发送人地址

  19.    // @params address _to 收款人地址

  20.    // @params uint256 _tokenId 代币ID

  21.    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;

  22.    // 转移代币

  23.    // @params address _from 发送人地址

  24.    // @params address _to 收款人地址

  25.    // @params uint256 _tokenId 代币ID

  26.    function transferFrom(address _from, address _to, uint256 _tokenId) external payable;

  27.    // 授权

  28.    // @params address _approved 被授权人

  29.    // @params uint256 _tokenId 代币ID

  30.    function approve(address _approved, uint256 _tokenId) external payable;

  31.    // 授权加入或者移除所有运营权

  32.    // @params address _approved 被授权人

  33.    // @params bool _approved 加入或删除

  34.    function setApprovalForAll(address _operator, bool _approved) external;

  35.    // 获取被授权人

  36.    // @params uint256 _tokenId 代币ID

  37.    // @return address 被授权地址

  38.    function getApproved(uint256 _tokenId) external view returns (address);

  39.    // 是否代币运营者

  40.    // @params address _owner 所有者

  41.    // @params address _operator 被授权者

  42.    // @return bool 是/否

  43.    function isApprovedForAll(address _owner, address _operator) external view returns (bool);

  44. }

  45. interface ERC165 {

  46.    // 查看是否支持该接口

  47.    // @params bytes4 interfaceID 接口ID

  48.    // 计算方式如:bytes4(keccak256('supportsInterface(bytes4)'))

  49.    function supportsInterface(bytes4 interfaceID) external view returns (bool);

  50. }

0x04 代码示例

以下为OpenZeppelin提供的代码示例,仅提供主要方法代码,完整版本代码可在附录中获取:

  1. pragma solidity ^0.4.18;

  2. /**

  3. * @title ERC721 Non-Fungible Token Standard basic implementation

  4. * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md

  5. */

  6. contract ERC721BasicToken {

  7.  // 等于 `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`

  8.  bytes4 constant ERC721_RECEIVED = 0xf0b9e5ba;

  9.  // 定义mapping 记录token的所有者

  10.  mapping (uint256 => address) internal tokenOwner;

  11.  // 记录指定token被授权人的地址

  12.  mapping (uint256 => address) internal tokenApprovals;

  13.  // 记录指定地址拥有多少个token

  14.  mapping (address => uint256) internal ownedTokensCount;

  15.  // 记录代币运营者

  16.  mapping (address => mapping (address => bool)) internal operatorApprovals;

  17.  // 修饰符,是否是 `_tokenId` 的所有者

  18.  modifier onlyOwnerOf(uint256 _tokenId) {

  19.    require(ownerOf(_tokenId) == msg.sender);

  20.    _;

  21.  }

  22.  // 修饰符 是否可以对该代币进行转账

  23.  modifier canTransfer(uint256 _tokenId) {

  24.    require(isApprovedOrOwner(msg.sender, _tokenId));

  25.    _;

  26.  }

  27.  // 获取代币余额

  28.  function balanceOf(address _owner) public view returns (uint256) {

  29.    require(_owner != address(0));

  30.    return ownedTokensCount[_owner];

  31.  }

  32.  // 代币持有人获取

  33.  function ownerOf(uint256 _tokenId) public view returns (address) {

  34.    address owner = tokenOwner[_tokenId];

  35.    require(owner != address(0));

  36.    return owner;

  37.  }

  38.  // 某个nft代币是否真实存在

  39.  function exists(uint256 _tokenId) public view returns (bool) {

  40.    address owner = tokenOwner[_tokenId];

  41.    return owner != address(0);

  42.  }

  43.  // 授权代币运营权

  44.  function approve(address _to, uint256 _tokenId) public {

  45.    address owner = ownerOf(_tokenId);

  46.    require(_to != owner);

  47.    require(msg.sender == owner || isApprovedForAll(owner, msg.sender));

  48.    if (getApproved(_tokenId) != address(0) || _to != address(0)) {

  49.      tokenApprovals[_tokenId] = _to;

  50.      Approval(owner, _to, _tokenId);

  51.    }

  52.  }

  53.  // 获取运营权归属者

  54.  function getApproved(uint256 _tokenId) public view returns (address) {

  55.    return tokenApprovals[_tokenId];

  56.  }

  57.  // 从运营列表中移除或者添加进列表

  58.  function setApprovalForAll(address _to, bool _approved) public {

  59.    require(_to != msg.sender);

  60.    operatorApprovals[msg.sender][_to] = _approved;

  61.    ApprovalForAll(msg.sender, _to, _approved);

  62.  }

  63.  // 判断是否是运营者

  64.  function isApprovedForAll(address _owner, address _operator) public view returns (bool) {

  65.    return operatorApprovals[_owner][_operator];

  66.  }

  67.  // 代币转移

  68.  function transferFrom(address _from, address _to, uint256 _tokenId) public canTransfer(_tokenId) {

  69.    require(_from != address(0));

  70.    require(_to != address(0));

  71.    clearApproval(_from, _tokenId);

  72.    removeTokenFrom(_from, _tokenId);

  73.    addTokenTo(_to, _tokenId);

  74.    Transfer(_from, _to, _tokenId);

  75.  }

  76.  // 安全转移

  77.  function safeTransferFrom(

  78.    address _from,

  79.    address _to,

  80.    uint256 _tokenId

  81.  )

  82.    public

  83.    canTransfer(_tokenId)

  84.  {

  85.    safeTransferFrom(_from, _to, _tokenId, "");

  86.  }

  87.  // 是否拥有代币的运营权

  88.  function isApprovedOrOwner(address _spender, uint256 _tokenId) internal view returns (bool) {

  89.    address owner = ownerOf(_tokenId);

  90.    return _spender == owner || getApproved(_tokenId) == _spender || isApprovedForAll(owner, _spender);

  91.  }

  92.  // 清除运营权

  93.  function clearApproval(address _owner, uint256 _tokenId) internal {

  94.    require(ownerOf(_tokenId) == _owner);

  95.    if (tokenApprovals[_tokenId] != address(0)) {

  96.      tokenApprovals[_tokenId] = address(0);

  97.      Approval(_owner, address(0), _tokenId);

  98.    }

  99.  }

  100.  // 添加一个代币

  101.  function addTokenTo(address _to, uint256 _tokenId) internal {

  102.    require(tokenOwner[_tokenId] == address(0));

  103.    tokenOwner[_tokenId] = _to;

  104.    ownedTokensCount[_to] = ownedTokensCount[_to].add(1);

  105.  }

  106.  // 移除一个代币

  107.  function removeTokenFrom(address _from, uint256 _tokenId) internal {

  108.    require(ownerOf(_tokenId) == _from);

  109.    ownedTokensCount[_from] = ownedTokensCount[_from].sub(1);

  110.    tokenOwner[_tokenId] = address(0);

  111.  }

  112.  // 是否是安全转移

  113.  // 能够接收ERC721代币的合约必须实现`onERC721Received`方法

  114.  // 通过判断是否存在该方法查看是否安全转移

  115.  function checkAndCallSafeTransfer(

  116.    address _from,

  117.    address _to,

  118.    uint256 _tokenId,

  119.    bytes _data

  120.  )

  121.    internal

  122.    returns (bool)

  123.  {

  124.    if (!_to.isContract()) {

  125.      return true;

  126.    }

  127.    bytes4 retval = ERC721Receiver(_to).onERC721Received(_from, _tokenId, _data);

  128.    return (retval == ERC721_RECEIVED);

  129.  }

  130. }

0x05 附录 A. 修饰符

在Solidity编程中,有一个概念叫做modifier以太坊链可以转erc20吗,英文是modify。 当一个修饰符被添加到一个方法中时,意味着该方法必须满足修饰符的要求。 例如,external 关键字是要求此方法只能由外部契约访问。

下面列出了上面提到的一些修饰符:

external 只允许外部合约调用这个方法

payable 只有标有该关键字的方法才能接收转账操作

b. 引用

ERC721草案

OpenZeppelin 完整实现 ERC721

喜欢就别说话,扫一扫~

以太坊搭建私链_sitesohu.com 以太坊公链私链_以太坊链可以转erc20吗