aboutsummaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/counterparty/counterparty.se
blob: abec0d102c8ba138f29de4c3813d50d380fda401 (plain) (blame)
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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# Ethereum forks Counterparty in 340 lines of serpent
# Not yet tested

# assets[i] = a registered asset, assets[i].holders[j] = former or current i-holder
data assets[2^50](creator, name, calldate, callprice, dividend_paid, holders[2^50], holdersCount)
data nextAssetId

# holdersMap: holdersMap[addr][asset] = 1 if addr holds asset
data holdersMap[2^160][2^50]

# balances[x][y] = how much of y x holds
data balances[2^160][2^50]

# orders[a][b] = heap of indices to (c, d, e) 
# = c offers to sell d units of a at a price of e units of b per 10^18 units
# of a
data orderbooks[2^50][2^50]

# store of general order data
data orders[2^50](seller, asset_sold, quantity, price)
data ordersCount

# data feeds
data feeds[2^50](owner, value)
data feedCount

# heap
data heap
extern heap: [register, push, pop, top, size]

data cfds[2^50](maker, acceptor, feed, asset, strike, leverage, min, max, maturity)
data cfdCount

data bets[2^50](maker, acceptor, feed, asset, makerstake, acceptorstake, eqtest, maturity)
data betCount

def init():
    heap = create('heap.se')

# Add units (internal method)
def add(to, asset, value):
    assert msg.sender == self
    self.balances[to][asset] += value
    # Add the holder to the holders list
    if not self.holdersMap[to][asset]:
        self.holdersMap[to][asset] = 1
        c = self.assets[asset].holdersCount
        self.assets[asset].holders[c] = to
        self.assets[asset].holdersCount = c + 1

# Register a new asset
def register_asset(q, name, calldate, callprice): 
    newid = self.nextAssetId
    self.assets[newid].creator = msg.sender
    self.assets[newid].name = name
    self.assets[newid].calldate = calldate
    self.assets[newid].callprice = callprice
    self.assets[newid].holders[0] = msg.sender
    self.assets[newid].holdersCount = 1
    self.balances[msg.sender][newid] = q
    self.holdersMap[msg.sender][newid] = 1

# Send
def send(to, asset, value):
    fromval = self.balances[msg.sender][asset]
    if fromval >= value:
        self.balances[msg.sender][asset] -= value
        self.add(to, asset, value)

# Order
def mkorder(selling, buying, quantity, price):
    # Make sure you have enough to pay for the order
    assert self.balances[msg.sender][selling] >= quantity:
    # Try to match existing orders
    o = orderbooks[buying][selling]
    if not o:
        o = self.heap.register()
        orderbooks[selling][buying] = o
    sz = self.heap.size(o)
    invprice = 10^36 / price
    while quantity > 0 and sz > 0: 
        orderid = self.heap.pop()
        p = self.orders[orderid].price
        if p > invprice:
            sz = 0
        else:
            q = self.orders[orderid].quantity
            oq = min(q, quantity)
            b = self.orders[orderid].seller
            self.balances[msg.sender][selling] -= oq * p / 10^18
            self.add(msg.sender, buying, oq)
            self.add(b, selling, oq * p / 10^18)
            self.orders[orderid].quantity = q - oq
            if oq == q:
                self.orders[orderid].seller = 0
                self.orders[orderid].price = 0
                self.orders[orderid].asset_sold = 0
            quantity -= oq
            sz -= 1
    assert quantity > 0
    # Make the order
    c = self.ordersCount
    self.orders[c].seller = msg.sender
    self.orders[c].asset_sold = selling
    self.orders[c].quantity = quantity
    self.orders[c].price = price
    self.ordersCount += 1
    # Add it to the heap
    o = orderbooks[selling][buying]
    if not o:
        o = self.heap.register()
        orderbooks[selling][buying] = o
    self.balances[msg.sender][selling] -= quantity
    self.heap.push(o, price, c)
    return(c)

def cancel_order(id):
    if self.orders[id].seller == msg.sender:
        self.orders[id].seller = 0
        self.orders[id].price = 0
        self.balances[msg.sender][self.orders[id].asset_sold] += self.orders[id].quantity
        self.orders[id].quantity = 0
        self.orders[id].asset_sold = 0

def register_feed():
    c = self.feedCount
    self.feeds[c].owner = msg.sender
    self.feedCount = c + 1
    return(c)

def set_feed(id, v):
    if self.feeds[id].owner == msg.sender:
        self.feeds[id].value = v

def mk_cfd_offer(feed, asset, strike, leverage, min, max, maturity):
    b = self.balances[msg.sender][asset]
    req = max((strike - min) * leverage, (strike - max) * leverage)
    assert b >= req
    self.balances[msg.sender][asset] = b - req
    c = self.cfdCount
    self.cfds[c].maker = msg.sender
    self.cfds[c].feed = feed
    self.cfds[c].asset = asset
    self.cfds[c].strike = strike
    self.cfds[c].leverage = leverage
    self.cfds[c].min = min
    self.cfds[c].max = max
    self.cfds[c].maturity = maturity
    self.cfdCount = c + 1
    return(c)

