Giới thiệu về Programmable Transaction Block (PTB)
Programmable Transaction Block (PTB) là công nghệ lõi của Sui, được thiết kế để nâng cao tính linh hoạt và khả năng lập trình của các giao dịch. PTB cho phép chúng ta kết hợp nhiều thao tác vào một giao dịch duy nhất, cho phép thực thi logic giao dịch phức tạp chỉ với một lần submit.
PTB giải quyết một số vấn đề chính trong giao dịch blockchain:
1.Độ phức tạp của giao dịch: Blockchain truyền thống chỉ thực thi một thao tác cho mỗi giao dịch. Logic nghiệp vụ phức tạp thường yêu cầu nhiều giao dịch, dẫn đến thao tác rườm rà và hiệu suất thấp. PTB cho phép kết hợp nhiều thao tác vào một giao dịch duy nhất, cải thiện hiệu quả xử lý nghiệp vụ.
2.Tính nguyên tử của các thao tác: Trong nhiều giao dịch, nếu một bước thất bại, cần phải thực hiện các thao tác rollback phức tạp. PTB đảm bảo tính nguyên tử của tất cả các thao tác, ngăn chặn vấn đề không nhất quán dữ liệu do thành công một phần.
3.Hiệu năng mạng: Bằng cách giảm số lượng giao dịch, PTB giảm băng thông mạng tiêu thụ và thời gian xác nhận giao dịch, nâng cao hiệu suất tổng thể.
Giới thiệu về câu lệnh với ptb
Nếu bạn đã làm việc với sui client
thì còn có một sub-command mà bạn nên biết đó là sui client ptb
.
sui client ptb [OPTIONS]
trong đó phần [OPTIONS]
chưa rất nhiều các functions cần thiết như là
--assign command
Mục đích của câu lệnh này là bạn sẽ assign một biến để được sử dụng trong PTB commands
sui client ptb --assign MYVAR 100
sui client ptb --assign X '[100, 5000]'
--merge-coins command
Gộp nhiều đồng coin vào một đồng coin được chỉ định. Các ID của object cần được thêm ký hiệu @ ở phía trước.
Syntax mà bạn cầnn truyền vào là:
<INTO_COIN> <[COIN OBJECTS]>
Ví dụ:
sui client ptb --merge-coins @coin_object_id '[@coin_obj_id1, @coin_obj_id2]'
--slit-coins command
Split thành nhiều coins khác nhau:
--split-coins gas '[1000, 5000, 75000]'
--assign new_coins
--split-coins @coin_object_id [100]
--move-call command
Gọi một hàm Move được chỉ định. Đây là syntax:
<PACKAGE::MODULE::FUNCTION> <TYPE_ARGS> <FUNCTION_ARGS>
Ví dụ:
--move-call std::option::is_none <u64> none
--assign a none
--move-call std::option::is_none <u64> a
--transfer-objects command
Transfer các objects để một address cụ thể:
--transfer-objects [obj1, obj2, obj3] @address
--split-coins gas [1000, 5000, 75000]
--assign new_coins
--transfer-objects [new_coins.0, new_coins.1, new_coins.2] @to_address
Mình có ví dụ sau đây publish một contract, call contract đo, mint NFT và transfer nó đến một địa chỉ bất kì. Như vậy cấu trúc sẽ là:
sui client ptb \
--move-call <PACKAGE-ID>::<MODULE>::<FUNCTION> <ARGS> \
--assign result \
--transfer-objects [result] sender \
--gas-budget 5000000 \
--summary
Đây là contract mẫu của mình về mint NFT đó:
module 0x0::mynft {
use sui::package::{Self, Publisher};
use sui::display::{Self, Display};
use std::string::{Self, String};
public struct HelloWorldObject has key, store {
id: UID,
text: string::String
}
entry fun mint(ctx: &mut TxContext) {
let object = HelloWorldObject {
id: object::new(ctx),
text: string::utf8(b"Hello World!")
};
transfer::public_transfer(object, tx_context::sender(ctx));
}
}
```nodemon
Như vậy đây sẽ là câu lệnh:
sui client ptb
--move-call 0x4fbd542193a20993ce514db7cb259908852de7f045e3d3e9c1030ea777e216f2::mynft::mint
--gas-budget 5000000
--summary
Đây chính là kết quả bạn sẽ nhận được:
```rust
╭──────────────────────────────────────────────────────╮
│ PTB Execution Summary │
├──────────────────────────────────────────────────────┤
│ Digest: A6qkvrA2s3moCxVDdG6TkHn5MHZHyhb8e7sRowEKV8CN │
│ Status: success │
│ Gas Cost Summary: │
│ Storage Cost: 2439600 │
│ Computation Cost: 1000000 │
│ Storage Rebate: 978120 │
│ Non-refundable Storage Fee: 9880 │
╰──────────────────────────────────────────────────────╯
Ví dụ TypeScript SDK dùng PTB
Khởi tạo project: Tạo và truy cập vào thư mục dự án để khởi tạo dự án
mkdir ptb-project && cd ptb-project && pnpm init
pnpm install @mysten/sui
import { Transaction } from '@mysten/sui/transactions';
import { getFullnodeUrl, SuiClient } from '@mysten/sui/client';
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
import { getFaucetHost, requestSuiFromFaucetV1} from '@mysten/sui/faucet';
const keypair = Ed25519Keypair.fromSecretKey("suiprivkey1qrttsfcmrca4cuc0ejwzkcezhmz487ksdyxgnj84dy50uyjn995mgy6e928");
const secretKey = keypair.getSecretKey();
console.log('Secret Key:', secretKey);
const address = keypair.getPublicKey().toSuiAddress();
console.log('Address :', address);
const client = new SuiClient({ url: getFullnodeUrl('testnet') });
let balance = await client.getCoins({
owner: address,
});
console.log('balance :', balance);
const tx = new Transaction();
const [coin] = tx.splitCoins(tx.gas, [100]);
tx.transferObjects([coin], address);
tx.moveCall({
target: '0x4fbd542193a20993ce514db7cb259908852de7f045e3d3e9c1030ea777e216f2::mynft::mint'
});
tx.setGasPrice(1000);
tx.setGasBudget(10000000);
const result =await client.signAndExecuteTransaction({ signer: keypair, transaction: tx });
console.log(result);
và đây là kết quả:
Secret Key: suiprivkey1qrttsfcmrca4cuc0ejwzkcezhmz487ksdyxgnj84dy50uyjn995mgy6e928
Address : 0xebb5a8837f470e86e09c9c74d7abe9019be7dbf874866bb0bf9447861424372a
balance : {
data: [
{
coinType: '0x2::sui::SUI',
coinObjectId: '0x777d98f486723a2ee895d7018bb09916a0bd227ae2ba27c71da6cac0b36cd8da',
version: '289572259',
digest: 'CSNh2Efbk2uaDMEbELAkdvrVbReGZb7GPYsUcMFJNXey',
balance: '2897245132',
previousTransaction: 'FXjobHuHqNihukiiygup4fP41gzrci2EvaENzmSNAGa5'
}
],
nextCursor: '0x777d98f486723a2ee895d7018bb09916a0bd227ae2ba27c71da6cac0b36cd8da',
hasNextPage: false
}
{
digest: 'AdoQGhMTnnkgNkWuoB694FaLmj8wWBVCSiSEbXZVU1YQ',
confirmedLocalExecution: false
}