Ryan
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # 快速建立 Sui Move Dapp 並實現贊助交易 我們這次要在 Sui Move Dapp 實現贊助交易(Sponsored Transaction) Sui 現在有提供 很好用的快速建立 Dapp 的工具 (Sui Dapp Kit) [Sui TypeScript Docs](https://sdk.mystenlabs.com/dapp-kit/create-dapp) 所以這次我們要順便來練習在 VSCode 用 Sui Dapp Kit 快速建立 Dapp 來玩玩看 ## 1. 使用 Sui Dapp Kit 快速建立 Dapp 打開 VSCode 終端機,輸入下方指令 ```javascript npm create @mysten/dapp ``` 接下來會問你要執行那種Dapp模組 目前 Sui 提供 2種範本 react-client-dapp:一個基本的 React Dapp,用於取得連接的錢包擁有的物件清單。 react-e2e-counter:帶有 Move 程式碼和簡單計數器應用程式 UI 的端到端範例。 最後輸入專案名稱 sui-dapp-demo 這次我們會使用 react-client-dapp ```javascript PS D:\vscode\SideProject> npm create @mysten/dapp ? Which starter template would you like to use? ... > react-client-dapp React Client dApp that reads data from wallet and the blockchain √ Which starter template would you like to use? · react-client-dapp √ What is the name of your dApp? (this will be used as the directory name) · sui-dapp-demo ``` 接下來我們進入到 sui-dapp-demo 目錄,並 install 依賴項及 Run 起來試試看 ```javascript PS D:\vscode\SideProject> cd sui-dapp-demo PS D:\vscode\SideProject\sui-dapp-demo> npm install added 321 packages, and audited 322 packages in 44s found 0 vulnerabilities PS D:\vscode\SideProject\sui-dapp-demo> npm run dev > sui-dapp-demo@0.0.0 dev > vite VITE v4.5.3 ready in 363 ms ➜ Local: http://localhost:5173/ ➜ Network: use --host to expose ➜ press h to show help ``` ![image](https://hackmd.io/_uploads/HkZUCvobA.png) ## 2. 跟智能合約做互動,並使用贊助交易 如果還沒部署擲骰子的智能合約,可以先去參考之前實做的 [使用 Sui Move Random](https://hackmd.io/4oGEgONRRLSFfPIkv-xcNA?view) ```javascript= /// Module: dice_demo module dice_demo::dice_demo { use sui::random::{Self, Random}; // 骰子的物件,是一個 Shared Object public struct Dice has key, store { id: UID, value: u8 } // 部署合約時,初始化一個骰子物件,裡面value給0 // 並且變成一個Shared Object fun init(ctx: &mut sui::tx_context::TxContext) { let uid = object::new(ctx); let dice = Dice { id:uid, value:0 }; transfer::share_object(dice); } // 擲骰子,傳入參數為 // 1. Random物件(sui在devnet提供的0x8) // 2. Shared Object Dice 骰子物件 entry fun roll_dice(r: &Random, dice: &mut Dice, ctx: &mut TxContext) { // 建立一個新的 generator let mut generator = random::new_generator(r, ctx); // 產生一個 1~6 範圍的隨機數,並回傳u8值 let random_num = random::generate_u8_in_range(&mut generator, 1, 6); // 把隨機數存入 Shared Object Dice 骰子物件 dice.value = random_num; } } ``` 或是直接使用下方範例內的智能合約地址,但是因開發環境過一段時間,Sui會清除開發環境內的資料,所以有可能之後會找不到部署過的智能合約 這邊有已經做好的 Demo Code [Demo Code GitHub](https://github.com/ryan19910912/my-first-sui-dapp) 主要會修改 WalletStatus.tsx,以及新增一個 SponsoredTransaction.tsx 主要流程是 1. 產生一個贊助交易區塊,裡面需設定好交易執行者、Gas Owner等等資訊 2. 把這個贊助交易區塊給用戶做簽名,拿到用戶的簽名後,就執行這個贊助交易區塊,讓礦工驗證並上鏈 WalletStatus.tsx ```javascript= import { useCurrentAccount, useSignTransactionBlock } from "@mysten/dapp-kit"; import { Button, Container, Flex, Heading, Text } from "@radix-ui/themes"; import { OwnedObjects } from "./OwnedObjects"; import { getRollDiceSponsoredTransactionBlock, executeRollDiceSponsoredTransactionBlock } from "./SponsoredTransaction"; export function WalletStatus() { const account = useCurrentAccount(); const { mutate: signTransactionBlock } = useSignTransactionBlock(); return ( <Container my="2"> <Heading mb="2">Wallet Status</Heading> {account ? ( <Flex direction="column"> <Text>Wallet connected</Text> <Text>Address: {account.address}</Text> // 這邊新增贊助交易按鈕 <Button // 發送贊助交易 onClick={() => { // 取得 擲骰子贊助交易區塊 getRollDiceSponsoredTransactionBlock(account.address).then(txb => { if (txb) { // 發送交易區塊給用戶簽名 signTransactionBlock( { transactionBlock: txb, chain: 'sui:devnet', }, { onSuccess: (result) => { console.log('sign transaction block', result); // 成功後執行該贊助交易區塊,並進行上鏈 executeRollDiceSponsoredTransactionBlock(txb, result.signature, result.transactionBlockBytes); }, }, ); } else { alert("Get Roll Dice Transaction Block Fail"); } }); }} > Sign and execute transaction block </Button> </Flex> ) : ( <Text>Wallet not connected</Text> )} <OwnedObjects /> </Container> ); } ``` SponsoredTransaction.tsx ```javascript= import { TransactionBlock } from '@mysten/sui.js/transactions'; import { getFullnodeUrl, SuiClient } from '@mysten/sui.js/client'; import { Ed25519Keypair } from '@mysten/sui.js/keypairs/ed25519'; // 骰子 Shared Object ID const dice_shared_object_id = "0x9a1586f13af7fc4af8cb5978b12b769c8a260cf9409cf6c3d76761108adef4fe"; // 智能合約 Package ID const contract_package_id = "0x31599f857ee6721afa26ece8ab992ba51af7c732390900d3a4834908606be223"; // 智能合約 module 名稱 const contract_module_name = "dice_demo"; // 智能合約 呼叫方法 名稱 const contract_method_name = "roll_dice"; // Sui Devnet Random Object ID const sui_random_object_id = "0x8"; // 幫忙付 Gas Fee 的 Owner 地址 const gas_owner = "0xe20abce08a16e397ec368979b03bb6323d42605b38c6bd9b6a983c6ebcc45e11"; // 幫忙付 Gas Fee 的 Owner 註記詞 const word_list = import.meta.env.VITE_SPONSORED_WORD_LIST; const suiClient = new SuiClient({ url: getFullnodeUrl('devnet'), }); /** * 取得 呼叫擲骰子方法的 贊助交易區塊 * @param address // 用戶的錢包地址 * @returns */ export async function getRollDiceSponsoredTransactionBlock(address: string) { // 產生一個新的交易區塊 const sponsoredTxb = new TransactionBlock(); // 設定 交易者(用戶的錢包地址) sponsoredTxb.setSender(address); // 設定 支付 Gas Fee 的 Owner(贊助商地址) sponsoredTxb.setGasOwner(gas_owner); // 取得贊助商的錢包 Coin Data let coinData = await suiClient.getCoins({ owner: gas_owner, }); let coins = coinData.data; if (coins) { // 如果 Coin 存在 // 抓取第一個 Coin let coin = coins[0]; // Gas Payment 物件 let payment = { digest: coin.digest, objectId: coin.coinObjectId, version: coin.version }; // 設定 Gas Payment sponsoredTxb.setGasPayment([payment]); // 呼叫智能合約 擲骰子方法 sponsoredTxb.moveCall({ // target 要帶入 PageckId::moduleName::methodName // ex: 0x31599f857ee6721afa26ece8ab992ba51af7c732390900d3a4834908606be223::dice_demo::roll_dice target: `${contract_package_id}::${contract_module_name}::${contract_method_name}`, // 傳遞2個參數,第1個為 Sui Devnet上的Random Object ID (0x8),第2個為 骰子的Shared Object ID arguments: [sponsoredTxb.object(sui_random_object_id), sponsoredTxb.object(dice_shared_object_id)], }); // 回傳這個贊助交易區塊 return sponsoredTxb; } } /** * 執行 呼叫擲骰子方法的 贊助交易區塊 * @param txb // 由 getRollDiceSponsoredTransactionBlock 取得的贊助交易區塊 * @param userSignature // 用戶對交易區塊的簽名 * @param transactionBlockBytes // 用戶所簽名的交易區塊 Bytes */ export async function executeRollDiceSponsoredTransactionBlock(txb: TransactionBlock, userSignature: string, transactionBlockBytes: string) { // 取得 交易區塊的 Bytes let txBuild = await txb.build({ client: suiClient }); // 取得贊助商的密鑰 By 註記詞 let sponsoredKeypair = Ed25519Keypair.deriveKeypair(word_list); // 使用贊助商的密鑰 對 交易區塊 進行簽名,並產生簽章 let sponsoredKSign = await sponsoredKeypair.signTransactionBlock(txBuild); console.log("贊助商簽名 : "+ sponsoredKSign.signature); console.log("贊助商簽名交易區塊 : "+ sponsoredKSign.bytes); console.log("用戶簽名 : "+ userSignature); console.log("用戶簽名交易區塊 : "+ transactionBlockBytes); // 執行 贊助交易區塊 上鏈 suiClient.executeTransactionBlock({ // 贊助交易區塊 Bytes 字串 transactionBlock: transactionBlockBytes, // 簽名者 [用戶的簽名, 贊助商的簽名] signature: [userSignature, sponsoredKSign.signature], // 選項(可放可不放),可以顯示一些想要看的資料 options: { showEffects: true, showEvents: true, showObjectChanges: true }, }).then(result => { console.log(JSON.stringify(result)); }); } ``` ## 3. 執行贊助交易 首先,先查看 目前骰子 Shared Object (0x9a1586f13af7fc4af8cb5978b12b769c8a260cf9409cf6c3d76761108adef4fe) 裡面的數字目前是 5 https://suiscan.xyz/devnet/object/0x9a1586f13af7fc4af8cb5978b12b769c8a260cf9409cf6c3d76761108adef4fe ![image](https://hackmd.io/_uploads/rktyhus-C.png) 再來查看 贊助商 (0xe20abce08a16e397ec368979b03bb6323d42605b38c6bd9b6a983c6ebcc45e11) 目前的 Sui Coin 數量是 9.967479224 https://suiscan.xyz/devnet/account/0xe20abce08a16e397ec368979b03bb6323d42605b38c6bd9b6a983c6ebcc45e11 ![image](https://hackmd.io/_uploads/SkMm2_i-C.png) 接下來按下 發送贊助交易按鈕 ![image](https://hackmd.io/_uploads/rJ8Q6OsWA.png) 會看到執行交易的是 0x3f6d...a175 且扣除的Sui為 0.001022876,扣除的Owner是 0xe20a...5e11 也就是贊助商的錢包地址 這個 0x3f6d...a175 錢包裡面目前是沒有 Sui Coin的 ![image](https://hackmd.io/_uploads/SJbPT_iWA.png) 往下拉看他的Detail 可以看到 Sponsored 區塊 我付費 0 個 SUI,贊助商幫我付了 Gas Fee ![image](https://hackmd.io/_uploads/Hyq3TOo-R.png) 按下 Approve 後,我們可以在頁面的開發者工具視窗(F12)的Console看到下方這些資訊 ![image](https://hackmd.io/_uploads/ryIA1Ks-A.png) 這邊要注意,贊助商簽名的交易區塊跟用戶簽名的交易區塊,要一樣,代表他們是簽同個交易區塊,如果不一樣則會失敗 ## 驗證執行結果 當執行完後,首先我們去查看骰子Shared Object的值是否有變動 我們可以發現,從原先的 5 -> 4 https://suiscan.xyz/devnet/object/0x9a1586f13af7fc4af8cb5978b12b769c8a260cf9409cf6c3d76761108adef4fe ![image](https://hackmd.io/_uploads/rksultsbR.png) 我們也可以查看他的Transaction Blocks Details 可以看到 User Signature 跟 Sponsor Signature https://suiscan.xyz/devnet/tx/j4hE5XzzZDVxDaU5LG1WLWSMYbsankpU7kD3TAS8Fuv ![image](https://hackmd.io/_uploads/SyemYFibC.png) 接下來查看贊助商的 SUI Coin有無變少 從 9.967479224 -> 9.966456348 https://suiscan.xyz/devnet/account/0xe20abce08a16e397ec368979b03bb6323d42605b38c6bd9b6a983c6ebcc45e11 ![image](https://hackmd.io/_uploads/rkGcttjZC.png) 這次的 Sui Move Dapp 實現贊助交易就到這邊 可以好好利用這種贊助交易實現很多不同的商業邏輯 ## 參考資料 [Sui TypeScript Docs](https://sdk.mystenlabs.com/dapp-kit/create-dapp) [Sui TypeDoc](https://sdk.mystenlabs.com/typedoc/index.html) [Sui Sponsored Transactions GitHub](https://github.com/MystenLabs/sui/tree/main/dapps/sponsored-transactions)

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully