Game on Sui
Giới thiệu
Sau khi chúng ta đã học các phần cơ bản của ngôn ngữ lập trình Move, đặc biệt là cách để tạo ra các Objects
trên Sui.
Bây giờ chúng ta sẽ áp dụng các kiến thức đó để tạo ra một game trên Sui
Mô tả Game Play
-
Tạo nhân vật(Player):
- Người chơi có thể tạo nhân vật với các thuộc tính cơ bản
- Mỗi nhân vật sẽ là một Object riêng biệt trên Sui blockchain
- Người chơi sở hữu hoàn toàn nhân vật của mình
-
Chiến đấu:
- Người chơi có thể cho nhân vật tham gia các trận chiến với quái vật
- Kết quả trận đấu được lưu trữ trên blockchain
-
Phát triển nhân vật:
- Nhân vật có thể tăng cấp thông qua các trận đấu (đánh quái, ... )
- Các chỉ số của nhân vật được cập nhật và lưu trữ trên chain
- Người chơi có thể trang bị các vật phẩm cho nhân vật ví dụ Sword, ...
Code
Step 1: Tạo project
sui move new game_on_sui
Link code: https://github.com/CocDap/game_on_move/tree/main (opens in a new tab)
Step 2: Định nghĩa các Objects
- Hero: Mô tả nhân vật của người chơi
- Sword: Vật phẩm của người chơi
- Boar: Quái vật heo
- GameInfo: Thông tin của game
- GameAdmin: Admin quản lý game
- Potion: Vật phẩm hồi máu
/// hero.move
/// -------------------------------------------------------------------------------
/// -------------------------------ĐỊNH NGHĨA OBJECT-------------------------------
/// -------------------------------------------------------------------------------
// Tạo 1 object Sword
public struct Sword has key, store {
id: UID,
// Sức mạnh phép thuật
magic: u64,
// Sức mạnh của Sword trong game
strength: u64,
game_id: ID
}
// Tạo 1 object Hero
public struct Hero has key, store {
id: UID,
// Hit point - Máu của Hero
hp: u64,
// Điểm kinh nghiệm của hero
experience: u64,
// Hero có Sword
sword: Option<Sword>,
// Game id mà user đang chơi
game_id: ID,
}
// Tạo 1 object "Máu" -> Sử dụng để hồi HP
public struct Potion has key, store {
id: UID,
// Lượng hồi máu
potency: u64,
// Game id mà user đang chơi
game_id: ID
}
// Tạo 1 object Quái Boar
public struct Boar has key {
id: UID,
// Máu của quái tối đa bao nhiêu
// HP =0 -> quái chết
hp: u64,
// Sức mạnh của quái
strength: u64,
// Game id
game_id: ID
}
// Tạo GameAdmin
public struct GameInfo has key {
id: UID,
admin: address,
payments: Balance<SUI>,
}
public struct GameAdmin has key {
id: UID,
boars_created: u64,
potions_created: u64,
game_id: ID
}
Link code: https://github.com/CocDap/game_on_move/tree/step2 (opens in a new tab)
Step 3: Định nghĩa Events
- BoarSlainEvent: Sự kiện khi người chơi hạ gục quái vật
/// hero.move
/// -------------------------------------------------------------------------------
/// -------------------------------ĐỊNH NGHĨA EVENT--------------------------------
/// -------------------------------------------------------------------------------
public struct BoarSlainEvent has copy, drop {
// player nào hạ gục boar
slayer_address: address,
// ID của hero mà user đang control
hero: ID,
// ID của boar đã bị hạ gục
boar: ID,
game_id: ID
}
Link code: https://github.com/CocDap/game_on_move/tree/step3 (opens in a new tab)
Step 4: Định nghĩa hằng số và lỗi
/// hero.move
/// -------------------------------------------------------------------------------
/// ----------------------ĐỊNH NGHĨA CÁC HẰNG SỐ ----------------------------------
/// -------------------------------------------------------------------------------
const MAX_HP: u64 = 1000;
const MAX_MAGIC: u64 = 10;
const MIN_SWORD_COST: u64 = 100;
/// -------------------------------------------------------------------------------
/// -------------------------------ĐỊNH NGHĨA LỖI----------------------------------
/// -------------------------------------------------------------------------------
const EBOAR_WON: u64 = 0;
const EHERO_TIRED: u64 = 1;
const ENOT_ADMIN: u64 = 2;
const EINSUFFICIENT_FUNDS: u64 = 3;
const ENO_SWORD: u64 = 4;
const EWRONG_GAME_PLAY: u64 = 5;
Link code: https://github.com/CocDap/game_on_move/tree/step4 (opens in a new tab)
Step 5: Tạo game info và game admin
GameInfo
: Lưu trữ thông tin game -> Share ObjectGameAdmin
: Lưu trữ thông tin game admin -> Transfer Object
/// hero.move
public entry fun new_game(ctx: &mut TxContext) {
create(ctx);
}
/// -------------------------------------------------------------------------------
/// -----------------HELPER FUNCTION CHO VIỆC TẠO GAME ADMIN VÀ GAME INFO----------
/// -------------------------------------------------------------------------------
fun create(ctx: &mut TxContext){
let sender = tx_context::sender(ctx);
let id = object::new(ctx);
let game_id = object::uid_to_inner(&id);
transfer::share_object(GameInfo {
id,
admin: sender,
payments: balance::zero()
});
transfer::transfer(
GameAdmin {
id: object::new(ctx),
boars_created: 0,
potions_created: 0,
game_id,
},
sender
)
}
Link code: https://github.com/CocDap/game_on_move/tree/step5 (opens in a new tab)
Step 6: Tạo game Hero và Sword
- Hero Object: Lưu trữ thông tin hero -> Transfer Object
- Sword Object: Lưu trữ thông tin sword -> Transfer Object
/// hero.move
public entry fun acquire_hero(game: &mut GameInfo, payment: Coin<SUI>, ctx: &mut TxContext) {
let sword = create_sword(game, payment, ctx);
let hero = create_hero(game, sword, ctx);
transfer::transfer(hero, tx_context::sender(ctx))
}
/// -------------------------------------------------------------------------------
/// ---------------------HELPER FUNCTION TẠO HERO VÀ SWORD-------------------------
/// -------------------------------------------------------------------------------
// Tạo Sword
public fun create_sword(game: &mut GameInfo, payment: Coin<SUI>, ctx: &mut TxContext): Sword {
// Lấy số lượng coin hiện tại mà user sở hữu
let value = coin::value(&payment);
assert!(value >= MIN_SWORD_COST, EINSUFFICIENT_FUNDS);
// pay coin cho admin
coin::put(&mut game.payments, payment);
// Công thức tính magic
let magic = (value - MIN_SWORD_COST)/ MIN_SWORD_COST;
Sword {
id: object::new(ctx),
magic: std::u64::min(magic, MAX_MAGIC),
strength: 1,
game_id: object::id(game)
}
}
// Tạo hero
public fun create_hero(game: &GameInfo, sword: Sword, ctx: &mut TxContext): Hero {
// Kiểm tra có cùng game id hay không
assert!(object::id(game) == sword.game_id, EWRONG_GAME_PLAY);
Hero {
id: object::new(ctx),
hp: 100,
experience: 0,
sword: option::some(sword),
game_id: object::id(game),
}
}
Link code: https://github.com/CocDap/game_on_move/tree/step6 (opens in a new tab)
Step 7: Tạo quái vật Boar
Boar
: Lưu trữ thông tin quái vật -> Transfer Object- Chỉ có admin mới tạo được quái vật
// Admin tạo boar cho player
public entry fun send_boar(
game: &GameInfo,
admin: &mut GameAdmin,
hp: u64,
strength: u64,
player: address,
ctx: &mut TxContext
) {
assert!(object::id(game) == admin.game_id, EWRONG_GAME_PLAY);
admin.boars_created = admin.boars_created + 1;
// send boars to the designated player
transfer::transfer(
Boar { id: object::new(ctx), hp, strength, game_id: object::id(game) },
player
)
}
Link code: https://github.com/CocDap/game_on_move/tree/step7 (opens in a new tab)
Step 8: Player đánh quái vật boar
/// -------------------------------------------------------------------------------
/// --------------ENTRY FUNCTION LIÊN QUAN TỚI HÀNH ĐỘNG CỦA HERO------------------
/// -------------------------------------------------------------------------------
// Hàm đánh quái
public entry fun slay(game: &GameInfo, hero: &mut Hero, boar: Boar, ctx: &TxContext){
// Kiểm tra game ID của hero
assert!(object::id(game) == hero.game_id, EWRONG_GAME_PLAY);
// Kiểm tra game ID của Boar
assert!(object::id(game) == boar.game_id, EWRONG_GAME_PLAY);
// Destructure boar object
let Boar {id: boar_id, strength: boar_strength, hp, game_id: _} = boar;
let hero_strength = hero_strength(hero);
assert!(hero_strength !=0, EHERO_TIRED);
let mut boar_hp = hp;
let mut hero_hp = hero.hp;
// Tấn công boar cho đến khi HP của Boar còn 0
while (boar_hp > hero_strength) {
// đầu tiên hero attack trước
boar_hp = boar_hp - hero_strength;
// sau đó boar attack
assert!(hero_hp >= boar_strength, EBOAR_WON);
hero_hp = hero_hp - boar_strength;
};
// lưu lại HP của Hero sau khi tấn công boar
hero.hp = hero_hp;
// Nhận kinh nghiệm bằng lượng HP của boar sau khi đánh bại
hero.experience = hero.experience + hp;
// Tăng sức mạnh của Sword lên 1 đơn vị
if (option::is_some(&hero.sword)) {
level_up_sword(option::borrow_mut(&mut hero.sword), 1)
};
event::emit(BoarSlainEvent {
slayer_address: tx_context::sender(ctx),
hero: object::uid_to_inner(&hero.id),
boar: object::uid_to_inner(&boar_id),
game_id: object::id(game)
});
object::delete(boar_id);
}
/// -------------------------------------------------------------------------------
/// ---------------------HELPER FUNCTION CHO HÀM SLAY(ĐÁNH QUÁI)-------------------
/// -------------------------------------------------------------------------------
// Sức mạnh của Sword khi tấn công
public fun sword_strength(sword: &Sword): u64 {
sword.magic + sword.strength
}
// Sức mạnh của Hero khi tấn công
public fun hero_strength(hero: &Hero): u64 {
// Nếu hero có HP = 0 thì không thể attack
if (hero.hp == 0) {
return 0
};
// Nếu hero có sử dụng Sword -> lấy sức mạnh của Sword
let sword_strength = if (option::is_some(&hero.sword)) {
sword_strength(option::borrow(&hero.sword))
}
else {
0
};
// Sức mạnh của hero
(hero.experience * hero.hp) + sword_strength
}
// Tăng cấp cho Sword
public fun level_up_sword(sword: &mut Sword, amount: u64) {
sword.strength = sword.strength + amount;
}
Link code: https://github.com/CocDap/game_on_move/tree/step8 (opens in a new tab)
Step 9: Hàm tạo vật phẩm hồi máu
Potion
: Lưu trữ thông tin vật phẩm hồi máu -> Transfer Object- Chỉ có admin mới tạo được vật phẩm hồi máu
// Admin tạo potion (bình máu) cho player
public entry fun send_potion(
game: &GameInfo,
potency: u64,
player: address,
admin: &mut GameAdmin,
ctx: &mut TxContext
) {
assert!(object::id(game) == admin.game_id, EWRONG_GAME_PLAY);
admin.potions_created = admin.potions_created + 1;
// send potion to the designated player
transfer::transfer(
Potion { id: object::new(ctx), potency, game_id: object::id(game) },
player
)
}
Link code: https://github.com/CocDap/game_on_move/tree/step9 (opens in a new tab)
Step 10: Hàm liên quan tới vật phẩm trang bị
/// Phục hồi máu cho hero
public fun heal(hero: &mut Hero, potion: Potion) {
assert!(hero.game_id == potion.game_id, EWRONG_GAME_PLAY);
let Potion { id, potency, game_id: _ } = potion;
object::delete(id);
let new_hp = hero.hp + potency;
// maximum HP của hero là 1000
hero.hp = std::u64::min(new_hp, MAX_HP)
}
/// Trang bị New Sword cho Hero và return old sword
public fun equip_sword(hero: &mut Hero, new_sword: Sword): Option<Sword> {
option::swap_or_fill(&mut hero.sword, new_sword)
}
/// Tháo Sword ra khỏi trang bị của Hero
public fun remove_sword(hero: &mut Hero): Sword {
assert!(option::is_some(&hero.sword), ENO_SWORD);
option::extract(&mut hero.sword)
}
Link code: https://github.com/CocDap/game_on_move/tree/step10 (opens in a new tab)
Step 11: Tạo hàm lấy payment
- Chỉ có
admin
mới có thể lấy payment
/// -------------------------------------------------------------------------------
/// ---------------------ENTRY FUNCTION LIÊN QUAN TỚI PAYMENT----------------------
/// -------------------------------------------------------------------------------
public entry fun take_payment(admin: &GameAdmin, game: &mut GameInfo, ctx: &mut TxContext
) {
assert!(admin.game_id == object::id(game), ENOT_ADMIN);
let payment = coin::from_balance(balance::withdraw_all(&mut game.payments), ctx);
transfer::public_transfer(payment, tx_context::sender(ctx))
}
Link code: https://github.com/CocDap/game_on_move/tree/step11 (opens in a new tab)
Step 12: Viết test case
/// tests/hero_tests.move
let admin = @0xAD014;
let player = @0x0;
let mut scenario_val = test_scenario::begin(admin);
let scenario = &mut scenario_val;
// Run the create new game
test_scenario::next_tx(scenario, admin);
{
new_game(test_scenario::ctx(scenario));
};
// Tạo Hero cùng với Sword
test_scenario::next_tx(scenario, player);
{
let mut game = test_scenario::take_shared<GameInfo>(scenario);
let coin = coin::mint_for_testing(500, test_scenario::ctx(scenario));
acquire_hero(&mut game, coin, test_scenario::ctx(scenario));
test_scenario::return_shared(game);
};
// Admin tạo boar cho Player
test_scenario::next_tx(scenario, admin);
{
let game = test_scenario::take_shared<GameInfo>(scenario);
let game_ref = &game;
let mut admin_cap = test_scenario::take_from_sender<GameAdmin>(scenario);
send_boar(game_ref, &mut admin_cap, 10, 10, player, test_scenario::ctx(scenario));
test_scenario::return_to_sender(scenario, admin_cap);
test_scenario::return_shared(game);
};
// Player slays the boar!
test_scenario::next_tx(scenario, player);
{
let game = test_scenario::take_shared<GameInfo>(scenario);
let game_ref = &game;
let mut hero = test_scenario::take_from_sender<Hero>(scenario);
std::debug::print(&b"Before slaying boar, our hero is:".to_string());
std::debug::print(&hero);
let boar = test_scenario::take_from_sender<Boar>(scenario);
slay(game_ref, &mut hero, boar, test_scenario::ctx(scenario));
test_scenario::return_to_sender(scenario, hero);
test_scenario::return_shared(game);
};
test_scenario::next_tx(scenario, player);
{
let hero = test_scenario::take_from_sender<Hero>(scenario);
std::debug::print(&b"After slaying boar, our updated hero is:".to_string());
std::debug::print(&hero);
test_scenario::return_to_sender(scenario, hero);
};
// Take Payment Checking
test_scenario::next_tx(scenario, admin);
{
let game = test_scenario::take_shared<GameInfo>(scenario);
std::debug::print(&b"Before taking payment:".to_string());
std::debug::print(&game);
test_scenario::return_shared(game);
};
test_scenario::next_tx(scenario, admin);
{
let mut game = test_scenario::take_shared<GameInfo>(scenario);
let admin_game = test_scenario::take_from_sender<GameAdmin>(scenario);
take_payment(&admin_game, &mut game, test_scenario::ctx(scenario));
test_scenario::return_to_sender(scenario, admin_game);
test_scenario::return_shared(game);
};
test_scenario::next_tx(scenario, admin);
{
let game = test_scenario::take_shared<GameInfo>(scenario);
std::debug::print(&b"After taking payment:".to_string());
std::debug::print(&game);
test_scenario::return_shared(game);
};
test_scenario::end(scenario_val);
Link code: https://github.com/CocDap/game_on_move/tree/step12 (opens in a new tab)
Cách publish và chạy game thông qua SUI CLI
Lưu ý:
- Bạn cần phải có 2 account -> Account 1 cho admin, account 2 cho player
- Faucet coin SUI cho các account
- Khi bạn publish hay run game thì lưu ý phải thay đổi
packageId
vàobjectId
trong cli - Tham khảo thêm ở trên Suiscan để view được các thông tin on-chain
Trong trường hợp này, mình sử dụng nifty-alexandrite
cho Player
và lucid-sphene
cho Admin
╭───────────────────┬────────────────────────────────────────────────────────────────────┬────────────────╮
│ alias │ address │ active address │
├───────────────────┼────────────────────────────────────────────────────────────────────┼────────────────┤
│ nifty-alexandrite │ 0xb2ff9d4b13077deecb7e03e2041772abcbe4b7720f413f84264c60384cf29b5c │ │
│ lucid-sphene │ 0xd51d17a672dfd63b91c1c555542f8151126f5e0872b85553644730c2471fdf28 │ * │
╰───────────────────┴────────────────────────────────────────────────────────────────────┴────────────────╯
- Export biến
export ADMIN=0xd51d17a672dfd63b91c1c555542f8151126f5e0872b85553644730c2471fdf28
export PLAYER=0xb2ff9d4b13077deecb7e03e2041772abcbe4b7720f413f84264c60384cf29b5c
Step 1: Publish game
- Sử dụng
lucid-sphene
để publish game
sui client publish --gas-budget 100000000
- Kết quả
...
│ Published Objects: │
│ ┌── │
│ │ PackageID: 0x0816216c6f165ceb6125cd1f72b9185527f6534bf58f56e5c29575c95321c45b │
│ │ Version: 1 │
│ │ Digest: 6JGSUL8gUU648ZCi1Gv7XSStTBxwZ7C59jGgUtQSaxFJ │
│ │ Modules: hero │
│ └── │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
...
- Sử dụng EXPORT để lưu packageId
export PACKAGE_ID=0x0816216c6f165ceb6125cd1f72b9185527f6534bf58f56e5c29575c95321c45b
Step 2: Tạo new game
- Sử dụng
lucid-sphene
để tạo new game
sui client call --package $PACKAGE_ID --module hero --function new_game --gas-budget 100000000
- Kết quả
...
│ Created Objects: │
│ ┌── │
│ │ ObjectID: 0x72dfc389f24d0f63cce06b9502ba9cb8e0a9ce313962f8065efa1cdd2e2858a0 │
│ │ Sender: 0xd51d17a672dfd63b91c1c555542f8151126f5e0872b85553644730c2471fdf28 │
│ │ Owner: Shared( 289571933 ) │
│ │ ObjectType: 0x816216c6f165ceb6125cd1f72b9185527f6534bf58f56e5c29575c95321c45b::hero::GameInfo │
│ │ Version: 289571933 │
│ │ Digest: 3Ts3DZzBnhX6JAiEr16YjF5VXw9jyisL4eVMMq6eYmcZ │
│ └── │
│ ┌── │
│ │ ObjectID: 0x80099d4f44f6a013a0e6ec8668a619ff7880ab956278b883ac01cfe9e07864c3 │
│ │ Sender: 0xd51d17a672dfd63b91c1c555542f8151126f5e0872b85553644730c2471fdf28 │
│ │ Owner: Account Address ( 0xd51d17a672dfd63b91c1c555542f8151126f5e0872b85553644730c2471fdf28 ) │
│ │ ObjectType: 0x816216c6f165ceb6125cd1f72b9185527f6534bf58f56e5c29575c95321c45b::hero::GameAdmin │
│ │ Version: 289571933 │
│ │ Digest: 9T5FdpWZJozJkbNQRfyqSjVKcSjCgLRB6h35fTqRFvqA │
│ └──
...
- Object Id của GameInfo:
0x72dfc389f24d0f63cce06b9502ba9cb8e0a9ce313962f8065efa1cdd2e2858a0
export GAME_INFO=0x72dfc389f24d0f63cce06b9502ba9cb8e0a9ce313962f8065efa1cdd2e2858a0
- Object Id của GameAdmin:
0x80099d4f44f6a013a0e6ec8668a619ff7880ab956278b883ac01cfe9e07864c3
export GAME_ADMIN=0x80099d4f44f6a013a0e6ec8668a619ff7880ab956278b883ac01cfe9e07864c3
Step 3: Tạo hero
- Sử dụng
nifty-alexandrite
để tạo hero
sui client switch --address nifty-alexandrite
- Faucet để tạo 1 object coins mới hoặc sử dụng transfer coins (Bạn cần phải có 1 object coins mới)
sui client transfer-sui --to nifty-alexandrite --sui-coin-object-id 0xd9384d06b794e76383e5f798eb02c97d9a01525e598187b2c44bb9c6d7434e92 --amount 500000000 --gas-budget 100000000
- Sau khi tạo 1 object coin mới
╭────────────────────────────────────────────────────────────────────┬────────────────────┬──────────────────╮
│ gasCoinId │ mistBalance (MIST) │ suiBalance (SUI) │
├────────────────────────────────────────────────────────────────────┼────────────────────┼──────────────────┤
│ 0x240bc32f91d5ca0db1fe1e3dfa5ec9c0978956ebc9da371dd02f6d23813e8989 │ 500000000 │ 0.50 │
│ 0xf23a5e0ab3f054ac8762ef9b09d8b118f5168cc6c2a49a253f49a4cfeed50923 │ 179105192 │ 0.17 │
- Lưu object coin mới vào biến
export COIN=0x240bc32f91d5ca0db1fe1e3dfa5ec9c0978956ebc9da371dd02f6d23813e8989
- Tạo hero
sui client call --package $PACKAGE_ID --module hero --function acquire_hero --args $GAME_INFO $COIN --gas-budget 100000000
- Kết quả
│ Created Objects: │
│ ┌── │
│ │ ObjectID: 0x55291019b9bb75105ec5a4e0dc3643b1428c984b53a1f86ec4210e9082af28e2 │
│ │ Sender: 0xb2ff9d4b13077deecb7e03e2041772abcbe4b7720f413f84264c60384cf29b5c │
│ │ Owner: Account Address ( 0xb2ff9d4b13077deecb7e03e2041772abcbe4b7720f413f84264c60384cf29b5c ) │
│ │ ObjectType: 0x816216c6f165ceb6125cd1f72b9185527f6534bf58f56e5c29575c95321c45b::hero::Hero │
│ │ Version: 289571934 │
│ │ Digest: CbLiGhmacsxHZzM8AeiKPJYycTqcXRH22tkKaBwEx1KY
- Object Id của Hero:
0x55291019b9bb75105ec5a4e0dc3643b1428c984b53a1f86ec4210e9082af28e2
export HERO=0x55291019b9bb75105ec5a4e0dc3643b1428c984b53a1f86ec4210e9082af28e2
Step 4: Tạo boar
- Chỉ có
Admin
mới tạo Boar -> switch account sanglucid-sphene
sui client switch --address lucid-sphene
- Tạo bear
sui client call --package $PACKAGE_ID --module hero --function send_boar --args $GAME_INFO $GAME_ADMIN 10 1 $PLAYER --gas-budget 100000000
- Kết quả
...
Created Objects: │
│ ┌── │
│ │ ObjectID: 0x3a3675e0c58694cbc031f0dff5d22892fe97722f0e61bad9ab67df5b82eaf821 │
│ │ Sender: 0xd51d17a672dfd63b91c1c555542f8151126f5e0872b85553644730c2471fdf28 │
│ │ Owner: Account Address ( 0xb2ff9d4b13077deecb7e03e2041772abcbe4b7720f413f84264c60384cf29b5c ) │
│ │ ObjectType: 0x816216c6f165ceb6125cd1f72b9185527f6534bf58f56e5c29575c95321c45b::hero::Boar │
│ │ Version: 289571935 │
│ │ Digest: 4CQPs9Rcyc9ZtPR7xeMTk7uFsKAe2o5RJjB8oLAMeRwZ
...
-
Object Id của Boar:
0x3a3675e0c58694cbc031f0dff5d22892fe97722f0e61bad9ab67df5b82eaf821
-
Lưu object boar vào biến
export BOAR=0x3a3675e0c58694cbc031f0dff5d22892fe97722f0e61bad9ab67df5b82eaf821
Step 5: Đánh quái
- Sử dụng
nifty-alexandrite
để đánh quái
sui client switch --address nifty-alexandrite
- Call hàm đánh quái
sui client call --package $PACKAGE_ID --module hero --function slay --args $GAME_INFO $HERO $BOAR --gas-budget 100000000
- Kết quả
...
╭───────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Transaction Block Events │
├───────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ ┌── │
│ │ EventID: 8GtPubC3J3KMcwotB9An1Hg3bGWS3qPFbxpsZ7iTvfV3:0 │
│ │ PackageID: 0x0816216c6f165ceb6125cd1f72b9185527f6534bf58f56e5c29575c95321c45b │
│ │ Transaction Module: hero │
│ │ Sender: 0xb2ff9d4b13077deecb7e03e2041772abcbe4b7720f413f84264c60384cf29b5c │
│ │ EventType: 0x816216c6f165ceb6125cd1f72b9185527f6534bf58f56e5c29575c95321c45b::hero::BoarSlainEvent │
│ │ ParsedJSON: │
│ │ ┌────────────────┬────────────────────────────────────────────────────────────────────┐ │
│ │ │ boar │ 0x3a3675e0c58694cbc031f0dff5d22892fe97722f0e61bad9ab67df5b82eaf821 │ │
│ │ ├────────────────┼────────────────────────────────────────────────────────────────────┤ │
│ │ │ game_id │ 0x72dfc389f24d0f63cce06b9502ba9cb8e0a9ce313962f8065efa1cdd2e2858a0 │ │
│ │ ├────────────────┼────────────────────────────────────────────────────────────────────┤ │
│ │ │ hero │ 0x55291019b9bb75105ec5a4e0dc3643b1428c984b53a1f86ec4210e9082af28e2 │ │
│ │ ├────────────────┼────────────────────────────────────────────────────────────────────┤ │
│ │ │ slayer_address │ 0xb2ff9d4b13077deecb7e03e2041772abcbe4b7720f413f84264c60384cf29b5c │ │
│ │ └────────────────┴────────────────────────────────────────────────────────────────────┘ │
│ └── │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────╯
...
Step 6: Lấy payment
- Sử dụng
lucid-sphene
để lấy payment
sui client switch --address lucid-sphene
- Lấy payment
sui client call --package $PACKAGE_ID --module hero --function take_payment --args $GAME_ADMIN $GAME_INFO --gas-budget 100000000
- Kết quả
...
│ Created Objects: │
│ ┌── │
│ │ ObjectID: 0x6f14e050068c87b13ded32c4cd171f351e344362d8fd8fed826ddae8f8e69617 │
│ │ Sender: 0xd51d17a672dfd63b91c1c555542f8151126f5e0872b85553644730c2471fdf28 │
│ │ Owner: Account Address ( 0xd51d17a672dfd63b91c1c555542f8151126f5e0872b85553644730c2471fdf28 ) │
│ │ ObjectType: 0x2::coin::Coin<0x2::sui::SUI> │
│ │ Version: 289571936 │
│ │ Digest: 9rpiTJgqM3DDifmY6Bt4tgnNkn64ks7jkCfLTfKqSrAU │
│ └──
...