block_io 1.0.6 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d0ac0a444bdd6e778287026a7d9e89ef91b25ddd
4
- data.tar.gz: 7e9bb72332639245c289c04f474be22ea512eba9
3
+ metadata.gz: f9dc992c3a7aa1fc125e1eaf8b16d531318e31fd
4
+ data.tar.gz: fdf9ae723127d8688e55cdc0c1ffc9f0eb263bda
5
5
  SHA512:
6
- metadata.gz: d06356ff689a5e4a8f30787d1683c2277b4237120daad993e4dac9b564c975d284427c8a147fe61194c1cef06cfb663cfff91bc26c0f86a8a42f3ee3aa58fa86
7
- data.tar.gz: 36554afd1641aed6eee40442178a16d337a6174a263f559eefdaf7e63915edbe56a726d738bb8feaa4c69851b984e6b4106149070a13de1a81995de7be175118
6
+ metadata.gz: 2ed068c30ce271df8745e66288f050b97f5f3ec3f68f3087c88ed3b7068059e29503edc1043521bb55d56f80dfbb57491ce709033e36ef021e850775ee94501f
7
+ data.tar.gz: e9c4c14b3c2bbd292a20f8a018bd9089b20d5742115b0ebc9d6c2a707e4fac3583e1dc620fb4a580c5ab284b45a4ce3bc911dbd42ba6853930e93524d0e5e412
@@ -21,8 +21,9 @@ Gem::Specification.new do |spec|
21
21
  spec.add_development_dependency "bundler", "~> 1.6"
22
22
  spec.add_development_dependency "rake", "~> 0"
23
23
  spec.add_runtime_dependency "ecdsa", "~> 1.2", '>= 1.2.0'
24
- spec.add_runtime_dependency "httpclient", "~> 2.4", '>= 2.4.0'
25
- spec.add_runtime_dependency "json", "~> 1.8", '>= 1.8.1'
26
- spec.add_runtime_dependency "connection_pool", "~> 2.0", '>= 2.0.0'
24
+ spec.add_runtime_dependency "httpclient", "~> 2.8", '>= 2.8.0'
25
+ spec.add_runtime_dependency "oj", "~> 3.3", '>= 3.3.5'
26
+ spec.add_runtime_dependency "oj_mimic_json"
27
+ spec.add_runtime_dependency "connection_pool", "~> 2.2", '>= 2.2.1'
27
28
  spec.add_runtime_dependency "pbkdf2-ruby", '~> 0.2', '>= 0.2.1'
28
29
  end
