Skip to content

Commit

Permalink
Fix review comments, improvements of bying flow
Browse files Browse the repository at this point in the history
  • Loading branch information
Dkwcs committed Nov 27, 2024
1 parent 79a6412 commit 97dc111
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 60 deletions.
127 changes: 86 additions & 41 deletions docs/examples/move/nft_marketplace/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,47 @@ iota client call \
--function default
```

### 3. Publish `item_for_market.move`
### 3. Publish `nft_marketplace` package

#### 3.1(Optional) Publish Kiosk rules modules if these are not present in the network you are using

Publish Kiosk rules modules(package):

```bash
iota client publish
iota client publish iota/kiosk
```

### 4. Create an Item
After publishing, export the following variable:

- `RULES_PACKAGE_ID`: The ID of rules package.

#### 3.2 Publish marketplace extension

Publish the nft_marketplace.move module:

```bash
iota client publish iota/docs/examples/move/nft_marketplace
```

After publishing, export the following variables:

- `MARKETPLACE_PACKAGE_ID`: The ID of whole marketplace package.
- `MARKETPLACE_PUBLISHER_ID`: The ID of the publisher object created during marketplace package publishing."

### 4. Create an Clothing Store Item

Create an item, for instance:

```bash
iota client call \
--package $M_ITEMS_ID \
--module market_items \
--package $MARKETPLACE_PACKAGE_ID \
--module clothing_store \
--function new_jeans
```

After creation, export the following variables:
After creation, export the following variable:

- `PACKAGE_ID`: The ID of the `market_items` package.
- `ITEM_ID`: The ID of the published item (in this case, Jeans).
- `PUBLISHER_ID`: The ID of the publisher object created during package publishing."
- `CLOTHING_STORE_ITEM_ID`: The ID of the published item (in this case, Jeans).

### 5. Create a Transfer Policy

Expand All @@ -58,77 +77,103 @@ iota client call \
--module transfer_policy \
--function default \
--gas-budget 10000000 \
--args $PUBLISHER_ID \
--type-args "$ITEM_FOR_MARKET_PACKAGE_ID::market_items::Jeans"
--args $MARKETPLACE_PUBLISHER_ID \
--type-args "$MARKETPLACE_PACKAGE_ID::clothing_store::Jeans"
```

### 6. Publish rules and marketplace extension

Publish Kiosk rules modules:
After publishing, export the following variables:

```bash
iota client publish iota/kiosk/Move.toml
```
- `ITEM_TRANS_POLICY`: The ID of the item transfer policy object.
- `ITEM_TRANS_POLICY_CAP`: The ID of the item transfer policy object owner capability"

Publish the nft_marketplace.move module:

