scale_rb 0.1.15 → 0.2.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d49c850c60bd8f6807d0c04995d3b8a5262f63dc627b585e683d774e91ed96ab
4
- data.tar.gz: adbba1bbba8cf9bbf3f559893a2b69f90d94a41a259db713f1a7db6dcb83b29f
3
+ metadata.gz: 204c629856c37264a38451c2655c36ea33aee9d97cb4220ab2d107dc692f1d79
4
+ data.tar.gz: 4e16a199f0d77c5a7fa4150e05a00204f3244cb33d64ec79604f7e19ff43fbc3
5
5
  SHA512:
6
- metadata.gz: b0b06fa722621edab033346e30d78ea8096d98fe032f285845f2685593b6cce266aaa18cd8126cdf1632b1e85f6bcdeea6e6858c12534608ab7fb98a27dbd777
7
- data.tar.gz: e57dc6323f7bd0024041ce0ed46bcc006f588e770f895d530d836755981248e1d37abf4d33c529da0e5db57dac231a941bcd506a8822170b8f074b72ba4877cc
6
+ metadata.gz: 5de7ac76c8a4113b2ae965845b2d7a940eabce3b732fad370a6bd1be039f83c0f251525c35ebace750493c07d4372868bc82fefcbd215f19c30b8702cf2ab281
7
+ data.tar.gz: a5796129a92d7bfca3d00cbdccf56a7574e3486d9562ef088ef74b5a24135cdbe6a3ee014692df2ba1bfbc3140dcd97a5d96bf575d73310eacabbde3e8876229
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- scale_rb (0.1.15)
4
+ scale_rb (0.2.2)
5
5
  base58
6
6
  blake2b_rs (~> 0.1.4)
7
7
  xxhash
data/lib/address.rb CHANGED
@@ -1,105 +1,101 @@
1
1
  require 'base58'
2
2
 
3
3
  # Warning: Just for test
4
- class Address
5
- SS58_PREFIX = 'SS58PRE'
6
-
7
- TYPES = [
8
- # Polkadot Live (SS58, AccountId)
9
- 0, 1,
10
- # Polkadot Canary (SS58, AccountId)
11
- 2, 3,
12
- # Kulupu (SS58, Reserved)
13
- 16, 17,
14
- # Darwinia Live
15
- 18,
16
- # Dothereum (SS58, AccountId)
17
- 20, 21,
18
- # Generic Substrate wildcard (SS58, AccountId)
19
- 42, 43,
20
-
21
- # Schnorr/Ristretto 25519 ("S/R 25519") key
22
- 48,
23
- # Edwards Ed25519 key
24
- 49,
25
- # ECDSA SECP256k1 key
26
- 50,
27
-
28
- # Reserved for future address format extensions.
29
- *64..255
30
- ]
31
-
32
- class << self
33
- def array_to_hex_string(arr)
34
- body = arr.map { |i| i.to_s(16).rjust(2, '0') }.join
35
- "0x#{body}"
36
- end
37
-
38
- def decode(address, addr_type = 42, _ignore_checksum = true)
39
- decoded = Base58.base58_to_binary(address, :bitcoin)
40
- is_pubkey = decoded.size == 35
41
-
42
- size = decoded.size - (is_pubkey ? 2 : 1)
43
-
44
- prefix = decoded[0, 1].unpack1('C*')
45
-
46
- raise 'Invalid address type' unless TYPES.include?(addr_type)
47
-
48
- hash_bytes = make_hash(decoded[0, size])
49
- is_valid_checksum =
50
- if is_pubkey
51
- decoded[-2].unpack1('C*') == hash_bytes[0] && decoded[-1].unpack1('C*') == hash_bytes[1]
52
- else
53
- decoded[-1].unpack1('C*') == hash_bytes[0]
54
- end
55
-
56
- # raise "Invalid decoded address checksum" unless is_valid_checksum && ignore_checksum
57
-
58
- decoded[1...size].unpack1('H*')
59
- end
60
-
61
- def encode(pubkey, addr_type = 42)
62
- pubkey = pubkey[2..-1] if pubkey =~ /^0x/i
63
- key = [pubkey].pack('H*')
4
+ module ScaleRb
5
+ class Address
6
+ SS58_PREFIX = 'SS58PRE'
7
+
8
+ TYPES = [
9
+ # Polkadot Live (SS58, AccountId)
10
+ 0, 1,
11
+ # Polkadot Canary (SS58, AccountId)
12
+ 2, 3,
13
+ # Kulupu (SS58, Reserved)
14
+ 16, 17,
15
+ # Darwinia Live
16
+ 18,
17
+ # Dothereum (SS58, AccountId)
18
+ 20, 21,
19
+ # Generic Substrate wildcard (SS58, AccountId)
20
+ 42, 43,
21
+
22
+ # Schnorr/Ristretto 25519 ("S/R 25519") key
23
+ 48,
24
+ # Edwards Ed25519 key
25
+ 49,
26
+ # ECDSA SECP256k1 key
27
+ 50,
28
+
29
+ # Reserved for future address format extensions.
30
+ *64..255
31
+ ]
32
+
33
+ class << self
34
+ def decode(address, addr_type = 42, _ignore_checksum = true)
35
+ decoded = Base58.base58_to_binary(address, :bitcoin)
36
+ is_pubkey = decoded.size == 35
37
+
38
+ size = decoded.size - (is_pubkey ? 2 : 1)
39
+
40
+ prefix = decoded[0, 1].unpack1('C*')
41
+
42
+ raise 'Invalid address type' unless TYPES.include?(addr_type)
43
+
44
+ hash_bytes = make_hash(decoded[0, size])
45
+ is_valid_checksum =
46
+ if is_pubkey
47
+ decoded[-2].unpack1('C*') == hash_bytes[0] && decoded[-1].unpack1('C*') == hash_bytes[1]
48
+ else
49
+ decoded[-1].unpack1('C*') == hash_bytes[0]
50
+ end
51
+
52
+ # raise "Invalid decoded address checksum" unless is_valid_checksum && ignore_checksum
53
+
54
+ decoded[1...size].unpack1('H*')
55
+ end
64
56
 
