erpc-sdk 0.5.0 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4f52f98e6f0df7cf416a17a3db62fe29b2182da2f4888eb0fd02293402c1a664
4
- data.tar.gz: 9d25c259f339edfd2c4c2e5080a7a6befd00cb587f2281ab9297ea71f83c974c
3
+ metadata.gz: 4152582a8b2cdb14a5b98a90761f07abf0ab2313540e5f46cef71d0111a6c531
4
+ data.tar.gz: 6f8d52e59d11fe4aa9d7d81af2941c65e59adfb98b5bade3a478f25c91d2bc52
5
5
  SHA512:
6
- metadata.gz: 70db8d372a797587c54a69992689c533ae20204a8c215c0637753524c19e47465935deaf1cec231161eb6ed1a50a2f044a084f84b1e281cabff1fe7a14bcb6ba
7
- data.tar.gz: f505d87463f95c0ac66c4d9789045dc92cd25765d3ed2d55538f4497d7894f1f599f020afd47f22627085df07f425cfef066911c3879d643ddd0739b39f52027
6
+ metadata.gz: 8f14e31048992941c30e753cf0ad84e066063ec667b66d5718c4d442acf2e5e1202b9bb7d70c391f720f32554cb518cde25de19c0166da4c2722cbe2ac66b0bf
7
+ data.tar.gz: '094c74f0c2939dab9312171da51889a121b8a1f6baed947bc11942ebde119211373f785abf5d8d81b8b1f9cf4818e3b2b8d6bedfe9ace572a7ce6beab765b73a'
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # ERPC SDK for Ruby
2
2
 
3
3
  Synchronous Ruby client for ERPC. It covers standard Solana, Ethereum, and
4
- Avalanche C-Chain JSON-RPC, indexed data, analytics, WebSocket subscriptions,
4
+ Avalanche C/P/X-chain JSON-RPC, indexed data, analytics, WebSocket subscriptions,
5
5
  price REST and server-sent events, account usage, and scoped Cloud reads.
6
6
 
7
7
  ```bash
@@ -47,14 +47,28 @@ only when `send` is called. `request` restricts calls to the namespace catalog;
47
47
  | `erpc.ethereum.subscriptions` | Ethereum WebSocket subscriptions |
48
48
  | `erpc.avalanche.rpc` | Avalanche C-Chain EVM-compatible JSON-RPC |
49
49
  | `erpc.avalanche.subscriptions` | Avalanche C-Chain WebSocket subscriptions |
50
+ | `erpc.avalanche.avax` | C-Chain AVAX atomic transaction API |
51
+ | `erpc.avalanche.x_chain` | X-Chain API |
52
+ | `erpc.avalanche.p_chain` | P-Chain API |
53
+ | `erpc.avalanche.proposer_vm` | P-Chain proposer VM API |
54
+ | `erpc.avalanche.info` | Network upgrade information |
55
+ | `erpc.avalanche.index` | C/P/X block and X transaction indexes |
50
56
  | `erpc.price` | Price metadata, updates, and SSE streams |
51
57
  | `erpc.account` | Token balance |
52
58
  | `erpc.usage` | Masked monthly API-key usage |
53
59
 
54
60
  `avalanche_endpoint` defaults to `https://ava-rpc.erpc.global` and can be
55
61
  overridden independently. The SDK uses its `/ava` HTTP route and `/ava-ws`
56
- WebSocket route. The Avalanche namespace uses the Ethereum-compatible typed
57
- catalog; use `raw` for additional C-Chain methods.
62
+ WebSocket route. Native methods use named Hash parameters and Index calls use
63
+ explicit chain/container paths. Native and Index batches are rejected locally;
64
+ use `raw` with an exact wire method name for forward compatibility.
65
+
66
+ ```ruby
67
+ p_height = erpc.avalanche.p_chain.get_height.send
68
+ indexed_tx = erpc.avalanche.index.x_chain_transactions
69
+ .get_container_by_id(id: transaction_id)
70
+ .send
71
+ ```
58
72
 
59
73
  ## Intact batches
60
74
 
@@ -3,7 +3,24 @@
3
3
  module ERPC
4
4
  SolanaClient = Struct.new(:rpc, :das, :history, :leaders, :analytics, :subscriptions, keyword_init: true)
5
5
  EthereumClient = Struct.new(:rpc, :subscriptions, keyword_init: true)
6
- AvalancheClient = Struct.new(:rpc, :subscriptions, keyword_init: true)
6
+ AvalancheIndexClient = Struct.new(
7
+ :c_chain_blocks,
8
+ :p_chain_blocks,
9
+ :x_chain_blocks,
10
+ :x_chain_transactions,
11
+ keyword_init: true
12
+ )
13
+ AvalancheClient = Struct.new(
14
+ :rpc,
15
+ :avax,
16
+ :x_chain,
17
+ :p_chain,
18
+ :proposer_vm,
19
+ :info,
20
+ :index,
21
+ :subscriptions,
22
+ keyword_init: true
23
+ )
7
24
 
