-
Notifications
You must be signed in to change notification settings - Fork 133
/
takeAskOrder.se
207 lines (185 loc) · 9.02 KB
/
takeAskOrder.se
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# Copyright (C) 2015 Forecast Foundation OU, full GPL notice in LICENSE
macro ORDERS: self.controller.lookup('orders')
macro COMPLETE_SETS: self.controller.lookup('completeSets')
macro ORDERS_FETCHER: self.controller.lookup('ordersFetcher')
inset('../macros/externs.sem')
inset('../macros/assertNoValue.sem')
inset('../macros/safeMath.sem')
inset('../macros/unitConversions.sem')
inset('../macros/require.sem')
inset('../macros/orderFields.sem')
data controller
data owner
# Trade types
macro BID: 1
macro ASK: 2
# Field counts
macro ORDER_FIELDS: 8
def any():
assertNoValue()
def init():
self.owner = msg.sender
def initialize(controller: address):
require(not self.controller)
require(msg.sender == self.owner)
self.controller = controller
return 1
# Filling an ask [aka buying shares]
# Scenarios:
# - Asker (maker) escrowed maxValue - price and expects complete set minus the one they're selling
# - Asker (maker) had shares and escrowed them and expects to be paid price - minValue for them
# - Bidder (taker/sender) pays price - minValue for their shares
# @internal
# @return fxp
def takeAskOrder(taker: address, orderID: address, market: address, outcome: int256, fxpAmountTakerWants: int256, tradeGroupID: int256):
assertNoValue()
self.controller.assertIsWhitelisted(msg.sender)
# Get order
order = array(ORDER_FIELDS)
order = ORDERS_FETCHER.getOrder(orderID, ASK, market, outcome, outitems=ORDER_FIELDS)
takerDesiredShares = min(fxpAmountTakerWants, order[ATTOSHARES])
orderDisplayPrice = order[DISPLAY_PRICE]
maker = order[OWNER]
makerSharesEscrowed = min(order[SHARES_ESCROWED], fxpAmountTakerWants)
require(maker != taker)
require(orderDisplayPrice <= market.getMaxDisplayPrice())
require(orderDisplayPrice >= market.getMinDisplayPrice())
require(market.getMaxDisplayPrice() + market.getMinDisplayPrice() <= 2**254)
# We can't use safeSub here because it disallows subtracting negative numbers. Worst case here is an operation of 2**254 - 1 as required above, which won't overflow
sharePriceShort = market.getMaxDisplayPrice() - orderDisplayPrice
# We can't use safeSub here because it disallows subtracting negative numbers. Worst case here is an operation of 2**254 - 1 as required above, which won't overflow
sharePriceLong = orderDisplayPrice - market.getMinDisplayPrice()
shareToken = market.getShareToken(outcome)
denominationToken = market.getDenominationToken()
numberOfOutcomes = market.getNumberOfOutcomes()
# sanity checks
require(not denominationToken.balanceOf(self))
i = 0
while i < numberOfOutcomes:
require(not market.getShareToken(i).balanceOf(self))
i += 1
makerSharesDepleted = 0
makerTokensDepleted = 0
takerSharesDepleted = 0
takerTokensDepleted = 0
# figure out how much of the taker's target will be leftover at the end
fxpAmountTakerWants = safeSub(fxpAmountTakerWants, takerDesiredShares)
# figure out how many shares taker has available to complete this bid
takerSharesAvailable = takerDesiredShares
i = 0
while i < numberOfOutcomes:
if i != outcome:
takerSharesAvailable = min(takerSharesAvailable, market.getShareToken(i).balanceOf(taker))
i += 1
# maker is closing a long, taker is closing a short
if makerSharesEscrowed and takerSharesAvailable:
# figure out how many complete sets exist between the maker and taker
completeSets = min(makerSharesEscrowed, takerSharesAvailable)
# transfer the appropriate amount of shares from maker (escrowed in market) to this contract
shareToken.transferFrom(market, self, completeSets)
# transfer the appropriate amount of shares from taker to this contract
i = 0
while i < numberOfOutcomes:
tempShareToken = market.getShareToken(i)
if tempShareToken.allowance(self, COMPLETE_SETS) < completeSets:
tempShareToken.approve(COMPLETE_SETS, 2**254)
if i != outcome:
tempShareToken.transferFrom(taker, self, completeSets)
i += 1
# sell the complete sets (this will pay fees)
COMPLETE_SETS.sellCompleteSets(self, market, completeSets)
# figure out the expected payout before fees
cost = COMPLETE_SETS.getCompleteSetsValue(market, completeSets)
# get the completeSetFee
payout = denominationToken.balanceOf(self)
completeSetFee = safeSub(cost, payout)
# maker gets their share minus proportional fee
cumulativeScale = market.getCompleteSetCostInAttotokens()
longFee = safeDiv(safeMul(completeSetFee, sharePriceLong), cumulativeScale)
makerShare = safeFxpMul(completeSets, sharePriceLong) - longFee
denominationToken.transfer(maker, makerShare)
# taker gets remainder
takerShare = denominationToken.balanceOf(self)
denominationToken.transfer(taker, takerShare)
# adjust internal accounting
makerSharesDepleted += completeSets
makerTokensDepleted += 0
takerSharesDepleted += completeSets
takerTokensDepleted += 0
takerSharesAvailable = safeSub(takerSharesAvailable, completeSets)
makerSharesEscrowed = safeSub(makerSharesEscrowed, completeSets)
takerDesiredShares = safeSub(takerDesiredShares, completeSets)
# maker is closing a long, taker is opening a long
if makerSharesEscrowed and takerDesiredShares:
# transfer shares from maker (escrowed in market) to taker
shareToken.transferFrom(market, taker, makerSharesEscrowed)
# transfer tokens from taker to maker
tokensRequiredToCoverTaker = safeFxpMul(makerSharesEscrowed, sharePriceLong)
denominationToken.transferFrom(taker, maker, tokensRequiredToCoverTaker)
# adjust internal accounting
makerSharesDepleted += makerSharesEscrowed
makerTokensDepleted += 0
takerSharesDepleted += 0
takerTokensDepleted += tokensRequiredToCoverTaker
takerDesiredShares = safeSub(takerDesiredShares, makerSharesEscrowed)
makerSharesEscrowed = 0
# maker is opening a short, taker is closing a short
if takerSharesAvailable and takerDesiredShares:
# transfer shares from taker to maker
i = 0
while i < numberOfOutcomes:
if i != outcome:
market.getShareToken(i).transferFrom(taker, maker, takerSharesAvailable)
i += 1
# transfer tokens from maker (escrowed in market) to taker
tokensRequiredToCoverMaker = safeFxpMul(takerSharesAvailable, sharePriceShort)
denominationToken.transferFrom(market, taker, tokensRequiredToCoverMaker)
# adjust internal accounting
makerSharesDepleted += 0
makerTokensDepleted += tokensRequiredToCoverMaker
takerSharesDepleted += takerSharesAvailable
takerTokensDepleted += 0
takerDesiredShares = safeSub(takerDesiredShares, takerSharesAvailable)
takerSharesAvailable = 0
# maker is opening a short, taker is opening a long
if takerDesiredShares:
# transfer cash from both parties into this contract for complete set purchase
takerPortionOfCompleteSetCost = safeFxpMul(takerDesiredShares, sharePriceLong)
denominationToken.transferFrom(taker, self, takerPortionOfCompleteSetCost)
makerPortionOfCompleteSetCost = safeFxpMul(takerDesiredShares, sharePriceShort)
denominationToken.transferFrom(market, self, makerPortionOfCompleteSetCost)
# buy a complete set
if denominationToken.allowance(self, COMPLETE_SETS) < takerPortionOfCompleteSetCost + makerPortionOfCompleteSetCost:
denominationToken.approve(COMPLETE_SETS, 2**254)
COMPLETE_SETS.buyCompleteSets(self, market, takerDesiredShares)
# send outcome share to taker and all other shares to maker
shareToken.transfer(taker, takerDesiredShares)
i = 0
while i < numberOfOutcomes:
if i != outcome:
market.getShareToken(i).transfer(maker, takerDesiredShares)
i +=1
# adjust internal accounting
makerSharesDepleted += 0
makerTokensDepleted += makerPortionOfCompleteSetCost
takerSharesDepleted += 0
takerTokensDepleted += takerPortionOfCompleteSetCost
takerDesiredShares = 0
ORDERS.takeOrderLog(market, outcome, ASK, orderID, taker, makerSharesDepleted, makerTokensDepleted, takerSharesDepleted, takerTokensDepleted, tradeGroupID)
ORDERS.fillOrder(orderID, ASK, market, outcome, makerSharesDepleted, makerTokensDepleted)
# make sure we didn't accidentally leave anything behind
require(not denominationToken.balanceOf(self))
i = 0
while i < numberOfOutcomes:
require(not market.getShareToken(i).balanceOf(self))
i += 1
return fxpAmountTakerWants
# @controller
def setController(newController: address):
require(msg.sender == self.controller)
self.controller = newController
return(1)
# @controller
def suicideFunds(to: address):
require(msg.sender == self.controller)
suicide(to)