65
- pubkey_bytes = key.bytes
57
+ def encode(pubkey, addr_type = 42)
58
+ pubkey = pubkey[2..-1] if pubkey =~ /^0x/i
59
+ key = [pubkey].pack('H*')
66
60
 
67
- checksum_length = case pubkey_bytes.length
68
- when 32, 33
69
- 2
70
- when 1, 2, 4, 8
71
- 1
72
- else
73
- raise 'Invalid pubkey length'
74
- end
61
+ pubkey_bytes = key.bytes
75
62
 
76
- ss58_format_bytes = if addr_type < 64
77
- [addr_type].pack('C*')
63
+ checksum_length = case pubkey_bytes.length
64
+ when 32, 33
65
+ 2
66
+ when 1, 2, 4, 8
67
+ 1
78
68
  else
79
- [
80
- ((ss58_format & 0b0000_0000_1111_1100) >> 2) | 0b0100_0000,
81
- (ss58_format >> 8) | ((ss58_format & 0b0000_0000_0000_0011) << 6)
82
- ].pack('C*')
69
+ raise 'Invalid pubkey length'
83
70
  end
84
71
 
85
- input_bytes = ss58_format_bytes.bytes + pubkey_bytes
86
- checksum = Blake2b.hex(SS58_PREFIX.bytes + input_bytes, 64).to_bytes
72
+ ss58_format_bytes = if addr_type < 64
73
+ [addr_type].pack('C*')
74
+ else
75
+ [
76
+ ((ss58_format & 0b0000_0000_1111_1100) >> 2) | 0b0100_0000,
77
+ (ss58_format >> 8) | ((ss58_format & 0b0000_0000_0000_0011) << 6)
78
+ ].pack('C*')
79
+ end
87
80
 
88
- Base58.binary_to_base58((input_bytes + checksum[0...checksum_length]).pack('C*'), :bitcoin)
89
- end
81
+ input_bytes = ss58_format_bytes.bytes + pubkey_bytes
82
+ checksum = Blake2b.hex(SS58_PREFIX.bytes + input_bytes, 64)._to_bytes
90
83
 
91
- def make_hash(body)
92
- Blake2b.hex("#{SS58_PREFIX}#{body}".bytes, 64)
93
- end
84
+ Base58.binary_to_base58((input_bytes + checksum[0...checksum_length]).pack('C*'), :bitcoin)
85
+ end
94
86
 
