Skip to content

Commit

Permalink
Merge pull request #250 from chexware/feature/anti-snipe-auctions
Browse files Browse the repository at this point in the history
Feature: Auction Pallet Improvements
  • Loading branch information
justinphamnz authored Nov 25, 2022
2 parents fb64619 + 6309a64 commit 1ad957e
Show file tree
Hide file tree
Showing 14 changed files with 492 additions and 267 deletions.
40 changes: 40 additions & 0 deletions .github/workflows/rust-benchmark.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Metaverse Build Benchmarking

on:
pull_request:
branches:
- master
push:
branches:
- master

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

jobs:
check:
# The type of runner that the job will run on
runs-on: ubuntu-20.04

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v3

- name: Set-Up
run: sudo apt install -y cmake pkg-config libssl-dev git build-essential clang libclang-dev curl

- name: Install Rustup
run: |
curl https://sh.rustup.rs -sSf | sh -s -- -y
source ~/.cargo/env
rustup default nightly && rustup update
rustup default nightly-2022-05-11
rustup target add wasm32-unknown-unknown --toolchain nightly-2022-05-11
- name: Check Rust version
run: rustup show
- name: Check Format
run: cargo fmt --all -- --check
- name: Build Benchmarking
run: |
SKIP_WASM_BUILD=1 cargo build --release --features runtime-benchmarks
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Metaverse Build & Test
name: Metaverse Build

on:
pull_request:
Expand Down Expand Up @@ -37,7 +37,4 @@ jobs:
run: cargo fmt --all -- --check
- name: Check Build
run: |
SKIP_WASM_BUILD=1 cargo check --release --features with-pioneer-runtime,with-metaverse-runtime
- name: Run all test cases
run: |
SKIP_WASM_BUILD= cargo test --all --features with-pioneer-runtime
SKIP_WASM_BUILD=1 cargo check --release --features with-pioneer-runtime,with-metaverse-runtime
38 changes: 38 additions & 0 deletions .github/workflows/rust-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Metaverse Test

on:
pull_request:
branches:
- master
push:
branches:
- master

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

jobs:
check:
# The type of runner that the job will run on
runs-on: ubuntu-20.04

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v3

- name: Set-Up
run: sudo apt install -y cmake pkg-config libssl-dev git build-essential clang libclang-dev curl

- name: Install Rustup
run: |
curl https://sh.rustup.rs -sSf | sh -s -- -y
source ~/.cargo/env
rustup default nightly && rustup update
rustup default nightly-2022-05-11
rustup target add wasm32-unknown-unknown --toolchain nightly-2022-05-11
- name: Check Rust version
run: rustup show
- name: Run all test cases
run: |
SKIP_WASM_BUILD= cargo test --all --features with-pioneer-runtime
82 changes: 72 additions & 10 deletions pallets/auction/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ pub mod pallet {
/// Minimum listing price
#[pallet::constant]
type MinimumListingPrice: Get<BalanceOf<Self>>;

/// Anti-snipe duration
#[pallet::constant]
type AntiSnipeDuration: Get<Self::BlockNumber>;
}

#[pallet::storage]
Expand Down Expand Up @@ -276,6 +280,8 @@ pub mod pallet {
NftOfferAccepted(ClassId, TokenId, T::AccountId),
/// Nft offer is withdrawn [class_id, token_id, account_id]
NftOfferWithdrawn(ClassId, TokenId, T::AccountId),
/// Auction extended. [auction_id, end_block]
AuctionExtended(AuctionId, T::BlockNumber),
}

