Sui.

Bài viết

Chia sẻ kiến thức của bạn.

Tiền thưởng+15

Xavier.eth.
Jun 17, 2025
Hỏi đáp Chuyên Gia

Làm thế nào để các ràng buộc về khả năng tương tác với các trường động trong các bộ sưu tập không đồng nhất?

Tôi đang xây dựng một thị trường cần xử lý nhiều loại tài sản với các yêu cầu về khả năng khác nhau và tôi đã gặp một số câu hỏi cơ bản về hệ thống loại hình của Move. Tôi muốn lưu trữ các loại tài sản khác nhau trong cùng một bộ sưu tập, nhưng chúng có khả năng khác nhau:

  • NFT thông thường: key + store(có thể chuyển nhượng)
  • Mã thông báo Soulbound: key chỉ (không thể chuyển nhượng)
  • Tài sản tùy chỉnh với các hạn chế chuyển nhượng
public struct Marketplace has key {
    id: UID,
    listings: Bag,  // Want to store different asset types here
}

// This works for transferable assets
public fun list_transferable<T: key + store>(
    marketplace: &mut Marketplace,
    asset: T,
    price: u64
) { /* ... */ }

// But how to handle soulbound assets?
public fun list_soulbound<T: key>(  // No store ability
    marketplace: &mut Marketplace,
    asset_ref: &T,  // Can only take reference
    price: u64
) { /* How do I store metadata about this? */ }

Các câu hỏi chính:

  • Yêu cầu về khả năng: Khi sử dụngdynamic_field::add<K, V>(), Vcó luôn cần store lúc biên dịch không? Các loại bao bọc có thể giải quyết được điều này không?
  • Lưu trữ không đồng nhất: Một Túi duy nhất có thể lưu trữ các đối tượng với các bộ khả năng khác nhau (key + store + copyvskey + store) và xử lý chúng khác nhau khi chạy không?
  • An toàn kiểu: Vì trường động thực hiện xóa kiểu, làm thế nào để duy trì độ an toàn kiểu khi truy xuất giá trị? Mẫu để lưu trữ siêu dữ liệu loại là gì?
  • Mẫu nhân chứng: Các ràng buộc về khả năng hoạt động như thế nào với các loại bóng ma? Tôi có thể lưu trữ Asset<Type1>Asset<Type2>trong cùng một bộ sưu tập và trích xuất thông tin loại sau này không?

Xây dựng một hệ thống mà NFT, token soulbound và tài sản bị hạn chế đều cần chức năng thị trường nhưng với ngữ nghĩa chuyển khác nhau.

Tôi đã thử các loại bao bọc, nhiều bộ sưu tập cho mỗi bộ khả năng, lưu trữ siêu dữ liệu loại riêng biệt. Mỗi loại đều có sự đánh đổi giữa an toàn loại, chi phí khí đốt và độ phức tạp.

  • Sui
  • Architecture
0
5
Chia sẻ
Bình luận
.

Câu trả lời

5
harry phan.
Jun 18 2025, 03:58

Bạn đang gặp phải cốt lõi của hệ thống loại hình và khả năng của Move và bạn hoàn toàn đúng khi đặt ra những câu hỏi này khi thiết kế một thị trường không đồng nhất.

Đầu tiên, về hạn chế khả năng: bất kỳ giá trị nào bạn lưu trữ bằng dynamic_field: :add<K, V> () phải có khả năng lưu trữ tại thời điểm biên dịch. Đây là một quy tắc cứng trong Move: các giá trị không có lưu trữ đơn giản là không thể tồn tại trong bộ nhớ, cho dù trong trường động, Bảng hoặc các cấu trúc tương tự. Cố gắng gói một kiểu không phải cửa hàng trong một struct cũng sẽ không hiệu quả — việc di chuyển rất nghiêm ngặt ở đây. Nếu ngay cả một trường thiếu kho, toàn bộ giấy gói cũng sẽ mất kho. Vì vậy, thật không may, không có giải pháp bọc nào ở đây. Các tài sản có tính linh hoạt chỉ có khóa (và không có cửa hàng) sẽ bị loại trừ khỏi bất kỳ bộ sưu tập nào ghi vào bộ nhớ toàn cầu như Túi hoặc trường động. Điều này được ghi chép rõ ràng trong tài liệu về khả năng di chuyển.