8
25
  class Client
9
26
  attr_reader :solana, :ethereum, :avalanche, :price, :account, :usage
@@ -31,6 +48,15 @@ module ERPC
31
48
  timeout: config.timeout,
32
49
  adapter: adapter
33
50
  )
51
+ avalanche_index_transport = lambda do |path|
52
+ HttpJsonRpcTransport.new(
53
+ api_key: config.api_key,
54
+ endpoint: URLs.with_path(config.avalanche_endpoint, path),
55
+ headers: config.headers,
56
+ timeout: config.timeout,
57
+ adapter: adapter
58
+ )
59
+ end
34
60
  solana_ws = WebSocketJsonRpcTransport.new(
35
61
  URLs.websocket(config.endpoint, config.api_key),
36
62
  config.api_key,
@@ -78,6 +104,37 @@ module ERPC
78
104
  )
79
105
  @avalanche = AvalancheClient.new(
80
106
  rpc: RpcNamespace.new(avalanche_transport, ETHEREUM_RPC_METHODS, parameter_mode: :positional),
107
+ avax: avalanche_namespace(avalanche_transport, AVALANCHE_AVAX_METHODS, "avax"),
108
+ x_chain: avalanche_namespace(avalanche_transport, AVALANCHE_X_CHAIN_METHODS, "avm"),
109
+ p_chain: avalanche_namespace(avalanche_transport, AVALANCHE_P_CHAIN_METHODS, "platform"),
110
+ proposer_vm: avalanche_namespace(
111
+ avalanche_transport,
112
+ AVALANCHE_PROPOSER_VM_METHODS,
113
+ "proposervm"
114
+ ),
115
+ info: avalanche_namespace(avalanche_transport, AVALANCHE_INFO_METHODS, "info"),
116
+ index: AvalancheIndexClient.new(
117
+ c_chain_blocks: avalanche_namespace(
118
+ avalanche_index_transport.call("/ava/ext/index/C/block"),
119
+ AVALANCHE_INDEX_METHODS,
120
+ "index"
121
+ ),
122
+ p_chain_blocks: avalanche_namespace(
123
+ avalanche_index_transport.call("/ava/ext/index/P/block"),
124
+ AVALANCHE_INDEX_METHODS,
125
+ "index"
126
+ ),
127
+ x_chain_blocks: avalanche_namespace(
128
+ avalanche_index_transport.call("/ava/ext/index/X/block"),
129
+ AVALANCHE_INDEX_METHODS,
130
+ "index"
131
+ ),
132
+ x_chain_transactions: avalanche_namespace(
133
+ avalanche_index_transport.call("/ava/ext/index/X/tx"),
134
+ AVALANCHE_INDEX_METHODS,
135
+ "index"
136
+ )
137
+ ),
81
138
  subscriptions: EthereumSubscriptions.new(avalanche_ws)
82
139
  )
83
140
  @price = PriceClient.new(
@@ -119,6 +176,18 @@ module ERPC
119
176
  avalanche.subscriptions.close
120
177
  nil
121
178
  end
179
+
180
+ private
181
+
182
+ def avalanche_namespace(transport, methods, prefix)
183
+ RpcNamespace.new(
184
+ transport,
185
+ methods,
186
+ parameter_mode: :named,
187
+ batch_policy: :unsupported,
188
+ method_prefix: prefix
189
+ )
190
+ end
122
191
  end
123
192
 
124
193
  class CloudClient
data/lib/erpc_sdk/rpc.rb CHANGED
@@ -162,6 +162,72 @@ module ERPC
162
162
  "eth_unsubscribe"
163
163
  ].freeze
164
164
 
