Sui.

Publication

Partagez vos connaissances.

Owen.
Owen1185
Jun 11, 2025
Questions et Réponses avec des Experts

Comment mettre à jour la clé d'un marchand dans ObjectTable lorsqu'elle change dans la structure ?

Bonjour à tous, je commence tout juste à écrire des contrats intelligents et je travaille sur mon tout premier projet. J'adorerais avoir de l'aide pour résoudre un problème sur lequel je suis bloqué.

Jusqu'à présent, j'ai créé une Merchantstructure qui ressemble à ceci : - id: un identifiant unique (UID) - owner: l'adresse du commerçant - key: une chaîne utilisée comme clé unique - balance: un u64 représentant leur équilibre

J'ai également créé une MerchantRegistrystructure pour gérer tous les marchands : - id: un autre UID - merchant_to_address: et ObjectTable<address, Merchant>mappage des adresses vers les commerçants - merchant_to_key: et des ObjectTable<String, Merchant>clés de mappage pour les commerçants

Je veux pouvoir rechercher un marchand soit par sonadresse, soit par saclé.

Lorsqu'un utilisateur met à jour sa clé dans la Merchantstructure, la modification ne met pas automatiquement à jour la clé dans la merchant_to_keytable. Cela signifie que l'ancienne clé pointe toujours vers le marchand, qui casse les objets.

J'ai essayé de supprimer l'entrée du tableau et de la réinsérer avec la nouvelle clé, mais je continue de rencontrer des erreurs telles que :

« Impossible d'ignorer les valeurs sans possibilité de suppression »

Je suis presque sûr qu'il s'agit d'une erreur de débutant, mais je n'ai trouvé nulle part d'explication ou de solution claire. Existe-t-il un moyen approprié de gérer la mise à jour de la clé à la fois dans la structure et dans la table de recherche ?

  • Sui
  • Move
5
6
Partager
Commentaires
.

Réponses

6
HaGiang.
Jul 23 2025, 15:44

Dans Sui Move, les objets sont des « ressources » par défaut, ce qui signifie qu'ils ne peuvent pas être dupliqués ou supprimés accidentellement. Ceci est appliqué par un système de types dans lequel les structures peuvent être supprimées (ce qui signifie qu'elles peuvent être supprimées si elles sortent de la portée) ou non.

Votre structure Merchant n'a probablement pas la capacité de suppression car elle contient un UID. Les UID sont des identifiants uniques pour les objets sur Sui. Ils sont conçus pour empêcher la suppression ou la duplication accidentelles de ces objets. Si un objet contient un UID, il ne peut généralement pas être supprimé.

Lorsque vous essayez de supprimer une entrée d'un ObjectTable, la fonction de suppression renvoie la valeur (l'objet Merchant dans ce cas). Si vous n'attribuez pas cette valeur renvoyée à une variable ou si vous ne la transmettez pas à une autre fonction qui la consomme, Move suppose que vous essayez de l' « ignorer » ou de la « supprimer ». Étant donné que votre structure Merchant n'a pas la capacité de suppression, cette action est interdite, ce qui entraîne l'erreur « Impossible d'ignorer les valeurs sans capacité de suppression ».

Le problème principal est que la modification d'un champ à l'intérieur d'un objet (comme merchant.key = new_key) ne met pas automatiquement à jour les clés de votre ObjectTable. L'ObjectTable stocke l'objet en fonction de la clé avec laquelle il a été ajouté. Ainsi, si la clé interne change, la table ne connaît toujours que l'ancienne clé.

module your_address::your_module_name {

    use sui::object::{Self, UID};
    use sui::tx_context::{Self, TxContext};
    use sui::string::{String, utf8};
    use sui::object_table::{Self, ObjectTable}; // Import ObjectTable

    // Define your Merchant struct
    public struct Merchant has key, store {
        id: UID,
        owner: address,
        key: String, // This is the key you want to update
        balance: u64,
    }

    // Define your MerchantRegistry struct
    public struct MerchantRegistry has key, store {
        id: UID,
        merchant_to_address: ObjectTable<address, Merchant>, // Mapping addresses to merchants
        merchant_to_key: ObjectTable<String, Merchant>,     // Mapping keys to merchants
    }