Đối với việc lưu trữ các loại tài sản khác nhau trong cùng một bộ sưu tập: nếu tất cả đều thực hiện key + store, thì có, một Túi duy nhất có thể lưu trữ chúng, nhưng dưới mui xe, Move không thực hiện tính đa hình thực sự. Kiểu phải được biết tại thời điểm truy cập và Bag phải đồng nhất theo quan điểm của trình biên dịch. Điều này dẫn đến câu hỏi tiếp theo của bạn: làm thế nào để chúng tôi duy trì an toàn kiểu trong các trường động? Vì Move thực hiện xóa kiểu cho các bộ sưu tập này, nó sẽ không nhớ chính xác loại nào bên trong — bạn cần cung cấp ánh xạ. Một mô hình phổ biến là gói từng tài sản trong một cấu trúc bao gồm siêu dữ liệu như u8 enum hoặc TypeName, vì vậy khi bạn truy xuất đối tượng, bạn kiểm tra siêu dữ liệu và hạ thấp hoặc xử lý cho phù hợp. Không có RTTI kỳ diệu; bạn giả mạo nó với kỷ luật dữ liệu.

Bây giờ về các kiểu ma và mẫu nhân chứng — những mẫu này rất hữu ích cho sự an toàn trong thời gian biên dịch nhưng không cung cấp cho bạn sự nội tâm khi chạy. Vì vậy, có, bạn có thể tạo Asset và có T khác nhau, nhưng mọi phiên bản của Asset vẫn phải đáp ứng các hạn chế về khả năng của bộ sưu tập. Nếu bạn muốn lưu trữ cả Asset và Asset ở cùng một nơi, cả hai đều phải triển khai lưu trữ và SoulBoundToken có thể sẽ không. Bạn sẽ cần xử lý chúng theo cách khác nhau — có thể sử dụng tham chiếu hoặc chỉ lưu trữ siêu dữ liệu cho các tài sản không thể chuyển nhượng, thay vì cố gắng lưu trữ đối tượng.

Trong thiết kế thị trường của bạn, điều này có nghĩa là bạn có thể đang xem xét một chiến lược lai. Đối với các NFT thông thường và các tài sản có thể chuyển nhượng khác, bạn có thể sử dụng các trường đối tượng động hoặc Túi một cách tự do, miễn là chúng phù hợp với key + store. Đối với các tài sản có liên quan đến linh hồn, vốn chỉ là quan trọng, cách tốt nhất của bạn là lưu trữ tài liệu tham khảo và siêu dữ liệu được liên kết trong Túi siêu dữ liệu song song hoặc sử dụng loại danh sách tùy chỉnh không lưu trữ chính tài sản mà ghi lại sự tồn tại của nó thông qua ID và dữ liệu bổ sung. Nó phức tạp hơn, nhưng nó mang lại cho bạn sự linh hoạt để thực thi ngữ nghĩa chuyển giao đúng cách.

Tài liệu tham khảo

  1. https://github.com/MystenLabs/sui/blob/c7ec9546978b3c52b0c57bbdb9693f5068dd3383/external-crates/move/documentation/book/src/abilities.md
  2. https://github.com/sui-foundation/sui-move-intro-course/blob/92bb4986ad91c5ffd01c10c5b0d3bbbfa9d12507/unit-four/lessons/2_dynamic_fields.md
1
Câu trả lời hay nhất
Bình luận
.
Owen.
Owen4587
Jun 23 2025, 14:33

1. Các giá trị trong trường động có luôn cần khôngstore?

dynamic_field::addNếu bạn muốnlưu trữgiá trị trực tiếp trong một trường động (ví dụ: thông quastore), nó phải đáp ứng tất cả các khả năng theo yêu cầu của loại trường - bao gồm cả. Nếu Vkhông cóstore, bạn không thể đưa nó vào một trường động trực tiếp.

Nhưng đây là mẹo:

Bạncó thể quảcác kiểu như vậy bên trong một cấu trúc khác cóstore, ngay cả khi kiểu bên trong không có.

Ví dụ:

struct AssetWrapper<T: key> has store {
    inner: T,
}

Mặc dù Tchỉ cókey, có AssetWrapper<T>thể được lưu trữ bởi vì chính nó đã cóstore.

Bây giờ bạn có thể làm:

dynamic_field::add(&mut object, key, AssetWrapper { inner: soulbound_token });

Điều này cho phép bạn lưu trữ cả tài sản có thể chuyển nhượng và không thể chuyển nhượng dưới cùng một trừu tượng.


