1# frozen_string_literal: true
2
3require "bigdecimal"
4require "em-http"
5require "em_promise"
6require "em-synchrony/em-http" # For apost vs post
7require "json"
8require "securerandom"
9
10class Electrum
11 def initialize(rpc_uri:, rpc_username:, rpc_password:, currency:)
12 @rpc_uri = URI(rpc_uri)
13 @rpc_username = rpc_username
14 @rpc_password = rpc_password
15 @currency = currency
16 end
17
18 def createnewaddress
19 rpc_call(:createnewaddress, {}).then { |r| r["result"] }
20 end
21
22 def getaddresshistory(address)
23 rpc_call(:getaddresshistory, address: address).then { |r| r["result"] }
24 end
25
26 def gettransaction(tx_hash)
27 rpc_call(:gettransaction, txid: tx_hash).then { |tx|
28 rpc_call(:deserialize, [tx["result"]])
29 }.then do |tx|
30 Transaction.new(self, tx_hash, tx["result"])
31 end
32 end
33
34 def get_tx_status(tx_hash)
35 rpc_call(:get_tx_status, txid: tx_hash).then { |r| r["result"] }
36 end
37
38 def notify(address, url)
39 rpc_call(:notify, address: address, URL: url).then { |r| r["result"] }
40 end
41
42 class Transaction
43 def initialize(electrum, tx_hash, tx)
44 @electrum = electrum
45 @tx_hash = tx_hash
46 @tx = tx
47 end
48
49 def confirmations
50 @electrum.get_tx_status(@tx_hash).then { |r| r["confirmations"] }
51 end
52
53 def amount_for(*addresses)
54 BigDecimal(
55 @tx["outputs"]
56 .select { |o| addresses.include?(o["address"]) }
57 .map { |o| o["value_sats"] }
58 .sum
59 ) * 0.00000001
60 end
61 end
62
63protected
64
65 def rpc_call(method, params)
66 post_json(
67 jsonrpc: "2.0",
68 id: SecureRandom.hex,
69 method: method.to_s,
70 params: params
71 ).then { |res| JSON.parse(res.response) }
72 end
73
74 def post_json(data)
75 EM::HttpRequest.new(
76 @rpc_uri,
77 tls: { verify_peer: true }
78 ).apost(
79 head: {
80 "Authorization" => [@rpc_username, @rpc_password],
81 "Content-Type" => "application/json"
82 },
83 body: data.to_json
84 )
85 end
86end