From cae972ca49541bacc7cc59d59d7723105c0b5041 Mon Sep 17 00:00:00 2001 From: icebaker Date: Sun, 2 Apr 2023 19:51:23 -0300 Subject: [PATCH] adding support for btc payments --- Gemfile.lock | 4 +- adapters/bitcoin/request.rb | 31 ++++ controllers/bitcoin/request.rb | 25 +++ controllers/bitcoin/request/decode.rb | 55 +++++++ controllers/bitcoin/transaction.rb | 4 +- controllers/bitcoin/transaction/all.rb | 15 +- docs/README.md | 18 +++ models/bitcoin/request.rb | 77 +++++++++ models/satoshis.rb | 16 +- ports/dsl/lighstorm.rb | 2 + .../bitcoin/request/decode_spec.rb | 152 ++++++++++++++++++ .../lightning/invoice/actions/pay_spec.rb | 4 +- .../lightning/node/actions/pay_spec.rb | 12 +- spec/models/lightning/edges/payment_spec.rb | 30 ++-- spec/models/satoshis_spec.rb | 20 +++ spec/ports/dsl/lighstorm_spec.rb | 1 + 16 files changed, 430 insertions(+), 36 deletions(-) create mode 100644 adapters/bitcoin/request.rb create mode 100644 controllers/bitcoin/request.rb create mode 100644 controllers/bitcoin/request/decode.rb create mode 100644 models/bitcoin/request.rb create mode 100644 spec/controllers/bitcoin/request/decode_spec.rb diff --git a/Gemfile.lock b/Gemfile.lock index 8472b10..ec50305 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -26,7 +26,7 @@ GEM grpc (~> 1.53) method_source (1.0.0) parallel (1.22.1) - parser (3.2.1.1) + parser (3.2.2.0) ast (~> 2.4.1) pry (0.14.2) coderay (~> 1.1) @@ -47,7 +47,7 @@ GEM rspec-expectations (3.12.2) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.12.0) - rspec-mocks (3.12.4) + rspec-mocks (3.12.5) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.12.0) rspec-support (3.12.0) diff --git a/adapters/bitcoin/request.rb b/adapters/bitcoin/request.rb new file mode 100644 index 0000000..1214965 --- /dev/null +++ b/adapters/bitcoin/request.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'digest' + +module Lighstorm + module Adapter + module Bitcoin + class Request + def self.decode(uri) + result = { + _source: :decode, + _key: Digest::SHA256.hexdigest([uri[:host]].concat(uri[:params].values).join('/')), + address: { code: uri[:host] } + } + + if uri[:params]['amount'] + result[:amount] = { + millisatoshis: uri[:params]['amount'].to_f * 100_000_000_000.0 + } + end + + result[:description] = uri[:params]['label'] if uri[:params]['label'] && uri[:params]['label'] != '' + + result[:message] = uri[:params]['message'] if uri[:params]['message'] && uri[:params]['message'] != '' + + result + end + end + end + end +end diff --git a/controllers/bitcoin/request.rb b/controllers/bitcoin/request.rb new file mode 100644 index 0000000..17ccb9c --- /dev/null +++ b/controllers/bitcoin/request.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require_relative '../concerns/impersonatable' +require_relative './request/decode' + +module Lighstorm + module Controller + module Bitcoin + module Request + extend Impersonatable + + class DSL < Impersonatable::DSL + def create + raise 'TODO' + # Create.perform(components, preview: preview, &vcr) + end + + def decode(uri) + Decode.model(Decode.data(uri: uri)) + end + end + end + end + end +end diff --git a/controllers/bitcoin/request/decode.rb b/controllers/bitcoin/request/decode.rb new file mode 100644 index 0000000..a919262 --- /dev/null +++ b/controllers/bitcoin/request/decode.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'uri' + +require_relative '../../../adapters/bitcoin/request' +require_relative '../../../models/bitcoin/request' + +module Lighstorm + module Controller + module Bitcoin + module Request + module Decode + def self.parse(uri) + # BIP21: https://bips.xyz/21 + parsed = if uri =~ /^\w+:/ + URI.parse(uri.sub('bitcoin:', 'bitcoin://')) + else + URI.parse("unknown://#{uri}") + end + + uri_hash = { + scheme: parsed.scheme, + host: parsed.host, + port: parsed.port, + path: parsed.path, + query: parsed.query, + fragment: parsed.fragment + } + + params = parsed.query ? URI.decode_www_form(parsed.query).to_h : {} + + { + raw: uri, + parsed: uri_hash.merge({ params: params }) + } + end + + def self.adapt(raw) + Lighstorm::Adapter::Bitcoin::Request.decode(raw[:parsed]) + end + + def self.data(uri:) + raw = parse(uri) + + adapt(raw) + end + + def self.model(data, components) + Lighstorm::Model::Bitcoin::Request.new(data, components) + end + end + end + end + end +end diff --git a/controllers/bitcoin/transaction.rb b/controllers/bitcoin/transaction.rb index da041c2..ca17c02 100644 --- a/controllers/bitcoin/transaction.rb +++ b/controllers/bitcoin/transaction.rb @@ -11,8 +11,8 @@ module Transaction extend Impersonatable class DSL < Impersonatable::DSL - def all(limit: nil) - All.model(All.data(components, limit: limit)) + def all(direction: nil, limit: nil) + All.model(All.data(components, direction: direction, limit: limit)) end def find_by_hash(hash, &vcr) diff --git a/controllers/bitcoin/transaction/all.rb b/controllers/bitcoin/transaction/all.rb index f899546..0085440 100644 --- a/controllers/bitcoin/transaction/all.rb +++ b/controllers/bitcoin/transaction/all.rb @@ -9,7 +9,7 @@ module Controller module Bitcoin module Transaction module All - def self.fetch(components, hash: nil, limit: nil) + def self.fetch(components, direction: nil, hash: nil, limit: nil) at = Time.now transactions = [] @@ -17,7 +17,12 @@ def self.fetch(components, hash: nil, limit: nil) response = components[:grpc].lightning.get_transactions response.transactions.each do |transaction| - next unless hash.nil? || transaction.to_h[:tx_hash] == hash + next unless hash.nil? || transaction.tx_hash == hash + + next unless + direction.nil? || + (direction == 'in' && transaction.amount.positive?) || + (direction == 'out' && transaction.amount.negative?) transactions << transaction.to_h end @@ -41,11 +46,11 @@ def self.transform(adapted) adapted[:get_transactions] end - def self.data(components, hash: nil, limit: nil, &vcr) + def self.data(components, hash: nil, direction: nil, limit: nil, &vcr) raw = if vcr.nil? - fetch(components, hash: hash, limit: limit) + fetch(components, hash: hash, direction: direction, limit: limit) else - vcr.call(-> { fetch(components, hash: hash, limit: limit) }) + vcr.call(-> { fetch(components, hash: hash, direction: direction, limit: limit) }) end adapted = adapt(raw) diff --git a/docs/README.md b/docs/README.md index cd3d1b3..cecfcaa 100644 --- a/docs/README.md +++ b/docs/README.md @@ -419,6 +419,24 @@ balance.to_h ## Bitcoin +### Request + +#### Decode + +Learn about [BIP 21](https://bips.xyz/21). + +```ruby +Lighstorm::Bitcoin::Request.decode( + 'bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=50&label=Luke-Jr&message=Donation%20for%20project%20xyz' +) +``` + +#### Create + +```ruby +# TODO +``` + ### Address #### Create diff --git a/models/bitcoin/request.rb b/models/bitcoin/request.rb new file mode 100644 index 0000000..0a242f3 --- /dev/null +++ b/models/bitcoin/request.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +require 'uri' + +require_relative '../satoshis' +require_relative './address' + +module Lighstorm + module Model + module Bitcoin + class Request + attr_reader :_key, :description, :message + + def initialize(data, components) + @data = data + @components = components + + @_key = @data[:_key] + @description = @data[:description] + @message = @data[:message] + end + + def address + @address ||= Address.new(@data[:address], @components) + end + + def amount + @amount ||= @data[:amount] ? Satoshis.new(millisatoshis: @data[:amount][:millisatoshis]) : nil + end + + def uri + return @uri unless @uri.nil? + + @uri = "bitcoin:#{address.code}" + + params = {} + + params[:amount] = amount.bitcoins if amount + params[:label] = description if description + params[:message] = message if message + + @uri = "#{@uri}?#{URI.encode_www_form(params)}" if params.keys.size.positive? + + @uri + end + + def pay( + fee:, required_confirmations: 6, + amount: nil, description: nil, + preview: false, &vcr + ) + address.pay( + amount: amount || self.amount.to_h, + fee: fee, + description: description || self.description, + required_confirmations: required_confirmations, + preview: false, &vcr + ) + end + + def to_h + output = { + _key: _key, + address: address.to_h, + uri: uri + } + + output[:amount] = amount.to_h if amount + output[:description] = description if description + output[:message] = message if message + + output + end + end + end + end +end diff --git a/models/satoshis.rb b/models/satoshis.rb index 40c49cf..b7077b0 100644 --- a/models/satoshis.rb +++ b/models/satoshis.rb @@ -20,7 +20,7 @@ def initialize(millisatoshis: nil, bitcoins: nil) end def parts_per_million(reference_millisatoshis) - ( + integer_if_possible( ( if reference_millisatoshis.zero? 0 @@ -32,15 +32,15 @@ def parts_per_million(reference_millisatoshis) end def millisatoshis - @amount_in_millisatoshis + integer_if_possible(@amount_in_millisatoshis) end def satoshis - @amount_in_millisatoshis.to_f / 1000.0 + integer_if_possible(@amount_in_millisatoshis.to_f / 1000.0) end def bitcoins - @amount_in_millisatoshis.to_f / 100_000_000_000 + integer_if_possible(@amount_in_millisatoshis.to_f / 100_000_000_000.0) end def sats @@ -60,6 +60,14 @@ def to_h millisatoshis: millisatoshis } end + + private + + def integer_if_possible(value) + return value.to_i if value.to_i == value + + value + end end end end diff --git a/ports/dsl/lighstorm.rb b/ports/dsl/lighstorm.rb index 5964673..880025d 100644 --- a/ports/dsl/lighstorm.rb +++ b/ports/dsl/lighstorm.rb @@ -18,6 +18,7 @@ require_relative '../../controllers/lightning/invoice' require_relative '../../controllers/bitcoin/transaction' +require_relative '../../controllers/bitcoin/request' require_relative '../../controllers/bitcoin/address' module Lighstorm @@ -37,6 +38,7 @@ module Lightning module Bitcoin Address = Controller::Bitcoin::Address + Request = Controller::Bitcoin::Request Transaction = Controller::Bitcoin::Transaction end diff --git a/spec/controllers/bitcoin/request/decode_spec.rb b/spec/controllers/bitcoin/request/decode_spec.rb new file mode 100644 index 0000000..e3318cc --- /dev/null +++ b/spec/controllers/bitcoin/request/decode_spec.rb @@ -0,0 +1,152 @@ +# frozen_string_literal: true + +require 'json' + +require_relative '../../../../controllers/bitcoin/request/decode' +require_relative '../../../../controllers/bitcoin/request' + +RSpec.describe Lighstorm::Controller::Bitcoin::Request::Decode do + context 'complete' do + let(:uri) do + 'bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=50&label=Luke-Jr&message=Donation%20for%20project%20xyz' + end + + it 'models' do + data = described_class.data(uri: uri) + + expect(data).to eq( + { _source: :decode, + _key: 'cfe53fceea2fb1ce8a0d40584e1e595bbc2182e445fd726df0ac80d288bb2952', + address: { code: '175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W' }, + amount: { millisatoshis: 5_000_000_000_000 }, + description: 'Luke-Jr', + message: 'Donation for project xyz' } + ) + + model = described_class.model(data, Lighstorm::Controller::Bitcoin::Request.components) + + expect(model.address.code).to eq('175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W') + expect(model.amount.bitcoins).to eq(50) + expect(model.description).to eq('Luke-Jr') + expect(model.message).to eq('Donation for project xyz') + expect(model.uri).to eq('bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=50&label=Luke-Jr&message=Donation+for+project+xyz') + + expect(model.to_h).to eq( + { + _key: 'cfe53fceea2fb1ce8a0d40584e1e595bbc2182e445fd726df0ac80d288bb2952', + address: { code: '175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W' }, + amount: { millisatoshis: 5_000_000_000_000 }, + description: 'Luke-Jr', + message: 'Donation for project xyz', + uri: 'bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=50&label=Luke-Jr&message=Donation+for+project+xyz' + } + ) + end + end + + context 'address' do + let(:uri) do + 'bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W' + end + + it 'models' do + data = described_class.data(uri: uri) + + expect(data).to eq( + { + _source: :decode, + _key: '416b10c7da18c34ae1444db9363e382e0db29b8323be07c34f312506425b834c', + address: { code: '175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W' } + } + ) + + model = described_class.model(data, Lighstorm::Controller::Bitcoin::Request.components) + + expect(model.address.code).to eq('175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W') + expect(model.amount).to be_nil + expect(model.description).to be_nil + expect(model.message).to be_nil + expect(model.uri).to eq('bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W') + + expect(model.to_h).to eq( + { + _key: '416b10c7da18c34ae1444db9363e382e0db29b8323be07c34f312506425b834c', + address: { code: '175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W' }, + uri: 'bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W' + } + ) + end + end + + context 'no scheme' do + let(:uri) do + '175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W' + end + + it 'models' do + data = described_class.data(uri: uri) + + expect(data).to eq( + { + _source: :decode, + _key: '416b10c7da18c34ae1444db9363e382e0db29b8323be07c34f312506425b834c', + address: { code: '175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W' } + } + ) + + model = described_class.model(data, Lighstorm::Controller::Bitcoin::Request.components) + + expect(model.address.code).to eq('175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W') + expect(model.amount).to be_nil + expect(model.description).to be_nil + expect(model.message).to be_nil + expect(model.uri).to eq('bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W') + + expect(model.to_h).to eq( + { + _key: '416b10c7da18c34ae1444db9363e382e0db29b8323be07c34f312506425b834c', + address: { code: '175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W' }, + uri: 'bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W' + } + ) + end + end + + context 'complete without scheme' do + let(:uri) do + '175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=50&label=Luke-Jr&message=Donation+for+project+xyz' + end + + it 'models' do + data = described_class.data(uri: uri) + + expect(data).to eq( + { _source: :decode, + _key: 'cfe53fceea2fb1ce8a0d40584e1e595bbc2182e445fd726df0ac80d288bb2952', + address: { code: '175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W' }, + amount: { millisatoshis: 5_000_000_000_000 }, + description: 'Luke-Jr', + message: 'Donation for project xyz' } + ) + + model = described_class.model(data, Lighstorm::Controller::Bitcoin::Request.components) + + expect(model.address.code).to eq('175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W') + expect(model.amount.bitcoins).to eq(50) + expect(model.description).to eq('Luke-Jr') + expect(model.message).to eq('Donation for project xyz') + expect(model.uri).to eq('bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=50&label=Luke-Jr&message=Donation+for+project+xyz') + + expect(model.to_h).to eq( + { + _key: 'cfe53fceea2fb1ce8a0d40584e1e595bbc2182e445fd726df0ac80d288bb2952', + address: { code: '175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W' }, + amount: { millisatoshis: 5_000_000_000_000 }, + description: 'Luke-Jr', + message: 'Donation for project xyz', + uri: 'bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=50&label=Luke-Jr&message=Donation+for+project+xyz' + } + ) + end + end +end diff --git a/spec/controllers/lightning/invoice/actions/pay_spec.rb b/spec/controllers/lightning/invoice/actions/pay_spec.rb index 732992c..b20b512 100644 --- a/spec/controllers/lightning/invoice/actions/pay_spec.rb +++ b/spec/controllers/lightning/invoice/actions/pay_spec.rb @@ -196,7 +196,7 @@ expect(action.result.hops.last.amount.millisatoshis).to eq(params[:amount][:millisatoshis]) Contract.expect( - action.to_h, '176e70048ea1618e0412201e4e6c494326f5a8a1de41c73a081082ef390b35e5' + action.to_h, '0e86079201a777a5b22557498ee6103b5ddf62241e7b73546d7e84aa9a925158' ) do |actual, expected| expect(actual.hash).to eq(expected.hash) expect(actual.contract).to eq(expected.contract) @@ -278,7 +278,7 @@ expect(action.result.hops.last.amount.millisatoshis).to eq(params[:amount][:millisatoshis]) Contract.expect( - action.to_h, '32223ce26ec6f43a68f78b2c20a7427f9fb269f6714db1c5f79e8f8ac0f63f02' + action.to_h, '2179a0240df1c3c5cdb20c84bf2991e469274670fbb4d87c013c2e2fbc0b9025' ) do |actual, expected| expect(actual.hash).to eq(expected.hash) expect(actual.contract).to eq(expected.contract) diff --git a/spec/controllers/lightning/node/actions/pay_spec.rb b/spec/controllers/lightning/node/actions/pay_spec.rb index a8a02d3..06dc5e3 100644 --- a/spec/controllers/lightning/node/actions/pay_spec.rb +++ b/spec/controllers/lightning/node/actions/pay_spec.rb @@ -96,7 +96,7 @@ expect(model.hops.last.amount.millisatoshis).to eq(params[:amount][:millisatoshis]) Contract.expect( - model.to_h, 'f3f98ff41f35d3047890a8bedcb3b6eb4e0621b0939fc00d9fe19d48d7a8e972' + model.to_h, '3115f113268ef62f4d2af45d9b8e389689e39881c5e508d955a8c3db3e3b2907' ) do |actual, expected| expect(actual.hash).to eq(expected.hash) expect(actual.contract).to eq(expected.contract) @@ -169,7 +169,7 @@ expect(action.result.hops.last.amount.millisatoshis).to eq(params[:amount][:millisatoshis]) Contract.expect( - action.to_h, 'ac91973911ee5018ed03a5a0d90dd15dd508ca33e4612aac7914843d898473c8' + action.to_h, 'e4388f26923e46ee472caf18b08e114de935e210fa0d59e526120a3f3ca5e257' ) do |actual, expected| expect(actual.hash).to eq(expected.hash) expect(actual.contract).to eq(expected.contract) @@ -261,7 +261,7 @@ expect(model.hops.last.amount.millisatoshis).to eq(params[:amount][:millisatoshis]) Contract.expect( - model.to_h, 'f3f98ff41f35d3047890a8bedcb3b6eb4e0621b0939fc00d9fe19d48d7a8e972' + model.to_h, '3115f113268ef62f4d2af45d9b8e389689e39881c5e508d955a8c3db3e3b2907' ) do |actual, expected| expect(actual.hash).to eq(expected.hash) expect(actual.contract).to eq(expected.contract) @@ -333,7 +333,7 @@ expect(action.result.hops.last.amount.millisatoshis).to eq(params[:amount][:millisatoshis]) Contract.expect( - action.to_h, '7a9a77d3b26b7f24ad095387b868767b1fb731b44f897c4db999be8510dbad43' + action.to_h, '0b9f0d982bbf0b3c1b59b68ecb8395cbc47d267d838bade66a9a0246c10a3e85' ) do |actual, expected| expect(actual.hash).to eq(expected.hash) expect(actual.contract).to eq(expected.contract) @@ -481,7 +481,7 @@ expect(model.hops).to be_nil Contract.expect( - model.to_h, '77e2f72deb98fda98eebef3f8984410dd8bfbd896058cbc93918bcf606f24355' + model.to_h, '887fa14bbe9ff66d841f1fdb7fbbe23d7fcb5ea76a06741e5108cf197f01544a' ) do |actual, expected| expect(actual.hash).to eq(expected.hash) expect(actual.contract).to eq(expected.contract) @@ -553,7 +553,7 @@ expect(e.response.last[:failure_reason]).to eq(:FAILURE_REASON_NO_ROUTE) Contract.expect( - e.to_h, 'dcae6cfd1d85026057db959d2b9baf62d265bb463271f2aafbd7bed07358f960' + e.to_h, 'd41a2a58a08274d90f61605c07135fc35b8cb2573899b9f4947939a665820557' ) do |actual, expected| expect(actual.hash).to eq(expected.hash) expect(actual.contract).to eq(expected.contract) diff --git a/spec/models/lightning/edges/payment_spec.rb b/spec/models/lightning/edges/payment_spec.rb index ee5f185..2f1fb16 100644 --- a/spec/models/lightning/edges/payment_spec.rb +++ b/spec/models/lightning/edges/payment_spec.rb @@ -69,7 +69,7 @@ Lighstorm::Model::Satoshis.new(millisatoshis: 1000) end - let(:to_h_contract) { 'bbe712677e9e72c5eb65865cda29b7e92ae3b9a196b5a946badaf45d4a9d306e' } + let(:to_h_contract) { '36a6dee173c4783a3ac04c0d69e60cffb34e0fe33846d8bdb7c7967888e46fb2' } it 'models' do expect(data[:meta][:calls][:decode_pay_req]).to be_nil @@ -184,7 +184,7 @@ Lighstorm::Model::Satoshis.new(millisatoshis: 1000) end - let(:to_h_contract) { 'abd510a173e1dc4de2547d48adab3b892a636802489e2fc99f239fe62d353760' } + let(:to_h_contract) { '0de14ab266b071700de90c0aa8a2f027873b30d7d997f45343a76e5d91b5f68f' } it 'models' do expect(data[:meta][:calls].keys.sort).to eq( @@ -301,7 +301,7 @@ Lighstorm::Model::Satoshis.new(millisatoshis: 150_000) end - let(:to_h_contract) { 'b965114e1ac50b653d74e39e8920235c95d79a2376a9e49837e78432e9587d21' } + let(:to_h_contract) { '5447edbf9384e7366a4c74283d324be2aa8ef390c44fcee365d17307bd0f43c1' } it 'models' do expect(payment._key.size).to eq(64) @@ -400,7 +400,7 @@ Lighstorm::Model::Satoshis.new(millisatoshis: 3_050_000_000) end - let(:to_h_contract) { '96769c5f7263f741463b7f0da83351219064a47f70180d6d4d2c9399c36ba88b' } + let(:to_h_contract) { '82049dafe05d8c5ddb3511538fc19af36d1f9ca4f4a91e8d99d41efd11eaac30' } it 'models' do expect(payment._key.size).to eq(64) @@ -497,7 +497,7 @@ Lighstorm::Model::Satoshis.new(millisatoshis: 137_000) end - let(:to_h_contract) { '99cbf5f017de4101e0612424d9378d9fa1d7628ae95a5644a97d4ea7cbb1bd0c' } + let(:to_h_contract) { '744a266bf986652626047c64f22d26e6902cb10ebb93978c3a9338643a73cf24' } it 'models' do expect(payment._key.size).to eq(64) @@ -598,7 +598,7 @@ Lighstorm::Model::Satoshis.new(millisatoshis: 130_000_000) end - let(:to_h_contract) { 'caf71adfc1bbe7a2f91a5a5935776aad3d921b8e2b7cb850cf98ce070d3db530' } + let(:to_h_contract) { 'a5560d0326bf693487f32bfa81e3388c76724330736e136186b78e69b56a6ff0' } it 'models' do expect(payment._key.size).to eq(64) @@ -699,7 +699,7 @@ Lighstorm::Model::Satoshis.new(millisatoshis: 1200) end - let(:to_h_contract) { 'ffb21922e00a6f37fa7ee599d38bb6f494a60efb40f4fc66a49a84e9b21d0b0d' } + let(:to_h_contract) { '39039307f9b86cb29aa45300709600111c5a985c6ce1fc8d0905a625e7b6f02c' } it 'models' do expect(payment._key.size).to eq(64) @@ -784,7 +784,7 @@ Lighstorm::Model::Satoshis.new(millisatoshis: 1500) end - let(:to_h_contract) { 'ffb21922e00a6f37fa7ee599d38bb6f494a60efb40f4fc66a49a84e9b21d0b0d' } + let(:to_h_contract) { '39039307f9b86cb29aa45300709600111c5a985c6ce1fc8d0905a625e7b6f02c' } it 'models' do expect(payment._key.size).to eq(64) @@ -869,7 +869,7 @@ Lighstorm::Model::Satoshis.new(millisatoshis: 1000) end - let(:to_h_contract) { 'e44bca0cb1d28df0865ee6eb880977367a4a5b18a55193f44cc5e86dcaacf154' } + let(:to_h_contract) { '5faff4c86ce94b6f06af506fa564da999640f9909ecfb4745a3a3bbbb1446f07' } it 'models' do expect(payment._key.size).to eq(64) @@ -983,7 +983,7 @@ Lighstorm::Model::Satoshis.new(millisatoshis: 1210) end - let(:to_h_contract) { 'bc43dd9fc7648e54185c27060219c2ee52adc14ec503469c0221513f826dfae3' } + let(:to_h_contract) { '4a98877e35774b817e887922ccfb86c5d6ac7ebb7b18749077922886741542be' } it 'models' do expect(payment._key.size).to eq(64) @@ -1096,7 +1096,7 @@ Lighstorm::Model::Satoshis.new(millisatoshis: 1121) end - let(:to_h_contract) { 'd54e69d7f72d4dbb8c5c617ff00bad9c9e42064b94e6e0a50a7a1174c9b19432' } + let(:to_h_contract) { 'bf98664158b4c62929000d2df2dc3d2140f1b629b372306498b0d13689fe4a6e' } it 'models' do expect(payment._key.size).to eq(64) @@ -1209,7 +1209,7 @@ Lighstorm::Model::Satoshis.new(millisatoshis: 1278) end - let(:to_h_contract) { '735c79f5d1120313407dd5f2b947c9afb44b6d5ccc5eb68e813a4d124d491d14' } + let(:to_h_contract) { '5360e82c935621238eedc10fea167472af32cc795bba828f23b74ae8c4156c89' } it 'models' do expect(payment._key.size).to eq(64) @@ -1322,7 +1322,7 @@ Lighstorm::Model::Satoshis.new(millisatoshis: 3_000_000) end - let(:to_h_contract) { 'bcdf5ab24266264839bed40e9ed45af9676a7b27d2ec95ad209efaacb1809b04' } + let(:to_h_contract) { 'fb3562b218ee7deee56bcd12b54e5cdf697f8bb8a68c6fc3b7de5c95c1f5fc1c' } it 'models' do expect(payment._key.size).to eq(64) @@ -1447,7 +1447,7 @@ Lighstorm::Model::Satoshis.new(millisatoshis: 49_000) end - let(:to_h_contract) { '8e72f213933366aa4099659d167f90890bce1448b1a04183e2cd8d7563dce7bc' } + let(:to_h_contract) { 'e5e5b0901e2a5c1e401aea998b2b75bfd9f6d794747dc07521005b771c00954a' } it 'models' do expect(payment._key.size).to eq(64) @@ -1563,7 +1563,7 @@ Lighstorm::Model::Satoshis.new(millisatoshis: 49_000) end - let(:to_h_contract) { '8e72f213933366aa4099659d167f90890bce1448b1a04183e2cd8d7563dce7bc' } + let(:to_h_contract) { 'e5e5b0901e2a5c1e401aea998b2b75bfd9f6d794747dc07521005b771c00954a' } it 'models' do expect(payment._key.size).to eq(64) diff --git a/spec/models/satoshis_spec.rb b/spec/models/satoshis_spec.rb index c4e4ce0..6d9e9eb 100644 --- a/spec/models/satoshis_spec.rb +++ b/spec/models/satoshis_spec.rb @@ -23,6 +23,26 @@ end end + describe 'satoshis int' do + it 'creates' do + amount = described_class.new( + millisatoshis: 50_000_000_000_0 + ) + + expect(amount.millisatoshis).to eq(500_000_000_000) + expect(amount.satoshis).to eq(500_000_000) + expect(amount.bitcoins).to eq(5) + + expect(amount.msats).to eq(500_000_000_000) + expect(amount.sats).to eq(500_000_000) + expect(amount.btc).to eq(5) + + expect(amount.parts_per_million(25_000_000_000_000)).to eq(20_000) + + expect(amount.to_h).to eq({ millisatoshis: 500_000_000_000 }) + end + end + describe 'bitcoins' do it 'creates 0.0045' do amount = described_class.new( diff --git a/spec/ports/dsl/lighstorm_spec.rb b/spec/ports/dsl/lighstorm_spec.rb index 5edc7e0..41ec226 100644 --- a/spec/ports/dsl/lighstorm_spec.rb +++ b/spec/ports/dsl/lighstorm_spec.rb @@ -11,6 +11,7 @@ expect(Lighstorm::Wallet).to respond_to(:balance) expect(Lighstorm::Wallet::Activity).to respond_to(:all) + expect(Lighstorm::Bitcoin::Request).to respond_to(:decode, :create) expect(Lighstorm::Bitcoin::Address).to respond_to(:new, :create) expect(Lighstorm::Bitcoin::Transaction).to respond_to(:all, :find_by_hash)