Module: Lightning::Invoice

Defined in:
lib/lightning/invoice.rb,
lib/lightning/invoice/version.rb,
lib/lightning/invoice/routing_info.rb

Defined Under Namespace

Classes: Message, RoutingInfo

Constant Summary collapse

PREFIX =
'lnbc'
MAX_LENGTH =
2 ** 64
VERSION =
"0.1.4"

Class Method Summary collapse

Class Method Details

.buffer_to_word(buffer) ⇒ Object



227
228
229
230
# File 'lib/lightning/invoice.rb', line 227

def self.buffer_to_word(buffer)
  words = convert(buffer.unpack('C*'), 8, 5, true)
  return words
end

.convert(data, inbits, outbits, padding) ⇒ Object



232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/lightning/invoice.rb', line 232

def self.convert(data, inbits, outbits, padding)
  value = 0
  bits = 0
  max = (1 << outbits) - 1

  result = []
  n = data.length
  n.times do |i|
    value = (value << inbits) | data[i]
    bits += inbits
    while bits >= outbits
      bits -= outbits
      result << ((value >> bits) & max)
    end
  end

  if padding && bits > 0
    result << ((value << (outbits - bits)) & max)
  end

  return result
end

.int_to_array(i, bits = 5, padding = 2) ⇒ Object



261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/lightning/invoice.rb', line 261

def self.int_to_array(i, bits = 5, padding = 2)
  array = []
  return [0] if i.nil? || i == 0
  while i > 0
    array << (i & (2**bits - 1))
    i = (i / (2**bits)).to_i
  end
  if padding > array.size
    array += [0] * (padding - array.size)
  end
  array.reverse
end

.msat_to_readable(msat) ⇒ Object



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/lightning/invoice.rb', line 200

def self.msat_to_readable(msat)
  if msat >= 100_000_000_000
    [(msat / 100_000_000_000).to_i, '']
  elsif msat >= 100_000_000
    [(msat / 100_000_000).to_i, 'm']
  elsif msat >= 100_000
    [(msat / 100_000).to_i, 'u']
  elsif msat >= 100
    [(msat  / 100).to_i, 'n']
  elsif msat > 0
    [(msat * 10).to_i, 'p']
  elsif msat == 0
    [0, '']
  else
    raise 'amount_msat should be greater than or equal to 0'
  end
end

.parse(str) ⇒ Object



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/lightning/invoice.rb', line 134

def self.parse(str)
  human, data_part = Bech32.decode(str, MAX_LENGTH)
  return nil unless human
  prefix, amount, multiplier = parse_human_readable(human)
  message = Message.new
  message.prefix = prefix
  message.amount = amount.to_i if !amount&.empty?
  message.multiplier = multiplier
  message.timestamp = to_int(data_part[0...7])
  tags = data_part[7...data_part.size - 104]
  index = 0
  if tags
    while index < tags.size
      type = tags[index]
      data_length = (tags[index + 1].to_i << 5) + tags[index + 2].to_i
      data = tags[index + 3 ... index + 3 + data_length]
      bytes = to_bytes(data)
      index += 3 + data_length
      case type
      when 1
        message.payment_hash = bytes[0...64].pack("C*").bth
      when 13
        message.description = bytes.pack("C*").force_encoding('utf-8')
      when 19
        message.pubkey = bytes[0...66].pack("C*").bth
      when 23
        message.description_hash = bytes[0...64].pack("C*").bth
      when 6
        message.expiry = to_int(data)
      when 24
        message.min_final_cltv_expiry = to_int(data)
      when 9
        address = to_bytes(data[1..-1])
        hex = address.pack("C*").unpack("H*").first
        case data[0]
        when 0
          message.fallback_address = Bitcoin::Script.to_p2wpkh(hex).addresses.first
        when 17
          message.fallback_address = Bitcoin.encode_base58_address(hex, Bitcoin.chain_params.address_version)
        when 18
          message.fallback_address = Bitcoin.encode_base58_address(hex, Bitcoin.chain_params.p2sh_version)
        else
        end
      when 3
        offset = 0
        while offset < bytes.size
          message.routing_info << Lightning::Invoice::RoutingInfo.new(
            bytes[offset...offset + 33].pack("C*").bth,
            bytes[offset + 33...offset + 41].pack("C*").bth,
            to_int(bytes[offset + 41...offset + 45]),
            to_int(bytes[offset + 45...offset + 49]),
            to_int(bytes[offset + 49...offset + 51])
          )
          offset += 51
        end
      else
      end
    end
  end
  sig = data_part[data_part.size - 104..-1]
  if sig
    message.signature = word_to_buffer(sig).bth
  end
  message
end

.parse_human_readable(human) ⇒ Object



218
219
220
# File 'lib/lightning/invoice.rb', line 218

def self.parse_human_readable(human)
  human.scan(/^([a-zA-Z]+)(\d*)([munp]?)$/)&.first
end

.to_bytes(data) ⇒ Object



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
# File 'lib/lightning/invoice.rb', line 274

def self.to_bytes(data)
  buf = []
  (data.size * 5).times do |i|
    loc5 = (i / 5).to_i
    loc8 = i >> 3
    if i % 8 == 0
      buf[loc8] = 0
    end
    buf[loc8] |= ((data[loc5] >> (4 - (i % 5))) & 1) << (7 - (i % 8))
  end
  if data.size % 8 != 0
    buf = buf[0...-1]
  end
  buf
end

.to_int(data) ⇒ Object



255
256
257
258
259
# File 'lib/lightning/invoice.rb', line 255

def self.to_int(data)
  data.inject(0) do |i, sum|
    sum + (i << 5)
  end
end

.word_to_buffer(data) ⇒ Object



222
223
224
225
# File 'lib/lightning/invoice.rb', line 222

def self.word_to_buffer(data)
  buffer = convert(data, 5, 8, false)
  return buffer.pack("C*")
end