2. Một Túi duy nhất có thể lưu trữ các đối tượng với các bộ khả năng khác nhau không?

Câu trả lời ngắn gọn là:** có**, sử dụng giấy gói và kỹ thuật xóa kiểu. Nhưng có những đánh đổi.

Trong Move, bạn không thể trực tiếp có danh sách nhiều loại bê tông trừ khi chúng được bọc trong một thùng chứa chung.

Một cách tiếp cận tốt là sử dụng một bao bọc như:

struct AnyAsset has store {
    // Maybe include metadata or witness type info
    data: Vector<u8>,     // serialized representation?
    type_info: TypeInfo, // Type metadata
}

Hoặc tốt hơn, hãy sử dụng mã hóa enum kiểu biến thể (nếu được hỗ trợ bởi phương ngữ Move của bạn):

enum AssetType has store {
    Transferable(NFT),
    Soulbound(SoulboundToken),
    Restricted(RestrictedAsset),
}

Tuy nhiên, điều này đòi hỏi sự phù hợp đầy đủ và không mở rộng tốt trên các mô-đun.

Vì vậy, một lần nữa:** gói + trường động + loại siêu dữ liệu**linh hoạt hơn.


3. Làm thế nào để duy trì an toàn loại khi lấy?

Move thực hiệnloại xóa nhậptrong các trường động. Vì vậy, một khi bạn lấy một giá trị từ một trường động, bạn chỉ nhận được một giá trị của một loại nào đó V- nhưng bạn không biết Vnhững gì đang chạy.

Để giải quyết vấn đề này một cách an toàn, bạn cần:

  • Lưu trữloại siêu dữ liệucùng với giá trị.
  • Sử dụngmẫu nhân đầuhoặcnhúng thẻ kiểuđể xác nhận lại thông tin loại khi truy xuất.

Mẫu: Siêu dữ liệu loại lưu trữ

struct AssetWithMetadata<T: key> has store {
    value: T,
    type_info: TypeInfo,
}

Sau đó lưu trữ AssetWithMetadata<NFT>hoặc AssetWithMetadata<SoulboundToken>trong một trường động.

Khi bạn truy xuất, hãy kiểm tra type_infođối với loại mong đợi trước khi làm bất cứ điều gì không an toàn.


4. Mẫu nhân chứng & các loại bóng ma

Bạn hoàn toàn có thể sử dụng các kiểu ma làm nhân chứng để mã hóa hành vi, như khả năng chuyển nhượng.

Ví dụ:

struct Transferable; // marker type
struct NonTransferable; // marker type

struct Asset<T: drop + copy + store + key, Policy: phantom> has key, store {
    id: UID,
    policy: PhantomData<Policy>,
}

Sau đó:

type NFT = Asset<_, Transferable>;
type Soulbound = Asset<_, NonTransferable>;

Sau đó, bạn có thể viết logic như:

public fun transfer<T>(asset: Asset<T, Transferable>) {
    // allowed
}

public fun transfer<T>(_asset: Asset<T, NonTransferable>) {
    // disallowed
    abort();
}

Điều này cho phép bạn thực thi các quy tắc chuyển tiền trong thời gian biên dịch.

Nhưng để lưu trữ cả hai loại trong cùng một bộ sưu tập, bạn vẫn sẽ cần một gói:

struct AnyAsset has store {
    data: Vector<u8>,
    type_info: TypeInfo,
}

type_infoVà xử lý giải mã hóa một cách linh hoạt dựa trên.

5
Bình luận
.
0xduckmove.
Jun 18 2025, 04:11

Dưới đây là cách bạn có thể thiết kế thị trường Sui Move hỗ trợ cả tài sản có thể chuyển nhượng (NFT, chìa khoa+cửa hàng) và linh hoạt (chỉ dành cho khóa), đồng thời duy trì các hạn chế về khả năng xử lý và an toàn loại.

Yêu cầu khả năng cho trường động

Có, V phải có kho lưu trữ tại thời điểm biên dịch cho dynamic_field: :add<K, V> () và các bộ sưu tập tương tự.

  • lưu trữ là bắt buộc đối với bất kỳ giá trị nào được lưu trữ trong bộ nhớ toàn cầu, bao gồm các trường động và Bảng.
  • Kiểu wrapper không thể giải quyết vấn đề này: Nếu bạn gói một loại mà không có kho trong một struct, wrapper cũng không thể có kho, vì tất cả các trường phải có kho để struct có kho (nguồn).

