SUI 主网上线,前端开发者的 DApp 开发指南

前言作为和Aptos同期出名的Move语言生态双子星的Sui网络,在北京时间5月3日晚上8点,也已上线了主网。那么要进入Sui生态进行dapp的开发,要先记住一句话:万物皆是Object。为什么这么说呢?Sui借鉴了BTC的UTXO的模式,它将每个交易输出

<!--StartFragment-->

前言

作为和 Aptos 同期出名的 Move 语言生态双子星的 Sui 网络,在北京时间5月3日晚上8点,也已上线了主网。那么要进入 Sui 生态进行 dapp 的开发,要先记住一句话:万物皆是 Object

  • 为什么这么说呢?

Sui 借鉴了 BTC 的 UTXO 的模式,它将每个交易输出视为一个未使用的交易,使得交易的输入和输出可以更精细地控制和跟踪。

用更为直观的方式来解读,在链上,我的资产,也是一个个 Object 的模式。看下图:

<!--EndFragment-->

Screenshot (1).png <!--StartFragment-->

一个账号下可以有多种 Coin,每一种 Coin 都是由一个个的 Object 组成,所有这种 Coin 的 Object 的 balance 相加,就是账户下这种 Coin 的余额。

而 nft 作为非同质化代币,在 Sui 上的表现,也是一个 Object,只不过它是一种更为特殊的 Object。

<!--EndFragment--> <!--StartFragment-->

进入开发

连接钱包

1. 安装依赖

作为 dapp 开发,第一步势必是从连接插件钱包开始,这里我们使用 suiet 团队开发的库,相较于官方的,它对于其他钱包连接的支持更好

<!--EndFragment-->


yarn add @suiet/wallet-kit

<!--StartFragment-->

2. 引入 WalletProvider

在项目的根文件中,引入 WalletProvider(也就是在你 React 项目的根文件中,如果是 nextjs,则在 _app.tsx 中)

&lt;WalletProvider>
  &lt;Component {...pageProps} />
&lt;/WalletProvider>

<!--EndFragment--> <!--StartFragment-->

3. 在页面中连接钱包

  • 可以使用 Suiet 中自带的按钮 ConnectButton,点击后展开钱包列表

<!--EndFragment-->

import { ConnectButton } from '@suiet/wallet-kit'
//... 
&lt;ConnectButton />

Screenshot (1).png <!--StartFragment-->

  • 也可以根据需求,支持哪些钱包的连接

这里 select 的参数,现在可以使用有 SuietSui WalletEthos Wallet和 Martian Sui Wallet 这4种,分别对应4种钱包。其中 Sui Wallet 是官方钱包

<!--EndFragment-->

const { select } = useWallet() 
&lt;button onClick={() => select('Suiet')}>Connect wallet&lt;/button>

<!--StartFragment-->

4. 获取地址和连接状态

<!--EndFragment-->

const { address, connected } = useWallet()

<!--StartFragment-->

5. 签名(signMessage)

<!--EndFragment-->

import { ethers } from 'ethers'; 
// 这里借用 ethers 库来帮我们处理 message,将其转为 Uint8Array 类型 
const message = ethers.utils.toUtf8Bytes('test 123') 
const { signature, messageBytes } = await signMessage({ message })

<!--StartFragment-->

6. 发送交易

这里要注意一下,sui 的交易和之前的 aptos、evm 都有所区别

  • 普通交易,不涉及到自己的资产的

<!--EndFragment-->