95
- def is_ss58_address?(address)
96
- begin
97
- decode(address)
98
- rescue StandardError
99
- return false
87
+ def make_hash(body)
88
+ Blake2b.hex("#{SS58_PREFIX}#{body}".bytes, 64)
89
+ end
90
+
91
+ def is_ss58_address?(address)
92
+ begin
93
+ decode(address)
94
+ rescue StandardError
95
+ return false
96
+ end
97
+ true
100
98
  end
101
- true
102
99
  end
103
100
  end
104
101
  end
105
-
@@ -1,100 +1,104 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class AbstractWsClient
4
- extend RpcRequestBuilder
5
- attr_accessor :metadata, :registry
6
-
7
- def initialize
8
- @id = 0
9
- @metadata = nil
10
- @registry = nil
11
- @callbacks = {}
12
- @subscription_callbacks = {}
13
- end
3
+ require_relative './rpc_request_builder'
4
+
5
+ module ScaleRb
6
+ class AbstractWsClient
7
+ extend RpcRequestBuilder
8
+ attr_accessor :metadata, :registry
9
+
10
+ def initialize
11
+ @id = 0
12
+ @metadata = nil
13
+ @registry = nil
14
+ @callbacks = {}
15
+ @subscription_callbacks = {}
16
+ end
14
17
 
15
- def send_json_rpc(_body)
16
- raise 'WsClient is a abstract base class for websocket client, please use its sub-class'
17
- end
18
+ def send_json_rpc(_body)
19
+ raise 'WsClient is a abstract base class for websocket client, please use its sub-class'
20
+ end
18
21
 
19
- # changes: [
20
- # [
21
- # "0x26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7", # storage key
22
- # "0x0400000000000000d887690900000000020000" # change
23
- # ]
24
- # ]
25
- def process(resp)
26
- # handle id
27
- @callbacks[resp['id']]&.call(resp['id'], resp) if resp['id']
28
-
29
- # handle storage subscription
30
- return unless resp['params'] && resp['params']['subscription']
31
- return unless @metadata && @registry
32
-
33
- subscription = resp['params']['subscription']
34
- changes = resp['params']['result']['changes']
35
- block = resp['params']['result']['block']
36
- p "block: #{block}"
37
-
38
- return unless @subscription_callbacks[subscription]
39
-
40
- pallet_name, item_name, subscription_callback = @subscription_callbacks[subscription]
41
- storage_item = Metadata.get_storage_item(pallet_name, item_name, @metadata)
42
- storages = decode_storages(changes.map(&:last), storage_item, registry)
43
- subscription_callback.call(storages)
44
- end
22
+ # changes: [
23
+ # [
24
+ # "0x26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7", # storage key
25
+ # "0x0400000000000000d887690900000000020000" # change
26
+ # ]
27
+ # ]
28
+ def process(resp)
29
+ # handle id
30
+ @callbacks[resp['id']]&.call(resp['id'], resp) if resp['id']
31
+
32
+ # handle storage subscription
33
+ return unless resp['params'] && resp['params']['subscription']
34
+ return unless @metadata && @registry
35
+
36
+ subscription = resp['params']['subscription']
37
+ changes = resp['params']['result']['changes']
38
+ block = resp['params']['result']['block']
39
+ p "block: #{block}"
40
+
41
+ return unless @subscription_callbacks[subscription]
42
+
43
+ pallet_name, item_name, subscription_callback = @subscription_callbacks[subscription]
44
+ storage_item = Metadata.get_storage_item(pallet_name, item_name, @metadata)
45
+ storages = decode_storages(changes.map(&:last), storage_item, registry)
46
+ subscription_callback.call(storages)
47
+ end
45
48
 
46
- def get_metadata(callback = nil)
47
- if callback.nil?
48
- callback = lambda do |id, resp|
49
- return unless resp['id'] && resp['result']
50
- return if resp['id'] != id
49
+ def get_metadata(callback = nil)
50
+ if callback.nil?
51
+ callback = lambda do |id, resp|
52
+ return unless resp['id'] && resp['result']
53
+ return if resp['id'] != id
51
54
 
