本文基于墨客區塊鏈(MOAC BlockChain),使用moac網頁版錢包部署ERC-721合約,實作相應數字化操作。
環境:
墨客區塊鏈版本:nvwa-vnode1.0.2.win.zip;
作業系統:64位Windows 10家庭版。
1.安裝并啟動本地節點
1.1 安裝moac節點
請參考檔案《第三篇 墨客區塊鏈(MOAC BlockChain)節點安裝教程》。
1.2 啟動moac節點
打開命令終端(cmd),轉到墨客當前目錄,在命令列中執行:
D:\nuwa1.0.2.win>moac --rpc --rpccorsdomain "http://wallet.moac.io"
備注:
--rpc 啟動RPC服務,本機訪問節點
--rpccorsdomain 啟動瀏覽器訪問服務,非本機訪問節點
"http://wallet.moac.io" moac在線錢包網址,會自動連接到本機啟動的moac節點并顯示已有賬號,如果本機節點沒有啟動,會顯示以下提示資訊。

啟動正常,會顯示以下賬號資訊。確保其中一個賬號有足夠的moac以進行智能合約部署。

2.撰寫并編譯智能合約
2.1 以下為基于erc-721撰寫的一個代幣合約
本文實際測驗代碼TestToken721.sol附在文章末尾。
注意:該代碼為測驗實體使用,非標準部署智能合約代碼。
2.2 編譯、部署合約
在網頁錢包點擊合約按鈕“CONTRACTS”

然后點擊部署新合約按鈕“DEPLOY NEW CONTRACT”
選擇一個有moac余額的賬號。

把自己撰寫的智能合約代碼放進代碼區“Solidity contract source code”,該代碼會自動進行編譯,如果編譯通過,右側會顯示"Select contract to deploy"。
如果編譯沒有通過,則不會顯示相應內容。

在“Select contract to deploy”下拉框選擇相應的token型別,本例為“Token Demo”。
在選擇gas費用后,點擊"DEPLOY"部署合約。此時會顯示發布合約確認界面。
如果提示需要解鎖(部署智能合約的)賬戶,進入moac命令列界面,輸入命令:
>personal.unlockAccount(mc.accounts[0], "passwd", 300)
該命令共有三個引數:
第一個引數表示解鎖的賬戶,
第二個引數是該賬戶的密碼,
第三個引數是解鎖時間,本例為300秒,300秒后會重新鎖住賬戶;
如果解鎖時間設為0,表示一直解鎖,此時賬號有風險,慎用。
為了隱藏密碼,可以輸入命令:
>personal.unlockAccount(mc.accounts[0])
回車后提示輸入密碼,此時密碼不顯示出來,該命令默認將賬戶解鎖300秒。
成功解鎖會回傳true。此時會顯示發布合約確認界面。

注意:Data里必須有資料,否則不能正常部署
點擊“OK”,開始部署合約,界面下方會顯示當前部署合約的進度條

進度條12區塊確認,表示部署完畢。
點擊成功部署的合約,可以看到基本內容,包括合約地址hash、被寫入的區塊號等。
登錄moac區塊鏈瀏覽器:http://explorer.moac.io/home。在tokens下拉框選擇“View ERC721”。

在搜索欄輸入合約地址,可以搜索到該合約的相應內容。

點擊進去,可以看到合約基本資訊、Token Transfers和Token Holders資訊。
注意:該步驟可能需要已經有交易才能在瀏覽器查詢。

至此,可以確認合約部署成功。
3.token的交易
3.1 查看合約狀態
點擊部署完畢的合約進度條上的“Token Demo (管理頁面)”,進入合約管理界面。

管理界面的上半部分顯示基本資訊,頂部是合約地址,右邊有通用功能按鈕。主要包括:接收墨客和token、瀏覽器查看、拷貝地址、二維碼和顯示介面。
點擊“顯示介面”,跳出如下界面,顯示“合約JSON介面”。提示如果有其他人需要管理或操作這個智能合約,則需要把介面內容連同合約地址一并發送給他。

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

其中左邊顯示合約的讀操作,本例中主要包括name、根據tokenID查詢擁有者賬戶、根據賬戶查詢余額等。
右邊為對合約的寫操作,簡單理解就是合約中的public函式。
本例中,當前沒有創建token,因此該合約中的721token數為0。
3.2 創建第一個erc721數字資產
本例中,創建token是一個寫合約的操作,在右邊select function下拉框選中“Create Token”,填入引數和擁有者地址,點擊“EXECUTE”。
此處的引數property就是資料結構里的內容,用戶可以根據自己的實際需要在合約里寫入多個欄位。

界面提示“transaction send”。
如果此處提示需要解鎖賬戶,請參照前面的步驟執行解鎖操作。
寫入區塊后,就可以在讀操作界面進行查詢了。如下圖所示:

上圖中,在index界面輸入0,顯示擁有該合約第一個721token(合約index編號從0開始,每次創建時,index編號自動遞增)的地址。本例為主賬戶。
在owner中輸入一個賬號,自動顯示該賬號當前擁有的token數量。
3.3 交易erc721數字資產
本例中,發送token是一個寫合約的操作,在右邊select function下拉框選中“Transfer”,填入接收地址和發送的index編號,選擇發送賬戶,點擊“EXECUTE”。如果該賬戶擁有該token,則會發送成功;如果該賬戶不擁有該token,此處的操作也沒有報錯資訊,只是不會有交易真實發生。

交易成功后,左邊的合約讀操作會自動更新。index編號為0的token有了新的擁有者,而之前的擁有者的token數量會自動減少1個,新的擁有者的數量會自動增加1個。

在主界面,將顯示你的所有賬戶及它們所擁有的數字資產。

至此,一個典型的ERC-721智能合約部署完成。
ERC-721智能合約可以與實際生活中的唯一性資產對應,有著廣闊的應用前景。
附件:
本文所用合約代碼TestToken721.sol。
注意:該代碼為測驗實體使用,非通用智能合約代碼。
pragma solidity ^0.4.16;
contract ERC721Token {
//Non-fungible Token
//與ERC20兼容的介面
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);
function ownerOf(uint256 _tokenId) public returns (address owner);
function tokensOfOwner(address _owner) public returns(uint256[] ownerTokens);
//元資料介面,可選
function tokenMetadata(uint256 _tokenId) public constant returns (string infoUrl);
//事件
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 structure
struct Token { //users can change structure for their dapp
string property;
}
Token[] tokens;
mapping (uint256 => address) public tokenIndexToOwner;
mapping (address => uint256) ownershipTokenCount;
mapping (uint256 => address) public tokenIndexToApproved;
mapping (uint256 => string) tokenLinks; //元資料,例如IPFS哈希或HTTP(S)鏈接
function TokenDemo() public {
minter = msg.sender;
}
//通證元資料介面
function tokenMetadata(uint256 _tokenId) public constant returns (string infoUrl){
return tokenLinks[_tokenId];
}
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];
}
Transfer(_from, _to, _tokenId); // Emit the transfer event
}
function createToken(string _property, address _owner) public returns (uint) {
require(msg.sender == minter); //only minter can create token
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];
}
}
---------------------
作者:Li_Yu_Qing
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/31814.html
標籤:區塊鏈技術
