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

------------
## Contract details
### EnglishAuctionStrategy
#### Variables
1. listings: mapping[listingManagerAddr => mapping[listingID => mapping[currency => AuctionItem]]]