platon 0.2.7
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 +7 -0
- data/.github/workflows/main.yml +18 -0
- data/.gitignore +15 -0
- data/.rspec +3 -0
- data/.rubocop.yml +10 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +69 -0
- data/LICENSE.txt +21 -0
- data/README.md +216 -0
- data/Rakefile +12 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/doc/zh-cn.md +1762 -0
- data/lib/bech32.rb +82 -0
- data/lib/platon.rb +77 -0
- data/lib/platon/abi.rb +32 -0
- data/lib/platon/address.rb +62 -0
- data/lib/platon/client.rb +175 -0
- data/lib/platon/contract.rb +351 -0
- data/lib/platon/contract_event.rb +24 -0
- data/lib/platon/contract_initializer.rb +54 -0
- data/lib/platon/decoder.rb +99 -0
- data/lib/platon/deployment.rb +49 -0
- data/lib/platon/encoder.rb +120 -0
- data/lib/platon/explorer_url_helper.rb +0 -0
- data/lib/platon/formatter.rb +142 -0
- data/lib/platon/function.rb +36 -0
- data/lib/platon/function_input.rb +13 -0
- data/lib/platon/function_output.rb +14 -0
- data/lib/platon/gas.rb +9 -0
- data/lib/platon/http_client.rb +55 -0
- data/lib/platon/initializer.rb +0 -0
- data/lib/platon/ipc_client.rb +45 -0
- data/lib/platon/key.rb +105 -0
- data/lib/platon/key/decrypter.rb +113 -0
- data/lib/platon/key/encrypter.rb +128 -0
- data/lib/platon/open_ssl.rb +267 -0
- data/lib/platon/ppos.rb +344 -0
- data/lib/platon/railtie.rb +0 -0
- data/lib/platon/secp256k1.rb +7 -0
- data/lib/platon/sedes.rb +40 -0
- data/lib/platon/segwit_addr.rb +66 -0
- data/lib/platon/singleton.rb +39 -0
- data/lib/platon/solidity.rb +40 -0
- data/lib/platon/transaction.rb +41 -0
- data/lib/platon/tx.rb +201 -0
- data/lib/platon/utils.rb +180 -0
- data/lib/platon/version.rb +5 -0
- data/lib/tasks/platon_contract.rake +27 -0
- data/platon-ruby-logo.png +0 -0
- data/platon.gemspec +50 -0
- metadata +235 -0
File without changes
|
data/lib/platon/sedes.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module Platon
|
2
|
+
module Sedes
|
3
|
+
include RLP::Sedes
|
4
|
+
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def address
|
8
|
+
Binary.fixed_length(20, allow_empty: true)
|
9
|
+
end
|
10
|
+
|
11
|
+
def int20
|
12
|
+
BigEndianInt.new(20)
|
13
|
+
end
|
14
|
+
|
15
|
+
def int32
|
16
|
+
BigEndianInt.new(32)
|
17
|
+
end
|
18
|
+
|
19
|
+
def int256
|
20
|
+
BigEndianInt.new(256)
|
21
|
+
end
|
22
|
+
|
23
|
+
def hash32
|
24
|
+
Binary.fixed_length(32)
|
25
|
+
end
|
26
|
+
|
27
|
+
def trie_root
|
28
|
+
Binary.fixed_length(32, allow_empty: true)
|
29
|
+
end
|
30
|
+
|
31
|
+
def big_endian_int
|
32
|
+
RLP::Sedes.big_endian_int
|
33
|
+
end
|
34
|
+
|
35
|
+
def binary
|
36
|
+
RLP::Sedes.binary
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Platon
|
2
|
+
|
3
|
+
class SegwitAddr
|
4
|
+
|
5
|
+
HRP_MAINNET = 'lat' ### TODO
|
6
|
+
HRP_TESTNET = 'atp'
|
7
|
+
HRP_REGTEST = 'atx'
|
8
|
+
|
9
|
+
attr_accessor :hrp # human-readable part
|
10
|
+
attr_accessor :ver # witness version
|
11
|
+
attr_accessor :prog # witness program
|
12
|
+
|
13
|
+
def initialize(addr = nil)
|
14
|
+
@hrp = HRP_TESTNET ## TODO
|
15
|
+
parse_addr(addr) if addr
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns segwit script pubkey which generated from witness version and witness program.
|
19
|
+
def to_script_pubkey
|
20
|
+
(prog.map{|p|[p].pack("C")}.join).unpack('H*').first
|
21
|
+
end
|
22
|
+
|
23
|
+
# parse script pubkey into witness version and witness program
|
24
|
+
def script_pubkey=(script_pubkey)
|
25
|
+
@prog = [script_pubkey].pack('H*').unpack("C*")
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns segwit address string which generated from hrp, witness version and witness program.
|
29
|
+
def addr
|
30
|
+
Bech32.encode(hrp, convert_bits(prog, 8, 5), 1)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def parse_addr(addr)
|
36
|
+
@hrp, data, spec = Bech32.decode(addr)
|
37
|
+
raise 'Invalid address.' if hrp.nil? || data[0].nil? || ![HRP_MAINNET, HRP_TESTNET, HRP_REGTEST].include?(hrp) #TODO
|
38
|
+
@ver = data[0]
|
39
|
+
@prog = convert_bits(data, 5, 8, false)
|
40
|
+
end
|
41
|
+
|
42
|
+
def convert_bits(data, from, to, padding=true)
|
43
|
+
acc = 0
|
44
|
+
bits = 0
|
45
|
+
ret = []
|
46
|
+
maxv = (1 << to) - 1
|
47
|
+
max_acc = (1 << (from + to - 1)) - 1
|
48
|
+
data.each do |v|
|
49
|
+
return nil if v < 0 || (v >> from) != 0
|
50
|
+
acc = ((acc << from) | v) & max_acc
|
51
|
+
bits += from
|
52
|
+
while bits >= to
|
53
|
+
bits -= to
|
54
|
+
ret << ((acc >> bits) & maxv)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
if padding
|
58
|
+
ret << ((acc << (to - bits)) & maxv) unless bits == 0
|
59
|
+
elsif bits >= from || ((acc << (to - bits)) & maxv) != 0
|
60
|
+
return nil
|
61
|
+
end
|
62
|
+
ret
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class Platon::Singleton
|
2
|
+
|
3
|
+
class << self
|
4
|
+
|
5
|
+
attr_accessor :client, :ipcpath, :host, :log, :instance, :default_account
|
6
|
+
|
7
|
+
def instance
|
8
|
+
@instance ||= configure_instance(create_instance)
|
9
|
+
end
|
10
|
+
|
11
|
+
def setup
|
12
|
+
yield(self)
|
13
|
+
end
|
14
|
+
|
15
|
+
def reset
|
16
|
+
@instance = nil
|
17
|
+
@client = nil
|
18
|
+
@host = nil
|
19
|
+
@log = nil
|
20
|
+
@ipcpath = nil
|
21
|
+
@default_account = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def create_instance
|
26
|
+
return Platon::IpcClient.new(@ipcpath) if @client == :ipc
|
27
|
+
return Platon::HttpClient.new(@host) if @client == :http
|
28
|
+
Platon::IpcClient.new
|
29
|
+
end
|
30
|
+
|
31
|
+
def configure_instance(instance)
|
32
|
+
instance.tap do |i|
|
33
|
+
i.default_account = @default_account if @default_account.present?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
require 'open3'
|
3
|
+
|
4
|
+
module Platon
|
5
|
+
class CompilationError < StandardError;
|
6
|
+
def initialize(msg)
|
7
|
+
super
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Solidity
|
12
|
+
|
13
|
+
OUTPUT_REGEXP = /======= (\S*):(\S*) =======\s*Binary:\s*(\S*)\s*Contract JSON ABI\s*(.*)/
|
14
|
+
|
15
|
+
def initialize(bin_path = "solc")
|
16
|
+
@bin_path = bin_path
|
17
|
+
@args = "--bin --abi --optimize"
|
18
|
+
end
|
19
|
+
|
20
|
+
def compile(filename)
|
21
|
+
result = {}
|
22
|
+
execute_solc(filename).scan(OUTPUT_REGEXP).each do |match|
|
23
|
+
_file, name, bin, abi = match
|
24
|
+
result[name] = {}
|
25
|
+
result[name]["abi"] = abi
|
26
|
+
result[name]["bin"] = bin
|
27
|
+
end
|
28
|
+
result
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def execute_solc(filename)
|
33
|
+
p cmd = "#{@bin_path} #{@args} '#{filename}'"
|
34
|
+
out, stderr, status = Open3.capture3(cmd)
|
35
|
+
raise SystemCallError, "Unanable to run solc compliers" if status.exitstatus == 127
|
36
|
+
raise CompilationError, stderr unless status.exitstatus == 0
|
37
|
+
out
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Platon
|
2
|
+
|
3
|
+
class Transaction
|
4
|
+
|
5
|
+
DEFAULT_TIMEOUT = 300.seconds
|
6
|
+
DEFAULT_STEP = 5.seconds
|
7
|
+
|
8
|
+
attr_accessor :id, :mined, :connection, :input, :input_parameters
|
9
|
+
|
10
|
+
def initialize(id, connection, data, input_parameters = [])
|
11
|
+
@mined = false
|
12
|
+
@connection = connection
|
13
|
+
@id = id
|
14
|
+
@input = data
|
15
|
+
@input_parameters = input_parameters
|
16
|
+
end
|
17
|
+
|
18
|
+
def address
|
19
|
+
@id
|
20
|
+
end
|
21
|
+
|
22
|
+
def mined?
|
23
|
+
return true if @mined
|
24
|
+
tx = @connection.platon_get_transaction_by_hash(@id)
|
25
|
+
@mined = !tx.nil? && tx["blockNumber"].present?
|
26
|
+
end
|
27
|
+
|
28
|
+
def wait_for_miner(timeout: DEFAULT_TIMEOUT, step: DEFAULT_STEP)
|
29
|
+
start_time = Time.now
|
30
|
+
loop do
|
31
|
+
raise Timeout::Error if ((Time.now - start_time) > timeout)
|
32
|
+
return true if self.mined?
|
33
|
+
sleep step
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.from_blockchain(address, connection = IpcClient.new)
|
38
|
+
Transaction.new(address, connection, nil, nil)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/platon/tx.rb
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
module Platon
|
2
|
+
class Tx
|
3
|
+
|
4
|
+
include RLP::Sedes::Serializable
|
5
|
+
extend Sedes
|
6
|
+
|
7
|
+
set_serializable_fields({
|
8
|
+
nonce: big_endian_int,
|
9
|
+
gas_price: big_endian_int,
|
10
|
+
gas_limit: big_endian_int,
|
11
|
+
to: address,
|
12
|
+
value: big_endian_int,
|
13
|
+
data_bin: binary,
|
14
|
+
v: big_endian_int,
|
15
|
+
r: big_endian_int,
|
16
|
+
s: big_endian_int
|
17
|
+
})
|
18
|
+
|
19
|
+
attr_writer :signature
|
20
|
+
|
21
|
+
def self.decode(data)
|
22
|
+
data = Utils.hex_to_bin(data) if data.match(/\A(?:0x)?\h+\Z/)
|
23
|
+
txh = deserialize(RLP.decode data).to_h
|
24
|
+
|
25
|
+
txh[:chain_id] = Platon.chain_id_from_signature(txh)
|
26
|
+
|
27
|
+
self.new txh
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(params)
|
31
|
+
fields = {v: 0, r: 0, s: 0}.merge params
|
32
|
+
fields[:to] = Utils.normalize_address(fields[:to])
|
33
|
+
|
34
|
+
self.chain_id = (params[:chain_id]) ? params.delete(:chain_id) : nil
|
35
|
+
|
36
|
+
if params[:data]
|
37
|
+
self.data = params.delete(:data)
|
38
|
+
fields[:data_bin] = data_bin
|
39
|
+
end
|
40
|
+
serializable_initialize fields
|
41
|
+
|
42
|
+
check_transaction_validity
|
43
|
+
end
|
44
|
+
|
45
|
+
def unsigned_encoded
|
46
|
+
us = unsigned
|
47
|
+
RLP.encode(us, sedes: us.sedes)
|
48
|
+
end
|
49
|
+
|
50
|
+
def signing_data
|
51
|
+
Utils.bin_to_prefixed_hex unsigned_encoded
|
52
|
+
end
|
53
|
+
|
54
|
+
def encoded
|
55
|
+
RLP.encode self
|
56
|
+
end
|
57
|
+
|
58
|
+
def hex
|
59
|
+
Utils.bin_to_prefixed_hex encoded
|
60
|
+
end
|
61
|
+
|
62
|
+
def sign(key)
|
63
|
+
sig = key.sign(unsigned_encoded)
|
64
|
+
vrs = Utils.v_r_s_for sig
|
65
|
+
self.v = self.chain_id ? ((self.chain_id * 2) + vrs[0] + 8) : vrs[0]
|
66
|
+
self.r = vrs[1]
|
67
|
+
self.s = vrs[2]
|
68
|
+
|
69
|
+
clear_signature
|
70
|
+
self
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_h
|
74
|
+
hash_keys.inject({}) do |hash, field|
|
75
|
+
hash[field] = send field
|
76
|
+
hash
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def from
|
81
|
+
if ecdsa_signature
|
82
|
+
public_key = OpenSsl.recover_compact(signature_hash, ecdsa_signature)
|
83
|
+
Utils.public_key_to_address(public_key) if public_key
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def signature
|
88
|
+
return @signature if @signature
|
89
|
+
@signature = { v: v, r: r, s: s } if [v, r, s].all? && (v > 0)
|
90
|
+
end
|
91
|
+
|
92
|
+
def ecdsa_signature
|
93
|
+
return @ecdsa_signature if @ecdsa_signature
|
94
|
+
|
95
|
+
if [v, r, s].all? && (v > 0)
|
96
|
+
s_v = (self.chain_id) ? (v - (self.chain_id * 2) - 8) : v
|
97
|
+
@ecdsa_signature = [
|
98
|
+
Utils.int_to_base256(s_v),
|
99
|
+
Utils.zpad_int(r),
|
100
|
+
Utils.zpad_int(s),
|
101
|
+
].join
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def hash
|
106
|
+
"0x#{Utils.bin_to_hex Utils.keccak256_rlp(self)}"
|
107
|
+
end
|
108
|
+
alias_method :id, :hash
|
109
|
+
|
110
|
+
def data_hex
|
111
|
+
Utils.bin_to_prefixed_hex data_bin
|
112
|
+
end
|
113
|
+
|
114
|
+
def data_hex=(hex)
|
115
|
+
self.data_bin = Utils.hex_to_bin(hex)
|
116
|
+
end
|
117
|
+
|
118
|
+
def data
|
119
|
+
true ? data_hex : data_bin
|
120
|
+
# Platon.tx_data_hex? ? data_hex : data_bin
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
def data=(string)
|
125
|
+
true ? self.data_hex=(string) : self.data_bin=(string)
|
126
|
+
# Platon.tx_data_hex? ? self.data_hex=(string) : self.data_bin=(string)
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
def chain_id
|
131
|
+
@chain_id
|
132
|
+
end
|
133
|
+
|
134
|
+
def chain_id=(cid)
|
135
|
+
if cid != @chain_id
|
136
|
+
self.v = 0
|
137
|
+
self.r = 0
|
138
|
+
self.s = 0
|
139
|
+
|
140
|
+
clear_signature
|
141
|
+
end
|
142
|
+
|
143
|
+
@chain_id = (cid == 0) ? nil : cid
|
144
|
+
end
|
145
|
+
|
146
|
+
def prevent_replays?
|
147
|
+
!self.chain_id.nil?
|
148
|
+
end
|
149
|
+
|
150
|
+
private
|
151
|
+
|
152
|
+
def clear_signature
|
153
|
+
@signature = nil
|
154
|
+
@ecdsa_signature = nil
|
155
|
+
end
|
156
|
+
|
157
|
+
def hash_keys
|
158
|
+
keys = self.class.serializable_fields.keys
|
159
|
+
keys.delete(:data_bin)
|
160
|
+
keys + [:data, :chain_id]
|
161
|
+
end
|
162
|
+
|
163
|
+
def check_transaction_validity
|
164
|
+
if [gas_price, gas_limit, value, nonce].max > UINT_MAX
|
165
|
+
raise InvalidTransaction, "Values way too high!"
|
166
|
+
elsif gas_limit < intrinsic_gas_used
|
167
|
+
raise InvalidTransaction, "Gas limit too low"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def intrinsic_gas_used
|
172
|
+
num_zero_bytes = data_bin.count(BYTE_ZERO)
|
173
|
+
num_non_zero_bytes = data_bin.size - num_zero_bytes
|
174
|
+
|
175
|
+
Gas::GTXCOST +
|
176
|
+
Gas::GTXDATAZERO * num_zero_bytes +
|
177
|
+
Gas::GTXDATANONZERO * num_non_zero_bytes
|
178
|
+
end
|
179
|
+
|
180
|
+
def signature_hash
|
181
|
+
Utils.keccak256 unsigned_encoded
|
182
|
+
end
|
183
|
+
|
184
|
+
def unsigned
|
185
|
+
Tx.new to_h.merge(v: (self.chain_id) ? self.chain_id : 0, r: 0, s: 0)
|
186
|
+
end
|
187
|
+
|
188
|
+
protected
|
189
|
+
|
190
|
+
def sedes
|
191
|
+
if self.prevent_replays? && !(Platon.replayable_v? v)
|
192
|
+
self.class
|
193
|
+
else
|
194
|
+
UnsignedTx
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
|
200
|
+
UnsignedTx = Tx.exclude([:v, :r, :s])
|
201
|
+
end
|
data/lib/platon/utils.rb
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
module Platon
|
2
|
+
module Utils
|
3
|
+
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def normalize_address(address)
|
7
|
+
if address.nil? || address == ''
|
8
|
+
''
|
9
|
+
elsif address.size == 40
|
10
|
+
hex_to_bin address
|
11
|
+
elsif address.size == 42 && address[0..1] == '0x'
|
12
|
+
hex_to_bin address[2..-1]
|
13
|
+
else
|
14
|
+
address
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def bin_to_hex(string)
|
19
|
+
RLP::Utils.encode_hex string
|
20
|
+
end
|
21
|
+
|
22
|
+
def hex_to_bin(string)
|
23
|
+
RLP::Utils.decode_hex remove_hex_prefix(string)
|
24
|
+
end
|
25
|
+
|
26
|
+
def base256_to_int(str)
|
27
|
+
RLP::Sedes.big_endian_int.deserialize str.sub(/\A(\x00)+/, '')
|
28
|
+
end
|
29
|
+
|
30
|
+
def int_to_base256(int)
|
31
|
+
RLP::Sedes.big_endian_int.serialize int
|
32
|
+
end
|
33
|
+
|
34
|
+
def v_r_s_for(signature)
|
35
|
+
[
|
36
|
+
signature[0].bytes[0],
|
37
|
+
Utils.base256_to_int(signature[1..32]),
|
38
|
+
Utils.base256_to_int(signature[33..65]),
|
39
|
+
]
|
40
|
+
end
|
41
|
+
|
42
|
+
def prefix_hex(hex)
|
43
|
+
hex.match(/\A0x/) ? hex : "0x#{hex}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def remove_hex_prefix(s)
|
47
|
+
s[0,2] == '0x' ? s[2..-1] : s
|
48
|
+
end
|
49
|
+
|
50
|
+
def bin_to_prefixed_hex(binary)
|
51
|
+
prefix_hex bin_to_hex(binary)
|
52
|
+
end
|
53
|
+
|
54
|
+
def prefix_message(message)
|
55
|
+
"\x19Platon Signed Message:\n#{message.length}#{message}"
|
56
|
+
# "\x19Ethereum Signed Message:\n#{message.length}#{message}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def public_key_to_address(hex)
|
60
|
+
bytes = hex_to_bin(hex)
|
61
|
+
address_bytes = Utils.keccak256(bytes[1..-1])[-20..-1]
|
62
|
+
format_address bin_to_prefixed_hex(address_bytes)
|
63
|
+
end
|
64
|
+
|
65
|
+
# bech32 address to bin
|
66
|
+
def bech32_to_bin(bech32Address)
|
67
|
+
address = decode_bech32_address(bech32Address)
|
68
|
+
hex_to_bin address
|
69
|
+
end
|
70
|
+
|
71
|
+
def is_bech32_address?(bech32Address)
|
72
|
+
return false if bech32Address.length != 42
|
73
|
+
hrp,data,spec = Bech32.decode bech32Address
|
74
|
+
return false if data == nil
|
75
|
+
return true
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
# Resolve the bech32 address
|
80
|
+
#
|
81
|
+
# @method decode_bech32_address
|
82
|
+
# @param {String} bech32Address
|
83
|
+
# @return {String} formatted address
|
84
|
+
# eg: Platon::Utils.decode_bech32_address("atp1kh9dktnszj04zn6d8ae9edhqfmt4awx94n6h4m")
|
85
|
+
def decode_bech32_address(bech32Address)
|
86
|
+
if is_bech32_address?(bech32Address) ## is_bech32_address? ## TODO
|
87
|
+
|
88
|
+
segwit_addr = SegwitAddr.new(bech32Address)
|
89
|
+
address = segwit_addr.to_script_pubkey
|
90
|
+
if address
|
91
|
+
return "0x" + address
|
92
|
+
end
|
93
|
+
end
|
94
|
+
return ''
|
95
|
+
end
|
96
|
+
|
97
|
+
# Transforms given string to bech32 address
|
98
|
+
#
|
99
|
+
# @method to_bech32_address
|
100
|
+
# @param {String} hrp
|
101
|
+
# @param {String} address
|
102
|
+
# @return {String} formatted bech32 address
|
103
|
+
|
104
|
+
# Platon::Utils.to_bech32_address("atp","0xb5cadb2e70149f514f4d3f725cb6e04ed75eb8c5")
|
105
|
+
def to_bech32_address(hrp,address)
|
106
|
+
if true ## isAddress
|
107
|
+
segwit_addr = SegwitAddr.new
|
108
|
+
segwit_addr.hrp = hrp
|
109
|
+
segwit_addr.script_pubkey = remove_hex_prefix(address) ## remove 0x
|
110
|
+
segwit_addr.addr
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def sha256(x)
|
115
|
+
Digest::SHA256.digest x
|
116
|
+
end
|
117
|
+
|
118
|
+
def keccak256(x)
|
119
|
+
Digest::SHA3.new(256).digest(x)
|
120
|
+
end
|
121
|
+
|
122
|
+
def keccak512(x)
|
123
|
+
Digest::SHA3.new(512).digest(x)
|
124
|
+
end
|
125
|
+
|
126
|
+
def keccak256_rlp(x)
|
127
|
+
keccak256 RLP.encode(x)
|
128
|
+
end
|
129
|
+
|
130
|
+
def ripemd160(x)
|
131
|
+
Digest::RMD160.digest x
|
132
|
+
end
|
133
|
+
|
134
|
+
def hash160(x)
|
135
|
+
ripemd160 sha256(x)
|
136
|
+
end
|
137
|
+
|
138
|
+
def zpad(x, l)
|
139
|
+
lpad x, BYTE_ZERO, l
|
140
|
+
end
|
141
|
+
|
142
|
+
def zunpad(x)
|
143
|
+
x.sub(/\A\x00+/, '')
|
144
|
+
end
|
145
|
+
|
146
|
+
def zpad_int(n, l=32)
|
147
|
+
zpad encode_int(n), l
|
148
|
+
end
|
149
|
+
|
150
|
+
def zpad_hex(s, l=32)
|
151
|
+
zpad decode_hex(s), l
|
152
|
+
end
|
153
|
+
|
154
|
+
def valid_address?(address)
|
155
|
+
Address.new(address).valid?
|
156
|
+
end
|
157
|
+
|
158
|
+
def format_address(address)
|
159
|
+
Address.new(address).checksummed
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
|
164
|
+
private
|
165
|
+
|
166
|
+
def lpad(x, symbol, l)
|
167
|
+
return x if x.size >= l
|
168
|
+
symbol * (l - x.size) + x
|
169
|
+
end
|
170
|
+
|
171
|
+
def encode_int(n)
|
172
|
+
unless n.is_a?(Integer) && n >= 0 && n <= UINT_MAX
|
173
|
+
raise ArgumentError, "Integer invalid or out of range: #{n}"
|
174
|
+
end
|
175
|
+
|
176
|
+
int_to_base256 n
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
end
|