Let's move - Sui Dapp counter计数器实现

  • stom698
  • 更新于 2024-03-28 16:23
  • 阅读 908

本文转自本人微信公众号的文章,所以带有wx水印,希望大家能理解一下。后续新文会自己留存不带水印。

Sui Dapp counter计数器实现

1.1使用template自动创建示例

#自动创建counter
pnpm create @mysten/dapp --template react-e2e-counter
#当前目录下会有counter目录
(base) root@DESKTOP-8UK78GU:~/sui_dappkit# ls
counter  hello_sui
(base) root@DESKTOP-8UK78GU:~/sui_dappkit# cd counter/
#安装依赖
pnpm add @mysten/sui.js @mysten/dapp-kit @tanstack/react-query

然后通过vscode打开

640_副本

将move.toml修改一下

[package]
name = "counter"
version = "0.0.1"
[dependencies]
Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "framework/mainnet" }
[addresses]
counter = "0x0

然后部署合约

sui client publish --gas-budget 100000000 --skip-dependency-verification
​
#package部分信息
│ Published Objects:                                                                               │
│  ┌──                                                                                             │
│  │ PackageID: 0xef7e9f18db243cd1391eb735c84e7293257682db11888b722510627a7ef42b93                 │
│  │ Version: 1                                                                                    │
│  │ Digest: GEBwAzQqMgTTtMsL2Zbt6QwUXjuq2Dtf9QCr6qxjqKmf                                          │
│  │ Modules: counter                                                                              │
│  └──                                                                                             │
​
#获取到PackageID
0xef7e9f18db243cd1391eb735c84e7293257682db11888b722510627a7ef42b93

1.2 修改模板中的前端代码

修改src/中的constant.ts文件,将packageid写入

export const DEVNET_COUNTER_PACKAGE_ID = "0xTODO";
export const MAINNET_COUNTER_PACKAGE_ID = "0xTODO";
export const TESTNET_COUNTER_PACKAGE_ID = "0xef7e9f18db243cd1391eb735c84e7293257682db11888b722510627a7ef42b93"

然后修改关于调用networkConfig.ts的其他文件内容(因为在前端交互的时候连接不到packageid,然后自己做了代码调整)。

CreateCounter.tsx,删除了networkConfig.ts的引用,直接用

TESTNET_COUNTER_PACKAGE_ID 作为代码中的packageid参数。

import { TransactionBlock } from "@mysten/sui.js/transactions";
import { Button, Container } from "@radix-ui/themes";
import {
  useSignAndExecuteTransactionBlock,
  useSuiClient,
} from "@mysten/dapp-kit";
import { TESTNET_COUNTER_PACKAGE_ID } from "./constants";
​
export function CreateCounter({
  onCreated,
}: {
  onCreated: (id: string) => void;
}) {
  const client = useSuiClient();
  const { mutate: signAndExecute } = useSignAndExecuteTransactionBlock();
​
  return (
    <Container>
      <Button
        size="3"
        onClick={() => {
          create();
        }}
      >
        Create Counter
      </Button>
    </Container>
  );
​
  function create() {
    const txb = new TransactionBlock();
​
    txb.moveCall({
      arguments: [],
      target: `${TESTNET_COUNTER_PACKAGE_ID}::counter::create`,
    });
​
    signAndExecute(
      {
        transactionBlock: txb,
        options: {
          showEffects: true,
          showObjectChanges: true,
        },
      },
      {
        onSuccess: (tx) => {
          client
            .waitForTransactionBlock({
              digest: tx.digest,
            })
            .then(() => {
              const objectId = tx.effects?.created?.[0]?.reference?.objectId;
​
              if (objectId) {
                onCreated(objectId);
              }
            });
        },
      },
    );
  }
}

Counter.tsx如上,删除了networkConfig.ts的引用。

import {
  useCurrentAccount,
  useSignAndExecuteTransactionBlock,
  useSuiClient,
  useSuiClientQuery,
} from "@mysten/dapp-kit";
import type { SuiObjectData } from "@mysten/sui.js/client";
import { TransactionBlock } from "@mysten/sui.js/transactions";
import { Button, Flex, Heading, Text } from "@radix-ui/themes";
import { TESTNET_COUNTER_PACKAGE_ID } from "./constants";
​
​
export function Counter({ id }: { id: string }) {
  const client = useSuiClient();
  const currentAccount = useCurrentAccount();
  const { mutate: signAndExecute } = useSignAndExecuteTransactionBlock();
  const { data, isPending, error, refetch } = useSuiClientQuery("getObject", {
    id,
    options: {
      showContent: true,
      showOwner: true,
    },
  });
​
  const executeMoveCall = (method: "increment" | "reset") => {
    const txb = new TransactionBlock();
​
    if (method === "reset") {
      txb.moveCall({
        arguments: [txb.object(id), txb.pure.u64(0)],
        target: `${TESTNET_COUNTER_PACKAGE_ID}::counter::set_value`,
      });
    } else {
      txb.moveCall({
        arguments: [txb.object(id)],
        target: `${TESTNET_COUNTER_PACKAGE_ID}::counter::increment`,
      });
    }
​
    signAndExecute(
      {
        transactionBlock: txb,
        options: {
          showEffects: true,
          showObjectChanges: true,
        },
      },
      {
        onSuccess: (tx) => {
          client.waitForTransactionBlock({ digest: tx.digest }).then(() => {
            refetch();
          });
        },
      },
    );
  };
​
  if (isPending) return <Text>Loading...</Text>;
​
  if (error) return <Text>Error: {error.message}</Text>;
​
  if (!data.data) return <Text>Not found</Text>;
​
  const ownedByCurrentAccount =
    getCounterFields(data.data)?.owner === currentAccount?.address;
​
  return (
    <>
      <Heading size="3">Counter {id}</Heading>
​
      <Flex direction="column" gap="2">
        <Text>Count: {getCounterFields(data.data)?.value}</Text>
        <Flex direction="row" gap="2">
          <Button onClick={() => executeMoveCall("increment")}>
            Increment
          </Button>
          {ownedByCurrentAccount ? (
            <Button onClick={() => executeMoveCall("reset")}>Reset</Button>
          ) : null}
        </Flex>
      </Flex>
    </>
  );
}
function getCounterFields(data: SuiObjectData) {
  if (data.content?.dataType !== "moveObject") {
    return null;
  }
​
  return data.content.fields as { value: number; owner: string };
}

