From 702218008ee2b6d708d6b2821cdef80736bb3224 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Mon, 16 Feb 2015 14:28:33 +0100 Subject: Add versioned dependencies from godep --- .../serpent/examples/cyberdyne/futarchy.se | 136 +++++++++++++++++++++ .../serpent-go/serpent/examples/cyberdyne/heap.se | 55 +++++++++ .../serpent/examples/cyberdyne/market.se | 117 ++++++++++++++++++ .../serpent/examples/cyberdyne/subcurrency.se | 35 ++++++ .../serpent-go/serpent/examples/cyberdyne/test.py | 39 ++++++ 5 files changed, 382 insertions(+) create mode 100644 Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/futarchy.se create mode 100644 Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/heap.se create mode 100644 Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/market.se create mode 100644 Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/subcurrency.se create mode 100644 Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/test.py (limited to 'Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne') diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/futarchy.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/futarchy.se new file mode 100644 index 000000000..0d68622ac --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/futarchy.se @@ -0,0 +1,136 @@ +# 0: current epoch +# 1: number of proposals +# 2: master currency +# 3: last winning market +# 4: last txid +# 5: long-term ema currency units purchased +# 6: last block when currency units purchased +# 7: ether allocated to last round +# 8: last block when currency units claimed +# 9: ether allocated to current round +# 1000+: [proposal address, market ID, totprice, totvolume] + +init: + # We technically have two levels of epoch here. We have + # one epoch of 1000, to synchronize with the 1000 epoch + # of the market, and then 100 of those epochs make a + # meta-epoch (I'll nominate the term "seculum") over + # which the futarchy protocol will take place + contract.storage[0] = block.number / 1000 + # The master currency of the futarchy. The futarchy will + # assign currency units to whoever the prediction market + # thinks will best increase the currency's value + master_currency = create('subcurrency.se') + contract.storage[2] = master_currency +code: + curepoch = block.number / 1000 + prevepoch = contract.storage[0] + if curepoch > prevepoch: + if (curepoch % 100) > 50: + # Collect price data + # We take an average over 50 subepochs to determine + # the price of each asset, weighting by volume to + # prevent abuse + contract.storage[0] = curepoch + i = 0 + numprop = contract.storage[1] + while i < numprop: + market = contract.storage[1001 + i * 4] + price = call(market, 2) + volume = call(market, 3) + contract.storage[1002 + i * 4] += price + contract.storage[1003 + i * 4] += volume * price + i += 1 + if (curepoch / 100) > (prevepoch / 100): + # If we are entering a new seculum, we determine the + # market with the highest total average price + best = 0 + bestmarket = 0 + besti = 0 + i = 0 + while i < numprop: + curtotprice = contract.storage[1002 + i * 4] + curvolume = contract.storage[1002 + i * 4] + curavgprice = curtotprice / curvolume + if curavgprice > best: + best = curavgprice + besti = i + bestmarket = contract.storage[1003 + i * 4] + i += 1 + # Reset the number of proposals to 0 + contract.storage[1] = 0 + # Reward the highest proposal + call(contract.storage[2], [best, 10^9, 0], 3) + # Record the winning market so we can later appropriately + # compensate the participants + contract.storage[2] = bestmarket + # The amount of ether allocated to the last round + contract.storage[7] = contract.storage[9] + # The amount of ether allocated to the next round + contract.storage[9] = contract.balance / 2 + # Make a proposal [0, address] + if msg.data[0] == 0 and curepoch % 100 < 50: + pid = contract.storage[1] + market = create('market.se') + c1 = create('subcurrency.se') + c2 = create('subcurrency.se') + call(market, [c1, c2], 2) + contract.storage[1000 + pid * 4] = msg.data[1] + contract.storage[1001 + pid * 4] = market + contract.storage[1] += 1 + # Claim ether [1, address] + # One unit of the first currency in the last round's winning + # market entitles you to a quantity of ether that was decided + # at the start of that epoch + elif msg.data[0] == 1: + first_subcurrency = call(contract.storage[2], 3) + # We ask the first subcurrency contract what the last transaction was. The + # way to make a claim is to send the amount of first currency units that + # you wish to claim 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 = call(first_subcurrency, [], 0, 4) + from = data[0] + to = data[1] + value = data[2] + txid = data[3] + if txid > contract.storage[4] and to == contract.address: + send(to, contract.storage[7] * value / 10^9) + contract.storage[4] = txid + # Claim second currency [2, address] + # One unit of the second currency in the last round's winning + # market entitles you to one unit of the futarchy's master + # currency + elif msg.data[0] == 2: + second_subcurrency = call(contract.storage[2], 3) + data = call(first_subcurrency, [], 0, 4) + from = data[0] + to = data[1] + value = data[2] + txid = data[3] + if txid > contract.storage[4] and to == contract.address: + call(contract.storage[2], [to, value], 2) + contract.storage[4] = txid + # Purchase currency for ether (target releasing 10^9 units per seculum) + # Price starts off 1 eth for 10^9 units but increases hyperbolically to + # limit issuance + elif msg.data[0] == 3: + pre_ema = contract.storage[5] + post_ema = pre_ema + msg.value + pre_reserve = 10^18 / (10^9 + pre_ema / 10^9) + post_reserve = 10^18 / (10^9 + post_ema / 10^9) + call(contract.storage[2], [msg.sender, pre_reserve - post_reserve], 2) + last_sold = contract.storage[6] + contract.storage[5] = pre_ema * (100000 + last_sold - block.number) + msg.value + contract.storage[6] = block.number + # Claim all currencies as the ether miner of the current block + elif msg.data[0] == 2 and msg.sender == block.coinbase and block.number > contract.storage[8]: + i = 0 + numproposals = contract.storage[1] + while i < numproposals: + market = contract.storage[1001 + i * 3] + fc = call(market, 4) + sc = call(market, 5) + call(fc, [msg.sender, 1000], 2) + call(sc, [msg.sender, 1000], 2) + i += 1 + contract.storage[8] = block.number diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/heap.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/heap.se new file mode 100644 index 000000000..1bc442e6d --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/heap.se @@ -0,0 +1,55 @@ +# 0: size +# 1-n: elements + +init: + contract.storage[1000] = msg.sender +code: + # Only owner of the heap is allowed to modify it + if contract.storage[1000] != msg.sender: + stop + # push + if msg.data[0] == 0: + sz = contract.storage[0] + contract.storage[sz + 1] = msg.data[1] + k = sz + 1 + while k > 1: + bottom = contract.storage[k] + top = contract.storage[k/2] + if bottom < top: + contract.storage[k] = top + contract.storage[k/2] = bottom + k /= 2 + else: + k = 0 + contract.storage[0] = sz + 1 + # pop + elif msg.data[0] == 1: + sz = contract.storage[0] + if !sz: + return(0) + prevtop = contract.storage[1] + contract.storage[1] = contract.storage[sz] + contract.storage[sz] = 0 + top = contract.storage[1] + k = 1 + while k * 2 < sz: + bottom1 = contract.storage[k * 2] + bottom2 = contract.storage[k * 2 + 1] + if bottom1 < top and (bottom1 < bottom2 or k * 2 + 1 >= sz): + contract.storage[k] = bottom1 + contract.storage[k * 2] = top + k = k * 2 + elif bottom2 < top and bottom2 < bottom1 and k * 2 + 1 < sz: + contract.storage[k] = bottom2 + contract.storage[k * 2 + 1] = top + k = k * 2 + 1 + else: + k = sz + contract.storage[0] = sz - 1 + return(prevtop) + # top + elif msg.data[0] == 2: + return(contract.storage[1]) + # size + elif msg.data[0] == 3: + return(contract.storage[0]) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/market.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/market.se new file mode 100644 index 000000000..2303a0b60 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/market.se @@ -0,0 +1,117 @@ +# 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 + +# storage 0: buy orders +# storage 1: sell orders +# storage 1000: first subcurrency +# storage 1001: last first subcurrency txid +# storage 2000: second subcurrency +# storage 2001: last second subcurrency txid +# storage 3000: current epoch +# storage 4000: price +# storage 4001: volume + +init: + # Heap for buy orders + contract.storage[0] = create('heap.se') + # Heap for sell orders + contract.storage[1] = create('heap.se') +code: + # Initialize with [ first_subcurrency, second_subcurrency ] + if !contract.storage[1000]: + contract.storage[1000] = msg.data[0] # First subcurrency + contract.storage[1001] = -1 + contract.storage[2000] = msg.data[1] # Second subcurrency + contract.storage[2001] = -1 + contract.storage[3000] = block.number / 1000 + stop + first_subcurrency = contract.storage[1000] + second_subcurrency = contract.storage[2000] + buy_heap = contract.storage[0] + sell_heap = contract.storage[1] + # 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 contract.storage[3000] < block.number / 100: + done = 0 + volume = 0 + while !done: + # Grab the top buy and sell order from each heap + topbuy = call(buy_heap, 1) + topsell = call(sell_heap, 1) + # An order is recorded in the heap as: + # Buys: (2^48 - 1 - price) * 2^208 + units of first currency * 2^160 + from + # Sells: price * 2^208 + units of second currency * 2^160 + from + buyprice = -(topbuy / 2^208) + buyfcvalue = (topbuy / 2^160) % 2^48 + buyer = topbuy % 2^160 + sellprice = topsell / 2^208 + sellscvalue = (topsell / 2^160) % 2^48 + seller = topsell % 2^160 + # Heap empty, or no more matching orders + if not topbuy or not topsell or buyprice < sellprice: + done = 1 + else: + # Add to volume counter + volume += buyfcvalue + # 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 + call(second_subcurrency, [buyer, buyscvalue], 2) + call(first_subcurrency, [seller, sellfcvalue], 2) + if volume: + contract.storage[4000] = (buyprice + sellprice) / 2 + contract.storage[4001] = volume + contract.storage[3000] = block.number / 100 + # Make buy order [0, price] + if msg.data[0] == 0: + # 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 = call(first_subcurrency, [], 0, 4) + from = data[0] + to = data[1] + value = data[2] + txid = data[3] + price = msg.data[1] + if txid > contract.storage[1001] and to == contract.address: + contract.storage[1001] = txid + # Adds the order to the heap + call(buy_heap, [0, -price * 2^208 + (value % 2^48) * 2^160 + from], 2) + # Make sell order [1, price] + elif msg.data[0] == 1: + # Same mechanics as buying + data = call(second_subcurrency, [], 0, 4) + from = data[0] + to = data[1] + value = data[2] + txid = data[3] + price = msg.data[1] + if txid > contract.storage[2001] and to == contract.address: + contract.storage[2001] = txid + call(sell_heap, [0, price * 2^208 + (value % 2^48) * 2^160 + from], 2) + # Ask for price + elif msg.data[0] == 2: + return(contract.storage[4000]) + # Ask for volume + elif msg.data[0] == 3: + return(contract.storage[1000]) + # Ask for first currency + elif msg.data[0] == 4: + return(contract.storage[2000]) + # Ask for second currency + elif msg.data[0] == 5: + return(contract.storage[4001]) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/subcurrency.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/subcurrency.se new file mode 100644 index 000000000..1501beff7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/subcurrency.se @@ -0,0 +1,35 @@ +# Initialization +# Admin can issue and delete at will +init: + contract.storage[0] = msg.sender +code: + # If a message with one item is sent, that's a balance query + if msg.datasize == 1: + addr = msg.data[0] + return(contract.storage[addr]) + # If a message with two items [to, value] are sent, that's a transfer request + elif msg.datasize == 2: + from = msg.sender + fromvalue = contract.storage[from] + to = msg.data[0] + value = msg.data[1] + if fromvalue >= value and value > 0 and to > 4: + contract.storage[from] = fromvalue - value + contract.storage[to] += value + contract.storage[2] = from + contract.storage[3] = to + contract.storage[4] = value + contract.storage[5] += 1 + return(1) + return(0) + elif msg.datasize == 3 and msg.sender == contract.storage[0]: + # Admin can issue at will by sending a [to, value, 0] message + if msg.data[2] == 0: + contract.storage[msg.data[0]] += msg.data[1] + # Change admin [ newadmin, 0, 1 ] + # Set admin to 0 to disable administration + elif msg.data[2] == 1: + contract.storage[0] = msg.data[0] + # Fetch last transaction + else: + return([contract.storage[2], contract.storage[3], contract.storage[4], contract.storage[5]], 4) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/test.py b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/test.py new file mode 100644 index 000000000..301a4a845 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/test.py @@ -0,0 +1,39 @@ +from __future__ import print_function +import pyethereum +t = pyethereum.tester +s = t.state() +# Create currencies +c1 = s.contract('subcurrency.se') +print("First currency: %s" % c1) +c2 = s.contract('subcurrency.se') +print("First currency: %s" % c2) +# Allocate units +s.send(t.k0, c1, 0, [t.a0, 1000, 0]) +s.send(t.k0, c1, 0, [t.a1, 1000, 0]) +s.send(t.k0, c2, 0, [t.a2, 1000000, 0]) +s.send(t.k0, c2, 0, [t.a3, 1000000, 0]) +print("Allocated units") +# Market +m = s.contract('market.se') +s.send(t.k0, m, 0, [c1, c2]) +# Place orders +s.send(t.k0, c1, 0, [m, 1000]) +s.send(t.k0, m, 0, [0, 1200]) +s.send(t.k1, c1, 0, [m, 1000]) +s.send(t.k1, m, 0, [0, 1400]) +s.send(t.k2, c2, 0, [m, 1000000]) +s.send(t.k2, m, 0, [1, 800]) +s.send(t.k3, c2, 0, [m, 1000000]) +s.send(t.k3, m, 0, [1, 600]) +print("Orders placed") +# Next epoch and ping +s.mine(100) +print("Mined 100") +s.send(t.k0, m, 0, []) +print("Updating") +# Check +assert s.send(t.k0, c2, 0, [t.a0]) == [800000] +assert s.send(t.k0, c2, 0, [t.a1]) == [600000] +assert s.send(t.k0, c1, 0, [t.a2]) == [833] +assert s.send(t.k0, c1, 0, [t.a3]) == [714] +print("Balance checks passed") -- cgit