M .rubocop.yml => .rubocop.yml +83 -63
@@ 1,113 1,133 @@
AllCops:
- TargetRubyVersion: 2.3
+ TargetRubyVersion: 2.5
+ NewCops: enable
-Metrics/LineLength:
- Max: 80
+Metrics/ClassLength:
+ Exclude:
+ - test/*
+
+Metrics/MethodLength:
+ Exclude:
+ - test/*
Metrics/BlockLength:
ExcludedMethods:
- route
- "on"
+ Exclude:
+ - test/*
+
+Metrics/AbcSize:
+ Exclude:
+ - test/*
+
+Naming/MethodParameterName:
+ AllowNamesEndingInNumbers: false
+ AllowedNames:
+ - m
+ - e
+ - r
+ - q
+ - s
+ - k
+ - v
+ - ex
+ - tx
+ - id
+ - iq
+ - ip
+ - db
+
+Layout/CaseIndentation:
+ EnforcedStyle: end
-Layout/Tab:
+Layout/IndentationStyle:
Enabled: false
+ EnforcedStyle: tabs
+ IndentationWidth: 4
Layout/IndentationWidth:
Width: 1 # one tab
-Lint/EndAlignment:
- EnforcedStyleAlignWith: variable
+Layout/LineLength:
+ Max: 80
+ Exclude:
+ - Gemfile
-Lint/RescueException:
- Enabled: false
+Layout/SpaceAroundEqualsInParameterDefault:
+ EnforcedStyle: no_space
-Style/AndOr:
- Enabled: false
+Layout/AccessModifierIndentation:
+ EnforcedStyle: outdent
-Layout/AlignParameters:
- Enabled: false
+Layout/FirstParameterIndentation:
+ EnforcedStyle: consistent
-Style/BlockDelimiters:
+Style/AccessModifierDeclarations:
Enabled: false
-Layout/CaseIndentation:
- EnforcedStyle: end
+Style/StringLiterals:
+ EnforcedStyle: double_quotes
-Style/Documentation:
+Style/NumericLiterals:
Enabled: false
-Style/FormatString:
- EnforcedStyle: percent
-
-Layout/LeadingCommentSpace:
- Enabled: false
+Style/SymbolArray:
+ EnforcedStyle: brackets
-Layout/MultilineMethodCallBraceLayout:
- Enabled: false
+Style/WordArray:
+ EnforcedStyle: brackets
-Layout/MultilineOperationIndentation:
+Style/Documentation:
Enabled: false
-Style/MultilineTernaryOperator:
+Style/DoubleNegation:
+ EnforcedStyle: allowed_in_returns
Enabled: false
-Style/Next:
+Style/PerlBackrefs:
Enabled: false
-Style/Not:
- Enabled: false
+Style/SpecialGlobalVars:
+ EnforcedStyle: use_perl_names
-Style/NumericLiterals:
- MinDigits: 20
- Strict: true
+Style/RegexpLiteral:
+ EnforcedStyle: slashes
+ AllowInnerSlashes: true
-Style/NumericPredicate:
- Enabled: false
+Lint/EndAlignment:
+ EnforcedStyleAlignWith: variable
-Layout/SpaceAroundOperators:
+Lint/OutOfRangeRegexpRef:
Enabled: false
-Layout/SpaceInsideHashLiteralBraces:
- EnforcedStyle: no_space
-
-Style/StringLiterals:
- EnforcedStyle: double_quotes
-
-Style/NegatedIf:
+Lint/MissingSuper:
Enabled: false
-Style/RedundantReturn:
- Enabled: false
+Style/BlockDelimiters:
+ EnforcedStyle: semantic
+ AllowBracesOnProceduralOneLiners: true
+ ProceduralMethods:
+ - execute_command
Style/MultilineBlockChain:
Enabled: false
-Layout/SpaceAroundEqualsInParameterDefault:
- EnforcedStyle: no_space
-
-Layout/IndentArray:
+Layout/FirstArgumentIndentation:
EnforcedStyle: consistent
-Style/SymbolArray:
- EnforcedStyle: brackets
-
-Layout/FirstParameterIndentation:
+Layout/FirstArrayElementIndentation:
EnforcedStyle: consistent
-Style/Lambda:
- EnforcedStyle: lambda
-
-Layout/AccessModifierIndentation:
- EnforcedStyle: outdent
+Style/FormatString:
+ EnforcedStyle: percent
Style/FormatStringToken:
- Enabled: false
+ EnforcedStyle: unannotated
-Style/WordArray:
- EnforcedStyle: brackets
-
-Lint/UriEscapeUnescape:
- Enabled: false
+Style/FrozenStringLiteralComment:
+ Exclude:
+ - forms/*
-Style/RescueModifier:
+Naming/AccessorMethodName:
Enabled: false
M bin/active_tels_on_catapult => bin/active_tels_on_catapult +1 -0
@@ 37,6 37,7 @@ DB.exec(
).each do |row|
cid = row["customer_id"]
next if REDIS.exists?("catapult_cred-customer_#{cid}@jmp.chat")
+
jid = REDIS.get("jmp_customer_jid-#{cid}")
tel = REDIS.lindex("catapult_cred-#{jid}", 3)
location = get_location(tel)
M bin/billing_monthly_cronjob => bin/billing_monthly_cronjob +21 -8
@@ 71,7 71,7 @@ end
stats = Stats.new(
not_renewed: 0,
renewed: 0,
- revenue: BigDecimal.new(0)
+ revenue: BigDecimal(0)
)
class Plan
@@ 85,7 85,7 @@ class Plan
end
def price
- BigDecimal.new(@plan["monthly_price"].to_i) * 0.0001
+ BigDecimal(@plan["monthly_price"].to_i) * 0.0001
end
def bill_customer(db, customer_id)
@@ 147,18 147,29 @@ class ExpiredCustomer
def try_renew(_, stats)
stats.add(:not_renewed, 1)
- if REDIS.exists?("jmp_customer_auto_top_up_amount-#{customer_id}") && \
- @row["expires_at"] > LAST_WEEK
- @db.exec_params("SELECT pg_notify('low_balance', $1)", [customer_id])
+ topup = "jmp_customer_auto_top_up_amount-#{customer_id}"
+ if REDIS.exists?(topup) && @row["expires_at"] > LAST_WEEK
+ @db.exec_params(
+ "SELECT pg_notify('low_balance', $1)",
+ [customer_id]
+ )
else
- return if REDIS.exists?("jmp_customer_low_balance-#{customer_id}")
- REDIS.set("jmp_customer_low_balance-#{customer_id}", Time.now, ex: ONE_WEEK)
- send_notification
+ notify_if_needed
end
end
protected
+ def notify_if_needed
+ return if REDIS.exists?("jmp_customer_low_balance-#{customer_id}")
+
+ REDIS.set(
+ "jmp_customer_low_balance-#{customer_id}",
+ Time.now, ex: ONE_WEEK
+ )
+ send_notification
+ end
+
def jid
REDIS.get("jmp_customer_jid-#{customer_id}")
end
@@ 175,12 186,14 @@ class ExpiredCustomer
def btc_addresses_for_notification
return if btc_addresses.empty?
+
"\nYou can buy credit by sending any amount of Bitcoin to one of "\
"these addresses:\n#{btc_addresses.join("\n")}"
end
def send_notification
raise "No JID for #{customer_id}, cannot notify" unless jid
+
BlatherNotify.say(
CONFIG[:notify_using][:target].call(jid),
CONFIG[:notify_using][:body].call(
M bin/correct_duplicate_addrs => bin/correct_duplicate_addrs +5 -5
@@ 12,14 12,14 @@ redis = Redis.new
customer_id = ENV["DEFAULT_CUSTOMER_ID"]
unless customer_id
- puts "The env-var DEFAULT_CUSTOMER_ID must be set to the ID of the customer "\
- "who will receive the duplicated addrs, preferably a support customer or "\
- "something linked to notifications when stray money is sent to these "\
- "addresses"
+ puts "The env-var DEFAULT_CUSTOMER_ID must be set to the ID " \
+ "of the customer who will receive the duplicated addrs, preferably " \
+ "a support customer or something linked to notifications when " \
+ "stray money is sent to these addresses"
exit 1
end
-STDIN.each_line do |line|
+$stdin.each_line do |line|
match = line.match(/^(\w+) is used by the following \d+ keys: (.*)/)
unless match
puts "The following line can't be understood and is being ignored"
M bin/detect_duplicate_addrs => bin/detect_duplicate_addrs +2 -1
@@ 8,6 8,7 @@ redis = Redis.new
get_addresses_with_users(redis).each do |addr, keys|
if keys.length > 1
- puts "#{addr} is used by the following #{keys.length} keys: #{keys.join(' ')}"
+ puts "#{addr} is used by the following " \
+ "#{keys.length} keys: #{keys.join(' ')}"
end
end
M bin/process_pending_btc_transactions => bin/process_pending_btc_transactions +18 -11
@@ 48,7 48,7 @@ unless (cad_to_usd = REDIS.get("cad_to_usd")&.to_f)
oxr.app_id = CONFIG.fetch(:oxr_app_id)
oxr.update_rates
cad_to_usd = oxr.get_rate("CAD", "USD")
- REDIS.set("cad_to_usd", cad_to_usd, ex: 60*60)
+ REDIS.set("cad_to_usd", cad_to_usd, ex: 60 * 60)
end
canadianbitcoins = Nokogiri::HTML.parse(
@@ 59,7 59,7 @@ bitcoin_row = canadianbitcoins.at("#ticker > table > tbody > tr")
raise "Bitcoin row has moved" unless bitcoin_row.at("td").text == "Bitcoin"
btc_sell_price = {}
-btc_sell_price[:CAD] = BigDecimal.new(
+btc_sell_price[:CAD] = BigDecimal(
bitcoin_row.at("td:nth-of-type(3)").text.match(/^\$(\d+\.\d+)/)[1]
)
btc_sell_price[:USD] = btc_sell_price[:CAD] * cad_to_usd
@@ 82,6 82,7 @@ class Plan
def self.from_name(customer, plan_name, klass: Plan)
return unless plan_name
+
plan = CONFIG[:plans].find { |p| p[:name] == plan_name }
klass.new(customer, plan) if plan
end
@@ 100,7 101,8 @@ class Plan
end
def bonus_for(fiat_amount)
- return BigDecimal.new(0) if fiat_amount <= 15
+ return BigDecimal(0) if fiat_amount <= 15
+
fiat_amount * case fiat_amount
when (15..29.99)
0.01
@@ 112,7 114,7 @@ class Plan
end
def price
- BigDecimal.new(@plan[:monthly_price].to_i) * 0.0001
+ BigDecimal(@plan[:monthly_price].to_i) * 0.0001
end
def insert(start:, expire:)
@@ 134,7 136,7 @@ class Plan
end
def activation_amount
- camnt = BigDecimal.new(CONFIG[:activation_amount].to_i) * 0.0001
+ camnt = BigDecimal(CONFIG[:activation_amount].to_i) * 0.0001
[camnt, price].max
end
@@ 159,6 161,7 @@ class Plan
-price,
"Activate pending plan"
)
+
insert(start: Date.today, expire: @go_until)
REDIS.del("pending_plan_for-#{@customer.id}")
notify_approved
@@ 186,6 189,7 @@ class Customer
def notify(body)
jid = REDIS.get("jmp_customer_jid-#{@customer_id}")
raise "No JID for #{customer_id}" unless jid
+
BlatherNotify.say(
CONFIG[:notify_using][:target].call(jid),
CONFIG[:notify_using][:body].call(jid, body)
@@ 204,12 208,13 @@ class Customer
result = DB.exec_params(<<-SQL, [@customer_id]).first&.[]("balance")
SELECT balance FROM balances WHERE customer_id=$1
SQL
- result || BigDecimal.new(0)
+ result || BigDecimal(0)
end
def add_btc_credit(txid, btc_amount, fiat_amount)
return unless add_transaction(txid, fiat_amount, "Bitcoin payment")
- if (bonus = plan.bonus_for(fiat_amount)) > 0
+
+ if (bonus = plan.bonus_for(fiat_amount)).positive?
add_transaction("bonus_for_#{txid}", bonus, "Bitcoin payment bonus")
end
notify_btc_credit(txid, btc_amount, fiat_amount, bonus)
@@ 220,13 225,14 @@ class Customer
notify([
"Your Bitcoin transaction of #{btc_amount.to_s('F')} BTC ",
"has been added as $#{'%.4f' % fiat_amount} (#{plan.currency}) ",
- ("+ $#{'%.4f' % bonus} bonus " if bonus > 0),
+ ("+ $#{'%.4f' % bonus} bonus " if bonus.positive?),
"to your account.\n(txhash: #{tx_hash})"
].compact.join)
end
def add_transaction(id, amount, note)
- DB.exec_params(<<-SQL, [@customer_id, id, amount, note]).cmd_tuples > 0
+ args = [@customer_id, id, amount, note]
+ DB.exec_params(<<-SQL, args).cmd_tuples.positive?
INSERT INTO transactions
(customer_id, transaction_id, amount, note)
VALUES
@@ 236,10 242,11 @@ class Customer
end
end
-done = REDIS.hgetall("pending_btc_transactions").map do |(txid, customer_id)|
+done = REDIS.hgetall("pending_btc_transactions").map { |(txid, customer_id)|
tx_hash, address = txid.split("/", 2)
transaction = ELECTRUM.gettransaction(tx_hash)
next unless transaction.confirmations >= CONFIG[:required_confirmations]
+
btc = transaction.amount_for(address)
if btc <= 0
# This is a send, not a receive, do not record it
@@ 258,6 265,6 @@ done = REDIS.hgetall("pending_btc_transactions").map do |(txid, customer_id)|
warn "No plan for #{customer_id} cannot save #{txid}"
end
end
-end
+}
puts done.compact.join("\n")
M config.ru => config.ru +40 -45
@@ 4,6 4,7 @@ require "braintree"
require "date"
require "delegate"
require "dhall"
+require "forwardable"
require "pg"
require "redis"
require "roda"
@@ 44,7 45,7 @@ class Plan
end
def price(months=1)
- (BigDecimal.new(@plan[:monthly_price].to_i) * months) / 10000
+ (BigDecimal(@plan[:monthly_price].to_i) * months) / 10000
end
def currency
@@ 56,7 57,7 @@ class Plan
end
def self.active?(customer_id)
- DB.exec_params(<<~SQL, [customer_id]).first&.[]("count").to_i > 0
+ DB.exec_params(<<~SQL, [customer_id]).first&.[]("count").to_i.positive?
SELECT count(1) AS count FROM customer_plans
WHERE customer_id=$1 AND expires_at > NOW()
SQL
@@ 139,6 140,7 @@ class CreditCardGateway
result = @gateway.customer.create
raise "Braintree customer create failed" unless result.success?
+
@customer_id = result.customer.id
save_customer_id!
end
@@ 183,6 185,7 @@ class CreditCardGateway
def sale(ip:, **kwargs)
return nil unless decline_guard(ip)
+
tx = Transaction.sale(@gateway, **kwargs)
return tx if tx
@@ 200,7 203,7 @@ class CreditCardGateway
amount: plan.price(5),
payment_method_nonce: nonce,
merchant_account_id: plan.merchant_account,
- options: {submit_for_settlement: true}
+ options: { submit_for_settlement: true }
)&.insert && plan.bill_plan(@customer_id)
end
@@ 219,15 222,18 @@ class UnknownTransactions
def self.from(customer_id, address, tx_hashes)
self.for(
customer_id,
- fetch_rows_for(address, tx_hashes).map { |row| row["transaction_id"] }
+ fetch_rows_for(address, tx_hashes).map { |row|
+ row["transaction_id"]
+ }
)
end
def self.fetch_rows_for(address, tx_hashes)
- values = tx_hashes.map do |tx_hash|
+ values = tx_hashes.map { |tx_hash|
"('#{DB.escape_string(tx_hash)}/#{DB.escape_string(address)}')"
- end
+ }
return [] if values.empty?
+
DB.exec_params(<<-SQL)
SELECT transaction_id FROM
(VALUES #{values.join(',')}) AS t(transaction_id)
@@ 257,24 263,25 @@ class UnknownTransactions
end
end
-# This class must contain all of the routes because of how the DSL works
-# rubocop:disable Metrics/ClassLength
class JmpPay < Roda
SENTRY_DSN = ENV["SENTRY_DSN"] && URI(ENV["SENTRY_DSN"])
plugin :render, engine: "slim"
plugin :common_logger, $stdout
+ extend Forwardable
+ def_delegators :request, :params
+
def redis_key_btc_addresses
- "jmp_customer_btc_addresses-#{request.params['customer_id']}"
+ "jmp_customer_btc_addresses-#{params['customer_id']}"
end
def verify_address_customer_id(r)
- return if REDIS.sismember(redis_key_btc_addresses, request.params["address"])
+ return if REDIS.sismember(redis_key_btc_addresses, params["address"])
warn "Address and customer_id do not match"
r.halt([
403,
- {"Content-Type" => "text/plain"},
+ { "Content-Type" => "text/plain" },
"Address and customer_id do not match"
])
end
@@ 284,10 291,10 @@ class JmpPay < Roda
verify_address_customer_id(r)
UnknownTransactions.from(
- request.params["customer_id"],
- request.params["address"],
+ params["customer_id"],
+ params["address"],
ELECTRUM
- .getaddresshistory(request.params["address"])
+ .getaddresshistory(params["address"])
.map { |item| item["tx_hash"] }
).enqueue!
@@ 295,19 302,17 @@ class JmpPay < Roda
end
r.on :jid do |jid|
- Sentry.set_user(id: request.params["customer_id"], jid: jid)
+ Sentry.set_user(id: params["customer_id"], jid: jid)
- gateway = CreditCardGateway.new(
- jid,
- request.params["customer_id"]
- )
+ gateway = CreditCardGateway.new(jid, params["customer_id"])
+ topup = "jmp_customer_auto_top_up_amount-#{gateway.customer_id}"
r.on "activate" do
Sentry.configure_scope do |scope|
scope.set_transaction_name("activate")
scope.set_context(
"activate",
- plan_name: request.params["plan_name"]
+ plan_name: params["plan_name"]
)
end
@@ 324,28 329,25 @@ class JmpPay < Roda
r.get do
if Plan.active?(gateway.customer_id)
- r.redirect request.params["return_to"], 303
+ r.redirect params["return_to"], 303
else
render.call
end
end
r.post do
- result = DB.transaction do
+ result = DB.transaction {
Plan.active?(gateway.customer_id) || gateway.buy_plan(
- request.params["plan_name"],
- request.params["braintree_nonce"],
+ params["plan_name"],
+ params["braintree_nonce"],
request.ip
)
- end
- if request.params["auto_top_up_amount"].to_i >= 15
- REDIS.set(
- "jmp_customer_auto_top_up_amount-#{gateway.customer_id}",
- request.params["auto_top_up_amount"].to_i
- )
+ }
+ if params["auto_top_up_amount"].to_i >= 15
+ REDIS.set(topup, params["auto_top_up_amount"].to_i)
end
if result
- r.redirect request.params["return_to"], 303
+ r.redirect params["return_to"], 303
else
render.call(error: true)
end
@@ 359,24 361,18 @@ class JmpPay < Roda
locals: {
token: gateway.client_token,
customer_id: gateway.customer_id,
- auto_top_up: REDIS.get(
- "jmp_customer_auto_top_up_amount-#{gateway.customer_id}"
- ) || (gateway.payment_methods? ? "" : "15")
+ auto_top_up: REDIS.get(topup) ||
+ (gateway.payment_methods? ? "" : "15")
}
)
end
r.post do
- gateway.default_payment_method = request.params["braintree_nonce"]
- if request.params["auto_top_up_amount"].to_i >= 15
- REDIS.set(
- "jmp_customer_auto_top_up_amount-#{gateway.customer_id}",
- request.params["auto_top_up_amount"].to_i
- )
- elsif request.params["auto_top_up_amount"].to_i == 0
- REDIS.del(
- "jmp_customer_auto_top_up_amount-#{gateway.customer_id}"
- )
+ gateway.default_payment_method = params["braintree_nonce"]
+ if params["auto_top_up_amount"].to_i >= 15
+ REDIS.set(topup, params["auto_top_up_amount"].to_i)
+ elsif params["auto_top_up_amount"].to_i.zero?
+ REDIS.del(topup)
end
"OK"
end
@@ 384,6 380,5 @@ class JmpPay < Roda
end
end
end
-# rubocop:enable Metrics/ClassLength
run JmpPay.freeze.app
M lib/blather_notify.rb => lib/blather_notify.rb +2 -2
@@ 16,11 16,11 @@ module BlatherNotify
EM.error_handler(&method(:panic))
- @thread = Thread.new do
+ @thread = Thread.new {
EM.run do
client.run
end
- end
+ }
Timeout.timeout(30) { @ready.pop }
at_exit { wait_then_exit }
M lib/electrum.rb => lib/electrum.rb +11 -4
@@ 47,7 47,7 @@ class Electrum
end
def amount_for(*addresses)
- BigDecimal.new(
+ BigDecimal(
@tx["outputs"]
.select { |o| addresses.include?(o["address"]) }
.map { |o| o["value_sats"] }
@@ 67,16 67,23 @@ protected
).body)
end
- def post_json(data)
- req = Net::HTTP::Post.new(@rpc_uri, "Content-Type" => "application/json")
+ def post_json_req(data)
+ req = Net::HTTP::Post.new(
+ @rpc_uri,
+ "Content-Type" => "application/json"
+ )
req.basic_auth(@rpc_username, @rpc_password)
req.body = data.to_json
+ req
+ end
+
+ def post_json(data)
Net::HTTP.start(
@rpc_uri.hostname,
@rpc_uri.port,
use_ssl: @rpc_uri.scheme == "https"
) do |http|
- http.request(req)
+ http.request(post_json_req(data))
end
end
end
M lib/redis_addresses.rb => lib/redis_addresses.rb +8 -5
@@ 25,12 25,15 @@ end
module RedisBtcAddresses
def self.each_user(redis)
- # I picked 1000 because it made a relatively trivial case take 15 seconds
- # instead of forever.
+ # I picked 1000 because it made a relatively trivial case take
+ # 15 seconds instead of forever.
# Basically it's "how long does each command take"
- # The lower it is (default is 10), it will go back and forth to the client a
- # ton
- redis.scan_each(match: "jmp_customer_btc_addresses-*", count: 1000) do |key|
+ # The lower it is (default is 10), it will go back and forth
+ # to the client a ton
+ redis.scan_each(
+ match: "jmp_customer_btc_addresses-*",
+ count: 1000
+ ) do |key|
yield key, redis.smembers(key)
end
end
M lib/transaction.rb => lib/transaction.rb +6 -1
@@ 29,6 29,7 @@ class Transaction
def bonus
return BigDecimal(0) if amount <= 15
+
amount *
case amount
when (15..29.99)
@@ 59,7 60,11 @@ protected
def insert_bonus
return if bonus <= 0
- params = [@customer_id, "bonus_for_#{@transaction_id}", @created_at, bonus]
+
+ params = [
+ @customer_id, "bonus_for_#{@transaction_id}",
+ @created_at, bonus
+ ]
DB.exec(<<~SQL, params)
INSERT INTO transactions
(customer_id, transaction_id, created_at, amount, note)
M test/test_electrum.rb => test/test_electrum.rb +9 -9
@@ 16,7 16,7 @@ class ElectrumTest < Minitest::Test
def stub_rpc(method, params)
stub_request(:post, RPC_URI).with(
- headers: {"Content-Type" => "application/json"},
+ headers: { "Content-Type" => "application/json" },
basic_auth: ["username", "password"],
body: hash_including(
method: method,
@@ 29,7 29,7 @@ class ElectrumTest < Minitest::Test
def getaddresshistory(address)
req =
stub_rpc("getaddresshistory", address: address)
- .to_return(body: {result: "result"}.to_json)
+ .to_return(body: { result: "result" }.to_json)
assert_equal "result", @electrum.getaddresshistory(address)
assert_requested(req)
end
@@ 38,7 38,7 @@ class ElectrumTest < Minitest::Test
def get_tx_status(tx_hash)
req =
stub_rpc("get_tx_status", txid: tx_hash)
- .to_return(body: {result: "result"}.to_json)
+ .to_return(body: { result: "result" }.to_json)
assert_equal "result", @electrum.get_tx_status(tx_hash)
assert_requested(req)
end
@@ 47,10 47,10 @@ class ElectrumTest < Minitest::Test
def gettransaction(tx_hash, dummy_tx)
req1 =
stub_rpc("gettransaction", txid: tx_hash)
- .to_return(body: {result: dummy_tx}.to_json)
+ .to_return(body: { result: dummy_tx }.to_json)
req2 =
stub_rpc("deserialize", [dummy_tx])
- .to_return(body: {result: {outputs: []}}.to_json)
+ .to_return(body: { result: { outputs: [] } }.to_json)
assert_kind_of Electrum::Transaction, @electrum.gettransaction(tx_hash)
assert_requested(req1)
assert_requested(req2)
@@ 73,7 73,7 @@ class ElectrumTest < Minitest::Test
electrum_mock, tx = transaction
electrum_mock.expect(
:get_tx_status,
- {"confirmations" => 1234},
+ { "confirmations" => 1234 },
["txhash"]
)
assert_equal 1234, tx.confirmations
@@ 85,17 85,17 @@ class ElectrumTest < Minitest::Test
end
def test_amount_for_address_not_present
- _, tx = transaction([{"address" => "address", "value_sats" => 1}])
+ _, tx = transaction([{ "address" => "address", "value_sats" => 1 }])
assert_equal 0, tx.amount_for("other_address")
end
def test_amount_for_address_present
- _, tx = transaction([{"address" => "address", "value_sats" => 1}])
+ _, tx = transaction([{ "address" => "address", "value_sats" => 1 }])
assert_equal 0.00000001, tx.amount_for("address")
end
def test_amount_for_one_of_address_present
- _, tx = transaction([{"address" => "address", "value_sats" => 1}])
+ _, tx = transaction([{ "address" => "address", "value_sats" => 1 }])
assert_equal 0.00000001, tx.amount_for("boop", "address", "lol")
end
end