diff options
author | Taylor Gerring <taylor.gerring@gmail.com> | 2015-02-16 21:28:33 +0800 |
---|---|---|
committer | Taylor Gerring <taylor.gerring@gmail.com> | 2015-02-16 21:28:33 +0800 |
commit | 702218008ee2b6d708d6b2821cdef80736bb3224 (patch) | |
tree | d55ff7ce88187082378e7d8e4c2f3aad14d23b4e /Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples | |
parent | 202362d9258335c695eb75f55f4be74a50a1af33 (diff) | |
download | go-tangerine-702218008ee2b6d708d6b2821cdef80736bb3224.tar.gz go-tangerine-702218008ee2b6d708d6b2821cdef80736bb3224.tar.zst go-tangerine-702218008ee2b6d708d6b2821cdef80736bb3224.zip |
Add versioned dependencies from godep
Diffstat (limited to 'Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples')
36 files changed, 2138 insertions, 0 deletions
diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/collatz.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/collatz.se new file mode 100644 index 000000000..148b47b59 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/collatz.se @@ -0,0 +1,11 @@ +x = msg.data[0] +steps = 0 + +while x > 1: + steps += 1 + if (x % 2) == 0: + x /= 2 + else: + x = 3 * x + 1 + +return(steps) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/counterparty/counterparty.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/counterparty/counterparty.se new file mode 100644 index 000000000..abec0d102 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/counterparty/counterparty.se @@ -0,0 +1,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 diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/counterparty/heap.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/counterparty/heap.se new file mode 100644 index 000000000..4a43a3974 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/counterparty/heap.se @@ -0,0 +1,69 @@ +data heaps[2^50](owner, size, nodes[2^50](key, value)) +data heapIndex + +def register(): + i = self.heapIndex + self.heaps[i].owner = msg.sender + self.heapIndex = i + 1 + return(i) + +def push(heap, key, value): + assert msg.sender == self.heaps[heap].owner + sz = self.heaps[heap].size + self.heaps[heap].nodes[sz].key = key + self.heaps[heap].nodes[sz].value = value + k = sz + 1 + while k > 1: + bottom = self.heaps[heap].nodes[k].key + top = self.heaps[heap].nodes[k/2].key + if bottom < top: + tvalue = self.heaps[heap].nodes[k/2].value + bvalue = self.heaps[heap].nodes[k].value + self.heaps[heap].nodes[k].key = top + self.heaps[heap].nodes[k].value = tvalue + self.heaps[heap].nodes[k/2].key = bottom + self.heaps[heap].nodes[k/2].value = bvalue + k /= 2 + else: + k = 0 + self.heaps[heap].size = sz + 1 + +def pop(heap): + sz = self.heaps[heap].size + assert sz + prevtop = self.heaps[heap].nodes[1].value + self.heaps[heap].nodes[1].key = self.heaps[heap].nodes[sz].key + self.heaps[heap].nodes[1].value = self.heaps[heap].nodes[sz].value + self.heaps[heap].nodes[sz].key = 0 + self.heaps[heap].nodes[sz].value = 0 + top = self.heaps[heap].nodes[1].key + k = 1 + while k * 2 < sz: + bottom1 = self.heaps[heap].nodes[k * 2].key + bottom2 = self.heaps[heap].nodes[k * 2 + 1].key + if bottom1 < top and (bottom1 < bottom2 or k * 2 + 1 >= sz): + tvalue = self.heaps[heap].nodes[1].value + bvalue = self.heaps[heap].nodes[k * 2].value + self.heaps[heap].nodes[k].key = bottom1 + self.heaps[heap].nodes[k].value = bvalue + self.heaps[heap].nodes[k * 2].key = top + self.heaps[heap].nodes[k * 2].value = tvalue + k = k * 2 + elif bottom2 < top and bottom2 < bottom1 and k * 2 + 1 < sz: + tvalue = self.heaps[heap].nodes[1].value + bvalue = self.heaps[heap].nodes[k * 2 + 1].value + self.heaps[heap].nodes[k].key = bottom2 + self.heaps[heap].nodes[k].value = bvalue + self.heaps[heap].nodes[k * 2 + 1].key = top + self.heaps[heap].nodes[k * 2 + 1].value = tvalue + k = k * 2 + 1 + else: + k = sz + self.heaps[heap].size = sz - 1 + return(prevtop) + +def top(heap): + return(self.heaps[heap].nodes[1].value) + +def size(heap): + return(self.heaps[heap].size) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/crowdfund.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/crowdfund.se new file mode 100644 index 000000000..9fd1e0643 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/crowdfund.se @@ -0,0 +1,53 @@ +data campaigns[2^80](recipient, goal, deadline, contrib_total, contrib_count, contribs[2^50](sender, value)) + +def create_campaign(id, recipient, goal, timelimit): + if self.campaigns[id].recipient: + return(0) + self.campaigns[id].recipient = recipient + self.campaigns[id].goal = goal + self.campaigns[id].deadline = block.timestamp + timelimit + +def contribute(id): + # Update contribution total + total_contributed = self.campaigns[id].contrib_total + msg.value + self.campaigns[id].contrib_total = total_contributed + + # Record new contribution + sub_index = self.campaigns[id].contrib_count + self.campaigns[id].contribs[sub_index].sender = msg.sender + self.campaigns[id].contribs[sub_index].value = msg.value + self.campaigns[id].contrib_count = sub_index + 1 + + # Enough funding? + if total_contributed >= self.campaigns[id].goal: + send(self.campaigns[id].recipient, total_contributed) + self.clear(id) + return(1) + + # Expired? + if block.timestamp > self.campaigns[id].deadline: + i = 0 + c = self.campaigns[id].contrib_count + while i < c: + send(self.campaigns[id].contribs[i].sender, self.campaigns[id].contribs[i].value) + i += 1 + self.clear(id) + return(2) + +def progress_report(id): + return(self.campaigns[id].contrib_total) + +# Clearing function for internal use +def clear(id): + if self == msg.sender: + self.campaigns[id].recipient = 0 + self.campaigns[id].goal = 0 + self.campaigns[id].deadline = 0 + c = self.campaigns[id].contrib_count + self.campaigns[id].contrib_count = 0 + self.campaigns[id].contrib_total = 0 + i = 0 + while i < c: + self.campaigns[id].contribs[i].sender = 0 + self.campaigns[id].contribs[i].value = 0 + i += 1 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") diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/datafeed.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/datafeed.se new file mode 100644 index 000000000..4c4a56de8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/datafeed.se @@ -0,0 +1,12 @@ +# Database updateable only by the original creator +data creator + +def init(): + self.creator = msg.sender + +def update(k, v): + if msg.sender == self.creator: + self.storage[k] = v + +def query(k): + return(self.storage[k]) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/ecrecover.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/ecrecover.se new file mode 100644 index 000000000..ce28f58c2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/ecrecover.se @@ -0,0 +1,40 @@ +# So I looked up on Wikipedia what Jacobian form actually is, and noticed that it's +# actually a rather different and more clever construction than the naive version +# that I created. It may possible to achieve a further 20-50% savings by applying +# that version. + +extern all: [call] + +data JORDANMUL +data JORDANADD +data EXP + +def init(): + self.JORDANMUL = create('jacobian_mul.se') + self.JORDANADD = create('jacobian_add.se') + self.EXP = create('modexp.se') + +def call(h, v, r, s): + N = -432420386565659656852420866394968145599 + P = -4294968273 + h = mod(h, N) + r = mod(r, P) + s = mod(s, N) + Gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240 + Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424 + x = r + xcubed = mulmod(mulmod(x, x, P), x, P) + beta = self.EXP.call(addmod(xcubed, 7, P), div(P + 1, 4), P) + + # Static-gascost ghetto conditional + y_is_positive = mod(v, 2) xor mod(beta, 2) + y = beta * y_is_positive + (P - beta) * (1 - y_is_positive) + + GZ = self.JORDANMUL.call(Gx, 1, Gy, 1, N - h, outsz=4) + XY = self.JORDANMUL.call(x, 1, y, 1, s, outsz=4) + COMB = self.JORDANADD.call(GZ[0], GZ[1], GZ[2], GZ[3], XY[0], XY[1], XY[2], XY[3], 1, outsz=5) + COMB[4] = self.EXP.call(r, N - 2, N) + Q = self.JORDANMUL.call(data=COMB, datasz=5, outsz=4) + ox = mulmod(Q[0], self.EXP.call(Q[1], P - 2, P), P) + oy = mulmod(Q[2], self.EXP.call(Q[3], P - 2, P), P) + return([ox, oy], 2) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/ecrecover_compiled.evm b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/ecrecover_compiled.evm new file mode 100644 index 000000000..f575fe70f --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/ecrecover_compiled.evm @@ -0,0 +1 @@ +6000607f535961071c80610013593961072f566000605f535961013d8061001359396101505661012b8061000e60003961013956600061023f5360003560001a6000141561012a5760806001602037602051151561002c576060511561002f565b60005b156100695760806080599059016000905260a052600060a051526001602060a05101526000604060a05101526001606060a051015260a051f25b6401000003d160000380608051826003846020516020510909098182600260605109836040516040510909828283098382830984858660026020510983098603866040518509088560405183098686888985604051098a038a85602051090809878689846040510909888960605183098a038a6080518509088960805183096080608059905901600090526101e052866101e051528560206101e05101528260406101e05101528160606101e05101526101e051f250505050505050505050505b5b6000f25b816000f090506000555961040680610168593961056e566000603f535961013d8061001359396101505661012b8061000e60003961013956600061023f5360003560001a6000141561012a5760806001602037602051151561002c576060511561002f565b60005b156100695760806080599059016000905260a052600060a051526001602060a05101526000604060a05101526001606060a051015260a051f25b6401000003d160000380608051826003846020516020510909098182600260605109836040516040510909828283098382830984858660026020510983098603866040518509088560405183098686888985604051098a038a85602051090809878689846040510909888960605183098a038a6080518509088960805183096080608059905901600090526101e052866101e051528560206101e05101528260406101e05101528160606101e05101526101e051f250505050505050505050505b5b6000f25b816000f0905060005561029a8061016860003961040256600061043f5360003560001a60001415610299576101006001602037602051151561002d5760605115610030565b60005b1561007657608059905901600090526101405260a051610140515260c051602061014051015260e051604061014051015261010051606061014051015261014051610120525b60a05115156100885760e0511561008b565b60005b156100d0576080599059016000905261016052602051610160515260405160206101605101526060516040610160510152608051606061016051015261016051610120525b61012051156100e157608061012051f25b6401000003d16000036000818260a0516040510983038360c051602051090814156101b1576000818260e051608051098303836101005160605109081415610175576080608080599059016000905260006101c0601f01536020516101e052604051610200526060516102205260805161024052818160816101c0601f01600060005460195a03f1508090509050f26101b0565b608060805990590160009052610280526000610280515260016020610280510152600060406102805101526001606061028051015261028051f25b5b808160405160c051098283610100516060510984038460805160e05109080981828360c0516020510984038460405160a051090883608051610100510909828283098382830984856020518309860386604051850908856040518309868760a051830988038860c0518509088760c051830988898a60405185098b038b8460205109088909898a836040510989098a8b60605183098c038c6080518509088b60805183096080608059905901600090526103e052866103e051528560206103e05101528260406103e05101528160606103e05101526103e051f2505050505050505050505050505b5b6000f25b816000f090506001556101928061058660003961071856600061013f5360003560001a600014156101915760a0600160203770014551231950b75fc4402da1732fc9bebf60000360a0510660a05260a05115606051156020511502011561007e5760806080599059016000905260c052600060c051526001602060c05101526000604060c05101526001606060c051015260c051f25b610120599059016000905260e052600060e051526000602060e05101526001604060e05101526000606060e05101526001608060e0510152600060a060e0510152600060c060e0510152600060e060e0510152600061010060e051015260e0517f80000000000000000000000000000000000000000000000000000000000000005b6000811115610187578060a0511615610165576080602083016081601f85016000600054614e20f15060205160a083015260405160c083015260605160e0830152608051610100830152608060208301610101601f85016000600154614e20f161017b565b6080602083016081601f85016000600054614e20f15b50600281049050610100565b608060208301f250505b5b6000f25b816000f0905060005559610406806107475939610b4d566000603f535961013d8061001359396101505661012b8061000e60003961013956600061023f5360003560001a6000141561012a5760806001602037602051151561002c576060511561002f565b60005b156100695760806080599059016000905260a052600060a051526001602060a05101526000604060a05101526001606060a051015260a051f25b6401000003d160000380608051826003846020516020510909098182600260605109836040516040510909828283098382830984858660026020510983098603866040518509088560405183098686888985604051098a038a85602051090809878689846040510909888960605183098a038a6080518509088960805183096080608059905901600090526101e052866101e051528560206101e05101528260406101e05101528160606101e05101526101e051f250505050505050505050505b5b6000f25b816000f0905060005561029a8061016860003961040256600061043f5360003560001a60001415610299576101006001602037602051151561002d5760605115610030565b60005b1561007657608059905901600090526101405260a051610140515260c051602061014051015260e051604061014051015261010051606061014051015261014051610120525b60a05115156100885760e0511561008b565b60005b156100d0576080599059016000905261016052602051610160515260405160206101605101526060516040610160510152608051606061016051015261016051610120525b61012051156100e157608061012051f25b6401000003d16000036000818260a0516040510983038360c051602051090814156101b1576000818260e051608051098303836101005160605109081415610175576080608080599059016000905260006101c0601f01536020516101e052604051610200526060516102205260805161024052818160816101c0601f01600060005460195a03f1508090509050f26101b0565b608060805990590160009052610280526000610280515260016020610280510152600060406102805101526001606061028051015261028051f25b5b808160405160c051098283610100516060510984038460805160e05109080981828360c0516020510984038460405160a051090883608051610100510909828283098382830984856020518309860386604051850908856040518309868760a051830988038860c0518509088760c051830988898a60405185098b038b8460205109088909898a836040510989098a8b60605183098c038c6080518509088b60805183096080608059905901600090526103e052866103e051528560206103e05101528260406103e05101528160606103e05101526103e051f2505050505050505050505050505b5b6000f25b816000f09050600155596100d080610b655939610c35566100be8061000e6000396100cc5660003560001a600014156100bd576060600160203760017f80000000000000000000000000000000000000000000000000000000000000005b60008111156100b157606051816040511615156020510a606051848509099150606051600282046040511615156020510a606051848509099150606051600482046040511615156020510a606051848509099150606051600882046040511615156020510a606051848509099150601081049050610038565b8160c052602060c0f250505b5b6000f25b816000f090506002556103d280610c4d60003961101f56600061095f5360003560001a600014156103d1576080600160203770014551231950b75fc4402da1732fc9bebf60000360a0526401000003d160000360c05260a0516020510660205260c0516060510660605260a051608051066080527f79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179860e0527f483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8610100526060516101205260c0516101205160c05161012051610120510909610140526000610180601f015360c051600761014051086101a0526004600160c05101046101c05260c0516101e05260206102006061610180601f01600060025460195a03f1506102005161016052600261016051066002604051061861022052610220516001036101605160c05103026102205161016051020161024052608080599059016000905260006102a0601f015360e0516102c05260016102e052610100516103005260016103205260205160a0510361034052818160a16102a0601f01600060005460195a03f150809050905061026052608080599059016000905260006103c0601f0153610120516103e052600161040052610240516104205260016104405260805161046052818160a16103c0601f01600060005460195a03f15080905090506103805260a080599059016000905260006104e0601f015361026051516105005260206102605101516105205260406102605101516105405260606102605101516105605261038051516105805260206103805101516105a05260406103805101516105c05260606103805101516105e05260016106005281816101216104e0601f01600060015460195a03f15080905090506104a0526000610640601f015360605161066052600260a051036106805260a0516106a05260206106c06061610640601f01600060025460195a03f1506106c05160806104a05101526104a05160208103805160018303608080599059016000905260008353818160a185600060005460195a03f150838552809050905090509050905090506106e05260c05160006107e0601f015360206106e051015161080052600260c051036108205260c05161084052602061086060616107e0601f01600060025460195a03f150610860516106e05151096107c05260c05160006108a0601f015360606106e05101516108c052600260c051036108e05260c05161090052602061092060616108a0601f01600060025460195a03f1506109205160406106e05101510961088052604060405990590160009052610940526107c051610940515261088051602061094051015261094051f25b5b6000f2 diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/jacobian_add.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/jacobian_add.se new file mode 100644 index 000000000..29dc390b2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/jacobian_add.se @@ -0,0 +1,32 @@ +extern all: [call] +data DOUBLE + +def init(): + self.DOUBLE = create('jacobian_double.se') + +def call(axn, axd, ayn, ayd, bxn, bxd, byn, byd): + if !axn and !ayn: + o = [bxn, bxd, byn, byd] + if !bxn and !byn: + o = [axn, axd, ayn, ayd] + if o: + return(o, 4) + with P = -4294968273: + if addmod(mulmod(axn, bxd, P), P - mulmod(axd, bxn, P), P) == 0: + if addmod(mulmod(ayn, byd, P), P - mulmod(ayd, byn, P), P) == 0: + return(self.DOUBLE.call(axn, axd, ayn, ayd, outsz=4), 4) + else: + return([0, 1, 0, 1], 4) + with mn = mulmod(addmod(mulmod(byn, ayd, P), P - mulmod(ayn, byd, P), P), mulmod(bxd, axd, P), P): + with md = mulmod(mulmod(byd, ayd, P), addmod(mulmod(bxn, axd, P), P - mulmod(axn, bxd, P), P), P): + with msqn = mulmod(mn, mn, P): + with msqd = mulmod(md, md, P): + with msqman = addmod(mulmod(msqn, axd, P), P - mulmod(msqd, axn, P), P): + with msqmad = mulmod(msqd, axd, P): + with xn = addmod(mulmod(msqman, bxd, P), P - mulmod(msqmad, bxn, P), P): + with xd = mulmod(msqmad, bxd, P): + with mamxn = mulmod(mn, addmod(mulmod(axn, xd, P), P - mulmod(xn, axd, P), P), P): + with mamxd = mulmod(md, mulmod(axd, xd, P), P): + with yn = addmod(mulmod(mamxn, ayd, P), P - mulmod(mamxd, ayn, P), P): + with yd = mulmod(mamxd, ayd, P): + return([xn, xd, yn, yd], 4) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/jacobian_double.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/jacobian_double.se new file mode 100644 index 000000000..b7d8221a6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/jacobian_double.se @@ -0,0 +1,16 @@ +def call(axn, axd, ayn, ayd): + if !axn and !ayn: + return([0, 1, 0, 1], 4) + with P = -4294968273: + # No need to add (A, 1) because A = 0 for bitcoin + with mn = mulmod(mulmod(mulmod(axn, axn, P), 3, P), ayd, P): + with md = mulmod(mulmod(axd, axd, P), mulmod(ayn, 2, P), P): + with msqn = mulmod(mn, mn, P): + with msqd = mulmod(md, md, P): + with xn = addmod(mulmod(msqn, axd, P), P - mulmod(msqd, mulmod(axn, 2, P), P), P): + with xd = mulmod(msqd, axd, P): + with mamxn = mulmod(addmod(mulmod(axn, xd, P), P - mulmod(axd, xn, P), P), mn, P): + with mamxd = mulmod(mulmod(axd, xd, P), md, P): + with yn = addmod(mulmod(mamxn, ayd, P), P - mulmod(mamxd, ayn, P), P): + with yd = mulmod(mamxd, ayd, P): + return([xn, xd, yn, yd], 4) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/jacobian_mul.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/jacobian_mul.se new file mode 100644 index 000000000..bf5b96bb4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/jacobian_mul.se @@ -0,0 +1,37 @@ +# Expected gas cost +# +# def expect(n, point_at_infinity=False): +# n = n % (2**256 - 432420386565659656852420866394968145599) +# if point_at_infinity: +# return 79 +# if n == 0: +# return 34479 +# L = int(1 + math.log(n) / math.log(2)) +# H = len([x for x in b.encode(n, 2) if x == '1']) +# return 34221 + 94 * L + 343 * H + +data DOUBLE +data ADD + +def init(): + self.DOUBLE = create('jacobian_double.se') + self.ADD = create('jacobian_add.se') + +def call(axn, axd, ayn, ayd, n): + n = mod(n, -432420386565659656852420866394968145599) + if !axn * !ayn + !n: # Constant-gas version of !axn and !ayn or !n + return([0, 1, 0, 1], 4) + with o = [0, 0, 1, 0, 1, 0, 0, 0, 0]: + with b = 2 ^ 255: + while gt(b, 0): + if n & b: + ~call(20000, self.DOUBLE, 0, o + 31, 129, o + 32, 128) + o[5] = axn + o[6] = axd + o[7] = ayn + o[8] = ayd + ~call(20000, self.ADD, 0, o + 31, 257, o + 32, 128) + else: + ~call(20000, self.DOUBLE, 0, o + 31, 129, o + 32, 128) + b = div(b, 2) + return(o + 32, 4) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/modexp.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/modexp.se new file mode 100644 index 000000000..687b12a04 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/modexp.se @@ -0,0 +1,11 @@ +def call(b, e, m): + with o = 1: + with bit = 2 ^ 255: + while gt(bit, 0): + # A touch of loop unrolling for 20% efficiency gain + o = mulmod(mulmod(o, o, m), b ^ !(!(e & bit)), m) + o = mulmod(mulmod(o, o, m), b ^ !(!(e & div(bit, 2))), m) + o = mulmod(mulmod(o, o, m), b ^ !(!(e & div(bit, 4))), m) + o = mulmod(mulmod(o, o, m), b ^ !(!(e & div(bit, 8))), m) + bit = div(bit, 16) + return(o) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/substitutes.py b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/substitutes.py new file mode 100644 index 000000000..0007da0cf --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/substitutes.py @@ -0,0 +1,78 @@ +import bitcoin as b +import math +import sys + + +def signed(o): + return map(lambda x: x - 2**256 if x >= 2**255 else x, o) + + +def hamming_weight(n): + return len([x for x in b.encode(n, 2) if x == '1']) + + +def binary_length(n): + return len(b.encode(n, 2)) + + +def jacobian_mul_substitute(A, B, C, D, N): + if A == 0 and C == 0 or (N % b.N) == 0: + return {"gas": 86, "output": [0, 1, 0, 1]} + else: + output = b.jordan_multiply(((A, B), (C, D)), N) + return { + "gas": 35262 + 95 * binary_length(N % b.N) + 355 * hamming_weight(N % b.N), + "output": signed(list(output[0]) + list(output[1])) + } + + +def jacobian_add_substitute(A, B, C, D, E, F, G, H): + if A == 0 or E == 0: + gas = 149 + elif (A * F - B * E) % b.P == 0: + if (C * H - D * G) % b.P == 0: + gas = 442 + else: + gas = 177 + else: + gas = 301 + output = b.jordan_add(((A, B), (C, D)), ((E, F), (G, H))) + return { + "gas": gas, + "output": signed(list(output[0]) + list(output[1])) + } + + +def modexp_substitute(base, exp, mod): + return { + "gas": 5150, + "output": signed([pow(base, exp, mod) if mod > 0 else 0]) + } + + +def ecrecover_substitute(z, v, r, s): + P, A, B, N, Gx, Gy = b.P, b.A, b.B, b.N, b.Gx, b.Gy + x = r + beta = pow(x*x*x+A*x+B, (P + 1) / 4, P) + BETA_PREMIUM = modexp_substitute(x, (P + 1) / 4, P)["gas"] + y = beta if v % 2 ^ beta % 2 else (P - beta) + Gz = b.jordan_multiply(((Gx, 1), (Gy, 1)), (N - z) % N) + GZ_PREMIUM = jacobian_mul_substitute(Gx, 1, Gy, 1, (N - z) % N)["gas"] + XY = b.jordan_multiply(((x, 1), (y, 1)), s) + XY_PREMIUM = jacobian_mul_substitute(x, 1, y, 1, s % N)["gas"] + Qr = b.jordan_add(Gz, XY) + QR_PREMIUM = jacobian_add_substitute(Gz[0][0], Gz[0][1], Gz[1][0], Gz[1][1], + XY[0][0], XY[0][1], XY[1][0], XY[1][1] + )["gas"] + Q = b.jordan_multiply(Qr, pow(r, N - 2, N)) + Q_PREMIUM = jacobian_mul_substitute(Qr[0][0], Qr[0][1], Qr[1][0], Qr[1][1], + pow(r, N - 2, N))["gas"] + R_PREMIUM = modexp_substitute(r, N - 2, N)["gas"] + OX_PREMIUM = modexp_substitute(Q[0][1], P - 2, P)["gas"] + OY_PREMIUM = modexp_substitute(Q[1][1], P - 2, P)["gas"] + Q = b.from_jordan(Q) + return { + "gas": 991 + BETA_PREMIUM + GZ_PREMIUM + XY_PREMIUM + QR_PREMIUM + + Q_PREMIUM + R_PREMIUM + OX_PREMIUM + OY_PREMIUM, + "output": signed(Q) + } diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/test.py b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/test.py new file mode 100644 index 000000000..48d21e32f --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/test.py @@ -0,0 +1,129 @@ +import bitcoin as b +import random +import sys +import math +from pyethereum import tester as t +import substitutes +import time + +vals = [random.randrange(2**256) for i in range(12)] + +test_points = [list(p[0]) + list(p[1]) for p in + [b.jordan_multiply(((b.Gx, 1), (b.Gy, 1)), r) for r in vals]] + +G = [b.Gx, 1, b.Gy, 1] +Z = [0, 1, 0, 1] + + +def neg_point(p): + return [p[0], b.P - p[1], p[2], b.P - p[3]] + +s = t.state() +s.block.gas_limit = 10000000 +t.gas_limit = 1000000 + + +c = s.contract('modexp.se') +print "Starting modexp tests" + +for i in range(0, len(vals) - 2, 3): + o1 = substitutes.modexp_substitute(vals[i], vals[i+1], vals[i+2]) + o2 = s.profile(t.k0, c, 0, funid=0, abi=vals[i:i+3]) + #assert o1["gas"] == o2["gas"], (o1, o2) + assert o1["output"] == o2["output"], (o1, o2) + +c = s.contract('jacobian_add.se') +print "Starting addition tests" + +for i in range(2): + P = test_points[i * 2] + Q = test_points[i * 2 + 1] + NP = neg_point(P) + + o1 = substitutes.jacobian_add_substitute(*(P + Q)) + o2 = s.profile(t.k0, c, 0, funid=0, abi=P + Q) + #assert o1["gas"] == o2["gas"], (o1, o2) + assert o1["output"] == o2["output"], (o1, o2) + + o1 = substitutes.jacobian_add_substitute(*(P + NP)) + o2 = s.profile(t.k0, c, 0, funid=0, abi=P + NP) + #assert o1["gas"] == o2["gas"], (o1, o2) + assert o1["output"] == o2["output"], (o1, o2) + + o1 = substitutes.jacobian_add_substitute(*(P + P)) + o2 = s.profile(t.k0, c, 0, funid=0, abi=P + P) + #assert o1["gas"] == o2["gas"], (o1, o2) + assert o1["output"] == o2["output"], (o1, o2) + + o1 = substitutes.jacobian_add_substitute(*(P + Z)) + o2 = s.profile(t.k0, c, 0, funid=0, abi=P + Z) + #assert o1["gas"] == o2["gas"], (o1, o2) + assert o1["output"] == o2["output"], (o1, o2) + + o1 = substitutes.jacobian_add_substitute(*(Z + P)) + o2 = s.profile(t.k0, c, 0, funid=0, abi=Z + P) + #assert o1["gas"] == o2["gas"], (o1, o2) + assert o1["output"] == o2["output"], (o1, o2) + + +c = s.contract('jacobian_mul.se') +print "Starting multiplication tests" + + +mul_tests = [ + Z + [0], + Z + [vals[0]], + test_points[0] + [0], + test_points[1] + [b.N], + test_points[2] + [1], + test_points[2] + [2], + test_points[2] + [3], + test_points[2] + [4], + test_points[3] + [5], + test_points[3] + [6], + test_points[4] + [7], + test_points[4] + [2**254], + test_points[4] + [vals[1]], + test_points[4] + [vals[2]], + test_points[4] + [vals[3]], + test_points[5] + [2**256 - 1], +] + +for i, test in enumerate(mul_tests): + print 'trying mul_test %i' % i, test + o1 = substitutes.jacobian_mul_substitute(*test) + o2 = s.profile(t.k0, c, 0, funid=0, abi=test) + # assert o1["gas"] == o2["gas"], (o1, o2, test) + assert o1["output"] == o2["output"], (o1, o2, test) + +c = s.contract('ecrecover.se') +print "Starting ecrecover tests" + +for i in range(5): + print 'trying ecrecover_test', vals[i*2], vals[i*2+1] + k = vals[i*2] + h = vals[i*2+1] + V, R, S = b.ecdsa_raw_sign(b.encode(h, 256, 32), k) + aa = time.time() + o1 = substitutes.ecrecover_substitute(h, V, R, S) + print 'sub', time.time() - aa + a = time.time() + o2 = s.profile(t.k0, c, 0, funid=0, abi=[h, V, R, S]) + print time.time() - a + # assert o1["gas"] == o2["gas"], (o1, o2, h, V, R, S) + assert o1["output"] == o2["output"], (o1, o2, h, V, R, S) + +# Explicit tests + +data = [[ + 0xf007a9c78a4b2213220adaaf50c89a49d533fbefe09d52bbf9b0da55b0b90b60, + 0x1b, + 0x5228fc9e2fabfe470c32f459f4dc17ef6a0a81026e57e4d61abc3bc268fc92b5, + 0x697d4221cd7bc5943b482173de95d3114b9f54c5f37cc7f02c6910c6dd8bd107 +]] + +for datum in data: + o1 = substitutes.ecrecover_substitute(*datum) + o2 = s.profile(t.k0, c, 0, funid=0, abi=datum) + #assert o1["gas"] == o2["gas"], (o1, o2, datum) + assert o1["output"] == o2["output"], (o1, o2, datum) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/channel.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/channel.se new file mode 100644 index 000000000..733f4a95b --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/channel.se @@ -0,0 +1,45 @@ +if msg.data[0] == 0: + new_id = contract.storage[-1] + # store [from, to, value, maxvalue, timeout] in contract storage + contract.storage[new_id] = msg.sender + contract.storage[new_id + 1] = msg.data[1] + contract.storage[new_id + 2] = 0 + contract.storage[new_id + 3] = msg.value + contract.storage[new_id + 4] = 2^254 + # increment next id + contract.storage[-1] = new_id + 10 + # return id of this channel + return(new_id) + +# Increase payment on channel: [1, id, value, v, r, s] +elif msg.data[0] == 1: + # Ecrecover native extension; will be a different address in testnet and live + ecrecover = 0x46a8d0b21b1336d83b06829f568d7450df36883f + # Message data parameters + id = msg.data[1] % 2^160 + value = msg.data[2] + # Determine sender from signature + h = sha3([id, value], 2) + sender = call(ecrecover, [h, msg.data[3], msg.data[4], msg.data[5]], 4) + # Check sender matches and new value is greater than old + if sender == contract.storage[id]: + if value > contract.storage[id + 2] and value <= contract.storage[id + 3]: + # Update channel, increasing value and setting timeout + contract.storage[id + 2] = value + contract.storage[id + 4] = block.number + 1000 + +# Cash out channel: [2, id] +elif msg.data[0] == 2: + id = msg.data[1] % 2^160 + # Check if timeout has run out + if block.number >= contract.storage[id + 3]: + # Send funds + send(contract.storage[id + 1], contract.storage[id + 2]) + # Send refund + send(contract.storage[id], contract.storage[id + 3] - contract.storage[id + 2]) + # Clear storage + contract.storage[id] = 0 + contract.storage[id + 1] = 0 + contract.storage[id + 2] = 0 + contract.storage[id + 3] = 0 + contract.storage[id + 4] = 0 diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/map.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/map.se new file mode 100644 index 000000000..768dfb9fc --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/map.se @@ -0,0 +1,19 @@ +# An implementation of a contract for storing a key/value binding +init: + # Set owner + contract.storage[0] = msg.sender +code: + # Check ownership + if msg.sender == contract.storage[0]: + # Get: returns (found, val) + if msg.data[0] == 0: + s = sha3(msg.data[1]) + return([contract.storage[s], contract.storage[s+1]], 2) + # Set: sets map[k] = v + elif msg.data[0] == 1: + s = sha3(msg.data[1]) + contract.storage[s] = 1 + contract.storage[s + 1] = msg.data[2] + # Suicide + elif msg.data[2] == 1: + suicide(0) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/multiforward.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/multiforward.se new file mode 100644 index 000000000..577794d97 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/multiforward.se @@ -0,0 +1,14 @@ +init: + contract.storage[0] = msg.sender +code: + if msg.sender != contract.storage[0]: + stop + i = 0 + while i < ~calldatasize(): + to = ~calldataload(i) + value = ~calldataload(i+20) / 256^12 + datasize = ~calldataload(i+32) / 256^30 + data = alloc(datasize) + ~calldatacopy(data, i+34, datasize) + ~call(tx.gas - 25, to, value, data, datasize, 0, 0) + i += 34 + datasize diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/shadowchain.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/shadowchain.se new file mode 100644 index 000000000..1e466a355 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/shadowchain.se @@ -0,0 +1,166 @@ +# Exists in state: +# (i) last committed block +# (ii) chain of uncommitted blocks (linear only) +# (iii) transactions, each tx with an associated block number +# +# Uncommitted block = +# [ numtxs, numkvs, tx1 (N words), tx2 (N words) ..., [k1, v1], [k2, v2], [k3, v3] ... ] +# +# Block checking process +# +# Suppose last committed state is m +# Last uncommitted state is n +# Contested block is b +# +# 1. Temporarily apply all state transitions from +# m to b +# 2. Run code, get list of changes +# 3. Check is list of changes matches deltas +# * if yes, do nothing +# * if no, set last uncommitted state to pre-b +# +# Storage variables: +# +# Last committed block: 0 +# Last uncommitted block: 1 +# Contract holding code: 2 +# Uncommitted map: 3 +# Transaction length (parameter): 4 +# Block b: 2^160 + b * 2^40: +# + 1: submission blknum +# + 2: submitter +# + 3: data in uncommitted block format above +# Last committed storage: +# sha3(k): index k + +# Initialize: [0, c, txlength], set address of the code-holding contract and the transaction +# length +if not contract.storage[2]: + contract.storage[2] = msg.data[1] + contract.storage[4] = msg.data[2] + stop + +# Sequentially commit all uncommitted blocks that are more than 1000 mainchain-blocks old +last_committed_block = contract.storage[0] +last_uncommitted_block = contract.storage[1] +lcb_storage_index = 2^160 + last_committed_block * 2^40 +while contract.storage[lcb_storage_index + 1] < block.number - 1000 and last_committed_block < last_uncommitted_block: + kvpairs = contract.storage[lcb_storage_index] + i = 0 + while i < kvpairs: + k = contract.storage[lcb_storage_index + 3 + i * 2] + v = contract.storage[lcb_storage_index + 4 + i * 2] + contract.storage[sha3(k)] = v + i += 1 + last_committed_block += 1 + lcb_storage_index += 2^40 +contract.storage[0] = last_committed_block + + +# Propose block: [ 0, block number, data in block format above ... ] +if msg.data[0] == 0: + blknumber = msg.data[1] + # Block number must be correct + if blknumber != contract.storage[1]: + stop + # Deposit requirement + if msg.value < 10^19: + stop + # Store the proposal in storage as + # [ 0, main-chain block number, sender, block data...] + start_index = 2^160 + blknumber * 2^40 + numkvs = (msg.datasize - 2) / 2 + contract.storage[start_index + 1] = block.number + 1ontract.storage[start_index + 2] = msg.sender + i = 0 + while i < msg.datasize - 2: + contract.storage[start_index + 3 + i] = msg.data[2 + i] + i += 1 + contract.storage[1] = blknumber + 1 + +# Challenge block: [ 1, b ] +elif msg.data[0] == 1: + blknumber = msg.data[1] + txwidth = contract.storage[4] + last_uncommitted_block = contract.storage[1] + last_committed_block = contract.storage[0] + # Cannot challenge nonexistent or committed blocks + if blknumber <= last_uncommitted_block or blknumber > last_committed_block: + stop + # Create a contract to serve as a map that maintains keys and values + # temporarily + tempstore = create('map.se') + contract.storage[3] = tempstore + # Unquestioningly apply the state transitions from the last committed block + # up to b + b = last_committed_block + cur_storage_index = 2^160 + last_committed_block * 2^40 + while b < blknumber: + numtxs = contract.storage[cur_storage_index + 3] + numkvs = contract.storage[cur_storage_index + 4] + kv0index = cur_storage_index + 5 + numtxs * txwidth + i = 0 + while i < numkvs: + k = contract.storage[kv0index + i * 2] + v = contract.storage[kx0index + i * 2 + 1] + call(tempstore, [1, k, v], 3) + i += 1 + b += 1 + cur_storage_index += 2^40 + # Run the actual code, and see what state transitions it outputs + # The way that the code is expected to work is to: + # + # (1) take as input the list of transactions (the contract should + # use msg.datasize to determine how many txs there are, and it should + # be aware of the value of txwidth) + # (2) call this contract with [2, k] to read current state data + # (3) call this contract with [3, k, v] to write current state data + # (4) return as output a list of all state transitions that it made + # in the form [kvcount, k1, v1, k2, v2 ... ] + # + # The reason for separating (2) from (3) is that sometimes the state + # transition may end up changing a given key many times, and we don't + # need to inefficiently store that in storage + numkvs = contract.storage[cur_storage_index + 3] + numtxs = contract.storage[cur_storage_index + 4] + # Populate input array + inpwidth = numtxs * txwidth + inp = array(inpwidth) + i = 0 + while i < inpwidth: + inp[i] = contract.storage[cur_storage_index + 5 + i] + i += 1 + out = call(contract.storage[2], inp, inpwidth, numkvs * 2 + 1) + # Check that the number of state transitions is the same + if out[0] != kvcount: + send(msg.sender, 10^19) + contract.storage[0] = last_committed_block + stop + kv0index = cur_storage_index + 5 + numtxs * txwidth + i = 0 + while i < kvcount: + # Check that each individual state transition matches + k = contract.storage[kv0index + i * 2 + 1] + v = contract.storage[kv0index + i * 2 + 2] + if k != out[i * 2 + 1] or v != out[i * 2 + 2]: + send(msg.sender, 10^19) + contract.storage[0] = last_committed_block + stop + i += 1 + # Suicide tempstore + call(tempstore, 2) + + +# Read data [2, k] +elif msg.data[0] == 2: + tempstore = contract.storage[3] + o = call(tempstore, [0, msg.data[1]], 2, 2) + if o[0]: + return(o[1]) + else: + return contract.storage[sha3(msg.data[1])] + +# Write data [3, k, v] +elif msg.data[0] == 3: + tempstore = contract.storage[3] + call(tempstore, [1, msg.data[1], msg.data[2]], 3, 2) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/fixedpoint.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/fixedpoint.se new file mode 100644 index 000000000..a8073c685 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/fixedpoint.se @@ -0,0 +1,31 @@ +type f: [a, b, c, d, e] + +macro f($a) + f($b): + f(add($a, $b)) + +macro f($a) - f($b): + f(sub($a, $b)) + +macro f($a) * f($b): + f(mul($a, $b) / 10000) + +macro f($a) / f($b): + f(sdiv($a * 10000, $b)) + +macro f($a) % f($b): + f(smod($a, $b)) + +macro f($v) = f($w): + $v = $w + +macro unfify(f($a)): + $a / 10000 + +macro fify($a): + f($a * 10000) + +a = fify(5) +b = fify(2) +c = a / b +e = c + (a / b) +return(unfify(e)) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/long_integer_macros.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/long_integer_macros.se new file mode 100644 index 000000000..58cdce6ab --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/long_integer_macros.se @@ -0,0 +1,116 @@ +macro smin($a, $b): + with $1 = $a: + with $2 = $b: + if(slt($1, $2), $1, $2) + +macro smax($a, $b): + with $1 = $a: + with $2 = $b: + if(slt($1, $2), $2, $1) + +def omul(x, y): + o = expose(mklong(x) * mklong(y)) + return(slice(o, 1), o[0]+1) + +def oadd(x, y): + o = expose(mklong(x) + mklong(y)) + return(slice(o, 1), o[0]+1) + +def osub(x, y): + o = expose(mklong(x) - mklong(y)) + return(slice(o, 1), o[0]+1) + +def odiv(x, y): + o = expose(mklong(x) / mklong(y)) + return(slice(o, 1), o[0]+1) + +def comb(a:a, b:a, sign): + sz = smax(a[0], b[0]) + msz = smin(a[0], b[0]) + c = array(sz + 2) + c[0] = sz + i = 0 + carry = 0 + while i < msz: + m = a[i + 1] + sign * b[i + 1] + carry + c[i + 1] = mod(m + 2^127, 2^128) - 2^127 + carry = (div(m + 2^127, 2^128) + 2^127) % 2^128 - 2^127 + i += 1 + u = if(a[0] > msz, a, b) + s = if(a[0] > msz, 1, sign) + while i < sz: + m = s * u[i + 1] + carry + c[i + 1] = mod(m + 2^127, 2^128) - 2^127 + carry = (div(m + 2^127, 2^128) + 2^127) % 2^128 - 2^127 + i += 1 + if carry: + c[0] += 1 + c[sz + 1] = carry + return(c, c[0]+1) + +def mul(a:a, b:a): + c = array(a[0] + b[0] + 2) + c[0] = a[0] + b[0] + i = 0 + while i < a[0]: + j = 0 + carry = 0 + while j < b[0]: + m = c[i + j + 1] + a[i + 1] * b[j + 1] + carry + c[i + j + 1] = mod(m + 2^127, 2^128) - 2^127 + carry = (div(m + 2^127, 2^128) + 2^127) % 2^128 - 2^127 + j += 1 + if carry: + c[0] = a[0] + b[0] + 1 + c[i + j + 1] += carry + i += 1 + return(c, c[0]+1) + +macro long($a) + long($b): + long(self.comb($a:$a[0]+1, $b:$b[0]+1, 1, outsz=$a[0]+$b[0]+2)) + +macro long($a) - long($b): + long(self.comb($a:$a[0]+1, $b:$b[0]+1, -1, outsz=$a[0]+$b[0]+2)) + +macro long($a) * long($b): + long(self.mul($a:$a[0]+1, $b:$b[0]+1, outsz=$a[0]+$b[0]+2)) + +macro long($a) / long($b): + long(self.div($a:$a[0]+1, $b:$b[0]+1, outsz=$a[0]+$b[0]+2)) + +macro mulexpand(long($a), $k, $m): + long: + with $c = array($a[0]+k+2): + $c[0] = $a[0]+$k + with i = 0: + while i < $a[0]: + v = $a[i+1] * $m + $c[i+$k+1] + $c[i+$k+1] = mod(v + 2^127, 2^128) - 2^127 + $c[i+$k+2] = div(v + 2^127, 2^128) + i += 1 + $c + +def div(a:a, b:a): + asz = a[0] + bsz = b[0] + while b[bsz] == 0 and bsz > 0: + bsz -= 1 + c = array(asz+2) + c[0] = asz+1 + while 1: + while a[asz] == 0 and asz > 0: + asz -= 1 + if asz < bsz: + return(c, c[0]+1) + sub = expose(mulexpand(long(b), asz - bsz, a[asz] / b[bsz])) + c[asz - bsz+1] = a[asz] / b[bsz] + a = expose(long(a) - long(sub)) + a[asz-1] += 2^128 * a[asz] + a[asz] = 0 + +macro mklong($i): + long([2, mod($i + 2^127, 2^128) - 2^127, div($i + 2^127, 2^128)]) + +macro expose(long($i)): + $i + diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/mul2.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/mul2.se new file mode 100644 index 000000000..65adff1e6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/mul2.se @@ -0,0 +1,2 @@ +def double(v): + return(v*2) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/mutuala.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/mutuala.se new file mode 100644 index 000000000..3efb0edeb --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/mutuala.se @@ -0,0 +1,187 @@ +# mutuala - subcurrency + +# We want to issue a currency that reduces in value as you store it through negative interest. +# That negative interest would be stored in a commons account. It's like the p2p version of a +# capital tax + +# the same things goes for transactions - you pay as you use the currency. However, the more +# you pay, the more you get to say about what the tax is used for + +# each participant can propose a recipient for a payout to be made out of the commons account, +# others can vote on it by awarding it tax_credits. + +# TODO should proposal have expiration timestamp?, after which the tax_credits are refunded +# TODO multiple proposals can take more credits that available in the Commons, how to handle this +# TODO how to handle lost accounts, after which no longer possible to get 2/3 majority + +shared: + COMMONS = 42 + ADMIN = 666 + CAPITAL_TAX_PER_DAY = 7305 # 5% per year + PAYMENT_TAX = 20 # 5% + + ACCOUNT_LIST_OFFSET = 2^160 + ACCOUNT_MAP_OFFSET = 2^161 + PROPOSAL_LIST_OFFSET = 2^162 + PROPOSAL_MAP_OFFSET = 2^163 + +init: + contract.storage[ADMIN] = msg.sender + contract.storage[ACCOUNT_LIST_OFFSET - 1] = 1 + contract.storage[ACCOUNT_LIST_OFFSET] = msg.sender + contract.storage[ACCOUNT_MAP_OFFSET + msg.sender] = 10^12 + contract.storage[ACCOUNT_MAP_OFFSET + msg.sender + 1] = block.timestamp + +# contract.storage[COMMONS] = balance commons + +# contract.storage[ACCOUNT_LIST_OFFSET - 1] = number of accounts +# contract.storage[ACCOUNT_LIST_OFFSET + n] = account n + +# contract.storage[PROPOSAL_LIST_OFFSET - 1] contains the number of proposals +# contract.storage[PROPOSAL_LIST_OFFSET + n] = proposal n + +# per account: +# contract.storage[ACCOUNT_MAP_OFFSET + account] = balance +# contract.storage[ACCOUNT_MAP_OFFSET + account+1] = timestamp_last_transaction +# contract.storage[ACCOUNT_MAP_OFFSET + account+2] = tax_credits + +# per proposal: +# contract.storage[PROPOSAL_MAP_OFFSET + proposal_id] = recipient +# contract.storage[PROPOSAL_MAP_OFFSET + proposal_id+1] = amount +# contract.storage[PROPOSAL_MAP_OFFSET + proposal_id+2] = total vote credits + +code: + if msg.data[0] == "suicide" and msg.sender == contract.storage[ADMIN]: + suicide(msg.sender) + + elif msg.data[0] == "balance": + addr = msg.data[1] + return(contract.storage[ACCOUNT_MAP_OFFSET + addr]) + + elif msg.data[0] == "pay": + from = msg.sender + fromvalue = contract.storage[ACCOUNT_MAP_OFFSET + from] + to = msg.data[1] + if to == 0 or to >= 2^160: + return([0, "invalid address"], 2) + value = msg.data[2] + tax = value / PAYMENT_TAX + + if fromvalue >= value + tax: + contract.storage[ACCOUNT_MAP_OFFSET + from] = fromvalue - (value + tax) + contract.storage[ACCOUNT_MAP_OFFSET + to] += value + # tax + contract.storage[COMMONS] += tax + contract.storage[ACCOUNT_MAP_OFFSET + from + 2] += tax + + # check timestamp field to see if target account exists + if contract.storage[ACCOUNT_MAP_OFFSET + to + 1] == 0: + # register new account + nr_accounts = contract.storage[ACCOUNT_LIST_OFFSET - 1] + contract.storage[ACCOUNT_LIST_OFFSET + nr_accounts] = to + contract.storage[ACCOUNT_LIST_OFFSET - 1] += 1 + contract.storage[ACCOUNT_MAP_OFFSET + to + 1] = block.timestamp + + return(1) + else: + return([0, "insufficient balance"], 2) + + elif msg.data[0] == "hash": + proposal_id = sha3(msg.data[1]) + return(proposal_id) + + elif msg.data[0] == "propose": + from = msg.sender + # check if sender has an account and has tax credits + if contract.storage[ACCOUNT_MAP_OFFSET + from + 2] == 0: + return([0, "sender has no tax credits"], 2) + + proposal_id = sha3(msg.data[1]) + # check if proposal doesn't already exist + if contract.storage[PROPOSAL_MAP_OFFSET + proposal_id]: + return([0, "proposal already exists"]) + + to = msg.data[2] + # check if recipient is a valid address and has an account (with timestamp) + if to == 0 or to >= 2^160: + return([0, "invalid address"], 2) + if contract.storage[ACCOUNT_MAP_OFFSET + to + 1] == 0: + return([0, "invalid to account"], 2) + + value = msg.data[3] + # check if there is enough money in the commons account + if value > contract.storage[COMMONS]: + return([0, "not enough credits in commons"], 2) + + # record proposal in list + nr_proposals = contract.storage[PROPOSAL_LIST_OFFSET - 1] + contract.storage[PROPOSAL_LIST_OFFSET + nr_proposals] = proposal_id + contract.storage[PROPOSAL_LIST_OFFSET - 1] += 1 + + # record proposal in map + contract.storage[PROPOSAL_MAP_OFFSET + proposal_id] = to + contract.storage[PROPOSAL_MAP_OFFSET + proposal_id + 1] = value + + return(proposal_id) + + elif msg.data[0] == "vote": + from = msg.sender + proposal_id = sha3(msg.data[1]) + value = msg.data[2] + # check if sender has an account and has tax credits + if value < contract.storage[ACCOUNT_MAP_OFFSET + from + 2]: + return([0, "sender doesn't have enough tax credits"], 2) + + # check if proposal exist + if contract.storage[PROPOSAL_MAP_OFFSET + proposal_id] == 0: + return([0, "proposal doesn't exist"], 2) + + # increase votes + contract.storage[PROPOSAL_MAP_OFFSET + proposal_id + 2] += value + # withdraw tax credits + contract.storage[ACCOUNT_MAP_OFFSET + from + 2] -= value + + # did we reach 2/3 threshold? + if contract.storage[PROPOSAL_MAP_OFFSET + proposal_id + 2] >= contract.storage[COMMONS] * 2 / 3: + # got majority + to = contract.storage[PROPOSAL_MAP_OFFSET + proposal_id] + amount = contract.storage[PROPOSAL_MAP_OFFSET + proposal_id + 1] + + # adjust balances + contract.storage[ACCOUNT_MAP_OFFSET + to] += amount + contract.storage[COMMONS] -= amount + + # reset proposal + contract.storage[PROPOSAL_MAP_OFFSET + proposal_id] = 0 + contract.storage[PROPOSAL_MAP_OFFSET + proposal_id + 1] = 0 + contract.storage[PROPOSAL_MAP_OFFSET + proposal_id + 2] = 0 + return(1) + + return(proposal_id) + + elif msg.data[0] == "tick": + nr_accounts = contract.storage[ACCOUNT_LIST_OFFSET - 1] + account_idx = 0 + tax_paid = 0 + # process all accounts and see if they have to pay their daily capital tax + while account_idx < nr_accounts: + cur_account = contract.storage[ACCOUNT_LIST_OFFSET + account_idx] + last_timestamp = contract.storage[ACCOUNT_MAP_OFFSET + cur_account + 1] + time_diff = block.timestamp - last_timestamp + if time_diff >= 86400: + tax_days = time_diff / 86400 + balance = contract.storage[ACCOUNT_MAP_OFFSET + cur_account] + tax = tax_days * (balance / CAPITAL_TAX_PER_DAY) + if tax > 0: + # charge capital tax, but give tax credits in return + contract.storage[ACCOUNT_MAP_OFFSET + cur_account] -= tax + contract.storage[ACCOUNT_MAP_OFFSET + cur_account + 1] += tax_days * 86400 + contract.storage[ACCOUNT_MAP_OFFSET + cur_account + 2] += tax + + contract.storage[COMMONS] += tax + tax_paid += 1 + account_idx += 1 + return(tax_paid) # how many accounts did we charge tax on + + else: + return([0, "unknown command"], 2) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/namecoin.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/namecoin.se new file mode 100644 index 000000000..11d6274ae --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/namecoin.se @@ -0,0 +1,7 @@ +def register(k, v): + if !self.storage[k]: # Is the key not yet taken? + # Then take it! + self.storage[k] = v + return(1) + else: + return(0) // Otherwise do nothing diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/peano.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/peano.se new file mode 100644 index 000000000..979854444 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/peano.se @@ -0,0 +1,43 @@ +macro padd($x, psuc($y)): + psuc(padd($x, $y)) + +macro padd($x, z()): + $x + +macro dec(psuc($x)): + dec($x) + 1 + +macro dec(z()): + 0 + +macro pmul($x, z()): + z() + +macro pmul($x, psuc($y)): + padd(pmul($x, $y), $x) + +macro pexp($x, z()): + one() + +macro pexp($x, psuc($y)): + pmul($x, pexp($x, $y)) + +macro fac(z()): + one() + +macro fac(psuc($x)): + pmul(psuc($x), fac($x)) + +macro one(): + psuc(z()) + +macro two(): + psuc(psuc(z())) + +macro three(): + psuc(psuc(psuc(z()))) + +macro five(): + padd(three(), two()) + +return([dec(pmul(three(), pmul(three(), three()))), dec(fac(five()))], 2) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/returnten.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/returnten.se new file mode 100644 index 000000000..7969c9eb8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/returnten.se @@ -0,0 +1,4 @@ +extern mul2: [double] + +x = create("mul2.se") +return(x.double(5)) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellingcoin/quicksort.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellingcoin/quicksort.se new file mode 100644 index 000000000..be5d97fc7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellingcoin/quicksort.se @@ -0,0 +1,33 @@ +def kall(): + argcount = ~calldatasize() / 32 + if argcount == 1: + return(~calldataload(1)) + + args = array(argcount) + ~calldatacopy(args, 1, argcount * 32) + low = array(argcount) + lsz = 0 + high = array(argcount) + hsz = 0 + i = 1 + while i < argcount: + if args[i] < args[0]: + low[lsz] = args[i] + lsz += 1 + else: + high[hsz] = args[i] + hsz += 1 + i += 1 + low = self.kall(data=low, datasz=lsz, outsz=lsz) + high = self.kall(data=high, datasz=hsz, outsz=hsz) + o = array(argcount) + i = 0 + while i < lsz: + o[i] = low[i] + i += 1 + o[lsz] = args[0] + j = 0 + while j < hsz: + o[lsz + 1 + j] = high[j] + j += 1 + return(o, argcount) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellingcoin/quicksort_pairs.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellingcoin/quicksort_pairs.se new file mode 100644 index 000000000..0e603a238 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellingcoin/quicksort_pairs.se @@ -0,0 +1,46 @@ +# Quicksort pairs +# eg. input of the form [ 30, 1, 90, 2, 70, 3, 50, 4] +# outputs [ 30, 1, 50, 4, 70, 3, 90, 2 ] +# +# Note: this can be used as a generalized sorting algorithm: +# map every object to [ key, ref ] where `ref` is the index +# in memory to all of the properties and `key` is the key to +# sort by + + +def kall(): + argcount = ~calldatasize() / 64 + if argcount == 1: + return([~calldataload(1), ~calldataload(33)], 2) + + args = array(argcount * 2) + ~calldatacopy(args, 1, argcount * 64) + low = array(argcount * 2) + lsz = 0 + high = array(argcount * 2) + hsz = 0 + i = 2 + while i < argcount * 2: + if args[i] < args[0]: + low[lsz] = args[i] + low[lsz + 1] = args[i + 1] + lsz += 2 + else: + high[hsz] = args[i] + high[hsz + 1] = args[i + 1] + hsz += 2 + i = i + 2 + low = self.kall(data=low, datasz=lsz, outsz=lsz) + high = self.kall(data=high, datasz=hsz, outsz=hsz) + o = array(argcount * 2) + i = 0 + while i < lsz: + o[i] = low[i] + i += 1 + o[lsz] = args[0] + o[lsz + 1] = args[1] + j = 0 + while j < hsz: + o[lsz + 2 + j] = high[j] + j += 1 + return(o, argcount * 2) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellingcoin/schellingcoin.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellingcoin/schellingcoin.se new file mode 100644 index 000000000..a7d7da9c5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellingcoin/schellingcoin.se @@ -0,0 +1,94 @@ +# SchellingCoin implementation +# +# Epoch length: 100 blocks +# Target savings depletion rate: 0.1% per epoch + +data epoch +data hashes_submitted +data output +data quicksort_pairs +data accounts[2^160] +data submissions[2^80](hash, deposit, address, value) +extern any: [call] + + +def init(): + self.epoch = block.number / 100 + self.quicksort_pairs = create('quicksort_pairs.se') + +def any(): + if block.number / 100 > epoch: + # Sort all values submitted + N = self.hashes_submitted + o = array(N * 2) + i = 0 + j = 0 + while i < N: + v = self.submissions[i].value + if v: + o[j] = v + o[j + 1] = i + j += 2 + i += 1 + values = self.quicksort_pairs.call(data=o, datasz=j, outsz=j) + + # Calculate total deposit, refund non-submitters and + # cleanup + + deposits = array(j / 2) + addresses = array(j / 2) + + i = 0 + total_deposit = 0 + while i < j / 2: + base_index = HASHES + values[i * 2 + 1] * 3 + deposits[i] = self.submissions[i].deposit + addresses[i] = self.submissions[i].address + if self.submissions[values[i * 2 + 1]].value: + total_deposit += deposits[i] + else: + send(addresses[i], deposits[i] * 999 / 1000) + i += 1 + + inverse_profit_ratio = total_deposit / (contract.balance / 1000) + 1 + + # Reward everyone + i = 0 + running_deposit_sum = 0 + halfway_passed = 0 + while i < j / 2: + new_deposit_sum = running_deposit_sum + deposits[i] + if new_deposit_sum > total_deposit / 4 and running_deposit_sum < total_deposit * 3 / 4: + send(addresses[i], deposits[i] + deposits[i] / inverse_profit_ratio * 2) + else: + send(addresses[i], deposits[i] - deposits[i] / inverse_profit_ratio) + + if not halfway_passed and new_deposit_sum > total_deposit / 2: + self.output = self.submissions[i].value + halfway_passed = 1 + self.submissions[i].value = 0 + running_deposit_sum = new_deposit_sum + i += 1 + self.epoch = block.number / 100 + self.hashes_submitted = 0 + +def submit_hash(h): + if block.number % 100 < 50: + cur = self.hashes_submitted + pos = HASHES + cur * 3 + self.submissions[cur].hash = h + self.submissions[cur].deposit = msg.value + self.submissions[cur].address = msg.sender + self.hashes_submitted = cur + 1 + return(cur) + +def submit_value(index, v): + if sha3([msg.sender, v], 2) == self.submissions[index].hash: + self.submissions[index].value = v + return(1) + +def request_balance(): + return(contract.balance) + +def request_output(): + return(self.output) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellingcoin/schellingdollar.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellingcoin/schellingdollar.se new file mode 100644 index 000000000..a34f42ce2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellingcoin/schellingdollar.se @@ -0,0 +1,171 @@ +# Hedged zero-supply dollar implementation +# Uses SchellingCoin as price-determining backend +# +# Stored variables: +# +# 0: Schelling coin contract +# 1: Last epoch +# 2: Genesis block of contract +# 3: USD exposure +# 4: ETH exposure +# 5: Cached price +# 6: Last interest rate +# 2^160 + k: interest rate accumulator at k epochs +# 2^161 + ADDR * 3: eth-balance of a particular address +# 2^161 + ADDR * 3 + 1: usd-balance of a particular address +# 2^161 + ADDR * 3 + 1: last accessed epoch of a particular address +# +# Transaction types: +# +# [1, to, val]: send ETH +# [2, to, val]: send USD +# [3, wei_amount]: convert ETH to USD +# [4, usd_amount]: converts USD to ETH +# [5]: deposit +# [6, amount]: withdraw +# [7]: my balance query +# [7, acct]: balance query for any acct +# [8]: global state query +# [9]: liquidation test any account +# +# The purpose of the contract is to serve as a sort of cryptographic +# bank account where users can store both ETH and USD. ETH must be +# stored in zero or positive quantities, but USD balances can be +# positive or negative. If the USD balance is negative, the invariant +# usdbal * 10 >= ethbal * 9 must be satisfied; if any account falls +# below this value, then that account's balances are zeroed. Note +# that there is a 2% bounty to ping the app if an account does go +# below zero; one weakness is that if no one does ping then it is +# quite possible for accounts to go negative-net-worth, then zero +# themselves out, draining the reserves of the "bank" and potentially +# bankrupting it. A 0.1% fee on ETH <-> USD trade is charged to +# minimize this risk. Additionally, the bank itself will inevitably +# end up with positive or negative USD exposure; to mitigate this, +# it automatically updates interest rates on USD to keep exposure +# near zero. + +data schelling_coin +data last_epoch +data starting_block +data usd_exposure +data eth_exposure +data price +data last_interest_rate +data interest_rate_accum[2^50] +data accounts[2^160](eth, usd, last_epoch) + +extern sc: [submit_hash, submit_value, request_balance, request_output] + +def init(): + self.schelling_coin = create('schellingcoin.se') + self.price = self.schelling_coin.request_output() + self.interest_rate_accum[0] = 10^18 + self.starting_block = block.number + +def any(): + sender = msg.sender + epoch = (block.number - self.starting_block) / 100 + last_epoch = self.last_epoch + usdprice = self.price + + # Update contract epochs + if epoch > last_epoch: + delta = epoch - last_epoch + last_interest_rate = self.last_interest_rate + usd_exposure - self.usd_exposure + last_accum = self.interest_rate_accum[last_epoch] + + if usd_exposure < 0: + self.last_interest_rate = last_interest_rate - 10000 * delta + elif usd_exposure > 0: + self.last_interest_rate = last_interest_rate + 10000 * delta + + self.interest_rate_accum[epoch] = last_accum + last_accum * last_interest_rate * delta / 10^9 + + # Proceeds go to support the SchellingCoin feeding it price data, ultimately providing the depositors + # of the SchellingCoin an interest rate + bal = max(self.balance - self.eth_exposure, 0) / 10000 + usdprice = self.schelling_coin.request_output() + self.price = usdprice + self.last_epoch = epoch + + ethbal = self.accounts[msg.sender].eth + usdbal = self.accounts[msg.sender].usd + + # Apply interest rates to sender and liquidation-test self + if msg.sender != self: + self.ping(self) + +def send_eth(to, value): + if value > 0 and value <= ethbal and usdbal * usdprice * 2 + (ethbal - value) >= 0: + self.accounts[msg.sender].eth = ethbal - value + self.ping(to) + self.accounts[to].eth += value + return(1) + +def send_usd(to, value): + if value > 0 and value <= usdbal and (usdbal - value) * usdprice * 2 + ethbal >= 0: + self.accounts[msg.sender].usd = usdbal - value + self.ping(to) + self.accounts[to].usd += value + return(1) + +def convert_to_eth(usdvalue): + ethplus = usdvalue * usdprice * 999 / 1000 + if usdvalue > 0 and (usdbal - usdvalue) * usdprice * 2 + (ethbal + ethplus) >= 0: + self.accounts[msg.sender].eth = ethbal + ethplus + self.accounts[msg.sender].usd = usdbal - usdvalue + self.eth_exposure += ethplus + self.usd_exposure -= usdvalue + return([ethbal + ethplus, usdbal - usdvalue], 2) + +def convert_to_usd(ethvalue): + usdplus = ethvalue / usdprice * 999 / 1000 + if ethvalue > 0 and (usdbal + usdplus) * usdprice * 2 + (ethbal - ethvalue) >= 0: + self.accounts[msg.sender].eth = ethbal - ethvalue + self.accounts[msg.sender].usd = usdbal + usdplus + self.eth_exposure -= ethvalue + self.usd_exposure += usdplus + return([ethbal - ethvalue, usdbal + usdplus], 2) + +def deposit(): + self.accounts[msg.sender].eth = ethbal + msg.value + self.eth_exposure += msg.value + return(ethbal + msg.value) + +def withdraw(value): + if value > 0 and value <= ethbal and usdbal * usdprice * 2 + (ethbal - value) >= 0: + self.accounts[msg.sender].eth -= value + self.eth_exposure -= value + return(ethbal - value) + +def balance(acct): + self.ping(acct) + return([self.accounts[acct].eth, self.accounts[acct].usd], 2) + +def global_state_query(acct): + interest = self.last_interest_rate + usd_exposure = self.usd_exposure + eth_exposure = self.eth_exposure + eth_balance = self.balance + return([epoch, usdprice, interest, usd_exposure, eth_exposure, eth_balance], 6) + +def ping(acct): + account_last_epoch = self.accounts[acct].last_epoch + if account_last_epoch != epoch: + cur_usd_balance = self.accounts[acct].usd + new_usd_balance = cur_usd_balance * self.interest_rate_accum[epoch] / self.interest_rate_accum[account_last_epoch] + self.accounts[acct].usd = new_usd_balance + self.accounts[acct].last_epoch = epoch + self.usd_exposure += new_usd_balance - cur_usd_balance + + ethbal = self.accounts[acct].eth + + if new_usd_balance * usdval * 10 + ethbal * 9 < 0: + self.accounts[acct].eth = 0 + self.accounts[acct].usd = 0 + self.accounts[msg.sender].eth += ethbal / 50 + self.eth_exposure += -ethbal + ethbal / 50 + self.usd_exposure += new_usd_balance + return(1) + return(0) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellinghelper.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellinghelper.se new file mode 100644 index 000000000..0e522d6e8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellinghelper.se @@ -0,0 +1 @@ +return(sha3([msg.sender, msg.data[0]], 2)) diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/short_namecoin.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/short_namecoin.se new file mode 100644 index 000000000..db327a77d --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/short_namecoin.se @@ -0,0 +1,3 @@ +def register(k, v): + if !self.storage[k]: + self.storage[k] = v diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/subcurrency.se b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/subcurrency.se new file mode 100644 index 000000000..fbda822b6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/subcurrency.se @@ -0,0 +1,11 @@ +def init(): + self.storage[msg.sender] = 1000000 + +def balance_query(k): + return(self.storage[addr]) + +def send(to, value): + fromvalue = self.storage[msg.sender] + if fromvalue >= value: + self.storage[from] = fromvalue - value + self.storage[to] += value |