Sending coin object as function parameter when there is only one coin object

Using sui SDK in a react app, I want to call a function that takes a coin as an argument. Now the wallet I connected most of the time only has one coin object. Now if send the coin object as an argument I get an error probably because there is no gas object. Is there any syntax that the SDK would automatically handle the gas payment and still send the coin object? Since splitting the coin would prompt the wallet twice though (maybe sending two transactions and signing once might be a solution, but I am not sure the syntax allows this).

2 Likes

The easiest way to do this is to build a PTB that first splits off a piece of the (single) input gas coin with the value you want to send, and then transfers the piece. The code from Building Programmable Transaction Blocks | Sui Documentation is a good reference for this:

const [coin] = txb.splitCoins(txb.gas, [txb.pure(100)]);
txb.transferObjects([coin], txb.pure("0xSomeSuiAddress"));
1 Like

However, if your intention is to transfer the entire gas coin (not a specific amount), you would do something like

txb.transferObjects([txb.gas], txb.pure("0xSomeSuiAddress"));
1 Like

@shb Thank you for the response. Two follow-up questions:

  1. Is 0xSomeSuiAddress referring to my own address? Cause I want to send the coin object in the function call later on like:
trx.moveCall({
        target: `${PACKAGE_ID}::protocol::mint`,
        arguments: [
          trx.pure(name),
          trx.object(coinObjectId),
        ],
      });

Here coinObjectId is the only coin object owned by the address.
2. More importantly, if you think about this happening from the frontend’s perspective, if we do go for the split coin approach, the user has to sign twice - one for splitting the coin and two for signing the tx to use the splited coin object and execute the function from the Package. IN what approach we make this a single signing experience?

1 Like

You can do something like

const [coin] = trx.splitCoins(txb.gas, [txb.pure(100)]);
trx.moveCall({
   target: `${PACKAGE_ID}::protocol::mint`,
        arguments: [
          trx.pure(name),
          coin,
        ],
});
signer.signAndExecuteTransactionBlock({ transactionBlock: trx });

This will not require the user to sign twice–the split, Move call, and any other commands you make will be packed into a single programmable transaction block that is signed once and executed atomically.

2 Likes

@shb I am getting the following error:

Dry run failed, could not automatically determine a
 budget: UnusedValueWithoutDrop { result_idx: 0, secondary_idx: 0 } 
(code: -1)
1 Like

Not a Move expert, but this is what I think happens. After the move call, you need to do something with the new object that was minted - that’s what UnusedValueWithoutDrop tells you - you have an object that is not dropped but also not transferred to an address / another object. Likely, you want to transfer it to some address to hold it.

2 Likes

To perform this operation efficiently, you can use Programmable Transaction Blocks (PTBs) to split and transfer a portion of a gas coin. Here’s a concise explanation:

  1. Split the Coin: Use splitCoins to isolate the specific value you want to send.
  2. Transfer the Coin: Use transferObjects to send the split coin to the desired address.

Here’s a sample code snippet from the Sui Documentation:

const [coin] = txb.splitCoins(txb.gas, [txb.pure(100)]);
txb.transferObjects([coin], txb.pure("0xSomeSuiAddress"));

In this example, splitCoins splits off 100 units of the gas coin, and transferObjects transfers it to the specified address. This method is efficient for managing and transferring digital assets, including NFTs
. For more details, check the “Building Programmable Transaction Blocks” section in the Sui Documentation.