0基础从前端入门到Web3 —— 从测试网 a + b 到主网领Sui挑战

一:简介

本篇需要大家事先准备好 <math xmlns="http://www.w3.org/1998/Math/MathML"> T y p e S c r i p t \mathit {TypeScript} </math>TypeScript 最基础的环境(能简单运行跑出来 <math xmlns="http://www.w3.org/1998/Math/MathML"> H e l l o W o r l d \mathit {Hello\ World} </math>Hello World 就够了),然后一步一步带着大家完成调用 <math xmlns="http://www.w3.org/1998/Math/MathML"> S u i t e s t \mathit {Sui}\ \mathit {test} </math>Sui test 链上的 <math xmlns="http://www.w3.org/1998/Math/MathML"> a + b \mathit {a\ +\ b} </math>a + b 合约(该合约在前面的篇章当中部署,感兴趣的可以自行翻阅,如果后续本篇中用到的 <math xmlns="http://www.w3.org/1998/Math/MathML"> O b j e c t I D \mathit {ObjectID} </math>ObjectID 失效了,那应该是测试链重置了吧,届时请按照前面的篇章自行部署相关的合约),所有用到的依赖本篇都会一一阐述(从安装到简单的用途),系统环境是 <math xmlns="http://www.w3.org/1998/Math/MathML"> M a c O S \mathit {MacOS} </math>MacOS, <math xmlns="http://www.w3.org/1998/Math/MathML"> N o d e . j s \mathit {Node.js} </math>Node.js 的替代包管理器使用的是 <math xmlns="http://www.w3.org/1998/Math/MathML"> p n p m \mathit {pnpm} </math>pnpm。

二:功能剖析

2.1 我是谁?

2.1.1 介绍

在 <math xmlns="http://www.w3.org/1998/Math/MathML"> S u i M o v e \mathit {Sui\ Move} </math>Sui Move 当中,不论是部署还是调用合约,都需要事先创建一个 <math xmlns="http://www.w3.org/1998/Math/MathML"> a d d r e s s \mathit {address} </math>address,它既是你的钱包,也是你身份对外的象征,而在 <math xmlns="http://www.w3.org/1998/Math/MathML"> T y p e S c r i p t \mathit {TypeScript} </math>TypeScript 当中,想要调用链上的合约,自然也需要表明是谁在调用。

这一点可能在本篇当中体现不出其重要性,但是在今后尤其是涉及到资产方面的转赠与获取将至关重要,因为区块链一切都是匿名的,如果资产出了问题(被钓鱼被骗被盗),几乎没有找回的可能。

当然,每一次合约调用都将支付一笔费用,这要求你在 <math xmlns="http://www.w3.org/1998/Math/MathML"> T y p e S c r i p t \mathit {TypeScript} </math>TypeScript 中表明的身份需要拥有一定的资产(由于是 <math xmlns="http://www.w3.org/1998/Math/MathML"> t e s t \mathit {test} </math>test​​ 链,可以领水,所以不存在这个问题,相关操作也可以自行翻阅前篇)。

2.1.2 助记词

本篇选择通过助记词来表明身份,通过 <math xmlns="http://www.w3.org/1998/Math/MathML"> S u i C L I \mathit {Sui\ CLI} </math>Sui CLI 创建 <math xmlns="http://www.w3.org/1998/Math/MathML"> a d d r e s s \mathit {address} </math>address 后(本篇选择的加密方式是Ed25519),会给你私钥和助记词( <math xmlns="http://www.w3.org/1998/Math/MathML"> 12 \text {12} </math>12 个单词),大家应该精心保存好。