/// Errors inform users that something went wrong.
Expand All @@ -289,6 +295,8 @@ pub mod pallet {
AuctionHasNotStarted,
/// Auction is expired
AuctionIsExpired,
/// Auction is not expired
AuctionIsNotExpired,
/// Auction type is supported for listing
AuctionTypeIsNotSupported,
/// Bid is not accepted e.g owner == bidder, listing stop accepting bid
Expand Down Expand Up @@ -345,6 +353,8 @@ pub mod pallet {
NoPermissionToMakeOffer,
/// No permission to accept offer for a NFT.
NoPermissionToAcceptOffer,
/// No permission to finalize auction
NoPermissionToFinalizeAuction,
/// Listing price is below the minimum.
ListingPriceIsBelowMinimum,
/// Only metaverse owner can participate
Expand Down Expand Up @@ -596,18 +606,13 @@ pub mod pallet {
///
/// The dispatch origin for this call must be _Root_.
/// this call
/// - `from`: the listing owner who created this listing
/// - `auction_id`: the auction id that wish to cancel
///
/// Emits `CollectionAuthorizationRemoveInMetaverse` if successful.
#[pallet::weight(T::WeightInfo::remove_authorise_metaverse_collection())]
/// Emits `AuctionCancelled` and `AuctionFinalizedNoBid` if successful.
#[pallet::weight(T::WeightInfo::cancel_listing())]
#[transactional]
pub fn cancel_listing(
origin: OriginFor<T>,
from: T::AccountId,
auction_id: AuctionId,
) -> DispatchResultWithPostInfo {
ensure_root(origin)?;
pub fn cancel_listing(origin: OriginFor<T>, auction_id: AuctionId) -> DispatchResultWithPostInfo {
let from = ensure_signed(origin)?;

ensure!(Auctions::<T>::contains_key(auction_id), Error::<T>::AuctionDoesNotExist);
let auction_item = AuctionItems::<T>::get(auction_id).ok_or(Error::<T>::AuctionDoesNotExist)?;
Expand Down Expand Up @@ -756,6 +761,27 @@ pub mod pallet {
Self::deposit_event(Event::<T>::NftOfferWithdrawn(asset.0, asset.1, offeror));
Ok(().into())
}

/// Manually finalize ended auction.
///
/// The dispatch origin for this call must be _Signed_.
/// - `auction_id`: the ID of the auction that will be finalized.
///
/// Emits `AuctionFinalized` or `AuctionFinalizedNoBid` if successful.
#[pallet::weight(T::WeightInfo::on_finalize())]
pub fn finalize_auction(origin: OriginFor<T>, auction_id: AuctionId) -> DispatchResultWithPostInfo {
ensure_signed(origin)?;

let auction = <Auctions<T>>::get(&auction_id).ok_or(Error::<T>::AuctionDoesNotExist)?;
ensure!(
auction.end.ok_or(Error::<T>::AuctionIsNotExpired)? < <system::Pallet<T>>::block_number(),
Error::<T>::AuctionIsNotExpired
);

T::Handler::on_auction_ended(auction_id, auction.bid);

Ok(().into())
}
}

#[pallet::hooks]
Expand Down Expand Up @@ -1072,7 +1098,7 @@ pub mod pallet {

/// Internal auction bid handler
fn auction_bid_handler(from: T::AccountId, id: AuctionId, value: Self::Balance) -> DispatchResult {
let auction_item: AuctionItem<T::AccountId, T::BlockNumber, BalanceOf<T>> =
let mut auction_item: AuctionItem<T::AccountId, T::BlockNumber, BalanceOf<T>> =
Self::get_auction_item(id.clone()).ok_or(Error::<T>::AuctionDoesNotExist)?;
ensure!(
auction_item.auction_type == AuctionType::Auction,
Expand Down Expand Up @@ -1124,6 +1150,27 @@ pub mod pallet {

Self::swap_new_bid(id, (from.clone(), value), auction.bid.clone())?;

if auction_item
.end_time
.saturating_sub(<system::Pallet<T>>::block_number())
<= T::AntiSnipeDuration::get()
{
// Trigger anti-snipe
// Remove existing auction end
AuctionEndTime::<T>::remove(auction_end, id);
// Extend auction end time
let new_auction_end = auction_end.saturating_add(T::AntiSnipeDuration::get());
// Update new auction item end time
auction_item.end_time = new_auction_end;
// Update storage key of auction item
AuctionItems::<T>::insert(id, auction_item);
// Update new auction end time
AuctionEndTime::<T>::insert(new_auction_end, id, ());
// Update auction struct
auction.end = Some(new_auction_end);
Self::deposit_event(Event::AuctionExtended(id, new_auction_end));
}

auction.bid = Some((from.clone(), value));
Self::deposit_event(Event::Bid(id, from, value));

Expand Down Expand Up @@ -1166,6 +1213,21 @@ pub mod pallet {
// Reserve balance
T::FungibleTokenCurrency::reserve(social_currency_id, &new_bidder, new_bid_price.saturated_into())?;
auction_item.amount = new_bid_price.clone();
if auction_item
.end_time
.saturating_sub(<system::Pallet<T>>::block_number())
<= T::AntiSnipeDuration::get()
{
let new_end = auction_item.end_time.saturating_add(T::AntiSnipeDuration::get());
if let Some(auction_info) = Self::auctions(id) {
let mut new_auction_info = auction_info;
new_auction_info.end = Some(new_end);
Auctions::<T>::insert(id, new_auction_info);
}
AuctionEndTime::<T>::remove(auction_item.end_time, id);
AuctionEndTime::<T>::insert(new_end, id, ());
auction_item.end_time = new_end;
}

Ok(())
})
Expand Down
2 changes: 2 additions & 0 deletions pallets/auction/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ parameter_types! {
pub const NetworkFeeCommission: Perbill = Perbill::from_percent(1); // Network fee collected after an auction is over
pub const OfferDuration: BlockNumber = 10; // Default 10
pub const MinimumListingPrice: Balance = 1;
pub const AntiSnipeDuration: BlockNumber = 5; // Default 5
}

pub struct MetaverseInfoSource {}
Expand Down Expand Up @@ -325,6 +326,7 @@ impl Config for Runtime {
type WeightInfo = ();
type OfferDuration = OfferDuration;
type MinimumListingPrice = MinimumListingPrice;
type AntiSnipeDuration = AntiSnipeDuration;
}

pub type AdaptedBasicCurrency = currencies::BasicCurrencyAdapter<Runtime, Balances, Amount, BlockNumber>;
Expand Down
Loading

0 comments on commit 1ad957e

Please sign in to comment.