glueby 0.4.4 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,186 +1,186 @@
1
- # frozen_string_literal: true
2
-
3
- require 'securerandom'
4
- require 'bigdecimal'
5
-
6
- module Glueby
7
- module Internal
8
- class Wallet
9
- class TapyrusCoreWalletAdapter < AbstractWalletAdapter
10
- module Util
11
- module_function
12
-
13
- # Convert TPC to tapyrus. 1 TPC is 10**8 tapyrus.
14
- # @param [String] tpc
15
- # @return [Integer] tapyrus
16
- #
17
- # Example) "0.00000010" to 10.
18
- def tpc_to_tapyrus(tpc)
19
- (BigDecimal(tpc) * 10**8).to_i
20
- end
21
- end
22
-
23
- include Glueby::Internal::Wallet::TapyrusCoreWalletAdapter::Util
24
-
25
- WALLET_PREFIX = 'wallet-'
26
-
27
- RPC_WALLET_ERROR_ERROR_CODE = -4 # Unspecified problem with wallet (key not found etc.)
28
- RPC_WALLET_NOT_FOUND_ERROR_CODE = -18 # Invalid wallet specified
29
-
30
- def create_wallet(wallet_id = nil)
31
- wallet_id = SecureRandom.hex(16) unless wallet_id
32
- begin
33
- RPC.client.createwallet(wallet_name(wallet_id))
34
- rescue Tapyrus::RPC::Error => ex
35
- if ex.rpc_error && ex.rpc_error['code'] == RPC_WALLET_ERROR_ERROR_CODE && /Wallet wallet-#{wallet_id} already exists\./ =~ ex.rpc_error['message']
36
- raise Errors::WalletAlreadyCreated, "Wallet #{wallet_id} has been already created."
37
- else
38
- raise ex
39
- end
40
- end
41
-
42
- wallet_id
43
- end
44
-
45
- # On TapyrusCoreWallet, there are no way to delete real wallet via RPC.
46
- # So, here just unload.
47
- def delete_wallet(wallet_id)
48
- unload_wallet(wallet_id)
49
- end
50
-
51
- def load_wallet(wallet_id)
52
- RPC.client.loadwallet(wallet_name(wallet_id))
53
- rescue Tapyrus::RPC::Error => ex
54
- if ex.rpc_error && ex.rpc_error['code'] == RPC_WALLET_ERROR_ERROR_CODE && /Duplicate -wallet filename specified/ =~ ex.rpc_error['message']
55
- raise Errors::WalletAlreadyLoaded, "Wallet #{wallet_id} has been already loaded."
56
- elsif ex.rpc_error && ex.rpc_error['code'] == RPC_WALLET_NOT_FOUND_ERROR_CODE
57
- raise Errors::WalletNotFound, "Wallet #{wallet_id} does not found"
58
- else
59
- raise ex
60
- end
61
- end
62
-
63
- def unload_wallet(wallet_id)
64
- RPC.client.unloadwallet(wallet_name(wallet_id))
65
- end
66
-
67
- def wallets
68
- RPC.client.listwallets.map do |wallet_name|
69
- match = /\A#{WALLET_PREFIX}(?<wallet_id>[0-9A-Fa-f]{32})\z/.match(wallet_name)
70
- next unless match
71
-
72
- match[:wallet_id]
73
- end.compact
74
- end
75
-
76
- def balance(wallet_id, only_finalized = true)
77
- perform_as(wallet_id) do |client|
78
- confirmed = tpc_to_tapyrus(client.getbalance)
79
- return confirmed if only_finalized
80
-
81
- confirmed + tpc_to_tapyrus(client.getunconfirmedbalance)
82
- end
83
- end
84
-
85
- def list_unspent(wallet_id, only_finalized = true, label = nil)
86
- perform_as(wallet_id) do |client|
87
- min_conf = only_finalized ? 1 : 0
88
- res = client.listunspent(min_conf)
89
-
90
- res = res.filter { |i| i['label'] == label } if label && (label != :unlabeled)
91
- res = res.filter { |i| i['label'] == "" } if label == :unlabeled
92
-
93
- res.map do |i|
94
- script = Tapyrus::Script.parse_from_payload(i['scriptPubKey'].htb)
95
- color_id = if script.cp2pkh? || script.cp2sh?
96
- Tapyrus::Color::ColorIdentifier.parse_from_payload(script.chunks[0].pushed_data).to_hex
97
- end
98
- {
99
- txid: i['txid'],
100
- vout: i['vout'],
101
- script_pubkey: i['scriptPubKey'],
102
- color_id: color_id,
103
- amount: tpc_to_tapyrus(i['amount']),
104
- finalized: i['confirmations'] != 0
105
- }
106
- end
107
- end
108
- end
109
-
110
- def sign_tx(wallet_id, tx, prevtxs = [], sighashtype: Tapyrus::SIGHASH_TYPE[:all])
111
- perform_as(wallet_id) do |client|
112
- res = client.signrawtransactionwithwallet(tx.to_hex, prevtxs, encode_sighashtype(sighashtype))
113
- if res['complete']
114
- Tapyrus::Tx.parse_from_payload(res['hex'].htb)
115
- else
116
- raise res['errors'].to_json
117
- end
118
- end
119
- end
120
-
121
- def broadcast(wallet_id, tx, &block)
122
- perform_as(wallet_id) do |client|
123
- block.call(tx) if block
124
- client.sendrawtransaction(tx.to_hex)
125
- end
126
- end
127
-
128
- def receive_address(wallet_id, label = nil)
129
- perform_as(wallet_id) do |client|
130
- client.getnewaddress(label || '')
131
- end
132
- end
133
-
134
- def change_address(wallet_id)
135
- perform_as(wallet_id) do |client|
136
- client.getrawchangeaddress
137
- end
138
- end
139
-
140
- def create_pubkey(wallet_id)
141
- perform_as(wallet_id) do |client|
142
- address = client.getnewaddress('')
143
- info = client.getaddressinfo(address)
144
- Tapyrus::Key.new(pubkey: info['pubkey'])
145
- end
146
- end
147
-
148
- private
149
-
150
- def perform_as(wallet_id)
151
- RPC.perform_as(wallet_name(wallet_id)) do |client|
152
- begin
153
- yield(client)
154
- rescue Tapyrus::RPC::Error => ex
155
- if ex.rpc_error && ex.rpc_error['code'] == RPC_WALLET_NOT_FOUND_ERROR_CODE
156
- raise Errors::WalletUnloaded, "The wallet #{wallet_id} is unloaded. You should load before use it."
157
- else
158
- raise ex
159
- end
160
- end
161
- end
162
- end
163
-
164
- def wallet_name(wallet_id)
165
- "#{WALLET_PREFIX}#{wallet_id}"
166
- end
167
-
168
- def encode_sighashtype(sighashtype)
169
- type = case sighashtype & (~(Tapyrus::SIGHASH_TYPE[:anyonecanpay]))
170
- when Tapyrus::SIGHASH_TYPE[:all] then 'ALL'
171
- when Tapyrus::SIGHASH_TYPE[:none] then 'NONE'
172
- when Tapyrus::SIGHASH_TYPE[:single] then 'SIGNLE'
173
- else
174
- raise Errors::InvalidSighashType, "Invalid sighash type '#{sighashtype}'"
175
- end
176
-
177
- if sighashtype & Tapyrus::SIGHASH_TYPE[:anyonecanpay] == 0x80
178
- type += '|ANYONECANPAY'
179
- end
180
-
181
- type
182
- end
183
- end
184
- end
185
- end
186
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+ require 'bigdecimal'
5
+
6
+ module Glueby
7
+ module Internal
8
+ class Wallet
9
+ class TapyrusCoreWalletAdapter < AbstractWalletAdapter
10
+ module Util
11
+ module_function
12
+
13
+ # Convert TPC to tapyrus. 1 TPC is 10**8 tapyrus.
14
+ # @param [String] tpc
15
+ # @return [Integer] tapyrus
16
+ #
17
+ # Example) "0.00000010" to 10.
18
+ def tpc_to_tapyrus(tpc)
19
+ (BigDecimal(tpc) * 10**8).to_i
20
+ end
21
+ end
22
+
23
+ include Glueby::Internal::Wallet::TapyrusCoreWalletAdapter::Util
24
+
25
+ WALLET_PREFIX = 'wallet-'
26
+
27
+ RPC_WALLET_ERROR_ERROR_CODE = -4 # Unspecified problem with wallet (key not found etc.)
28
+ RPC_WALLET_NOT_FOUND_ERROR_CODE = -18 # Invalid wallet specified
29
+
30
+ def create_wallet(wallet_id = nil)
31
+ wallet_id = SecureRandom.hex(16) unless wallet_id
32
+ begin
33
+ RPC.client.createwallet(wallet_name(wallet_id))
34
+ rescue Tapyrus::RPC::Error => ex
35
+ if ex.rpc_error && ex.rpc_error['code'] == RPC_WALLET_ERROR_ERROR_CODE && /Wallet wallet-#{wallet_id} already exists\./ =~ ex.rpc_error['message']
36
+ raise Errors::WalletAlreadyCreated, "Wallet #{wallet_id} has been already created."
37
+ else
38
+ raise ex
39
+ end
40
+ end
41
+
42
+ wallet_id
43
+ end
44
+
45
+ # On TapyrusCoreWallet, there are no way to delete real wallet via RPC.
46
+ # So, here just unload.
47
+ def delete_wallet(wallet_id)
48
+ unload_wallet(wallet_id)
49
+ end
50
+
51
+ def load_wallet(wallet_id)
52
+ RPC.client.loadwallet(wallet_name(wallet_id))
53
+ rescue Tapyrus::RPC::Error => ex
54
+ if ex.rpc_error && ex.rpc_error['code'] == RPC_WALLET_ERROR_ERROR_CODE && /Duplicate -wallet filename specified/ =~ ex.rpc_error['message']
55
+ raise Errors::WalletAlreadyLoaded, "Wallet #{wallet_id} has been already loaded."
56
+ elsif ex.rpc_error && ex.rpc_error['code'] == RPC_WALLET_NOT_FOUND_ERROR_CODE
57
+ raise Errors::WalletNotFound, "Wallet #{wallet_id} does not found"
58
+ else
59
+ raise ex
60
+ end
61
+ end
62
+
63
+ def unload_wallet(wallet_id)
64
+ RPC.client.unloadwallet(wallet_name(wallet_id))
65
+ end
66
+
67
+ def wallets
68
+ RPC.client.listwallets.map do |wallet_name|
69
+ match = /\A#{WALLET_PREFIX}(?<wallet_id>[0-9A-Fa-f]{32})\z/.match(wallet_name)
70
+ next unless match
71
+
72
+ match[:wallet_id]
73
+ end.compact
74
+ end
75
+
76
+ def balance(wallet_id, only_finalized = true)
77
+ perform_as(wallet_id) do |client|
78
+ confirmed = tpc_to_tapyrus(client.getbalance)
79
+ return confirmed if only_finalized
80
+
81
+ confirmed + tpc_to_tapyrus(client.getunconfirmedbalance)
82
+ end
83
+ end
84
+
85
+ def list_unspent(wallet_id, only_finalized = true, label = nil)
86
+ perform_as(wallet_id) do |client|
87
+ min_conf = only_finalized ? 1 : 0
88
+ res = client.listunspent(min_conf)
89
+
90
+ res = res.filter { |i| i['label'] == label } if label && (label != :unlabeled)
91
+ res = res.filter { |i| i['label'] == "" } if label == :unlabeled
92
+
93
+ res.map do |i|
94
+ script = Tapyrus::Script.parse_from_payload(i['scriptPubKey'].htb)
95
+ color_id = if script.cp2pkh? || script.cp2sh?
96
+ Tapyrus::Color::ColorIdentifier.parse_from_payload(script.chunks[0].pushed_data).to_hex
97
+ end
98
+ {
99
+ txid: i['txid'],
100
+ vout: i['vout'],
101
+ script_pubkey: i['scriptPubKey'],
102
+ color_id: color_id,
103
+ amount: tpc_to_tapyrus(i['amount']),
104
+ finalized: i['confirmations'] != 0
105
+ }
106
+ end
107
+ end
108
+ end
109
+
110
+ def sign_tx(wallet_id, tx, prevtxs = [], sighashtype: Tapyrus::SIGHASH_TYPE[:all])
111
+ perform_as(wallet_id) do |client|
112
+ res = client.signrawtransactionwithwallet(tx.to_hex, prevtxs, encode_sighashtype(sighashtype))
113
+ if res['complete']
114
+ Tapyrus::Tx.parse_from_payload(res['hex'].htb)
115
+ else
116
+ raise res['errors'].to_json
117
+ end
118
+ end
119
+ end
120
+
121
+ def broadcast(wallet_id, tx, &block)
122
+ perform_as(wallet_id) do |client|
123
+ block.call(tx) if block
124
+ client.sendrawtransaction(tx.to_hex)
125
+ end
126
+ end
127
+
128
+ def receive_address(wallet_id, label = nil)
129
+ perform_as(wallet_id) do |client|
130
+ client.getnewaddress(label || '')
131
+ end
132
+ end
133
+
134
+ def change_address(wallet_id)
135
+ perform_as(wallet_id) do |client|
136
+ client.getrawchangeaddress
137
+ end
138
+ end
139
+
140
+ def create_pubkey(wallet_id)
141
+ perform_as(wallet_id) do |client|
142
+ address = client.getnewaddress('')
143
+ info = client.getaddressinfo(address)
144
+ Tapyrus::Key.new(pubkey: info['pubkey'])
145
+ end
146
+ end
147
+
148
+ private
149
+
150
+ def perform_as(wallet_id)
151
+ RPC.perform_as(wallet_name(wallet_id)) do |client|
152
+ begin
153
+ yield(client)
154
+ rescue Tapyrus::RPC::Error => ex
155
+ if ex.rpc_error && ex.rpc_error['code'] == RPC_WALLET_NOT_FOUND_ERROR_CODE
156
+ raise Errors::WalletUnloaded, "The wallet #{wallet_id} is unloaded. You should load before use it."
157
+ else
158
+ raise ex
159
+ end
160
+ end
161
+ end
162
+ end
163
+
164
+ def wallet_name(wallet_id)
165
+ "#{WALLET_PREFIX}#{wallet_id}"
166
+ end
167
+
168
+ def encode_sighashtype(sighashtype)
169
+ type = case sighashtype & (~(Tapyrus::SIGHASH_TYPE[:anyonecanpay]))
170
+ when Tapyrus::SIGHASH_TYPE[:all] then 'ALL'
171
+ when Tapyrus::SIGHASH_TYPE[:none] then 'NONE'
172
+ when Tapyrus::SIGHASH_TYPE[:single] then 'SIGNLE'
173
+ else
174
+ raise Errors::InvalidSighashType, "Invalid sighash type '#{sighashtype}'"
175
+ end
176
+
177
+ if sighashtype & Tapyrus::SIGHASH_TYPE[:anyonecanpay] == 0x80
178
+ type += '|ANYONECANPAY'
179
+ end
180
+
181
+ type
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end