当然, 你大可以大大咧咧地将这个助记词写进代码里,但是一旦你将这份代码公开(例如 <math xmlns="http://www.w3.org/1998/Math/MathML"> g i t p u s h \mathit {git\ push} </math>git push 到 <math xmlns="http://www.w3.org/1998/Math/MathML"> g i t h u b \mathit {github} </math>github 上,没有人能够 <math xmlns="http://www.w3.org/1998/Math/MathML"> 100% \text {100\%} </math>100% 保证每一次都将助记词隐去),这就存在严重的安全隐患,因为所有人都可以通过这一份助记词来盗取你的资产。

因此,我们借助dotenv来读取环境变量。

  • 创建项目目录并初始化
bash 复制代码
mkdir sui_sdk_call_a_add_b
cd sui_sdk_call_a_add_b
pnpm init
# 后续的代码写在 index.ts 文件当中
touch index.ts
  • 安装(如果已经安装过了请跳过这一步,本篇后续所有的安装选项皆是如此)

pnpm install -g dotenv

  • 在项目目录下添加依赖

pnpm add -D dotenv

此时在package.json当中的devDependencies字段里,就会出现"dotenv": "^16.4.5",后面的数字代表版本号,请以你自己的版本为准。

  • 设置环境变量

export MNEMONIC="if you want to try it then try it it is ok"

注意: 上面双引号内的内容请自行替换成你的助记词 不会真有人直接复制粘贴吧

  • 测试代码
ts 复制代码
import dotenv from "dotenv";

dotenv.config();
const MNEMONIC = process.env.MNEMONIC!;
console.log(MNEMONIC);

process.env.MNEMONIC就是用来读取环境变量的值,它可能不存在,此时MNEMONIC的类型就是string | undefined(这一点可能会对后续使用该值造成困扰,具体困扰的原因后面再解释),而在最后添加!的目的就是人为标注保证这个值一定存在,此时MNEMONIC的类型就是固定的string,方便后续使用。

这里顺便提一下如何运行 <math xmlns="http://www.w3.org/1998/Math/MathML"> t s \mathit {ts} </math>ts 代码,本篇选择用ts-node来跳过生成 <math xmlns="http://www.w3.org/1998/Math/MathML"> j s \mathit {js} </math>js 文件再运行这一步骤,想要使用它只需要通过pnpm install -g ts-node安装即可。

  • 运行

ts-node index.ts

得到的输出就是你之前设置的环境变量的值,如果你真是直接复制粘贴的上面,那么这里得到的就是if you want to try it then try it it is ok

如果你无法运行,可能是你缺少@types/node这个依赖,请按照安装并添加dotenv依赖的方式,将其添加到package.json文件的依赖项字段里。

2.1.3 密钥对

在 <math xmlns="http://www.w3.org/1998/Math/MathML"> S u i T y p e S c r i p t S D K \mathit {Sui\ TypeScript\ SDK} </math>Sui TypeScript SDK 当中,提供了Keypair类来处理与 <math xmlns="http://www.w3.org/1998/Math/MathML"> S u i a d d r e s s \mathit {Sui\ address} </math>Sui address​ 相关的加密密钥对,提供了签名并验证的逻辑,当然,想要使用它,首先你得需要有这个 <math xmlns="http://www.w3.org/1998/Math/MathML"> S D K \mathit {SDK} </math>SDK。

  • 添加依赖

pnpm add -D @mysten/sui.js

  • 根据助记词创建Keypair
ts 复制代码
// 这里根据你选择的加密方式进行选择,还有两个是
// @mysten/sui.js/keypairs/secp256k1 和
// @mysten/sui.js/keypairs/secp256r1
import { Ed25519Keypair } from '@mysten/sui.js/keypairs/ed25519';

const keyPair = Ed25519Keypair.deriveKeypair(MNEMONIC);

如果在从环境变量读取助记词的时候不在末尾添加!,那么这里就会报错,因为这个函数只能接受类型为string的参数(这就是上面提到的可能产生的困扰)。

通过这个Keypair类,我们可以轻松获得其对应的私钥、公钥及更多信息,但在本篇当中,我们只需要这个实例化的类即可,具体作用请继续向下阅读。