    // You'll likely have an `init` function to create the registry
    fun init(ctx: &mut TxContext) {
        let registry = MerchantRegistry {
            id: object::new(ctx),
            merchant_to_address: object_table::new(ctx),
            merchant_to_key: object_table::new(ctx),
        };
        // Transfer ownership of the registry, or make it shared if applicable
        sui::transfer::transfer(registry, tx_context::sender(ctx));
    }

    // Function to add a new merchant (for context)
    public entry fun add_merchant(
        registry: &mut MerchantRegistry,
        merchant_owner: address,
        merchant_key: vector<u8>, // Using vector<u8> for input, convert to String
        ctx: &mut TxContext
    ) {
        let merchant = Merchant {
            id: object::new(ctx),
            owner: merchant_owner,
            key: utf8(merchant_key),
            balance: 0,
        };

        // Add to both tables
        object_table::add(&mut registry.merchant_to_address, merchant_owner, object::share_object(merchant));     
        // You'll need to decide on a primary storage and potentially store references or IDs in other tables.
        // For simplicity, let's assume `merchant_to_key` is the primary and `merchant_to_address` stores the object ID.
        // If `Merchant` is a shared object, you can store it in multiple tables.
        // Let's adjust the `Merchant` struct for clarity in this example.

        // For simplicity and to avoid the "same object in multiple places" issue,
        // it's often better to have one "primary" table that owns the object,
        // and other tables store only the object's ID or a reference.
        // If you truly need the Merchant object directly in both tables, the Merchant itself needs to be a SHARED object.
        // Let's revise the example to make Merchant a shared object.

        // REVISED MERCHANT STRUCT (if you want it in both tables directly):
        // public struct Merchant has key { // No 'store' ability if it's shared directly
        //     id: UID,
        //     owner: address,
        //     key: String,
        //     balance: u64,
        // }
        // public entry fun add_merchant(...) {
        //     let merchant = Merchant { ... };
        //     object::share_object(merchant); // Make it shared
        //     object_table::add(&mut registry.merchant_to_address, merchant_owner, merchant);
        //     object_table::add(&mut registry.merchant_to_key, utf8(merchant_key), merchant);
        // }
        // This makes `Merchant` a shared object, which has different implications for ownership and mutability.

        //***************Let's stick to the original assumption that Merchant is not shared,
        //***************and therefore only one table directly owns the `Merchant` object.
        //***************If you want to look up by address AND key, and only one table can own the object,
        //***************then one table (e.g., merchant_to_address) stores the `Merchant` object,
        //***************and the other (merchant_to_key) stores the `ID` of the Merchant.

        // For this scenario, let's assume `merchant_to_address` owns the `Merchant` objects,
        // and `merchant_to_key` will map a String key to the `ID` of the Merchant.

        // New Merchant struct:
        // public struct Merchant has key, store {
        //     id: UID,
        //     owner: address,
        //     key: String, // Stored inside the object
        //     balance: u64,
        // }

        // Updated MerchantRegistry:
        // public struct MerchantRegistry has key, store {
        //     id: UID,
        //     merchant_to_address: ObjectTable<address, Merchant>, // Owners the Merchant object
        //     merchant_to_key: ObjectTable<String, object::ID>,    // Maps key to Merchant's ID
        // }

        //****************Let's assume for the sake of the user's original question*****************
        //****************that `ObjectTable<String, Merchant>` is intended to hold****************
        //****************the actual Merchant object, which implies it's the primary****************
        //****************owner or the `Merchant` is shared.
        //****************If `Merchant` is not shared, only ONE `ObjectTable` can hold it.
        //****************The error "Cannot ignore values without drop ability" confirms
        //****************that the `Merchant` object itself is being handled.

        // Assuming merchant_to_key is the primary table where the Merchant object resides:
        object_table::add(&mut registry.merchant_to_key, utf8(merchant_key), merchant);
        // If you still need lookup by address, you'd store the ID in merchant_to_address:
        // object_table::add(&mut registry.merchant_to_address, merchant_owner, object::id(&merchant));
        // This creates a circular dependency in a single transaction if you try to get ID *after* adding.
        // Best practice is one table owning the object, others holding IDs.

        // For the sake of directly answering the user's original question about `merchant_to_key`:
    }


