# 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
