Sui.

Пост

Поделитесь своими знаниями.

Награда+15

Bolke .
Aug 12, 2025
Экспертные Вопросы и Ответы

Ошибка Sui Move — невозможно обработать транзакцию Не найдено действительных газовых монет для транзакции

Когда я это сделаю:

//Отделите платеж от основной монеты константа [PaymentCoin] = TX.SplitCoins ( объект tx.object (идентификатор объекта PrimaryCoin.coin), [tx.pure.u64 (обязательная сумма платежа)] );

//Используйте оригинальную монету для оплаты газа tx.Установите оплату газа ([{ Идентификатор объекта: идентификатор объекта PrimaryCoin.coin, версия: версия PrimaryCoin, дайджест: PrimaryCoin.Дайджест }]);

Налогообложение бюджета на газ (10_000_000); Он жалуется на то, что изменяемые объекты не могут появляться более одного в одной транзакции. Когда я удаляю платеж за газ, оно жалуется: «Невозможно обработать транзакцию» Для транзакции не найдено действительных газовых монет». Моя контрактная функция принимает сумму 0,01 евро в обмен на NFT

  • Sui
  • Transaction Processing
  • Move
2
9
Поделиться
Комментарии
.

Ответы

9
Matthardy.
Aug 15 2025, 09:02
  1. В языке Суй монета — это изменчивый объект.

  2. Если вы используете одну и ту же монету в качестве платежа и газовой монеты, транзакция завершится ошибкой «изменяемые объекты».

  3. Это связано с тем, что к изменяемому объекту нельзя получить доступ в нескольких ролях в одной транзакции.

  4. В вашем коде PrimaryCoin разделяется для оплаты, а также используется в качестве оплаты за газ.

  5. Это вызывает конфликт изменчивости в правилах транзакций Sui.

  6. Решение заключается в использовании двух отдельных монет — одного для газа, а другого для оплаты.

  7. Если в вашем кошельке есть только одна монета, вам сначала нужно разделить ее на две части, прежде чем проводить фактическую транзакцию.

  8. Интерфейс командной строки Sui или JavaScript SDK могут разделять монеты с помощью SplitCoins и возвращать два разных объекта монет.

  9. Газовая монета не должна быть изменена во время транзакции.

  10. Ниже приведен рабочий JavaScript-подход:

константные монеты = ждут провайдера.getCoins ({владелец: адрес отправителя}); если (coins.data.length < 2) выдаст новую ошибку («На бензин нужно не менее 2 монет + оплата»);

const GasCoin = coins.data [0];//Только для газа const PaymentCoin = coins.data [1];//Для оплаты по контракту

налог на константу = новый блок транзакций (); объекты tx.transfer ([tx.object (идентификатор объекта PaymentCoin.coin)], tx.pure (адрес получателя)); tx.setGasPayment ([{Идентификатор объекта: идентификатор объекта gascoin.coin, версия: gascoin.version, дайджест: gascoin.digest}]); Задайте бюджет на газ (10_000_000);

дождитесь подписания и выполнения блока транзакций ({TransactionBlock: tx});

  1. Таким образом, газовая монета останется нетронутой, за исключением оплаты за газ.

  2. Платежная монета используется для оплаты комиссии в размере 0,01 SUI по вашему контракту.

  3. Если у вас есть только одна монета, сначала отправьте себе небольшую транзакцию, чтобы разделить ее на две части.

  4. Это можно сделать с помощью специального клиента split-coin или вызова SDK перед основной транзакцией.

  5. Соблюдение этого правила разделения позволяет избежать ошибок, связанных как с изменчивыми объектами, так и с ошибками «нет действительной газовой монеты»

4
Комментарии
.
MiniBob.
Aug 12 2025, 19:33

Это происходит потому, что вы пытаетесь использовать один и тот же монетный объект (primaryCoin) как для оплаты газа, так и для вводаsplitCoins, поэтому его можно использовать в двух разных контекстах, а Sui не допускает этого из соображений безопасности и линейной логики (поскольку монеты — это линейные объекты).

Имхо, вообще не нужно настраивать оплату за газ вручную. Просто позвольте кошельку/клиенту Sui автоматически выбрать подходящую газовую монету. Используйте только в том случае, setGasPaymentесли вам действительно нужно указать, за какую монету можно платить за газ (например, кошельки с несколькими монетами, специальные системы управления газом). В противном случае избегайте этого.

Попробуйте следующее:

