onchain 3.2 → 3.03
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 +4 -4
- data/lib/onchain.rb +3 -1
- data/lib/onchain/block_chain.rb +13 -6
- data/lib/onchain/payments.rb +88 -0
- data/lib/onchain/providers/bitcoind_api.rb +25 -73
- data/lib/onchain/providers/blockchaininfo_api.rb +2 -13
- data/lib/onchain/providers/blockr_api.rb +0 -11
- data/lib/onchain/providers/insight_api.rb +0 -11
- data/lib/onchain/sweeper.rb +139 -0
- data/lib/onchain/transaction.rb +1 -13
- metadata +4 -17
- data/lib/onchain/exchange_rates.rb +0 -87
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fd3dee9b9c3e89866a52611e36e4fec6c510675c
|
4
|
+
data.tar.gz: dfec0707b7aa380e6c6189f7065ada17b991dd93
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4c363a289b43d919c7850de400ae48f3226fe8851cb770148b34ce084549cccb6f654538596a16bd0da586441273cc699696c2cc03772d23f7ef8e351aa31848
|
7
|
+
data.tar.gz: 3a16f3eabf4e6306c89ed07fcae622cfd5d481afbb86676b50142293d6a0e2e48d753df0d699eb474d818f34a5c8d46d29e1e793ad85f3da31f5b3696d0aa1f8
|
data/lib/onchain.rb
CHANGED
@@ -3,11 +3,13 @@ require 'onchain/providers/blockchaininfo_api.rb'
|
|
3
3
|
require 'onchain/providers/blockr_api.rb'
|
4
4
|
require 'onchain/providers/insight_api.rb'
|
5
5
|
require 'onchain/providers/bitcoind_api.rb'
|
6
|
+
require 'onchain/sweeper.rb'
|
7
|
+
require 'onchain/payments.rb'
|
6
8
|
require 'onchain/transaction.rb'
|
7
|
-
require 'onchain/exchange_rates.rb'
|
8
9
|
require 'money-tree'
|
9
10
|
require 'bitcoin'
|
10
11
|
|
12
|
+
|
11
13
|
# Setup the bitcoin gem for zcash
|
12
14
|
module Bitcoin
|
13
15
|
|
data/lib/onchain/block_chain.rb
CHANGED
@@ -62,6 +62,17 @@ class OnChain::BlockChain
|
|
62
62
|
end
|
63
63
|
|
64
64
|
end
|
65
|
+
|
66
|
+
def get_history_for_addresses(addresses, network = :bitcoin)
|
67
|
+
history = []
|
68
|
+
addresses.each do |address|
|
69
|
+
res = address_history(address, network)
|
70
|
+
res.each do |r|
|
71
|
+
history << r
|
72
|
+
end
|
73
|
+
end
|
74
|
+
return history
|
75
|
+
end
|
65
76
|
|
66
77
|
# Given a list of addresses, return those
|
67
78
|
# that don't have balances in the cahce.
|
@@ -107,7 +118,7 @@ class OnChain::BlockChain
|
|
107
118
|
end
|
108
119
|
|
109
120
|
def get_balance_satoshi(address, network = :bitcoin)
|
110
|
-
return (get_balance(address, network).to_f * 100000000).to_i
|
121
|
+
return (get_balance(address, network = :bitcoin).to_f * 100000000).to_i
|
111
122
|
end
|
112
123
|
|
113
124
|
def get_available_suppliers(method_name, network)
|
@@ -123,7 +134,7 @@ class OnChain::BlockChain
|
|
123
134
|
next
|
124
135
|
end
|
125
136
|
|
126
|
-
if supplier == :insight and ! [:bitcoin].include? network
|
137
|
+
if supplier == :insight and ! [:bitcoin, :testnet3].include? network
|
127
138
|
next
|
128
139
|
end
|
129
140
|
|
@@ -147,10 +158,6 @@ class OnChain::BlockChain
|
|
147
158
|
next
|
148
159
|
end
|
149
160
|
|
150
|
-
if supplier == :insight and method_name.to_s == 'get_address_info'
|
151
|
-
next
|
152
|
-
end
|
153
|
-
|
154
161
|
if supplier == :blockr and network == :bitcoin and method_name.to_s == 'get_history_for_addresses'
|
155
162
|
next
|
156
163
|
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
class OnChain::Payments
|
2
|
+
class << self
|
3
|
+
|
4
|
+
FEE = 50000
|
5
|
+
|
6
|
+
def get_address_from_redemption_script(redemption_script)
|
7
|
+
|
8
|
+
sbin = OnChain.hex_to_bin(redemption_script)
|
9
|
+
hex = OnChain.bin_to_hex(sbin)
|
10
|
+
fund_address = Bitcoin.hash160_to_p2sh_address(Bitcoin.hash160(hex))
|
11
|
+
|
12
|
+
return fund_address
|
13
|
+
end
|
14
|
+
|
15
|
+
def hex_to_script(hex)
|
16
|
+
return Bitcoin::Script.new(OnChain::hex_to_bin(hex))
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_payment_tx(redemption_script, payments)
|
20
|
+
|
21
|
+
begin
|
22
|
+
|
23
|
+
fund_address = get_address_from_redemption_script(redemption_script)
|
24
|
+
|
25
|
+
tx = Bitcoin::Protocol::Tx.new
|
26
|
+
|
27
|
+
total_amount = FEE
|
28
|
+
|
29
|
+
payments.each do |payment|
|
30
|
+
if payment[1].is_a?(String)
|
31
|
+
payment[1] = payment[1].to_i
|
32
|
+
end
|
33
|
+
total_amount = total_amount + payment[1]
|
34
|
+
end
|
35
|
+
|
36
|
+
total_in_fund = OnChain::BlockChain.get_balance_satoshi(fund_address)
|
37
|
+
|
38
|
+
# Do we have enough in the fund.
|
39
|
+
if(total_amount > total_in_fund)
|
40
|
+
return 'Balance is not enough to cover payment'
|
41
|
+
end
|
42
|
+
|
43
|
+
# OK, let's get some inputs
|
44
|
+
amount_so_far = 0
|
45
|
+
unspent = OnChain::BlockChain.get_unspent_outs(fund_address)
|
46
|
+
unspent.each do |spent|
|
47
|
+
|
48
|
+
txin = Bitcoin::Protocol::TxIn.new
|
49
|
+
|
50
|
+
txin.prev_out = spent[0].scan(/../).map { |x| x.hex }.pack('c*').reverse
|
51
|
+
txin.prev_out_index = spent[1]
|
52
|
+
txin.script = hex_to_script(redemption_script).to_payload
|
53
|
+
|
54
|
+
tx.add_in(txin)
|
55
|
+
|
56
|
+
amount_so_far = amount_so_far + spent[3].to_i
|
57
|
+
if amount_so_far >= total_amount
|
58
|
+
next
|
59
|
+
end
|
60
|
+
end
|
61
|
+
change = amount_so_far - total_amount
|
62
|
+
|
63
|
+
payments.each do |payment|
|
64
|
+
|
65
|
+
txout = Bitcoin::Protocol::TxOut.new(payment[1],
|
66
|
+
Bitcoin::Script.to_address_script(payment[0]))
|
67
|
+
|
68
|
+
tx.add_out(txout)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Send the chnage back.
|
72
|
+
if total_in_fund > total_amount
|
73
|
+
|
74
|
+
txout = Bitcoin::Protocol::TxOut.new(total_in_fund - total_amount,
|
75
|
+
Bitcoin::Script.to_address_script(fund_address))
|
76
|
+
|
77
|
+
tx.add_out(txout)
|
78
|
+
end
|
79
|
+
|
80
|
+
return tx
|
81
|
+
|
82
|
+
rescue Exception => e
|
83
|
+
return 'Unable to parse payment :: ' + e.to_s
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
@@ -5,45 +5,14 @@ class OnChain::BlockChain
|
|
5
5
|
|
6
6
|
# Get last 20 transactions
|
7
7
|
def bitcoind_address_history(address, network = :bitcoin)
|
8
|
-
|
9
|
-
|
10
|
-
result = execute_remote_command('searchrawtransactions ' + address + ' 1 0 20 0', network)
|
11
|
-
cache_write(network.to_s + ' history ' + address, result, BALANCE_CACHE_FOR)
|
12
|
-
end
|
13
|
-
|
14
|
-
result = cache_read(network.to_s + ' history ' + address)
|
8
|
+
|
9
|
+
result = execute_remote_command('searchrawtransactions ' + address + ' 1 0 20 0', network)
|
15
10
|
|
16
11
|
json = JSON.parse result
|
17
12
|
|
18
13
|
return parse_bitcoind_address_tx(address, json, network)
|
19
14
|
|
20
15
|
end
|
21
|
-
|
22
|
-
def bitcoind_get_history_for_addresses(addresses, network = :bitcoin)
|
23
|
-
|
24
|
-
commands = []
|
25
|
-
if cache_read(network.to_s + ' history ' + addresses[0]) == nil
|
26
|
-
addresses.each do |address|
|
27
|
-
commands << 'searchrawtransactions ' + address + ' 1 0 20 0'
|
28
|
-
end
|
29
|
-
histories = OnChain::BlockChain.execute_remote_command(commands, :zclassic)
|
30
|
-
|
31
|
-
index = 0
|
32
|
-
histories.each_line do |history|
|
33
|
-
cache_write(network.to_s + ' history ' + addresses[index], history, BALANCE_CACHE_FOR)
|
34
|
-
index = index + 1
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
history = []
|
39
|
-
addresses.each do |address|
|
40
|
-
res = bitcoind_address_history(address, network)
|
41
|
-
res.each do |r|
|
42
|
-
history << r
|
43
|
-
end
|
44
|
-
end
|
45
|
-
return history
|
46
|
-
end
|
47
16
|
|
48
17
|
def parse_bitcoind_address_tx(address, json, network)
|
49
18
|
|
@@ -86,10 +55,12 @@ class OnChain::BlockChain
|
|
86
55
|
|
87
56
|
def bitcoind_send_tx(tx_hex, network = :bitcoin)
|
88
57
|
|
89
|
-
execute_remote_command('sendrawtransaction ' + tx_hex, network)
|
58
|
+
remote = execute_remote_command('sendrawtransaction ' + tx_hex, network)
|
59
|
+
|
60
|
+
#res = JSON.parse(remote)
|
90
61
|
|
91
|
-
mess = '
|
92
|
-
stat = '
|
62
|
+
mess = 'Unknown'
|
63
|
+
stat = 'Unknown'
|
93
64
|
tx_hash = 'Unknown'
|
94
65
|
|
95
66
|
ret = "{\"status\":\"#{stat}\",\"data\":\"#{tx_hash}\",\"code\":200,\"message\":\"#{mess}\"}"
|
@@ -98,14 +69,21 @@ class OnChain::BlockChain
|
|
98
69
|
|
99
70
|
def bitcoind_get_balance(address, network = :bitcoin)
|
100
71
|
|
101
|
-
if cache_read(
|
72
|
+
if cache_read(address) == nil
|
102
73
|
|
103
|
-
|
74
|
+
outs = bitcoind_get_unspent_outs(address, network)
|
104
75
|
|
105
|
-
|
76
|
+
puts outs.to_s
|
77
|
+
|
78
|
+
bal = 0
|
79
|
+
outs.each do |out|
|
80
|
+
bal += out[3].to_i
|
81
|
+
end
|
82
|
+
|
83
|
+
cache_write(address, bal, BALANCE_CACHE_FOR)
|
106
84
|
end
|
107
85
|
|
108
|
-
bal = cache_read(
|
86
|
+
bal = cache_read(address)
|
109
87
|
if bal.class == Fixnum
|
110
88
|
bal = bal.to_f
|
111
89
|
end
|
@@ -115,22 +93,6 @@ class OnChain::BlockChain
|
|
115
93
|
|
116
94
|
def bitcoind_get_all_balances(addresses, network = :bitcoin)
|
117
95
|
|
118
|
-
|
119
|
-
# if first address is missing get them all.
|
120
|
-
commands = []
|
121
|
-
if cache_read(network.to_s + ' ' + addresses[0]) == nil
|
122
|
-
addresses.each do |address|
|
123
|
-
commands << 'getallbalance ' + address + ' 0'
|
124
|
-
end
|
125
|
-
balances = OnChain::BlockChain.execute_remote_command(commands, :zclassic)
|
126
|
-
|
127
|
-
index = 0
|
128
|
-
balances.each_line do |line|
|
129
|
-
cache_write(network.to_s + ' ' + addresses[index], line.to_f, BALANCE_CACHE_FOR)
|
130
|
-
index = index + 1
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
96
|
addresses.each do |address|
|
135
97
|
bitcoind_get_balance(address, network)
|
136
98
|
end
|
@@ -138,7 +100,7 @@ class OnChain::BlockChain
|
|
138
100
|
|
139
101
|
def bitcoind_get_unspent_outs(address, network = :bitcoin)
|
140
102
|
|
141
|
-
result = execute_remote_command('listallunspent ' + address + ' 1
|
103
|
+
result = execute_remote_command('listallunspent ' + address + ' 1', network)
|
142
104
|
|
143
105
|
json = JSON.parse result
|
144
106
|
|
@@ -162,34 +124,24 @@ class OnChain::BlockChain
|
|
162
124
|
|
163
125
|
# Run the command via ssh. For this to work you need
|
164
126
|
# to create the follwing ENV vars.
|
165
|
-
def execute_remote_command(
|
127
|
+
def execute_remote_command(cmd, network)
|
166
128
|
|
167
129
|
host = ENV[network.to_s.upcase + '_HOST']
|
168
130
|
username = ENV[network.to_s.upcase + '_USER']
|
169
131
|
password = ENV[network.to_s.upcase + '_PASSWORD']
|
170
|
-
|
132
|
+
cmd = ENV[network.to_s.upcase + '_CLI_CMD'] + ' ' + cmd
|
171
133
|
|
172
134
|
stdout = ""
|
135
|
+
stderr = ""
|
173
136
|
begin
|
174
137
|
Net::SSH.start(host, username,
|
175
138
|
:password => password,
|
176
139
|
:auth_methods => [ 'password' ],
|
177
140
|
:number_of_password_prompts => 0) do |ssh|
|
178
|
-
|
179
|
-
if ! commands.is_a?(Array)
|
180
|
-
commands = [commands]
|
181
|
-
end
|
182
|
-
|
183
|
-
commands.each do |command|
|
184
|
-
|
185
|
-
cmdout = ""
|
186
|
-
|
187
|
-
ssh.exec! prefix + ' '+ command do |channel, stream, data|
|
188
|
-
cmdout << data if stream == :stdout
|
189
|
-
end
|
190
141
|
|
191
|
-
|
192
|
-
stdout <<
|
142
|
+
ssh.exec! cmd do |channel, stream, data|
|
143
|
+
stdout << data if stream == :stdout
|
144
|
+
stderr << data if stream == :stderr
|
193
145
|
end
|
194
146
|
end
|
195
147
|
rescue Timeout::Error
|
@@ -8,17 +8,6 @@ class OnChain::BlockChain
|
|
8
8
|
|
9
9
|
blockinfo_parse_address_tx(address, json)
|
10
10
|
end
|
11
|
-
|
12
|
-
def blockinfo_get_history_for_addresses(addresses, network = :bitcoin)
|
13
|
-
history = []
|
14
|
-
addresses.each do |address|
|
15
|
-
res = blockinfo_address_history(address, network)
|
16
|
-
res.each do |r|
|
17
|
-
history << r
|
18
|
-
end
|
19
|
-
end
|
20
|
-
return history
|
21
|
-
end
|
22
11
|
|
23
12
|
def blockinfo_parse_address_tx(address, json)
|
24
13
|
|
@@ -92,7 +81,7 @@ class OnChain::BlockChain
|
|
92
81
|
end
|
93
82
|
end
|
94
83
|
|
95
|
-
def blockinfo_get_unspent_outs(address
|
84
|
+
def blockinfo_get_unspent_outs(address)
|
96
85
|
base_url = "https://blockchain.info/unspent?active=#{address}"
|
97
86
|
json = fetch_response(base_url, true)
|
98
87
|
|
@@ -129,7 +118,7 @@ class OnChain::BlockChain
|
|
129
118
|
|
130
119
|
def blockinfo_get_transaction(txhash)
|
131
120
|
base = "https://blockchain.info/rawtx/#{txhash}?format=hex"
|
132
|
-
return fetch_response(URI::encode(base)
|
121
|
+
return fetch_response(URI::encode(base))
|
133
122
|
end
|
134
123
|
|
135
124
|
def block_chain(cmd, address, params = "")
|
@@ -14,17 +14,6 @@ class OnChain::BlockChain
|
|
14
14
|
|
15
15
|
return parse_address_tx(address, json, network)
|
16
16
|
end
|
17
|
-
|
18
|
-
def blockr_get_history_for_addresses(addresses, network = :bitcoin)
|
19
|
-
history = []
|
20
|
-
addresses.each do |address|
|
21
|
-
res = blockr_address_history(address, network)
|
22
|
-
res.each do |r|
|
23
|
-
history << r
|
24
|
-
end
|
25
|
-
end
|
26
|
-
return history
|
27
|
-
end
|
28
17
|
|
29
18
|
def parse_address_tx(address, json, network)
|
30
19
|
|
@@ -18,17 +18,6 @@ class OnChain::BlockChain
|
|
18
18
|
return parse_insight_address_tx(address, json, network)
|
19
19
|
|
20
20
|
end
|
21
|
-
|
22
|
-
def insight_get_history_for_addresses(addresses, network = :bitcoin)
|
23
|
-
history = []
|
24
|
-
addresses.each do |address|
|
25
|
-
res = insight_address_history(address, network)
|
26
|
-
res.each do |r|
|
27
|
-
history << r
|
28
|
-
end
|
29
|
-
end
|
30
|
-
return history
|
31
|
-
end
|
32
21
|
|
33
22
|
def parse_insight_address_tx(address, json, network)
|
34
23
|
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
|
3
|
+
class OnChain::Sweeper
|
4
|
+
class << self
|
5
|
+
|
6
|
+
# Turn a bunch of master keys into a redemption scriopt
|
7
|
+
# i.e. derive the path.
|
8
|
+
def multi_sig_address_from_mpks(minimum_sigs, mpks, path)
|
9
|
+
|
10
|
+
rs = generate_redemption_script_from_mpks(minimum_sigs, mpks, path)
|
11
|
+
|
12
|
+
return generate_address_of_redemption_script(rs)
|
13
|
+
end
|
14
|
+
|
15
|
+
def generate_redemption_script_from_mpks(minimum_sigs, mpks, path)
|
16
|
+
|
17
|
+
addresses = []
|
18
|
+
mpks.each do |mpk|
|
19
|
+
master = MoneyTree::Node.from_serialized_address(mpk)
|
20
|
+
m = master.node_for_path(path)
|
21
|
+
addresses << m.public_key.to_hex
|
22
|
+
end
|
23
|
+
|
24
|
+
return generate_redemption_script(minimum_sigs, addresses)
|
25
|
+
end
|
26
|
+
|
27
|
+
def generate_redemption_script(minimum_sigs, addresses)
|
28
|
+
address, redeem_script = Bitcoin.pubkeys_to_p2sh_multisig_address(minimum_sigs, *addresses)
|
29
|
+
return redeem_script.hth
|
30
|
+
end
|
31
|
+
|
32
|
+
def generate_address_of_redemption_script(redemption_script)
|
33
|
+
hash160 = Bitcoin.hash160(redemption_script)
|
34
|
+
|
35
|
+
return Bitcoin.hash160_to_p2sh_address(hash160)
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_block_height
|
39
|
+
return Chain.get_latest_block["height"].to_i
|
40
|
+
end
|
41
|
+
|
42
|
+
# With a bunch of HD wallet paths, build a transaction
|
43
|
+
# That pays all the coins to a certain address
|
44
|
+
def sweep(minimum_sigs, mpks, path, limit, last_block_checked)
|
45
|
+
|
46
|
+
block_height_now = get_block_height
|
47
|
+
|
48
|
+
to_sweep = {}
|
49
|
+
# Get all the addresses we are interested in.
|
50
|
+
for i in 0..limit do
|
51
|
+
r = path.sub('#{index}', i.to_s)
|
52
|
+
a = multi_sig_address_from_mpks(minimum_sigs, mpks, r)
|
53
|
+
# store address as lookup for path.
|
54
|
+
to_sweep[a] = r
|
55
|
+
end
|
56
|
+
|
57
|
+
incoming_coins = []
|
58
|
+
|
59
|
+
to_sweep.each do |address, path|
|
60
|
+
|
61
|
+
txs = Chain.get_address_transactions(address)
|
62
|
+
|
63
|
+
txs.each do |tx|
|
64
|
+
|
65
|
+
block_height = tx["block_height"].to_i
|
66
|
+
if block_height > last_block_checked
|
67
|
+
|
68
|
+
tx["outputs"].each do |output|
|
69
|
+
output["addresses"].each do |address|
|
70
|
+
if to_sweep[address] != nil
|
71
|
+
incoming_coins << [address,
|
72
|
+
to_sweep[address],
|
73
|
+
output["value"],
|
74
|
+
output["transaction_hash"],
|
75
|
+
output["output_index"],
|
76
|
+
output["script"]]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
else
|
82
|
+
break
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
return incoming_coins, block_height_now
|
88
|
+
end
|
89
|
+
|
90
|
+
def create_payment_tx_from_sweep(minimum_sigs, incoming, destination_address, mpks)
|
91
|
+
|
92
|
+
tx = Bitcoin::Protocol::Tx.new
|
93
|
+
total_amount = 0
|
94
|
+
|
95
|
+
incoming.each do |output|
|
96
|
+
|
97
|
+
txin = Bitcoin::Protocol::TxIn.new
|
98
|
+
|
99
|
+
rs = generate_redemption_script_from_mpks(minimum_sigs, mpks, output[1])
|
100
|
+
|
101
|
+
txin.prev_out = OnChain.hex_to_bin(output[3]).reverse
|
102
|
+
txin.prev_out_index = output[4]
|
103
|
+
txin.script = OnChain.hex_to_bin(rs)
|
104
|
+
|
105
|
+
tx.add_in(txin)
|
106
|
+
|
107
|
+
total_amount = total_amount + output[2].to_i
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
total_amount = total_amount - 10000
|
112
|
+
|
113
|
+
if total_amount < 0
|
114
|
+
return "Not enough coins to create a transaction."
|
115
|
+
end
|
116
|
+
|
117
|
+
# Add an output and we're done.
|
118
|
+
txout = Bitcoin::Protocol::TxOut.new(total_amount,
|
119
|
+
Bitcoin::Script.to_address_script(destination_address))
|
120
|
+
|
121
|
+
tx.add_out(txout)
|
122
|
+
|
123
|
+
paths = incoming.map { |i| i[1] }
|
124
|
+
|
125
|
+
return OnChain.bin_to_hex(tx.to_payload), paths
|
126
|
+
end
|
127
|
+
|
128
|
+
def post_tx_for_signing(tx_hex, paths, address)
|
129
|
+
|
130
|
+
return HTTParty.post('https://onchain.herokuapp.com/api/v1/transaction',
|
131
|
+
:body => { :tx => tx_hex,
|
132
|
+
:address => address,
|
133
|
+
:meta_data => paths.join(','),
|
134
|
+
:user_email => ENV['ONCHAIN_EMAIL'],
|
135
|
+
:user_token => ENV['ONCHAIN_TOKEN'] })
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
end
|
data/lib/onchain/transaction.rb
CHANGED
@@ -11,7 +11,6 @@ class OnChain::Transaction
|
|
11
11
|
input_amount = 0
|
12
12
|
# Let's add up the value of all the inputs.
|
13
13
|
tx.in.each_with_index do |txin, index|
|
14
|
-
|
15
14
|
prev_hash = txin.to_hash['prev_out']['hash']
|
16
15
|
prev_index = txin.to_hash['prev_out']['n']
|
17
16
|
|
@@ -117,17 +116,6 @@ class OnChain::Transaction
|
|
117
116
|
|
118
117
|
end
|
119
118
|
|
120
|
-
def generate_redemption_script(minimum_sigs, addresses)
|
121
|
-
address, redeem_script = Bitcoin.pubkeys_to_p2sh_multisig_address(minimum_sigs, *addresses)
|
122
|
-
return redeem_script.hth
|
123
|
-
end
|
124
|
-
|
125
|
-
def generate_address_of_redemption_script(redemption_script)
|
126
|
-
hash160 = Bitcoin.hash160(redemption_script)
|
127
|
-
|
128
|
-
return Bitcoin.hash160_to_p2sh_address(hash160)
|
129
|
-
end
|
130
|
-
|
131
119
|
# Like create_single_address_transaction but for multi sig wallets.
|
132
120
|
def create_transaction_with_fee(redemption_scripts, address, amount, fee_percent, fee_addr)
|
133
121
|
|
@@ -136,7 +124,7 @@ class OnChain::Transaction
|
|
136
124
|
total_amount = amount + fee
|
137
125
|
|
138
126
|
addresses = redemption_scripts.map { |rs|
|
139
|
-
generate_address_of_redemption_script(rs)
|
127
|
+
OnChain::Sweeper.generate_address_of_redemption_script(rs)
|
140
128
|
}
|
141
129
|
|
142
130
|
unspents, indexes, change = OnChain::BlockChain.get_unspent_for_amount(addresses, total_amount)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: onchain
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '3.
|
4
|
+
version: '3.03'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Number 6
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-11-
|
11
|
+
date: 2016-11-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -94,20 +94,6 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: google_currency
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
104
|
-
type: :runtime
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
111
97
|
description: Call 3rd party API's but also switch API's if a 3rd party is down
|
112
98
|
email:
|
113
99
|
- support@onchain.io
|
@@ -117,11 +103,12 @@ extra_rdoc_files: []
|
|
117
103
|
files:
|
118
104
|
- lib/onchain.rb
|
119
105
|
- lib/onchain/block_chain.rb
|
120
|
-
- lib/onchain/
|
106
|
+
- lib/onchain/payments.rb
|
121
107
|
- lib/onchain/providers/bitcoind_api.rb
|
122
108
|
- lib/onchain/providers/blockchaininfo_api.rb
|
123
109
|
- lib/onchain/providers/blockr_api.rb
|
124
110
|
- lib/onchain/providers/insight_api.rb
|
111
|
+
- lib/onchain/sweeper.rb
|
125
112
|
- lib/onchain/transaction.rb
|
126
113
|
homepage: https://github.com/onchain/onchain-gem
|
127
114
|
licenses: []
|
@@ -1,87 +0,0 @@
|
|
1
|
-
require 'httparty'
|
2
|
-
require 'cgi'
|
3
|
-
require 'money'
|
4
|
-
require 'money/bank/google_currency'
|
5
|
-
|
6
|
-
class OnChain::ExchangeRate
|
7
|
-
|
8
|
-
class << self
|
9
|
-
|
10
|
-
BALANCE_RATE_FOR = 120
|
11
|
-
|
12
|
-
def bitcoin_exchange_rate(currency)
|
13
|
-
begin
|
14
|
-
ticker = "BTC-" + currency.to_s
|
15
|
-
|
16
|
-
if OnChain::BlockChain.cache_read(ticker) == nil
|
17
|
-
if currency == :USD
|
18
|
-
begin
|
19
|
-
r = HTTParty.get("https://www.bitstamp.net/api/ticker/")
|
20
|
-
j = JSON.parse r.response.body
|
21
|
-
rate = j["last"]
|
22
|
-
OnChain::BlockChain.cache_write(ticker, rate, BALANCE_RATE_FOR)
|
23
|
-
rescue
|
24
|
-
r = HTTParty.get("https://blockchain.info/ticker")
|
25
|
-
j = JSON.parse r.response.body
|
26
|
-
OnChain::BlockChain.cache_write(ticker, j["USD"]["last"], BALANCE_RATE_FOR)
|
27
|
-
end
|
28
|
-
|
29
|
-
elsif currency == :EUR
|
30
|
-
|
31
|
-
Money.default_bank = Money::Bank::GoogleCurrency.new
|
32
|
-
|
33
|
-
btc_usd = exchange_rate(:USD).to_f
|
34
|
-
|
35
|
-
money = Money.new(1_00, "USD")
|
36
|
-
|
37
|
-
usd_eur = money.exchange_to(:EUR).to_f
|
38
|
-
|
39
|
-
rate = usd_eur * btc_usd
|
40
|
-
|
41
|
-
OnChain::BlockChain.cache_write(ticker, rate.to_s, BALANCE_RATE_FOR)
|
42
|
-
|
43
|
-
elsif currency == :GBP
|
44
|
-
|
45
|
-
Money.default_bank = Money::Bank::GoogleCurrency.new
|
46
|
-
|
47
|
-
btc_usd = exchange_rate(:USD).to_f
|
48
|
-
|
49
|
-
money = Money.new(1_00, "USD")
|
50
|
-
|
51
|
-
usd_gbp = money.exchange_to(:GBP).to_f
|
52
|
-
|
53
|
-
rate = usd_gbp * btc_usd
|
54
|
-
|
55
|
-
OnChain::BlockChain.cache_write(ticker, rate.to_s, BALANCE_RATE_FOR)
|
56
|
-
|
57
|
-
else
|
58
|
-
OnChain::BlockChain.cache_write(ticker, "0", BALANCE_RATE_FOR)
|
59
|
-
end
|
60
|
-
|
61
|
-
end
|
62
|
-
return OnChain::BlockChain.cache_read(ticker)
|
63
|
-
rescue Exception => e
|
64
|
-
puts e.to_s
|
65
|
-
'0'
|
66
|
-
end
|
67
|
-
|
68
|
-
end
|
69
|
-
|
70
|
-
def alt_exchange_rate(alt_currency)
|
71
|
-
|
72
|
-
url = 'https://api.coinmarketcap.com/v1/ticker/' + alt_currency.to_s + '/'
|
73
|
-
|
74
|
-
begin
|
75
|
-
resp = OnChain::BlockChain.fetch_response(url)
|
76
|
-
|
77
|
-
return resp[0]['price_btc'].to_f
|
78
|
-
rescue => e
|
79
|
-
puts e.to_s
|
80
|
-
return 0.0
|
81
|
-
end
|
82
|
-
|
83
|
-
end
|
84
|
-
|
85
|
-
end
|
86
|
-
|
87
|
-
end
|