165
+ AVALANCHE_AVAX_METHODS = [
166
+ "avax.getAtomicTx",
167
+ "avax.getAtomicTxStatus",
168
+ "avax.getUTXOs",
169
+ "avax.issueTx"
170
+ ].freeze
171
+
172
+ AVALANCHE_X_CHAIN_METHODS = [
173
+ "avm.buildGenesis",
174
+ "avm.getAllBalances",
175
+ "avm.getAssetDescription",
176
+ "avm.getBalance",
177
+ "avm.getBlockByHeight",
178
+ "avm.getHeight",
179
+ "avm.getTx",
180
+ "avm.getTxFee",
181
+ "avm.getTxStatus",
182
+ "avm.getUTXOs",
183
+ "avm.issueTx"
184
+ ].freeze
185
+
186
+ AVALANCHE_P_CHAIN_METHODS = [
187
+ "platform.getAllValidatorsAt",
188
+ "platform.getBalance",
189
+ "platform.getBlockchainStatus",
190
+ "platform.getBlockchains",
191
+ "platform.getCurrentSupply",
192
+ "platform.getCurrentValidators",
193
+ "platform.getFeeConfig",
194
+ "platform.getFeeState",
195
+ "platform.getHeight",
196
+ "platform.getMinStake",
197
+ "platform.getRewardUTXOs",
198
+ "platform.getStake",
199
+ "platform.getStakingAssetID",
200
+ "platform.getSubnets",
201
+ "platform.getTimestamp",
202
+ "platform.getTotalStake",
203
+ "platform.getTx",
204
+ "platform.getTxStatus",
205
+ "platform.getUTXOs",
206
+ "platform.getValidatorFeeConfig",
207
+ "platform.getValidatorFeeState",
208
+ "platform.getValidatorsAt",
209
+ "platform.issueTx",
210
+ "platform.sampleValidators",
211
+ "platform.validatedBy",
212
+ "platform.validates"
213
+ ].freeze
214
+
215
+ AVALANCHE_PROPOSER_VM_METHODS = [
216
+ "proposervm.getCurrentEpoch",
217
+ "proposervm.getProposedHeight"
218
+ ].freeze
219
+
220
+ AVALANCHE_INFO_METHODS = ["info.upgrades"].freeze
221
+
222
+ AVALANCHE_INDEX_METHODS = [
223
+ "index.getContainerByID",
224
+ "index.getContainerByIndex",
225
+ "index.getContainerRange",
226
+ "index.getIndex",
227
+ "index.getLastAccepted",
228
+ "index.isAccepted"
229
+ ].freeze
230
+
165
231
  HEAVY_SOLANA_METHODS = %w[
166
232
  getPriorityFeeEstimate
167
233
  getProgramAccounts
@@ -197,11 +263,16 @@ module ERPC
197
263
  class RpcNamespace
198
264
  attr_reader :endpoint
199
265
 
200
- def initialize(transport, methods, parameter_mode:, batch_policy: :any)
266
+ def initialize(transport, methods, parameter_mode:, batch_policy: :any, method_prefix: nil)
201
267
  @transport = transport
202
268
  @endpoint = transport.endpoint
203
- @methods = methods.to_h { |method| [method, true] }.freeze
204
- @aliases = methods.to_h { |method| [snake_case(method), method] }.freeze
269
+ prefix = method_prefix.nil? ? "" : "#{method_prefix}."
270
+ @wire_methods = methods.to_h do |method|
271
+ public_method = method.start_with?(prefix) ? method.delete_prefix(prefix) : method
272
+ [public_method, method]
273
+ end.freeze
274
+ @methods = @wire_methods.transform_values { true }.freeze
275
+ @aliases = @methods.to_h { |method, _| [snake_case(method), method] }.freeze
205
276
  @parameter_mode = parameter_mode
206
277
  @batch_policy = batch_policy
207
278
  end
@@ -211,7 +282,7 @@ module ERPC
211
282
  raise ConfigError, "#{method.inspect} is not in this namespace; use raw for forward-compatible methods"
212
283
  end
213
284
 
214
- PendingRpcRequest.new(@transport, method, params, decoder || ->(value) { value })
285
+ PendingRpcRequest.new(@transport, @wire_methods.fetch(method), params, decoder || ->(value) { value })
215
286
  end
216
287
 
217
288
  def raw(method, params = nil, decoder: nil)
@@ -222,7 +293,7 @@ module ERPC
222
293
 
223
294
  def batch(calls)
224
295
  if @batch_policy == :unsupported && !calls.empty?
225
- raise BatchPolicyError, "Leader RPC methods do not support batching"
296
+ raise BatchPolicyError, "This RPC namespace does not support batching"
226
297
  end
227
298
  if @batch_policy == :solana_standard
228
299
  methods = calls.map { |call| call[:method] || call["method"] }
@@ -233,7 +304,12 @@ module ERPC
233
304
  end
234
305
  end
235
306
 
236
- PendingRpcBatchRequest.new(@transport, calls)
307
+ wire_calls = if @wire_methods.any? { |method, wire| method != wire }
308
+ calls.map { |call| wire_call(call) }
309
+ else
310
+ calls
311
+ end
312
+ PendingRpcBatchRequest.new(@transport, wire_calls)
237
313
  end
238
314
 
239
315
  def method_missing(name, *arguments, &block)
@@ -262,6 +338,18 @@ module ERPC
262
338
 
263
339
  private
264
340
 
341
+ def wire_call(call)
342
+ method = call[:method] || call["method"]
343
+ unless @wire_methods.key?(method)
344
+ raise ConfigError, "#{method.inspect} is not in this namespace; use raw for forward-compatible methods"
345
+ end
346
+
347
+ mapped = { method: @wire_methods.fetch(method) }
348
+ mapped[:params] = call[:params] if call.key?(:params)
349
+ mapped[:params] = call["params"] if call.key?("params")
350
+ mapped
351
+ end
352
+
265
353
  def snake_case(value)
266
354
  value.gsub(/(?<=[a-z0-9])(?=[A-Z])/, "_").downcase
267
355
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ERPC
4
- VERSION = "0.5.0"
4
+ VERSION = "0.6.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: erpc-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ELSOUL LABO B.V.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-04 00:00:00.000000000 Z
11
+ date: 2026-09-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest