electrum.rb

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