import { TransactionBlock } from '@mysten/sui.js';
const { signAndExecuteTransactionBlock } = useWallet() 
const handleTransaction = async () => { 
const tx = new TransactionBlock() 
tx.moveCall({ target: \`${packageId}::${moduleName}::${functionName}\`, arguments: \[ tx.pure(参数1), tx.pure(参数2), ], typeArguments: \[], }) 
const result = await signAndExecuteTransactionBlock({ transactionBlock: tx, options: { showEffects: true }, }) console.log('result', result) // 通过result?.effects?.status?.status获取交易状态,成功为 'success',失败为'failure' } 
&lt;button onClick={handleTransaction}>Send Transaction&lt;/button>

<!--StartFragment-->

  • 涉及到资产交易的。

由于上文提到过 Sui 的核心:万物皆 object,在对资产进行交易时,需要传入作为费用的 objectId。

但这又会出现一个问题:如果我只有一个 object,我既要用这个 object 来作为交易费用,同时,我有需要一个 object 来支付这笔交易的 gasFee,那这交易应该怎么发呢?

这里就会引入一个新的概念:拆币(splitCoin)。也就是说,我需要发一笔交易,把一个 object 拆成了两个,一个足以支付交易费用,一个集合了剩余的 balance 的 object 来作为 gasFee。

例如:我的账户下当前只有一个 balance 为 0.5 的 object。我要发一笔交易,这个合约需要收 0.3 的费用。那么此时,我需要发送一笔拆币交易,将这个 0.5 的 object 拆出一个 0.3 的object,剩余部分作为一个 object 来作为 gasFee。

但如果每次交易都要分开发送两笔:拆币、调用合约,那太复杂了,这里我们将它们合并成一笔交易: <!--EndFragment-->

import { TransactionBlock } from '@mysten/sui.js'; 
const { signAndExecuteTransactionBlock } = useWallet() 
const handleTransaction = async () => { 
const tx = new TransactionBlock() const value = '300000000' // 这里是想要拆出的目标值 
const \[coins] = tx.splitCoins(tx.gas, \[ tx.pure(BigInt(value)), ]) 
tx.moveCall({ target: \`${packageId}::${moduleName}::${functionName}\`, arguments: \[ tx.pure(参数1), tx.pure(参数2), tx.makeMoveVec({ objects: \[coins] }), ], typeArguments: \[], }) const result = await signAndExecuteTransactionBlock({ transactionBlock: tx, options: { showEffects: true }, }) console.log('result', result) 
// 通过result?.effects?.status?.status获取交易状态,成功为 'success',失败为'failure' } 
&lt;button onClick={handleTransaction}>Send Transaction\&lt;/button>

<!--StartFragment-->

可以看到,这里的交易合并了 splitCoin 和 moveCall 两笔交易。为了确保所有人都能够正常交易,建议涉及到资产的交易,都加入 splitCoin

常用 rpc 方法

1. 创建 rpcProvider

<!--EndFragment-->

import { Connection, JsonRpcProvider } from '@mysten/sui.js'; 
const suiProvider = new JsonRpcProvider(new Connection({ fullnode: \`${节点rpc地址}\` }))

<!--StartFragment-->

2. 获取余额

<!--EndFragment-->

const { totalBalance } = await suiProvider.getBalance({ 
owner: \`${你的地址}\`, 
coinType: \`${币的类型地址}\` //如果不传,那么返回的就是 SUI 的 balance })

<!--StartFragment-->

3. 获取账户下的所有 object,注意:这里的 getOwnedObjects 是分页返回的

<!--EndFragment-->

const allObjects = await suiProvider.getOwnedObjects({ 
owner: address, 
options: { 
showType: true, 
showDisplay: true, 
showContent: true,
}
});

<!--StartFragment-->

4. 筛选账户下的 nft

<!--EndFragment-->

import { Coin } from '@mysten/sui.js'; 
const objectIDs = (allObjectRefs?.data || \[]) 
.filter((item) => !Coin.isCoin(item)) 
.map((anObj) => anObj.data.objectId);

<!--StartFragment-->

5. 模拟交易(调用合约的 public 的方法,也用这个)

<!--EndFragment-->

import { TransactionBlock, JsonRpcProvider, Connection } from '@mysten/sui.js'; 
const suiProvider = new JsonRpcProvider(new Connection({ fullnode: \`${节点rpc地址}\` })) 
const tx = new TransactionBlock() 
tx.moveCall({ 
target: \`${packageId}::${moduleName}::${functionName}\`, 
arguments: \[ tx.pure(参数1), tx.pure(参数2), ], typeArguments: \[], }) 
const result = await suiProvider.devInspectTransactionBlock({ 
transactionBlock: tx, sender: \`${地址}\` })

<!--StartFragment-->

总结

Sui 相对于 evm、aptos 生态,它是一种完全不同的链。不管是内部实现,还是对于 dapp 开发者来说,都是一种非常新奇的体验。

<!--EndFragment-->

Telegram:https://t.me/+P3Z7P_xQxbNlZWZl 来源:https://www.fabipingtai.com

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
加密女士
加密女士
无代码发币平台