52
- metadata_hex = resp['result']
53
- metadata = Metadata.decode_metadata(metadata_hex.strip.to_bytes)
54
- return unless metadata
55
+ metadata_hex = resp['result']
56
+ metadata = Metadata.decode_metadata(metadata_hex.strip._to_bytes)
57
+ return unless metadata
55
58
 
56
- @metadata = metadata
57
- @registry = Metadata.build_registry(@metadata)
59
+ @metadata = metadata
60
+ @registry = Metadata.build_registry(@metadata)
61
+ end
58
62
  end
59
- end
60
63
 
61
- id = bind_id_to(callback)
62
- body = state_getMetadata(id)
63
- send_json_rpc(body)
64
- end
64
+ id = bind_id_to(callback)
65
+ body = state_getMetadata(id)
66
+ send_json_rpc(body)
67
+ end
65
68
 
66
- def subscribe_storage(pallet_name, item_name, subscription_callback, key = nil, registry = nil)
67
- callback = create_callback_for_subscribe_storage(pallet_name, item_name, subscription_callback)
68
- id = bind_id_to(callback)
69
- body = derived_state_subscribe_storage(id, pallet_name, item_name, key, registry)
70
- send_json_rpc(body)
71
- end
69
+ def subscribe_storage(pallet_name, item_name, subscription_callback, key = nil, registry = nil)
70
+ callback = create_callback_for_subscribe_storage(pallet_name, item_name, subscription_callback)
71
+ id = bind_id_to(callback)
72
+ body = derived_state_subscribe_storage(id, pallet_name, item_name, key, registry)
73
+ send_json_rpc(body)
74
+ end
72
75
 
73
- private
76
+ private
74
77
 
75
- def bind_id_to(callback)
76
- @callbacks[@id] = callback
77
- old = @id
78
- @id += 1
79
- old
80
- end
78
+ def bind_id_to(callback)
79
+ @callbacks[@id] = callback
80
+ old = @id
81
+ @id += 1
82
+ old
83
+ end
81
84
 
82
- def decode_storages(datas, storage_item, registry)
83
- datas.map do |data|
84
- StorageHelper.decode_storage2(data, storage_item, registry)
85
+ def decode_storages(datas, storage_item, registry)
86
+ datas.map do |data|
87
+ StorageHelper.decode_storage2(data, storage_item, registry)
88
+ end
85
89
  end
86
- end
87
90
 
88
- def create_callback_for_subscribe_storage(pallet_name, item_name, subscription_callback)
89
- lambda do |id, resp|
90
- return unless resp['id'] && resp['result']
91
- return if resp['id'] != id
91
+ def create_callback_for_subscribe_storage(pallet_name, item_name, subscription_callback)
92
+ lambda do |id, resp|
93
+ return unless resp['id'] && resp['result']
94
+ return if resp['id'] != id
92
95
 
93
- @subscription_callbacks[resp['result']] = [
94
- pallet_name,
95
- item_name,
96
- subscription_callback
97
- ]
96
+ @subscription_callbacks[resp['result']] = [
97
+ pallet_name,
98
+ item_name,
99
+ subscription_callback
100
+ ]
101
+ end
98
102
  end
99
103
  end
100
104
  end
@@ -3,6 +3,7 @@
3
3
  require 'uri'
4
4
  require 'net/http'
5
5
  require 'json'
6
+ require_relative './rpc_request_builder'
6
7
  require_relative './http_client_metadata'
7
8
  require_relative './http_client_storage'
8
9
 
@@ -12,7 +13,7 @@ module ScaleRb
12
13
  extend RpcRequestBuilder
13
14
 
14
15
  class << self
15
- def request(url, body)
16
+ def request(url, body, tries = 0)
16
17
  ScaleRb.logger.debug "url: #{url}"
17
18
  ScaleRb.logger.debug "body: #{body}"
18
19
  uri = URI(url)
@@ -30,10 +31,12 @@ module ScaleRb
30
31
 
31
32
  result['result']
32
33
  rescue StandardError => e
34
+ raise e unless tries < 5
35
+
33
36
  ScaleRb.logger.error e.message
34
- ScaleRb.logger.error 'retry...'
35
- sleep 2
36
- request(url, body)
37
+ ScaleRb.logger.error 'retry after 5 seconds...'
38
+ sleep 5
39
+ request(url, body, tries + 1)
37
40
  end
