Publicación
Comparte tu conocimiento.
+15
Error de movimiento: no se puede procesar la transacción No se han encontrado monedas de gasolina válidas para la transacción
Cuando hago esto:
//Divida el pago de la moneda principal const [PaymentCoin] = tx.SplitCoins ( tx.object (ID principal de Coin.coinObjectID), [tx.pure.u64 (cantidad de pago requerida)] );
//Usa la moneda original para el pago de la gasolina tx.setGasPayment ([{ ID de objeto: primarycoin.coinObjectID, versión: PrimaryCoin.Version, resumen: PrimaryCoin.digest }]);
tx.SetGas Budget (10_000_000); Se queja de que los objetos mutables no pueden aparecer más de uno en una transacción. Cuando elimino el pago de la gasolina, aparece una queja: «No se puede procesar la transacción No se han encontrado monedas de gasolina válidas para la transacción». Mi función de contratación acepta 0,01 sui a cambio de un NFT
- Sui
- Transaction Processing
- Move
Respuestas
9-
En Sui, una moneda es un objeto mutable.
-
Si utilizas la misma moneda como moneda de pago y como moneda de gasolina, la transacción fallará y aparecerá el error de «objetos mutables».
-
Esto se debe a que no se puede acceder a un objeto mutable en varios roles dentro de la misma transacción.
-
En su código, PrimaryCoin se divide para el pago y también se establece como pago de gasolina.
-
Esto desencadena el conflicto de mutabilidad en las reglas de transacción de Sui.
-
La solución es utilizar dos monedas distintas: una para la gasolina y otra para el pago.
-
Si su billetera solo tiene una moneda, primero debe dividirla en dos antes de realizar su transacción real.
-
La CLI o el SDK de JavaScript de Sui pueden dividir monedas usando SplitCoins y devolver dos objetos de monedas distintos.
-
La moneda de gas no debe modificarse durante la transacción.
-
A continuación se muestra un enfoque de JavaScript que funciona:
const coins = await Provider.getCoins ({owner: senderAddress}); si (coins.data.length < 2) arroja un nuevo error («Se necesitan al menos 2 monedas para la gasolina y el pago»);
const GasCoin = coins.data [0];//Solo para gasolina const PaymentCoin = coins.data [1];//Para el pago de contratos
const tx = new TransactionBlock (); tx.transferObjects ([tx.object (paymentcoin.coinObjectID)], tx.pure (RecipientAddress)); tx.setGasPayment ([{ObjectID: gascoin.coinObjectID, versión: Gascoin.VERSION, resumen: Gascoin.digest}]); tx.setGasBudget (10_000_000);
espere a Signer.signAndExecuteTransactionBlock ({TransactionBlock: tx});
-
De esta forma, la moneda del gas permanece intacta, excepto para pagar la gasolina.
-
La moneda de pago se utiliza para pagar la tarifa de 0,01 SUI de su contrato.
-
Si solo tienes una moneda, primero envíate una pequeña transacción para dividirla en dos.
-
Esto se puede hacer utilizando sui client split-coin o una llamada al SDK antes de la transacción principal.
-
Seguir esta regla de separación evita los errores tanto de «objetos mutables» como de «moneda de gas no válida»
Esto ocurre porque intentas usar el mismo objeto de moneda (primaryCoin
) como pago de gasolina y como entradasplitCoins
, lo que lo convierte en una referencia mutable que se usa en dos contextos diferentes, y Sui no lo permite por motivos de seguridad y lógica lineal (ya que las monedas son objetos lineales).
En mi humilde opinión, la forma es no establecer manualmente el pago de la gasolina en absoluto. Simplemente deje que la billetera/cliente de Sui seleccione automáticamente una moneda de gasolina adecuada. Úsala solo setGasPayment
si realmente necesitas especificar con qué moneda se paga la gasolina (p. ej., monederos con varias monedas o una gestión específica del gas). De lo contrario, evítalo.
Prueba lo siguiente:
// 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 hará lo siguiente:
- Elige automáticamente una moneda de gasolina (puede ser la misma moneda SUI o la misma que tengas en la cartera).
- Manéjala de
splitCoins
forma segura. - Usa unamoneda diferente(o, a veces, la misma, pero manipúlala de forma segura bajo el capó mediante el control adecuado de las versiones de los objetos).
Importante: siempre y cuando tu monedero tenga al menos 1 USD para cubrir la gasolina, esto funcionará.
Se encuentra con una restricción común de diseño de transacciones de Sui Moveel mismo objeto de moneda no puede usarse como entrada mutable (por ejemplo, para dividir o transferir) y como moneda de gas en una sola transacción.
Por qué sucede esto
- Cuando usas tx.splitCoins (tx.object (PrimaryCoin.CoinObjectID),...), estás marcando PrimaryCoin como entrada mutable.
- Si también lo configuras como moneda de gas con tx.setGasPayment (...), Sui ve que el mismo objeto se utiliza en dos funciones, lo que no está permitido.
- Si eliminas el pago de gasolina, Sui no podrá encontrar ninguna moneda de gas válida, por lo que aparecerá el error «No se han encontrado monedas de gas válidas para la transacción».
Del contexto:
Estado de los efectos de la transacción: uso del valor no válido. Los valores tomados de forma mutable requieren un uso único. Los valores prestados de forma inmutable no pueden tomarse ni tomarse en préstamo de forma mutable. Los valores tomados no se pueden volver a utilizar. (fuente)
Cómo solucionarlo
Debe usar una moneda diferente a la que está dividiendo o transfiriendo para la gasolina.
La solución: ten al menos dos monedas SUI en tu monedero. Usa una para el pago (dividir/transferir) y otra para la gasolina.
Ejemplo de flujo
- Selecciona dos monedas:
- PrimaryCoin (para pago)
- GasCoin (para gasolina)
- Divida y pague con PrimaryCoin:
const [paymentCoin] = tx.splitCoins(
tx.object(primaryCoin.coinObjectId),
[tx.pure.u64(requiredPaymentAmount)]
);
- Configure el pago de gasolina con GasCoin:
tx.setGasPayment([{
objectId: gasCoin.coinObjectId,
version: gasCoin.version,
digest: gasCoin.digest
}]);
tx.setGasBudget(10_000_000);
No utilice el mismo objeto monetario tanto para el pago como para la gasolina.
Mi referencia
Sui Move: toma inválida de la moneda de gas. Solo se puede usar por valor con TransferObjects
El error se produce porque estás intentando usar el primaryCoin
objeto original(que se consume durante la splitCoins
operación) como pago de gas. Tras dividirse, la versión/resumen de la moneda original deja de ser válida, lo que provoca el error «los objetos mutables no pueden aparecer más de una vez» cuando se vuelve a hacer referencia a ella.
primaryCoin
Para solucionarlo, no configures manualmente el pago de la gasolina utilizando el objeto previo a la división. Y asegúrese de tener primaryCoin
un saldo suficiente para cubrir ambas cosas:
- El importe del pago (
requiredPaymentAmount
= 0,01 SUI) - El presupuesto de gas (
10_000_000
= 0,01 SUI) → Total necesario:≥ 0.02 SUI
¡Simplemente inténtalo
// 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
Problemas
Te encuentras con dos problemas principales:
1.Error de mutabilidad: si se intenta utilizar el mismo objeto de moneda tanto para el pago como para la entrada de transacciones de gas, se produce el siguiente error: «Los objetos mutables no pueden aparecer más de una vez en una transacción».
2.Falta una moneda de gas: Sin una moneda de gas válida, se produce el error «No se puede procesar la transacción: no se han encontrado monedas de gas válidas para la transacción».
Solución
Para resolver estos problemas:
1.Divida la moneda principal para el pago: utilícela tx.splitCoins
para crear una nueva moneda para la compra de NFT, asegurándose de que esté separada del pago de la gasolina.
-
tx.setGasPayment
Establezca una moneda de gas separada: asigne una moneda diferente para el pago de la gasolina. -
tx.setGasBudget
Defina el presupuesto de gas: establezca un presupuesto de gas adecuado utilizando.
Código
// 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);
EnSui, un solo objeto de moneda es mutable (su saldo cambia cuando lo usas) y no puedes hacer referencia al mismo objeto mutable dos veces en una transacción, por eso:
Te estás separando de la misma moneda primaria
Y también lo usa como pago de gasolina
→ El generador de transacciones marca esto como «el objeto mutable aparece más de una vez».
¿Por qué ocurre «No se han encontrado monedas de gasolina válidas» cuando eliminas SetGasPayment
Cuando no especificas una moneda de gasolina, el SDK de Sui selecciona automáticamente una moneda de gas de entre las monedas que tienes y que aún no se ha utilizado en la transacción. Pero como tu transacción ya está consumiendo la única moneda que tienes (a través de SplitCoins), no queda ninguna moneda extra para pagar gasolina.
Cómo solucionarlo:
Necesitas dos objetos monetarios distintos:
Moneda A→ se usa solo para gasolina
Moneda B→ divídela para tu pago de 0,01 USI
Si solo tienes una moneda en tu monedero, primero debes dividirla en dos monedas distintas en unatransacción preliminar.
La clave es:
- El Sui evita que un objeto de una sola moneda sea a la vez gas y una entrada mutable en la misma transacción, ya que se trata como la misma referencia mutable.
- Sin embargo, en Move, puedes recibir una moneda a modo de pago sin importar de qué objeto provenga, incluida una moneda que se dividió de la moneda de gas al principio de la misma transacción.
Esto significa que tu función Move solo debe aceptar la moneda de pago, no la moneda original, y dejar que el creador de transacciones se encargue de dividirla antes de pasarla.
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>,
}
}
Cómo se soluciona el problema
Cuando el cliente crea la transacción:
1. La moneda de gas (tx.gas) se usa automáticamente para la gasolina.
2. Separe de la gasolina para obtener una nueva moneda de pago:
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 lo permite porque:
tx.gas
es el objeto delpago de gas. -La salida dividida(paymentCoin
) es unobjeto nuevo.- Ahora sonobjetos mutables distintosen latransacción.
✅ Ventaja: Ya no necesitarás la cartera para guardar dos monedas distintas: la función Move solo se ocupa de la moneda de pago y el cliente siempre puede separarla de la moneda de gasolina antes de llamar.
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.
Para solucionar el problema con el que te encuentras con el error de transacción de Sui, ya que no se encuentran monedas de gasolina válidas o que aparecen objetos mutables más de una vez, es porque no puedes usar la misma moneda para dividir el pago y cubrir las tarifas de gasolina, ya que las monedas de gasolina deben permanecer separadas de los artículos que estás modificando en la oferta. El ajuste más fácil es dividir el pago directamente desde la fuente de gas en lugar de tu moneda principal, así que cámbialo por algo como
const paymentCoin = tx.splitCoins(tx.gas(), [tx.pure.u64(requiredPaymentAmount)]);
luego, elimine por completo la línea de pago manual de gas, ya que el sistema la recogerá por sí solo y mantendrá su presupuesto de gas establecido como de costumbre. Esto le permite sacar provecho de la moneda de la gasolina sin chocar, siempre y cuando su cartera tenga suficiente para pagar 0,01 Sui más las comisiones.
Este problema se debe a que utilizas la misma moneda (PrimaryCoin) tanto para gas como entrada en SplitCoins, lo que no está permitido en Sui debido a sus reglas sobre objetos lineales y mutaciones seguras.
Para solucionarlo, no configures manualmente el pago de la gasolina. Deje que la billetera o el cliente de Sui seleccionen automáticamente una moneda de gasolina adecuada. Solo necesitas SetGasPayment en casos avanzados (como el control preciso de las monedas). Este es el enfoque limpio:
// 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 cogerá de forma segura una moneda de gasolina de tu cartera (siempre que haya una disponible) y se encargará de todo lo que esté detrás de escena
Sabes la respuesta?
Inicie sesión y compártalo.
Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.
Gana tu parte de 1000 Sui
Gana puntos de reputación y obtén recompensas por ayudar a crecer a la comunidad de Sui.

- ¿Por qué BCS requiere un orden de campo exacto para la deserialización cuando las estructuras Move tienen campos con nombre?55
- «Errores de verificación de múltiples fuentes» en las publicaciones del módulo Sui Move: resolución automática de errores45
- Fallo en la transacción Sui: objetos reservados para otra transacción48
- Error de movimiento: no se puede procesar la transacción No se han encontrado monedas de gasolina válidas para la transacción29
- ¿Cómo interactúan las restricciones de capacidad con los campos dinámicos en colecciones heterogéneas?07