Buy&Sell methods for Uniques (#11398)

* Allow to set item's price

* Clean the state when we transfer/burn an item or destroy a collection

* Allow to buy an item

* Remove redundant checks

* Improve events

* Cover with tests

* Add comments

* Apply suggestions

* Fmt

* Improvements for price validation

* Improve validation

* Update to use the new terminology

* Remove multi-assets support

* Chore

* Weights + benchmarking

* Shield against human error

* Test when we pass the higher item's price

* fmt fix

* Chore

* cargo run --quiet --profile=production  --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_uniques --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/uniques/src/weights.rs --template=./.maintain/frame-weight-template.hbs

* Remove is_frozen check when setting the price

* Try to fix benchmarking

* Fix benchmarking

* cargo run --quiet --profile=production  --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_uniques --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/uniques/src/weights.rs --template=./.maintain/frame-weight-template.hbs

* Add transactional

* Add 'allow deprecated' flag for transactional

* Remove #[allow(deprecated)]

* ".git/.scripts/bench-bot.sh" pallet dev pallet_uniques

Co-authored-by: Parity Bot <admin@parity.io>
Co-authored-by: command-bot <>
This commit is contained in:
Jegor Sidorenko
2022-07-13 13:41:20 +01:00
committed by GitHub
parent 3ea6a88eba
commit 5d96c0a0ea
6 changed files with 485 additions and 72 deletions
+177 -1
View File
@@ -18,7 +18,7 @@
//! Tests for Uniques pallet.
use crate::{mock::*, Event, *};
use frame_support::{assert_noop, assert_ok, traits::Currency};
use frame_support::{assert_noop, assert_ok, dispatch::Dispatchable, traits::Currency};
use pallet_balances::Error as BalancesError;
use sp_std::prelude::*;
@@ -694,3 +694,179 @@ fn max_supply_should_work() {
assert!(!CollectionMaxSupply::<Test>::contains_key(collection_id));
});
}
#[test]
fn set_price_should_work() {
new_test_ext().execute_with(|| {
let user_id = 1;
let collection_id = 0;
let item_1 = 1;
let item_2 = 2;
assert_ok!(Uniques::force_create(Origin::root(), collection_id, user_id, true));
assert_ok!(Uniques::mint(Origin::signed(user_id), collection_id, item_1, user_id));
assert_ok!(Uniques::mint(Origin::signed(user_id), collection_id, item_2, user_id));
assert_ok!(Uniques::set_price(
Origin::signed(user_id),
collection_id,
item_1,
Some(1),
None,
));
assert_ok!(Uniques::set_price(
Origin::signed(user_id),
collection_id,
item_2,
Some(2),
Some(3)
));
let item = ItemPriceOf::<Test>::get(collection_id, item_1).unwrap();
assert_eq!(item.0, 1);
assert_eq!(item.1, None);
let item = ItemPriceOf::<Test>::get(collection_id, item_2).unwrap();
assert_eq!(item.0, 2);
assert_eq!(item.1, Some(3));
assert!(events().contains(&Event::<Test>::ItemPriceSet {
collection: collection_id,
item: item_1,
price: 1,
whitelisted_buyer: None,
}));
// validate we can unset the price
assert_ok!(Uniques::set_price(Origin::signed(user_id), collection_id, item_2, None, None));
assert!(events().contains(&Event::<Test>::ItemPriceRemoved {
collection: collection_id,
item: item_2
}));
assert!(!ItemPriceOf::<Test>::contains_key(collection_id, item_2));
});
}
#[test]
fn buy_item_should_work() {
new_test_ext().execute_with(|| {
let user_1 = 1;
let user_2 = 2;
let user_3 = 3;
let collection_id = 0;
let item_1 = 1;
let item_2 = 2;
let item_3 = 3;
let price_1 = 20;
let price_2 = 30;
let initial_balance = 100;
Balances::make_free_balance_be(&user_1, initial_balance);
Balances::make_free_balance_be(&user_2, initial_balance);
Balances::make_free_balance_be(&user_3, initial_balance);
assert_ok!(Uniques::force_create(Origin::root(), collection_id, user_1, true));
assert_ok!(Uniques::mint(Origin::signed(user_1), collection_id, item_1, user_1));
assert_ok!(Uniques::mint(Origin::signed(user_1), collection_id, item_2, user_1));
assert_ok!(Uniques::mint(Origin::signed(user_1), collection_id, item_3, user_1));
assert_ok!(Uniques::set_price(
Origin::signed(user_1),
collection_id,
item_1,
Some(price_1),
None,
));
assert_ok!(Uniques::set_price(
Origin::signed(user_1),
collection_id,
item_2,
Some(price_2),
Some(user_3),
));
// can't buy for less
assert_noop!(
Uniques::buy_item(Origin::signed(user_2), collection_id, item_1, 1),
Error::<Test>::BidTooLow
);
// pass the higher price to validate it will still deduct correctly
assert_ok!(Uniques::buy_item(Origin::signed(user_2), collection_id, item_1, price_1 + 1,));
// validate the new owner & balances
let item = Item::<Test>::get(collection_id, item_1).unwrap();
assert_eq!(item.owner, user_2);
assert_eq!(Balances::total_balance(&user_1), initial_balance + price_1);
assert_eq!(Balances::total_balance(&user_2), initial_balance - price_1);
// can't buy from yourself
assert_noop!(
Uniques::buy_item(Origin::signed(user_1), collection_id, item_2, price_2),
Error::<Test>::NoPermission
);
// can't buy when the item is listed for a specific buyer
assert_noop!(
Uniques::buy_item(Origin::signed(user_2), collection_id, item_2, price_2),
Error::<Test>::NoPermission
);
// can buy when I'm a whitelisted buyer
assert_ok!(Uniques::buy_item(Origin::signed(user_3), collection_id, item_2, price_2,));
assert!(events().contains(&Event::<Test>::ItemBought {
collection: collection_id,
item: item_2,
price: price_2,
seller: user_1,
buyer: user_3,
}));
// ensure we reset the buyer field
assert!(!ItemPriceOf::<Test>::contains_key(collection_id, item_2));
// can't buy when item is not for sale
assert_noop!(
Uniques::buy_item(Origin::signed(user_2), collection_id, item_3, price_2),
Error::<Test>::NotForSale
);
// ensure we can't buy an item when the collection or an item is frozen
{
assert_ok!(Uniques::set_price(
Origin::signed(user_1),
collection_id,
item_3,
Some(price_1),
None,
));
// freeze collection
assert_ok!(Uniques::freeze_collection(Origin::signed(user_1), collection_id));
let buy_item_call = mock::Call::Uniques(crate::Call::<Test>::buy_item {
collection: collection_id,
item: item_3,
bid_price: price_1,
});
assert_noop!(buy_item_call.dispatch(Origin::signed(user_2)), Error::<Test>::Frozen);
assert_ok!(Uniques::thaw_collection(Origin::signed(user_1), collection_id));
// freeze item
assert_ok!(Uniques::freeze(Origin::signed(user_1), collection_id, item_3));
let buy_item_call = mock::Call::Uniques(crate::Call::<Test>::buy_item {
collection: collection_id,
item: item_3,
bid_price: price_1,
});
assert_noop!(buy_item_call.dispatch(Origin::signed(user_2)), Error::<Test>::Frozen);
}
});
}