This tutorial is about using MOAC Wallet online to deploy ERC-721 contracts and realize all kinds of functional operations related to digitalization based on MOAC Chain.

Operating environment: Public blockchain: MOAC-pangu0.8.2

Node version: MOAC-pangu0.8.2-windows.exe

Operating system: Windows 10 Home

1. Install and run moac node.js on localhost

1.1 Refer to How to Install MOAC for moac node.js installation:

Please visit https://github.com/caivega/MoacDocs/wiki/2、to access the tutorial.

1.2 Run a moac node.js

Open the command (cmd), shift to moac current directory, and execute in the command line:

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

Note:

— rpc: start RPC service and access to node.js on localhost

— rpccorsdomain: start RPC service and access to node.js on non-localhost

MOAC Wallet online URL (http://wallet.moac.io) automatically connects with moac node.js running on localhost and displays established accounts. If no node.js runs on localhost, you will be prompted for the following information.

If node.js runs successfully, you will see the account information below. Make sure one of the accounts has enough moac for smart contract deployment.

2. Create and compile a smart contract

2.1 Here is a smart contract created based on ERC-721.

The actual test code TestToken721.sol is attached to the end of this tutorial.

Note: The code is for testing purposes only. It is not a standard code to deploy smart contracts.

2.2 Compile and deploy a contract

Click “CONTRACTS” in Wallets

Click “DEPLOY NEW CONTRACT”

Select an account with moac balance

Put your own smart contract code into the code segment “SOLIDITY CONTRACT SOURCE CODE”, and it will automatically start compiling. If the compilation passes, “SELECT CONTRACT TO DEPLOY” will appear on the right.

Otherwise, there will be no such content.

Select the token type in the drop-down list “SELECT CONTRACT TO DEPLOY”. It is “Test Token” in this case.

After selecting gas fee, click “DEPLOY” to deploy the contract.

If prompted to unlock the account (the sending account), go to moac console and enter the command below to unlock the account:

>personal.unlockAccount(mc.accounts[0], “passwd”, 0)

You will return true when the account is unlocked.

Resend token and you will see the confirmation of the contract release.

Note: There must be data in Data segment; otherwise, the contract cannot be deployed.

If everything is okay, it will start to deploy contract. You can find the progress bar at the bottom of the interface.

When the progress bar displays 12 blocks have confirmed, it means contract deployment is completed.

3. Inquiry and transaction

3.1 Contract status inquiry

After the contract is deployed, click “Test Token (管理页面)” in the progress bar to enter the contract manager interface.

The upper half of the manager interface displays basic information, with the contract address on top and general function buttons on the right, including Transfer Mc & Tokens, View on Moacscan, Copy Address, Show QR Code, and Show Interface.

Click “View on Moacscan” and you will be redirected to a blockchain explorer, which automatically shows contract inquiry results.

Click “Show Interface” and you will have the following “Contract JSON Interface”. If you want to have someone else execute the contract, send him the interface content together with the contract address.

The lower half of the manager interface is about built-in functions of the contract.

Read operations are on the left, including name, owner’s account inquiry based on token ID, and balance inquiry based on account in this case.

The write operation on the right is basically about public functions in the contract.

With no token created for now, ERC-721 token in this contract is numbered 0.

3.2 Create the first ERC-721 digital asset

In this case, creating token is an action of writing to contract. Select “Create Token” in the drop-down list Select Function on the right, fill in parameters and owner’s address, and click “EXECUTE”.

The interface prompts “transaction send”.

If you are prompted to unlock the account, please refer to the aforementioned steps to execute unlocking.

After writing to blockchain, you can make inquiry on the read interface, as shown below:

Enter 0 on the index.html, and you can see the contract address of the first 721 token (The index number starts with 0. Every time a token is created, the number automatically increments). It is the Main Account in this case.

Enter an account in the owner box and the current number of tokens in this account is automatically displayed.

3.3 ERC-721 digital asset transaction

In this case, sending token is an action of writing to contract. Select “Transfer” in the drop-down list Select Function on the right, enter the receiving address and index number to be sent, select the sending account, and click “EXECUTE”. If the token is in the account, it will be sent successfully. Otherwise, this operation will not lead to debugging information, nor actual transaction.

With a successful transaction, read operations on the right automatically update. When a token with the index number of 0 is sent to a new owner, tokens held by the original owner automatically reduces by one in number and those held by the new owner automatically increases by one.

All your accounts and digital assets in them are shown on the main interface.

Attachment: This tutorial uses the contract code TestToken721.sol.

Note: The code is for testing purposes only. It is not a universal code for all smart contracts.

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];

}

}

Where to Find Us

Website: https://moac.io/

GitHub: https://github.com/MOACChain/moac-core

Twitter: https://twitter.com/moac_io

Reddit: https://www.reddit.com/r/MOAC/

Medium: https://medium.com/moac

Telegram(International): https://t.me/moacblockchain

Telegram(Developers): https://t.co/8m3m9RD5ix

Telegram(China): https://t.co/73rU9sHWLH