38
41
 
39
42
  def json_rpc_call(url, method, *params)
@@ -64,3 +67,31 @@ module ScaleRb
64
67
  end
65
68
  end
66
69
  end
70
+
71
+ # https://polkadot.js.org/docs/substrate/rpc/
72
+ #
73
+ # Examples:
74
+ # # Get all supported rpc methods
75
+ # ScaleRb::HttpClient.rpc_methods("https://rpc.darwinia.network")
76
+ #
77
+ # # eth_blockNumber
78
+ # ScaleRb::HttpClient.eth_blockNumber("https://rpc.darwinia.network")
79
+ #
80
+ # # system_name
81
+ # ScaleRb::HttpClient.system_name("https://rpc.darwinia.network")
82
+ #
83
+ # # chain_getHead
84
+ # ScaleRb::HttpClient.chain_getHead("https://rpc.darwinia.network")
85
+ #
86
+ # # state_getMetadata of darwinia block #1582
87
+ # ScaleRb::HttpClient.state_getMetadata(
88
+ # "https://rpc.darwinia.network",
89
+ # "0xb5a4f16d0feba7531e75315432b4d31a5b918987e026437890a2cbf5b8d9956d"
90
+ # )
91
+ #
92
+ # # eth_getBalance of address 0x0000000000000000000000000000000000000000 at block #1582
93
+ # ScaleRb::HttpClient.eth_getBalance(
94
+ # "https://rpc.darwinia.network",
95
+ # "0x0000000000000000000000000000000000000000",
96
+ # 1582
97
+ # )
@@ -6,7 +6,7 @@ module ScaleRb
6
6
  class << self
7
7
  def get_metadata(url, at = nil)
8
8
  hex = state_getMetadata(url, at)
9
- Metadata.decode_metadata(hex.strip.to_bytes)
9
+ Metadata.decode_metadata(hex.strip._to_bytes)
10
10
  end
11
11
 
12
12
  # cached version of get_metadata
@@ -35,7 +35,7 @@ module ScaleRb
35
35
  item['changes'].map do |change|
36
36
  storage_key = change[0]
37
37
  data = change[1] || default
38
- storage = data.nil? ? nil : PortableCodec.decode(type_id, data.to_bytes, registry)[0]
38
+ storage = data.nil? ? nil : PortableCodec.decode(type_id, data._to_bytes, registry)[0]
39
39
  { storage_key: storage_key, storage: storage }
40
40
  end
41
41
  end.flatten
@@ -80,7 +80,7 @@ module ScaleRb
80
80
  # 'System',
81
81
  # 'Account',
82
82
  # key = {
83
- # value: [['0x724d50824542b56f422588421643c4a162b90b5416ef063f2266a1eae6651641'.to_bytes]], # [AccountId]
83
+ # value: [['0x724d50824542b56f422588421643c4a162b90b5416ef063f2266a1eae6651641'._to_bytes]], # [AccountId]
84
84
  # type: 0,
85
85
  # hashers: ['Blake2128Concat']
86
86
  # },
@@ -96,7 +96,7 @@ module ScaleRb
96
96
  if key
97
97
  if key[:value].nil? || key[:value].empty?
98
98
  # map, but no key's value provided. get all storages under the partial storage key
99
- partial_storage_key = StorageHelper.encode_storage_key(pallet_name, item_name).to_hex
99
+ partial_storage_key = StorageHelper.encode_storage_key(pallet_name, item_name)._to_hex
100
100
  get_storages_by_partial_key(
101
101
  url,
102
102
  partial_storage_key,
@@ -107,7 +107,7 @@ module ScaleRb
107
107
  )
108
108
  elsif key[:value].length != key[:hashers].length
109
109
  # map with multi parts, but not have all values
110
- partial_storage_key = StorageHelper.encode_storage_key(pallet_name, item_name, key, registry).to_hex
110
+ partial_storage_key = StorageHelper.encode_storage_key(pallet_name, item_name, key, registry)._to_hex
111
111
  get_storages_by_partial_key(
112
112
  url,
113
113
  partial_storage_key,
@@ -118,7 +118,7 @@ module ScaleRb
118
118
  )
119
119
  end
120
120
  else