    /// Entry function to update a merchant's key in the ObjectTable.
    public entry fun update_merchant_key(
        registry: &mut MerchantRegistry,
        old_key: vector<u8>, // Input as vector<u8> for String conversion
        new_key: vector<u8>, // Input as vector<u8> for String conversion
        ctx: &mut TxContext // TxContext is often needed for object::new or other operations
    ) {
        // Convert input vectors to Sui Strings
        let old_key_str = utf8(old_key);
        let new_key_str = utf8(new_key);

        // 1. Remove the merchant using the old key.
        // This returns the 'Merchant' object. Since Merchant does not have 'drop',
        // we *must* bind it to a variable.
        let mut merchant = object_table::remove(&mut registry.merchant_to_key, old_key_str);

        // 2. Update the 'key' field inside the retrieved Merchant struct.
        merchant.key = new_key_str;

        // 3. Re-insert the updated Merchant object into the table with the new key.
        // This will create a new entry in the ObjectTable.
        object_table::add(&mut registry.merchant_to_key, new_key_str, merchant);

        // If you also had a `merchant_to_address` table mapping to `object::ID`,
        // and the `owner` of the merchant might also change, you'd need to update that as well.
        // For example:
        // let old_address = merchant.owner; // Assuming merchant.owner is still the original owner
        // if (old_address != new_owner_address) { // If owner changes
        //     let merchant_id = object_table::remove(&mut registry.merchant_to_address, old_address);
        //     // merchant.owner = new_owner_address; // Update owner in the struct if needed
        //     object_table::add(&mut registry.merchant_to_address, new_owner_address, merchant_id);
        // }
    }

    // You might also want a function to get a merchant by key for testing
    public fun get_merchant_by_key(
        registry: &MerchantRegistry,
        key: vector<u8>
    ): &Merchant {
        object_table::borrow(&registry.merchant_to_key, utf8(key))
    }
}
4
Commentaires
.
MoonBags.
Jul 23 2025, 15:30

Dans Sui Move, vous ne pouvez pas simplement modifier la clé d'un objet dans un tableau ou supprimer/remplacer directement des objets sans les manipuler correctement. Lorsque vous modifiez le champ clé dans votre structure Merchant, la table merchant_to_key n'est pas automatiquement mise à jour. Ainsi, votre ancienne clé pointe toujours vers l'objet, tandis que la nouvelle clé n'a aucune association.

L'erreur « Impossible d'ignorer les valeurs sans capacité de suppression » survient parce que votre structure Merchant n'a probablement pas la capacité de suppression (ce qui est courant pour les structures contenant un UID). Cela signifie que vous ne pouvez pas simplement supprimer l'objet du tableau et le supprimer ; vous devez explicitement stocker et réutiliser l'objet renvoyé.

3
Commentaires
.
0xduckmove.
Jul 23 2025, 15:32

Pour mettre à jour correctement la clé d'un marchand, vous devez supprimer manuellement l'ancienne entrée, mettre à jour la structure Merchant avec la nouvelle clé, puis la réinsérer dans le tableau. Voici comment procéder dans le cadre d'une transaction :