@@ -0,0 +1,117 @@
1
+ # 1. create an address (first_address), move all coins to it
2
+ # 2. create an address (second_address), as the change address for the first_address
3
+ # 3. send destination_amount to destination_address from first_address, and the rest of the coins to second_address
4
+ # 4. archive first_address since it will no longer be used
5
+
6
+ # execute with:
7
+ # $ DESTINATION_ADDRESS=AN_ADDRESS DESTINATION_AMOUNT=COINS_TO_SEND_TO_DESTINATION_ADDRESS API_KEY=TESTNET_API_KEY PIN=YOUR_SECRET_PIN ruby change.rb
8
+
9
+ require 'block_io'
10
+ require 'securerandom'
11
+ require 'bigdecimal'
12
+
13
+ # please use the Dogecoin/Bitcoin Testnet API key here
14
+ BlockIo.set_options :api_key => ENV['API_KEY'], :pin => ENV['PIN'], :version => 2
15
+
16
+ # create address A, and withdraw all coins to address A
17
+ first_address_label = SecureRandom.hex(8) # the source address
18
+ second_address_label = SecureRandom.hex(8) # the change address
19
+
20
+ # let's fill up the first address with whatever coins exist in this account
21
+ puts BlockIo.get_new_address(:label => first_address_label)
22
+
23
+ available_balance = BigDecimal(BlockIo.get_balance()['data']['available_balance'])
24
+ network_fee = BigDecimal('0.0')
25
+
26
+ puts "Available Balance: #{available_balance.truncate(8).to_s('F')}"
27
+
28
+ options = {:to_labels => first_address_label, :amounts => available_balance.to_s("F")}
29
+
30
+ tries = 2 # retry twice at most
31
+
32
+ begin
33
+ options[:amounts] = (available_balance - network_fee).truncate(8).to_s("F")
34
+
35
+ response = BlockIo.get_network_fee_estimate(options)
36
+ network_fee = BigDecimal(response['data']['estimated_network_fee'])
37
+
38
+ puts "Final Network Fee: #{network_fee.truncate(8).to_s('F')}"
39
+
40
+ options[:amounts] = (available_balance - network_fee).truncate(8).to_s("F")
41
+ rescue Exception => e
42
+ # extract the fee and subtract it from the available amount
43
+
44
+ network_fee = BigDecimal(e.to_s.split(' ')[7])
45
+ puts "Estimated Network Fee: #{e.to_s.split(' ')[7]}"
46
+
47
+ retry unless (tries -= 1).zero?
48
+
49
+ raise Exception.new("UNABLE TO ESTIMATE NETWORK FEE")
50
+ end
51
+
52
+ # make the withdrawal
53
+ puts BlockIo.withdraw(options)
54
+
55
+ # all balance has been transferred to first_address_label
56
+
57
+ # create the change address
58
+ puts BlockIo.get_new_address(:label => second_address_label)
59
+
60
+ destination_address = ENV['DESTINATION_ADDRESS']
61
+ destination_amount = BigDecimal(ENV['DESTINATION_AMOUNT'])
62
+
63
+ puts "Sending #{destination_amount} to #{destination_address}"
64
+
65
+ available_balance = BigDecimal(BlockIo.get_balance(:labels => first_address_label)['data']['available_balance'])
66
+
67
+ second_address = BlockIo.get_address_by_label(:label => second_address_label)['data']['address']
68
+
69
+ options = {}
70
+
71
+ tries = 2 # two tries to estimate the correct network fee
72
+
73
+ network_fee = BigDecimal('0.0')
74
+
75
+ to_addresses = []
76
+ amounts = []
77
+
78
+ # estimate the fee for this withdrawal
79
+ begin
80
+
81
+ change_amount = available_balance - destination_amount
82
+
83
+ if change_amount - network_fee > 0 then
84
+ to_addresses = [destination_address, second_address]
85
+ amounts = [destination_amount.truncate(8).to_s("F"), (change_amount - network_fee).truncate(8).to_s("F")]
86
+ else
87
+ to_addresses = [destination_address]
88
+ amounts = [destination_amount.truncate(8).to_s("F")]
89
+ end
90
+
91
+ response = BlockIo.get_network_fee_estimate(:from_labels => first_address_label, :to_addresses => to_addresses.join(','), :amounts => amounts.join(','))
92
+ network_fee = BigDecimal(response['data']['estimated_network_fee'])
93
+
94
+ puts "Final Network Fee: #{network_fee.truncate(8).to_s('F')}"
95
+
96
+ rescue Exception => e
97
+ # extract the fee and subtract it from the available amount
98
+
99
+ puts "Exception: #{e.to_s}"
100
+
101
+ network_fee = BigDecimal(e.to_s.split(' ')[7])
102
+ puts "Estimated Network Fee: #{e.to_s.split(' ')[7]}"
103
+
104
+ retry unless (tries -= 1).zero?
105
+
106
+ raise Exception.new("UNABLE TO ESTIMATE NETWORK FEE")
107
+ end
108
+
109
+ # make the withdrawal + send change to change address
110
+
111
+ puts BlockIo.withdraw(:from_labels => first_address_label, :to_addresses => to_addresses.join(','), :amounts => amounts.join(','))
112
+
113
+ # archive the first address
114
+
115
+ puts BlockIo.archive_address(:labels => first_address_label)
116
+
117
+
@@ -1,6 +1,6 @@
1
1
  require 'block_io/version'
2
2
  require 'httpclient'
