Sui.

Beitrag

Teile dein Wissen.

Prämie+15

Xavier.eth.
Jun 17, 2025
Experten Q&A

Wie interagieren Fähigkeitsbeschränkungen mit dynamischen Feldern in heterogenen Sammlungen?

Ich baue einen Marktplatz auf, der mit mehreren Asset-Typen mit unterschiedlichen Fähigkeitsanforderungen umgehen muss, und ich bin auf einige grundlegende Fragen zum Typensystem von Move gestoßen. Ich möchte verschiedene Asset-Typen in derselben Sammlung speichern, aber sie haben unterschiedliche Fähigkeiten:

  • Reguläre NFTs: key + store(übertragbar)
  • key Nur Soulbound-Token (nicht übertragbar)
  • Benutzerdefinierte Vermögenswerte mit Übertragungsbeschränkungen
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? */ }

Die wichtigsten Fragen:

  • Anforderungen an die Fähigkeiten: Wird bei der Verwendung dynamic_field::add<K, V>()``Vimmer store zur Kompilierzeit benötigt? Können Wrapper-Typen das umgehen?
  • Heterogener Speicher: Kann ein einziger Beutel Objekte mit unterschiedlichen Fähigkeiten (key + store + copyvskey + store) speichern und sie zur Laufzeit unterschiedlich handhaben?
  • Typsicherheit: Da dynamische Felder eine Typlöschung durchführen, wie kann ich die Typsicherheit beim Abrufen von Werten gewährleisten? Nach welchem Muster werden Typmetadaten gespeichert?
  • Zeugenmuster: Wie funktionieren Fähigkeitsbeschränkungen bei Phantomtypen? Kann ich Asset<Type1>``Asset<Type2>Informationen zum Typ speichern und in derselben Sammlung speichern und zu einem späteren Zeitpunkt extrahieren?

Aufbau eines Systems, in dem NFTs, Soulbound-Token und eingeschränkte Vermögenswerte alle Marktplatzfunktionen benötigen, jedoch mit unterschiedlicher Übertragungssemantik.

Ich habe Wrapper-Typen ausprobiert, mehrere Sammlungen pro Fähigkeitssatz, separate Typ-Metadatenspeicherung. Jede hat Kompromisse zwischen Typsicherheit, Gaskosten und Komplexität.

  • Sui
  • Architecture
0
5
Teilen
Kommentare
.

Antworten

5
harry phan.
Jun 18 2025, 03:58

Sie stoßen auf den Kern des Typ- und Fähigkeitssystems von Move und Sie haben absolut Recht, wenn Sie diese Fragen bei der Gestaltung eines heterogenen Marktplatzes aufwerfen.

Zunächst zu den Fähigkeitsbeschränkungen: Jeder Wert, den Sie mit dynamic_field: :add<K, V> () speichern, muss die Fähigkeit haben, zur Kompilierzeit zu speichern. Dies ist eine harte Regel in Move: Werte ohne Speicher können einfach nicht im Speicher gespeichert werden, egal ob in dynamischen Feldern, Tabellen oder ähnlichen Konstrukten. Der Versuch, einen Nichtspeichertyp in eine Struktur einzuschließen, funktioniert auch nicht — Move ist hier strikt. Wenn auch nur ein Feld keinen Speicherplatz hat, verliert auch der gesamte Wrapper an Speicherplatz. Leider gibt es hier keinen Wrapper-Workaround. Soulbound-Assets, die nur einen Schlüssel (und keinen Speicher) enthalten, sind von jeder Sammlung ausgeschlossen, die in einen globalen Speicher schreibt, wie z. B. ein Bag oder ein dynamisches Feld. Dies ist in der Dokumentation zu den Move-Fähigkeiten gut dokumentiert.

Was das Speichern verschiedener Asset-Typen in derselben Sammlung angeht: Wenn sie alle Key + Store implementieren, dann ja, ein einziger Bag kann sie speichern, aber unter der Haube macht Move keinen echten Polymorphismus. Der Typ muss zum Zeitpunkt des Zugriffs bekannt sein, und der Bag muss aus Sicht des Compilers homogen sein. Dies führt zu Ihrer nächsten Frage: Wie gewährleisten wir die Typsicherheit in dynamischen Feldern? Da Move die Typen für diese Sammlungen löscht, merkt es sich nicht, welcher genaue Typ darin enthalten ist — Sie müssen die Zuordnung angeben. Ein gängiges Muster besteht darin, jedes Asset in eine Struktur einzuschließen, die Metadaten wie eine u8-Aufzählung oder einen TypeName enthält. Wenn Sie das Objekt abrufen, überprüfen Sie die Metadaten und stufen sie entsprechend herunter oder behandeln sie entsprechend. Es gibt kein magisches RTTI; Sie täuschen es mit Datendisziplin vor.