```bash
iota client publish iota/docs/examples/move/nft_marketplace/sources/nft_marketplace.move`
```

### 7. Install the Extension on the Kiosk
### 6. Install the Extension on the Kiosk

The install function enables installation of the Marketplace extension in a kiosk.
Under the hood it invokes `kiosk_extension::add` that adds extension to the Kiosk via dynamic field.
Install the marketplace extension on the created kiosk using the command:

```bash
iota client call \
--package $MARKETPLACE_ID \
--package $MARKETPLACE_PACKAGE_ID \
--module nft_marketplace \
--function install \
--args $KIOSK_ID $KIOSK_CAP_ID
```

### 8. Set a Price for the Item
### 7. Set a Price for the Item

Set the price for the item:

```bash
iota client call \
--package $MARKETPLACE_ID \
--package $MARKETPLACE_PACKAGE_ID \
--module nft_marketplace \
--function set_price \
--args $KIOSK_ID $KIOSK_CAP_ID $ITEM_ID 50000 \
--type-args "&ITEM_FOR_MARKET_PACKAGE_ID::market_items::Jeans"
--args $KIOSK_ID $KIOSK_CAP_ID $CLOTHING_STORE_ITEM_ID 50000 \
--type-args "$MARKETPLACE_PACKAGE_ID::clothing_store::Jeans"
```

### 9.(Optional) Set Royalties
### 8.(Optional) Set Royalties

Royalties are a percentage of the item's price or revenue paid to the owner for the use or sale of their asset.

Set royalties for the item:

```bash
iota client call \
--package $MARKETPLACE \
--package $MARKETPLACE_PACKAGE_ID \
--module nft_marketplace \
--function setup_royalties \
--args $ITEM_TRANS_POLICY_ID $ITEM_TRANS_POLICY_CAP_ID 5000 2000 \
--type-args "ITEM_FOR_MARKET_PACKAGE_ID::market_items::Jeans"
--args $ITEM_TRANS_POLICY $ITEM_TRANS_POLICY_CAP 5000 2000 \
--type-args "$MARKETPLACE_PACKAGE_ID::clothing_store::Jeans"
```

### 10. Buy an Item:
### 9. Buy an Item:

Here, when we buy an item, we pay the owner the item's price. If the royalty rule is enabled, an additional royalty fee, calculated as a percentage of the initial item price, is also paid. Once both payments are completed, the item is transferred to the buyer.
#### 9.1 Get the Item Price:

```bash
iota client ptb \
--move-call $MARKETPLACE_PACKAGE_ID::nft_marketplace::get_item_price "<$MARKETPLACE_PACKAGE_ID::clothing_store::Jeans>" @$KIOSK_ID @$CLOTHING_STORE_ITEM_ID --assign item_price \
```

#### 9.2(Optional) Calculate rolyalties of the Item:

```bash
--move-call $RULES_PACKAGE_ID::royalty_rule::fee_amount "<$MARKETPLACE_PACKAGE_ID::clothing_store::Jeans>" @$ITEM_TRANS_POLICY item_price --assign royalties_amount \
```

#### 9.3 Create a payment coin with a specific amount (price + optional royalties):

```bash
--split-coins gas "[item_price, royalties_amount]" --assign payment_coins \
--merge-coins payment_coins.0 "[payment_coins.1]" \
```

#### 9.4 Buy an Item using `payment_coins.0`:

Here, when we buy an item, we pay the owner the item's price. If the royalty rule is enabled, an additional royalty fee, calculated as a percentage of the initial item price, is also paid. Once both payments are completed, the item is ready for transferring to the buyer.

To purchase the item:

```bash
iota client call \
--package $MARKETPLACE \
--module nft_marketplace \
--function buy_item \
--args $KIOSK_ID $ITEM_TRANS_POLICY_ID &ITEM_ID $COIN_ID \
--type-args "ITEM_FOR_MARKET_PACKAGE_ID::market_items::Jeans"
--move-call $MARKETPLACE_PACKAGE_ID::nft_marketplace::buy_item "<$MARKETPLACE_PACKAGE_ID::clothing_store::Jeans>" @$KIOSK_ID @$ITEM_TRANS_POLICY @$CLOTHING_STORE_ITEM_ID payment_coins.0 --assign purchased_item
```

#### 9.5 Transfer an Item to the buyer:

```bash
--move-call 0x2::transfer::public_transfer "<$MARKETPLACE_PACKAGE_ID::clothing_store::Jeans>" purchased_item @<buyer address> \
```

The final purchase PTB request, including royalties, should look like this:

```bash
iota client ptb \
--move-call $MARKETPLACE_PACKAGE_ID::nft_marketplace::get_item_price "<$MARKETPLACE_PACKAGE_ID::clothing_store::Jeans>" @$KIOSK_ID @$CLOTHING_STORE_ITEM_ID --assign item_price \
--move-call $RULES_PACKAGE_ID::royalty_rule::fee_amount "<$MARKETPLACE_PACKAGE_ID::clothing_store::Jeans>" @$ITEM_TRANS_POLICY item_price --assign royalties_amount \
--split-coins gas "[item_price, royalties_amount]" --assign payment_coins \
--merge-coins payment_coins.0 "[payment_coins.1]" \
--move-call $MARKETPLACE_PACKAGE_ID::nft_marketplace::buy_item "<$MARKETPLACE_PACKAGE_ID::clothing_store::Jeans>" @$KIOSK_ID @$ITEM_TRANS_POLICY @$CLOTHING_STORE_ITEM_ID payment_coins.0 --assign purchased_item \
--move-call 0x2::transfer::public_transfer "<$MARKETPLACE_PACKAGE_ID::clothing_store::Jeans>" purchased_item @<buyer address>
```
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/// Module provides `mock` items for using them in nft_marketplace and rental extensions.
module nft_marketplace::market_items {
module nft_marketplace::clothing_store {
use iota::package;
/// One Time Witness.
public struct MARKET_ITEMS has drop {}
public struct CLOTHING_STORE has drop {}


fun init(otw: MARKET_ITEMS, ctx: &mut TxContext) {
fun init(otw: CLOTHING_STORE, ctx: &mut TxContext) {
package::claim_and_keep(otw, ctx)
}

Expand Down
43 changes: 28 additions & 15 deletions docs/examples/move/nft_marketplace/sources/nft_marketplace.move
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,13 @@ module nft_marketplace::nft_marketplace {
};

// rules imports
// use kiosk::floor_price_rule::Rule as FloorPriceRule;
// use kiosk::personal_kiosk_rule::Rule as PersonalRule;
use kiosk::royalty_rule::Rule as RoyaltyRule;
use kiosk::royalty_rule;
// use kiosk::witness_rule::Rule as WitnessRule;


// === Errors ===
const EExtensionNotInstalled: u64 = 0;
const EObjectNotExist: u64 = 1;
const EWrongPaymentRoyalties: u64 = 1;

// === Constants ===
const ALLOW_PLACE_AND_LOCK: u128 = 11;
Expand All @@ -30,7 +27,7 @@ module nft_marketplace::nft_marketplace {
/// Used as a key for the item that has been up for sale that's placed in the Extension's Bag.
public struct Listed has store, copy, drop { id: ID }

public struct ItemPrice<T: key + store> has store {
public struct ItemPrice<phantom T: key + store> has store {
/// Total amount of time offered for renting in days.
price: u64,
}
Expand Down Expand Up @@ -62,21 +59,23 @@ module nft_marketplace::nft_marketplace {
}

/// Buy listed item with the indicated price and pay royalties if needed
public fun buy_item<T: key + store>(kiosk: &mut Kiosk, policy: &mut TransferPolicy<T>, item_id: object::ID, mut payment: Coin<IOTA>, ctx: &mut TxContext) {
public fun buy_item<T: key + store>(kiosk: &mut Kiosk, policy: &mut TransferPolicy<T>, item_id: object::ID, mut payment: Coin<IOTA>, ctx: &mut TxContext): T {
assert!(kiosk_extension::is_installed<Marketplace>(kiosk), EExtensionNotInstalled);
let ItemPrice { price } = take_from_bag<T, Listed>(kiosk, Listed { id: item_id });
let payment_amount = payment.split(price, ctx);
let payment_amount_value = payment_amount.value();
let (item, mut transfer_request) = purchase(kiosk, item_id, payment_amount);

let payment_amount_value = payment.value();
let coin_price = payment.split(price, ctx);

let (item, mut transfer_request) = purchase(kiosk, item_id, coin_price);
if (policy.has_rule<T, RoyaltyRule>()) {
let royalties_value = royalty_rule::fee_amount(policy, payment_amount_value);
let royalties_coin = payment.split(royalties_value, ctx);
royalty_rule::pay(policy, &mut transfer_request, royalties_coin);
let royalties_value = royalty_rule::fee_amount(policy, price);
assert!(payment_amount_value == price + royalties_value, EWrongPaymentRoyalties);
royalty_rule::pay(policy, &mut transfer_request, payment);
} else {
payment.destroy_zero();
};
transfer_policy::confirm_request(policy, transfer_request);
transfer::public_transfer<T>(item, ctx.sender());
// Send a leftover back to buyer
transfer::public_transfer(payment, ctx.sender());
item
}


Expand All @@ -98,6 +97,20 @@ module nft_marketplace::nft_marketplace {
}


public fun get_item_price<T: key + store>(
kiosk: &Kiosk,
item_id: ID,
) : u64 {
let storage_ref = kiosk_extension::storage(Marketplace {}, kiosk);
let ItemPrice { price } = bag::borrow<Listed, ItemPrice<T>>(
storage_ref,
Listed { id: item_id },
);

*price
}


// === Private Functions ===

fun take_from_bag<T: key + store, Key: store + copy + drop>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ module nft_marketplace::rental_extension {
const ENotEnoughCoins: u64 = 2;
const EInvalidKiosk: u64 = 3;
const ERentingPeriodNotOver: u64 = 4;
const EObjectNotExist: u64 = 5;
const ETotalPriceOverflow: u64 = 6;

// === Constants ===
Expand Down

0 comments on commit 97dc111

Please sign in to comment.