IsCurrency (..),
)
( ProjectId,
UserId,
)
newtype AuctionId = AuctionId UUID
makePrisms ''AuctionId
data Auction c
= Auction
{ _projectId :: ProjectId,
BidId = BidId UUID
makePrisms ''BidId
data Bid c
= Bid
{ _bidUser :: UserId,
Commitment c
= Commitment
{ _baseBid :: Bid c,
AuctionResult c
= WinningBids [Bid c]
| InsufficientBids c
foldMap (view bidAmount)
comparing costRatio <> comparing (^. bidTime)
where
(toRational $ bid ^. bidSeconds) / (toRational $ bid ^. bidAmount . _Units)
-- lowest bids of seconds/btc win
runAuction' (auction ^. raiseAmount)
let takeWinningBids :: c -> [Bid c] -> [Bid c]
takeWinningBids total (bid : xs)
| total <> (bid ^. bidAmount) < raiseAmount' =
-- if the total is fully within the raise amount
bid : takeWinningBids (total <> (bid ^. bidAmount)) xs
| total < raiseAmount' =
-- if the last bid will exceed the raise amount, reduce it to fit
let winFraction r =
(r ^. _Units) % (bid ^. bidAmount . _Units)
remainderSeconds r =
Seconds . round $ winFraction r * fromIntegral (bid ^. bidSeconds)
adjustBid r =
bid & bidSeconds .~ remainderSeconds r & bidAmount .~ r
in toList $ adjustBid <$> raiseAmount' `csub` total
| otherwise =
[]
takeWinningBids _ [] = []
submittedTotal = bidsTotal bids
in maybe
(WinningBids $ takeWinningBids mempty $ sortBy bidOrder bids)
InsufficientBids
(raiseAmount' `csub` submittedTotal)
(