0x0::listing

Module for an NFT Listing

A Listing allows creators to sell their NFTs to the primary market using bespoke market primitives, such as FixedPriceMarket and DutchAuctionMarket. Listing can be standalone or be attached to Marketplace.

Associated Marketplace objects may stipulate a fee policy, the marketplace admin can decide to create a custom fee policy for each Listing.

Listing may define multiple Inventory objects which themselves can define multiple markets. In consequence, each Listing may tier it's sales into different NFT rarities, but may also want to sell one NFT inventory through different sales channels. For example, a creator might want to auction a rare tier of their collection or provide an instant-buy option for users not wanting to participate in the auction. Alternatively, an inventory listing may want to sell NFTs for multiple fungible tokens.

In essence, Listing is a shared object that provides a safe API to the underlying inventories which are unprotected.

Structs

listing::Listing has store, key

Fields:

Name Type Description
id object::UID
marketplace_id option::Option<typed_id::TypedID<marketplace::Marketplace>>

The ID of the marketplace if any

admin address

The address of the Listing administrator

receiver address

The address of the receiver of funds

proceeds proceeds::Proceeds

Proceeds object holds the balance of fungible tokens acquired from the sale of the listing

venues object_table::ObjectTable<object::ID, venue::Venue>

Main object that holds all venues part of the listing

inventories object_bag::ObjectBag

Main object that holds all inventories part of the listing

custom_fee object_box::ObjectBox

Field with Object Box holding a Custom Fee implementation if any. In case this box is empty the calculation will applied on the default fee object in the associated Marketplace

listing::RequestToJoin has store, key

Fields:

Name Type Description
id object::UID
marketplace_id typed_id::TypedID<marketplace::Marketplace>

An ephemeral object representing the intention of a Listing admin to join a given Marketplace.

listing::CreateListingEvent has copy, drop

Fields:

Name Type Description
listing_id object::ID

Event signalling that a Listing was created

listing::DeleteListingEvent has copy, drop

Fields:

Name Type Description
listing_id object::ID

Event signalling that a Listing was deleted

listing::NftSoldEvent has copy, drop

Fields:

Name Type Description
nft object::ID
price u64
ft_type ascii::String
nft_type ascii::String
buyer address

Event signalling that Nft was sold by Listing

Methods

public fun new(
    listing_admin: address,
    receiver: address,
    ctx: &mut tx_context::TxContext,
): listing::Listing

Initialises a Listing object and returns it.

public entry fun init_listing(
    listing_admin: address,
    receiver: address,
    ctx: &mut tx_context::TxContext,
)

Initialises a standalone Listing object.

public entry fun init_venue<Market: store>(
    listing: &mut listing::Listing,
    market: Market,
    is_whitelisted: bool,
    ctx: &mut tx_context::TxContext,
)

Initializes a Venue on Listing

Panics

Panics if transaction sender is not listing admin.

public fun create_venue<Market: store>(
    listing: &mut listing::Listing,
    market: Market,
    is_whitelisted: bool,
    ctx: &mut tx_context::TxContext,
): object::ID

Creates a Venue on Listing and returns it's ID

Panics

Panics if transaction sender is not listing admin.

public entry fun init_warehouse<C>(
    listing: &mut listing::Listing,
    collection: &collection::Collection<C>,
    ctx: &mut tx_context::TxContext,
)

Initializes an empty Warehouse on Listing

Requires that transaction sender is collection creator registered in CreatorsDomain.

Panics

Panics if transaction sender is not listing admin or creator.

public fun create_warehouse<C>(
    witness: witness::Witness<C>,
    listing: &mut listing::Listing,
    ctx: &mut tx_context::TxContext,
): object::ID

Creates an empty Warehouse on Listing and returns it's ID

Function transparently wraps Warehouse in Inventory, therefore, the returned ID is that of the Inventory not the Warehouse.

Panics

Panics if transaction sender is not listing admin.

public fun pay<FT>(
    listing: &mut listing::Listing,
    balance: balance::Balance<FT>,
    quantity: u64,
)

Pay for Nft sale and direct funds to Listing proceeds

public fun emit_sold_event<FT, C>(
    nft: &nft::Nft<C>,
    price: u64,
)

Emits NftSoldEvent for provided Nft

Buyer is set to the logical_owner of the Nft.

public fun pay_and_emit_sold_event<FT, C>(
    listing: &mut listing::Listing,
    nft: &nft::Nft<C>,
    balance: &mut balance::Balance<FT>,
    price: u64,
)

Pay for Nft sale, direct fund to Listing proceeds, and emit sale events.

Will charge price from the provided Balance object.

Panics

Panics if balance is not enough to fund price

public fun buy_nft<C, FT, Market: store, MarketWitness: drop>(
    witness: MarketWitness,
    listing: &mut listing::Listing,
    inventory_id: object::ID,
    venue_id: object::ID,
    owner: address,
    price: u64,
    balance: &mut balance::Balance<FT>,
    ctx: &mut tx_context::TxContext,
): 
    nft::Nft<C>

Buys an NFT from an Inventory

Only venues registered on the Listing have authorization to withdraw from an Inventory, therefore this operation must be authorized using a witness that corresponds to the market contract.

Endpoint will redeem NFTs sequentially, if you need random withdrawal use buy_pseudorandom_nft or buy_random_nft.

Panics

  • Market type does not correspond to venue_id on the Listing
  • MarketWitness does not correspond to Market type
  • No supply is available from underlying Inventory

public fun buy_pseudorandom_nft<C, FT, Market: store, MarketWitness: drop>(
    witness: MarketWitness,
    listing: &mut listing::Listing,
    inventory_id: object::ID,
    venue_id: object::ID,
    owner: address,
    price: u64,
    balance: &mut balance::Balance<FT>,
    ctx: &mut tx_context::TxContext,
): 
    nft::Nft<C>

Buys a pseudo-random NFT from an Inventory

Only venues registered on the Listing have authorization to withdraw from an Inventory, therefore this operation must be authorized using a witness that corresponds to the market contract.

Endpoint is susceptible to validator prediction of the resulting index, use buy_random_nft instead.

Panics

  • Market type does not correspond to venue_id on the Listing
  • MarketWitness does not correspond to Market type
  • Underlying Inventory is not a Warehouse and there is no supply

public fun buy_random_nft<C, FT, Market: store, MarketWitness: drop>(
    witness: MarketWitness,
    listing: &mut listing::Listing,
    commitment: warehouse::RedeemCommitment,
    user_commitment: vector<u8>,
    inventory_id: object::ID,
    venue_id: object::ID,
    owner: address,
    price: u64,
    balance: &mut balance::Balance<FT>,
    ctx: &mut tx_context::TxContext,
): 
    nft::Nft<C>

Buys a random NFT from Inventory

Requires a RedeemCommitment created by the user in a separate transaction to ensure that validators may not bias results favorably. You can obtain a RedeemCommitment by calling warehouse::init_redeem_commitment.

Only venues registered on the Listing have authorization to withdraw from an Inventory, therefore this operation must be authorized using a witness that corresponds to the market contract.

Panics

  • Market type does not correspond to venue_id on the Listing
  • MarketWitness does not correspond to Market type
  • Underlying Inventory is not a Warehouse and there is no supply
  • user_commitment does not match the hashed commitment in RedeemCommitment

public entry fun request_to_join_marketplace(
    marketplace: &marketplace::Marketplace,
    listing: &mut listing::Listing,
    ctx: &mut tx_context::TxContext,
)

To be called by the Listing administrator, to declare the intention of joining a Marketplace. This is the first step to join a marketplace. Joining a Marketplace is a two step process in which both the Listing admin and the Marketplace admin need to declare their intention to partner up.

public entry fun accept_listing_request(
    marketplace: &marketplace::Marketplace,
    listing: &mut listing::Listing,
    ctx: &mut tx_context::TxContext,
)

To be called by the Marketplace administrator, to accept the Listing request to join. This is the second step to join a marketplace. Joining a Marketplace is a two step process in which both the Listing admin and the Marketplace admin need to declare their intention to partner up.

public entry fun add_fee<FeeType: store + key>(
    marketplace: &marketplace::Marketplace,
    listing: &mut listing::Listing,
    fee: FeeType,
    ctx: &mut tx_context::TxContext,
)

Adds a fee object to the Listing's custom_fee

Can only be called by the Marketplace admin

public entry fun add_venue(
    listing: &mut listing::Listing,
    venue: venue::Venue,
    ctx: &mut tx_context::TxContext,
)

Adds a Venue to the Listing

Panics

Panics if inventory that Venue is assigned to does not exist or if transaction sender is not the listing admin.

public entry fun add_nft<C>(
    listing: &mut listing::Listing,
    inventory_id: object::ID,
    nft: nft::Nft<C>,
    ctx: &mut tx_context::TxContext,
)

Adds an Nft to a Warehouse on the Listing

To avoid shared consensus during mass minting, Warehouse can be constructed as a private object and later inserted into the Listing.

Panics

  • Inventory with the given ID does not exist
  • Inventory with the given ID is not a Warehouse
  • Transaction sender is not the listing admin

public entry fun add_inventory<C>(
    listing: &mut listing::Listing,
    inventory: inventory::Inventory<C>,
    ctx: &mut tx_context::TxContext,
)

Adds Inventory to Listing

Inventory is a type-erased wrapper around Warehouse or Factory.

To create a new inventory call inventory::from_warehouse or inventory::from_factory.

Panics

Panics if transaction sender is not the listing admin

public entry fun add_warehouse<C>(
    listing: &mut listing::Listing,
    collection: &collection::Collection<C>,
    warehouse: warehouse::Warehouse<C>,
    ctx: &mut tx_context::TxContext,
)

Adds Warehouse to Listing

Function transparently wraps Warehouse in Inventory, therefore, the returned ID is that of the Inventory not the Warehouse.

Panics

Panics if transaction sender is not listing admin or creator registered in CreatorsDomain.

public fun insert_warehouse<C>(
    witness: witness::Witness<C>,
    listing: &mut listing::Listing,
    warehouse: warehouse::Warehouse<C>,
    ctx: &mut tx_context::TxContext,
): object::ID

Adds Warehouse to Listing and returns it's ID

Function transparently wraps Warehouse in Inventory, therefore, the returned ID is that of the Inventory not the Warehouse.

Panics

Panics if transaction sender is not listing admin.

public entry fun add_factory<C>(
    listing: &mut listing::Listing,
    collection: &collection::Collection<C>,
    factory: factory::Factory<C>,
    ctx: &mut tx_context::TxContext,
)

Adds Factory to Listing

Function transparently wraps Factory in Inventory, therefore, the returned ID is that of the Inventory not the Factory.

Panics

Panics if transaction sender is not listing admin or creator registered in CreatorsDomain.

public fun insert_factory<C>(
    witness: witness::Witness<C>,
    listing: &mut listing::Listing,
    factory: factory::Factory<C>,
    ctx: &mut tx_context::TxContext,
): object::ID

Adds Factory to Listing and returns it's ID

Function transparently wraps Factory in Inventory, therefore, the returned ID is that of the Inventory not the Factory.

Panics

Panics if transaction sender is not listing admin.

public entry fun sale_on(
    listing: &mut listing::Listing,
    venue_id: object::ID,
    ctx: &mut tx_context::TxContext,
)

Set market's live status to true therefore making the NFT sale live. To be called by the Listing admin.

public entry fun sale_off(
    listing: &mut listing::Listing,
    venue_id: object::ID,
    ctx: &mut tx_context::TxContext,
)

Set market's live status to false therefore pausing or stopping the NFT sale. To be called by the Listing admin.

public entry fun sale_on_delegated(
    marketplace: &marketplace::Marketplace,
    listing: &mut listing::Listing,
    venue_id: object::ID,
    ctx: &mut tx_context::TxContext,
)

Set market's live status to true therefore making the NFT sale live. To be called by the Marketplace admin.

