diff options
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.se | 171 |
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) |