public entry fun update_merchant_key(
    registry: &mut MerchantRegistry,
    old_key: String,
    new_key: String
) {
    // 1. Remove the merchant using the old key and store the returned object.
    let merchant = object_table::remove(&mut registry.merchant_to_key, old_key);

    // 2. Update the key field inside the struct.
    merchant.key = new_key;

    // 3. Re-insert the merchant into the table with the updated (new) key.
    object_table::add(&mut registry.merchant_to_key, new_key, merchant);
}```

Cette approche vous permet d'extraire en toute sécurité l'objet Merchant, de modifier sa clé, puis de le réinsérer dans l'ObjectTable avec la nouvelle clé. 
Cette méthode respecte les règles de propriété de Move et empêche les pertes accidentelles ou les « fuites » de ressources, ce qui est crucial lorsqu'il s'agit de types qui ne sont pas capables de tomber.

3
Commentaires
.
harry phan.
Jul 23 2025, 15:45

Pour mettre à jour la clé d'un marchand dans ObjectTable, vous devez manuellement :

supprimez l'objet Merchant à l'aide de la old_key.

Mettez à jour le champ clé dans la structure Merchant que vous venez de récupérer et ajoutez à nouveau l'objet Merchant modifié dans l'ObjectTable à l'aide de new_key.

public entry fun update_merchant_key(
    registry: &mut MerchantRegistry,
    old_key: String,
    new_key: String
) {
    let mut merchant = object_table::remove(&mut registry.merchant_to_key, old_key); // 1. Remove and capture
    merchant.key = new_key; // 2. Update the struct
    object_table::add(&mut registry.merchant_to_key, new_key, merchant); // 3. Re-insert
}
2
Commentaires
.
Meaning.Sui.
Jul 23 2025, 15:52

Si vous essayez de mettre à jour la clé d'un marchand dans un ObjectTable<String, Merchant> et que vous rencontrez des erreurs telles que « Impossible d'ignorer les valeurs sans possibilité de suppression », le problème est que dans Sui Move, vous ne pouvez pas simplement supprimer ou remplacer des objets stockés sans gérer explicitement la propriété et les types qui ne peuvent pas être supprimés. Lorsque vous modifiez la clé dans votre structure Merchant, cela ne met pas automatiquement à jour la table merchant_to_key. Vous vous retrouvez donc avec l'ancienne clé pointant toujours vers l'objet, tandis que la nouvelle clé n'est pas du tout liée.

2
Commentaires
.
24p30p.
24p30p1865
Jul 9 2025, 05:43

Si vous essayez de mettre à jour l'identifiant d'un marchand key``ObjectTable<String, Merchant>et que vous rencontrez des erreurs telles que « Impossible d'ignorer les valeurs sans possibilité de suppression », le problème est que dans Sui Move, vous ne pouvez pas simplement supprimer ou remplacer des objets stockés sans gérer explicitement la propriété et les types qui ne le droppermettent pas. Lorsque vous modifiez la clé dans votre Merchantstructure, cela ne met pas automatiquement à jour la merchant_to_keytable. Vous vous retrouvez donc avec l'ancienne clé pointant toujours vers l'objet, tandis que la nouvelle clé n'est pas du tout liée.

Pour résoudre ce problème, vous devezsupprimer manuellement l'ancienne entrée, mettre à jour la structure, puisla réinsérer à l'aide de la nouvelle clé. Mais comme la Merchantstructure n'a pas cette dropcapacité, vous ne pouvez pas simplement la supprimer et ignorer le résultat : vous devez stocker et réutiliser l'objet renvoyé. Voici comment procéder correctement dans le cadre d'une transaction :

public entry fun update_merchant_key(
    registry: &mut MerchantRegistry,
    old_key: String,
    new_key: String
) {
    // Remove the merchant using the old key and store the returned object
    let merchant = object_table::remove(&mut registry.merchant_to_key, old_key);

    // Update the key field inside the struct
    merchant.key = new_key;

    // Re-insert into the table with the updated key
    object_table::add(&mut registry.merchant_to_key, new_key, merchant);
}

De cette façon, vous pouvez extraire le marchand en toute sécurité, le modifier et le réinsérer à l'aide de la nouvelle clé, tout en respectant les règles de propriété de Move.

N'oubliez pas que cela est nécessaire car Move est conçu pour empêcher les chutes ou les fuites accidentelles de ressources. Si votre Merchantstructure n'en a pas la dropcapacité (ce qui est courant lorsqu'elle contient unUID), vous devez toujours la gérer explicitement.

Pour avoir une idée plus précise de son ObjectTablefonctionnement et de la manière de gérer la propriété en toute sécurité, consultez la documentation officielle ici : https://docs.sui.io/build/move/object-tables.

0
Commentaires
.

Connaissez-vous la réponse ?

Veuillez vous connecter et la partager.

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

609Publications1280Réponses
Sui.X.Peera.

Gagne ta part de 1000 Sui

Gagne des points de réputation et obtiens des récompenses pour avoir aidé la communauté Sui à se développer.

Campagne de RécompensesJuillet