3
- require 'json'
3
+ require 'oj'
4
4
  require 'connection_pool'
5
5
  require 'ecdsa'
6
6
  require 'openssl'
@@ -24,7 +24,7 @@ module BlockIo
24
24
  @pin = args[:pin]
25
25
  @encryptionKey = Helper.pinToAesKey(@pin) if !@pin.nil?
26
26
 
27
- @conn_pool = ConnectionPool.new(size: 5, timeout: 300) { HTTPClient.new }
27
+ @conn_pool = ConnectionPool.new(size: 1, timeout: 300) { h = HTTPClient.new; h.tcp_keepalive = true; h.ssl_config.ssl_version = :auto; h }
28
28
 
29
29
  @version = args[:version] || 2 # default version is 2
30
30
 
@@ -56,7 +56,7 @@ module BlockIo
56
56
 
57
57
  params = get_params(args)
58
58
 
59
- params += "&pin=#{@pin}" if @version == 1 # Block.io handles the Secret PIN in the legacy API (v1)
59
+ params << "&pin=" << @pin if @version == 1 # Block.io handles the Secret PIN in the legacy API (v1)
60
60
 
61
61
  response = self.api_call([method_name, params])
62
62
 
@@ -74,21 +74,10 @@ module BlockIo
74
74
  # let's sign all the inputs we can
75
75
  inputs = response['data']['inputs']
76
76
 
77
- inputs.each do |input|
78
- # iterate over all signers
79
-
80
- input['signers'].each do |signer|
81
- # if our public key matches this signer's public key, sign the data
82
-
83
- signer['signed_data'] = key.sign(input['data_to_sign']) if signer['signer_public_key'] == key.public_key
84
-
85
- end
86
-
87
- end
77
+ Helper.signData(inputs, [key])
88
78
 
89
79
  # the response object is now signed, let's stringify it and finalize this withdrawal
90
-
91
- response = self.api_call(['sign_and_finalize_withdrawal',{:signature_data => response['data'].to_json}])
80
+ response = self.api_call(['sign_and_finalize_withdrawal',{:signature_data => Oj.dump(response['data'])}])
92
81
 
93
82
  # if we provided all the required signatures, this transaction went through
94
83
  # otherwise Block.io responded with data asking for more signatures
@@ -118,22 +107,10 @@ module BlockIo
118
107
 
119
108
  # let's sign all the inputs we can
120
109
  inputs = response['data']['inputs']
121
-
122
- inputs.each do |input|
123
- # iterate over all signers
124
-
125
- input['signers'].each do |signer|
126
- # if our public key matches this signer's public key, sign the data
127
-
128
- signer['signed_data'] = key.sign(input['data_to_sign']) if signer['signer_public_key'] == key.public_key
129
-
130
- end
131
-
132
- end
110
+ Helper.signData(inputs, [key])
133
111
 
134
112
  # the response object is now signed, let's stringify it and finalize this withdrawal
135
-
136
- response = self.api_call(['sign_and_finalize_sweep',{:signature_data => response['data'].to_json}])
113
+ response = self.api_call(['sign_and_finalize_sweep',{:signature_data => Oj.dump(response['data'])}])
137
114
 
138
115
  # if we provided all the required signatures, this transaction went through
139
116
  # otherwise Block.io responded with data asking for more signatures
@@ -154,11 +131,10 @@ module BlockIo
154
131
  @conn_pool.with do |hc|
155
132
  # prevent initiation of HTTPClients every time we make this call, use a connection_pool
156
133
 
157
- hc.ssl_config.ssl_version = :TLSv1
158
134
  response = hc.post("#{@base_url.gsub('API_CALL',endpoint[0]).gsub('VERSION', 'v'+@version.to_s) + @api_key}", endpoint[1])
159
135
 
160
136
  begin
161
- body = JSON.parse(response.body)
137
+ body = Oj.load(response.body)
162
138
  raise Exception.new(body['data']['error_message']) if !body['status'].eql?('success')
163
139
  rescue