然后修改main.tsx修改网络配置,使用getFullnodeUrl

import React from "react";
import ReactDOM from "react-dom/client";
import "@mysten/dapp-kit/dist/index.css";
import "@radix-ui/themes/styles.css";
​
import { SuiClientProvider, WalletProvider, createNetworkConfig } from "@mysten/dapp-kit";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { Theme } from "@radix-ui/themes";
import App from "./App.tsx";
import { getFullnodeUrl } from "@mysten/sui.js/client";
​
​
const queryClient = new QueryClient();
const { networkConfig } = createNetworkConfig({
  localnet: { url: getFullnodeUrl("localnet") },
  devnet: { url: getFullnodeUrl("devnet") },
  testnet: { url: getFullnodeUrl("testnet") },
  mainnet: { url: getFullnodeUrl("mainnet") },
});
​
ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <Theme appearance="light">
      <QueryClientProvider client={queryClient}>
        <SuiClientProvider networks={networkConfig} defaultNetwork="testnet">
          <WalletProvider autoConnect>
            <App />
          </WalletProvider>
        </SuiClientProvider>
      </QueryClientProvider>
    </Theme>
  </React.StrictMode>,
);

CTRL+鼠标左键选中getFullnodeUrl,修改一下getFullnodeUrl中的testnet的rpc端点

https://wallet-rpc.testnet.sui.io/

640 (1)_副本

然后就可以执行代码了

(base) root@DESKTOP-8UK78GU:~/sui_dappkit/counter# npm run dev
​
> counter@0.0.0 dev
> vite
​
​
  VITE v4.5.2  ready in 362 ms
​
  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h to show help
​

640 (2)_副本

点击连接钱包

640

选择需要连接的地址

img

然后就连接上了

img

如果需要切换钱包则需要在钱包处断开连接

img

然后点击Create Counter

img

然后就创建好了

img

点击Increment按钮

img

然后Count的值成功变为了1

img

再点击Reset按钮

img

Count的值重置为0了

img

1.3 合约解读

在合约的代码中调用create函数是value默认为0

    public fun create(ctx: &mut TxContext) {
        transfer::share_object(Counter {
            id: object::new(ctx),
            owner: tx_context::sender(ctx),
            value: 0
        })
    }

通过点击Increment按钮,调用increment时实现自增+1

    /// Increment a counter by 1.
    public fun increment(counter: &mut Counter) {
        counter.value = counter.value + 1;
    }

通过点击Reset按钮,调用set_value时实现数值修改,在下面的代码中reset的按钮默认往set_value中传入objectid和u64类型的整数0。

    if (method === "reset") {
      txb.moveCall({
        arguments: [txb.object(id), txb.pure.u64(0)],
        target: `${TESTNET_COUNTER_PACKAGE_ID}::counter::set_value`,
      });
    } else {
      txb.moveCall({
        arguments: [txb.object(id)],
        target: `${TESTNET_COUNTER_PACKAGE_ID}::counter::increment`,
      });
    }
​

当参数传入set_value,则将objectid中的value值等于传入的value值0,实现重置为0。

    /// Set value (only runnable by the Counter owner)
    public fun set_value(counter: &mut Counter, value: u64, ctx: &TxContext) {
        assert!(counter.owner == tx_context::sender(ctx), 0);
        counter.value = value;
    }

本文源码已上传github:

https://github.com/baicaiyihao/counter

Sui move_cn社交账号

telegram: https://t.me/move_cn

X(twitter): https://twitter.com/move_cn

QQ群: 79489587

微信公众号:Move中文

Sui中文开发群: https://t.me/sui_dev_cn

  • 原创
  • 学分: 2
  • 分类: Sui
  • 标签:
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。
5 订阅 9 篇文章

0 条评论

请先 登录 后评论
stom698
stom698
0x06CC...099B
努力提升