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