card-battle
项目的建立
因为要使用 Sui TypeScript SDK,所以直接使用了模板
npm create @mysten/dapp
创建出的项目本身有 SDK 的引入,不用自己配置了 参考地址:https://sdk.mystenlabs.com/dapp-kit/create-dapp 项目参考地址:https://github.com/ppnnssy/cardbattle-solidity
项目中关于 Sui TypeScript SDK 的使用
依赖安装:
npm i @mysten/sui.js
项目中有 src/context/networkConfig.ts 文件,这个文件本来是打算全局提供 networkConfig 句柄的,后来发现每个页面直接创造一个 client 对象更加稳定方便
const client = new SuiClient({ url: getFullnodeUrl("testnet") });
在 SDK 中功能有很多,这里 记录一下项目中用到的一些:
连接钱包
直接使用 SDK 中提供的组件
import { ConnectButton } from "@mysten/dapp-kit";
简单的使用组件,甚至不需要传入任何参数
获取当前账户
import { useCurrentAccount } from "@mysten/dapp-kit";
这是个钩子函数
const myAccount = useCurrentAccount();
获取对象信息
根据对象 id 获取对象信息。这是使用了封装好的钩子函数 useSuiClientQuery
const { data, isPending, error, refetch } = useSuiClientQuery("getObject", {
id: battleId ? battleId : "",
options: {
showContent: true,
showOwner: true,
},
});
同时获取多个对象,也是一个钩子函数
let { data: gameData } = useSuiClientQueries({
// queries参数应该是一个数组,数组中的元素是一个对象
queries: isPending
? []
: (battleData as any)?.data.content.fields.battles.map((val: any) => {
return {
method: "getObject",
params: {
id: val,
options: {
showContent: true,
showOwner: true,
},
},
};
}),
// 请求回来的数据可以在combine函数中过滤
combine: (result) => {
return {
// 过滤掉其他状态,只保留待开始的
data: result
.map((res, idx) => {
console.log("====================================");
console.log(res);
console.log("====================================");
let status = (res as any)?.data?.data?.content.fields.status;
if (status == 0 || status == 1 || status == 2) {
return {
key: idx,
battleId: (res as any)?.data.data.objectId,
battleName: (res as any)?.data.data.content.fields.name,
players: (res as any)?.data.data.content.fields.players,
status: (res as any)?.data.data.content.fields.status,
};
}
})
.filter((item2) => item2 !== undefined),
isSuccess: result.every((res) => res.isSuccess),
isPending: result.some((res) => res.isPending),
isError: result.some((res) => res.isError),
};
},
});
普通函数获取对象
client.getObject({
id: objId,
options: {
showContent: true,
showOwner: true,
},
});
普通函数获取多个对象
client.multiGetObjects({
ids,
options: {
showContent: true,
showOwner: true,
},
});
根据账号获取名下资产
client.getOwnedObjects({
owner: account?.address,
filter: {
MatchAll: [
{
StructType: `${TESTNET_CARD_PACKAGE_ID}::card::Card`,
},
],
},
});
获取动态字段对象
Move 合约中有些对象是动态字段,参考https://docs.sui.io/concepts/dynamic-fields 想要获取动态字段对象,靠上面的函数是不行的,需要以下函数
client.getDynamicFields({
parentId: id,
});
parentId 就是想要获取的对象 id
调用合约函数
引入依赖
import { TransactionBlock } from "@mysten/sui.js/transactions";
import { useSignAndExecuteTransactionBlock } from "@mysten/dapp-kit";
获取发送交易的函数。useSignAndExecuteTransactionBlock 是钩子函数,只能在组件中 使用
const { mutate: signAndExecute } = useSignAndExecuteTransactionBlock();
构造交易块 构造交易块的时候要注意,arguments 是合约函数参数。如果需要传入 number,string 等类型的参数,需要用 txb.pure.类型(实际参数)先转换格式
const txb = new TransactionBlock();
txb.moveCall({
arguments: [txb.object(CARD_RECORD), txb.object("0x6")],
target: `${TESTNET_CARD_PACKAGE_ID}::card::create_card`,
});
发送交易
signAndExecute(
{
transactionBlock: txb,
options: {
showEffects: true,
showObjectChanges: true,
},
},
{
onSuccess: (tx) => {
console.log("🚀 ~ handleJoin ~ tx:", tx);
},
onError: (err) => {
console.log("🚀 ~ handleJoin ~ tx:", err);
},
},
);
监听事件
事件监听还没有完全做好,有 bug 不能使用,暂时先放一下代码 官方文档有问题 事件监听需要特殊的 client.这是 SDK 开发不完善,可能在后续版本中会修复
let client = new SuiClient({
transport: new SuiHTTPTransport({
url: getFullnodeUrl("testnet"),
WebSocketConstructor: window.WebSocket,//这一行不加会出错
}),
});
订阅事件
const unsubscribe = await client.subscribeEvent({
filter: {
// Package:
// "0xfe0deaecbfe19fd2beeb085e634b0086e78123f9283257fda35c1226c9ab8fa7",
// MoveEventType: `${TESTNET_CARD_PACKAGE_ID}::card::MoveChoice`,
MoveEventType: `${TESTNET_CARD_PACKAGE_ID}::card::MoveChoice`,
},
onMessage(event) {
console.log("🚀 ~ onMessage ~ event:", event);
refetch();
// handle subscription notification message here. This function is called once per subscription message.
},
});
解绑事件
unsubscribe()
