trx 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/trx/abi/contract_event.rb +25 -0
- data/lib/trx/abi/decoder.rb +101 -0
- data/lib/trx/abi/encoder.rb +119 -0
- data/lib/trx/abi/function.rb +37 -0
- data/lib/trx/abi/function_input.rb +15 -0
- data/lib/trx/abi/function_output.rb +15 -0
- data/lib/trx/abi.rb +33 -0
- data/lib/trx/address.rb +63 -0
- data/lib/trx/http_client.rb +34 -0
- data/lib/trx/key.rb +82 -0
- data/lib/trx/signature.rb +14 -0
- data/lib/trx/utils.rb +48 -0
- data/lib/trx/version.rb +5 -0
- data/lib/trx.rb +29 -0
- metadata +201 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: dfcdbe41de11ca908dfaf1b12e58262dba9966cc7b319d57fc48c9e455d36360
|
4
|
+
data.tar.gz: f048ec52470a044ae883262dbfe51ee706bd2a8339a2298c014c642ac4e92e53
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 870645d6c67d40a2ca3eb7f6d70186408cfd622534eb89040008683298e68ae4c84a9137f6144771afe9003844b6fb3d7339fbb0eb1085f8c9c3835464ed54cc
|
7
|
+
data.tar.gz: 134d7401cfd15c6192f6f8974dd3fb13bf829e7e707632dba50166ecc26a422fe081a94b2cfccc78d37c749cc90293bc08abc50d3b07c9ce51a8fa2a8dc83408
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Trx
|
2
|
+
module Abi
|
3
|
+
class ContractEvent
|
4
|
+
|
5
|
+
attr_accessor :name, :signature, :input_types, :inputs, :event_string, :address, :client
|
6
|
+
|
7
|
+
def initialize(data)
|
8
|
+
@name = data["name"]
|
9
|
+
@input_types = data.fetch("inputs", []).map {|x| x["type"]}
|
10
|
+
@inputs = data.fetch("inputs", []).map {|x| x["name"]}
|
11
|
+
@event_string = "#{@name}(#{@input_types.join(",")})"
|
12
|
+
@signature = Digest::Keccak.hexdigest(@event_string, 256)
|
13
|
+
end
|
14
|
+
|
15
|
+
def set_address(address)
|
16
|
+
@address = address
|
17
|
+
end
|
18
|
+
|
19
|
+
def set_client(client)
|
20
|
+
@client = client
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module Trx
|
2
|
+
module Abi
|
3
|
+
class Decoder
|
4
|
+
|
5
|
+
def decode(type, value, start = 0)
|
6
|
+
is_array, arity, array_subtype = Abi::parse_array_type(type)
|
7
|
+
if is_array && arity
|
8
|
+
decode_static_array(arity, array_subtype, value, start)
|
9
|
+
elsif is_array
|
10
|
+
decode_dynamic_array(array_subtype, value, start)
|
11
|
+
else
|
12
|
+
value = value.gsub(/^0x/,'')
|
13
|
+
core, subtype = Abi::parse_type(type)
|
14
|
+
method_name = "decode_#{core}".to_sym
|
15
|
+
self.send(method_name, value, subtype, start)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def decode_static_array(arity, array_subtype, value, start)
|
20
|
+
(0..arity-1).map { |i| decode(array_subtype, value, start + i * 64) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def decode_dynamic_array(array_subtype, value, start)
|
24
|
+
location = decode_uint(value[start..(start+63)]) * 2
|
25
|
+
size = decode_uint(value[location..location+63])
|
26
|
+
(0..size-1).map { |i| decode(array_subtype, value, location + (i+1) * 64) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def decode_fixed(value, subtype = "128x128", start = 0)
|
30
|
+
decode_int(trim(value, start, fixed_bitsize(subtype))).to_f / 2**exponent(subtype)
|
31
|
+
end
|
32
|
+
|
33
|
+
def decode_uint(value, subtype = "256", start = 0)
|
34
|
+
trim(value, start, bitsize(subtype)).hex
|
35
|
+
end
|
36
|
+
|
37
|
+
def decode_int(value, subtype = "256", start = 0)
|
38
|
+
raise ArgumentError if value.nil?
|
39
|
+
size = bitsize(subtype)
|
40
|
+
value = trim(value, start, size)
|
41
|
+
(value[0..1] == "ff") ? (value.hex - (2 ** size)) : value.hex
|
42
|
+
end
|
43
|
+
|
44
|
+
def decode_bool(value, _, start)
|
45
|
+
value = trim(value, start, 4)
|
46
|
+
return true if value == "1"
|
47
|
+
return false if value == "0"
|
48
|
+
raise ArgumentError
|
49
|
+
end
|
50
|
+
|
51
|
+
def decode_address(value, _ = nil, start)
|
52
|
+
raise ArgumentError if value.size-start < 64
|
53
|
+
value[start+24..start+63]
|
54
|
+
end
|
55
|
+
|
56
|
+
def decode_bytes(value, subtype, start)
|
57
|
+
subtype.present? ? decode_static_bytes(value, subtype, start) : decode_dynamic_bytes(value, start)
|
58
|
+
end
|
59
|
+
|
60
|
+
def decode_static_bytes(value, subtype = nil, start = 0)
|
61
|
+
trim(value, start, subtype.to_i*8).scan(/.{2}/).map {|x| x.hex}.pack('C*').strip
|
62
|
+
end
|
63
|
+
|
64
|
+
def decode_dynamic_bytes(value, start = 0)
|
65
|
+
location = decode_uint(value[start..(start+63)]) * 2
|
66
|
+
size = decode_uint(value[location..location+63]) * 2
|
67
|
+
value[location+64..location+63+size].scan(/.{2}/).map {|x| x.hex}.pack('C*')
|
68
|
+
end
|
69
|
+
|
70
|
+
def decode_string(value, _ = nil, start = 0)
|
71
|
+
decode_dynamic_bytes(value, start).force_encoding('utf-8')
|
72
|
+
end
|
73
|
+
|
74
|
+
def decode_arguments(arguments, data)
|
75
|
+
data = data.gsub(/^0x/,'')
|
76
|
+
types = arguments.map { |o| o.type }
|
77
|
+
types.each.with_index.map { |t , i| decode(t, data, i*64) }
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
def trim(value, start, bitsize = 256)
|
82
|
+
value[start+63-(bitsize/4-1)..start+63]
|
83
|
+
end
|
84
|
+
|
85
|
+
def bitsize(subtype, default = 256)
|
86
|
+
subtype.present? ? subtype.to_i : default
|
87
|
+
end
|
88
|
+
|
89
|
+
def fixed_bitsize(subtype = nil)
|
90
|
+
subtype ||= "128x128"
|
91
|
+
_, x, n = /(\d+)x(\d+)/.match(subtype).to_a
|
92
|
+
x.to_i + n.to_i
|
93
|
+
end
|
94
|
+
|
95
|
+
def exponent(subtype, default = 128)
|
96
|
+
subtype.nil? ? default : /(\d+)x(\d+)/.match(subtype)[2].to_i
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module Trx
|
2
|
+
|
3
|
+
module Abi
|
4
|
+
class Encoder
|
5
|
+
|
6
|
+
def encode(type, value)
|
7
|
+
is_array, arity, array_subtype = Abi::parse_array_type(type)
|
8
|
+
if is_array && arity
|
9
|
+
encode_static_array(arity, array_subtype, value)
|
10
|
+
elsif is_array
|
11
|
+
encode_dynamic_array(array_subtype, value)
|
12
|
+
else
|
13
|
+
core, subtype = Abi::parse_type(type)
|
14
|
+
method_name = "encode_#{core}".to_sym
|
15
|
+
self.send(method_name, value, subtype)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def encode_static_array(arity, array_subtype, array)
|
20
|
+
raise "Wrong number of arguments" if arity != array.size
|
21
|
+
array.inject("") { |a, e| a << encode(array_subtype, e) }
|
22
|
+
end
|
23
|
+
|
24
|
+
def encode_dynamic_array(array_subtype, array)
|
25
|
+
location = encode_uint(@inputs ? size_of_inputs(@inputs) + @tail.size/2 : 32)
|
26
|
+
size = encode_uint(array.size)
|
27
|
+
data = array.inject("") { |a, e| a << encode(array_subtype, e) }
|
28
|
+
[location, size + data]
|
29
|
+
end
|
30
|
+
|
31
|
+
def encode_int(value, _ = nil)
|
32
|
+
to_twos_complement(value).to_s(16).rjust(64, '0')
|
33
|
+
end
|
34
|
+
|
35
|
+
def encode_uint(value, _ = nil)
|
36
|
+
raise ArgumentError if value < 0
|
37
|
+
encode_int(value)
|
38
|
+
end
|
39
|
+
|
40
|
+
def encode_bool(value, _)
|
41
|
+
(value ? "1" : "0").rjust(64, '0')
|
42
|
+
end
|
43
|
+
|
44
|
+
def encode_fixed(value, subtype)
|
45
|
+
n = subtype.nil? ? 128 : /(\d+)x(\d+)/.match(subtype)[2].to_i
|
46
|
+
do_encode_fixed(value, n)
|
47
|
+
end
|
48
|
+
|
49
|
+
def do_encode_fixed(value, n)
|
50
|
+
encode_uint((value * 2**n).to_i)
|
51
|
+
end
|
52
|
+
|
53
|
+
def encode_ufixed(_value, _)
|
54
|
+
raise NotImplementedError
|
55
|
+
end
|
56
|
+
|
57
|
+
def encode_bytes(value, subtype)
|
58
|
+
subtype.nil? ? encode_dynamic_bytes(value) : encode_static_bytes(value)
|
59
|
+
end
|
60
|
+
|
61
|
+
def encode_static_bytes(value)
|
62
|
+
value.bytes.map {|x| x.to_s(16).rjust(2, '0')}.join("").ljust(64, '0')
|
63
|
+
end
|
64
|
+
|
65
|
+
def encode_dynamic_bytes(value)
|
66
|
+
location = encode_uint(@inputs ? size_of_inputs(@inputs) + @tail.size/2 : 32)
|
67
|
+
size = encode_uint(value.size)
|
68
|
+
content = encode_static_bytes(value)
|
69
|
+
[location, size + content]
|
70
|
+
end
|
71
|
+
|
72
|
+
def encode_string(value, _)
|
73
|
+
location = encode_uint(@inputs ? size_of_inputs(@inputs) + @tail.size/2 : 32)
|
74
|
+
size = encode_uint(value.bytes.size)
|
75
|
+
content = value.bytes.map {|x| x.to_s(16).rjust(2, '0')}.join("").ljust(64, '0')
|
76
|
+
[location, size + content]
|
77
|
+
end
|
78
|
+
|
79
|
+
def encode_address(value, _)
|
80
|
+
value = "0" * 24 + value.gsub(/^0x/,'')
|
81
|
+
raise ArgumentError if value.size != 64
|
82
|
+
value
|
83
|
+
end
|
84
|
+
|
85
|
+
def ensure_prefix(value)
|
86
|
+
value.start_with?("0x") ? value : ("0x" + value)
|
87
|
+
end
|
88
|
+
|
89
|
+
def encode_arguments(inputs, args)
|
90
|
+
raise "Wrong number of arguments" if inputs.length != args.length
|
91
|
+
@head = ""
|
92
|
+
@tail = ""
|
93
|
+
@inputs = inputs
|
94
|
+
inputs.each.with_index do |input, index|
|
95
|
+
encoded = encode(input.type, args[index])
|
96
|
+
if encoded.is_a? Array
|
97
|
+
@head << encoded[0]
|
98
|
+
@tail << encoded[1]
|
99
|
+
else
|
100
|
+
@head << encoded
|
101
|
+
end
|
102
|
+
end
|
103
|
+
@head + @tail
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
def to_twos_complement(number)
|
108
|
+
(number & ((1 << 256) - 1))
|
109
|
+
end
|
110
|
+
|
111
|
+
def size_of_inputs(inputs)
|
112
|
+
inputs.map do |input|
|
113
|
+
_, arity, _ = Abi::parse_array_type(input.type)
|
114
|
+
arity.nil? ? 32 : arity * 32
|
115
|
+
end.inject(:+)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Trx
|
2
|
+
module Abi
|
3
|
+
class Function
|
4
|
+
|
5
|
+
attr_accessor :name, :inputs, :outputs, :signature, :constant, :function_string
|
6
|
+
|
7
|
+
def initialize(data)
|
8
|
+
@name = data["name"]
|
9
|
+
@constant = data["constant"]
|
10
|
+
@inputs = data.fetch("inputs", []).map do |input|
|
11
|
+
FunctionInput.new(input)
|
12
|
+
end
|
13
|
+
@outputs = data.fetch("outputs", []).map do |output|
|
14
|
+
FunctionOutput.new(output)
|
15
|
+
end
|
16
|
+
@function_string = self.class.calc_signature(@name, @inputs)
|
17
|
+
@signature = self.class.calc_id(@function_string)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.to_canonical_type(type)
|
21
|
+
type
|
22
|
+
.gsub(/(int)(\z|\D)/, '\1256\2')
|
23
|
+
.gsub(/(uint)(\z|\D)/, '\1256\2')
|
24
|
+
.gsub(/(fixed)(\z|\D)/, '\1128x128\2')
|
25
|
+
.gsub(/(ufixed)(\z|\D)/, '\1128x128\2')
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.calc_signature(name, inputs)
|
29
|
+
"#{name}(#{inputs.map {|x| self.to_canonical_type(x.type) }.join(",")})"
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.calc_id(signature)
|
33
|
+
Digest::Keccak.hexdigest(signature, 256)[0..7]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/trx/abi.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module Trx
|
2
|
+
module Abi
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def parse_abi(abi)
|
6
|
+
constructor = abi.detect {|x| x["type"].downcase == "constructor"}
|
7
|
+
if constructor.present?
|
8
|
+
constructor_inputs = constructor["inputs"].map { |input| FunctionInput.new(input) }
|
9
|
+
else
|
10
|
+
constructor_inputs = []
|
11
|
+
end
|
12
|
+
functions = abi.select {|x| x["type"].downcase == "function" }.map { |fun| Function.new(fun) }
|
13
|
+
events = abi.select {|x| x["type"].downcase == "event" }.map { |evt| ContractEvent.new(evt) }
|
14
|
+
[constructor_inputs, functions, events]
|
15
|
+
end
|
16
|
+
|
17
|
+
def parse_type(type)
|
18
|
+
raise NotImplementedError if type.ends_with?("]")
|
19
|
+
match = /(\D+)(\d.*)?/.match(type)
|
20
|
+
[match[1], match[2]]
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse_array_type(type)
|
24
|
+
match = /(.+)\[(\d*)\]\z/.match(type)
|
25
|
+
if match
|
26
|
+
[true, match[2].present? ? match[2].to_i : nil, match[1]]
|
27
|
+
else
|
28
|
+
[false, nil, nil]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
data/lib/trx/address.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Trx
|
4
|
+
class Address
|
5
|
+
ADDRESS_PREFIX = "41"
|
6
|
+
|
7
|
+
def self.from_public_hex(public_hex)
|
8
|
+
raise ArgumentError, "Expected String, got #{public_hex.class}" unless public_hex.is_a?(String)
|
9
|
+
|
10
|
+
bytes = Utils.hex_to_bin(public_hex)
|
11
|
+
address_bytes = Utils.keccak256(bytes[1..-1])[-20..-1]
|
12
|
+
prefixed_address_hex = ADDRESS_PREFIX + RLP::Utils.encode_hex(address_bytes)
|
13
|
+
prefixed_address_bytes = Utils.hex_to_bin(prefixed_address_hex)
|
14
|
+
checksum = Utils.base58check(prefixed_address_bytes).hexdigest[0..7]
|
15
|
+
base58check_adress = Base58.encode_hex(prefixed_address_hex + checksum)
|
16
|
+
|
17
|
+
Address.new(base58check_adress)
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :address
|
21
|
+
|
22
|
+
def initialize(address)
|
23
|
+
raise ArgumentError, "Expected String, got #{address.class}" unless address.is_a?(String)
|
24
|
+
|
25
|
+
@address = Utils.prefix_hex(address)
|
26
|
+
end
|
27
|
+
|
28
|
+
def checksum_matches?
|
29
|
+
computed_checksum = Utils.sha256(
|
30
|
+
Utils.sha256(to_bytes).digest
|
31
|
+
).hexdigest[0..7]
|
32
|
+
|
33
|
+
checksum_hex == computed_checksum
|
34
|
+
end
|
35
|
+
alias_method :valid?, :checksum_matches?
|
36
|
+
|
37
|
+
def to_bytes
|
38
|
+
Utils.hex_to_bin(to_base58_decode_hex)[0..-5]
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_base58_decode_hex
|
42
|
+
Utils.base58_decode_hex(address)
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_hex
|
46
|
+
Utils.base58_decode_hex(address)[0..-9]
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_s
|
50
|
+
Utils.remove_hex_prefix(address)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def checksum_bytes
|
56
|
+
bytes[0..3]
|
57
|
+
end
|
58
|
+
|
59
|
+
def checksum_hex
|
60
|
+
to_base58_decode_hex[-8..-1]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Trx
|
2
|
+
class HttpClient
|
3
|
+
attr_reader :host, :timeout, :trongrig_token, :headers, :raise_error
|
4
|
+
|
5
|
+
MAINNET_HOST = "https://api.trongrid.io"
|
6
|
+
SHASTA_HOST = "https://api.shasta.trongrid.io"
|
7
|
+
NILE_HOST = "https://nile.trongrid.io"
|
8
|
+
|
9
|
+
def initialize(host = nil, timeout: 10, trongrig_token: nil, headers: {}, raise_error: true)
|
10
|
+
@host = host
|
11
|
+
@timeout = timeout
|
12
|
+
@trongrig_token = trongrig_token
|
13
|
+
@headers = headers
|
14
|
+
@raise_error = raise_error
|
15
|
+
end
|
16
|
+
|
17
|
+
def perform_command(command, params, method: :post)
|
18
|
+
connection.public_send(method, command, params).body
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def connection
|
24
|
+
@_connection ||= Faraday.new(host) do |builder|
|
25
|
+
builder.options.timeout = timeout
|
26
|
+
builder.use Faraday::Response::RaiseError if raise_error
|
27
|
+
builder.request :url_encoded
|
28
|
+
builder.response :json
|
29
|
+
builder.adapter Faraday.default_adapter
|
30
|
+
builder.headers['TRON-PRO-API-KEY'] = trongrig_token unless trongrig_token.nil?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/trx/key.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Trx
|
4
|
+
class Key
|
5
|
+
attr_reader :private_key, :public_key
|
6
|
+
|
7
|
+
def initialize(priv: nil)
|
8
|
+
|
9
|
+
# Creates a new, randomized libsecp256k1 context.
|
10
|
+
ctx = Secp256k1::Context.new context_randomization_bytes: SecureRandom.random_bytes(32)
|
11
|
+
|
12
|
+
key = if priv.nil?
|
13
|
+
# Creates a new random key pair (public, private).
|
14
|
+
ctx.generate_key_pair
|
15
|
+
else
|
16
|
+
|
17
|
+
# Converts hex private keys to binary strings.
|
18
|
+
priv = Utils.hex_to_bin priv if Utils.is_hex? priv
|
19
|
+
|
20
|
+
# Creates a keypair from existing private key data.
|
21
|
+
ctx.key_pair_from_private_key priv
|
22
|
+
end
|
23
|
+
|
24
|
+
# Sets the attributes.
|
25
|
+
@private_key = key.private_key
|
26
|
+
@public_key = key.public_key
|
27
|
+
end
|
28
|
+
|
29
|
+
def private_hex
|
30
|
+
Utils.bin_to_hex @private_key.data
|
31
|
+
end
|
32
|
+
|
33
|
+
def private_bytes
|
34
|
+
@private_key.data
|
35
|
+
end
|
36
|
+
|
37
|
+
def public_hex
|
38
|
+
Utils.bin_to_hex @public_key.uncompressed
|
39
|
+
end
|
40
|
+
|
41
|
+
def public_hex_compressed
|
42
|
+
Utils.bin_to_hex @public_key.compressed
|
43
|
+
end
|
44
|
+
|
45
|
+
def public_bytes
|
46
|
+
@public_key.uncompressed
|
47
|
+
end
|
48
|
+
|
49
|
+
def public_bytes_compressed
|
50
|
+
@public_key.compressed
|
51
|
+
end
|
52
|
+
|
53
|
+
def address
|
54
|
+
Address.from_public_hex public_hex
|
55
|
+
end
|
56
|
+
|
57
|
+
def sign(blob)
|
58
|
+
context = Secp256k1::Context.new
|
59
|
+
compact, recovery_id = context.sign_recoverable(@private_key, blob).compact
|
60
|
+
signature = compact.bytes
|
61
|
+
is_leading_zero = true
|
62
|
+
signature.append recovery_id
|
63
|
+
|
64
|
+
# TODO: WTF? It is necessary?
|
65
|
+
|
66
|
+
# [recovery_id].pack("N").unpack("C*").each do |byte|
|
67
|
+
# is_leading_zero = false if byte > 0 and is_leading_zero
|
68
|
+
# unless is_leading_zero and byte === 0
|
69
|
+
# signature.append recovery_id
|
70
|
+
# end
|
71
|
+
# end
|
72
|
+
|
73
|
+
Utils.bin_to_hex signature.pack "c*"
|
74
|
+
end
|
75
|
+
|
76
|
+
def personal_sign(message)
|
77
|
+
prefixed_message = Signature.prefix_message message
|
78
|
+
hashed_message = Utils.keccak256 prefixed_message
|
79
|
+
sign hashed_message
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Trx
|
4
|
+
module Signature
|
5
|
+
class SignatureError < StandardError; end
|
6
|
+
extend self
|
7
|
+
|
8
|
+
PREFIX_BYTE = "\x19".freeze
|
9
|
+
|
10
|
+
def prefix_message(message)
|
11
|
+
"#{PREFIX_BYTE}Tron Signed Message:\n#{message.size}#{message}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/trx/utils.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Trx
|
4
|
+
module Utils
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def hex_to_bin(string)
|
8
|
+
RLP::Utils.decode_hex remove_hex_prefix(string)
|
9
|
+
end
|
10
|
+
|
11
|
+
def bin_to_hex(bytes)
|
12
|
+
RLP::Utils.encode_hex bytes
|
13
|
+
end
|
14
|
+
|
15
|
+
def remove_hex_prefix(string)
|
16
|
+
string[0, 2] == "0x" ? string[2..-1] : string
|
17
|
+
end
|
18
|
+
|
19
|
+
def prefix_hex(hex)
|
20
|
+
hex.match(/\A0x/) ? hex : "0x#{hex}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def keccak256(value)
|
24
|
+
Digest::Keccak.new(256).digest(value)
|
25
|
+
end
|
26
|
+
|
27
|
+
def base58check(value)
|
28
|
+
sha256(sha256(value).digest)
|
29
|
+
end
|
30
|
+
|
31
|
+
def base58_decode_hex(hex)
|
32
|
+
Base58.decode_hex(remove_hex_prefix(hex))
|
33
|
+
end
|
34
|
+
|
35
|
+
def sha256(value)
|
36
|
+
hash = OpenSSL::Digest.new("SHA256")
|
37
|
+
hash.update(value)
|
38
|
+
|
39
|
+
hash
|
40
|
+
end
|
41
|
+
|
42
|
+
def is_hex?(str)
|
43
|
+
return false unless str.is_a? String
|
44
|
+
str = remove_hex_prefix str
|
45
|
+
str.match /\A[0-9a-fA-F]*\z/
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/trx/version.rb
ADDED
data/lib/trx.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "digest/keccak"
|
4
|
+
require "rlp"
|
5
|
+
require "openssl"
|
6
|
+
require "base58-alphabets"
|
7
|
+
require "rbsecp256k1"
|
8
|
+
require "securerandom"
|
9
|
+
require "faraday"
|
10
|
+
require "active_support"
|
11
|
+
require "active_support/core_ext"
|
12
|
+
|
13
|
+
require_relative "trx/utils"
|
14
|
+
require_relative "trx/signature"
|
15
|
+
require_relative "trx/key"
|
16
|
+
require_relative "trx/address"
|
17
|
+
require_relative "trx/version"
|
18
|
+
require_relative "trx/http_client"
|
19
|
+
require_relative "trx/abi"
|
20
|
+
require_relative "trx/abi/encoder"
|
21
|
+
require_relative "trx/abi/decoder"
|
22
|
+
require_relative "trx/abi/function"
|
23
|
+
require_relative "trx/abi/function_input"
|
24
|
+
require_relative "trx/abi/function_output"
|
25
|
+
require_relative "trx/abi/contract_event"
|
26
|
+
|
27
|
+
module Trx
|
28
|
+
class Error < StandardError; end
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: trx
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Anton Kostyuk
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-02-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.2'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pry
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.14'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.14'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: ecdsa
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.2'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.2'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: faraday
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.2.0
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.2.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: keccak
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.3.0
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.3.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rlp
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.7.3
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.7.3
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rbsecp256k1
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '5.1'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '5.1'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: securerandom
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: base58-alphabets
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '1.0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '1.0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: activesupport
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '4.2'
|
146
|
+
type: :runtime
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '4.2'
|
153
|
+
description: ''
|
154
|
+
email:
|
155
|
+
- anton.kostuk.2012@gmail.com
|
156
|
+
executables: []
|
157
|
+
extensions: []
|
158
|
+
extra_rdoc_files: []
|
159
|
+
files:
|
160
|
+
- lib/trx.rb
|
161
|
+
- lib/trx/abi.rb
|
162
|
+
- lib/trx/abi/contract_event.rb
|
163
|
+
- lib/trx/abi/decoder.rb
|
164
|
+
- lib/trx/abi/encoder.rb
|
165
|
+
- lib/trx/abi/function.rb
|
166
|
+
- lib/trx/abi/function_input.rb
|
167
|
+
- lib/trx/abi/function_output.rb
|
168
|
+
- lib/trx/address.rb
|
169
|
+
- lib/trx/http_client.rb
|
170
|
+
- lib/trx/key.rb
|
171
|
+
- lib/trx/signature.rb
|
172
|
+
- lib/trx/utils.rb
|
173
|
+
- lib/trx/version.rb
|
174
|
+
homepage: https://github.com/RainbowPonny/trx-rb
|
175
|
+
licenses:
|
176
|
+
- MIT
|
177
|
+
metadata:
|
178
|
+
homepage_uri: https://github.com/RainbowPonny/trx-rb
|
179
|
+
source_code_uri: https://github.com/RainbowPonny/trx-rb
|
180
|
+
changelog_uri: https://github.com/RainbowPonny/trx-rb
|
181
|
+
rubygems_mfa_required: 'true'
|
182
|
+
post_install_message:
|
183
|
+
rdoc_options: []
|
184
|
+
require_paths:
|
185
|
+
- lib
|
186
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
187
|
+
requirements:
|
188
|
+
- - ">="
|
189
|
+
- !ruby/object:Gem::Version
|
190
|
+
version: 2.5.0
|
191
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
192
|
+
requirements:
|
193
|
+
- - ">="
|
194
|
+
- !ruby/object:Gem::Version
|
195
|
+
version: '0'
|
196
|
+
requirements: []
|
197
|
+
rubygems_version: 3.3.7
|
198
|
+
signing_key:
|
199
|
+
specification_version: 4
|
200
|
+
summary: TRON HTTP API client
|
201
|
+
test_files: []
|