Nun zu Phantomtypen und Zeugenmustern — diese sind hilfreich für die Sicherheit bei der Kompilierung, bieten Ihnen aber keinen Einblick in die Laufzeit. Also ja, Sie können Asset erstellen und T variieren lassen, aber jede Instanziierung von Asset muss trotzdem die Leistungsbeschränkungen der Sammlung erfüllen. Wenn Sie sowohl Asset als auch Asset am selben Ort speichern möchten, müssen beide den Speicher implementieren, und SoulBoundToken wird das wahrscheinlich nicht tun. Sie müssen diese unterschiedlich handhaben — möglicherweise verwenden Sie Referenzen oder speichern Sie nur Metadaten für nicht übertragbare Assets, anstatt zu versuchen, das Objekt zu speichern.

In Ihrem Marktplatz-Design bedeutet das, dass Sie wahrscheinlich nach einer hybriden Strategie suchen. Für reguläre NFTs und andere übertragbare Assets kannst du dynamische Objektfelder oder Bags frei verwenden, solange sie dem Key+Store entsprechen. Für soulbound-Assets, bei denen es sich nur um wichtige Assets handelt, ist es am besten, Referenzen und zugehörige Metadaten in einer parallelen Metadatentasche zu speichern oder einen benutzerdefinierten Auflistungstyp zu verwenden, der das Asset selbst nicht speichert, sondern dessen Existenz über ID und ergänzende Daten aufzeichnet. Es ist komplexer, bietet Ihnen aber die Flexibilität, die Übertragungssemantik ordnungsgemäß durchzusetzen.

Referenzen

  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
Beste Antwort
Kommentare
.
Owen.
Owen4587
Jun 23 2025, 14:33

1. storeMüssen Werte in dynamischen Feldern immer benötigt werden?

dynamic_field::addWenn Sie den Wert direkt in einem dynamischen Feld (z. B. viastore)speichernmöchten, muss er alle für den Feldtyp erforderlichen Fähigkeiten erfüllen — einschließlich. Wenn Vdies nicht der Fall iststore, können Sie ihn nicht direkt in ein dynamisches Feld einfügen.

Aber hier ist der Trick:

Siekönnensolche Typen in eine andere Struktur einschließen, die das hatstore, auch wenn der innere Typ das nicht tut.

Beispiel:

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

Auch wenn es Tnur hatkey, AssetWrapper<T>kann gespeichert werden, weil es selbst hatstore.

Jetzt kannst du Folgendes tun:

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

Auf diese Weise können Sie sowohl übertragbare als auch nicht übertragbare Vermögenswerte unter derselben Abstraktion speichern.


#2 Kann eine einzelne Tasche Gegenstände mit unterschiedlichen Fähigkeiten verstauen?

Die kurze Antwort lautet:ja, wobei Wrapper und Tipplöschtechniken verwendet werden. Aber es gibt Kompromisse.

In Move können Sie nicht direkt eine Liste mit mehreren konkreten Typen haben, es sei denn, sie sind in einen generischen Container verpackt.

Ein guter Ansatz ist die Verwendung eines Wrappers wie:

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

Oder noch besser, verwende eine Enum-Kodierung im Variantenstil (sofern dies von deinem Move-Dialekt unterstützt wird):

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

Dies erfordert jedoch ein umfassendes Matching und lässt sich nicht gut zwischen den Modulen skalieren.

Also nochmal:Wrapping + dynamische Felder + Typ Metadatenist flexibler.


#3. Wie kann die Typsicherheit beim Abrufen gewahrt werden?

Move führt in dynamischen FeldernTyplöschungdurch. Sobald Sie also einen Wert aus einem dynamischen Feld abrufen, erhalten Sie nur einen Wert irgendeines Typs V— aber Sie wissen nicht, was zur Laufzeit der Wert Vist.

Um dies sicher zu lösen, müssen Sie:

  • Speichern Sie neben dem WertTyp-Metadaten.
  • Verwenden Sie einZeugenmusteroderTyp-Tag-Einbettung, um Typinformationen beim Abrufen wieder einzufügen.

Muster: Typ-Metadaten speichern

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

Dann speichern AssetWithMetadata<NFT>oder AssetWithMetadata<SoulboundToken>in einem dynamischen Feld.

Überprüfen Sie beim Abrufen type_infoden erwarteten Typ, bevor Sie etwas Unsicheres tun.


#4 Zeugenmuster und Phantomtypen

Sie können auf jeden Fall Phantomtypen als Zeugen verwenden, um Verhalten wie Übertragbarkeit zu kodieren.

Zum Beispiel:

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>,
}

Dann:

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

Sie können dann Logik schreiben wie:

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

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

Auf diese Weise können Sie Übertragungsregeln während der Kompilierung durchsetzen.

