block_io 1.0.5 → 1.0.6

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: 0940811390b9b507fed0e47b2a04769206f6942c
4
- data.tar.gz: ec335dcad5f5a0b8cb70524ac3a619e5e70094c5
3
+ metadata.gz: d0ac0a444bdd6e778287026a7d9e89ef91b25ddd
4
+ data.tar.gz: 7e9bb72332639245c289c04f474be22ea512eba9
5
5
  SHA512:
6
- metadata.gz: 27f8d7f35c2d73438f0faf47e1d57b8d866dfeefde4a9080c1618eb0dd623b205caed1e345782dae052ad2039f470c0ec1a7476bfea832e67429e9916f3f8749
7
- data.tar.gz: e0b5606867ac6a6618732c3ca2c05fb48822a68ee00de2728a2bf283d6514b963d53609a23ee43809adba88b5384c9ba62b26cc5bd740f0937ed6ccf2734b231
6
+ metadata.gz: d06356ff689a5e4a8f30787d1683c2277b4237120daad993e4dac9b564c975d284427c8a147fe61194c1cef06cfb663cfff91bc26c0f86a8a42f3ee3aa58fa86
7
+ data.tar.gz: 36554afd1641aed6eee40442178a16d337a6174a263f559eefdaf7e63915edbe56a726d738bb8feaa4c69851b984e6b4106149070a13de1a81995de7be175118
data/README.md CHANGED
@@ -14,10 +14,12 @@ And then execute:
14
14
 
15
15
  Or install it yourself as:
16
16
 
17
- $ gem install block_io -v=1.0.4
17
+ $ gem install block_io -v=1.0.6
18
18
 
19
19
  ## Changelog
20
20
 
21
+ *01/21/15*: Added ability to sweep coins from one address to another.
22
+ *11/04/14*: Fix issue with nil parameters in an API call.
21
23
  *11/03/14*: Reduce dependence on OpenSSL. PBKDF2 function is now Ruby-based. Should work well with Heroku's libraries.
22
24
  *10/18/14*: Now using deterministic signatures (RFC6979), and BIP62 to hinder transaction malleability.
23
25
 
@@ -0,0 +1,24 @@
1
+ # Example script for sweeping all coins from a given address
2
+ # Must use the API Key for the Network the address belongs to
3
+ # Must also provide the Private Key to the sweep address in Wallet Import Format (WIF)
4
+ #
5
+ # Contact support@block.io if you have any issues
6
+
7
+ require "block_io"
8
+
9
+ BlockIo.set_options :api_key => 'YOUR API KEY', :pin => 'PIN NOT NEEDED', :version => 2
10
+
11
+ to_address = 'SWEEP COINS TO THIS ADDRESS'
12
+
13
+ from_address = 'SWEEP COINS FROM THIS ADDRESS'
14
+ private_key = 'PRIVATE KEY FOR FROM_ADDRESS'
15
+
16
+ begin
17
+ response = BlockIo.sweep_from_address(:to_address => to_address, :private_key => private_key, :from_address => from_address)
18
+
19
+ puts "Sweep Complete: #{response['data']['amount_sent']} #{response['data']['network']} swept from #{from_address} to #{to_address}."
20
+ puts "Transaction ID: #{response['data']['txid']}"
21
+ puts "Network Fee Incurred: #{response['data']['network_fee']} #{response['data']['network']}"
22
+ rescue Exception => e
23
+ puts "Sweep failed: #{e}"
24
+ end
@@ -36,9 +36,12 @@ module BlockIo
36
36
  method_name = m.to_s
37
37
 
38
38
  if ['withdraw', 'withdraw_from_address', 'withdraw_from_addresses', 'withdraw_from_user', 'withdraw_from_users', 'withdraw_from_label', 'withdraw_from_labels'].include?(m.to_s) then
39
-
39
+ # need to withdraw from an address
40
40
  self.withdraw(args.first, m.to_s)
41
41
 
42
+ elsif ['sweep_from_address'].include?(m.to_s) then
43
+ # need to sweep from an address
44
+ self.sweep(args.first, m.to_s)
42
45
  else
43
46
  params = get_params(args.first)
44
47
  self.api_call([method_name, params])
@@ -96,6 +99,51 @@ module BlockIo
96
99
 
97
100
  end
98
101
 
102
+ def self.sweep(args = {}, method_name = 'sweep_from_address')
103
+ # sweep coins from a given address + key
104
+
105
+ raise Exception.new("No private_key provided.") unless args.has_key?(:private_key)
106
+
107
+ key = Key.from_wif(args[:private_key])
108
+
109
+ args[:public_key] = key.public_key # so Block.io can match things up
110
+ args.delete(:private_key) # the key must never leave this machine
111
+
112
+ params = get_params(args)
113
+
114
+ response = self.api_call([method_name, params])
115
+
116
+ if response['data'].has_key?('reference_id') then
117
+ # Block.io's asking us to provide some client-side signatures, let's get to it
118
+
119
+ # let's sign all the inputs we can
120
+ 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
133
+
134
+ # 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}])
137
+
138
+ # if we provided all the required signatures, this transaction went through
139
+ # otherwise Block.io responded with data asking for more signatures
140
+ # the latter will be the case for dTrust addresses
141
+ end
142
+
143
+ return response
144
+
145
+ end
146
+
99
147
 
