Publication
Partagez vos connaissances.
+15
Erreur Sui Move - Impossible de traiter la transaction Aucune pièce de gaz valide n'a été trouvée pour la transaction
Quand je fais ça :
//Séparer le paiement de la pièce principale const [PaymentCoin] = TX.SplitCoins ( tx.object (PrimaryCoin.CoinObjectId), [tx.pure.u64 (montant de paiement requis)] ) ;
//Utilisez la pièce originale pour le paiement de l'essence TX.setGasPayment ([{ ID de l'objet : PrimaryCoin.CoinObjectID, version : PrimaryCoin.version, résumé : PrimaryCoin.Digest }]) ;
Tx. Budget gazier fixe (10_000_000) ; Il se plaint du fait que les objets mutables ne peuvent pas apparaître plus d'une fois dans une transaction. Lorsque je supprime le paiement du gaz, il se plaint « Impossible de traiter la transaction » Aucune pièce de gaz valide n'a été trouvée pour la transaction. ». Ma fonction de contrat accepte 0,01 sui en échange d'un NFT
- Sui
- Transaction Processing
- Move
Réponses
9-
En Sui, une pièce est un objet mutable.
-
Lorsque vous utilisez la même pièce comme pièce de paiement et comme pièce de gaz, la transaction échouera avec l'erreur « objets mutables ».
-
Cela est dû au fait qu'il n'est pas possible d'accéder à un objet mutable dans plusieurs rôles au sein de la même transaction.
-
Dans votre code, PrimaryCoin est divisé pour le paiement et également défini comme paiement du gaz.
-
Cela déclenche un conflit de mutabilité dans les règles de transaction Sui.
-
La solution consiste à utiliser deux objets distincts, l'un pour le gaz et l'autre pour le paiement.
-
Si votre portefeuille ne contient qu'une seule pièce, vous devez d'abord la diviser en deux avant de créer votre transaction proprement dite.
-
La CLI ou le SDK JavaScript de Sui peuvent diviser des pièces à l'aide de SplitCoins et renvoyer deux objets de pièces distincts.
-
La pièce de gaz ne doit pas être modifiée pendant la transaction.
-
Vous trouverez ci-dessous une approche JavaScript fonctionnelle :
const coins = await Provider.getCoins ({owner : SenderAddress}) ; if (coins.data.length < 2) renvoie une nouvelle erreur (« Il faut au moins 2 pièces pour l'essence et le paiement ») ;
const GasCoin = coins.data [0] ;//Pour le gaz uniquement const PaymentCoin = coins.data [1] ;//Pour le paiement du contrat
const tx = new TransactionBlock () ; tx.TransferObjects ([tx.object (paymentcoin.coinObjectId)], tx.pure (adresse du destinataire)) ; tx.setGasPayment ([{ObjectId : gascoin.coinObjectId, version : gascoin.version, résumé : Gascoin.digest}]) ; Tx. Budget gazier fixe (10_000_000) ;
wait Signer.SignAndExecuteTransactionBlock ({TransactionBlock : tx}) ;
-
De cette façon, la pièce d'essence reste intacte, sauf pour le paiement de l'essence.
-
La pièce de paiement est utilisée pour les frais de 0,01 SUI de votre contrat.
-
Si vous n'avez qu'une seule pièce, envoyez-vous d'abord une petite transaction pour la diviser en deux.
-
Cela peut être fait à l'aide d'un client unique split-coin ou d'un appel au SDK avant la transaction principale.
-
Le respect de cette règle de séparation permet d'éviter à la fois les erreurs « objets mutables » et les erreurs « aucune pièce de gaz valide ».
Cela se produit parce que vous essayez d'utiliser le même objet de monnaie (primaryCoin
) à la fois pour le paiement du gaz et comme entréesplitCoins
, ce qui en fait une référence mutable utilisée dans deux contextes différents — et Sui ne l'autorise pas pour des raisons de sécurité et de logique linéaire (puisque les pièces sont des objets linéaires).
À mon humble avis, la méthode consiste à ne pas régler manuellement le paiement de l'essence. Laissez simplement le portefeuille/client Sui sélectionner automatiquement la pièce de gaz appropriée. À utiliser uniquement setGasPayment
si vous avez vraiment besoin de spécifier quelle pièce permet de payer l'essence (par exemple, des portefeuilles multipièces, une gestion spécifique du gaz). Sinon, évitez-le.
Essayez ce qui suit :
// Split the primary coin to get a payment coin
const [paymentCoin] = tx.splitCoins(
tx.object(primaryCoin.coinObjectId),
[tx.pure.u64(requiredPaymentAmount)]
);
// Do your call that sends .01 SUI and gets an NFT
tx.moveCall({
target: `${packageId}::your_module::buy_nft`,
arguments: [
paymentCoin,
// other args...
],
});
// DO NOT set gas payment manually
// tx.setGasPayment(...) ← Remove this line
// Optional: set budget
tx.setGasBudget(10_000_000);
// Send the transaction
const result = await signer.signAndExecuteTransactionBlock({
transactionBlock: tx,
options: { showEffects: true },
});
Sui va :
- Choisissez automatiquement une pièce de gaz (il peut s'agir de la même pièce SUI ou d'une autre dans le portefeuille).
- Manipulez-les en
splitCoins
toute sécurité. - Utilisez unepièce différente(ou parfois la même, mais manipulée en toute sécurité grâce à une gestion des versions d'objets appropriée).
Important : tant que votre portefeuille contient au moins 1 dollar SUI pour couvrir l'essence, cela fonctionnera.
Vous êtes confronté à une contrainte de conception de transaction Sui Move courantele même objet de pièce ne peut pas être utilisé à la fois comme entrée mutable (par exemple, pour le fractionnement ou le transfert) et comme pièce de gaz dans une seule transaction.
Pourquoi cela se produit
- Lorsque vous utilisez tx.SplitCoins (tx.object (PrimaryCoin.CoinObjectId),...), vous marquez PrimaryCoin comme entrée mutable.
- Lorsque vous le définissez également comme pièce à gaz avec tx.setGasPayment (...), Sui voit le même objet utilisé dans deux rôles, ce qui n'est pas autorisé.
- Si vous supprimez le paiement du gaz, Sui ne trouve pas de pièce de gaz valide, d'où l'erreur « Aucune pièce de gaz valide trouvée pour la transaction ».
À partir du contexte :
État des effets de la transaction : utilisation non valide de la valeur. Les valeurs empruntées de manière mutable nécessitent une utilisation unique. Les valeurs empruntées de manière immuable ne peuvent pas être prises ou empruntées de manière mutante. Les valeurs prises ne peuvent pas être réutilisées. (source)
Comment réparer
Vous devez utiliser pour l'essence une pièce différente de celle que vous divisez ou transférez.
La solution : ayez au moins deux pièces SUI dans votre portefeuille. Utilisez-en un pour le paiement (fractionnement/transfert) et un autre pour le gaz.
Exemple de flux
- Sélectionnez deux pièces :
- PrimaryCoin (pour le paiement)
- GasCoin (pour le gaz)
- Divisez et payez avec PrimaryCoin :
const [paymentCoin] = tx.splitCoins(
tx.object(primaryCoin.coinObjectId),
[tx.pure.u64(requiredPaymentAmount)]
);
- Réglez le paiement du gaz avec GasCoin :
tx.setGasPayment([{
objectId: gasCoin.coinObjectId,
version: gasCoin.version,
digest: gasCoin.digest
}]);
tx.setGasBudget(10_000_000);
N'utilisez pas le même objet pour le paiement et l'essence.
Ma référence
L'erreur se produit car vous essayez d'utiliser l'primaryCoin
objet d'origine(qui est consommé pendant l'splitCoins
opération) pour payer le gaz. Après la division, la version ou le résumé de la pièce originale deviennent invalides, ce qui entraîne l'erreur « Les objets mutables ne peuvent pas apparaître plus d'un » lorsqu'elle est référencée à nouveau.
Pour résoudre ce problème, ne définissez pas manuellement le paiement du gaz à l'aide de l'primaryCoin
objet pré-divisé. Et assurez-vous d'avoir primaryCoin
un solde suffisant pour couvrir à la fois :
- Le montant du paiement (
requiredPaymentAmount
= 0,01 SUI) - Le budget du gaz (
10_000_000
= 0,01 SUI) → Total nécessaire :≥ 0,02 SUI
Il suffit d'essayer
// Split payment from primary coin (leaves remaining balance in primaryCoin)
const [paymentCoin] = tx.splitCoins(
tx.object(primaryCoin.coinObjectId),
[tx.pure.u64(requiredPaymentAmount)]
);
// DO NOT setGasPayment manually - SDK auto-uses updated primaryCoin for gas
tx.setGasBudget(10_000_000); // Gas paid from primaryCoin's remaining balance
Problèmes
Vous rencontrez deux problèmes principaux :
1.Erreur de mutabilité : Si vous tentez d'utiliser la même pièce pour le paiement du gaz et pour la saisie des transactions, l'erreur suivante s'affiche : « Les objets mutables ne peuvent pas apparaître plus d'une fois au cours d'une transaction ».
2.Pièce de gaz manquante : sans pièce d'essence valide, le message d'erreur « Impossible de traiter la transaction : aucune pièce de gaz valide n'a été trouvée pour la transaction » s'affiche.
Solution
Pour résoudre ces problèmes :
1.Divisez la pièce principale pour le paiement : utilisez-la tx.splitCoins
pour créer une nouvelle pièce pour l'achat du NFT, en vous assurant qu'elle est distincte du paiement de l'essence.
-
tx.setGasPayment
Définissez une pièce d'essence séparée : attribuez une pièce différente pour le paiement de l'essence à l'aide de. -
tx.setGasBudget
Définissez le budget du gaz : définissez un budget de gaz approprié à l'aide de.
Code
// Step 1: Split the primary coin for payment
const [paymentCoin] = tx.splitCoins(
tx.object(primaryCoin.coinObjectId),
[tx.pure.u64(requiredPaymentAmount)]
);
// Step 2: Set a separate gas payment coin
const gasCoin = tx.object(gasCoinObjectId);
tx.setGasPayment([{
objectId: gasCoin.coinObjectId,
version: gasCoin.version,
digest: gasCoin.digest
}]);
// Step 3: Set the gas budget for the transaction
tx.setGasBudget(10_000_000);
SurSui, une pièce unique est modifiable (son solde change lorsque vous l'utilisez), et vous ne pouvez pas référencer deux fois le même objet mutable en une seule transaction. C'est pourquoi :
Vous vous séparez du même PrimaryCoin
Et aussi en l'utilisant comme paiement de l'essence
→ Le générateur de transactions signale cela comme « un objet mutable apparaît plusieurs fois ».
Pourquoi « Aucune pièce de gaz valide n'a été trouvée » apparaît lorsque vous supprimez SetGasPayment
Lorsque vous ne spécifiez pas de pièce de gaz, le SDK Sui sélectionne automatiquement une pièce de gaz parmi les pièces que vous possédez et qui n'est pas encore utilisée dans la transaction. Mais comme votre transaction consomme déjà la seule pièce que vous possédez (via SplitCoins), il ne vous reste plus de pièce supplémentaire pour payer l'essence.
Comment y remédier :
Vous avez besoin de deux objets de monnaie distincts :
Pièce A→ utilisée pour le gaz uniquement
Coin B→ fractionnez pour votre paiement de 0,01 SUI
Si vous n'avez qu'une seule pièce dans votre portefeuille, vous devez d'abord la diviser en deux pièces distinctes lors d'unetransaction préliminaire.
La clé est la suivante :
- Sui empêche qu'une seule pièce soit à la fois un gaz et une entrée mutable dans la même transaction, car elle est traitée comme la même référence mutable.
- Mais dans Move, vous pouvez recevoir une pièce à payer sans vous soucier de l'objet dont elle provient, y compris une pièce qui a été séparée de la pièce à gaz plus tôt lors de la même transaction.
Cela signifie que votre fonction Move ne doit accepter que la pièce de paiement, pas la pièce d'origine, et que vous laissez l'éditeur de transactions se charger de la diviser avant de la transmettre.
move
module my_package::nft_market {
use sui::coin::{Self, Coin};
use sui::sui::{SUI};
use sui::object::{UID};
use sui::transfer;
use sui::tx_context::{Self, TxContext};
/// Simple function: take 0.01 SUI and give NFT
public entry fun buy_nft(
payment: Coin<SUI>, // User provides exactly 0.01 SUI
ctx: &mut TxContext
) {
let amount = coin::value(&payment);
let price = 10_000_000; // 0.01 SUI in MIST (1 SUI = 1_000_000_000 MIST)
assert!(amount == price, 0);
// Transfer the payment to the seller (hardcoded example)
transfer::transfer(payment, tx_context::sender(ctx));
// Mint NFT for buyer
let nft = NFT {
id: object::new(ctx),
name: b"Special NFT".to_vec(),
};
transfer::transfer(nft, tx_context::sender(ctx));
}
struct NFT has key, store {
id: UID,
name: vector<u8>,
}
}
Comment cela résout le problème
Lorsque le client crée la transaction :
1. La pièce de gaz (tx.gas) est automatiquement utilisée pour le gaz.
2. Séparez-vous de l'essence pour obtenir un nouveau PaymentCoin :
js
const [paymentCoin] = tx.splitCoins(
tx.gas, // mutable reference to gas coin
[tx.pure.u64(requiredPaymentAmount)]
);
tx.moveCall({
target: `${packageId}::nft_market::buy_nft`,
arguments: [paymentCoin],
});
tx.setGasBudget(10_000_000);
3. Sui l'autorise parce que :
tx.gas
est l'objetdu paiement du gaz. -La sortie fractionnée (paymentCoin
) est unnouvel objet.- Ce sont désormais desobjets mutables distinctsdans latransaction.
✅ Avantage : Il n'est plus nécessaire que le portefeuille contienne deux objets distincts au préalable : la fonction Move ne prend en compte que la pièce à payer, et le client peut toujours la séparer de la pièce à gaz avant d'appeler.
The error you're encountering occurs because you're trying to use the same coin object for both payment and gas payment. Let's fix this with a proper implementation that follows Sui's best practices.
Here's the correct way to structure your transaction:
const tx = new Transaction();
// Split the primary coin into two parts:
// 1. Payment amount (0.01 SUI)
// 2. Gas payment amount (remainder)
const [paymentCoin, gasCoin] = tx.splitCoins(
tx.object(primaryCoin.coinObjectId),
[
tx.pure.u64(requiredPaymentAmount), // 0.01 SUI for payment
tx.pure.u64(1_000_000) // 1 SUI for gas
]
);
// Set the gas payment using the gas coin
tx.setGasPayment([gasCoin]);
// Set appropriate gas budget
tx.setGasBudget(10_000_000);
// Now use the payment coin in your transaction
// Example:
tx.moveCall({
target: '0x2::nft::mint',
arguments: [
tx.object(paymentCoin),
// ... other arguments
]
});
Why Your Original Code Failed Your original code had two issues:
- Duplicate Object Usage
// Problem: Using same coin object twice
const [paymentCoin] = tx.splitCoins(tx.object(primaryCoin.coinObjectId), [tx.pure.u64(requiredPaymentAmount)]);
tx.setGasPayment([{
objectId: primaryCoin.coinObjectId, // Same object used again
version: primaryCoin.version,
digest: primaryCoin.digest
}]);
This fails because Sui doesn't allow using the same mutable object more than once in a transaction.
- Missing Gas Payment
// Problem: No valid gas coins found
tx.setGasBudget(10_000_000); // Budget set but no gas payment specified
When you removed the gas payment, the transaction failed because every transaction needs a valid gas payment.
Best Practices for Gas Management
-
Split Coins Efficiently
i. Always split coins before using them in transactions
ii. Ensure sufficient balance for both payment and gas
iii. Use appropriate gas amounts based on transaction complexity
-
Gas Payment Configuration
i. Set gas payment immediately after splitting coins
ii. Use the SDK's built-in gas management features
iii. Ensure gas budget is sufficient for transaction execution
-
Transaction Structure
i. Split coins first
ii. Set gas payment
iii. Set gas budget
iv. Then perform the main transaction operations
The solution provided at the top of this answer follows these best practices and will resolve both errors you're encountering. Remember that proper gas management is crucial for successful transaction execution on the Sui network.
Pour résoudre le problème que vous rencontrez avec l'erreur de transaction Sui concernant l'absence de pièces de gaz valides ou l'apparition d'objets modifiables plusieurs fois, c'est parce que vous ne pouvez pas utiliser la même pièce à la fois pour fractionner le paiement et couvrir les frais de gaz, car les pièces d'essence doivent rester séparées des articles que vous modifiez dans le cadre de la transaction. La solution la plus simple consiste à fractionner le paiement directement à partir de la source de gaz au lieu de votre pièce principale, alors remplacez-le par quelque chose comme
const paymentCoin = tx.splitCoins(tx.gas(), [tx.pure.u64(requiredPaymentAmount)]);
puis supprimez complètement la ligne de paiement manuel de l'essence, car le système le récupérera tout seul, et maintenez votre budget d'essence comme d'habitude. Cela vous permet de retirer la pièce d'essence sans vous heurter, à condition que votre portefeuille soit suffisant pour gérer le paiement à 0,01 Sui plus les frais.
Ce problème se produit parce que vous utilisez la même pièce (PrimaryCoin) à la fois pour le gaz et comme entrée dans SplitCoins, ce qui n'est pas autorisé dans Sui en raison de ses règles relatives aux objets linéaires et à la mutation sûre.
Pour résoudre ce problème, ne définissez pas manuellement le paiement du gaz. Laissez le portefeuille ou le client Sui sélectionner automatiquement une pièce de gaz appropriée. Vous n'avez besoin de SetGasPayment que dans les cas avancés (comme un contrôle précis des pièces). Voici l'approche propre :
// Split the primary coin to create a new payment coin
const [paymentCoin] = tx.splitCoins(
tx.object(primaryCoin.coinObjectId),
[tx.pure.u64(requiredPaymentAmount)]
);
// Call your function using the new coin
tx.moveCall({
target: ${packageId}::your_module::buy_nft,
arguments: [paymentCoin],
});
// No manual gas setting — remove tx.setGasPayment(...)
// Set your gas budget
tx.setGasBudget(10_000_000);
// Execute the transaction
const result = await signer.signAndExecuteTransactionBlock({
transactionBlock: tx,
options: { showEffects: true },
});
Sui choisira en toute sécurité une pièce d'essence dans votre portefeuille (tant qu'il en reste une) et s'occupera de tout dans les coulisses
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.
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.

- Pourquoi BCS exige-t-il un ordre de champs exact pour la désérialisation alors que les structures Move ont des champs nommés ?55
- « Erreurs de vérification de sources multiples » dans les publications du module Sui Move - Résolution automatique des erreurs45
- Échec de la transaction Sui : objets réservés pour une autre transaction48
- Erreur Sui Move - Impossible de traiter la transaction Aucune pièce de gaz valide n'a été trouvée pour la transaction29
- Comment les contraintes de capacité interagissent-elles avec les champs dynamiques dans des collections hétérogènes ?07