1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
{-# 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)])
)
}
}
|