164
140
  raise Exception.new('Unknown error occurred. Please report this.')
@@ -310,6 +286,39 @@ module BlockIo
310
286
 
311
287
  module Helper
312
288
 
289
+ def self.signData(inputs, keys)
290
+ # sign the given data with the given keys
291
+ # TODO loop is O(n^3), make it better
292
+
293
+ raise Exception.new('Keys object must be an array of keys, without at least one key inside it.') unless keys.is_a?(Array) and keys.size >= 1
294
+
295
+ i = 0
296
+ while i < inputs.size do
297
+ # iterate over all signers
298
+ input = inputs[i]
299
+
300
+ j = 0
301
+ while j < input['signers'].size do
302
+ # if our public key matches this signer's public key, sign the data
303
+ signer = inputs[i]['signers'][j]
304
+
305
+ k = 0
306
+ while k < keys.size do
307
+ # sign for each key provided, if we can
308
+ key = keys[k]
309
+ signer['signed_data'] = key.sign(input['data_to_sign']) if signer['signer_public_key'] == key.public_key
310
+ k = k + 1
311
+ end
312
+
313
+ j = j + 1
314
+ end
315
+
316
+ i = i + 1
317
+ end
318
+
319
+ inputs
320
+ end
321
+
313
322
  def self.extractKey(encrypted_data, b64_enc_key)
314
323
  # passphrase is in plain text
315
324
  # encrypted_data is in base64, as it was stored on Block.io
@@ -1,3 +1,3 @@
1
1
  module BlockIo
2
- VERSION = "1.0.6"
2
+ VERSION = "1.0.8"
3
3
  end
metadata CHANGED
@@ -1,141 +1,155 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: block_io
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.6
4
+ version: 1.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Atif Nazir
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-21 00:00:00.000000000 Z
11
+ date: 2017-09-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ~>
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.6'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ~>
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.6'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ~>
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ~>
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: ecdsa
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ~>
46
46
  - !ruby/object:Gem::Version
47
47
  version: '1.2'
48
- - - ">="
48
+ - - '>='
49
49
  - !ruby/object:Gem::Version
50
50
  version: 1.2.0
51
51
  type: :runtime
52
52
  prerelease: false
53
53
  version_requirements: !ruby/object:Gem::Requirement
54
54
  requirements:
55
- - - "~>"
55
+ - - ~>
56
56
  - !ruby/object:Gem::Version
57
57
  version: '1.2'
58
- - - ">="
58
+ - - '>='
59
59
  - !ruby/object:Gem::Version
60
60
  version: 1.2.0
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: httpclient
63
63
  requirement: !ruby/object:Gem::Requirement
64
64
  requirements:
65
- - - "~>"
65
+ - - ~>
66
66
  - !ruby/object:Gem::Version
67
- version: '2.4'
68
- - - ">="
67
+ version: '2.8'
68
+ - - '>='
69
69
  - !ruby/object:Gem::Version
70
- version: 2.4.0
70
+ version: 2.8.0
71
71
  type: :runtime
72
72
  prerelease: false
73
73
  version_requirements: !ruby/object:Gem::Requirement
74
74
  requirements:
75
- - - "~>"
75
+ - - ~>
76
76
  - !ruby/object:Gem::Version
77
- version: '2.4'
78
- - - ">="
77
+ version: '2.8'
78
+ - - '>='
79
79
  - !ruby/object:Gem::Version
80
- version: 2.4.0
80
+ version: 2.8.0
81
81
  - !ruby/object:Gem::Dependency
82
- name: json
82
+ name: oj
83
83
  requirement: !ruby/object:Gem::Requirement
84
84
  requirements:
85
- - - "~>"
85
+ - - ~>
86
86
  - !ruby/object:Gem::Version
87
- version: '1.8'
88
- - - ">="
87
+ version: '3.3'
88
+ - - '>='
89
89
  - !ruby/object:Gem::Version
90
- version: 1.8.1
90
+ version: 3.3.5
91
91
  type: :runtime