100
148
  private
101
149
 
@@ -139,12 +187,13 @@ module BlockIo
139
187
 
140
188
  class Key
141
189
 
142
- def initialize(privkey = nil)
190
+ def initialize(privkey = nil, compressed = true)
143
191
  # the privkey must be in hex if at all provided
144
192
 
145
193
  @group = ECDSA::Group::Secp256k1
146
194
  @private_key = privkey.to_i(16) || 1 + SecureRandom.random_number(group.order - 1)
147
195
  @public_key = @group.generator.multiply_by_scalar(@private_key)
196
+ @compressed = compressed
148
197
 
149
198
  end
150
199
 
@@ -156,7 +205,7 @@ module BlockIo
156
205
  def public_key
157
206
  # returns the compressed form of the public key to save network fees (shorter scripts)
158
207
 
159
- return ECDSA::Format::PointOctetString.encode(@public_key, compression: true).unpack("H*")[0]
208
+ return ECDSA::Format::PointOctetString.encode(@public_key, compression: @compressed).unpack("H*")[0]
160
209
  end
161
210
 
162
211
  def sign(data)
@@ -189,6 +238,19 @@ module BlockIo
189
238
 
190
239
  return Key.new(hashed_key)
191
240
  end
241
+
242
+ def self.from_wif(wif)
243
+ # returns a new key extracted from the Wallet Import Format provided
244
+ # TODO check against checksum
245
+
246
+ hexkey = Helper.decode_base58(wif)
247
+ actual_key = hexkey[2...66]
248
+
249
+ compressed = hexkey[2..hexkey.length].length-8 > 64 and hexkey[2..hexkey.length][64...66] == '01'
250
+
251
+ return Key.new(actual_key, compressed)
252
+
253
+ end
192
254
 
193
255
  def isPositive(i)
194
256
  sig = "!+-"[i <=> 0]
@@ -304,6 +366,41 @@ module BlockIo
304
366
  aes.iv = iv if iv != nil
305
367
  Base64.strict_encode64(aes.update(data) + aes.final)
306
368
  end
369
+
370
+ # courtesy bitcoin-ruby
371
+
372
+ def self.int_to_base58(int_val, leading_zero_bytes=0)
373
+ alpha = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
374
+ base58_val, base = '', alpha.size
375
+ while int_val > 0
376
+ int_val, remainder = int_val.divmod(base)
377
+ base58_val = alpha[remainder] + base58_val
378
+ end
379
+ base58_val
380
+ end
381
+
382
+ def self.base58_to_int(base58_val)
383
+ alpha = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
384
+ int_val, base = 0, alpha.size
385
+ base58_val.reverse.each_char.with_index do |char,index|
386
+ raise ArgumentError, 'Value not a valid Base58 String.' unless char_index = alpha.index(char)
387
+ int_val += char_index*(base**index)
388
+ end
389
+ int_val
390
+ end
391
+
392
+ def self.encode_base58(hex)
393
+ leading_zero_bytes = (hex.match(/^([0]+)/) ? $1 : '').size / 2
394
+ ("1"*leading_zero_bytes) + Helper.int_to_base58( hex.to_i(16) )
395
+ end
396
+
397
+ def self.decode_base58(base58_val)
398
+ s = Helper.base58_to_int(base58_val).to_s(16); s = (s.bytesize.odd? ? '0'+s : s)
399
+ s = '' if s == '00'
400
+ leading_zero_bytes = (base58_val.match(/^([1]+)/) ? $1 : '').size
401
+ s = ("00"*leading_zero_bytes) + s if leading_zero_bytes > 0
402
+ s
403
+ end
307
404
  end
308
405
 
309
406
  end
@@ -1,3 +1,3 @@
1
1
  module BlockIo
2
- VERSION = "1.0.5"
2
+ VERSION = "1.0.6"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: block_io
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.5
4
+ version: 1.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Atif Nazir
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-04 00:00:00.000000000 Z
11
+ date: 2015-01-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -155,6 +155,7 @@ files:
155
155
  - block_io.gemspec
156
156
  - examples/basic.rb
157
157
  - examples/dtrust.rb
158
+ - examples/sweeper.rb
158
159
  - lib/block_io.rb
159
160
  - lib/block_io/version.rb
160
161
  homepage: https://block.io/api/simple/ruby