cita-sdk-ruby 0.20.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.gitmodules +6 -0
- data/.pryrc +4 -0
- data/.rspec +3 -0
- data/.rubocop.yml +103 -0
- data/.travis.yml +16 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +95 -0
- data/LICENSE.txt +21 -0
- data/README.md +106 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/cita.gemspec +47 -0
- data/lib/cita/address.rb +26 -0
- data/lib/cita/client.rb +17 -0
- data/lib/cita/contract.rb +98 -0
- data/lib/cita/http.rb +57 -0
- data/lib/cita/protos/blockchain_pb.rb +112 -0
- data/lib/cita/rpc.rb +84 -0
- data/lib/cita/transaction.rb +57 -0
- data/lib/cita/transaction_signer.rb +137 -0
- data/lib/cita/utils.rb +87 -0
- data/lib/cita/version.rb +5 -0
- data/lib/cita.rb +19 -0
- data/lib/web3_eth/contract.rb +28 -0
- metadata +226 -0
data/lib/cita/http.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "json"
|
3
|
+
require "faraday"
|
4
|
+
|
5
|
+
module CITA
|
6
|
+
class Http
|
7
|
+
attr_accessor :url
|
8
|
+
|
9
|
+
DEFAULT_JSONRPC = "2.0"
|
10
|
+
DEFAULT_PARAMS = [].freeze
|
11
|
+
DEFAULT_ID = 83
|
12
|
+
|
13
|
+
def initialize(url)
|
14
|
+
@url = url
|
15
|
+
end
|
16
|
+
|
17
|
+
# wrapper for call rpc method
|
18
|
+
#
|
19
|
+
# @param method [String] method you want to call
|
20
|
+
# @param jsonrpc [String] jsonrpc version
|
21
|
+
# @param params [Array] rpc params
|
22
|
+
# @param id [Integer] jsonrpc id
|
23
|
+
#
|
24
|
+
# @return [Faraday::Response]
|
25
|
+
def call_rpc(method, jsonrpc: DEFAULT_JSONRPC, params: DEFAULT_PARAMS, id: DEFAULT_ID)
|
26
|
+
conn.post("/", rpc_params(method, jsonrpc: jsonrpc, params: params, id: id))
|
27
|
+
end
|
28
|
+
|
29
|
+
# wrapper for rpc params
|
30
|
+
#
|
31
|
+
# @param method [String] method you want to call
|
32
|
+
# @param jsonrpc [String] jsonrpc version
|
33
|
+
# @param params [Array] rpc params
|
34
|
+
# @param id [Integer] jsonrpc id
|
35
|
+
#
|
36
|
+
# @return [String] json string
|
37
|
+
def rpc_params(method, jsonrpc: DEFAULT_JSONRPC, params: DEFAULT_PARAMS, id: DEFAULT_ID)
|
38
|
+
{
|
39
|
+
jsonrpc: jsonrpc,
|
40
|
+
id: id,
|
41
|
+
method: method,
|
42
|
+
params: params
|
43
|
+
}.to_json
|
44
|
+
end
|
45
|
+
|
46
|
+
# wrapper faraday object with CITA URL and Content-Type
|
47
|
+
#
|
48
|
+
# @return [Faraday]
|
49
|
+
def conn
|
50
|
+
Faraday.new(url: url) do |faraday|
|
51
|
+
faraday.headers["Content-Type"] = "application/json"
|
52
|
+
faraday.request :url_encoded # form-encode POST params
|
53
|
+
faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
2
|
+
# source: blockchain.proto
|
3
|
+
|
4
|
+
require 'google/protobuf'
|
5
|
+
|
6
|
+
Google::Protobuf::DescriptorPool.generated_pool.build do
|
7
|
+
add_message "Proof" do
|
8
|
+
optional :content, :bytes, 1
|
9
|
+
optional :type, :enum, 2, "ProofType"
|
10
|
+
end
|
11
|
+
add_message "BlockHeader" do
|
12
|
+
optional :prevhash, :bytes, 1
|
13
|
+
optional :timestamp, :uint64, 2
|
14
|
+
optional :height, :uint64, 3
|
15
|
+
optional :state_root, :bytes, 4
|
16
|
+
optional :transactions_root, :bytes, 5
|
17
|
+
optional :receipts_root, :bytes, 6
|
18
|
+
optional :quota_used, :uint64, 7
|
19
|
+
optional :quota_limit, :uint64, 8
|
20
|
+
optional :proof, :message, 9, "Proof"
|
21
|
+
optional :proposer, :bytes, 10
|
22
|
+
end
|
23
|
+
add_message "Status" do
|
24
|
+
optional :hash, :bytes, 1
|
25
|
+
optional :height, :uint64, 2
|
26
|
+
end
|
27
|
+
add_message "AccountGasLimit" do
|
28
|
+
optional :common_quota_limit, :uint64, 1
|
29
|
+
map :specific_quota_limit, :string, :uint64, 2
|
30
|
+
end
|
31
|
+
add_message "RichStatus" do
|
32
|
+
optional :hash, :bytes, 1
|
33
|
+
optional :height, :uint64, 2
|
34
|
+
repeated :nodes, :bytes, 3
|
35
|
+
optional :interval, :uint64, 4
|
36
|
+
optional :version, :uint32, 5
|
37
|
+
repeated :validators, :bytes, 6
|
38
|
+
end
|
39
|
+
add_message "Transaction" do
|
40
|
+
optional :to, :string, 1
|
41
|
+
optional :nonce, :string, 2
|
42
|
+
optional :quota, :uint64, 3
|
43
|
+
optional :valid_until_block, :uint64, 4
|
44
|
+
optional :data, :bytes, 5
|
45
|
+
optional :value, :bytes, 6
|
46
|
+
optional :chain_id, :uint32, 7
|
47
|
+
optional :version, :uint32, 8
|
48
|
+
optional :to_v1, :bytes, 9
|
49
|
+
optional :chain_id_v1, :bytes, 10
|
50
|
+
end
|
51
|
+
add_message "UnverifiedTransaction" do
|
52
|
+
optional :transaction, :message, 1, "Transaction"
|
53
|
+
optional :signature, :bytes, 2
|
54
|
+
optional :crypto, :enum, 3, "Crypto"
|
55
|
+
end
|
56
|
+
add_message "SignedTransaction" do
|
57
|
+
optional :transaction_with_sig, :message, 1, "UnverifiedTransaction"
|
58
|
+
optional :tx_hash, :bytes, 2
|
59
|
+
optional :signer, :bytes, 3
|
60
|
+
end
|
61
|
+
add_message "BlockBody" do
|
62
|
+
repeated :transactions, :message, 1, "SignedTransaction"
|
63
|
+
end
|
64
|
+
add_message "Block" do
|
65
|
+
optional :version, :uint32, 1
|
66
|
+
optional :header, :message, 2, "BlockHeader"
|
67
|
+
optional :body, :message, 3, "BlockBody"
|
68
|
+
end
|
69
|
+
add_message "BlockWithProof" do
|
70
|
+
optional :blk, :message, 1, "Block"
|
71
|
+
optional :proof, :message, 2, "Proof"
|
72
|
+
end
|
73
|
+
add_message "BlockTxs" do
|
74
|
+
optional :height, :uint64, 1
|
75
|
+
optional :body, :message, 3, "BlockBody"
|
76
|
+
end
|
77
|
+
add_message "BlackList" do
|
78
|
+
repeated :black_list, :bytes, 1
|
79
|
+
repeated :clear_list, :bytes, 2
|
80
|
+
end
|
81
|
+
add_message "StateSignal" do
|
82
|
+
optional :height, :uint64, 1
|
83
|
+
end
|
84
|
+
add_enum "ProofType" do
|
85
|
+
value :AuthorityRound, 0
|
86
|
+
value :Raft, 1
|
87
|
+
value :Bft, 2
|
88
|
+
end
|
89
|
+
add_enum "Crypto" do
|
90
|
+
value :SECP, 0
|
91
|
+
value :SM2, 1
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
module CITA::Protos
|
96
|
+
Proof = Google::Protobuf::DescriptorPool.generated_pool.lookup("Proof").msgclass
|
97
|
+
BlockHeader = Google::Protobuf::DescriptorPool.generated_pool.lookup("BlockHeader").msgclass
|
98
|
+
Status = Google::Protobuf::DescriptorPool.generated_pool.lookup("Status").msgclass
|
99
|
+
AccountGasLimit = Google::Protobuf::DescriptorPool.generated_pool.lookup("AccountGasLimit").msgclass
|
100
|
+
RichStatus = Google::Protobuf::DescriptorPool.generated_pool.lookup("RichStatus").msgclass
|
101
|
+
Transaction = Google::Protobuf::DescriptorPool.generated_pool.lookup("Transaction").msgclass
|
102
|
+
UnverifiedTransaction = Google::Protobuf::DescriptorPool.generated_pool.lookup("UnverifiedTransaction").msgclass
|
103
|
+
SignedTransaction = Google::Protobuf::DescriptorPool.generated_pool.lookup("SignedTransaction").msgclass
|
104
|
+
BlockBody = Google::Protobuf::DescriptorPool.generated_pool.lookup("BlockBody").msgclass
|
105
|
+
Block = Google::Protobuf::DescriptorPool.generated_pool.lookup("Block").msgclass
|
106
|
+
BlockWithProof = Google::Protobuf::DescriptorPool.generated_pool.lookup("BlockWithProof").msgclass
|
107
|
+
BlockTxs = Google::Protobuf::DescriptorPool.generated_pool.lookup("BlockTxs").msgclass
|
108
|
+
BlackList = Google::Protobuf::DescriptorPool.generated_pool.lookup("BlackList").msgclass
|
109
|
+
StateSignal = Google::Protobuf::DescriptorPool.generated_pool.lookup("StateSignal").msgclass
|
110
|
+
ProofType = Google::Protobuf::DescriptorPool.generated_pool.lookup("ProofType").enummodule
|
111
|
+
Crypto = Google::Protobuf::DescriptorPool.generated_pool.lookup("Crypto").enummodule
|
112
|
+
end
|
data/lib/cita/rpc.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "active_support/inflector"
|
3
|
+
|
4
|
+
module CITA
|
5
|
+
class RPC
|
6
|
+
attr_reader :url, :http
|
7
|
+
|
8
|
+
# CITA v0.18 RPC list
|
9
|
+
METHOD_NAMES = %w(
|
10
|
+
peerCount
|
11
|
+
blockNumber
|
12
|
+
sendRawTransaction
|
13
|
+
getBlockByHash
|
14
|
+
getBlockByNumber
|
15
|
+
getTransaction
|
16
|
+
getTransactionReceipt
|
17
|
+
getLogs
|
18
|
+
call
|
19
|
+
getTransactionCount
|
20
|
+
getCode
|
21
|
+
getAbi
|
22
|
+
getBalance
|
23
|
+
newFilter
|
24
|
+
newBlockFilter
|
25
|
+
uninstallFilter
|
26
|
+
getFilterChanges
|
27
|
+
getFilterLogs
|
28
|
+
getTransactionProof
|
29
|
+
getMetaData
|
30
|
+
getBlockHeader
|
31
|
+
getStateProof
|
32
|
+
).freeze
|
33
|
+
|
34
|
+
def initialize(url)
|
35
|
+
@url = url
|
36
|
+
@http = Http.new(@url)
|
37
|
+
end
|
38
|
+
|
39
|
+
# generate rpc methods
|
40
|
+
METHOD_NAMES.each do |name|
|
41
|
+
define_method name do |*params|
|
42
|
+
call_rpc(name, params: params)
|
43
|
+
end
|
44
|
+
|
45
|
+
define_method name.underscore do |*params|
|
46
|
+
send(name, *params)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# @return [Hash] response body
|
51
|
+
def call_rpc(method, jsonrpc: Http::DEFAULT_JSONRPC, params: Http::DEFAULT_PARAMS, id: Http::DEFAULT_ID)
|
52
|
+
resp = http.call_rpc(method, params: params, jsonrpc: jsonrpc, id: id)
|
53
|
+
JSON.parse(resp.body)
|
54
|
+
end
|
55
|
+
|
56
|
+
# @param transaction [CITA::Transaction]
|
57
|
+
# @return [Hash]
|
58
|
+
def send_transaction(transaction, private_key)
|
59
|
+
content = TransactionSigner.encode(transaction, private_key)
|
60
|
+
send_raw_transaction(content)
|
61
|
+
end
|
62
|
+
|
63
|
+
# easy to transfer tokens
|
64
|
+
#
|
65
|
+
# @param to [String] to address
|
66
|
+
# @param private_key [String]
|
67
|
+
# @param value [String | Integer] hex string or decimal integer
|
68
|
+
# @param quota [Integer] default to 30_000
|
69
|
+
#
|
70
|
+
# @return [Hash]
|
71
|
+
def transfer(to:, private_key:, value:, quota: 30_000)
|
72
|
+
valid_until_block = block_number["result"].hex + 88
|
73
|
+
meta_data = get_meta_data("latest")["result"]
|
74
|
+
version = meta_data["version"]
|
75
|
+
chain_id = if version.zero?
|
76
|
+
meta_data["chainId"]
|
77
|
+
elsif version == 1
|
78
|
+
meta_data["chainIdV1"]
|
79
|
+
end
|
80
|
+
transaction = Transaction.new(nonce: Utils.nonce, valid_until_block: valid_until_block, chain_id: chain_id, to: to, value: value, quota: quota, version: version)
|
81
|
+
send_transaction(transaction, private_key)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "active_support/core_ext/string"
|
3
|
+
|
4
|
+
module CITA
|
5
|
+
class Transaction
|
6
|
+
class VersionError < StandardError
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_accessor :to, :nonce, :quota, :valid_until_block, :data, :value, :chain_id, :version
|
10
|
+
|
11
|
+
# @param nonce [String] default is SecureRandom.hex; if you provide with nil or empty string, it will be assigned a random string.
|
12
|
+
# @param valid_until_block [Integer]
|
13
|
+
# @param chain_id [Integer | String] hex string if version == 1
|
14
|
+
# @param version [Integer]
|
15
|
+
# @param to [String]
|
16
|
+
# @param data [String]
|
17
|
+
# @param value: [String | Integer] hex string or decimal integer
|
18
|
+
# @param quota [Integer]
|
19
|
+
#
|
20
|
+
# @return [void]
|
21
|
+
def initialize(valid_until_block:, chain_id:, nonce: nil, version: 1, to: nil, data: nil, value: "0", quota: 1_000_000) # rubocop:disable Metrics/ParameterLists
|
22
|
+
raise VersionError, "transaction version error, expected 0 or 1, got #{version}" unless [0, 1].include?(version)
|
23
|
+
|
24
|
+
@to = to
|
25
|
+
@nonce = nonce.blank? ? SecureRandom.hex : nonce
|
26
|
+
@quota = quota
|
27
|
+
@valid_until_block = valid_until_block
|
28
|
+
@data = data
|
29
|
+
@chain_id = if chain_id.is_a?(String)
|
30
|
+
chain_id.delete("-")
|
31
|
+
else
|
32
|
+
chain_id
|
33
|
+
end
|
34
|
+
@version = version
|
35
|
+
@value = if value.is_a?(Integer)
|
36
|
+
Utils.to_hex(value)
|
37
|
+
else
|
38
|
+
value
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.from_hash(hash)
|
43
|
+
h = hash.map { |k, v| { k.to_sym => v } }.reduce({}, :merge)
|
44
|
+
|
45
|
+
new(
|
46
|
+
nonce: h[:nonce],
|
47
|
+
valid_until_block: h[:valid_until_block],
|
48
|
+
chain_id: h[:chain_id],
|
49
|
+
to: h[:to],
|
50
|
+
data: h[:data],
|
51
|
+
version: h[:version] || 1,
|
52
|
+
value: h[:value] || "0",
|
53
|
+
quota: h[:quota] || 1_000_000
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ciri/utils"
|
4
|
+
require "ciri/crypto"
|
5
|
+
|
6
|
+
module CITA
|
7
|
+
class TransactionSigner
|
8
|
+
class << self
|
9
|
+
# sign transaction
|
10
|
+
#
|
11
|
+
# @param transaction [CITA::Transaction]
|
12
|
+
# @param private_key [String]
|
13
|
+
def encode(transaction, private_key)
|
14
|
+
tx = CITA::Protos::Transaction.new
|
15
|
+
|
16
|
+
to = CITA::Utils.remove_hex_prefix(transaction.to)&.downcase
|
17
|
+
|
18
|
+
tx.nonce = transaction.nonce
|
19
|
+
tx.quota = transaction.quota
|
20
|
+
tx.data = CITA::Utils.to_bytes(transaction.data)
|
21
|
+
tx.value = hex_to_bytes(transaction.value)
|
22
|
+
tx.version = transaction.version
|
23
|
+
tx.valid_until_block = transaction.valid_until_block
|
24
|
+
|
25
|
+
if transaction.version.zero?
|
26
|
+
tx.to = to unless to.nil?
|
27
|
+
tx.chain_id = transaction.chain_id
|
28
|
+
elsif transaction.version == 1
|
29
|
+
tx.to_v1 = Utils.to_bytes(to) unless to.nil?
|
30
|
+
tx.chain_id_v1 = hex_to_bytes(transaction.chain_id)
|
31
|
+
end
|
32
|
+
|
33
|
+
encoded_tx = Protos::Transaction.encode(tx)
|
34
|
+
|
35
|
+
private_key_bytes = CITA::Utils.to_bytes(private_key)
|
36
|
+
|
37
|
+
protobuf_hash = Utils.keccak256(encoded_tx)
|
38
|
+
|
39
|
+
signature = Ciri::Crypto.ecdsa_signature(private_key_bytes, protobuf_hash).signature
|
40
|
+
|
41
|
+
unverified_tx = Protos::UnverifiedTransaction.new(transaction: tx, signature: signature)
|
42
|
+
|
43
|
+
encoded_unverified_tx = Protos::UnverifiedTransaction.encode(unverified_tx)
|
44
|
+
|
45
|
+
CITA::Utils.from_bytes(encoded_unverified_tx)
|
46
|
+
end
|
47
|
+
|
48
|
+
# unsign transaction
|
49
|
+
#
|
50
|
+
# @param tx_content [String] hex string
|
51
|
+
def simple_decode(tx_content)
|
52
|
+
content_bytes = CITA::Utils.to_bytes(tx_content)
|
53
|
+
unverified_transaction = Protos::UnverifiedTransaction.decode(content_bytes)
|
54
|
+
|
55
|
+
signature = unverified_transaction["signature"]
|
56
|
+
|
57
|
+
transaction = unverified_transaction["transaction"]
|
58
|
+
msg = Protos::Transaction.encode(transaction)
|
59
|
+
msg_hash = CITA::Utils.keccak256(msg)
|
60
|
+
pubkey = Ciri::Crypto.ecdsa_recover(msg_hash, signature)
|
61
|
+
pubkey_hex = Utils.from_bytes(pubkey[1..-1])
|
62
|
+
|
63
|
+
from_address = Utils.keccak256(pubkey[1..-1])[-20..-1]
|
64
|
+
from_address_hex = Utils.from_bytes(from_address)
|
65
|
+
|
66
|
+
sender = {
|
67
|
+
address: from_address_hex,
|
68
|
+
public_key: pubkey_hex
|
69
|
+
}
|
70
|
+
|
71
|
+
{
|
72
|
+
unverified_transaction: unverified_transaction.to_h,
|
73
|
+
sender: sender
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
# decode and support forks
|
78
|
+
#
|
79
|
+
# @param tx_content [String] hex string
|
80
|
+
# @return [Hash]
|
81
|
+
def original_decode(tx_content)
|
82
|
+
data = simple_decode(tx_content)
|
83
|
+
utx = data[:unverified_transaction]
|
84
|
+
tx = utx[:transaction]
|
85
|
+
version = tx[:version]
|
86
|
+
|
87
|
+
if version == 0 # rubocop:disable Style/NumericPredicate
|
88
|
+
tx.delete(:to_v1)
|
89
|
+
tx.delete(:chain_id_v1)
|
90
|
+
elsif version == 1
|
91
|
+
tx[:to] = tx.delete(:to_v1)
|
92
|
+
tx[:chain_id] = tx.delete(:chain_id_v1)
|
93
|
+
else
|
94
|
+
raise Transaction::VersionError, "transaction version error, expected 0 or 1, got #{version}"
|
95
|
+
end
|
96
|
+
|
97
|
+
data
|
98
|
+
end
|
99
|
+
|
100
|
+
# decode and parse bytes to hex string
|
101
|
+
#
|
102
|
+
# @param tx_content [String] hex string
|
103
|
+
# @return [Hash]
|
104
|
+
def decode(tx_content)
|
105
|
+
data = original_decode(tx_content)
|
106
|
+
utx = data[:unverified_transaction]
|
107
|
+
tx = utx[:transaction]
|
108
|
+
version = tx[:version]
|
109
|
+
|
110
|
+
tx[:value] = Utils.from_bytes(tx[:value])
|
111
|
+
tx[:data] = Utils.from_bytes(tx[:data])
|
112
|
+
tx[:nonce] = Utils.add_prefix_for_not_blank(tx[:nonce])
|
113
|
+
utx[:signature] = Utils.from_bytes(utx[:signature])
|
114
|
+
|
115
|
+
if version == 0 # rubocop:disable Style/NumericPredicate
|
116
|
+
tx.delete(:to_v1)
|
117
|
+
tx.delete(:chain_id_v1)
|
118
|
+
tx[:to] = Utils.add_prefix_for_not_blank(tx[:to])
|
119
|
+
elsif version == 1
|
120
|
+
tx[:to] = Utils.from_bytes(tx[:to])
|
121
|
+
tx[:chain_id] = Utils.from_bytes(tx[:chain_id])
|
122
|
+
end
|
123
|
+
|
124
|
+
data
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
# @param value [String] hex string with or without `0x` prefix
|
130
|
+
# @param length [Integer] length, default is 64
|
131
|
+
# @return [String] byte code string
|
132
|
+
def hex_to_bytes(value, length = 64)
|
133
|
+
CITA::Utils.to_bytes(CITA::Utils.remove_hex_prefix(value).rjust(length, "0"))
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
data/lib/cita/utils.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CITA
|
4
|
+
class Utils
|
5
|
+
HEX_PREFIX = "0x"
|
6
|
+
|
7
|
+
class << self
|
8
|
+
# add `0x` prefix to hex string
|
9
|
+
#
|
10
|
+
# @param hex [String]
|
11
|
+
def add_hex_prefix(hex)
|
12
|
+
return if hex.nil?
|
13
|
+
return hex if hex.start_with?(HEX_PREFIX)
|
14
|
+
|
15
|
+
HEX_PREFIX + hex
|
16
|
+
end
|
17
|
+
|
18
|
+
# add `0x` prefix to not blank hex string
|
19
|
+
#
|
20
|
+
# @param hex [String]
|
21
|
+
def add_prefix_for_not_blank(hex)
|
22
|
+
return add_hex_prefix(hex) unless hex.blank?
|
23
|
+
|
24
|
+
hex
|
25
|
+
end
|
26
|
+
|
27
|
+
# remove `0x` prefix from hex string
|
28
|
+
#
|
29
|
+
# @param hex [String]
|
30
|
+
def remove_hex_prefix(hex)
|
31
|
+
return if hex.nil?
|
32
|
+
return hex.gsub(HEX_PREFIX, "") if hex.start_with?(HEX_PREFIX)
|
33
|
+
|
34
|
+
hex
|
35
|
+
end
|
36
|
+
|
37
|
+
# convert decimal value to hex string without `0x` prefix
|
38
|
+
#
|
39
|
+
# @param decimal [Integer]
|
40
|
+
# @return [String]
|
41
|
+
def to_hex(decimal)
|
42
|
+
add_hex_prefix decimal.to_s(16)
|
43
|
+
end
|
44
|
+
|
45
|
+
# convert hex string to decimal value
|
46
|
+
#
|
47
|
+
# @param hex [String]
|
48
|
+
# @return [Integer]
|
49
|
+
def to_decimal(hex)
|
50
|
+
hex.hex
|
51
|
+
end
|
52
|
+
|
53
|
+
# to byte code value
|
54
|
+
# remove `0x` prefix first
|
55
|
+
#
|
56
|
+
# @param str [String] normal string
|
57
|
+
# @return [String] byte code string
|
58
|
+
def to_bytes(str)
|
59
|
+
[CITA::Utils.remove_hex_prefix(str)].pack("H*")
|
60
|
+
end
|
61
|
+
|
62
|
+
# byte code to string value, with `0x` prefix
|
63
|
+
#
|
64
|
+
# @param bytes_str [String] byte code string
|
65
|
+
# @return [String] normal string
|
66
|
+
def from_bytes(bytes_str)
|
67
|
+
hex = bytes_str.unpack1("H*")
|
68
|
+
return CITA::Utils.add_hex_prefix(hex) unless hex.blank?
|
69
|
+
|
70
|
+
hex
|
71
|
+
end
|
72
|
+
|
73
|
+
# keccak 256 hash
|
74
|
+
#
|
75
|
+
def keccak256(*data)
|
76
|
+
Ciri::Utils.keccak(*data)
|
77
|
+
end
|
78
|
+
|
79
|
+
# get nonce
|
80
|
+
#
|
81
|
+
# @return [String]
|
82
|
+
def nonce
|
83
|
+
SecureRandom.hex
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/lib/cita/version.rb
ADDED
data/lib/cita.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "cita/version"
|
4
|
+
|
5
|
+
module CITA
|
6
|
+
# Your code goes here...
|
7
|
+
require "cita/protos/blockchain_pb"
|
8
|
+
|
9
|
+
require "web3_eth/contract"
|
10
|
+
|
11
|
+
require "cita/address"
|
12
|
+
require "cita/transaction"
|
13
|
+
require "cita/transaction_signer"
|
14
|
+
require "cita/utils"
|
15
|
+
require "cita/http"
|
16
|
+
require "cita/rpc"
|
17
|
+
require "cita/client"
|
18
|
+
require "cita/contract"
|
19
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "web3/eth"
|
4
|
+
|
5
|
+
module Web3
|
6
|
+
module Eth
|
7
|
+
class Contract
|
8
|
+
class ContractInstance
|
9
|
+
def function_data(method_name, *args)
|
10
|
+
@contract.function_data(method_name.to_s, args)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class ContractMethod
|
15
|
+
def function_data(args)
|
16
|
+
["0x" + signature_hash + encode_hex(encode_abi(input_types, args)), output_types]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def function_data(method_name, args)
|
21
|
+
function = functions[method_name]
|
22
|
+
raise "No method found in ABI: #{method_name}" unless function
|
23
|
+
|
24
|
+
function.function_data args
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|