2.2 我在哪?

2.2.1 介绍

接触过 <math xmlns="http://www.w3.org/1998/Math/MathML"> S u i M o v e \mathit {Sui\ Move} </math>Sui Move 或多或少都应该了解,它分为主网 <math xmlns="http://www.w3.org/1998/Math/MathML"> m a i n n e t \mathit {mainnet} </math>mainnet,开发网 <math xmlns="http://www.w3.org/1998/Math/MathML"> d e v n e t \mathit {devnet} </math>devnet,测试网 <math xmlns="http://www.w3.org/1998/Math/MathML"> t e s t n e t \mathit {testnet} </math>testnet​ 以及本地网络(其实绝大多数开发者都不会用到本地网),本篇想要调用的合约在测试网上,那么我们如何确定我在哪条链上呢?

2.2.2 获取对应的 rpcUrl

依赖@mysten/sui.js上面已经添加,所以可以直接使用,在@mysten/sui.js/client里有一个getFullnodeUrl可以用来获取对应的 <math xmlns="http://www.w3.org/1998/Math/MathML"> u r l \mathit {url} </math>url,传入的参数也很简单 ------ mainnet or devnet or testnetlocalnet这里不做展开,就像上面说的,大多数人都不会用到本地模拟的链上环境。

我们调用的合约在测试网上,所以我们可以这么做:const rpcUrl = getFullnodeUrl('testnet');

2.2.3 获取对应的 client

光有 <math xmlns="http://www.w3.org/1998/Math/MathML"> u r l \mathit {url} </math>url 还不够,我们需要通过这个 <math xmlns="http://www.w3.org/1998/Math/MathML"> u r l \mathit {url} </math>url 来获取对应的 <math xmlns="http://www.w3.org/1998/Math/MathML"> c l i e n t \mathit {client} </math>client,同样的,在@mysten/sui.js/client里有一个SuiClient可以做到这一点,就像是这样:const client = new SuiClient({ url: rpcUrl });

2.3 无内鬼,如何交易?

2.3.1 介绍

至此,我们已经明确了身份信息和所在的链,那么如何进行交易,也就是合约调用?

我们需要创建交易相关的信息,也就是调用合约时的必要参数,包括 <math xmlns="http://www.w3.org/1998/Math/MathML"> P a c k a g e I D , M o d u l e , F u n c t i o n , A r g u m e n t s \mathit {PackageID},\ \mathit {Module},\ \mathit {Function},\ \mathit {Arguments} </math>PackageID, Module, Function, Arguments 等,这些内容组合在一起,可以称之为交易块( <math xmlns="http://www.w3.org/1998/Math/MathML"> T r a n s a c t i o n B l o c k \mathit {TransactionBlock} </math>TransactionBlock),每一笔交易( <math xmlns="http://www.w3.org/1998/Math/MathML"> T r a n s a c t i o n \mathit {Transaction} </math>Transaction)都接受一组输入并产生结果,在本篇当中,我们只需要一笔交易。

2.3.2 交易块

@mysten/sui.js/transactions当中提供了TransactionBlock来创建交易块,代码也十分简单:const txb = new TransactionBlock();

接下去,我们来预处理一些信息:

  • <math xmlns="http://www.w3.org/1998/Math/MathML"> t a r g e t : \mathit {target}: </math>target: 按照PackageID::Module::Function的形式组成的字符串,按照前面篇章当中的部署上链的信息,我们可以编写以下代码:
