block_io 1.0.6 → 1.0.8

Sign up to get free protection for your applications and to get access to all the features.
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