上一節(jié)我們創(chuàng)建了錢包,并領(lǐng)取了免費(fèi)的NAS铁孵,現(xiàn)在我們來(lái)到DApp化的核心步驟——?jiǎng)?chuàng)建合約锭硼。
編寫合約
星云鏈的合約需要用javascript或Typescript編寫,一個(gè)合約定義了一個(gè)javascript對(duì)象的構(gòu)造函數(shù)蜕劝,構(gòu)造函數(shù)里定義了對(duì)象所具有的方法檀头。
對(duì)于應(yīng)用開(kāi)發(fā)者,每一個(gè)方法就是一個(gè)和星云鏈交互的接口岖沛,合約要定義什么樣的方法是由應(yīng)用的需求決定的暑始,也就在在第一節(jié)一、一個(gè)普通App里面提到的婴削,設(shè)計(jì)應(yīng)用之初廊镜,應(yīng)該考慮需要在星云鏈存儲(chǔ)或者獲取什么數(shù)據(jù)。
智能合約例子
這里我們用一個(gè)例子來(lái)看一個(gè)合約包括哪些智能合約-SmartContract
"use strict";
var DepositeContent = function (text) {
if (text) {
var o = JSON.parse(text);
this.balance = new BigNumber(o.balance);
this.expiryHeight = new BigNumber(o.expiryHeight);
} else {
this.balance = new BigNumber(0);
this.expiryHeight = new BigNumber(0);
}
};
DepositeContent.prototype = {
toString: function () {
return JSON.stringify(this);
}
};
var BankVaultContract = function () {
LocalContractStorage.defineMapProperty(this, "bankVault", {
parse: function (text) {
return new DepositeContent(text);
},
stringify: function (o) {
return o.toString();
}
});
};
// save value to contract, only after height of block, users can takeout
BankVaultContract.prototype = {
init: function () {
//TODO:
},
save: function (height) {
var from = Blockchain.transaction.from;
var value = Blockchain.transaction.value;
var bk_height = new BigNumber(Blockchain.block.height);
var orig_deposit = this.bankVault.get(from);
if (orig_deposit) {
value = value.plus(orig_deposit.balance);
}
var deposit = new DepositeContent();
deposit.balance = value;
deposit.expiryHeight = bk_height.plus(height);
this.bankVault.put(from, deposit);
},
takeout: function (value) {
var from = Blockchain.transaction.from;
var bk_height = new BigNumber(Blockchain.block.height);
var amount = new BigNumber(value);
var deposit = this.bankVault.get(from);
if (!deposit) {
throw new Error("No deposit before.");
}
if (bk_height.lt(deposit.expiryHeight)) {
throw new Error("Can not takeout before expiryHeight.");
}
if (amount.gt(deposit.balance)) {
throw new Error("Insufficient balance.");
}
var result = Blockchain.transfer(from, amount);
if (!result) {
throw new Error("transfer failed.");
}
Event.Trigger("BankVault", {
Transfer: {
from: Blockchain.transaction.to,
to: from,
value: amount.toString()
}
});
deposit.balance = deposit.balance.sub(amount);
this.bankVault.put(from, deposit);
},
balanceOf: function () {
var from = Blockchain.transaction.from;
return this.bankVault.get(from);
},
verifyAddress: function (address) {
// 1-valid, 0-invalid
var result = Blockchain.verifyAddress(address);
return {
valid: result == 0 ? false : true
};
}
};
module.exports = BankVaultContract;
這份智能合約定義了5個(gè)接口唉俗。
init接口是一個(gè)合約必須要有的方法嗤朴。
save, takeout, balanceOf, verifyAddress 分別是存錢,轉(zhuǎn)賬虫溜,查詢合約余額雹姊,校驗(yàn)合約地址。
星云鏈庫(kù)簡(jiǎn)介
合約中用到星云鏈提供的一些庫(kù):
LocalContractStorage
用來(lái)支持星云鏈上的數(shù)據(jù)持久化存儲(chǔ)衡楞。這是一個(gè)鍵值存儲(chǔ)系統(tǒng)容为,可存儲(chǔ)的數(shù)據(jù)類型包括數(shù)字、字符串和 JavaScript 對(duì)象(需要序列化為字符串)。
LocalContractStorage 支持三個(gè)操作:set坎背、get/put和 del替劈,分別實(shí)現(xiàn)存儲(chǔ)、讀取和刪除數(shù)據(jù)功能得滤。
LocalContractStorage 還支持綁定以下兩類鏈上存儲(chǔ)空間到合約屬性上:?jiǎn)沃殿愋停╯torage property)和Map類型(storage map)陨献。上面的智能合約就綁定了Map類型存儲(chǔ)空間。Blockchain
Blockchain 模塊用來(lái)獲取當(dāng)前正在執(zhí)行的合約內(nèi)的交易和區(qū)塊信息和一些方法
Blockchain 有兩個(gè)屬性:
1懂更、block 執(zhí)行合約的當(dāng)前區(qū)塊眨业,它具有下列屬性:
— timestamp 區(qū)塊時(shí)間戳
— height 區(qū)塊高度
2、transaction 執(zhí)行合約的當(dāng)前交易沮协,它具有下列屬性:
— hash 交易哈希值
— from 交易源地址
— to 交易目的地址龄捡,對(duì)于合約調(diào)用就是合約地址
— value 交易數(shù)值,字符串慷暂, 合約內(nèi)用BigNumber存儲(chǔ)計(jì)算
— nonce 交易的 nonce 值
— timestamp 交易時(shí)間戳
— gasPrice 交易的 gasPrice聘殖,字符串,合約內(nèi)用 BigNumber 存儲(chǔ)計(jì)算
— gasLimit 交易的 gasLimit行瑞,字符串奸腺,合約內(nèi)用 BigNumber 存儲(chǔ)計(jì)算
Blockchain 還提供了兩個(gè)方法:
1、transfer(address, value) 將 NAS 從合約轉(zhuǎn)出到address對(duì)應(yīng)的賬戶血久。
· 參數(shù) address:接收 NAS 的 Nebulas 賬戶地址
· 參數(shù) value:轉(zhuǎn)移數(shù)值突照,一個(gè) BigNumber 對(duì)象
返回:0 – 轉(zhuǎn)移成功,1 – 轉(zhuǎn)移失敗
2氧吐、verifyAddress(address) 驗(yàn)證參數(shù) address 是否為一個(gè)有效的 Nebulas 地址讹蘑。
返回:1 – 地址有效,0 – 地址無(wú)效
請(qǐng)參照智能合約的例子編寫自己的合約筑舅。
部署合約
編寫完自己的合約座慰,就可以部署到星云鏈上來(lái)調(diào)用了。
打開(kāi)二豁翎、創(chuàng)建錢包里下載的星云錢包的主頁(yè)web-wallet/index.html角骤,打開(kāi)Contract頁(yè)隅忿,選擇Deploy頁(yè)面
在code里面粘貼整個(gè)合約的源代碼心剥,語(yǔ)言選擇Javascript,arguments留白背桐,選擇錢包keystore文件并輸入錢包密碼优烧,點(diǎn)擊unlock解鎖錢包信息。
From Address和To Address都自動(dòng)填充為錢包地址链峭,Balance顯示的是錢包余額畦娄,點(diǎn)擊Test
顯示這樣的結(jié)果表示合約沒(méi)有問(wèn)題,點(diǎn)擊Submit就正式部署合約。
txhash是合約哈希熙卡,contract_address是合約地址杖刷,保存好這兩個(gè)值。
此時(shí)合約部署成功驳癌。
調(diào)用合約
點(diǎn)擊Call來(lái)到合約調(diào)用頁(yè)面滑燃,此頁(yè)面供開(kāi)發(fā)者測(cè)試合約中的方法,建議在應(yīng)用中調(diào)用合約之前都在此先測(cè)試合約方法颓鲜。
function: 要調(diào)用的合約的方法表窘,如智能合約中的 save, takeout, balanceOf。
arguments: 調(diào)用的方法的參數(shù)甜滨,如智能合約中save方法乐严,需要參數(shù)[‘1000’],如果方法不需要參數(shù)衣摩,則不填寫昂验。
From Address: 錢包地址
To Address: 合約地址,此處需要注意昭娩。
下面測(cè)試智能合約中的balanceOf方法
點(diǎn)擊Test凛篙,返回結(jié)果中result為null,對(duì)于新創(chuàng)建的合約栏渺,還沒(méi)有在合約地址中存入任何數(shù)據(jù)呛梆,所以查詢到的結(jié)果為null。
我們嘗試先調(diào)用save存入數(shù)據(jù)磕诊。
Value/Amount to Send這里的單位是NAS, 所以對(duì)于NAS不多的同學(xué)來(lái)說(shuō)填物,這里一定要填小一點(diǎn)的數(shù)比如0.000000000000000001或者直接0(如果你的交易數(shù)據(jù)不是Value/Amount的話),開(kāi)源節(jié)流嘛霎终,如果你的Value/Amount大于你的錢包余額滞磺,調(diào)用會(huì)出現(xiàn)NAS不足的錯(cuò)誤。
先單擊Test測(cè)試合約調(diào)用是否正常
以上結(jié)果說(shuō)明合約調(diào)用正常莱褒,再點(diǎn)擊Submit提交交易击困,數(shù)據(jù)才會(huì)真正的存儲(chǔ)到星云鏈。每個(gè)交易會(huì)返回txhash, 可以在Check TX Status查看交易的狀態(tài)广凸,只有狀態(tài)為Success阅茶,交易才被存儲(chǔ)到了鏈上。
然后我們?cè)俅握{(diào)用banlanceOf接口谅海,可以看到我們調(diào)用save接口存儲(chǔ)在星云鏈上的數(shù)據(jù)脸哀。
合約部署并測(cè)試成功了,就可以將我們的應(yīng)用DApp化了四扭吁、DApp化
如果你覺(jué)得本教程對(duì)你有用撞蜂,請(qǐng)使用本邀請(qǐng)鏈接注冊(cè)星云鏈星云鏈注冊(cè)入口盲镶,謝謝!