// 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 в кошельке).
  • Обращайтесь с ними splitCoinsбезопасно.
  • Используйтедругую монету(а иногда и ту же самую, но при правильном управлении версиями объектов ее можно безопасно хранить под капотом).

Важно: если в вашем кошельке есть SUI стоимостью не менее 1 доллара США, который может покрыть бензин, это сработает.

2
Комментарии
.
0xduckmove.
Aug 13 2025, 03:14

Вы столкнулись с распространенным ограничением дизайна транзакций Sui MoveОдин и тот же объект монеты нельзя использовать одновременно в качестве изменяемых входных данных (например, для разделения или перевода) и в качестве газовой монеты за одну транзакцию.

Почему это происходит

  • Когда вы используете tx.SplitCoins (tx.object (PrimaryCoin.coinObjectID),...), вы помечаете PrimaryCoin как изменяемые входные данные.
  • Если вы также укажете эту монету в качестве газовой монеты с помощью tx.setGasPayment (...), Суй увидит, что один и тот же объект используется в двух ролях, что недопустимо.
  • Если вы отмените оплату за газ, Суй не сможет найти действительную газовую монету, поэтому появится ошибка «Для транзакции не найдено действительных газовых монет».

Из контекста:

Состояние эффектов транзакции: неправильное использование значения. Взаимно заимствованные значения требуют уникального использования. Неизменно заимствованные ценности не могут быть взяты или заимствованы на постоянной основе. Взятые значения нельзя использовать снова. (источник)

Как исправить

Для оплаты газа необходимо использовать другую монету, отличную от той, которую вы делите или передаете.

Решение: имейте в кошельке как минимум две монеты SUI. Используйте одну для оплаты (разделения/перевода), а другую для оплаты газа.

Пример потока

  1. Выберите две монеты:
  • PrimaryCoin (для оплаты)
  • GasCoin (для газа)
  1. Разделяйте и платите с помощью PrimaryCoin:
const [paymentCoin] = tx.splitCoins(
    tx.object(primaryCoin.coinObjectId),
    [tx.pure.u64(requiredPaymentAmount)]
);
  1. Настройте оплату за газ с помощью GAScoin:
tx.setGasPayment([{
    objectId: gasCoin.coinObjectId,
    version: gasCoin.version,
    digest: gasCoin.digest
}]);
tx.setGasBudget(10_000_000);

Не используйте один и тот же монетный предмет как для оплаты, так и для газа.

Моя рекомендация

Суи ход: недействительное изъятие монеты «Газ». Его можно использовать только по стоимости в TransferObjects

2
Комментарии
.
Owen.
Owen4622
Aug 13 2025, 06:10

Ошибка возникает из-за того, что вы пытаетесь использоватьоригинальный primaryCoinобъект(который потребляется во время splitCoinsэксплуатации) в качестве оплаты за газ. После разделения версия/дайджест исходной монеты становится недействительной, в результате чего при повторной ссылке появляется ошибка «изменяемые объекты не могут отображаться более одного».

primaryCoinЧтобы исправить ошибку, не устанавливайте оплату за газ вручную с помощью предварительно сплит-объекта. И убедитесь, что на вашем primaryCoinбалансе достаточно средств, чтобы покрыть и то, и другое:

  • Сумма платежа (requiredPaymentAmount= 0,01 SUI)
  • Бюджет на газ (10_000_000= 0,01 SUI) → Всего необходимых сумм:≥ 0,02 SUI

Просто попробуйте

// 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
Комментарии
.
Paul.
Paul4200
Aug 13 2025, 08:48

Проблемы

Вы столкнулись с двумя основными проблемами:

1.Ошибка изменчивости: попытка использовать один и тот же объект монеты как для оплаты газа, так и для ввода транзакций приводит к ошибке: «Меняемые объекты не могут появляться более одного раза в одной транзакции».

2.Отсутствует газовая монета: при отсутствии действительной газовой монеты возникает ошибка «Невозможно обработать транзакцию: действительных газовых монет для транзакции не найдено».


Решение

Чтобы решить эти проблемы, выполните следующие действия:

1.Разделите основную монету для оплаты: используйте tx.splitCoinsее для создания новой монеты для покупки NFT, отдельно от оплаты за газ.

  1. tx.setGasPaymentУстановите отдельную монету за газов: назначьте другую монету для оплаты газа.

  2. tx.setGasBudgetОпределите бюджет газа: установите соответствующий бюджет газа, используя.


