Skip to main content

Party Objects

A party object is owned by a Party: a permission set that determines which addresses can access the object and how. Like shared objects, party objects are sequenced and versioned by consensus, so several transactions can be submitted concurrently. As with shared objects, transactions that mutate a party object are sequenced and execute one at a time, while transactions that only read it can execute concurrently. Unlike shared objects, only the addresses with the appropriate permissions can access a party object. These permissions govern all aspects of an object, including reads, writes, and transfers.

Party objects are transferred using the sui::transfer::party_transfer or sui::transfer::public_party_transfer function. The object's permissions are then defined by the Party to which it is transferred.

info

Party objects currently support only single-address ownership. The sui::party::Party type already models permissions for multiple members, but the public transfer functions today accept only a single-owner party. Support for multi-member parties, and for additional ownership variants, is planned.

Party, address-owned, and shared objects compared

Party objects sit between address-owned objects and shared objects. They keep single-address ownership like address-owned objects, but they are sequenced by consensus like shared objects. The following table summarizes the practical differences.

PropertyAddress-ownedPartyShared
OwnerA single address (account address or object ID).A single address (account address or object ID).No owner. Anyone can access the object.
Versioned byOwner-signed fast path, not sequenced by consensus.Consensus.Consensus.
Concurrent inflight transactionsOne at a time, because the object takes a fast path lock.Many, because consensus assigns versions.Many, because consensus assigns versions.
Access controlOnly the owner can use the object.Only addresses with the required permissions can use the object.Anyone can use the object, so the module must enforce its own rules.
Transfer and wrapSupported.Supported. You can move the object to and from other ownership types and wrap it.Not supported. Sharing is permanent.
Coin<SUI> gas paymentSupported.Not supported. Convert the coin back to address-owned first.Not supported.
Transfer to objectSupported.Not supported when the owning address is an object ID.Not applicable.

Create party objects

Use these transfer module functions to create party objects:

public fun party_transfer<T: key>(obj: T, party: sui::party::Party)
public fun public_party_transfer<T: key + store>(obj: T, party: sui::party::Party)

Both functions take a sui::party::Party value. Currently, that value can be constructed only with sui::party::single_owner, which grants all permissions to one address and no permissions to anyone else:

public fun single_owner(owner: address): sui::party::Party

The sui::party module also provides wrapper macros for the transfer functions that can be used with method syntax, e.g. my_party.public_transfer(). The sui::party::transfer macro calls sui::transfer::party_transfer, and the sui::party::public_transfer macro calls sui::transfer::public_party_transfer.

The following example creates an object and transfers it to a single-owner party in one function:

Loading code...

After creation, a party object behaves like an address-owned object: you can transfer it to another address or ownership type, wrap it, or make it immutable.

When to use party objects

Use party objects when you want an object to remain owned by one address but be versioned by consensus, such as for operational convenience. If you only use an object together with other party or shared objects, converting it to a party object has no additional performance cost.

Party objects can be used by multiple inflight transactions at the same time. This contrasts with address-owned objects, which allow only a single inflight transaction at a time. Because consensus manages the versioning of a party object, many applications can pipeline several transactions against the same object without waiting for one to finalize before submitting the next.

info

A Coin can be a party object, including a Coin<SUI>. However, you cannot use a party object Coin<SUI> for gas payment. To use a party object Coin<SUI> for gas, you must first transfer it back to address-owned.

Transfer a party object

You can transfer an existing object to a single-owner party from the CLI or the TypeScript SDK. Both approaches build the same programmable transaction: they construct a single-owner party for the recipient and call public_party_transfer.

Use the Sui CLI

The sui client party-transfer command transfers one object to a recipient as a party object. Provide the recipient with --to (an address or a keystore alias) and the object with --object-id:

$ sui client party-transfer --to RECIPIENT_ADDRESS --object-id OBJECT_ID

The command accepts the standard gas and transaction processing options, so you can add flags such as --gas to choose a gas coin, or --serialize-unsigned-transaction to output transaction bytes for offline signing instead of executing immediately.

Use the TypeScript SDK

The TypeScript SDK does not provide a dedicated party-transfer helper, so you build the programmable transaction directly. Call 0x2::party::single_owner to construct the party, then pass its result to 0x2::transfer::public_party_transfer along with the object and its type:

import { Transaction } from '@mysten/sui/transactions';

const tx = new Transaction();

// Construct a single-owner party for the recipient.
const party = tx.moveCall({
target: '0x2::party::single_owner',
arguments: [tx.pure.address(RECIPIENT_ADDRESS)],
});

// Transfer the object to that party.
tx.moveCall({
target: '0x2::transfer::public_party_transfer',
typeArguments: [OBJECT_TYPE],
arguments: [tx.object(OBJECT_ID), party],
});

OBJECT_TYPE is the fully qualified type of the object, for example 0xPACKAGE::module::Type. After you build the transaction, sign and execute it with your client as you would any other programmable transaction.

Interact with party objects

You specify party objects as input to a transaction in the same way as shared objects. Sui validators ensure that the sender of the transaction can access the object. A validator might abort a transaction at execution time if the owner of an input party object changed because of an earlier, conflicting transaction.

In the TypeScript SDK, reference a party object with tx.object(PARTY_OBJECT_ID). The SDK detects that the object is a consensus object from its owner and resolves the input automatically, using the consensus start version, so you do not pass a version yourself:

import { Transaction } from '@mysten/sui/transactions';

const tx = new Transaction();

tx.moveCall({
target: `${PACKAGE_ID}::counter::increment`,
arguments: [tx.object(PARTY_OBJECT_ID)],
});

Party objects whose owning address corresponds to an object ID are not supported for access through the transfer to object mechanism. To transfer a party object owned by an account address:

public fun party_transfer_single_owner(o: Object, recipient: address) {
let party = party::single_owner(recipient);
transfer::public_party_transfer(o, party)
}

Limitations

Keep the following constraints in mind when you design with party objects:

  • Single-owner only: The public transfer functions currently accept only single-owner parties, constructed with sui::party::single_owner. The type models permissions for multiple members, and support for multi-member parties is planned.
  • No transfer to object for object-ID owners: Even when a single-owner party's address corresponds to an object ID, the party object cannot currently be received through the sui::transfer::Receiving mechanism.
  • No gas payment with party Coin<SUI>: You cannot pay gas with a party object Coin<SUI>. Transfer it back to address-owned first.

Troubleshooting

Use the following guidance when a transaction that uses party objects fails.

  • Owner changed or access denied: A validator aborts the transaction when the owner of an input party object changed because of an earlier, conflicting transaction, or when the sender is not the current owner. Refetch the object's current owner and version, then rebuild and resubmit the transaction.
  • Gas payment failed with a party coin: A party object Coin<SUI> cannot pay for gas. Transfer the coin back to address-owned, then use it as the gas coin, or select a different address-owned gas coin.