aboutsummaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/mutuala.se
diff options
context:
space:
mode:
Diffstat (limited to 'Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/mutuala.se')
-rw-r--r--Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/mutuala.se187
1 files changed, 187 insertions, 0 deletions
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)