接收物件 (Receiving as Object)
地址擁有的 物件狀態支援兩種類型的擁有者:帳戶和另一個物件。如果一個物件被轉移到另一個物件,Sui 提供了一種透過其擁有者的 UID 來「接收 (receive)」此物件的方法。
此功能也被稱為「轉移至物件 (Transfer to Object)」或 TTO。
定義
接收功能在 sui::transfer 模組中實作。它包含一個特殊的類型 Receiving(透過特殊的交易參數實例化),以及接收函式 receive(接收父物件的 UID)。
目前,transfer::receive 中的 T 受限於 內部約束 (Internal Constraint)。receive 的公開版本稱為 public_receive,與其他 [存儲函式 (storage functions)][storage-funs] 一樣,它要求 T 具有 store。
module sui::transfer;
// 基於 `Receiving` 參數的臨時封裝器。在交易區塊中作為特殊輸入提供。
// 注意:此類型必須明確匯入才能使用!
public struct Receiving<phantom T: key> has drop {
id: ID,
version: u64,
}
/// 從父物件 `UID` 透過特殊類型 `Receiving` 接收 `T`。
public fun receive<T: key>(parent: &mut UID, to_receive: Receiving<T>): T;
由於對 UID 類型的要求,接收操作無法在不提供存取權限或特殊接收實作的任意物件上執行。此功能應謹慎使用,並在受控環境下進行。
範例
作為「轉移」與「接收」的說明,考慮一個範例:PostOffice 允許註冊郵政信箱 (Post Box) 並向帳戶的郵政信箱發送物件。
module book::receiving;
use sui::derived_object;
use sui::transfer::Receiving; // 預設未匯入!
/// 用於建立衍生 `PostBox` 的基礎衍生物件。
public struct PostOffice has key { id: UID }
/// 具有衍生 UID 的物件,接收發送到某個位址的物件。
public struct PostBox has key { id: UID, owner: address }
/// 轉移功能。任何人都可以來 PostOffice 並發送到特定
/// 收件者的 PostBox。收件者可以從 `PostBox` 接收項目。
public fun send<T: key + store>(office: &PostOffice, parcel: T, recipient: address) {
let postbox = derived_object::derive_address(office.id.to_inner(), recipient);
transfer::public_transfer(parcel, postbox)
}
/// 接收包裹。需要發送者是 `PostBox` 的擁有者!
public fun receive<T: key + store>(
box: &mut PostBox,
to_receive: Receiving<T>,
ctx: &TxContext
): T {
assert!(box.owner == ctx.sender());
// 從 `PostBox` 接收 `to_receive`。
let parcel = transfer::public_receive(&mut box.id, to_receive);
parcel
}
/// 如果使用者還沒有宣告他們的 `PostBox`,就建立它。
/// 注意:這不是轉移資產的要求!
/// 甚至可以將包裹發送到未註冊的郵箱,詳見 `send` 實現。
public fun register_address(office: &mut PostOffice, ctx: &mut TxContext) {
transfer::share_object(PostBox {
id: derived_object::claim(&mut office.id, ctx.sender()),
owner: ctx.sender()
})
}
// 在模組發佈時建立一個 PostOffice。
fun init(ctx: &mut TxContext) {
transfer::share_object(PostOffice { id: object::new(ctx) });
}
使用場景
轉移至物件是一項強大的功能,它允許物件充當其他物件的擁有者。使用它的原因之一是可以在接收時執行額外的授權,例如上述範例中的 PostOffice 可以收取接收費用。
- 允許並行執行對多個物件的轉移,而無需在交易中引用它們;
- 父物件也可以被轉移,充當容器;
- 分類似於郵政信箱的應用程式,使用者只有在啟動帳戶後才能獲得資產;
- 帳戶抽象 (Account Abstraction) 類的應用程式,其中一個物件在模擬一個帳戶。
相關連結
- Sui 文件中的 轉移至物件 (Transfer to Object)
- sui::transfer 模組文件