Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
158 lines (135 sloc) 5.5 KB
# Creates a decentralized market between any two subcurrencies
#
# Here, the first subcurrency is the base asset and the second
# subcurrency is the asset priced against the base asset. Hence,
# "buying" refers to trading the first for the second, and
# "selling" refers to trading the second for the first
data buy_heap
data sell_heap
data first_subcurrency(contract, txid)
data second_subcurrency(contract, txid)
data current_epoch
data price
data volume
extern heap: [pop:[]:int256, push:[int256]:_, set_owner:[int256]:_, size:[]:int256, top:[]:int256]
extern subcurrency: [balance:[int256]:int256, change_ownership:[int256]:_, issue:[int256,int256]:_, last_tx:[]:int256[], send:[int256,int256]:int256]
# Initialize with [ buy_heap, sell_heap, first_subcurrency, second_subcurrency ]
def init_market(buy_heap, sell_heap, first_subcurrency, second_subcurrency):
if !self.first_subcurrency.contract:
self.buy_heap = buy_heap
self.sell_heap = sell_heap
self.first_subcurrency.contract = first_subcurrency # First subcurrency
self.first_subcurrency.txid = -1
self.second_subcurrency.contract = second_subcurrency # Second subcurrency
self.second_subcurrency.txid = -1
self.current_epoch = block.number / 1000
stop
def tick():
if !self.first_subcurrency.contract:
return(0)
# This contract operates in "epochs" of 100 blocks
# At the end of each epoch, we process all orders
# simultaneously, independent of order. This algorithm
# prevents front-running, and generates a profit from
# the spread. The profit is permanently kept in the
# market (ie. destroyed), making both subcurrencies
# more valuable
# Epoch transition code
if self.current_epoch < block.number / 100:
done = 0
volume = 0
price = 0
while !done:
# Grab the top buy and sell order from each heap
topbuy = self.buy_heap.top()
topsell = self.sell_heap.top()
# An order is recorded in the heap
buyprice = -(topbuy / 2^208) + 1
buyfcvalue = mod((topbuy / 2^160), 2^48) - 1
buyer = mod(topbuy, 2^160)
sellprice = topsell / 2^208
sellscvalue = mod((topsell / 2^160), 2^48)
seller = mod(topsell, 2^160)
# Heap empty, or no more matching orders
if not topbuy or not topsell or buyprice < sellprice:
done = 1
else:
# Matching order, pop them from the heap
self.buy_heap.pop()
self.sell_heap.pop()
# Update last trading price
price = (buyprice + sellprice) / 2
# Calculate how much of the second currency the buyer gets, and
# how much of the first currency the seller gets
sellfcvalue = sellscvalue / buyprice
buyscvalue = buyfcvalue * sellprice
# Send the currency units along
# & Push back partial orders
if sellscvalue >= buyscvalue:
self.second_subcurrency.contract.send(buyer, buyscvalue)
else:
self.second_subcurrency.contract.send(buyer, sellscvalue)
push_buy_order(buyprice, buyfcvalue - sellfcvalue, buyer)
if buyfcvalue >= sellfcvalue:
self.first_subcurrency.contract.send(seller, sellfcvalue)
volume += sellfcvalue
else:
self.first_subcurrency.contract.send(seller, buyfcvalue)
push_sell_order(sellprice, sellscvalue - buyscvalue, seller)
volume += buyfcvalue
if volume:
self.price = price
self.volume = volume
self.current_epoch = block.number / 100
return(1)
return(0)
# Adds the order to the heap
macro push_buy_order($price, $value, $from):
self.buy_heap.push(-$price * 2^208 + mod($value, 2^48) * 2^160 + $from)
macro push_sell_order($price, $value, $from):
self.sell_heap.push($price * 2^208 + mod($value, 2^48) * 2^160 + $from)
# Make buy order
def buy(price):
# We ask the first subcurrency contract what the last transaction was. The
# way to make a buy order is to send the amount of first currency units that
# you wish to buy with, and then immediately call this contract. For security
# it makes sense to set up a tx which sends both messages in sequence atomically
data = self.first_subcurrency.contract.last_tx(outitems=4)
from = data[0]
to = data[1]
value = data[2]
txid = data[3]
if txid > self.first_subcurrency.txid and to == self:
self.first_subcurrency.txid = txid
push_buy_order(price, value, from)
return(1)
return(0)
# Make sell order
def sell(price):
# Same mechanics as buying
data = self.second_subcurrency.contract.last_tx(outitems=4)
from = data[0]
to = data[1]
value = data[2]
txid = data[3]
if txid > self.second_subcurrency.txid and to == self:
self.second_subcurrency.txid = txid
push_sell_order(price, value, from)
return(1)
return(0)
# Ask for price
def price():
return(self.price)
# Ask for volume
def volume():
return(self.volume)
def buy_heap():
return(self.buy_heap)
def sell_heap():
return(self.sell_heap)
# Ask for first currency
def first_currency():
return(self.first_subcurrency.contract)
# Ask for second currency
def second_currency():
return(self.second_subcurrency.contract)