• 注册
  • 开发教程 开发教程 关注:22 内容:62

    技术教程 | 在MOAC公链上快速部署ERC-721智能合约

  • 查看作者
  • 打赏作者
  • 拉黑名单
    • 开发教程
    • 大版主

      本文基于moac公链,使用moac网页版工具部署ERC-721 合约,实现相关数字化各类功能操作。

      环境

      公链:MOAC-pangu0.8.2。

      节点版本:

      MOAC-pangu0.8.2-windows.exe。

      操作系统:Windows 10家庭版。

      一  安装并启动moac本地节点

      1、安装moac节点

      请参考文档《MOAC Windows版系统安装教程》

      2、启动moac节点

      打开命令终端(cmd),转到墨客当前目录,在命令行中执行:

      D:\moacPangu0.8.2-win>moac --rpc --rpccorsdomain "http://wallet.moac.io"

      备注:

      --rpc  启动RPC服务,本机访问节点

      --rpccorsdomain 启动RPC服务,非本机访问节点

      "http://wallet.moac.io" moac在线钱包网址,会自动连接到本机启动的moac节点并显示已有账号,如果本机节点没有启动,会显示以下提示信息。

      技术教程 | 在MOAC公链上快速部署ERC-721智能合约

      启动正常,会显示以下账号信息。确保其中一个账号有足够的moac以进行智能合约部署。

      技术教程 | 在MOAC公链上快速部署ERC-721智能合约

      二  编写并编译智能合约

      1、以下为基于erc-721编写的一个智能合约

      本文实际测试代码TestToken721.sol附在文章末尾。

      注意:该代码为测试实例使用,非标准部署智能合约代码。

       

      2、编译、部署合约

      在网页钱包点击“CONTRACTS”

      技术教程 | 在MOAC公链上快速部署ERC-721智能合约

      点击“DEPLOY NEW CONTRACT”

      技术教程 | 在MOAC公链上快速部署ERC-721智能合约

      选择一个有moac余额的账号

      技术教程 | 在MOAC公链上快速部署ERC-721智能合约

      把自己编写的智能合约代码放进代码区“Solidity contract source code”,该代码会自动进行编译,如果编译通过,右侧会显示"Select contract to deploy"。

      如果编译没有通过,则不会显示相应内容。

      技术教程 | 在MOAC公链上快速部署ERC-721智能合约

      在“Select contract to deploy”下拉框选择相应的token类型,本例为“Test Token”。

      在选择gas费用后,点击"DEPLOY"部署合约

      技术教程 | 在MOAC公链上快速部署ERC-721智能合约

      如果提示需要解锁(发送代币的)账户,

      进入moac命令行界面,输入命令:

       >personal.unlockAccount(mc.accounts[0], "passwd", 300)

      共有三个参数:

      第一个参数表示解锁的账户,

      第二个参数是该账户的密码,

      第三个参数是解锁时间,本例为300秒,300秒后会重新锁住账户;

      如果解锁时间设为0,表示一直解锁,此时账号有风险,慎用。

      为了隐藏密码,可以输入命令:

      >personal.unlockAccount(mc.accounts[0])

      回车后提示输入密码,此时密码不显示出来,该命令默认将账户解锁5分钟。

      成功解锁会返回true。

      此时会显示发布合约确认界面。

      注意:Data里必须有数据,否则不能正常部署

      技术教程 | 在MOAC公链上快速部署ERC-721智能合约

      一切正常,会开始部署合约,在界面下方显示进度条:

      技术教程 | 在MOAC公链上快速部署ERC-721智能合约

      进度条12区块确认,表示部署完毕。

      三  查询与交易

      1、查询合约状态

      点击部署完毕的合约进度条上的“Test Token (管理页面)”,进入合约管理界面。

      技术教程 | 在MOAC公链上快速部署ERC-721智能合约

      管理界面的上半部分显示基本信息,顶部是合约地址,右边有通用功能按钮。主要包括:接收墨客和token、浏览器查看、拷贝地址、二维码和显示接口。

      点击“浏览器查看”,会跳转到区块浏览器并自动显示合约查询结果界面。

      点击“显示接口”,跳出如下界面,显示“合约JSON接口”。提示如果有其他人需要管理或操作这个智能合约,则需要把接口内容连同合约地址一并发送给他。

      技术教程 | 在MOAC公链上快速部署ERC-721智能合约

      管理界面的下半部分显示合约自身功能。

      技术教程 | 在MOAC公链上快速部署ERC-721智能合约

      其中左边显示合约的读操作,本例中主要包括name、根据tokenID查询拥有者账户、根据账户查询余额等。

      右边为对合约的写操作,简单理解就是合约中的public函数。

      当前没有创建token,因此该合约中的721token数为0。

      2、创建第一个erc721数字资产

      本例中,创建token是一个写合约的操作,在右边select function下拉框选中“Create Token”,填入参数和拥有者地址,点击“EXECUTE”。

      技术教程 | 在MOAC公链上快速部署ERC-721智能合约

      界面提示“transaction send”。

      如果此处提示需要解锁账户,请参照前面的步骤执行解锁操作。

      写入区块后,就可以在读操作界面进行查询了。如下图所示:

      技术教程 | 在MOAC公链上快速部署ERC-721智能合约

      在index界面输入0,显示拥有该合约第一个721token(合约index编号从0开始,每次创建时,index编号自动递增)的地址。本例为主账户。

      在owner中输入一个账号,自动显示该账号当前拥有的token数量。

      3、交易erc721数字资产

      本例中,发送token是一个写合约的操作,在右边select function下拉框选中“Transfer”,填入接收地址和发送的index编号,选择发送账户,点击“EXECUTE”。如果该账户拥有该token,则会发送成功;如果该账户不拥有该token,此处的操作也没有报错信息,只是不会有交易真实发生。

      技术教程 | 在MOAC公链上快速部署ERC-721智能合约

      交易成功后,左边的合约读操作会自动更新。index编号为0的token有了新的拥有者,而之前的拥有者的token数量会自动减少1个,新的拥有者的数量会自动增加1个。

      技术教程 | 在MOAC公链上快速部署ERC-721智能合约

      在主界面,将显示你的所有账户及它们所拥有的数字资产。

      附件

      本文所用合约代码TestToken721.sol。

      注意:该代码为测试实例使用,非通用智能合约代码。

      pragma solidity ^0.4.16;

      contract ERC721Token {

        //Non-fungible Token,非同质代币,简称"NFTs"

        function balanceOf(address _owner) public constant returns (uint256 balance);

        

        function transfer(address _to, uint256 _token) public returns (bool success);

        

        function transferFrom(address _from, address _to, uint256 _token) public returns (bool success);

        function approve(address _spender, uint256 _token) public returns (bool success);

        function allowance(address _owner, address _spender) public constant returns (uint256 remaining);

        

        //返回当前被标记的_tokenId代币持有者的地址,该方法一定不会返回0

        function ownerOf(uint256 _tokenId) public returns (address owner);

        

        function tokensOfOwner(address _owner) public returns(uint256[] ownerTokens);

        

        //通过任意机制转移NFT所有权时该事件必须要被触发

        event Transfer(address indexed _from, address indexed _to, uint256 _token);

        

        event Approval(address indexed _owner, address indexed _spender, uint256 _token);

        

      }

      contract TokenDemo is ERC721Token {

        string  public name = "Test Token";    

        string  public symbol = "TEST";   

        uint8   public decimals = 0;

        uint256 public INITIAL_SUPPLY = 100 * (10 ** uint256(decimals));  

        

        address minter;

        mapping (address => uint256) balances;

        mapping (address => mapping (address => uint256)) allowed;

        //token的结构

        struct Token {       

          string property;     //属性

        }

        Token[] tokens;

        mapping (uint256 => address) public tokenIndexToOwner;

        mapping (address => uint256) ownershipTokenCount;

        mapping (uint256 => address) public tokenIndexToApproved;

        function TokenDemo() public {

        minter = msg.sender;

        }

        

        function getProperty(uint256 _tokenId) public returns (string property){

            return tokens[_tokenId].property;

        }

       

        function totalSupply() public returns (uint) {

            return tokens.length;

        }

        function ownerOf(uint256 _tokenId)  public returns (address owner) {

            owner = tokenIndexToOwner[_tokenId];

            require(owner != address(0));

        }

        function tokensOfOwner(address _owner) public returns(uint256[] ownerTokens) {

            uint256 tokenCount = balanceOf(_owner);

            if (tokenCount == 0) {

                return new uint256[](0);

            } else {

                uint256[] memory result = new uint256[](tokenCount);

                uint256 totalTokens = totalSupply();

                uint256 resultIndex = 0;

                uint256 tokenId;

                for (tokenId = 0; tokenId < totalTokens; tokenId++) {

                    if (tokenIndexToOwner[tokenId] == _owner) {

                        result[resultIndex] = tokenId;

                        resultIndex++;

                    }

                }

                return result;

            }

        }

        function _transfer(address _from, address _to, uint256 _tokenId) internal {

            ownershipTokenCount[_to]++;

            tokenIndexToOwner[_tokenId] = _to;

            if (_from != address(0)) {

                ownershipTokenCount[_from]--;

                delete tokenIndexToApproved[_tokenId];

            }

            // Emit the transfer event.

            Transfer(_from, _to, _tokenId);

        }

        function createToken(string _property, address _owner) public returns (uint) {    

       //只有部署账号能create token

       require(msg.sender == minter);      

        

          Token memory token = Token({

         property: _property

          });

          var newTokenId = tokens.push(token) - 1;

          require(newTokenId == uint256(uint32(newTokenId)));

          _transfer(0, _owner, newTokenId);

          return newTokenId;

        }

        function _owns(address _claimant, uint256 _tokenId) internal view returns (bool) {

            return tokenIndexToOwner[_tokenId] == _claimant;

        }

        function transfer(address _to, uint256 _tokenId) public returns (bool) {

          require(_to != address(0));

          require(_to != address(this));

          require(_owns(msg.sender, _tokenId));

          _transfer(msg.sender, _to, _tokenId);

        }

        function transferFrom(address _from, address _to, uint256 _tokenId) public returns (bool success) {

          require(_to != address(0));

          require(_to != address(this));

          require(_approvedFor(msg.sender, _tokenId));

          require(_owns(_from, _tokenId));

          _transfer(_from, _to, _tokenId);

        }

        function balanceOf(address _owner) public view returns (uint256 count) {

            return ownershipTokenCount[_owner];

        }

        function _approvedFor(address _claimant, uint256 _tokenId) internal view returns (bool) {

            return tokenIndexToApproved[_tokenId] == _claimant;

        }

        function _approve(uint256 _tokenId, address _approved) internal {

            tokenIndexToApproved[_tokenId] = _approved;

        }

        function approve(address _to, uint256 _tokenId) public returns (bool success) {

          require(_owns(msg.sender, _tokenId));

          _approve(_tokenId, _to);

          Approval(msg.sender, _to, _tokenId);

        }

        function allowance(address _owner, address _spender) public constant returns (uint256 remaining) {

          return allowed[_owner][_spender];

        }

      }

      请登录之后再进行评论

      登录
    • 做任务
    • 实时动态
    • 偏好设置
    • 返回顶部
    • 帖子间隔 侧栏位置: