diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c8d683c..5fbaf138 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,12 @@ Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to - `create_safe_and_bid` - `create_safe_and_bid_with_commission` - `list_multiple_nfts` +- Helper endpoints in launchpad which allow marketplaces to perform actions in a single tx. + The marketplaces can now + - `create_safe_and_buy_whitelisted_nft` + - `create_safe_and_buy_nft` + - `buy_nft_into_safe` + - `buy_whitelisted_nft_into_safe` ### Fixed diff --git a/sources/launchpad/market/fixed_price.move b/sources/launchpad/market/fixed_price.move index 70bacf2b..248d0cea 100644 --- a/sources/launchpad/market/fixed_price.move +++ b/sources/launchpad/market/fixed_price.move @@ -9,13 +9,15 @@ module nft_protocol::fixed_price { use sui::balance; use sui::coin::{Self, Coin}; use sui::object::{Self, ID, UID}; + use sui::transfer::{transfer, share_object}; use sui::tx_context::{Self, TxContext}; - use sui::transfer; - use nft_protocol::venue; - use nft_protocol::listing::{Self, Listing}; use nft_protocol::inventory; + use nft_protocol::listing::{Self, Listing}; use nft_protocol::market_whitelist::{Self, Certificate}; + use nft_protocol::nft::Nft; + use nft_protocol::safe; + use nft_protocol::venue; /// Fixed price market object struct FixedPriceMarket has key, store { @@ -65,7 +67,7 @@ module nft_protocol::fixed_price { ctx: &mut TxContext, ) { let market = new(inventory_id, price, ctx); - transfer::transfer(market, tx_context::sender(ctx)); + transfer(market, tx_context::sender(ctx)); } /// Initializes a `Venue` with `FixedPriceMarket` @@ -137,7 +139,48 @@ module nft_protocol::fixed_price { venue::assert_is_live(venue); venue::assert_is_not_whitelisted(venue); - buy_nft_(listing, venue_id, wallet, ctx); + let nft = buy_nft_(listing, venue_id, wallet, ctx); + transfer(nft, tx_context::sender(ctx)); + } + + /// Buy NFT for non-whitelisted sale + /// + /// #### Panics + /// + /// Panics if `Venue` does not exist, is not live, or is whitelisted or + /// wallet does not have the necessary funds. + public entry fun buy_nft_into_safe( + listing: &mut Listing, + venue_id: ID, + wallet: &mut Coin, + buyer_safe: &mut safe::Safe, + ctx: &mut TxContext, + ) { + let venue = listing::borrow_venue(listing, venue_id); + venue::assert_is_live(venue); + venue::assert_is_not_whitelisted(venue); + + let nft = buy_nft_(listing, venue_id, wallet, ctx); + safe::deposit_nft(nft, buyer_safe, ctx); + } + + /// Buy NFT for non-whitelisted sale. + /// Deposits the NFT to a safe and transfers the ownership to the buyer. + /// + /// #### Panics + /// + /// Panics if `Venue` does not exist, is not live, or is whitelisted or + /// wallet does not have the necessary funds. + public entry fun create_safe_and_buy_nft( + listing: &mut Listing, + venue_id: ID, + wallet: &mut Coin, + ctx: &mut TxContext, + ) { + let (buyer_safe, owner_cap) = safe::new(ctx); + buy_nft_into_safe(listing, venue_id, wallet, &mut buyer_safe, ctx); + transfer(owner_cap, tx_context::sender(ctx)); + share_object(buyer_safe); } /// Buy NFT for whitelisted sale @@ -160,7 +203,61 @@ module nft_protocol::fixed_price { market_whitelist::burn(whitelist_token); - buy_nft_(listing, venue_id, wallet, ctx); + let nft = buy_nft_(listing, venue_id, wallet, ctx); + transfer(nft, tx_context::sender(ctx)); + } + + /// Buy NFT for whitelisted sale + /// Deposits the NFT to a safe and transfers the ownership to the buyer. + /// + /// #### Panics + /// + /// - If `Venue` does not exist, is not live, or is not whitelisted + /// - If whitelist `Certificate` was not issued for given market + public entry fun buy_whitelisted_nft_into_safe( + listing: &mut Listing, + venue_id: ID, + wallet: &mut Coin, + safe: &mut safe::Safe, + whitelist_token: Certificate, + ctx: &mut TxContext, + ) { + let venue = listing::borrow_venue(listing, venue_id); + venue::assert_is_live(venue); + venue::assert_is_whitelisted(venue); + market_whitelist::assert_certificate(&whitelist_token, venue_id); + + market_whitelist::burn(whitelist_token); + + let nft = buy_nft_(listing, venue_id, wallet, ctx); + safe::deposit_nft(nft, safe, ctx); + } + + /// Buy NFT for whitelisted sale + /// Deposits the NFT to a safe and transfers the ownership to the buyer. + /// + /// #### Panics + /// + /// - If `Venue` does not exist, is not live, or is not whitelisted + /// - If whitelist `Certificate` was not issued for given market + public entry fun create_safe_and_buy_whitelisted_nft( + listing: &mut Listing, + venue_id: ID, + wallet: &mut Coin, + whitelist_token: Certificate, + ctx: &mut TxContext, + ) { + let (buyer_safe, owner_cap) = safe::new(ctx); + buy_whitelisted_nft_into_safe( + listing, + venue_id, + wallet, + &mut buyer_safe, + whitelist_token, + ctx, + ); + transfer(owner_cap, tx_context::sender(ctx)); + share_object(buyer_safe); } /// Internal method to buy NFT @@ -174,7 +271,7 @@ module nft_protocol::fixed_price { venue_id: ID, wallet: &mut Coin, ctx: &mut TxContext, - ) { + ): Nft { let venue = listing::borrow_venue(listing, venue_id); let market = venue::borrow_market>(venue); @@ -188,9 +285,11 @@ module nft_protocol::fixed_price { ); let owner = tx_context::sender(ctx); - inventory::transfer(inventory, owner, ctx); + let nft = inventory::redeem_nft(inventory, owner, ctx); listing::pay(listing, funds, 1); + + nft } // === Modifier Functions === diff --git a/sources/launchpad/market/limited_fixed_price.move b/sources/launchpad/market/limited_fixed_price.move index c6329cfa..aa7934be 100644 --- a/sources/launchpad/market/limited_fixed_price.move +++ b/sources/launchpad/market/limited_fixed_price.move @@ -15,13 +15,15 @@ module nft_protocol::limited_fixed_price { use sui::coin::{Self, Coin}; use sui::object::{Self, ID, UID}; use sui::tx_context::{Self, TxContext}; - use sui::transfer; + use sui::transfer::{transfer, share_object}; use sui::vec_map::{Self, VecMap}; - use nft_protocol::venue; - use nft_protocol::listing::{Self, Listing}; use nft_protocol::inventory; + use nft_protocol::listing::{Self, Listing}; use nft_protocol::market_whitelist::{Self, Certificate}; + use nft_protocol::nft::Nft; + use nft_protocol::safe; + use nft_protocol::venue; /// Limit of NFTs withdrawn from the market was exceeded /// @@ -90,7 +92,7 @@ module nft_protocol::limited_fixed_price { ctx: &mut TxContext, ) { let market = new(inventory_id, limit, price, ctx); - transfer::transfer(market, tx_context::sender(ctx)); + transfer(market, tx_context::sender(ctx)); } /// Initializes a `Venue` with `LimitedFixedPriceMarket` @@ -204,7 +206,48 @@ module nft_protocol::limited_fixed_price { venue::assert_is_live(venue); venue::assert_is_not_whitelisted(venue); - buy_nft_(listing, venue_id, wallet, ctx); + let nft = buy_nft_(listing, venue_id, wallet, ctx); + transfer(nft, tx_context::sender(ctx)); + } + + /// Buy NFT for non-whitelisted sale + /// + /// #### Panics + /// + /// Panics if `Venue` does not exist, is not live, or is whitelisted or + /// wallet does not have the necessary funds. + public entry fun buy_nft_into_safe( + listing: &mut Listing, + venue_id: ID, + wallet: &mut Coin, + buyer_safe: &mut safe::Safe, + ctx: &mut TxContext, + ) { + let venue = listing::borrow_venue(listing, venue_id); + venue::assert_is_live(venue); + venue::assert_is_not_whitelisted(venue); + + let nft = buy_nft_(listing, venue_id, wallet, ctx); + safe::deposit_nft(nft, buyer_safe, ctx); + } + + /// Buy NFT for non-whitelisted sale. + /// Deposits the NFT to a safe and transfers the ownership to the buyer. + /// + /// #### Panics + /// + /// Panics if `Venue` does not exist, is not live, or is whitelisted or + /// wallet does not have the necessary funds. + public entry fun create_safe_and_buy_nft( + listing: &mut Listing, + venue_id: ID, + wallet: &mut Coin, + ctx: &mut TxContext, + ) { + let (buyer_safe, owner_cap) = safe::new(ctx); + buy_nft_into_safe(listing, venue_id, wallet, &mut buyer_safe, ctx); + transfer(owner_cap, tx_context::sender(ctx)); + share_object(buyer_safe); } /// Buy NFT for whitelisted sale @@ -227,7 +270,61 @@ module nft_protocol::limited_fixed_price { market_whitelist::burn(whitelist_token); - buy_nft_(listing, venue_id, wallet, ctx); + let nft = buy_nft_(listing, venue_id, wallet, ctx); + transfer(nft, tx_context::sender(ctx)); + } + + /// Buy NFT for whitelisted sale + /// Deposits the NFT to a safe and transfers the ownership to the buyer. + /// + /// #### Panics + /// + /// - If `Venue` does not exist, is not live, or is not whitelisted + /// - If whitelist `Certificate` was not issued for given market + public entry fun buy_whitelisted_nft_into_safe( + listing: &mut Listing, + venue_id: ID, + wallet: &mut Coin, + safe: &mut safe::Safe, + whitelist_token: Certificate, + ctx: &mut TxContext, + ) { + let venue = listing::borrow_venue(listing, venue_id); + venue::assert_is_live(venue); + venue::assert_is_whitelisted(venue); + market_whitelist::assert_certificate(&whitelist_token, venue_id); + + market_whitelist::burn(whitelist_token); + + let nft = buy_nft_(listing, venue_id, wallet, ctx); + safe::deposit_nft(nft, safe, ctx); + } + + /// Buy NFT for whitelisted sale + /// Deposits the NFT to a safe and transfers the ownership to the buyer. + /// + /// #### Panics + /// + /// - If `Venue` does not exist, is not live, or is not whitelisted + /// - If whitelist `Certificate` was not issued for given market + public entry fun create_safe_and_buy_whitelisted_nft( + listing: &mut Listing, + venue_id: ID, + wallet: &mut Coin, + whitelist_token: Certificate, + ctx: &mut TxContext, + ) { + let (buyer_safe, owner_cap) = safe::new(ctx); + buy_whitelisted_nft_into_safe( + listing, + venue_id, + wallet, + &mut buyer_safe, + whitelist_token, + ctx, + ); + transfer(owner_cap, tx_context::sender(ctx)); + share_object(buyer_safe); } /// Internal method to buy NFT @@ -241,7 +338,7 @@ module nft_protocol::limited_fixed_price { venue_id: ID, wallet: &mut Coin, ctx: &mut TxContext, - ) { + ): Nft { let venue = listing::venue_internal_mut< LimitedFixedPriceMarket, Witness >( @@ -262,9 +359,11 @@ module nft_protocol::limited_fixed_price { Witness {}, listing, venue_id, inventory_id ); - inventory::transfer(inventory, owner, ctx); + let nft = inventory::redeem_nft(inventory, owner, ctx); listing::pay(listing, funds, 1); + + nft } // === Modifier Functions ===