Module: Webcash::Helpers

Defined in:
lib/webcash/helpers.rb

Overview

Provides helper methods for Webcash.

Class Method Summary collapse

Class Method Details

.assert_is_array(input) ⇒ Object



158
159
160
161
162
# File 'lib/webcash/helpers.rb', line 158

def self.assert_is_array(input)
  unless input.is_a?(Array) && input.all? { |e| e.is_a?(Integer) }
    raise "This method only supports number arrays but input was: #{input}"
  end
end

.chunk_array(array, chunk_size) ⇒ Object



25
26
27
# File 'lib/webcash/helpers.rb', line 25

def self.chunk_array(array, chunk_size)
  array.each_slice(chunk_size).to_a
end

.convert_secret_hex_to_bytes(secret) ⇒ Object



127
128
129
# File 'lib/webcash/helpers.rb', line 127

def self.convert_secret_hex_to_bytes(secret)
  hex_to_padded_bytes(secret)
end

.convert_secret_value_to_public_value(secret_value) ⇒ Object



92
93
94
# File 'lib/webcash/helpers.rb', line 92

def self.convert_secret_value_to_public_value(secret_value)
  Digest::SHA256.hexdigest(secret_value)
end

.create_webcash_with_random_secret_from_amount(amount) ⇒ Object



117
118
119
# File 'lib/webcash/helpers.rb', line 117

def self.create_webcash_with_random_secret_from_amount(amount)
  "e#{amount.to_s('F')}:secret:#{generate_random_value(32)}"
end

.decimal_amount_to_string(amount) ⇒ Object

Convert a decimal amount to a string. This is used for representing different webcash when serializing webcash. When the amount is not known, the string should be “?”.



105
106
107
108
109
110
111
112
113
114
115
# File 'lib/webcash/helpers.rb', line 105

def self.decimal_amount_to_string(amount)
  return "?" if amount.nil?

  if amount.frac.zero?
    amount.to_i.to_s
  else
    # Force 8 decimals and trim trailing zeros
    amount_str = format("%.8f", amount)
    amount_str.sub(/\.?0+$/, "")
  end
end

.deserialize_webcash(webcash) ⇒ Object

Raises:



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/webcash/helpers.rb', line 44

def self.deserialize_webcash(webcash)
  raise Error, "Unusable format for webcash." unless webcash.include?(":")

  parts = webcash.split(":")
  raise Error, "Don't know how to deserialize this webcash." if parts.length < 2

  amount_raw = parts[0]
  public_or_secret = parts[1]
  value = parts[2]

  raise Error, "Can't deserialize this webcash, value is missing." if value.nil?

  unless %w[public secret].include?(public_or_secret)
    raise Error, "Can't deserialize this webcash, needs to be either public/secret."
  end

  amount = parse_amount_from_string(amount_raw)

  if public_or_secret == "secret"
    Webcash::Secret.new(amount, value)
  else
    Webcash::Public.new(amount, value)
  end
end

.generate_random_value(length) ⇒ Object



174
175
176
# File 'lib/webcash/helpers.rb', line 174

def self.generate_random_value(length)
  (1..length).map { rand(16).to_s(16) }.join
end

.hex_to_bytes(hex) ⇒ Object



131
132
133
134
# File 'lib/webcash/helpers.rb', line 131

def self.hex_to_bytes(hex)
  hex = hex.sub(/^0x/i, "")
  hex.scan(/../).map { |x| x.hex }
end

.hex_to_padded_bytes(hex, padding_target_length = 32) ⇒ Object



121
122
123
124
125
# File 'lib/webcash/helpers.rb', line 121

def self.hex_to_padded_bytes(hex, padding_target_length = 32)
  bytes = [ hex.sub(/^0x/, "") ].pack("H*").bytes
  padded_bytes = Array.new(padding_target_length - bytes.length, 0) + bytes
  padded_bytes
end

.long_to_byte_array(num) ⇒ Object



147
148
149
150
151
152
153
154
155
156
# File 'lib/webcash/helpers.rb', line 147

def self.long_to_byte_array(num)
  byte_array = Array.new(8, 0)

  (0...byte_array.length).each do |index|
    byte_array[index] = num & 0xff
    num >>= 8
  end

  byte_array
end

.padded_bytes(bytes, padding_target_length = 32) ⇒ Object



136
137
138
139
140
141
142
143
144
145
# File 'lib/webcash/helpers.rb', line 136

def self.padded_bytes(bytes, padding_target_length = 32)
  if bytes.length == padding_target_length
    bytes
  elsif bytes.length > padding_target_length
    raise "Can only handle up to #{padding_target_length} bytes, int too big to convert"
  else
    padding_needed = padding_target_length - bytes.length
    Array.new(padding_needed, 0) + bytes
  end
end

.parse_amount_from_string(amount_raw) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/webcash/helpers.rb', line 69

def self.parse_amount_from_string(amount_raw)
  # If there is a colon in the value, then the amount is going to be on the
  # left hand side.
  part1 = amount_raw.split(":")[0]

  # There can be at most one 'e' in the value, at the beginning.
  count = part1.count("e")
  if count.zero?
    BigDecimal(part1)
  elsif count <= 1
    # should be at the beginning
    raise Error, "Invalid amount format for webcash." unless part1[0] == "e"
    # there needs to be an actual amount
    raise Error, "Invalid amount format for webcash." unless part1 != "e"

    part2 = part1.split("e")[1]
    BigDecimal(part2)

  else
    raise Error, "Invalid amount format for webcash."
  end
end

.range(start, stop, step = 1) ⇒ Object



12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/webcash/helpers.rb', line 12

def self.range(start, stop, step = 1)
  return [] if (step.positive? && start >= stop) || (step.negative? && start <= stop)

  result = []
  i = start
  while step.positive? ? i < stop : i > stop
    result << i
    i += step
  end

  result
end

.sha256_from_array(array) ⇒ Object



164
165
166
167
168
169
170
171
172
# File 'lib/webcash/helpers.rb', line 164

def self.sha256_from_array(array)
  assert_is_array(array)

  # Convert the array of integers to a binary string
  binary_string = array.pack("C*")

  # Create and return the SHA256 digest
  Digest::SHA256.digest(binary_string)
end

.string_amount_to_decimal(amount) ⇒ Object

Convert from a string amount to a Decimal value.



97
98
99
# File 'lib/webcash/helpers.rb', line 97

def self.string_amount_to_decimal(amount)
  BigDecimal(amount)
end

.validate_amount_decimals(amount) ⇒ Object

Check that the amount has no more than a maximum number of decimal places.

Raises:

  • (RangeError)


30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/webcash/helpers.rb', line 30

def self.validate_amount_decimals(amount)
  if amount.is_a?(String)
    amount = parse_amount_from_string(amount)
  elsif amount.is_a?(Float)
    amount = BigDecimal(amount.to_s)
  else
    amount = BigDecimal(amount)
  end

  raise RangeError, "Amount precision should be at most 8 decimals." unless amount.scale <= 8

  true
end