Aber um beide Typen in derselben Sammlung zu speichern, brauchst du immer noch einen Wrapper:

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

type_infoUnd behandeln Sie die Deserialisierung dynamisch auf der Grundlage von.

5
Kommentare
.
0xduckmove.
Jun 18 2025, 04:11

So können Sie einen Sui Move-Marktplatz entwerfen, der sowohl übertragbare (NFTs, Schlüssel + Store) als auch seelengebundene (nur Schlüssel) Assets unterstützt und gleichzeitig die Typsicherheit und die Einschränkungen der Bedienbarkeit beibehält.

Anforderungen an die Fähigkeiten dynamischer Felder

Ja, V muss zur Kompilierzeit einen Speicher für dynamic_field: :add<K, V> () und ähnliche Sammlungen haben.

  • Store ist für jeden Wert erforderlich, der im globalen Speicher gespeichert werden soll, einschließlich dynamischer Felder und Tabellen.
  • Wrapper-Typen können das nicht umgehen: Wenn Sie einen Typ ohne Speicher in eine Struktur einschließen, kann der Wrapper auch keinen Speicher haben, da alle Felder einen Speicher haben müssen, damit die Struktur einen Speicher hat (source).

Heterogener Speicher in einer Tasche

  • In einer Tasche (oder einer anderen dynamischen, feldbasierten Sammlung) können nur Typen aufbewahrt werden, die die erforderlichen Fähigkeiten erfüllen.
  • Bei dynamischen Objektfeldern muss für den Wert der Schlüssel + gespeichert sein.
  • Für dynamische Felder muss der Wert gespeichert sein.
  • Du kannst einen Typ, der nur einen Schlüssel enthält (z. B. ein Soulbound-Token), nicht in einer Tasche speichern, die gespeichert werden muss.
  • Dies ist eine grundlegende Einschränkung des Move-Typsystems (source).

Tippsicherheit und Typlöschung

  • Dynamische Felder werden zur Laufzeit typgelöscht. Sie müssen den Typ kennen, den Sie beim Zugriff abrufen möchten.
  • Muster für die Typsicherheit:
  • Speichern Sie Typmetadaten (z. B. eine Aufzählung oder TypeName) neben dem Wert.
  • Verwenden Sie eine Wrapper-Struktur, die sowohl das Asset als auch dessen Typinformationen enthält.
  • Überprüfen Sie beim Abrufen die Metadaten vor dem Casting.
  • Beispielmuster:
  • Speichern Sie Listing {asset_type: u8,...} und verwenden Sie asset_type, um zu bestimmen, wie mit dem Asset umgegangen werden soll.

Zeugenmuster und Phantomtypen

  • Phantomtypen und das Witness-Pattern helfen bei der Kompilierung, nicht bei der Laufzeit.
  • Sie können Asset für verschiedene Typen verwenden, müssen aber trotzdem sicherstellen, dass alle T über die erforderlichen Fähigkeiten für die Sammlung verfügen.
  • Zur Laufzeit können Sie keine Typinformationen aus einem Phantomtyp extrahieren; Sie müssen explizite Metadaten speichern (source).
  1. Marktplatz-Design für gemischte Anlagetypen
  • Übertragbare Vermögenswerte (NFTs): Verwenden Sie Schlüssel und speichern Sie sie in dynamischen Objektfeldern oder Taschen.

  • Soulbound-Token (nur Schlüssel): Können nicht in dynamischen Feldern oder Taschen gespeichert werden, die aufbewahrt werden müssen. Du musst sie separat behandeln, z. B. indem du nur Metadaten oder Referenzen speicherst (nicht das Objekt selbst).

  • Benutzerdefinierte Assets mit Einschränkungen: Solange für sie der Schlüssel + gespeichert ist, können Sie sie speichern. Wenn nicht, benötigen Sie einen separaten Behandlungspfad.

  • Alle Werte in dynamischen Feldern oder Bags müssen einen Speicher (und einen Schlüssel für dynamische Objektfelder) haben.

  • In diesen Sammlungen können Sie keine Typen speichern, die nur Schlüssel enthalten.

  • Für die Typsicherheit zur Laufzeit sind explizite Metadaten erforderlich.

  • Hilfe bei Phantomtypen/Zeugenmustern zur Kompilierzeit, nicht zur Laufzeit.

2
Kommentare
.
md rifat hossen.
Jun 19 2025, 17:11

Vielen Dank Xavier.eth für diese durchdachte und technische Frage. Hier ist mein Beitrag zu Fähigkeitsbeschränkungen und dynamischen Feldern in Sui Move:

VJa, jeder Wert (dynamic_field::add<K, V>()), der in verwendet wird, storemuss eine Fähigkeit haben. Dies wird bei den Kompilierzeitprüfungen von Move strikt durchgesetzt. Selbst das Einschließen eines Werts, der nicht gespeichert ist, in eine Struktur hilft nicht — wenn ein Feld fehltstore, verliert es auch die gesamte Struktur.

