keoken 0.1.1 → 0.2.0
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/.rubocop.yml +2 -0
- data/Gemfile.lock +1 -1
- data/README.md +8 -8
- data/lib/keoken/backend/base.rb +55 -0
- data/lib/keoken/backend/bitcoin_ruby/transaction.rb +17 -50
- data/lib/keoken/backend/trezor/transaction.rb +100 -0
- data/lib/keoken/errors/data_not_parsed.rb +7 -0
- data/lib/keoken/parser.rb +53 -0
- data/lib/keoken/token.rb +74 -26
- data/lib/keoken/version.rb +1 -1
- data/lib/keoken.rb +10 -7
- data/spec/keoken_spec.rb +66 -26
- metadata +6 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 910f95d9e5c38b7bd38a3931b31172285811a45d0dcfdbd280d0c9f86c177a8c
|
4
|
+
data.tar.gz: f6d5dbc887a6bb374da47157dcede765a4f236f2d241058b9e9bd3e08b60e196
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a3b15901f51755d600d766fab2c96c4a0e42b2722368d763d27a4930761882060f5ab2d7f9f053e1639c3cc841bf862b6556c9cb0fd8214c0a0211a13bb8667c
|
7
|
+
data.tar.gz: a0c828852eb3b6929c39b78e9454add080bb142b708bff5c60488eec17b5ffeb6f015f74a994e8aaf0e5ab2ae046bb43571e2343a2ea9fe31b5d75c4ed32c5b8
|
data/.rubocop.yml
ADDED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -22,17 +22,17 @@ Or install it yourself as:
|
|
22
22
|
|
23
23
|
## Usage
|
24
24
|
|
25
|
+
It uses bitcoin-ruby, but you can use Trezor or Electrum, the most important command is the script,
|
26
|
+
which you can obtain with token.hex,
|
27
|
+
then you can send it as an output with a scriptPubKey and a value of 0.
|
28
|
+
In order to crate a token you need two outputs,
|
29
|
+
the change address with an amount less than original (for fees)
|
30
|
+
and the other one for the script. To send money you need three outputs,
|
31
|
+
the change address, the address who owns the recipient token and the script.
|
32
|
+
|
25
33
|
### Create token and send it to the blockchain
|
26
34
|
|
27
35
|
```ruby
|
28
|
-
# It uses bitcoin-ruby, but you can use Trezor or Electrum, the most important command is the script,
|
29
|
-
# which you can obtain with token.hex,
|
30
|
-
# then you can send it as an output with a scriptPubKey and a value of 0.
|
31
|
-
# In order to crate a token you need two outputs,
|
32
|
-
# the change address with an amount less than original (for fees)
|
33
|
-
# and the other one for the script. To send money you need three outputs,
|
34
|
-
# the change address, the address who owns the recipient token and the script.
|
35
|
-
|
36
36
|
Bitcoin.network = :testnet3
|
37
37
|
token = Keoken::Token.new(name: "test-keoken-bitex")
|
38
38
|
token.create(1_000_000)
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Keoken
|
2
|
+
module Backend
|
3
|
+
class Base
|
4
|
+
attr_accessor :inputs, :bitprim_transaction
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@inputs = []
|
8
|
+
@bitprim_transaction = Keoken::Bitprim::Transaction.new
|
9
|
+
end
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def build_inputs(address)
|
14
|
+
utxos = bitprim_transaction.utxos(address)
|
15
|
+
utxos.each do |utxo|
|
16
|
+
txid = utxo['txid']
|
17
|
+
transaction = bitprim_transaction.tx(txid)
|
18
|
+
outputs = transaction['vout'].select do |vout|
|
19
|
+
addresses = vout['scriptPubKey']['addresses']
|
20
|
+
if addresses
|
21
|
+
addresses.any? { |vout_address| vout_address == address }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
raise Keoken::OutputNotFound if outputs.empty?
|
25
|
+
output = outputs.first
|
26
|
+
@inputs.push(
|
27
|
+
tx_id: txid,
|
28
|
+
position: output['n'],
|
29
|
+
input_script: output['scriptPubKey']['hex'],
|
30
|
+
input_amount: output['value'].sub!(/\./, '').sub!(/^0+/, '').to_i
|
31
|
+
)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def build_fee(type)
|
36
|
+
total = @inputs.map { |input| input[:input_amount].to_i }.inject(:+)
|
37
|
+
estimate_fee = @bitprim_transaction.estimate_fee.to_f
|
38
|
+
[total,
|
39
|
+
((10 + 149 * @inputs.length + 35 * output_length(type)) * estimate_fee)
|
40
|
+
.to_s[0..9].sub!(/\./, '').sub!(/0+/, '')]
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def output_length(type)
|
46
|
+
case type
|
47
|
+
when :create
|
48
|
+
2
|
49
|
+
when :send
|
50
|
+
3
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module Keoken
|
2
2
|
module Backend
|
3
3
|
module BitcoinRuby
|
4
|
-
class Transaction
|
4
|
+
class Transaction < Keoken::Backend::Base
|
5
5
|
attr_accessor :to_json, :raw
|
6
|
-
|
6
|
+
include Bitcoin::Builder
|
7
7
|
|
8
8
|
# Create the transaction to broadcast in order to create tokens.
|
9
9
|
#
|
@@ -13,7 +13,7 @@ module Keoken
|
|
13
13
|
#
|
14
14
|
# @return [Keoken::Backend::BitcoinRuby::Transaction] An object instanciated with the transaction to broadcast.
|
15
15
|
#
|
16
|
-
def
|
16
|
+
def build_for_creation(address, key, script)
|
17
17
|
build(address, nil, key, script, :create)
|
18
18
|
end
|
19
19
|
|
@@ -26,7 +26,7 @@ module Keoken
|
|
26
26
|
#
|
27
27
|
# @return [Keoken::Backend::BitcoinRuby::Transaction] An object instanciated with the transaction to broadcast.
|
28
28
|
#
|
29
|
-
def
|
29
|
+
def build_for_send_amount(address, address_dest, key, script)
|
30
30
|
build(address, address_dest, key, script, :send)
|
31
31
|
end
|
32
32
|
|
@@ -40,39 +40,17 @@ module Keoken
|
|
40
40
|
#
|
41
41
|
# @return [Keoken::Backend::BitcoinRuby::Transaction] An object instanciated with the transaction to broadcast.
|
42
42
|
#
|
43
|
-
def
|
44
|
-
|
45
|
-
|
46
|
-
inputs = []
|
47
|
-
utxos.each do |utxo|
|
48
|
-
txid = utxo['txid']
|
49
|
-
transaction = bitprim_transaction.tx(txid)
|
50
|
-
outputs = transaction['vout'].select do |vout|
|
51
|
-
addresses = vout['scriptPubKey']['addresses']
|
52
|
-
if addresses
|
53
|
-
addresses.any? { |vout_address| vout_address == address }
|
54
|
-
end
|
55
|
-
end
|
56
|
-
raise Keoken::OutputNotFound if outputs.empty?
|
57
|
-
output = outputs.first
|
58
|
-
inputs.push(
|
59
|
-
tx_id: txid,
|
60
|
-
position: output['n'],
|
61
|
-
input_script: output['scriptPubKey']['hex'],
|
62
|
-
input_amount: output['value'].sub!(/\./, '').sub!(/^0+/, '').to_i
|
63
|
-
)
|
64
|
-
end
|
65
|
-
total = inputs.map { |input| input[:input_amount].to_i }.inject(:+)
|
66
|
-
estimate_fee = bitprim_transaction.estimate_fee.to_f
|
67
|
-
fee = ((10 + 149 * inputs.length + 35 * output_length(type)) * estimate_fee).to_s[0..9].sub!(/\./, '').sub!(/0+/, '')
|
43
|
+
def build(address, addr2, key, script, type)
|
44
|
+
build_inputs(address)
|
45
|
+
total, fee = build_fee(type)
|
68
46
|
case type
|
69
47
|
when :create
|
70
48
|
output_amount = total - fee.to_i
|
71
|
-
create(inputs, output_amount, key.addr, key, script)
|
49
|
+
create(@inputs, output_amount, key.addr, key, script)
|
72
50
|
when :send
|
73
51
|
output_amount = total - (fee.to_i * 2)
|
74
52
|
output_amount_to_addr2 = fee.to_i
|
75
|
-
send_amount(inputs, output_amount, key.addr, output_amount_to_addr2, addr2, key, script)
|
53
|
+
send_amount(@inputs, output_amount, key.addr, output_amount_to_addr2, addr2, key, script)
|
76
54
|
end
|
77
55
|
end
|
78
56
|
|
@@ -86,8 +64,7 @@ module Keoken
|
|
86
64
|
#
|
87
65
|
# @return [Keoken::Backend::BitcoinRuby::Transaction] An object instanciated with the transaction to broadcast.
|
88
66
|
#
|
89
|
-
def
|
90
|
-
token = new
|
67
|
+
def create(inputs, output_amount, output_address, key, script)
|
91
68
|
tx = build_tx do |t|
|
92
69
|
inputs.each do |input|
|
93
70
|
t.input do |i|
|
@@ -106,9 +83,9 @@ module Keoken
|
|
106
83
|
o.to(script, :custom)
|
107
84
|
end
|
108
85
|
end
|
109
|
-
|
110
|
-
|
111
|
-
|
86
|
+
@to_json = tx.to_json
|
87
|
+
@raw = tx.to_payload.bth
|
88
|
+
self
|
112
89
|
end
|
113
90
|
|
114
91
|
# Create the transaction to broadcast in order to send amount between tokens.
|
@@ -123,8 +100,7 @@ module Keoken
|
|
123
100
|
#
|
124
101
|
# @return [Keoken::Backend::BitcoinRuby::Transaction] An object instanciated with the transaction to broadcast.
|
125
102
|
#
|
126
|
-
def
|
127
|
-
token = self.new
|
103
|
+
def send_amount(inputs, output_amount, output_address, output_amount_to_addr2, addr2, key, script)
|
128
104
|
tx = build_tx do |t|
|
129
105
|
inputs.each do |input|
|
130
106
|
t.input do |i|
|
@@ -149,18 +125,9 @@ module Keoken
|
|
149
125
|
o.to(script, :custom)
|
150
126
|
end
|
151
127
|
end
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
end
|
156
|
-
|
157
|
-
def self.output_length(type)
|
158
|
-
case type
|
159
|
-
when :create
|
160
|
-
2
|
161
|
-
when :send
|
162
|
-
3
|
163
|
-
end
|
128
|
+
@to_json = tx.to_json
|
129
|
+
@raw = tx.to_payload.bth
|
130
|
+
self
|
164
131
|
end
|
165
132
|
end
|
166
133
|
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Keoken
|
2
|
+
module Backend
|
3
|
+
module Trezor
|
4
|
+
class Transaction < Keoken::Backend::Base
|
5
|
+
attr_accessor :to_json
|
6
|
+
|
7
|
+
# Create the transaction to broadcast in order to create tokens.
|
8
|
+
#
|
9
|
+
# @param address [String] Address that will contain the token.
|
10
|
+
# @param path [Array] Address derivation path.
|
11
|
+
# @param script [String] The token script.
|
12
|
+
#
|
13
|
+
# @return [Keoken::Backend::Trezor::Transaction] A serialized object ready for Trezor signing.
|
14
|
+
#
|
15
|
+
def build_for_creation(address, path, script)
|
16
|
+
build_inputs(address)
|
17
|
+
total, fee = build_fee(type)
|
18
|
+
output_amount = total - fee.to_i
|
19
|
+
create(@inputs, path, address, output_amount, script)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Create the transaction to broadcast in order to send amount between tokens.
|
23
|
+
#
|
24
|
+
# @param address [String] Address that will contain the token.
|
25
|
+
# @param address_dest [String] Address to receive the tokens.
|
26
|
+
# @param path [Array] Address derivation path.
|
27
|
+
# @param script [String] The token script.
|
28
|
+
#
|
29
|
+
# @return [Keoken::Backend::Trezor::Transaction] A serialized object ready for Trezor signing.
|
30
|
+
#
|
31
|
+
def build_for_send_amount(address, address_dest, path, script)
|
32
|
+
build_inputs(address)
|
33
|
+
total, fee = build_fee(type)
|
34
|
+
output_amount = total - (fee.to_i * 2)
|
35
|
+
output_amount_to_addr2 = fee.to_i
|
36
|
+
send(@inputs, path, output_amount, address, output_amount_to_addr2, address_dest, script)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def create(inputs, path, address, output_amount, script)
|
42
|
+
{
|
43
|
+
inputs:
|
44
|
+
inputs.map do |input|
|
45
|
+
{
|
46
|
+
address_n: path,
|
47
|
+
prev_index: input[:position],
|
48
|
+
prev_hash: input[:tx_id],
|
49
|
+
amount: input[:input_amount]
|
50
|
+
}
|
51
|
+
end,
|
52
|
+
outputs: [
|
53
|
+
{
|
54
|
+
address: address,
|
55
|
+
amount: output_amount,
|
56
|
+
script_type: 'PAYTOADDRESS'
|
57
|
+
},
|
58
|
+
{
|
59
|
+
op_return_data: script,
|
60
|
+
amount: '0',
|
61
|
+
script_type: 'PAYTOOPRETURN'
|
62
|
+
}
|
63
|
+
]
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
def send(inputs, path, output_amount, address, output_amount_to_addr2, addr2, script)
|
68
|
+
{
|
69
|
+
inputs:
|
70
|
+
inputs.map do |input|
|
71
|
+
{
|
72
|
+
address_n: path,
|
73
|
+
prev_index: input[:position],
|
74
|
+
prev_hash: input[:tx_id],
|
75
|
+
amount: input[:input_amount]
|
76
|
+
}
|
77
|
+
end,
|
78
|
+
outputs: [
|
79
|
+
{
|
80
|
+
address: address,
|
81
|
+
amount: output_amount,
|
82
|
+
script_type: 'PAYTOADDRESS'
|
83
|
+
},
|
84
|
+
{
|
85
|
+
address: addr2,
|
86
|
+
amount: output_amount_to_addr2,
|
87
|
+
script_type: 'PAYTOADDRESS'
|
88
|
+
},
|
89
|
+
{
|
90
|
+
op_return_data: script,
|
91
|
+
amount: '0',
|
92
|
+
script_type: 'PAYTOOPRETURN'
|
93
|
+
}
|
94
|
+
]
|
95
|
+
}
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Keoken
|
2
|
+
class Parser
|
3
|
+
attr_accessor :data, :transaction_type, :name, :amount
|
4
|
+
def initialize(script)
|
5
|
+
binary = script.htb
|
6
|
+
@data = binary.bytes
|
7
|
+
end
|
8
|
+
|
9
|
+
def prefix
|
10
|
+
result = @data.slice!(0)
|
11
|
+
raise Keoken::DataNotParsed, 'OP_RETURN missing' unless result == Bitcoin::Script::OP_RETURN.to_i
|
12
|
+
result = @data.slice!(0)
|
13
|
+
raise Keoken::DataNotParsed, 'Prefix size missing' unless result == Keoken::PREFIX_SIZE.to_i
|
14
|
+
result = @data.slice!(0..Keoken::PREFIX.htb.bytes.length - 1)
|
15
|
+
raise Keoken::DataNotParsed, 'Prefix not provided' unless result == Keoken::PREFIX.htb.bytes
|
16
|
+
bytesize = @data.slice!(0)
|
17
|
+
raise Keoken::DataNotParsed, 'Bytesize not provided' unless bytesize == @data.length
|
18
|
+
end
|
19
|
+
|
20
|
+
def set_transaction_type
|
21
|
+
result = @data.slice!(0..3).join
|
22
|
+
@transaction_type = if result == Keoken::TYPE_CREATE_ASSET
|
23
|
+
:create
|
24
|
+
elsif result == Keoken::TYPE_SEND_TOKEN
|
25
|
+
:send
|
26
|
+
else
|
27
|
+
raise Keoken::DataNotParsed, 'Transaction type not valid'
|
28
|
+
end
|
29
|
+
@transaction_type
|
30
|
+
end
|
31
|
+
|
32
|
+
def name_or_id
|
33
|
+
name = []
|
34
|
+
end_of_name = false
|
35
|
+
loop do
|
36
|
+
tmp = @data.slice!(0)
|
37
|
+
end_of_name ||= tmp > 0
|
38
|
+
next if tmp.zero? && !end_of_name
|
39
|
+
break if tmp.zero? && end_of_name
|
40
|
+
name.push tmp
|
41
|
+
end
|
42
|
+
if @transaction_type == :create
|
43
|
+
name.map { |n| n.to_s(16).htb }.join
|
44
|
+
elsif @transaction_type == :send
|
45
|
+
name.map { |n| n.to_s(16) }.join
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def amount
|
50
|
+
@data.map { |byte| byte.zero? ? "#{byte}0" : byte.to_s }.join.to_i
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/keoken/token.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Keoken
|
2
2
|
class Token
|
3
|
-
attr_accessor :
|
3
|
+
attr_accessor :data_script, :name, :id, :amount, :transaction_type
|
4
4
|
|
5
5
|
# Creates a new token object.
|
6
6
|
#
|
@@ -9,8 +9,8 @@ module Keoken
|
|
9
9
|
# @option options [Number] :id The id of token to obtain an amount to send to another address.
|
10
10
|
#
|
11
11
|
def initialize(options = {})
|
12
|
-
@name
|
13
|
-
@id
|
12
|
+
@name = options[:name]
|
13
|
+
@id = options[:id]
|
14
14
|
end
|
15
15
|
|
16
16
|
# Generate the script to create a token.
|
@@ -21,17 +21,13 @@ module Keoken
|
|
21
21
|
#
|
22
22
|
def create(amount)
|
23
23
|
raise Keoken::NameNotFound unless @name
|
24
|
-
data_script =
|
25
|
-
[
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
@hex = [Bitcoin::Script::OP_RETURN.to_s(16),
|
32
|
-
Keoken::PREFIX_SIZE,
|
33
|
-
Keoken::PREFIX,
|
34
|
-
data_length].join + data_script
|
24
|
+
@data_script =
|
25
|
+
[
|
26
|
+
Keoken::VERSION_NODE,
|
27
|
+
Keoken::TYPE_CREATE_ASSET,
|
28
|
+
name_to_hex(@name),
|
29
|
+
Keoken::PREFIX_BYTE_AMOUNT[0..prefix_length(amount)] + amount.to_s
|
30
|
+
].flatten.join
|
35
31
|
self
|
36
32
|
end
|
37
33
|
|
@@ -43,25 +39,77 @@ module Keoken
|
|
43
39
|
#
|
44
40
|
def send_amount(amount)
|
45
41
|
raise Keoken::IdNotFound unless @id
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
42
|
+
asset_length = Keoken::ASSET_ID_SIZE - @id.to_s.length - 1
|
43
|
+
@data_script =
|
44
|
+
[
|
45
|
+
Keoken::VERSION_NODE,
|
46
|
+
Keoken::TYPE_SEND_TOKEN,
|
47
|
+
Keoken::PREFIX_BYTE_ASSET_ID[0..asset_length] + @id.to_s,
|
48
|
+
Keoken::PREFIX_BYTE_AMOUNT[0..prefix_length(amount)] + amount.to_s
|
49
|
+
].flatten.join
|
50
|
+
self
|
51
|
+
end
|
51
52
|
|
52
|
-
|
53
|
+
# Hexadecimal value of script.
|
54
|
+
#
|
55
|
+
# @return [String] Hexadecimal value of script token.
|
56
|
+
def hex
|
57
|
+
[
|
58
|
+
Bitcoin::Script::OP_RETURN.to_s(16),
|
59
|
+
Keoken::PREFIX_SIZE,
|
60
|
+
Keoken::PREFIX,
|
61
|
+
data_length
|
62
|
+
].join + @data_script
|
63
|
+
end
|
53
64
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
65
|
+
# JSON serialization of object
|
66
|
+
#
|
67
|
+
# return [String] JSON serialization of token object.
|
68
|
+
def to_json
|
69
|
+
{
|
70
|
+
id: @id,
|
71
|
+
name: @name,
|
72
|
+
amount: @amount,
|
73
|
+
transaction_type: @transaction_type
|
74
|
+
}.to_json
|
75
|
+
end
|
76
|
+
|
77
|
+
# Deserialization of object
|
78
|
+
#
|
79
|
+
# return [Hash] Deserialization of token object.
|
80
|
+
def to_hash
|
81
|
+
{
|
82
|
+
id: @id,
|
83
|
+
name: @name,
|
84
|
+
amount: @amount,
|
85
|
+
transaction_type: @transaction_type
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
def parse_script(script)
|
90
|
+
parser = Keoken::Parser.new(script)
|
91
|
+
parser.prefix
|
92
|
+
@transaction_type = parser.set_transaction_type
|
93
|
+
if @transaction_type == :create
|
94
|
+
@name = parser.name_or_id
|
95
|
+
else
|
96
|
+
@id = parser.name_or_id
|
97
|
+
end
|
98
|
+
@amount = parser.amount
|
59
99
|
end
|
60
100
|
|
61
101
|
private
|
62
102
|
|
103
|
+
def data_length
|
104
|
+
@data_script.htb.bytesize.to_s(16)
|
105
|
+
end
|
106
|
+
|
107
|
+
def prefix_length(amount)
|
108
|
+
Keoken::AMOUNT_SIZE - amount.to_s.length - 1
|
109
|
+
end
|
110
|
+
|
63
111
|
def name_to_hex(name)
|
64
|
-
asset_bytes = name.bytes.map{|n| n.to_s(16)}
|
112
|
+
asset_bytes = name.bytes.map { |n| n.to_s(16) }
|
65
113
|
asset_bytes + ['00']
|
66
114
|
end
|
67
115
|
end
|
data/lib/keoken/version.rb
CHANGED
data/lib/keoken.rb
CHANGED
@@ -2,19 +2,22 @@ require 'bitcoin'
|
|
2
2
|
|
3
3
|
require 'keoken/extensions/bitcoin/script'
|
4
4
|
require 'keoken/token'
|
5
|
+
require 'keoken/parser'
|
6
|
+
require 'keoken/backend/base'
|
5
7
|
require 'keoken/backend/bitcoin_ruby/transaction'
|
6
8
|
require 'keoken/bitprim/transaction'
|
7
9
|
require 'keoken/errors/id_not_found'
|
8
10
|
require 'keoken/errors/name_not_found'
|
11
|
+
require 'keoken/errors/data_not_parsed'
|
9
12
|
|
10
13
|
module Keoken
|
11
|
-
PREFIX_SIZE = '04'
|
12
|
-
PREFIX = '00004b50'
|
13
|
-
VERSION_NODE = '0000'
|
14
|
-
TYPE_CREATE_ASSET = '0000'
|
15
|
-
TYPE_SEND_TOKEN = '0001'
|
16
|
-
PREFIX_BYTE_AMOUNT = '0000000000000000'
|
14
|
+
PREFIX_SIZE = '04'.freeze
|
15
|
+
PREFIX = '00004b50'.freeze
|
16
|
+
VERSION_NODE = '0000'.freeze
|
17
|
+
TYPE_CREATE_ASSET = '0000'.freeze
|
18
|
+
TYPE_SEND_TOKEN = '0001'.freeze
|
19
|
+
PREFIX_BYTE_AMOUNT = '0000000000000000'.freeze
|
17
20
|
AMOUNT_SIZE = 16
|
18
|
-
PREFIX_BYTE_ASSET_ID = '00000000'
|
21
|
+
PREFIX_BYTE_ASSET_ID = '00000000'.freeze
|
19
22
|
ASSET_ID_SIZE = 8
|
20
23
|
end
|
data/spec/keoken_spec.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Keoken do
|
4
|
-
it
|
4
|
+
it 'has a version number' do
|
5
5
|
expect(Keoken::VERSION).not_to be nil
|
6
6
|
end
|
7
7
|
|
8
|
-
it
|
8
|
+
it 'defines keoken constants' do
|
9
9
|
expect(Keoken::PREFIX_SIZE).not_to be nil
|
10
10
|
expect(Keoken::PREFIX).not_to be nil
|
11
11
|
expect(Keoken::VERSION_NODE).not_to be nil
|
@@ -17,33 +17,67 @@ describe Keoken do
|
|
17
17
|
expect(Keoken::ASSET_ID_SIZE).not_to be nil
|
18
18
|
end
|
19
19
|
|
20
|
-
it
|
21
|
-
token = Keoken::Token.new(name:
|
20
|
+
it 'creates the test-keoken token' do
|
21
|
+
token = Keoken::Token.new(name: 'test-keoken')
|
22
22
|
token.create(1_000_000)
|
23
23
|
expect(token.hex).to(
|
24
|
-
eq(
|
24
|
+
eq('6a0400004b501800000000746573742d6b656f6b656e000000000001000000')
|
25
25
|
)
|
26
26
|
end
|
27
27
|
|
28
|
-
it
|
28
|
+
it 'serialize the test-keoken token' do
|
29
|
+
token = Keoken::Token.new
|
30
|
+
token.parse_script('6a0400004b501800000000746573742d6b656f6b656e000000000001000000')
|
31
|
+
expect(token.to_json).to(
|
32
|
+
eq('{"id":null,"name":"test-keoken","amount":1000000,"transaction_type":"create"}')
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'deserialize the test-keoken token' do
|
37
|
+
token = Keoken::Token.new
|
38
|
+
token.parse_script('6a0400004b501800000000746573742d6b656f6b656e000000000001000000')
|
39
|
+
expect(token.to_hash).to(
|
40
|
+
eq(
|
41
|
+
amount: 1_000_000,
|
42
|
+
name: 'test-keoken',
|
43
|
+
id: nil,
|
44
|
+
transaction_type: :create
|
45
|
+
)
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'deserialize the token with id' do
|
50
|
+
token = Keoken::Token.new
|
51
|
+
token.parse_script('6a0400004b501000000001000000340000000001000000')
|
52
|
+
expect(token.to_hash).to(
|
53
|
+
eq(
|
54
|
+
amount: 1_000_000,
|
55
|
+
name: nil,
|
56
|
+
id: '34',
|
57
|
+
transaction_type: :send
|
58
|
+
)
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'raise an error when name is not provided' do
|
29
63
|
token = Keoken::Token.new
|
30
64
|
expect { token.create(1_000_000) }.to raise_error(Keoken::NameNotFound)
|
31
65
|
end
|
32
66
|
|
33
|
-
it
|
67
|
+
it 'raise an error when id is not provided' do
|
34
68
|
token = Keoken::Token.new
|
35
69
|
expect { token.send_amount(1_000_000) }.to raise_error(Keoken::IdNotFound)
|
36
70
|
end
|
37
71
|
|
38
|
-
it
|
72
|
+
it 'send 1_000_000 to token with 34 id' do
|
39
73
|
token = Keoken::Token.new(id: 34)
|
40
74
|
token.send_amount(1_000_000)
|
41
75
|
expect(token.hex).to(
|
42
|
-
eq(
|
76
|
+
eq('6a0400004b501000000001000000340000000001000000')
|
43
77
|
)
|
44
78
|
end
|
45
79
|
|
46
|
-
describe
|
80
|
+
describe 'creates token' do
|
47
81
|
before(:each) do
|
48
82
|
mock_requests
|
49
83
|
Bitcoin.network = :testnet3
|
@@ -51,7 +85,8 @@ describe Keoken do
|
|
51
85
|
token.create(1_000_000)
|
52
86
|
key = Bitcoin::Key.from_base58('cShKfHoHVf6iKKZym18ip1MJFQFxJwbcLxW53MQikxdDsGd2oxBU')
|
53
87
|
script = token.hex
|
54
|
-
@transaction_token = Keoken::Backend::BitcoinRuby::Transaction.
|
88
|
+
@transaction_token = Keoken::Backend::BitcoinRuby::Transaction.new
|
89
|
+
@transaction_token.build_for_creation(key.addr, key, script)
|
55
90
|
end
|
56
91
|
|
57
92
|
it "format to_json" do
|
@@ -72,22 +107,26 @@ describe Keoken do
|
|
72
107
|
)
|
73
108
|
end
|
74
109
|
|
75
|
-
it
|
110
|
+
it 'raw transaction' do
|
76
111
|
raw = @transaction_token.raw
|
77
|
-
expect(raw).to start_with(
|
78
|
-
expect(raw).to end_with(
|
112
|
+
expect(raw).to start_with('0100000001dae8143d5422d5e1018c43732baa74ac3114d4399a1f58a9ea7e31f656938a44010000006')
|
113
|
+
expect(raw).to end_with('6a0400004b501800000000746573742d6b656f6b656e00000000000100000000000000')
|
79
114
|
end
|
80
115
|
|
81
|
-
it
|
82
|
-
stub_request(:post,
|
83
|
-
.with(
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
116
|
+
it 'broadcast transaction' do
|
117
|
+
stub_request(:post, 'https://tbch.blockdozer.com/insight-api/tx/send')
|
118
|
+
.with(
|
119
|
+
body:
|
120
|
+
{
|
121
|
+
'rawtx' => /0100000001dae8143d5422d5e1018c43732baa74ac3114d4399a1f58a9ea7e31f656938a44010000006/
|
122
|
+
},
|
123
|
+
headers: {
|
124
|
+
"Accept" => "*/*",
|
125
|
+
"Accept-Encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3",
|
126
|
+
"Content-Type" => "application/x-www-form-urlencoded",
|
127
|
+
"Host" => "tbch.blockdozer.com",
|
128
|
+
"User-Agent" => "Ruby",
|
129
|
+
})
|
91
130
|
.to_return(status: 200, body: "{\"txid\":\"f410c773d079327b8283c175b08a84faa6ffcfbde40b5939b85f07f0dfde2eb8\"}", headers: {})
|
92
131
|
transaction = Keoken::Bitprim::Transaction.new
|
93
132
|
expect(transaction.send_tx(@transaction_token.raw)).to eq({"txid" => "f410c773d079327b8283c175b08a84faa6ffcfbde40b5939b85f07f0dfde2eb8"})
|
@@ -104,7 +143,8 @@ describe Keoken do
|
|
104
143
|
token.send_amount(500_000)
|
105
144
|
key = Bitcoin::Key.from_base58('cShKfHoHVf6iKKZym18ip1MJFQFxJwbcLxW53MQikxdDsGd2oxBU')
|
106
145
|
script = token.hex
|
107
|
-
@transaction_token = Keoken::Backend::BitcoinRuby::Transaction.
|
146
|
+
@transaction_token = Keoken::Backend::BitcoinRuby::Transaction.new
|
147
|
+
@transaction_token.build_for_send_amount(key.addr, 'mnTd41YZ1e1YqsaPNJh3wkeSUrFvp1guzi', key, script)
|
108
148
|
end
|
109
149
|
|
110
150
|
it "format to_json" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: keoken
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bitex
|
@@ -116,6 +116,7 @@ extra_rdoc_files: []
|
|
116
116
|
files:
|
117
117
|
- ".gitignore"
|
118
118
|
- ".rspec"
|
119
|
+
- ".rubocop.yml"
|
119
120
|
- ".travis.yml"
|
120
121
|
- ".yardoc/checksums"
|
121
122
|
- ".yardoc/complete"
|
@@ -153,13 +154,17 @@ files:
|
|
153
154
|
- doc/top-level-namespace.html
|
154
155
|
- keoken.gemspec
|
155
156
|
- lib/keoken.rb
|
157
|
+
- lib/keoken/backend/base.rb
|
156
158
|
- lib/keoken/backend/bitcoin_ruby/transaction.rb
|
159
|
+
- lib/keoken/backend/trezor/transaction.rb
|
157
160
|
- lib/keoken/bitprim/config.yaml
|
158
161
|
- lib/keoken/bitprim/transaction.rb
|
162
|
+
- lib/keoken/errors/data_not_parsed.rb
|
159
163
|
- lib/keoken/errors/id_not_found.rb
|
160
164
|
- lib/keoken/errors/name_not_found.rb
|
161
165
|
- lib/keoken/errors/output_not_found.rb
|
162
166
|
- lib/keoken/extensions/bitcoin/script.rb
|
167
|
+
- lib/keoken/parser.rb
|
163
168
|
- lib/keoken/token.rb
|
164
169
|
- lib/keoken/version.rb
|
165
170
|
- spec/keoken_spec.rb
|