aboutsummaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/futarchy.se
blob: 0d68622ac53bf961fd2d32eda20fbab7874d256f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# 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