92
92
  prerelease: false
93
93
  version_requirements: !ruby/object:Gem::Requirement
94
94
  requirements:
95
- - - "~>"
95
+ - - ~>
96
96
  - !ruby/object:Gem::Version
97
- version: '1.8'
98
- - - ">="
97
+ version: '3.3'
98
+ - - '>='
99
99
  - !ruby/object:Gem::Version
100
- version: 1.8.1
100
+ version: 3.3.5
101
+ - !ruby/object:Gem::Dependency
102
+ name: oj_mimic_json
103
+ requirement: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - '>='
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ type: :runtime
109
+ prerelease: false
110
+ version_requirements: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - '>='
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
101
115
  - !ruby/object:Gem::Dependency
102
116
  name: connection_pool
103
117
  requirement: !ruby/object:Gem::Requirement
104
118
  requirements:
105
- - - "~>"
119
+ - - ~>
106
120
  - !ruby/object:Gem::Version
107
- version: '2.0'
108
- - - ">="
121
+ version: '2.2'
122
+ - - '>='
109
123
  - !ruby/object:Gem::Version
110
- version: 2.0.0
124
+ version: 2.2.1
111
125
  type: :runtime
112
126
  prerelease: false
113
127
  version_requirements: !ruby/object:Gem::Requirement
114
128
  requirements:
115
- - - "~>"
129
+ - - ~>
116
130
  - !ruby/object:Gem::Version
117
- version: '2.0'
118
- - - ">="
131
+ version: '2.2'
132
+ - - '>='
119
133
  - !ruby/object:Gem::Version
120
- version: 2.0.0
134
+ version: 2.2.1
121
135
  - !ruby/object:Gem::Dependency
122
136
  name: pbkdf2-ruby
123
137
  requirement: !ruby/object:Gem::Requirement
124
138
  requirements:
125
- - - "~>"
139
+ - - ~>
126
140
  - !ruby/object:Gem::Version
127
141
  version: '0.2'
128
- - - ">="
142
+ - - '>='
129
143
  - !ruby/object:Gem::Version
130
144
  version: 0.2.1
131
145
  type: :runtime
132
146
  prerelease: false
133
147
  version_requirements: !ruby/object:Gem::Requirement
134
148
  requirements:
135
- - - "~>"
149
+ - - ~>
136
150
  - !ruby/object:Gem::Version
137
151
  version: '0.2'
138
- - - ">="
152
+ - - '>='
139
153
  - !ruby/object:Gem::Version
140
154
  version: 0.2.1
141
155
  description: This Ruby Gem is the official reference client for the Block.io payments
@@ -147,13 +161,14 @@ executables: []
147
161
  extensions: []
148
162
  extra_rdoc_files: []
149
163
  files:
150
- - ".gitignore"
164
+ - .gitignore
151
165
  - Gemfile
152
166
  - LICENSE
153
167
  - README.md
154
168
  - Rakefile
155
169
  - block_io.gemspec
156
170
  - examples/basic.rb
171
+ - examples/change.rb
157
172
  - examples/dtrust.rb
158
173
  - examples/sweeper.rb
159
174
  - lib/block_io.rb
@@ -168,17 +183,17 @@ require_paths:
168
183
  - lib
169
184
  required_ruby_version: !ruby/object:Gem::Requirement
170
185
  requirements:
171
- - - ">="
186
+ - - '>='
172
187
  - !ruby/object:Gem::Version
173
188
  version: '0'
174
189
  required_rubygems_version: !ruby/object:Gem::Requirement
175
190
  requirements:
176
- - - ">="
191
+ - - '>='
177
192
  - !ruby/object:Gem::Version
178
193
  version: '0'
179
194
  requirements: []
180
195
  rubyforge_project:
181
- rubygems_version: 2.2.2
196
+ rubygems_version: 2.0.14.1
182
197
  signing_key:
183
198
  specification_version: 4
184
199
  summary: An easy to use Dogecoin, Bitcoin, Litecoin wallet API by Block.io. Sign up