Lưu trữ không đồng nhất trong túi

  • Túi (hoặc bất kỳ bộ sưu tập dựa trên trường động nào) chỉ có thể lưu trữ các loại đáp ứng các khả năng cần thiết.
  • Đối với trường đối tượng động, giá trị phải có key + store.
  • Đối với trường động, giá trị phải có kho lưu trữ.
  • Bạn không thể lưu trữ một loại chỉ có khóa (ví dụ: mã thông báo soulbound) trong Túi yêu cầu lưu trữ.
  • Đây là một hạn chế cơ bản của hệ thống loại Di chuyển (nguồn).

Loại an toàn và loại xóa

  • Các trường động bị xóa kiểu khi chạy. Bạn phải biết loại bạn muốn truy xuất tại thời điểm truy cập.
  • Mẫu cho loại an toàn:
  • Lưu trữ siêu dữ liệu loại (ví dụ: enum hoặc TypeName) cùng với giá trị.
  • Sử dụng cấu trúc wrapper bao gồm cả tài sản và thông tin loại của nó.
  • Khi truy xuất, hãy kiểm tra siêu dữ liệu trước khi casting.
  • Mẫu ví dụ:
  • Lưu danh sách {asset_type: u8,...} và sử dụng asset_type để xác định cách xử lý tài sản.

Mẫu nhân chứng và các loại bóng ma

  • Các loại Phantom và mô hình nhân chứng trợ giúp tại thời gian biên dịch, không phải thời gian chạy.
  • Bạn có thể sử dụng Tài sản cho các loại khác nhau, nhưng bạn vẫn cần đảm bảo tất cả T đều có khả năng cần thiết cho bộ sưu tập.
  • Khi chạy, bạn không thể trích xuất thông tin kiểu từ kiểu ảo; bạn phải lưu trữ siêu dữ liệu rõ ràng (nguồn).
  1. Thiết kế thị trường cho các loại tài sản hỗn hợp
  • Tài sản có thể chuyển nhượng (NFT): Sử dụng khóa + lưu trữ, lưu trữ trong các trường đối tượng động hoặc Túi.

  • Mã thông báo Soulbound (chỉ khóa): Không thể được lưu trữ trong các trường động hoặc Túi yêu cầu lưu trữ. Bạn phải xử lý chúng một cách riêng biệt, ví dụ, bằng cách chỉ lưu trữ siêu dữ liệu hoặc tham chiếu (không phải chính đối tượng).

  • Tài sản tùy chỉnh với các hạn chế: Miễn là chúng có khóa + cửa hàng, bạn có thể lưu trữ chúng. Nếu không, bạn cần một đường dẫn xử lý riêng biệt.

  • Tất cả các giá trị trong trường động hoặc Túi phải có kho lưu trữ (và khóa cho trường đối tượng động).

  • Bạn không thể lưu trữ các loại chỉ có khóa trong các bộ sưu tập này.

  • Kiểu an toàn khi chạy yêu cầu siêu dữ liệu rõ ràng.

  • Các loại phantom/mô hình nhân chứng trợ giúp tại thời gian biên dịch, không phải thời gian chạy.

2
Bình luận
.
md rifat hossen.
Jun 19 2025, 17:11

Cảm ơn bạn Xavier.eth cho câu hỏi kỹ thuật và chu đáo này. Dưới đây là đóng góp của tôi liên quan đến hạn chế khả năng và lĩnh vực động trong Sui Move:

✅** Có, bất kỳ giá trị (V) nào được sử dụng trong dynamic_field::add<K, V>()phải có storekhả năng.** Điều này được thực thi nghiêm ngặt trong các kiểm tra thời gian biên dịch của Move. Ngay cả việc gói một giá trị không lưu trữ bên trong một struct cũng không giúp ích gì — nếu bất kỳ trường nào thiếustore, toàn bộ struct cũng sẽ mất nó.

key + store✅** Có thể lưu trữ các tài sản không đồng nhất với các khả năng khác nhau, nhưng chỉ trong điều kiện hạn chế rằng tất cả các tài sản trong lĩnh vực động nhạc/Túi phải đáp ứng cùng một bộ khả năng**(thông thường).