121
- storage_key = StorageHelper.encode_storage_key(pallet_name, item_name, key, registry).to_hex
121
+ storage_key = StorageHelper.encode_storage_key(pallet_name, item_name, key, registry)._to_hex
122
122
  data = state_getStorage(url, storage_key, at)
123
123
  StorageHelper.decode_storage(data, value[:type], value[:modifier] == 'Optional', value[:fallback], registry)
124
124
  end
@@ -168,7 +168,7 @@ module ScaleRb
168
168
  # convert key to byte array
169
169
  def c(key)
170
170
  if key.start_with?('0x')
171
- key.to_bytes
171
+ key._to_bytes
172
172
  elsif key.to_i.to_s == key # check if key is a number
173
173
  key.to_i
174
174
  else
@@ -2,52 +2,54 @@
2
2
 
3
3
  require 'json'
4
4
 
5
- module RpcRequestBuilder
6
- def build_json_rpc_body(method, params, id)
7
- {
8
- 'id' => id,
9
- 'jsonrpc' => '2.0',
10
- 'method' => method,
11
- 'params' => params.reject(&:nil?)
12
- }.to_json
13
- end
5
+ module ScaleRb
6
+ module RpcRequestBuilder
7
+ def build_json_rpc_body(method, params, id)
8
+ {
9
+ 'id' => id,
10
+ 'jsonrpc' => '2.0',
11
+ 'method' => method,
12
+ 'params' => params.reject(&:nil?)
13
+ }.to_json
14
+ end
14
15
 
15
- def respond_to_missing?(*_args)
16
- true
17
- end
16
+ def respond_to_missing?(*_args)
17
+ true
18
+ end
18
19
 
19
- # example:
20
- # state_getStorage(1, '0x363a..', 563_868)
21
- #
22
- # ==
23
- #
24
- # build_json_rpc_body('state_getStorage', ['0x363a..', 563_868], 1)
25
- def method_missing(method, *args)
26
- build_json_rpc_body(method, args[1..], args[0])
27
- end
20
+ # example:
21
+ # state_getStorage(1, '0x363a..', 563_868)
22
+ #
23
+ # ==
24
+ #
25
+ # build_json_rpc_body('state_getStorage', ['0x363a..', 563_868], 1)
26
+ def method_missing(method, *args)
27
+ build_json_rpc_body(method, args[1..], args[0])
28
+ end
28
29
 
29
- ###################################
30
- # derived functions
31
- ###################################
32
- def derived_state_get_storage(rpc_id, pallet_name, item_name, key = nil, registry = nil)
33
- storage_key = StorageHelper.encode_storage_key(pallet_name, item_name, key, registry).to_hex
34
- state_getStorage(rpc_id, [storage_key])
35
- end
30
+ ###################################
31
+ # derived functions
32
+ ###################################
33
+ def derived_state_get_storage(rpc_id, pallet_name, item_name, key = nil, registry = nil)
34
+ storage_key = StorageHelper.encode_storage_key(pallet_name, item_name, key, registry)._to_hex
35
+ state_getStorage(rpc_id, [storage_key])
36
+ end
36
37
 
37
- def derived_state_subscribe_storage(rpc_id, pallet_name, item_name, key = nil, registry = nil)
38
- storage_key = StorageHelper.encode_storage_key(pallet_name, item_name, key, registry).to_hex
39
- state_subscribeStorage(rpc_id, [storage_key])
40
- end
38
+ def derived_state_subscribe_storage(rpc_id, pallet_name, item_name, key = nil, registry = nil)
39
+ storage_key = StorageHelper.encode_storage_key(pallet_name, item_name, key, registry)._to_hex
40
+ state_subscribeStorage(rpc_id, [storage_key])
41
+ end
41
42
 
42
- def derived_eth_call(rpc_id, to, data, at = nil)
43
- eth_call(
44
- rpc_id,
45
- [
46
- {
47
- 'from' => nil, 'to' => to, 'data' => data
48
- },
49
- at
50
- ]
51
- )
43
+ def derived_eth_call(rpc_id, to, data, at = nil)
44
+ eth_call(
45
+ rpc_id,
46
+ [
47
+ {
48
+ 'from' => nil, 'to' => to, 'data' => data
49
+ },
50
+ at
51
+ ]
52
+ )
53
+ end
52
54
  end
53
55
  end