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