Код

// 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
Комментарии
.
casey.
Aug 14 2025, 03:40

ВSuiобъект с одной монетой является изменяемым (его баланс меняется при использовании), и вы не можете ссылаться на один и тот же изменяемый объект дважды за одну транзакцию — вот почему:

Вы отделяетесь от одного и того же PrimaryCoin

А также используете его в качестве оплаты за газ

→ Конструктор транзакций отмечает это как «изменяемый объект появляется несколько раз».

Почему при удалении SetGasPayment появляется сообщение «Не найдено действительных газовых монет»

Если вы не укажете монету за газ, Sui SDK автоматически выберет газов��ю монету из ваших собственных монет, которые еще не были использованы в транзакции. Но поскольку на транзакцию уже потрачена единственная имеющаяся у вас монета (через SplitCoins), дополнительных монет для оплаты газа не осталось.

Как это исправить:

Вам нужны два разных предмета для монет:

Монета A→ используется только для газа

Монета B→ разделите сумму платежа в размере 0.1 SUI

Если в вашем кошельке есть только одна монета, вы должны сначала разделить ее на два отдельных монетных объекта в ходе предварительнойтранзакции.

Ключ заключается в следующем:

  • Система Sui предотвращает превращение одного и того же монетного объекта в одну и ту же транзакцию одновременно в качестве газа и изменчивых исходных данных, поскольку он рассматривается как одна и та же изменяемая ссылка.
  • Но в Move вы можете получить в качестве оплаты монету, не обращая внимания на то, с какого предмета она была получена. В том числе и монеты, которая была отделена от газовой монеты ранее в ходе той же транзакции.

Это означает, что ваша функция Move должна принимать только платежную монету, а не оригинальную монету, и вы позволяете разработчику транзакций разделить ее на части, прежде чем передавать ее.

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

Как это решает проблему

Когда клиент создает транзакцию:

1. Газовая монета (tx.gas) автоматически используется для оплаты газа.

2. Откажитесь от газа и получите новую 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 разрешает это, потому что:

  • tx.gasэто объектоплаты газа. -Разделенный выход (paymentCoin) — этоновый объект.
  • Теперь ониотдельные изменяемые объектывтранзакции.

✅ Преимущество: Вам больше не нужно предварительно хранить в кошельке две отдельные монеты — функция Move заботится только о платежной монете, и клиент всегда может отделить ее от газовой монеты перед звонком.

2
Комментарии
.
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
Комментарии
.
Redterror.
Aug 15 2025, 10:50

Чтобы решить проблему, связанную с ошибкой транзакции Sui, заключающейся в том, что действительные газовые монеты не найдены или изменяемые предметы появлялись более одного раза, это связано с тем, что одну и ту же монету нельзя использовать для разделения платежа и оплаты за газ, так как газовые монеты необходимо хранить отдельно от предметов, которые вы дорабатываете в сделке. Проще всего разделить платеж прямо с источника газа, а не на основную монету, поэтому замените его на что-то вроде

const paymentCoin = tx.splitCoins(tx.gas(), [tx.pure.u64(requiredPaymentAmount)]);

затем полностью откажитесь от ручной линии оплаты газа, так как система сама возьмет ее на себя, и поддержите свой бюджет на газ в обычном режиме. Это позволит вам без проблем потратить деньги на бензин, если в вашем кошельке хватит денег на оплату в размере 0,01 суя плюс комиссии.

2
Комментарии
.
BigDev.
Aug 15 2025, 16:20

Эта проблема возникает из-за того, что вы используете одну и ту же монету (PrimaryCoin) как для газа, так и для входа в SplitCoins, что запрещено использовать в Sui из-за правил, регулирующих линейные объекты и безопасную мутацию.

Чтобы исправить эту проблему, не устанавливайте оплату за газ вручную. Позвольте кошельку или клиенту Sui автоматически выбрать подходящую газовую монету. SetGasPayment нужен только в сложных случаях (например, при точном управлении монетами). Вот простой подход:


// 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 безопасно выберет из вашего кошелька газовую монету (если она есть) и разберется со всем за кулисами

0
Комментарии
.

Знаете ответ?

Пожалуйста, войдите в систему и поделитесь им.

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

715Посты1825Ответы
Sui.X.Peera.

Заработай свою долю из 1000 Sui

Зарабатывай очки репутации и получай награды за помощь в развитии сообщества Sui.

Кампания вознагражденийАвгуст