ts 复制代码
const PACKAGE = "0xe2496799139225a06e7251857cdf46a32c20d773030c62b9bf24095cd60aac43";
const MODULE = "my_module";
const FUN = "add";
const target = `${PACKAGE}::${MODULE}::${FUN}`;
// console.log(target);
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> a r g u m e n t s : \mathit {arguments:} </math>arguments: 该函数需要两个 <math xmlns="http://www.w3.org/1998/Math/MathML"> u 64 \mathit u \text {64} </math>u64 的参数,这个参数并不是链对象上的值,所以我们需要将这些值序列化后传入,在这里可以使用txb.pure,例如:txb.pure.u64(a),其中 <math xmlns="http://www.w3.org/1998/Math/MathML"> a \mathit a </math>a 在 <math xmlns="http://www.w3.org/1998/Math/MathML"> T y p e s c r i p t \mathit {Typescript} </math>Typescript 文件当中是一个number类型的值。

紧接着,我们就可以通过 <math xmlns="http://www.w3.org/1998/Math/MathML"> m o v e C a l l \mathit {moveCall} </math>moveCall 将这些信息导入:

ts 复制代码
txb.moveCall({
    target,
    arguments: [txb.pure.u64(a), txb.pure.u64(b)],
});

2.4 签字画押!

2.4.1 介绍

交易信息已经处理好了,就差签字画押提供费用进行交易了,在 <math xmlns="http://www.w3.org/1998/Math/MathML"> S D K \mathit {SDK} </math>SDK 当中提供了两个相关的接口:executeTransactionBlocksignAndExecuteTransactionBlock

前者将签字画押和发送执行交易这两个过程分开了,本篇的内容我们选择使用后者,也就是将签名和交易二合一的方法。

2.4.2 交易

在之前得到的client当中,存在刚刚提到的signAndExecuteTransactionBlock函数,需要向其提供如下参数:

  • <math xmlns="http://www.w3.org/1998/Math/MathML"> t r a n s a c t i o n B l o c k : \mathit {transactionBlock:} </math>transactionBlock: 序列化后的交易数据,也就是上面处理好的txb
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> s i g n e r : \mathit {signer:} </math>signer: 交易发起者(签字画押的人),也就是上面早早就得到的keyPair
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> r e q u e s t T y p e : \mathit {requestType:} </math>requestType: 确定 <math xmlns="http://www.w3.org/1998/Math/MathML"> R P C \mathit {RPC} </math>RPC 节点应何时返回响应,有WaitForEffectsCertWaitForLocalExecution可选,默认是WaitForLocalExecution
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> o p t i o n s : \mathit {options:} </math>options: 设置一系列布尔值,来确定返回响应时得到哪些信息(默认值都是False):
    • <math xmlns="http://www.w3.org/1998/Math/MathML"> s h o w B a l a n c e C h a n g e s : \mathit {showBalanceChanges:} </math>showBalanceChanges: 是否显示余额变化
    • <math xmlns="http://www.w3.org/1998/Math/MathML"> s h o w E f f e c t s : \mathit {showEffects:} </math>showEffects: 是否显示交易效果
    • <math xmlns="http://www.w3.org/1998/Math/MathML"> s h o w E v e n t s : \mathit {showEvents:} </math>showEvents: 是否显示交易事件
    • <math xmlns="http://www.w3.org/1998/Math/MathML"> s h o w I n p u t : \mathit {showInput:} </math>showInput: 是否显示输入数据
    • <math xmlns="http://www.w3.org/1998/Math/MathML"> s h o w O b j e c t C h a n g e s : \mathit {showObjectChanges:} </math>showObjectChanges: 是否显示对象变化
    • <math xmlns="http://www.w3.org/1998/Math/MathML"> s h o w R a w I n p u t : \mathit {showRawInput:} </math>showRawInput: 是否显示 <math xmlns="http://www.w3.org/1998/Math/MathML"> b c s \mathit {bcs} </math>bcs 编码的交易输入数据

在这里,我们选择将 <math xmlns="http://www.w3.org/1998/Math/MathML"> s h o w O b j e c t C h a n g e s \mathit {showObjectChanges} </math>showObjectChanges 设置为 True,根据得到的 <math xmlns="http://www.w3.org/1998/Math/MathML"> O b j e c t I D \mathit {ObjectID} </math>ObjectID 来查询里面存储的值是否为 <math xmlns="http://www.w3.org/1998/Math/MathML"> a + b \mathit a\ +\ \mathit b </math>a + b 的和,由于各种数据都在前面经过处理,这段代码就非常简洁:

ts 复制代码
const result = await client.signAndExecuteTransactionBlock({
    transactionBlock: txb,
    signer: keyPair,
    requestType: "WaitForLocalExecution",
    options: {
        showObjectChanges: true,
    }
});

console.log(
    `executeTransactionBlock result: ${JSON.stringify(result, null, 2)}`
);

最后console.log的内容,将会是本次交易的 <math xmlns="http://www.w3.org/1998/Math/MathML"> O b j e c t C h a n g e s \mathit {ObjectChanges} </math>ObjectChanges 的相关信息。

2.5 由我来决定!

2.5.1 介绍

每次 <math xmlns="http://www.w3.org/1998/Math/MathML"> a + b \mathit a\ +\ \mathit b </math>a + b 的参数,都只能通过代码修改?不!我要自己决定!

怎么决定?

从终端输入!

注意: 这里并非本篇文章的重点,所以简单带过。

2.5.2 输入

利用readline当中的createInterface来创建标准输入输出:

ts 复制代码
const readline = createInterface({
    input: process.stdin,
    output: process.stdout,
});

定义一个用来接受输入的空的字符串,并将得到的值传递给它:

ts 复制代码
var strNumber = "";
readline.question("Please enter two numbers, separated by spaces: ", inputNumber => {
    strNumber = inputNumber;
    readline.close();
});

从逻辑上来讲,我们需要等待用户完成输入再进行后续操作(交易块数据处理以及发送交易等环节),所以我们判断strNumber是否为空,再循环sleep

ts 复制代码
while (strNumber == "")
    await new Promise(resolve => setTimeout(resolve, 100));

由于这里用到了await(等待一个异步函数的结果),所以这段输入的代码需要放在async声明的异步函数当中,如果有返回值也应该是Promise<Type>

ts 复制代码
async function read(): Promise<string[]> {
  	// TODO
  	// ......
		return strNumber.split(' ');
}

2.6 完整代码

ts 复制代码
import dotenv from "dotenv";
import { Ed25519Keypair } from '@mysten/sui.js/keypairs/ed25519';
import { getFullnodeUrl, SuiClient } from "@mysten/sui.js/client";
import { TransactionBlock } from "@mysten/sui.js/transactions";
import { createInterface } from "readline";

dotenv.config();
const MNEMONIC = process.env.MNEMONIC!;
// console.log(MNEMONIC);

const keyPair = Ed25519Keypair.deriveKeypair(MNEMONIC);

const client = new SuiClient({url: getFullnodeUrl("testnet")});

const txb = new TransactionBlock();

const PACKAGE = "0xe2496799139225a06e7251857cdf46a32c20d773030c62b9bf24095cd60aac43";
const MODULE = "my_module";
const FUN = "add";
const target = `${PACKAGE}::${MODULE}::${FUN}`;
// console.log(target);

async function read(): Promise<string[]> {
    const readline = createInterface({
        input: process.stdin,
        output: process.stdout,
    });

    var strNumber = "";
    readline.question("Please enter two numbers, separated by spaces: ", inputNumber => {
        strNumber = inputNumber;
        readline.close();
    });

    while (strNumber == "")
        await new Promise(resolve => setTimeout(resolve, 100));
    return strNumber.split(' ');
}

async function callAdd(a: number, b: number) {
    txb.moveCall({
        target,
        arguments: [txb.pure.u64(a), txb.pure.u64(b)],
    });
    
    const result = await client.signAndExecuteTransactionBlock({
        transactionBlock: txb,
        signer: keyPair,
        requestType: "WaitForLocalExecution",
        options: {
            showObjectChanges: true,
        }
    });
    
    console.log(
        `executeTransactionBlock result: ${JSON.stringify(result, null, 2)}`
    );
}