public entry fun sale_off_delegated(
    marketplace: &marketplace::Marketplace,
    listing: &mut listing::Listing,
    venue_id: object::ID,
    ctx: &mut tx_context::TxContext,
)

Set market's live status to false therefore pausing or stopping the NFT sale. To be called by the Marketplace admin.

public entry fun collect_proceeds<FT>(
    listing: &mut listing::Listing,
    ctx: &mut tx_context::TxContext,
)

To be called by Listing admins for standalone Listings. Standalone Listings do not envolve marketplace fees, and therefore the listing admin can freely call this entrypoint.

public fun receiver(listing: &listing::Listing): address

Get the Listing's receiver address

public fun admin(listing: &listing::Listing): address

Get the Listing's admin address

public fun contains_custom_fee(listing: &listing::Listing): bool

public fun custom_fee(listing: &listing::Listing): 
    &object_box::ObjectBox

public fun borrow_proceeds(listing: &listing::Listing): 
    &proceeds::Proceeds

Borrow the Listing's Proceeds

public fun borrow_proceeds_mut(listing: &mut listing::Listing): 
    &mut proceeds::Proceeds

Mutably borrow the Listing's Proceeds

public fun contains_venue(
    listing: &listing::Listing,
    venue_id: object::ID,
): bool

Returns whether Venue with given ID exists

public fun borrow_venue(
    listing: &listing::Listing,
    venue_id: object::ID,
): &venue::Venue

Borrow the listing's Venue

Panics

Panics if Venue does not exist.

public fun borrow_market<Market: store>(
    listing: &listing::Listing,
    venue_id: object::ID,
): &Market

Borrow the listing's Market

Panics

Panics if Market does not exist.

public fun venue_internal_mut<Market: store, Witness: drop>(
    _witness: Witness,
    listing: &mut listing::Listing,
    venue_id: object::ID,
): 
    &mut venue::Venue

Mutably borrow the listing's Venue

Venue and inventories are unprotected therefore only market modules registered on a Venue can gain mutable access to it.

Panics

Panics if witness does not originate from the same module as market.

public fun market_internal_mut<Market: store, Witness: drop>(
    witness: Witness,
    listing: &mut listing::Listing,
    venue_id: object::ID,
): 
    &mut Market

Mutably borrow the Listing's Market

Market is unprotected therefore only market modules registered on a Venue can gain mutable access to it.

Panics

Panics if witness does not originate from the same module as market.

public fun contains_inventory<C>(
    listing: &listing::Listing,
    inventory_id: object::ID,
): bool

Returns whether Inventory with given ID exists

public fun borrow_inventory<C>(
    listing: &listing::Listing,
    inventory_id: object::ID,
): &inventory::Inventory<C>

Borrow the listing's Inventory

Panics

Panics if Inventory does not exist.

public fun inventory_internal_mut<C, Market: store, Witness: drop>(
    witness: Witness,
    listing: &mut listing::Listing,
    venue_id: object::ID,
    inventory_id: object::ID,
): 
    &mut inventory::Inventory<C>

Mutably borrow a Warehouse

Warehouse is unprotected therefore only market modules registered on a Venue can gain mutable access to it.

Panics

Panics if witness does not originate from the same module as market.

public fun supply<C>(
    listing: &listing::Listing,
    inventory_id: object::ID,
): option::Option<u64>

Returns how many NFTs can be withdrawn

Returns none if the supply is uncapped

Panics

Panics if Warehouse or Listing with the ID does not exist

public fun assert_listing_marketplace_match(
    marketplace: &marketplace::Marketplace,
    listing: &listing::Listing,
)

public fun assert_listing_admin(
    listing: &listing::Listing,
    ctx: &mut tx_context::TxContext,
)

public fun assert_correct_admin(
    marketplace: &marketplace::Marketplace,
    listing: &listing::Listing,
    ctx: &mut tx_context::TxContext,
)

public fun assert_default_fee(listing: &listing::Listing)

public fun assert_venue(
    listing: &listing::Listing,
    venue_id: object::ID,
)

public fun assert_inventory<C>(
    listing: &listing::Listing,
    inventory_id: object::ID,
)