Are You Lucky Bastard?
Tags: ruby, blockchain, news, showdev
Published: 2021-04-04 15:52:03

{% github decentralizuj/luckybastard no-readme %}

![LuckyBastard Preview](https://raw.githubusercontent.com/decentralizuj/luckybastard/main/luckybastard.gif)

# Introduction

This is a fun-only project, just to do something fun while drinking amazing cold Nescafe-Shake.

So how it works? _**SecureRandom**_ create 32bits random hex string. This string is used by _**Money-Tree gem**_ to make Master Node of Bip32 HD wallet. I could just let money-tree to create random seed, but where's my fun then?

# Let's start!

You can add gems into Gemfile, then use it for luckybastard, but most of ruby devs have this gems installed. In case you don't have:

```ruby
# install gems localy with:
gem install money-tree colorize

or

# create Gemfile and add gems
# run `bundle install` to install them
gem 'money-tree'
gem 'colorize'
```  

Now create file called `luckybastard.rb` and open it. Write _shebang_ (because I guess you're on linux, if you are on windows, go install linux), and require needed dependencies.

```ruby
#!/usr/bin/env ruby

require 'securerandom'
require 'money-tree'
require 'open-uri'
require 'colorize'
require 'net/http'
```

MoneyTree and Colorize are gems we need to install, and other  dependencies need to require.

Let's create our class `LuckyBastard`

```ruby
  # class LuckyBastard - code is part of this

  # max-time to sleep if request fail
  SLEEP = 2

  # default type of checking address
  TYPE  = :sent


  def initialize( max_sleep = SLEEP, type = TYPE )

    # count all requests (generated seeds)
    @counter = 0

    # this counter reset on 10, to show in terminal
    @count = 0

    # type of address-check
    @type = type

    # is loop paused
    @work = false

    # max_sleep between fail requests
    @pause = max_sleep

    # start time
    @start = Time.now.to_i
  end
```

After initializing variables, it's time to make methods to get/set/use them.

```ruby
  # set max_pause time
  def pause=(max_sleep)
    @pause = max_sleep
  end

  # get max_pause time
  def pause
    @pause
  end

  # check is paused or not
  def pause? 
    @work == true
  end

  # start or stop loop
  def pause!
    if pause? then start else stop end
  end

  # stop loop
  def stop
    @loop = false
  end

  # start loop if paused (or not)
  def start
    pause! if pause?
    until pause? do execute end      
  end

  # from check(address)
  def success?
    @balance > 0.0
  end
```

That's all for public methods. Now we need `LuckyBastard#execute` (used in #start). That method will use another to generate seed and check for address balance. This methods should be private.

>Private methods you can't call directly. You put them inside public method to run.

```ruby
# ... public code

  private

  # called from #start
  def execute

    # generate random keys
    random_private_key!

    # check address balance
    check @address 
    @count += 1

    # if balance is more then 0.0
    if success?
      @end = Time.now.to_i - @start

      # write valid data to file and print them
      write_to_file(@address, @balance, @hex_seed)
      puts "[*] Valid seed found in #{(@end / 60)} minutes".yellow
      puts "[!] Enter 'Q' to quit, or any key to continue (q/Q):".yellow

      # get answer from input, exit if include q/Q
      answer = STDIN.gets.chomp
      %w[q Q].include?(answer) ? exit(1) : start

    # when fail, print data if 10 seeds generated
    elsif @count >= 10

      # add previous seeds to total counter 
      @counter += @count

      # clean screen and print number of generated seeds
      system 'clear' or system 'cls'
      print "\n >> Looking for [".green + "#{@type.to_s.upcase}".yellow + "]".green
      puts " coins on random address".green
      puts "\n " +" #{@counter} ".black.on_yellow + " random seeds checked...".yellow
      puts ""

      # print fail address data, do not save
      write_to_file(@address, @balance, @hex_seed, save: false)

      # reset count, so we can count next 10 seeds
      @count = 0

      # sleep random time, we defined maximum
      sleep rand(pause)
    end
  end


  def random_private_key!

    # generate random 32bit hex string
    @hex_seed = SecureRandom.hex 32

    # make new master node, and get address
    @address = MoneyTree::Master.new(seed_hex: @hex_seed).to_address
  end


  def check(address)

    # define to check for `received/sent` by address
    type = @type.to_s 
    url  = "https://blockchain.info/q/get#{type}byaddress/#{address}"
    data = Net::HTTP.get URI url

    # get balance in float
    return @balance = data.to_f 

    # if request fail, sleep 1 min and repeat
    rescue
    puts 'request timeout, repeating process in 60 seconds...'
    sleep(60) and start
  end


  def write_to_file(address, balance, seed, opt = {})
    @data = " #{Time.now.to_s}" + "\n"
    @data += "\n Address: #{address}\n Balance: #{balance}\n HexSeed: #{seed}"

    # do not save if option save is true (for invalid seed)
    File.write("#{address}.txt", @data) unless opt[:save] == false

    # print red for fail, green for success (balance > 0)
    clr = success? ? :green : :red
    puts @data.colorize(clr)
  end
```

After you put this code inside **LuckyBastard** class, you can write one more method as a shortcut to run loop

```ruby
class LuckyBastard

  # all previous code here

  def self.start!(max_sleep = 2, type = :sent)
    LuckyBastard.new(max_sleep, type).start
  end

end
```

You need a way to run it from terminal. Without arguments print help instructions, which tell us to run with `--start`, and to add `--sent` if we want.

```ruby
  # check for received coins unless args include `--sent`
  type = ARGV.include?('--sent') ? :sent : :received

  # start if args include start, or print help
  if ARGV.include?('--start')
    system 'clear'
    puts "\n Starting random seed generation..."
    LuckyBastard.start! 2, type
  else
    puts "\n              Are You Lucky Bastard?".green.bold
    puts "      Generate random hex seed and find out!".green.bold
    print ' '
    50.times { print '='.green } and puts
    puts "  Get received by address:".white
    puts "   $ ruby luckybastard.rb --start".light_green
    puts "  Get sent by address:".white
    puts "   $ ruby luckybastard.rb --start --sent\n".light_green
  end
```