async function main() {
    const nums = await read();
    // const a = Number(nums[0]);
    // const b = Number(nums[1]);
    // console.log(typeof a, typeof b, a, b);
    callAdd(Number(nums[0]), Number(nums[1]));
}

main();

三:运行校验

  • 运行命令

ts-node index.ts

  • 得到如下信息并且等待输入:

Please enter two numbers, separated by spaces:

  • 根据提示输入两个数:

Please enter two numbers, separated by spaces: 369 963

  • 得到信息:
bash 复制代码
executeTransactionBlock result: {
  "digest": "BiFBgM2AdpAGSkpsYcgWUFUK7osETW3NFNhdyUkWxKG",
  "objectChanges": [
    {
      "type": "mutated",
      "sender": "0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67",
      "owner": {
        "AddressOwner": "0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67"
      },
      "objectType": "0x2::coin::Coin<0x2::sui::SUI>",
      "objectId": "0x03335f68ff3616af7e000b113c56a5ad53e8e8209784ca0a5623f70997c8d948",
      "version": "28131890",
      "previousVersion": "28131889",
      "digest": "C6kmRbL5LB5wvikk8bEij1YgZTN4gnyLCvSSu1aRPpv3"
    },
    {
      "type": "created",
      "sender": "0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67",
      "owner": {
        "AddressOwner": "0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67"
      },
      "objectType": "0xe2496799139225a06e7251857cdf46a32c20d773030c62b9bf24095cd60aac43::my_module::Result",
      "objectId": "0xafd346ba388f626f2bbc364ed507a33b3e8073bf0e610f538803ac0c986183f7",
      "version": "28131890",
      "digest": "CByybjYC9EKoGAGWvY2T3zuY8TLsmdkgJtyLh1rUd536"
    }
  ],
  "confirmedLocalExecution": true
}
  • 根据新创建的Result ObjectID进行查询:

sui client object 0xafd346ba388f626f2bbc364ed507a33b3e8073bf0e610f538803ac0c986183f7

  • <math xmlns="http://www.w3.org/1998/Math/MathML"> a + b \mathit a\ +\ \mathit b </math>a + b 的和:
bash 复制代码
╭───────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ objectId      │  0xafd346ba388f626f2bbc364ed507a33b3e8073bf0e610f538803ac0c986183f7                                             │
│ version       │  28131890                                                                                                       │
│ digest        │  CByybjYC9EKoGAGWvY2T3zuY8TLsmdkgJtyLh1rUd536                                                                   │
│ objType       │  0xe2496799139225a06e7251857cdf46a32c20d773030c62b9bf24095cd60aac43::my_module::Result                          │
│ owner         │ ╭──────────────┬──────────────────────────────────────────────────────────────────────╮                         │
│               │ │ AddressOwner │  0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67  │                         │
│               │ ╰──────────────┴──────────────────────────────────────────────────────────────────────╯                         │
│ prevTx        │  BiFBgM2AdpAGSkpsYcgWUFUK7osETW3NFNhdyUkWxKG                                                                    │
│ storageRebate │  1368000                                                                                                        │
│ content       │ ╭───────────────────┬─────────────────────────────────────────────────────────────────────────────────────────╮ │
│               │ │ dataType          │  moveObject                                                                             │ │
│               │ │ type              │  0xe2496799139225a06e7251857cdf46a32c20d773030c62b9bf24095cd60aac43::my_module::Result  │ │
│               │ │ hasPublicTransfer │  false                                                                                  │ │
│               │ │ fields            │ ╭─────┬───────────────────────────────────────────────────────────────────────────────╮ │ │
│               │ │                   │ │ id  │ ╭────┬──────────────────────────────────────────────────────────────────────╮ │ │ │
│               │ │                   │ │     │ │ id │  0xafd346ba388f626f2bbc364ed507a33b3e8073bf0e610f538803ac0c986183f7  │ │ │ │
│               │ │                   │ │     │ ╰────┴──────────────────────────────────────────────────────────────────────╯ │ │ │
│               │ │                   │ │ res │  1332                                                                         │ │ │
│               │ │                   │ ╰─────┴───────────────────────────────────────────────────────────────────────────────╯ │ │
│               │ ╰───────────────────┴─────────────────────────────────────────────────────────────────────────────────────────╯ │
╰───────────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