key + storeDas Speichern heterogener Vermögenswerte mit unterschiedlichen Fähigkeiten ist möglich, aber nur unter der Bedingung, dass alle Vermögenswerte im dynamischen Feld/den dynamischen Taschen den gleichen Fähigkeitssatz erfüllen müssen(in der Regel).

🔒Seelengebundene Vermögenswerte, die nur keyFähigkeiten besitzen, können nicht direkt in solchen Sammlungen gespeichert werden. Stattdessen kannst du:

  • Speicherenur Metadaten(ID, Typ enum usw.) dynamic_field::add<AssetID, Metadata>- Benutze ein paralleles Mapping wie bei seelengebundenen Typen.
  • Führe eine referenzbasierte Registry, die Soulbound-Asset-Listings nachverfolgt, ohne das gesamte Objekt zu speichern.

🧩Phantomtypenhelfennur bei der Kompilierzeit. Für die eigentliche Abruflogik benötigen Sie weiterhin explizite Metadaten vom Runtime-Typ.

🚀Vorgeschlagene Hybridarchitektur: Bag<AssetID, TransferableAsset>- für Vermögenswerte mit store

  • Map<AssetID, SoulboundMetadata>für Typen, die nur Schlüssel enthalten
  • AssetWrapperStruktur mit type_idoder u8 asset_typezur Typidentifizierung zur Laufzeit

Nochmals vielen Dank! Ich freue mich darauf, zu sehen, wie sich dieser Marktplatz weiterentwickelt!

— Herr Rifat Hossen

2
Kommentare
.
24p30p.
24p30p2042
Jul 9 2025, 05:17

Wenn Sie einen Marktplatz aufbauen, der mehrere Asset-Typen mit unterschiedlichen Fähigkeiten in Sui Move unterstützt, besteht die größte Herausforderung darin, wie dieFähigkeitseinschränkungenvon Move mitdynamischen Feldernund heterogenen Daten interagieren. store``dynamic_field::add<K, V>()``VOhne die Fähigkeit können Sie Werte nicht direkt speichernstore, also ja — wenn Sie sie verwenden, muss der Wert bei der Kompilierung über die Fähigkeit verfügen. storeDas bedeutet, dass Sie so etwas wie ein Soulbound-Token nicht direkt speichern können, es sei denn, es ist in einen Typ eingebunden, der es hat. Um dies zu umgehen, können SieWrapper-Strukturenverwenden, die Metadaten über das Asset oder eine Referenz-ID enthalten und gleichzeitig die erforderlichen Fähigkeiten erfüllen. Ein SoulboundListing<T: key>Wrapper kann beispielsweise nur eine Referenz oder Metadaten enthalten, nicht das vollständige Objekt. Bei heterogenem Speicher Bag``Tablekann ein oder nur einen Typ pro Instanziierung speichern, aber Sie können dafür sorgen, dass dies funktioniert, indem Sie Assets in einen aufzählungsähnlichen benutzerdefinierten Typ einschließen oder merkmalsähnliche Phantomtypen verwenden, um Typinformationen zu simulieren. Sie erhalten zwar keinen systemeigenen Polymorphismus, aber Sie können Asset-Typen mit manuellem Tagging verfolgen oder dasWitness-Musterverwenden, bei dem Sie mithilfe von Phantomtypen und Laufzeitdiskriminanten die Trennung auf Typebene simulieren können. Asset<T>``T1Wenn Sie T2für jeden Asset-Typ verwenden und beide ein Asset<T1>``Asset<T2>Phantom sind, dann ja — Sie können und in einem gemeinsam genutzten Container speichern, indem Sie den Typ in einem gemeinsamen Wrapper löschen. Sie müssen die Typinformationen dann separat speichern (wie ein type_idFeld), damit sie beim Lesen korrekt zugeordnet werden. Es ist ein Balanceakt zwischenTypsicherheit,GaseffizienzundKonstruktionskomplexität. Die Verwendung separater Sammlungen pro Asset-Typ ist aus Sicherheitsgründen am saubersten, aber Wrapper-Typen und indizierte Metadaten sind besser skalierbar, wenn Sie Flexibilität wünschen. Sie müssen je nachdem, ob die Gaskosten oder die Einfachheit des Entwicklers für Ihren Anwendungsfall wichtiger sind, eine Auswahl treffen.

1
Kommentare
.

Weißt du die Antwort?

Bitte melde dich an und teile sie.

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

621Beiträge1665Antworten
Sui.X.Peera.

Verdiene deinen Anteil an 1000 Sui

Sammle Reputationspunkte und erhalte Belohnungen für deine Hilfe beim Wachstum der Sui-Community.

BelohnungskampagneAugust