Ruby Quiz - (Crypto) Blockchain Contract Edition - Challenge #2 - Code Challenge #2 - Create a PonzICO Investment Contract - Blockchain Performance Art


(Gerald Bauer) #1

Hello,

  to kickstart the new ruby quiz (crypto) blockchain contract edition
let's add another (easier) coding challenge:

   Challenge #2 - Create a PonzICO Investment Contract - Blockchain
Performance Art [1]

    Let's use the live and "real world" blockchain performance art
  PonzICO investment contract [2] running on the Ethereum world computer.

  Read the PonzICO White Paper [3] for how the investment scheme and
dividend payouts work and what your money will get used for (hint:
thanks for the free Tesla - don't forget to vote on the color :slight_smile: and
maybe a two bedroom condo in San Francisco).

   Can you do better (than the JavaScript-like Solidity "world standard")?

   Post your code snippets (or questions or comments) on the
"official" Ruby Quiz Channel, that is, the ruby-talk mailing list
right here.

  Happy hacking and (crypto) blockchain contract scripting with sruby.

[1] https://github.com/s6ruby/quiz/tree/master/002
[2] https://etherscan.io/address/0x1ce7986760ade2bf0f322f5ef39ce0de3bd0c82b/#code
[3] https://ponzico.win


(Gerald Bauer) #2

Hello,

   Another Spoiler Alert! Here's the (secure) ruby reference solution [1]
plus the bonus level exercise [2] in its full glory for the (Secure) Ruby Quiz -
Code Challenge #2 - Create a PonzICO Investment Contract - Blockchain
Performance Art:

```

···

####################################
# PonzICO contract

# log event of successful investment/withdraw and address
Investment = Event.new( :investor, :amount )
Withdrawal = Event.new( :investor, :amount )

# constructor for initializing PonzICO.
# the owner is the genius who made this revolutionary smart contract
def setup
@owner = msg.sender
  @total = 0
  @invested = Mapping.of( Address => Money )
  @balances = Mapping.of( Address => Money )
  @investors = Array.of( Address )
end

# the logic for a small fee for the creator of this contract
# miniscule in the grand scheme of things
def owner_fee( amount )
  assert @total < 200_000.ether
  fee = amount / 2
  @balances[@owner] += fee
  fee
end

# This is where the magic is withdrawn.
# For users with balances. Can only be used to withdraw full balance.
def withdraw
  assert @balances[msg.sender] > 0

  amount = @balances[msg.sender]
  @balances[msg.sender] = 0
  if !msg.sender.send(amount)
    @balances[msg.sender] = amount
  else
    log Withdrawal.new(msg.sender, amount)
  end
end

# What's better than withdrawing? Re-investing profits!
def reinvest
  assert @balances[msg.sender] > 0

  dividend = @balances[msg.sender]
  @balances[msg.sender] = 0
  fee = owner_fee( dividend )
  dividend -= fee
  @investors.each do |investor|
    @balances[investors] += dividend * @invested[investors] / total
  end
  @invested[msg.sender] += (dividend + fee);
  total += (dividend + fee)
  log Investment.new(msg.sender, dividend+fee)
end

# This is the where the magic is invested.
# Note the accreditedInvestor() modifier, to ensure only sophisticated
# investors with 0.1 ETH or more can invest. #SelfRegulation
def invest
  assert msg.value > 100.finney

  # first send the owner's modest 50% fee but only if the total
invested is less than 200000 ETH
  dividend = msg.value
  fee = owner_fee( dividend )
  dividend -= fee
  # then accrue balances from the generous remainder to everyone else
previously invested
  @inverstors.each do |investor|
    @balances[investors += dividend * @invested[investors / total
  end

  # finally, add this enterprising new investor to the public balances
  if @invested[msg.sender] == 0
    @investors.push( msg.sender )
    @invested[msg.sender] = msg.value
  else
    @invested[msg.sender] += msg.value
  end
  total += msg.value
  log Investment.new(msg.sender, msg.value)
end

# finally, fallback function. no one should send money to this contract
# without first being added as an investment.
def receive() throw; end


and the bonus level:

####################################
# Vote On My Tesla Color Contract

Color = Enum.new( :solid_black, # 0
                  :midnight_silver_metallic, # 1
                  :deep_blue_metallic, # 2
                  :silver_metallic, # 3
                  :red_multi_coat ) # 4

Votes = Event.new( :color, :num )
Winner = Event.new( :color )

# constructor for initializing VoteOnMyTeslaColor
# the owner is the genius who made the revolutionary smart contract PonzICO
# obviously blue starts with 10 votes because it is objectively the BEST color
def setup
  @owner = msg.sender
  @votes = Mapping.of( Color => Integer )
  @voted = Mapping.of( Address => Bool )

  # YOURE MY BOY BLUE
  @votes[ Color.deep_blue_metallic ] = 10

  # hardcode production PonzICO address
  @ponzico = PonzICO.at( 0x1ce7986760ADe2BF0F322f5EF39Ce0DE3bd0C82B )
end

# SUPER ACCREDITED INVESTORS ONLY, YOU CAN ONLY VOTE ONCE
def vote( choice )
  assert @ponzico.invested[msg.sender] >= 100.finney && !@voted[msg.sender]

  color = Color( choice )
  # 0.1 ETH (100 finney) invested in PonzICO per vote, truncated
  num = @ponzico.invested[msg.sender] / 100.finney
  @votes[color] += num
  @voted[msg.sender] = true
  log Votes.new( color, num )
end

# pay to vote again! I don't care!
# ...but it'll cost you 1 ether for me to look the other way, wink wink
def its_like_chicago
  assert @voted[msg.sender] && msg.value >= 1.ether
  @voted[msg.sender] = false
end

def winnovate
   assert msg.sender == owner
   winner = Color.solid_black
   (1..5).each do |choice|
     if @votes[choice] > @votes[choice-1]
        winner = Color(choice)
     end
  end

  log Winner.new( winner )
  # keeping dat blockchain bloat on check
  selfdestruct(owner)
end
```

Compare to the (secure) ruby (scode) code to the Solidity "world standard"?
Questions and comments welcome. If you have ideas for upcoming (ruby
quiz) contracts,
please tell!

   Cheers. Prost. Happy coding and (crypto) blockchain contract
scripting with sruby.

[1] https://github.com/s6ruby/quiz/blob/master/002/solution.rb
[2] https://github.com/s6ruby/quiz/blob/master/002/solution_bonus.rb