Sui.

Publicación

Comparte tu conocimiento.

Recompensa+15

Bolke .
Aug 12, 2025
P&R expertos

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
2
9
Cuota
Comentarios
.

Respuestas

9
Matthardy.
Aug 15 2025, 09:02
  1. En Sui, una moneda es un objeto mutable.

  2. 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».

  3. Esto se debe a que no se puede acceder a un objeto mutable en varios roles dentro de la misma transacción.

  4. En su código, PrimaryCoin se divide para el pago y también se establece como pago de gasolina.

  5. Esto desencadena el conflicto de mutabilidad en las reglas de transacción de Sui.

  6. La solución es utilizar dos monedas distintas: una para la gasolina y otra para el pago.

  7. Si su billetera solo tiene una moneda, primero debe dividirla en dos antes de realizar su transacción real.

  8. La CLI o el SDK de JavaScript de Sui pueden dividir monedas usando SplitCoins y devolver dos objetos de monedas distintos.

  9. La moneda de gas no debe modificarse durante la transacción.

  10. 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});

  1. De esta forma, la moneda del gas permanece intacta, excepto para pagar la gasolina.

  2. La moneda de pago se utiliza para pagar la tarifa de 0,01 SUI de su contrato.

  3. Si solo tienes una moneda, primero envíate una pequeña transacción para dividirla en dos.

  4. Esto se puede hacer utilizando sui client split-coin o una llamada al SDK antes de la transacción principal.

  5. Seguir esta regla de separación evita los errores tanto de «objetos mutables» como de «moneda de gas no válida»

4
Comentarios
.
MiniBob.
Aug 12 2025, 19:33

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 setGasPaymentsi 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 splitCoinsforma 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á.

2
Comentarios
.
0xduckmove.
Aug 13 2025, 03:14

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

  1. Selecciona dos monedas:
  • PrimaryCoin (para pago)
  • GasCoin (para gasolina)
  1. Divida y pague con PrimaryCoin:
const [paymentCoin] = tx.splitCoins(
    tx.object(primaryCoin.coinObjectId),
    [tx.pure.u64(requiredPaymentAmount)]
);
  1. 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

2
Comentarios
.
Owen.
Owen4622
Aug 13 2025, 06:10

El error se produce porque estás intentando usar el primaryCoinobjeto original(que se consume durante la splitCoinsoperació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.

primaryCoinPara solucionarlo, no configures manualmente el pago de la gasolina utilizando el objeto previo a la división. Y asegúrese de tener primaryCoinun 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
2
Comentarios
.
Paul.
Paul4200
Aug 13 2025, 08:48

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.splitCoinspara crear una nueva moneda para la compra de NFT, asegurándose de que esté separada del pago de la gasolina.

  1. tx.setGasPaymentEstablezca una moneda de gas separada: asigne una moneda diferente para el pago de la gasolina.

  2. tx.setGasBudgetDefina 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);
2
Comentarios
.
casey.
Aug 14 2025, 03:40

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.gases 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.

2
Comentarios
.
d-podium.
Aug 15 2025, 00:18

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:

  1. 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.

  1. 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

  1. 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

  2. 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

  3. 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.

2
Comentarios
.
Redterror.
Aug 15 2025, 10:50

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.

2
Comentarios
.
BigDev.
Aug 15 2025, 16:20

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

0
Comentarios
.

Sabes la respuesta?

Inicie sesión y compártalo.