Unable to execute object transfer w/ payment on Sui Explorer

Greetings fellow Movers. Pls lend a helping hand. I wrote a simple module where sender initializes a struct and then transfers it to another address (receiver) for some SUI payment. The code is as below:

#[allow(unused)]

module try::item;

use sui::coin::{Self, Coin};

use sui::balance::{Self, Balance};

use sui::sui::SUI;

public struct Item has key, store {

id: UID,

ask: u64,

}

public struct Shop has key {

id: UID,

purse: Balance<SUI>,

}

fun init(ctx: &mut TxContext) {

transfer::transfer(Item {

    id: object::new(ctx),

    ask: 3000000000,

}, tx_context::sender(ctx));

transfer::share_object(Shop {

    id: object::new(ctx),

    purse: balance::zero()

});

}

public entry fun burn_item(item: Item) {

let Item { id, ask: \_ } = item;

object::delete(id);

}

public entry fun transfer_item(

shop: &mut Shop,

item: Item,

mysui: &mut Coin<SUI>,

receiver: address,

ctx: &mut TxContext) {

    assert!(coin::value(mysui) >= item.ask, 100);

    let mysui_bal = coin::balance_mut(mysui);

    let payment_bal = balance::split(mysui_bal, item.ask);

    balance::join(&mut shop.purse, payment_bal);

    transfer::public_transfer(item, receiver);

}

public entry fun collect_payment(

shop: &mut Shop,

ctx: &mut TxContext) {

    let payment_val = balance::value(&shop.purse);

    let payment_coin = coin::take(&mut shop.purse, payment_val, ctx);

    transfer::public_transfer(payment_coin, tx_context::sender(ctx));

}

The problem arises when, in Sui Explorer, I (as sender) try to transfer object Item to the other address (receiver). When I try to do it using the receiver’s wallet, Sui Explorer rewards me with the error below:

For clarity’s sake, we have,

sender address: 0x020073142cedefa9c0e2fa4c101751c3ca1ce0ab940d2f3151b26f8d6876b8d4

receiver address: 0x6ff0266c0f6cd1e53554ea5515ff38f75fae7d3f545dcec4063ac958df1dd55b

object uid: 0x18876657b2be33d9fc791fe68c8dd9b168500ceea3f36485183b7426458b41f8

The error makes perfect sense: Although the required asking price of 3 SUI is coming from the receiver, for the transaction to occur it needs a tiny amount of gas from the sender, and this cannot happen because the Explorer transaction is linked to the receiver’s wallet. I just cannot figure out how to go around this hurdle. Pls offer your insights.

I thank you in advance.

P.S. when transfer_item fun is executed linked with the sender’s wallet everything works. However, this does not correspond to a real life scenario.

Hi! As the error message indicates, in Sui Move you cannot use an owned object as input to a transaction signed by someone other than its owner.
https://docs.sui.io/concepts/object-ownership/address-owned#:~:text=An%20address%2Downed%20object%20is%20owned%20by%20a%20specific%2032%2Dbyte%20address%20that%20is%20either%20an%20account%20address%20(derived%20from%20a%20particular%20signature%20scheme)%20or%20an%20object%20ID.%20An%20address%2Downed%20object%20is%20accessible%20only%20to%20its%20owner%20and%20no%20others.

One common solution is to use a shared object as an intermediary so that multiple parties can interact in sequence:

  • Seller deposits an Item first.

  • Buyer pays with their Coin and receives the Item.

In your case, since Shop is already a shared object, you can use it as an escrow vault:

  • Seller lists an Item in Shop with a price.

  • Buyer purchases the Item via Shop, paying the price and triggering the transfer.

This sample app may help: https://docs.sui.io/guides/developer/sui-101/shared-owned
You may also want to look into Kiosk, which provides this type of commerce flow and more as a framework:
https://docs.sui.io/standards/kiosk

1 Like

taki, thank you so much. Will try it first thing in the morning. BTW, Kiosk is next on the todo list. would you know if there are any tutorials on Kiosk?

Great! This Kiosk course is a good place to start:
https://github.com/MystenLabs/kiosk-course

1 Like

Thank you. Right on it after escrow.