Auction Sale Implementation Design (English variation) ===== <style>.markdown-body { max-width: 1500px; }</style> [TOC] ----- Auction Asset Listing --- [As an asset provider I want to list my asset for sale as an auction](https://miro.com/app/board/uXjVOXldX24=/?moveToWidget=3458764515998653314&cot=14) ```mermaid sequenceDiagram actor Provider actor Scheduler actor RSK participant ListingManager participant EnglishAuctionStrategy Provider ->> ListingManager: create Listing activate ListingManager note over ListingManager: using AssetManager ListingManager ->> ListingManager: asset owner = msg.sender alt NOT AN ASSET OWNER ListingManager -->> Provider: revert end ListingManager ->> ListingManager: asset state = Active alt ASSET NOT ACTIVE ListingManager -->> Provider: revert end ListingManager ->> ListingManager: end date >= timeNowWindow alt END DATE IN THE PAST ListingManager -->> Provider: revert end note over ListingManager: using Configuration ListingManager ->> ListingManager: sale strategy is whitelisted alt NOT A WHITELISTED SALE STRATEGY ListingManager -->> Provider: revert end ListingManager ->> ListingManager: generate listing ID ListingManager ->> ListingManager: listingById[listingId] => Listing ListingManager ->> ListingManager: marketplace fee > 0 note over ListingManager: using Marketplace alt HAS MARKETPLACE FEE ListingManager -->> ListingManager: store fee in Listing end ListingManager ->> ListingManager: sponsor fee > 0 alt HAS SPONSOR FEE ListingManager -->> ListingManager: store fee in Listing end ListingManager ->> EnglishAuctionStrategy: createAuction activate EnglishAuctionStrategy EnglishAuctionStrategy ->> EnglishAuctionStrategy: is manager in whitelist alt CONTRACT NOT ALLOWED IN SALE STRATEGY EnglishAuctionStrategy -->> ListingManager: revert end EnglishAuctionStrategy ->> EnglishAuctionStrategy: auctionItem[msg.sender][listingId] => (owner) deactivate EnglishAuctionStrategy ListingManager ->> ListingManager: is currency whitelisted alt NOT A WHITELISTED CURRENCY ListingManager -->> Provider: revert end ListingManager ->> ListingManager: store currency <- price ListingManager ->> EnglishAuctionStrategy: registerAuctionCurrency activate EnglishAuctionStrategy EnglishAuctionStrategy ->> EnglishAuctionStrategy: minBidStepPerCurrency includes currency alt CURRENCY NOT AVAILABLE IN THE SALE STARTEGY EnglishAuctionStrategy -->> Provider: revert end EnglishAuctionStrategy ->> EnglishAuctionStrategy: minimumBid >= minBidStepPerCurrency alt MIN BID STEP LOWER THAN REQUIRED BY SALE STRATEGY FOR GIVEN CURRENCY EnglishAuctionStrategy -->> Provider: revert end EnglishAuctionStrategy ->> EnglishAuctionStrategy: auctionItem[msg.sender][listingId][currency] => CurrencyItem EnglishAuctionStrategy -->> ListingManager: deactivate EnglishAuctionStrategy ListingManager -) EnglishAuctionStrategy: transfer Asset note right of ListingManager: sent to the given ISaleStrategy ListingManager -) RSK: emit Listing Created event ListingManager ->> ListingManager: endDate == timeNowWindow alt ACTIVATE IMMEDIATELY ListingManager ->> ListingManager: activateAuction end alt SCHEDULE ACTIVATION ListingManager ->> ListingManager: Listing.deputy => Scheduler ListingManager -) Scheduler: set timeout (ListingManager.activateListing) end ListingManager -->> Provider: deactivate ListingManager ``` Activate an Asset Auction --- [As an asset provider I want to activate an asset auction sale](https://miro.com/app/board/uXjVOXldX24=/?moveToWidget=3458764516161937801&cot=14) ```mermaid sequenceDiagram actor Scheduler actor RSK participant ListingManager participant EnglishAuctionStrategy Scheduler ->> ListingManager: activateListing activate ListingManager ListingManager ->> ListingManager: Listing.deputy = Scheduler alt DEPUTY IS SCHEDULER ListingManager -) Scheduler: remove timeout (ListingManager.activateListing) end ListingManager ->> ListingManager: msg.sender = Asset.owner || Listing.deputy alt ACCOUNT NOT ALLOWED ListingManager -->> Provider: revert end ListingManager ->> ListingManager: listing state = Active alt LISTING ALREADY ACTIVE ListingManager -->> Provider: revert end ListingManager ->> ListingManager: asset state != Active alt NOT AN ACTIVE ASSET ListingManager -->> Provider: revert end ListingManager ->> ListingManager: Listing.state => Active ListingManager ->> ListingManager: Listing.deputy => EnglishAuctionStrategy ListingManager ->> EnglishAuctionStrategy: activateAuction activate EnglishAuctionStrategy EnglishAuctionStrategy ->> EnglishAuctionStrategy: auctionItem[msg.sender][listingId].state => Active EnglishAuctionStrategy -) Scheduler: set timout (triggerEndSale) EnglishAuctionStrategy -->> ListingManager: deactivate EnglishAuctionStrategy ListingManager -) RSK: emit Listing Activated event deactivate ListingManager ``` Process Bids on Auction --- [As an asset owner, I want to accept bids on my auction](https://miro.com/app/board/uXjVOXldX24=/?moveToWidget=3458764516120318325&cot=14) ```mermaid sequenceDiagram actor Bidder actor RSK actor Scheduler participant Marketplace participant AssetManager participant ListingManager participant EnglishAuctionStrategy Bidder ->> ListingManager: placeBid(listingId, currency, bid) activate ListingManager ListingManager ->> EnglishAuctionStrategy: placeBid(listingId, currency, bid, bidder) activate EnglishAuctionStrategy EnglishAuctionStrategy ->> ListingManager: get Listing ListingManager -->> EnglishAuctionStrategy: Listing EnglishAuctionStrategy ->> EnglishAuctionStrategy: auction is active alt NOT AN ACTIVE AUCTION EnglishAuctionStrategy -->> Bidder: revert end EnglishAuctionStrategy ->> EnglishAuctionStrategy: auction[currency]. alt NOT ALLOWED CURRENCY EnglishAuctionStrategy -->> Bidder: revert end EnglishAuctionStrategy ->> EnglishAuctionStrategy: price oracle exists alt without oracle EnglishAuctionStrategy ->> EnglishAuctionStrategy: currency count is 1 alt PRICE COMPARISSON FAILED EnglishAuctionStrategy ->> Bidder: revert end end EnglishAuctionStrategy ->> EnglishAuctionStrategy: is bid > (highestBid ? (highestBid + minBidStep) : reservedPrice) alt BID TOO LOW EnglishAuctionStrategy -->> Bidder: revert end EnglishAuctionStrategy ->> EnglishAuctionStrategy: is highestBid > 0 alt RELEASE_LAST_BID_FUNDS EnglishAuctionStrategy ->> EnglishAuctionStrategy: balance[highestBidder][currency] => bighestBid EnglishAuctionStrategy -->> RSK: emit event BidReleased end EnglishAuctionStrategy ->> EnglishAuctionStrategy: highestBidder => msg.sender EnglishAuctionStrategy ->> EnglishAuctionStrategy: highestBid => bid EnglishAuctionStrategy ->> EnglishAuctionStrategy: is bid >= buyNowThreshold || endDate <= now alt BUY NOW (triggerEndSale) EnglishAuctionStrategy ->> EnglishAuctionStrategy: is scheduler set alt CANCEL SCHEDULER EnglishAuctionStrategy -) Scheduler: cancel schedule end EnglishAuctionStrategy ->> ListingManager: endSale(listingId) end EnglishAuctionStrategy -->> ListingManager: ListingManager -->> Bidder: deactivate EnglishAuctionStrategy deactivate ListingManager ``` Change price of an Auction --- ```mermaid sequenceDiagram actor Provider participant ListingManager participant EnglishAuctionStrategy Provider ->> ListingManager: changePrice ListingManager ->> ListingManager: some checks activate ListingManager ListingManager ->> EnglishAuctionStrategy: changeReservedPrice activate EnglishAuctionStrategy EnglishAuctionStrategy ->> EnglishAuctionStrategy: is currency in minBidStepPerCurrency EnglishAuctionStrategy ->> EnglishAuctionStrategy: is highestBidder = 0 EnglishAuctionStrategy ->> EnglishAuctionStrategy: set reservedPrice EnglishAuctionStrategy -->> ListingManager: deactivate EnglishAuctionStrategy ListingManager -->> Provider: deactivate ListingManager ``` Extend Expiration Time of Auction --- ```mermaid sequenceDiagram actor Provider actor Scheduler participant ListingManager participant EnglishAuctionStrategy Provider ->> ListingManager: changeEndDate ListingManager ->> ListingManager: some checks ``` Transfer Assets & Funds on Auction Completion --- [As an asset provider, I want to transfer my asset and receive funds upon the satisfaction of the auction parameters](https://miro.com/app/board/uXjVOXldX24=/?moveToWidget=3458764516120428706&cot=14) ```mermaid sequenceDiagram actor Bidder actor Provider actor Scheduler participant ListingManager participant EnglishAuctionStrategy Scheduler ->> ListingManager: endAuction activate ListingManager ListingManager ->> EnglishAuctionStrategy: endAuction activate EnglishAuctionStrategy EnglishAuctionStrategy ->> EnglishAuctionStrategy: deactivate EnglishAuctionStrategy deactivate ListingManager ``` Class Diagram --- ```mermaid classDiagram class Scheduler { <<external>> } class Listing { <<struct>> ... deputy: address } class IListingManagementStrategy { <<interface>> #setDeputy(newDeputy: address) +endSale(listingId) } class ListingManager { } class Escrow { <<external>> } class Ownable { <<external>> } class ISaleStrategy { <<interface>> +placeBid(listingId: uint256, bidCurrency: address, bidAmount: uint256, bidder: address) +createAuction(listingId: bytes32, owner: address) +registerAuctionCurrency(listingId: bytes32, currency: address, reservedPrice: uint256, buyNowPrice: uint256, minBidIncrement: uint256): bool +changeReservedPrice(listingId: uint256, currency: address, price: uin256) +endAuction(listingId: uint256) } class Bid { <<struct>> currency: address; bid: uint256; bidder: address; } class AuctionState { <<enum>> Initial Created Active } class Price { buyNowPrice: uint256; reservedPrice: uint256; minBidStep: uint256; } class AuctionItem { address assetOwner; AuctionState state; bytes32 scheduleId; price: AuctionPrice currency: address; bids: mapping[uint256 => Bid]; bidCount: uint256; } class AbstractScheduler { <<abstract>> -_scheduler: RifScheduler -_schedulerPlanIndex: uint256 # virtual _validateCaller(): bool +setScheduler(scheduler: RIFScheduler, planId: uint256) +getScheduler(): (RIFScheduler, uint256) } class AbstractSaleStrategy { <<abstract>> -_managerWhitelist: mapping[address => bool] -_currencyWhitelist: mapping[address => bool] -_auctionsByListing: mapping[address => mapping[uint256 => AuctionItem]] # virtual _validateListing(manager: address, listingId: uint256, assetOwner: address): bool # virtual _validateCurrency(manager: address, listingId: uint256, currency: address): bool # virtual _validatePrice(item: AuctionItem, currency: address, price: Price): bool # virtual _validateBid(manager: address, listingId: uint256, bid: Bid): bool # virtual _validateEndDate(manager: address, listingId: uint256, date: uint256) # virtual _triggerEndSale(manager: address, listingId: uint256) +allowListingManager(listingManager: IListingManagementStrategy) +revokeListingManager(listingManager: IListingManagementStrategy) +isWhitelistedListingManager(listingManager: IListingManagementStrategy): bool +allowCurrency(currency: address) +revokeCurrency(currency: address) +isWhitelistedCurrency(currency: address): bool +getAuctionItem(manage: IListingManagementStrategy, listingId: uint256): AuctionItem +getPriceForCurrency(manage: IListingManagementStrategy, listingId: uint256, currency: address): Price +createAuction(listingId: uint256, assetOwner: address) +registerAuctionCurrency(listingId: uint256, currency: address, price: Price) +activateAuction(listingId: uint256, uint256 endDate) +triggerEndSale(manager: address, listingId: uint256) +deactivateAuction(listingId: uint256) +endAuction(listingId: uint256, assetId: bytes32, fees: Fee[]) +placeBid(listingId: uint256, bid: Bid) +changePrice(listingId: uint256, currency: address, price: Price) +changeEndDate(listingId: uint256, date: uint256) } class AbstractAuction { <<abstract>> #minBidStepPerCurrency: mapping[address => uint256] } class FixedPriceStrategy { } class EnglishAuctionStrategy { } AuctionItem *--> Price AuctionItem o--> Bid AuctionItem *--> AuctionState AbstractSaleStrategy o--> AuctionItem AbstractSaleStrategy ..|> ISaleStrategy AbstractSaleStrategy --|> Escrow AbstractSaleStrategy --|> Ownable AbstractSaleStrategy *--> AbstractScheduler AbstractAuction --|> AbstractSaleStrategy EnglishAuctionStrategy --|> AbstractAuction FixedPriceStrategy --|> AbstractSaleStrategy ListingManager o--> Listing ListingManager ..|> IListingManagementStrategy Scheduler -- IListingManagementStrategy ListingManager o--> ISaleStrategy ``` ------------ ## Flow of ownership ![](https://i.imgur.com/z7SoHIV.png) ------------ ## Contract details ### EnglishAuctionStrategy #### Variables 1. listings: mapping[listingManagerAddr => mapping[listingID => mapping[currency => AuctionItem]]]