def accept_cfd_offer(c):
    assert not self.cfds[c].acceptor and self.cfds[c].maker
    asset = self.cfds[c].asset
    strike = self.cfds[c].strike
    min = self.cfds[c].min
    max = self.cfds[c].max
    leverage = self.cfds[c].leverage
    b = self.balances[msg.sender][asset]
    req = max((min - strike) * leverage, (max - strike) * leverage)
    assert b >= req
    self.balances[msg.sender][asset] = b - req
    self.cfds[c].acceptor = msg.sender
    self.cfds[c].maturity += block.timestamp

def claim_cfd_offer(c):
    asset = self.cfds[c].asset
    strike = self.cfds[c].strike
    min = self.cfds[c].min
    max = self.cfds[c].max
    leverage = self.cfds[c].leverage
    v = self.feeds[self.cfds[c].feed].value
    assert v <= min or v >= max or block.timestamp >= self.cfds[c].maturity
    maker_req = max((strike - min) * leverage, (strike - max) * leverage)
    acceptor_req = max((min - strike) * leverage, (max - strike) * leverage)
    paydelta = (strike - v) * leverage
    self.add(self.cfds[c].maker, asset, maker_req + paydelta)
    self.add(self.cfds[c].acceptor, asset, acceptor_req - paydelta)
    self.cfds[c].maker = 0
    self.cfds[c].acceptor = 0
    self.cfds[c].feed = 0
    self.cfds[c].asset = 0
    self.cfds[c].strike = 0
    self.cfds[c].leverage = 0
    self.cfds[c].min = 0
    self.cfds[c].max = 0
    self.cfds[c].maturity = 0

def withdraw_cfd_offer(c):
    if self.cfds[c].maker == msg.sender and not self.cfds[c].acceptor:
        asset = self.cfds[c].asset
        strike = self.cfds[c].strike
        min = self.cfds[c].min
        max = self.cfds[c].max
        leverage = self.cfds[c].leverage
        maker_req = max((strike - min) * leverage, (strike - max) * leverage)
        self.balances[self.cfds[c].maker][asset] += maker_req
        self.cfds[c].maker = 0
        self.cfds[c].acceptor = 0
        self.cfds[c].feed = 0
        self.cfds[c].asset = 0
        self.cfds[c].strike = 0
        self.cfds[c].leverage = 0
        self.cfds[c].min = 0
        self.cfds[c].max = 0
        self.cfds[c].maturity = 0
        

def mk_bet_offer(feed, asset, makerstake, acceptorstake, eqtest, maturity):
    assert self.balances[msg.sender][asset] >= makerstake
    c = self.betCount
    self.bets[c].maker = msg.sender
    self.bets[c].feed = feed
    self.bets[c].asset = asset
    self.bets[c].makerstake = makerstake
    self.bets[c].acceptorstake = acceptorstake
    self.bets[c].eqtest = eqtest
    self.bets[c].maturity = maturity
    self.balances[msg.sender][asset] -= makerstake
    self.betCount = c + 1
    return(c)

def accept_bet_offer(c):
    assert self.bets[c].maker and not self.bets[c].acceptor
    asset = self.bets[c].asset
    acceptorstake = self.bets[c].acceptorstake
    assert self.balances[msg.sender][asset] >= acceptorstake
    self.balances[msg.sender][asset] -= acceptorstake
    self.bets[c].acceptor = msg.sender

def claim_bet_offer(c):
    assert block.timestamp >= self.bets[c].maturity
    v = self.feeds[self.bets[c].feed].value
    totalstake = self.bets[c].makerstake + self.bets[c].acceptorstake
    if v == self.bets[c].eqtest:
        self.add(self.bets[c].maker, self.bets[c].asset, totalstake)
    else:
        self.add(self.bets[c].acceptor, self.bets[c].asset, totalstake)
    self.bets[c].maker = 0
    self.bets[c].feed = 0
    self.bets[c].asset = 0
    self.bets[c].makerstake = 0
    self.bets[c].acceptorstake = 0
    self.bets[c].eqtest = 0
    self.bets[c].maturity = 0

def cancel_bet(c):
    assert not self.bets[c].acceptor and msg.sender == self.bets[c].maker
    self.balances[msg.sender][self.bets[c].asset] += self.bets[c].makerstake
    self.bets[c].maker = 0
    self.bets[c].feed = 0
    self.bets[c].asset = 0
    self.bets[c].makerstake = 0
    self.bets[c].acceptorstake = 0
    self.bets[c].eqtest = 0
    self.bets[c].maturity = 0

def dividend(holder_asset, divvying_asset, ratio):
    i = 0
    sz = self.assets[holder_asset].holdersCount
    t = 0
    holders = array(sz)
    payments = array(sz)
    while i < sz:
        holders[i] = self.assets[holder_asset].holders[i]
        payments[i] = self.balances[holders[i]][holder_asset] * ratio / 10^18
        t += payments[i]
        i += 1
    if self.balances[msg.sender][divvying_asset] >= t:
        i = 0
        while i < sz:
            self.add(holders[i], divvying_asset, payments[i])
            i += 1
        self.balances[msg.sender][divvying_asset] -= t