不难发现,其中存储的 <math xmlns="http://www.w3.org/1998/Math/MathML"> r e s \mathit {res} </math>res 值为 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1332 \text {1332} </math>1332,大成功(๑•̀ㅂ•́)و✧

四:挑战任务在主网领 Sui

有了上述内容打底,你是否对安装、添加依赖,简单调用相关的 <math xmlns="http://www.w3.org/1998/Math/MathML"> A P I \mathit {API} </math>API 有了一定的了解?

现在就到了实践的时刻!

<math xmlns="http://www.w3.org/1998/Math/MathML"> t w i t t e r \mathit {twitter} </math>twitter 以及 <math xmlns="http://www.w3.org/1998/Math/MathML"> l e t ′ s m o v e t a s k 6 \mathit {let's\ move\ task}\text 6 </math>let′s move task6,完成相关任务就可以领 <math xmlns="http://www.w3.org/1998/Math/MathML"> S u i \mathit {Sui} </math>Sui(主网的,可在交易所变现的那种),与本篇的差异就是需要你添加navi-sdk,通过助记词在NAVISDKClient上表明身份,再调用depositToNavi向 <math xmlns="http://www.w3.org/1998/Math/MathML"> N a v i \mathit {Navi} </math>Navi 转 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 S u i \text 1 \mathit {Sui} </math>1Sui,最后根据这笔交易的信息提交并等待 <math xmlns="http://www.w3.org/1998/Math/MathML"> S u i \mathit {Sui} </math>Sui 到账即可,甚至都不需要自己创建并处理交易块信息。

<math xmlns="http://www.w3.org/1998/Math/MathML"> n a v i s d k \mathit {navi\ sdk} </math>navi sdk 相关可以点击查看文档。

注意: 任务奖励随时可能截止,尤其是 <math xmlns="http://www.w3.org/1998/Math/MathML"> t w i t t e r \mathit {twitter} </math>twitter 上的 (可能就在这几天吧),先到先得,抓紧做起来(๑•̀ㅂ•́)و✧

五:加入组织,共同进步!

  • Sui 中文开发群(TG)
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> M o v e \mathit{Move} </math>Move 语言学习交流群: 79489587
相关推荐
Roun32 小时前
去中心化存储:Web3中的数据安全新标准
web3·去中心化·区块链
王解3 小时前
Jest项目实战(2): 项目开发与测试
前端·javascript·react.js·arcgis·typescript·单元测试
鸿蒙开天组●6 小时前
鸿蒙进阶篇-网格布局 Grid/GridItem(二)
前端·华为·typescript·harmonyos·grid·mate70
zhizhiqiuya6 小时前
第二章 TypeScript 函数详解
前端·javascript·typescript
dingzd9517 小时前
Web3对社交媒体的影响:重新定义用户互动方式
web3·去中心化·区块链·媒体
初遇你时动了情21 小时前
react 18 react-router-dom V6 路由传参的几种方式
react.js·typescript·react-router
王解21 小时前
Jest进阶知识:深入测试 React Hooks-确保自定义逻辑的可靠性
前端·javascript·react.js·typescript·单元测试·前端框架
web3探路者21 小时前
加密货币行业与2024年美国大选
java·大数据·web3·区块链·团队开发·开源软件
_jiang1 天前
nestjs 入门实战最强篇
redis·typescript·nestjs
清清ww1 天前
【TS】九天学会TS语法---计划篇
前端·typescript