{-# STDLIB_VERSION 3 #-} {-# CONTENT_TYPE DAPP #-} {-# SCRIPT_TYPE ACCOUNT #-} let maxAuctionDuration = 1440 * 30 # ~ 30 days # priceAssetId = "WAVES" or assetId @Callable(i) func startAuction(duration: Int, startPrice: Int, priceAssetId:String) = { let auctionId = toBase58String(i.transactionId) let endHeight = lastBlock.height + duration let pmt = extract(i.payment) if (duration > maxAuctionDuration) then throw("Duration is too long. Must be less than " + toString(maxAuctionDuration)) else WriteSet( [ DataEntry(auctionId, endHeight), DataEntry(auctionId + "_organizer", i.caller.bytes.toBase58String()), DataEntry(auctionId + "_lot_assetId", if (isDefined(pmt.assetId)) then toBase58String(value(pmt.assetId)) else "WAVES"), DataEntry(auctionId + "_lot_amount", pmt.amount), DataEntry(auctionId + "_startPrice", startPrice), DataEntry(auctionId + "_priceAssetId", priceAssetId) ]) } @Callable(i) func bid(auctionId: String) = { let pmt = extract(i.payment) let pmtAssetIdStr = if (isDefined(pmt.assetId)) then toBase58String(value(pmt.assetId)) else "WAVES" let callerAddressStr = i.caller.bytes.toBase58String() let endHeight = getIntegerValue(this, auctionId) let startPrice = getIntegerValue(this, auctionId + "_startPrice") let priceAssetId = getStringValue(this, auctionId + "_priceAssetId") let winAmount = getInteger(this, auctionId + "_winAmount") let winner = getString(this, auctionId + "_winner") let bidFromTheSameUser = isDefined(winner) && value(winner) == callerAddressStr let totalBidAmount = pmt.amount + if bidFromTheSameUser then value(winAmount) else 0 if (lastBlock.height >= endHeight) then throw("Auction already finished") else if (priceAssetId != pmtAssetIdStr) then throw("Bid must be in asset '" + priceAssetId + "'") else if (isDefined(winAmount) && totalBidAmount <= value(winAmount) || !isDefined(winAmount) && totalBidAmount <= startPrice) then throw("Bid must be more then " + toString(if isDefined(winAmount) then value(winAmount) else startPrice)) else if (bidFromTheSameUser || !isDefined(winner)) then WriteSet([ DataEntry(auctionId + "_winner", callerAddressStr), DataEntry(auctionId + "_winAmount", totalBidAmount) ]) else { let previousBidderAddr = addressFromStringValue(value(winner)) let priceAsset = if (priceAssetId == "WAVES" || priceAssetId == "") then unit else fromBase58String(priceAssetId) ScriptResult( WriteSet([ DataEntry(auctionId + "_winner", callerAddressStr), DataEntry(auctionId + "_winAmount", totalBidAmount) ]), TransferSet([ ScriptTransfer(previousBidderAddr, value(winAmount), priceAsset) ]) ) } } @Callable(i) func withdraw(auctionId: String) = { let pmt = extract(i.payment) let pmtAssetIdStr = if (isDefined(pmt.assetId)) then toBase58String(value(pmt.assetId)) else "WAVES" let callerAddressStr = i.caller.bytes.toBase58String() let endHeight = getIntegerValue(this, auctionId) let organizer = getStringValue(this, auctionId + "_organizer") let winner = getString(this, auctionId + "_winner") let lotAssetId = getStringValue(this, auctionId + "_lot_assetId") let lotAmount = getIntegerValue(this, auctionId + "_lot_amount") let priceAssetId = getStringValue(this, auctionId + "_priceAssetId") let winAmount = getIntegerValue(this, auctionId + "_winAmount") let lotAsset = if (lotAssetId == "WAVES") then unit else fromBase58String(lotAssetId) let priceAsset = if (priceAssetId == "WAVES" || priceAssetId == "") then unit else fromBase58String(priceAssetId) let winnerAddr = addressFromStringValue(value(winner)) let organizerAddr = addressFromStringValue(value(organizer)) let betAmount = getInteger(this, auctionId + "_bidder_" + callerAddressStr) if (lastBlock.height < endHeight) then throw("Auction is not finished yet") else if (!isDefined(winner)) then { if (isDefined(getString(this, auctionId + "_lot_passed"))) then throw("Organizer has already got his lot back") else ScriptResult( WriteSet([DataEntry(auctionId + "_lot_passed", organizer)]), TransferSet([ScriptTransfer(organizerAddr, lotAmount, lotAsset)]) ) } else { # Lot -> winner, winner's bet -> organizer if (isDefined(getString(this, auctionId + "_lot_passed"))) then throw("Lot is already passed to the winner, and organizer got his reward") else ScriptResult( WriteSet([DataEntry(auctionId + "_lot_passed", winnerAddr.bytes.toBase58String())]), TransferSet([ScriptTransfer(winnerAddr, lotAmount, lotAsset), ScriptTransfer(organizerAddr, winAmount, priceAsset)]) ) } }