Tạo transaction với Sui Blockchain
Sui objects
Sui Blockchain hoạt động trên hệ thống Object Based, đây cũng là sự khác biệt lớn nhất so với các blockchain khác. Thay vì lưu lại balance theo account, Sui Blockchain sẽ hoạt động xung quanh các objects, mọi thứ trong Sui Blockchain đều là objects.
Ví dụ
Bạn có 2 object có type là coin::Coin<0x2::sui::SUI>
và có thông số balance lần lượt của object thứ 1: 699206037
, và object thứ 2 là: 145432704
, vậy tổng cộng bạn có: 844638741, (0.8446Sui, coin Sui có chỉ số decimals
là 9). Balance của bạn sẽ được cấu thành dựa trên tổng số balance nằm trong các object cùng type mà bạn muốn tính balance.
Và để quản lý, các object chắc chắn đều sẽ có object id của riêng bản thân nó.
Fact: coin::Coin<0x2::sui::SUI>
cũng là object (có object id là 0x2
) và chúng ta đang sử dụng module
coin
có lưu trữ Struct
Coin
với type là 0x2::sui::SUI
(Coin<0x2::sui::SUI>
)
Chuyển tiền
Thay vì ghi nợ và ghi có như cách hoạt động bình thường của ledger, để mô phỏng thế giới thật, Sui Blocckhain hoạt động dựa trên cơ chế merge, split (hợp nhất và phân tách).
Cụ thể, giống như việc bạn ra biển và múc lấy 1 nắm cát (objects) và bỏ vào hủ của bạn (account), để tính tổng số hạt cát mà bạn có, bạn phải đếm nó (calculate balance from adding balance in objects), sau khi đếm xong bạn đã nắm rõ số lượng cát trong hủ của mình.
Bạn có thể hợp nhất các hạt cát trong hủ thành 1 hạt cát to có balance bằng tổng balance của các hạt nhỏ.
Khi chuyển 1 nữa cát trong hủ, nếu bạn chưa hợp nhất, bạn có thể múc 1 nữa hủ để chuyển, nếu đã hợp nhất, bạn chia đôi hạt cát to để chuyển.
Tìm hiểu theo về object trong Sui tạI: https://docs.sui.io/learn/objects
Flow cơ bản
- Tạo object transaction (tx)
- Thực hiện các bước trong transaction
- Sign transaction (tham khảo cách tạo
signer
tại: https://viblo.asia/p/sui-blockchain-wallet-account-38X4EN9zJN2#_tao-signer-tu-keypair-va-provider-6) - Chạy dry run
- Submit lên blockchain
- Chờ blockchain thực hiện và trả kết quả
- Kiểm tra kết quả của transaction
Transaction gửi Sui
Lấy ra tất cả Sui objects hiện đang có trong account
import { SUI_TYPE_ARG } from "@mysten/sui.js";
const suiCoins = await provider.getCoins({ owner: address, cursor: nextCursor || undefined, limit: 100, coinType: SUI_TYPE_ARG });
Để lấy tất cả các objects, hãy sử dụng loop với hasNextPage
, nextCursor
trong kết quả trả về của suiCoins
cho đến khi hasNextPage
=== false
.
(xem các tạo provider
và signer
tại: https://viblo.asia/p/sui-blockchain-wallet-account-38X4EN9zJN2#_tao-signer-tu-keypair-va-provider-6)
Warning: nên kiểm tra tổng số objects hiện tại của coin type cần gửi trong account trước khi fetch lấy hết các objects (sử dụng getAllBalances
với prop: coinObjectCount
), vì nếu tổng số quá lớn thì có thể sẽ không thực hiện được tx (tối đa khoảng 500 objects/lần) . Hãy merge tổng số objects về nhỏ hơn 500 để thực hiện các tx 1 cách tốt nhất (công cụ hỗ trợ merge: https://fewcha.app/sui-merge-coin/)
Gửi 1 phần đến người nhận
const tx = new TransactionBlock();
tx.setGasPayment(suiCoins.map((coin) => ({ version: coin.version, digest: coin.digest, objectId: coin.coinObjectId }))); // lấy tất cả objects sui hiện tại
const [coinIn] = tx.splitCoins(tx.gas, [tx.pure(amount)]); // lấy phần cần chuyển
tx.transferObjects([coinIn], tx.pure(receiverAddress, "address")); // chuyển đến người nhận
const dryrun = await signer.dryRunTransactionBlock({ transactionBlock: tx });
// kiểm tra dryrun nếu bạn muốn
const submittedTx = await signer.signAndExecuteTransactionBlock({ transactionBlock: tx });
await provider.waitForTransactionBlock({ digest: submittedTx.digest });
Gửi tất cả Sui đến người nhận
const tx = new TransactionBlock();
tx.setGasPayment(suiCoins.map((coin) => ({ version: coin.version, digest: coin.digest, objectId: coin.coinObjectId })));
tx.transferObjects(tx.gas, tx.pure(receiverAddress, "address")); // chuyển tất cả sui đang có đến người nhận
const dryrun = await signer.dryRunTransactionBlock({ transactionBlock: tx });
const submittedTx = await signer.signAndExecuteTransactionBlock({ transactionBlock: tx });
await provider.waitForTransactionBlock({ digest: submittedTx.digest });
Để gửi Sui đến nhiều người nhận trong cùng 1 tx
Sử dụng công cụ Sui Bulk Send tại: https://fewcha.app/sui-merge-coin/
Transaction gửi coin
const tx = new TransactionBlock();
tx.setGasPayment(suiCoins.map((coin) => ({ version: coin.version, digest: coin.digest, objectId: coin.coinObjectId })));
const coinXs = await provider.getCoins({ owner: currentAddress, coinType: coinTypeX }); // nên lấy tất cả objects bằng loop qua hasNextPage và nextCursor
const [primaryCoinX, ...restCoinXs] = coinYs.data;
tx.mergeCoins(
tx.object(primaryCoinX.coinObjectId),
restCoinXs.map((coin) => tx.object(coin.coinObjectId)),
);
const [coinIn] = tx.splitCoins(tx.object(primaryCoinY.coinObjectId), [tx.pure(amount)]); // lấy phần cần chuyển
tx.transferObjects([coinIn], tx.pure(receiverAddress, "address"));
const dryrun = await signer.dryRunTransactionBlock({ transactionBlock: tx });
const submittedTx = await signer.signAndExecuteTransactionBlock({ transactionBlock: tx });
await provider.waitForTransactionBlock({ digest: submittedTx.digest });
Gửi tất cả balance của coin
const tx = new TransactionBlock();
tx.setGasPayment(suiCoins.map((coin) => ({ version: coin.version, digest: coin.digest, objectId: coin.coinObjectId })));
const coinXs = await provider.getCoins({ owner: currentAddress, coinType: coinTypeX }); // nên lấy tất cả objects bằng loop qua hasNextPage và nextCursor
const [primaryCoinX, ...restCoinXs] = coinYs.data;
tx.mergeCoins(
tx.object(primaryCoinX.coinObjectId),
restCoinXs.map((coin) => tx.object(coin.coinObjectId)),
);
tx.transferObjects([tx.object(primaryCoinX.coinObjectId)], tx.pure(receiverAddress, "address"));
const dryrun = await signer.dryRunTransactionBlock({ transactionBlock: tx });
const submittedTx = await signer.signAndExecuteTransactionBlock({ transactionBlock: tx });
await provider.waitForTransactionBlock({ digest: submittedTx.digest });
Gửi Sui và Coin khác trong cùng 1 transaction
const tx = new TransactionBlock();
tx.setGasPayment(suiCoins.map((coin) => ({ version: coin.version, digest: coin.digest, objectId: coin.coinObjectId })));
const coinXs = await provider.getCoins({ owner: currentAddress, coinType: coinTypeX });
const [primaryCoinX, ...restCoinXs] = coinYs.data;
tx.mergeCoins(
tx.object(primaryCoinX.coinObjectId),
restCoinXs.map((coin) => tx.object(coin.coinObjectId)),
);
const [suiCoinIn] = tx.splitCoins(tx.gas, [tx.pure(suiAmount)]);
const [coinIn] = tx.splitCoins(tx.object(primaryCoinY.coinObjectId), [tx.pure(xAmount)]);
tx.transferObjects([suiCoinIn, coinIn], tx.pure(receiverAddress, "address"));
const dryrun = await signer.dryRunTransactionBlock({ transactionBlock: tx });
const submittedTx = await signer.signAndExecuteTransactionBlock({ transactionBlock: tx });
await provider.waitForTransactionBlock({ digest: submittedTx.digest });
Transaction gọi lên Smart Contract
Transaction buy suifrens
Để thực hiện việc mua NFT suifrens bằng script, chúng ta có thể tạo transaction như sau:
const tx = new TransactionBlock();
const coin = tx.splitCoins(tx.gas, [tx.pure(8000000000)]); // SUI
const rest = tx.moveCall({
target: "0xee496a0cc04d06a345982ba6697c90c619020de9e274408c7819f787ff66e1a1::genesis::Mint",
arguments: [
tx.object("0x2ec5baa9b548b0dbf76f70063f74f95e2451fa409535b7cf755a829b167b4a58"),
tx.object("0x0000000000000000000000000000000000000000000000000000000000000006"),
coin,
],
typeArguments: ["0xee496a0cc04d06a345982ba6697c90c619020de9e274408c7819f787ff66e1a1::capy::Capy"],
});
tx.transferObjects([rest, coin], tx.pure(currentAddress));
tx.setSender(currentAddress);
const dryrun = await signer.dryRunTransactionBlock({ transactionBlock: tx });
const submittedTx = await signer.signAndExecuteTransactionBlock({ transactionBlock: tx });
await provider.waitForTransactionBlock({ digest: submittedTx.digest });
All rights reserved