简介
Move是一种新的编程语言,为 Libra 区块链提供安全、可编程的基础。 Libra区块链中的帐户作为容器,包含了任意数量的Move资源和Move模块。 提交给 Libra 区块链的每个交易都使用 Move 编写的交易脚本来实现其逻辑。 交易脚本可以通过调用模块声明的过程(procedures)来更新区块链的全局状态。
最大的特色
以太坊, 以及其他几乎所有的系统(银行,支付宝,微信 ...),里面的货币都是数字表示,转账就是一个账户余额加,另一个账户余额减。这就存在很多可利用的漏洞,随意修改数值,造成各种损失。 而 Move 里面,实现了现实中的货币的概念,比如你有一张100元纸币,去买20块钱的东西,那么先要把100元换成50+20+20+10 4张纸币,然后用一张20元的纸币支付。这就是Move里面的货币的实现,每笔余额都是唯一object, 在支付前都需要先拆散成更小的面额。
本DEMO知识点
1. 消息 2. 权限 3. 货币的分割/合并 4. 共享object 5. 转账 6. 前端连接钱包 7. 前端调用合约
开发一个合约
我们选择Sui Chain, 来开发一个去中心化的聊天室合约。类似的Solidity的合约网上有不少。原理都是:用户发送一条消息,合约产出一个Event,WebApp 查询Events 和 监听消息。
定义一个消息,消息必须是 copy drop 的。
struct MessageSended has copy, drop {
sender: address,
message: String,
}
发送一个消息,只记录发送者address和内容message就好。
public entry fun send_msg(chatfee: &mut ChatFee, payment: &mut Coin<SUI>, msg_bytes: vector<u8>, ctx: &mut TxContext) {
let sender = tx_context::sender(ctx);
event::emit(MessageSended {
sender: sender,
message: string::utf8(msg_bytes)
});
}
光这样还是比较简陋,再加点东西,比如发一条消息收费 100 Sui , 使用 share_object 来实现。
struct OwnerCap has key { id: UID }
struct ChatFee has key {
id: UID,
fee: u64,
balance: Balance<SUI>
}
fun init(ctx: &mut TxContext) {
transfer::transfer(OwnerCap {id: object::new(ctx)}, tx_context::sender(ctx));
transfer::share_object(ChatFee {
id: object::new(ctx),
fee: 100,
balance: balance::zero()
});
}
最终合约里面堆积的余额来个提现,当然只能是合约owner才行,上面代码里面的 OwnerCap 就相当于 Solidity 里面的 OnlyOwner 一个意思,在 init 里面创建,transfer 给 合约创建人。后面的提现函数的第一个参数就是这个object,也就意味着只能owner 才能调用成功。
public entry fun collect_profits(_: &OwnerCap, chatfee: &mut ChatFee, ctx: &mut TxContext) {
let amount = balance::value(&chatfee.balance);
let profits = coin::take(&mut chatfee.balance, amount, ctx);
transfer::transfer(profits, tx_context::sender(ctx))
}
WebApp调用合约
第一步连接钱包,使用 suiet wallet react kit ,文档这里:Quick Start | Suiet Wallet Kit
root.render(
<React.StrictMode>
<WalletProvider defaultWallets={[
SuietWallet,
SuiWallet,
EthosWallet
]}>
<App />
</WalletProvider>
</React.StrictMode>
);
获取历史消息列表,使用 sui.js 请求 RPC API 获取
async function queryMsg() {
const msgs = [];
try {
const { data: events } = await provider.getEvents({
MoveModule: { package: ContractInfo.package, module: ContractInfo.module }
});
for (let i = 0; i < events.length; i++) {
const moveEvent = events[i].event.moveEvent;
if (!moveEvent) continue;
if (moveEvent.type != ContractInfo.eventType) continue;
msgs.unshift({
timestamp: events[i].timestamp,
sender: moveEvent.fields.sender,
message: moveEvent.fields.message
});
}
} catch (err) {
console.log(err)
}
return msgs;
}
调用插件钱包发送消息,合约里面写的,发消息是要收费100的,合约 send_msg 第二个参数 是 Sui Coin, 那么在这个web 发送代码里面,就是第二个参数 sui_id, 那么先要调用API 获取钱包用户的 sui coin 列表,在其中选择一个余额大于 100 的使用。
const resData = await wallet.signAndExecuteTransaction({
transaction: {
kind: 'moveCall',
data: {
packageObjectId: datalib.ContractInfo.package,
module: datalib.ContractInfo.module,
function: 'send_msg',
typeArguments: [],
arguments: [
datalib.ContractInfo.share,
sui_id,
msg,
],
gasBudget: 10000,
}
}
});
console.log('successfully:', resData);
至此演示完成:move 合约开发,web调用合约 的整个过程
完整源码:GitHub - kf702/suichat: sui chat, Move contract, react sui wallet
Web Demo URL: SuiChat