cita-sdk-ruby 0.20.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 +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
|