Publisher object là gì?
Trong bài viết này sẽ giới thiệu bạn về Publish object. Publisher Object như là proof chứng minh rằng keeper ấy là người đã deploy object.
fun init(witness: MY_MODULE, ctx: &mut TxContext) {
assert!(types::is_one_time_witness(&witness), ENotOneTimeWitness);
let publisher_object = package::claim(witness, ctx);
// Use or store the publisher object...
}
Mình lấy một ví dụ tại sao ta cần **Publisher Authority**
. Giả sử khi đọc sách, bạn không chỉ quan tâm đến nội dung mà còn cần quan tâm đến nguồn gốc của cuốn sách đó đúng không? Publisher trong sui move giống như ví dụ nhà xuất bản vậy để:
- Xác minh danh tính tác giả
- Kiểm duyệt nội dung
- Đảm bảo chất lượng và độ tin cậy
Khi chúng ta lấy Publisher Object thông qua smart contract và triển khai nó lên blockchain, các node đồng thuận sẽ xác minh để đảm bảo tính hợp pháp và duy nhất của NFTs đó. Thông qua Publisher, chúng ta có thể:
- Xác thực identity của người publish
- Control được version của contract
- Đảm bảo trust và khả năng xác minh metadata của NFT
Đây là ví dụ trong documentation:
module book::publisher;
use sui::package::{Self, Publisher};
/// Some type defined in the module.
public struct Book {}
/// The OTW for the module.
public struct PUBLISHER has drop {}
/// Uses the One Time Witness to claim the Publisher object.
fun init(otw: PUBLISHER, ctx: &mut TxContext) {
// Claim the Publisher object.
let publisher: Publisher = sui::package::claim(otw, ctx);
// Usually it is transferred to the sender.
// It can also be stored in another object.
transfer::public_transfer(publisher, ctx.sender())
}
Còn đây là ví dụ của mình. Mình sẽ code 2 module một cái tạo publisher cái kia sẽ có function để kiểm tra xem mình có phải là publisher không nhé:
module 0x0::owner {
use sui::tx_context::TxContext;
use sui::package;
public struct OWNER has drop {}
public struct ThisType {}
/// After the module is published, the sender will receive
fun init(otw: OWNER, ctx: &mut TxContext) {
package::claim_and_keep(otw, ctx);
}
}
module 0x0::type_owner {
use sui::object::{Self, UID};
use sui::tx_context::TxContext;
use sui::package::{Self, Publisher};
/// Trying to claim ownership of a type with a wrong `Publisher`.
const ENotOwner: u64 = 0;
/// Uses the `Publisher` object to check if the caller owns the type `T`.
public fun check_ownership<T>(
publisher: &Publisher, ctx: &mut TxContext
){
assert!(package::from_package<T>(publisher), ENotOwner);
}
}
Nếu chạy lệnh call sau khi publish:
sui client publish
sui client call --package $PACKAGE_ID --module type_owner --function check_ownership --args $Publisher_id --type-args $PACKAGE_ID::owner::ThisType
├───────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Digest: 4Twhdcj8rLZAq3Fgz4HY6pbGrFScHVokRSoxmeazW1fe │
│ Status: Success │
│ Executed Epoch: 588 │
│ Mutated Objects: │
│ ┌── │
│ │ ID: 0x1aaeb0b2a45bedc002ca7a5873ae0d66ea3095c2d394ef7642274a0d132b7ad2 │
│ │ Owner: Account Address ( 0x915c2d19ee5fde257693f25e6c2cabb04c25e7ae03932817d52e122258c88ddb ) │
│ │ Version: 110923739 │
│ │ Digest: HLtDgwCYkT9i1KTbvxhJdngrqE5NFQEoSg3jdFjQWJrU │
│ └── │
│ ┌── │
│ │ ID: 0x47d3cf4dc3c7df5682fc3b837816f5b03ae89baa3731ef442bc37394513495a6 │
│ │ Owner: Account Address ( 0x915c2d19ee5fde257693f25e6c2cabb04c25e7ae03932817d52e122258c88ddb ) │
│ │ Version: 110923739 │
│ │ Digest: HKvxoqZMRTSD8KMEZVasYec1ABDzUfNUXVWkRvEnm3DC │
│ └── │
│ Gas Object: │
│ ┌── │
│ │ ID: 0x1aaeb0b2a45bedc002ca7a5873ae0d66ea3095c2d394ef7642274a0d132b7ad2 │
│ │ Owner: Account Address ( 0x915c2d19ee5fde257693f25e6c2cabb04c25e7ae03932817d52e122258c88ddb ) │
│ │ Version: 110923739 │
│ │ Digest: HLtDgwCYkT9i1KTbvxhJdngrqE5NFQEoSg3jdFjQWJrU │
│ └── │
│ Gas Cost Summary: │
│ Storage Cost: 2842400 MIST │
│ Computation Cost: 1000000 MIST │
│ Storage Rebate: 2813976 MIST │
│ Non-refundable Storage Fee: 28424 MIST │
│ │
│ Transaction Dependencies: │
│ 6Hxx9k65j2tNTkicZwKoAuuZ8TdVGjYC5uPg1hTVPrX5 │
│ GHcAV2sA5LVxfQnz4RnDLPuat32CQmyuwov2wLsGXerG │
╰───────────────────────────────────────────────────────────────────────────────────────────────────╯
Trong phát triển ứng dụng, việc chứng minh publisher (nhà phát hành) là rất cần thiết. Điều này đặc biệt quan trọng trong tài sản số, nơi mà publisher có thể bật hoặc tắt các tính năng cho tài sản của họ. Publisher Object là một object được định nghĩa trong Move Network, cho phép publisher chứng minh quyền kiểm soát của họ đối với một type.
// File: sui-framework/sources/package.move
public struct Publisher has key, store {
id: UID,
package: String,
module_name: String,
}
Sử dụng Publisher Object như thế nào?
Publisher object có 2 chức năng chính để chứng minh quyền sở hữu của người publish đối với một type:
// Checks if the type is from the same module, hence the `Publisher` has the
// authority over it.
assert!(publisher.from_module<Book>(), 0);
// Checks if the type is from the same package, hence the `Publisher` has the
// authority over it.
assert!(publisher.from_package<Book>(), 0);
Publisher as Admin Role
Đối với các ứng dụng nhỏ hoặc các trường hợp sử dụng đơn giản, Publisher object có thể được sử dụng như một admin capability.
/// Some action in the application gated by the Publisher object.
public fun admin_action(cap: &Publisher, /* app objects... */ param: u64) {
assert!(cap.from_module<Book>(), ENotAuthorized);
// perform application-specific action
}
Vai trò của Publisher trong Sui
Publisher là yêu cầu bắt buộc cho một số tính năng trên Sui Network. Object Display chỉ có thể được tạo bởi Publisher, và TransferPolicy - một thành phần quan trọng của hệ thống Kiosk - cũng yêu cầu object Publisher để chứng minh quyền sở hữu của type.