🔒** Không thể lưu trữ trực tiếp các tài sản có linh hồn chỉ keycó khả năng được lưu trữ trực tiếp**trong các bộ sưu tập như vậy. Thay vào đó, bạn có thể:

  • Lưu trữ** chỉ siêu dữ liệu**(ID, loại enum, v.v.)
  • Sử dụng bản đồ song song như dynamic_field::add<AssetID, Metadata>đối với các loại soulbound.
  • Giữ một sổ đăng ký dựa trên tham chiếu theo dõi danh sách tài sản có liên quan đến linh hồn mà không lưu trữ toàn bộ đối tượng.

🧩** Các loại phantomgiúpchỉ tại thời điểm biên lịch**. Bạn vẫn sẽ cần siêu dữ liệu kiểu thời gian chạy rõ ràng cho logic truy xuất thực tế.

🚀** Kiến trúc lai được đề xuất**:

  • Bag<AssetID, TransferableAsset>đối với tài sản có store
  • dành Map<AssetID, SoulboundMetadata>cho các loại chỉ có khóa
  • AssetWrappercấu trúc với type_idhoặc u8 asset_typeđể xác định loại khi chạy

Cảm ơn một lần nữa! Tôi mong được thấy thị trường này phát triển!

— md rifat hossen

2
Bình luận
.
24p30p.
24p30p2042
Jul 9 2025, 05:17

Nếu bạn đang xây dựng một thị trường hỗ trợ nhiều loại tài sản với các khả năng khác nhau trong Sui Move, thách thức chính là cáchgiới hạn về khả năngcủa Move tương tác vớitrường độngvà dữ liệu không đồng nhất. Bạn không thể trực tiếp lưu trữ các giá trị mà không có storekhả năng, vì vậy có — khi bạn sử dụngdynamic_field::add<K, V>(), giá trị Vphải có storekhả năng tại thời điểm biên dịch. storeĐiều này có nghĩa là bạn không thể trực tiếp lưu trữ thứ gì đó giống như token soulbound trừ khi nó được gói trong một loại có. Để giải quyết vấn đề này, bạn có thể sử dụngcấu trúc wrapperchứa siêu dữ liệu về tài sản hoặc ID tham chiếu trong khi đáp ứng các khả năng cần thiết. Ví dụ: một SoulboundListing<T: key>wrapper có thể chỉ chứa một tham chiếu hoặc siêu dữ liệu, không phải đối tượng đầy đủ. Đối với lưu trữ không đồng nhất, một Baghoặc Tablechỉ có thể lưu trữ một loại cho mỗi phiên bản, nhưng bạn có thể làm cho nó hoạt động bằng cách gói nội dung theo kiểu tùy chỉnh giống như enum hoặc sử dụng các kiểu ảo giống đặc điểm để mô phỏng thông tin kiểu. Bạn sẽ không nhận được tính đa hình gốc, nhưng bạn có thể theo dõi các loại tài sản bằng cách gắn thẻ thủ công hoặc sử dụng** mẫu chứng thức**, trong đó các kiểu ảo và phân biệt thời gian chạy giúp bạn mô phỏng sự phân tách cấp loại. Nếu bạn đang sử dụng Asset<T>cho từng loại tài sản T1và cả hai đều T2là ảo, thì có — bạn có thể lưu trữ Asset<T1>Asset<T2>trong một vùng chứa dùng chung bằng cách nhập xóa vào một bao bọc chung. Sau đó, bạn sẽ cần lưu trữ thông tin loại riêng biệt (như một type_idtrường) để khớp chính xác khi đọc. Đó là một hành động cân bằng giữa** an toàn kiểu phẩm**,** hiệu quả khí độ phức tạp của thiết kế**. Sử dụng các bộ sưu tập riêng biệt cho mỗi loại tài sản là dễ dàng nhất để đảm bảo an toàn, nhưng các loại bao bọc và siêu dữ liệu được lập chỉ mục có thể mở rộng hơn khi bạn muốn tính linh hoạt. Bạn sẽ cần phải lựa chọn dựa trên việc chi phí gas hay sự đơn giản của nhà phát triển có quan trọng hơn đối với trường hợp sử dụng của bạn hay không.

1
Bình luận
.

Bạn có biết câu trả lời không?

Hãy đăng nhập và chia sẻ nó.

Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.

621Bài viết1665Câu trả lời
Sui.X.Peera.

Kiếm phần của bạn từ 1000 Sui

Tích lũy điểm danh tiếng và nhận phần thưởng khi giúp cộng đồng Sui phát triển.

Chiến dịch phần thưởngTháng Tám