Sui.

帖子

分享您的知识。

赏金+15

Bolke .
Aug 12, 2025
专家问答

Sui Move 错误-无法处理交易未找到用于交易的有效汽油币

当我这样做时:

//从主币中拆分付款 const [PaymentCoin] = tx.SplitCoins ( tx.object (primaryCoin.coinObjectID), [tx.pure.u64(所需付款金额)] );

//使用原始硬币支付汽油 tx.setGasPayment ([{ ObjectID:primarycoin.coinObjectID, 版本:PrimaryCoin.Version, 摘要:Primarycoin.digest }]);

tx.setgasBudget (10_000_000); 它抱怨可变对象在一次交易中不能出现多个对象. 当我取消汽油付款时,它会抱怨 “无法处理交易 未找到用于交易的有效汽油币. ”.我的合约函数接受 .01 sui 来换取 NFT

  • Sui
  • Transaction Processing
  • Move
2
9
分享
评论
.

答案

9
Matthardy.
Aug 15 2025, 09:02
  1. 在 Sui 中,硬币是一个可变的物体.

  2. 当你使用相同的硬币作为支付币和汽油币时,交易将因 “可变对象” 错误而失败.

3.这是因为在同一个事务中不能以多个角色访问可变对象.

  1. 在你的代码中,PrimaryCoin被拆分用于付款,也被设置为汽油付款.

  2. 这会触发 Sui 交易规则中的可变性冲突.

  3. 解决方案是使用两个单独的硬币对象——一个用于汽油,一个用于付款.

  4. 如果您的钱包只有一枚硬币,则在构建实际交易之前,您首先需要将其分成两个.

  5. Sui 的 CLI 或 JavaScript SDK 可以使用 SplitCoins 拆分硬币,并返回两个不同的硬币对象.

  6. 在交易过程中,不应修改汽油币.

  7. 以下是行之有效的 JavaScript 方法:

const coins = 等待 provider.getCoins ({所有者:SenderAddress}); if (coins.data.length < 2) 抛出新错误(“需要至少 2 个硬币才能使用汽油 + 付款”);

const GasCoin = coins.data [0];//仅适用于汽油 const PaymentCoin = coins.data [1];//用于合约支付

const tx = new TransactionBlock (); tx.transferObject([tx.object (PaymentCoin.coinObjectID)],tx.pure(收件人地址)); tx.setGasPayment([{ObjectID:gascoin.coinObjectID,版本:Gascoin.Version,摘要:Gascoin.Digest}]); tx.setgasBudget (10_000_000);

等待 signer.signandExecuteTransactionBlock ({TransactionBlock: tx});

  1. 这样,除了支付汽油费外,汽油币保持不变.

  2. 付款硬币用于支付合约的.01 SUI费用.

  3. 如果您只有一枚硬币,请先给自己发送一笔小额交易,将其分成两部分.

  4. 这可以在主要交易之前使用sui客户端拆分硬币或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 将: -自动选择一枚汽油币(可以是钱包中相同的一种或另一种 SUI 硬币). -splitCoins安全地处理. -使用不同的硬币(有时是相同的硬币,但通过适当的对象版本控制在后台安全处理).

重要提示:只要你的钱包里有至少 1 美元的 SUI 可以支付汽油,这就行得通了.

2
评论
.
0xduckmove.
Aug 13 2025, 03:14

您遇到了一个常见的 Sui Move 交易设计约束条件**同一个硬币对象不能同时用作可变输入(例如,用于拆分或转移),也不能在单笔交易中用作汽油币. **

为什么会发生这种情况

  • 当你使用 tx.splitCoins(tx.object(PrimaryCoin.coinObjectID),...)时,你是在将 PrimaryCoin 标记为可变输入.
  • 当你还使用 tx.setGasPayment (...) 将其设置为汽油币时,Sui 会看到同一个物品被用于两个角色,这是不允许的.
  • 如果您取消汽油付款,Sui 找不到有效的汽油币,因此出现 “未找到用于交易的有效汽油币” 错误.

从上下文来看:

交易影响状态:价值使用无效. 可变的借用值需要独特的用法. 不可改变的借用值不能以可变方式取用或借用. 已获取的值不能再次使用. (来源)

如何修复

您必须使用与拆分或转移的硬币不同的硬币作为汽油.

解决方案:你的钱包里至少有两个 SUI 硬币. 使用一种进行付款(拆分/转账),另一种用于汽油.

示例流程

  1. 选择两枚硬币:
  • PrimaryCoin(用于付款)
  • GasCoin(用于汽油)
  1. 使用 PrimaryCoin 拆分并付款:
const [paymentCoin] = tx.splitCoins(
    tx.object(primaryCoin.coinObjectId),
    [tx.pure.u64(requiredPaymentAmount)]
);

3.使用 GasCoin 设置汽油支付:

tx.setGasPayment([{
    objectId: gasCoin.coinObjectId,
    version: gasCoin.version,
    digest: gasCoin.digest
}]);
tx.setGasBudget(10_000_000);

不要将相同的硬币对象用于支付和汽油.

我的参考资料

Sui Move:获取汽油币无效. 它只能在 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 创建新硬币,确保其与汽油付款分开.

  2. tx.setGasPayment设置单独的汽油币:使用不同的硬币进行汽油支付.

3.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→ 仅用于汽油

Coin B→ 分成您的 .01 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 Sui的付款和费用,这就可以让你在不发生冲突的情况下从汽油币中提取资金.

2
评论
.
BigDev.
Aug 15 2025, 16:20

之所以会出现这个问题,是因为你使用相同的硬币(PrimaryCoin)作为气体和SplitCoins的输入,Sui不允许使用这种硬币(PrimaryCoin),因为它有关于线性物体和安全突变的规则.

要修复这个问题,不要手动设置汽油支付. 让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 社区成长而获得奖励。

奖励活动八月