subxt_rpcs/methods/
legacy.rs

1// Copyright 2019-2025 Parity Technologies (UK) Ltd.
2// This file is dual-licensed as Apache-2.0 or GPL-3.0.
3// see LICENSE for license details.
4
5//! An interface to call the raw legacy RPC methods.
6
7use crate::client::{RpcClient, RpcSubscription, rpc_params};
8use crate::{Error, RpcConfig};
9use codec::Decode;
10use derive_where::derive_where;
11use frame_metadata::RuntimeMetadataPrefixed;
12use primitive_types::U256;
13use serde::{Deserialize, Serialize};
14
15/// An interface to call the legacy RPC methods. This interface is instantiated with
16/// some `T: Config` trait which determines some of the types that the RPC methods will
17/// take or hand back.
18#[derive_where(Clone, Debug)]
19pub struct LegacyRpcMethods<T> {
20    client: RpcClient,
21    _marker: std::marker::PhantomData<T>,
22}
23
24impl<T: RpcConfig> LegacyRpcMethods<T> {
25    /// Instantiate the legacy RPC method interface.
26    pub fn new(client: RpcClient) -> Self {
27        LegacyRpcMethods {
28            client,
29            _marker: std::marker::PhantomData,
30        }
31    }
32
33    /// Fetch the raw bytes for a given storage key
34    pub async fn state_get_storage(
35        &self,
36        key: &[u8],
37        hash: Option<T::Hash>,
38    ) -> Result<Option<StorageData>, Error> {
39        let params = rpc_params![to_hex(key), hash];
40        let data: Option<Bytes> = self.client.request("state_getStorage", params).await?;
41        Ok(data.map(|b| b.0))
42    }
43
44    /// Returns the keys with prefix with pagination support.
45    /// Up to `count` keys will be returned.
46    /// If `start_key` is passed, return next keys in storage in lexicographic order.
47    pub async fn state_get_keys_paged(
48        &self,
49        key: &[u8],
50        count: u32,
51        start_key: Option<&[u8]>,
52        at: Option<T::Hash>,
53    ) -> Result<Vec<StorageKey>, Error> {
54        let start_key = start_key.map(to_hex);
55        let params = rpc_params![to_hex(key), count, start_key, at];
56        let data: Vec<Bytes> = self.client.request("state_getKeysPaged", params).await?;
57        Ok(data.into_iter().map(|b| b.0).collect())
58    }
59
60    /// Query historical storage entries in the range from the start block to the end block,
61    /// defaulting the end block to the current best block if it's not given. The first
62    /// [`StorageChangeSet`] returned has all of the values for each key, and subsequent ones
63    /// only contain values for any keys which have changed since the last.
64    pub async fn state_query_storage(
65        &self,
66        keys: impl IntoIterator<Item = &[u8]>,
67        from: T::Hash,
68        to: Option<T::Hash>,
69    ) -> Result<Vec<StorageChangeSet<T::Hash>>, Error> {
70        let keys: Vec<String> = keys.into_iter().map(to_hex).collect();
71        let params = rpc_params![keys, from, to];
72        self.client.request("state_queryStorage", params).await
73    }
74
75    /// Query storage entries at some block, using the best block if none is given.
76    /// This essentially provides a way to ask for a batch of values given a batch of keys,
77    /// despite the name of the [`StorageChangeSet`] type.
78    pub async fn state_query_storage_at(
79        &self,
80        keys: impl IntoIterator<Item = &[u8]>,
81        at: Option<T::Hash>,
82    ) -> Result<Vec<StorageChangeSet<T::Hash>>, Error> {
83        let keys: Vec<String> = keys.into_iter().map(to_hex).collect();
84        let params = rpc_params![keys, at];
85        self.client.request("state_queryStorageAt", params).await
86    }
87
88    /// Fetch the genesis hash
89    pub async fn genesis_hash(&self) -> Result<T::Hash, Error> {
90        let block_zero = 0u32;
91        let params = rpc_params![block_zero];
92        let genesis_hash: Option<T::Hash> =
93            self.client.request("chain_getBlockHash", params).await?;
94        genesis_hash.ok_or_else(|| Error::Client("Genesis hash not found".into()))
95    }
96
97    /// Fetch the metadata via the legacy `state_getMetadata` RPC method.
98    pub async fn state_get_metadata(
99        &self,
100        at: Option<T::Hash>,
101    ) -> Result<StateGetMetadataResponse, Error> {
102        let bytes: Bytes = self
103            .client
104            .request("state_getMetadata", rpc_params![at])
105            .await?;
106        Ok(StateGetMetadataResponse(bytes.0))
107    }
108
109    /// Fetch system health
110    pub async fn system_health(&self) -> Result<SystemHealth, Error> {
111        self.client.request("system_health", rpc_params![]).await
112    }
113
114    /// Fetch system chain
115    pub async fn system_chain(&self) -> Result<String, Error> {
116        self.client.request("system_chain", rpc_params![]).await
117    }
118
119    /// Fetch system name
120    pub async fn system_name(&self) -> Result<String, Error> {
121        self.client.request("system_name", rpc_params![]).await
122    }
123
124    /// Fetch system version
125    pub async fn system_version(&self) -> Result<String, Error> {
126        self.client.request("system_version", rpc_params![]).await
127    }
128
129    /// Fetch system properties
130    pub async fn system_properties(&self) -> Result<SystemProperties, Error> {
131        self.client
132            .request("system_properties", rpc_params![])
133            .await
134    }
135
136    /// Fetch next nonce for an Account
137    ///
138    /// Return account nonce adjusted for extrinsics currently in transaction pool
139    pub async fn system_account_next_index(&self, account_id: &T::AccountId) -> Result<u64, Error> {
140        self.client
141            .request("system_accountNextIndex", rpc_params![&account_id])
142            .await
143    }
144
145    /// Get a header
146    pub async fn chain_get_header(
147        &self,
148        hash: Option<T::Hash>,
149    ) -> Result<Option<T::Header>, Error> {
150        let params = rpc_params![hash];
151        let header = self.client.request("chain_getHeader", params).await?;
152        Ok(header)
153    }
154
155    /// Get a block hash, returns hash of latest _best_ block by default.
156    pub async fn chain_get_block_hash(
157        &self,
158        block_number: Option<BlockNumber>,
159    ) -> Result<Option<T::Hash>, Error> {
160        let params = rpc_params![block_number];
161        let block_hash = self.client.request("chain_getBlockHash", params).await?;
162        Ok(block_hash)
163    }
164
165    /// Get a block hash of the latest finalized block
166    pub async fn chain_get_finalized_head(&self) -> Result<T::Hash, Error> {
167        let hash = self
168            .client
169            .request("chain_getFinalizedHead", rpc_params![])
170            .await?;
171        Ok(hash)
172    }
173
174    /// Get a Block
175    pub async fn chain_get_block(
176        &self,
177        hash: Option<T::Hash>,
178    ) -> Result<Option<BlockDetails<T>>, Error> {
179        let params = rpc_params![hash];
180        let block = self.client.request("chain_getBlock", params).await?;
181        Ok(block)
182    }
183
184    /// Reexecute the specified `block_hash` and gather statistics while doing so.
185    ///
186    /// This function requires the specified block and its parent to be available
187    /// at the queried node. If either the specified block or the parent is pruned,
188    /// this function will return `None`.
189    pub async fn dev_get_block_stats(
190        &self,
191        block_hash: T::Hash,
192    ) -> Result<Option<BlockStats>, Error> {
193        let params = rpc_params![block_hash];
194        let stats = self.client.request("dev_getBlockStats", params).await?;
195        Ok(stats)
196    }
197
198    /// Get proof of storage entries at a specific block's state.
199    pub async fn state_get_read_proof(
200        &self,
201        keys: impl IntoIterator<Item = &[u8]>,
202        hash: Option<T::Hash>,
203    ) -> Result<ReadProof<T::Hash>, Error> {
204        let keys: Vec<String> = keys.into_iter().map(to_hex).collect();
205        let params = rpc_params![keys, hash];
206        let proof = self.client.request("state_getReadProof", params).await?;
207        Ok(proof)
208    }
209
210    /// Fetch the runtime version
211    pub async fn state_get_runtime_version(
212        &self,
213        at: Option<T::Hash>,
214    ) -> Result<RuntimeVersion, Error> {
215        let params = rpc_params![at];
216        let version = self
217            .client
218            .request("state_getRuntimeVersion", params)
219            .await?;
220        Ok(version)
221    }
222
223    /// Subscribe to all new best block headers.
224    pub async fn chain_subscribe_new_heads(&self) -> Result<RpcSubscription<T::Header>, Error> {
225        let subscription = self
226            .client
227            .subscribe(
228                // Despite the name, this returns a stream of all new blocks
229                // imported by the node that happen to be added to the current best chain
230                // (ie all best blocks).
231                "chain_subscribeNewHeads",
232                rpc_params![],
233                "chain_unsubscribeNewHeads",
234            )
235            .await?;
236
237        Ok(subscription)
238    }
239
240    /// Subscribe to all new block headers.
241    pub async fn chain_subscribe_all_heads(&self) -> Result<RpcSubscription<T::Header>, Error> {
242        let subscription = self
243            .client
244            .subscribe(
245                // Despite the name, this returns a stream of all new blocks
246                // imported by the node that happen to be added to the current best chain
247                // (ie all best blocks).
248                "chain_subscribeAllHeads",
249                rpc_params![],
250                "chain_unsubscribeAllHeads",
251            )
252            .await?;
253
254        Ok(subscription)
255    }
256
257    /// Subscribe to finalized block headers.
258    ///
259    /// Note: this may not produce _every_ block in the finalized chain;
260    /// sometimes multiple blocks are finalized at once, and in this case only the
261    /// latest one is returned. the higher level APIs that use this "fill in" the
262    /// gaps for us.
263    pub async fn chain_subscribe_finalized_heads(
264        &self,
265    ) -> Result<RpcSubscription<T::Header>, Error> {
266        let subscription = self
267            .client
268            .subscribe(
269                "chain_subscribeFinalizedHeads",
270                rpc_params![],
271                "chain_unsubscribeFinalizedHeads",
272            )
273            .await?;
274        Ok(subscription)
275    }
276
277    /// Subscribe to runtime version updates that produce changes in the metadata.
278    /// The first item emitted by the stream is the current runtime version.
279    pub async fn state_subscribe_runtime_version(
280        &self,
281    ) -> Result<RpcSubscription<RuntimeVersion>, Error> {
282        let subscription = self
283            .client
284            .subscribe(
285                "state_subscribeRuntimeVersion",
286                rpc_params![],
287                "state_unsubscribeRuntimeVersion",
288            )
289            .await?;
290        Ok(subscription)
291    }
292
293    /// Create and submit an extrinsic and return corresponding Hash if successful
294    pub async fn author_submit_extrinsic(&self, extrinsic: &[u8]) -> Result<T::Hash, Error> {
295        let params = rpc_params![to_hex(extrinsic)];
296        let xt_hash = self
297            .client
298            .request("author_submitExtrinsic", params)
299            .await?;
300        Ok(xt_hash)
301    }
302
303    /// Create and submit an extrinsic and return a subscription to the events triggered.
304    pub async fn author_submit_and_watch_extrinsic(
305        &self,
306        extrinsic: &[u8],
307    ) -> Result<RpcSubscription<TransactionStatus<T::Hash>>, Error> {
308        let params = rpc_params![to_hex(extrinsic)];
309        let subscription = self
310            .client
311            .subscribe(
312                "author_submitAndWatchExtrinsic",
313                params,
314                "author_unwatchExtrinsic",
315            )
316            .await?;
317        Ok(subscription)
318    }
319
320    /// Insert a key into the keystore.
321    pub async fn author_insert_key(
322        &self,
323        key_type: String,
324        suri: String,
325        public: Vec<u8>,
326    ) -> Result<(), Error> {
327        let params = rpc_params![key_type, suri, Bytes(public)];
328        self.client.request("author_insertKey", params).await
329    }
330
331    /// Generate new session keys and returns the corresponding public keys.
332    pub async fn author_rotate_keys(&self) -> Result<Vec<u8>, Error> {
333        let bytes: Bytes = self
334            .client
335            .request("author_rotateKeys", rpc_params![])
336            .await?;
337        Ok(bytes.0)
338    }
339
340    /// Checks if the keystore has private keys for the given session public keys.
341    ///
342    /// `session_keys` is the SCALE encoded session keys object from the runtime.
343    ///
344    /// Returns `true` if all private keys could be found.
345    pub async fn author_has_session_keys(&self, session_keys: Vec<u8>) -> Result<bool, Error> {
346        let params = rpc_params![Bytes(session_keys)];
347        self.client.request("author_hasSessionKeys", params).await
348    }
349
350    /// Checks if the keystore has private keys for the given public key and key type.
351    ///
352    /// Returns `true` if a private key could be found.
353    pub async fn author_has_key(
354        &self,
355        public_key: Vec<u8>,
356        key_type: String,
357    ) -> Result<bool, Error> {
358        let params = rpc_params![Bytes(public_key), key_type];
359        self.client.request("author_hasKey", params).await
360    }
361
362    /// Execute a runtime API call via `state_call` RPC method.
363    pub async fn state_call(
364        &self,
365        function: &str,
366        call_parameters: Option<&[u8]>,
367        at: Option<T::Hash>,
368    ) -> Result<Vec<u8>, Error> {
369        let call_parameters = call_parameters.unwrap_or_default();
370        let bytes: Bytes = self
371            .client
372            .request(
373                "state_call",
374                rpc_params![function, to_hex(call_parameters), at],
375            )
376            .await?;
377        Ok(bytes.0)
378    }
379
380    /// Submits the extrinsic to the dry_run RPC, to test if it would succeed.
381    ///
382    /// Returns a [`DryRunResult`], which is the result of performing the dry run.
383    pub async fn dry_run(
384        &self,
385        encoded_signed: &[u8],
386        at: Option<T::Hash>,
387    ) -> Result<DryRunResultBytes, Error> {
388        let params = rpc_params![to_hex(encoded_signed), at];
389        let result_bytes: Bytes = self.client.request("system_dryRun", params).await?;
390        Ok(DryRunResultBytes(result_bytes.0))
391    }
392}
393
394/// Response from the legacy `state_get_metadata` RPC call.
395pub struct StateGetMetadataResponse(Vec<u8>);
396
397impl StateGetMetadataResponse {
398    /// Return the raw SCALE encoded metadata bytes
399    pub fn into_raw(self) -> Vec<u8> {
400        self.0
401    }
402    /// Decode and return [`frame_metadata::RuntimeMetadataPrefixed`].
403    pub fn to_frame_metadata(
404        &self,
405    ) -> Result<frame_metadata::RuntimeMetadataPrefixed, codec::Error> {
406        RuntimeMetadataPrefixed::decode(&mut &*self.0)
407    }
408}
409
410/// Storage key.
411pub type StorageKey = Vec<u8>;
412
413/// Storage data.
414pub type StorageData = Vec<u8>;
415
416/// Health struct returned by the RPC
417#[derive(Deserialize, Clone, Debug)]
418#[serde(rename_all = "camelCase")]
419pub struct SystemHealth {
420    /// Number of connected peers
421    pub peers: usize,
422    /// Is the node syncing
423    pub is_syncing: bool,
424    /// Should this node have any peers
425    ///
426    /// Might be false for local chains or when running without discovery.
427    pub should_have_peers: bool,
428}
429
430/// System properties; an arbitrary JSON object.
431pub type SystemProperties = serde_json::Map<String, serde_json::Value>;
432
433/// A block number
434pub type BlockNumber = NumberOrHex;
435
436/// The response from `chain_getBlock`
437#[derive(Debug, Deserialize)]
438#[serde(bound = "T: RpcConfig")]
439pub struct BlockDetails<T: RpcConfig> {
440    /// The block itself.
441    pub block: Block<T>,
442    /// Block justification.
443    pub justifications: Option<Vec<BlockJustification>>,
444}
445
446/// Block details in the [`BlockDetails`].
447#[derive(Debug, Deserialize)]
448pub struct Block<T: RpcConfig> {
449    /// The block header.
450    pub header: T::Header,
451    /// The accompanying extrinsics.
452    pub extrinsics: Vec<Bytes>,
453}
454
455/// An abstraction over justification for a block's validity under a consensus algorithm.
456pub type BlockJustification = (ConsensusEngineId, EncodedJustification);
457/// Consensus engine unique ID.
458pub type ConsensusEngineId = [u8; 4];
459/// The encoded justification specific to a consensus engine.
460pub type EncodedJustification = Vec<u8>;
461
462/// This contains the runtime version information necessary to make transactions, as obtained from
463/// the RPC call `state_getRuntimeVersion`,
464#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
465#[serde(rename_all = "camelCase")]
466pub struct RuntimeVersion {
467    /// Version of the runtime specification. A full-node will not attempt to use its native
468    /// runtime in substitute for the on-chain Wasm runtime unless all of `spec_name`,
469    /// `spec_version` and `authoring_version` are the same between Wasm and native.
470    pub spec_version: u32,
471
472    /// All existing dispatches are fully compatible when this number doesn't change. If this
473    /// number changes, then `spec_version` must change, also.
474    ///
475    /// This number must change when an existing dispatchable (module ID, dispatch ID) is changed,
476    /// either through an alteration in its user-level semantics, a parameter
477    /// added/removed/changed, a dispatchable being removed, a module being removed, or a
478    /// dispatchable/module changing its index.
479    ///
480    /// It need *not* change when a new module is added or when a dispatchable is added.
481    pub transaction_version: u32,
482
483    /// Fields unnecessary to Subxt are written out to this map.
484    #[serde(flatten)]
485    pub other: std::collections::HashMap<String, serde_json::Value>,
486}
487
488/// Possible transaction status events.
489///
490/// # Note
491///
492/// This is copied from `sp-transaction-pool` to avoid a dependency on that crate. Therefore it
493/// must be kept compatible with that type from the target substrate version.
494#[derive(Debug, Deserialize)]
495#[serde(rename_all = "camelCase")]
496pub enum TransactionStatus<Hash> {
497    /// Transaction is part of the future queue.
498    Future,
499    /// Transaction is part of the ready queue.
500    Ready,
501    /// The transaction has been broadcast to the given peers.
502    Broadcast(Vec<String>),
503    /// Transaction has been included in block with given hash.
504    InBlock(Hash),
505    /// The block this transaction was included in has been retracted.
506    Retracted(Hash),
507    /// Maximum number of finality watchers has been reached,
508    /// old watchers are being removed.
509    FinalityTimeout(Hash),
510    /// Transaction has been finalized by a finality-gadget, e.g GRANDPA
511    Finalized(Hash),
512    /// Transaction has been replaced in the pool, by another transaction
513    /// that provides the same tags. (e.g. same (sender, nonce)).
514    Usurped(Hash),
515    /// Transaction has been dropped from the pool because of the limit.
516    Dropped,
517    /// Transaction is no longer valid in the current state.
518    Invalid,
519}
520
521/// The decoded result returned from calling `system_dryRun` on some extrinsic.
522#[derive(Debug, PartialEq, Eq)]
523pub enum DryRunResult<'a> {
524    /// The transaction could be included in the block and executed.
525    Success,
526    /// The transaction could be included in the block, but the call failed to dispatch.
527    /// If Subxt is available, the bytes here can be further decoded by calling:
528    ///
529    /// ```rust,ignore
530    /// subxt::error::DispatchError::decode_from(bytes, metadata)?;
531    /// ```
532    ///
533    /// Where metadata is an instance of `subxt::Metadata` that is valid for the runtime
534    /// version which returned this error.
535    DispatchError(&'a [u8]),
536    /// The transaction could not be included in the block.
537    TransactionValidityError,
538}
539
540/// The bytes representing an error dry running an extrinsic. call [`DryRunResultBytes::into_dry_run_result`]
541/// to attempt to decode this into something more meaningful.
542pub struct DryRunResultBytes(pub Vec<u8>);
543
544impl DryRunResultBytes {
545    /// Attempt to decode the error bytes into a [`DryRunResult`].
546    pub fn into_dry_run_result(&self) -> Result<DryRunResult<'_>, DryRunDecodeError> {
547        // dryRun returns an ApplyExtrinsicResult, which is basically a
548        // `Result<Result<(), DispatchError>, TransactionValidityError>`.
549        let bytes = &*self.0;
550
551        // We expect at least 2 bytes. In case we got a naff response back (or
552        // manually constructed this struct), just error to avoid a panic:
553        if bytes.len() < 2 {
554            return Err(DryRunDecodeError::WrongNumberOfBytes);
555        }
556
557        if bytes[0] == 0 && bytes[1] == 0 {
558            // Ok(Ok(())); transaction is valid and executed ok
559            Ok(DryRunResult::Success)
560        } else if bytes[0] == 0 && bytes[1] == 1 {
561            // Ok(Err(dispatch_error)); transaction is valid but execution failed
562            Ok(DryRunResult::DispatchError(&bytes[2..]))
563        } else if bytes[0] == 1 {
564            // Err(transaction_error); some transaction validity error (we ignore the details at the moment)
565            Ok(DryRunResult::TransactionValidityError)
566        } else {
567            // unable to decode the bytes; they aren't what we expect.
568            Err(DryRunDecodeError::InvalidBytes)
569        }
570    }
571}
572
573/// An error which can be emitted when calling [`DryRunResultBytes::into_dry_run_result`].
574pub enum DryRunDecodeError {
575    /// The dry run result was less than 2 bytes, which is invalid.
576    WrongNumberOfBytes,
577    /// The dry run bytes are not valid.
578    InvalidBytes,
579}
580
581/// Storage change set
582#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Debug)]
583#[serde(rename_all = "camelCase")]
584pub struct StorageChangeSet<Hash> {
585    /// Block hash
586    pub block: Hash,
587    /// A list of changes; tuples of storage key and optional storage data.
588    pub changes: Vec<(Bytes, Option<Bytes>)>,
589}
590
591/// Statistics of a block returned by the `dev_getBlockStats` RPC.
592#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
593#[serde(rename_all = "camelCase")]
594pub struct BlockStats {
595    /// The length in bytes of the storage proof produced by executing the block.
596    pub witness_len: u64,
597    /// The length in bytes of the storage proof after compaction.
598    pub witness_compact_len: u64,
599    /// Length of the block in bytes.
600    ///
601    /// This information can also be acquired by downloading the whole block. This merely
602    /// saves some complexity on the client side.
603    pub block_len: u64,
604    /// Number of extrinsics in the block.
605    ///
606    /// This information can also be acquired by downloading the whole block. This merely
607    /// saves some complexity on the client side.
608    pub num_extrinsics: u64,
609}
610
611/// ReadProof struct returned by the RPC
612///
613/// # Note
614///
615/// This is copied from `sc-rpc-api` to avoid a dependency on that crate. Therefore it
616/// must be kept compatible with that type from the target substrate version.
617#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
618#[serde(rename_all = "camelCase")]
619pub struct ReadProof<Hash> {
620    /// Block hash used to generate the proof
621    pub at: Hash,
622    /// A proof used to prove that storage entries are included in the storage trie
623    pub proof: Vec<Bytes>,
624}
625
626/// A number type that can be serialized both as a number or a string that encodes a number in a
627/// string.
628///
629/// We allow two representations of the block number as input. Either we deserialize to the type
630/// that is specified in the block type or we attempt to parse given hex value.
631///
632/// The primary motivation for having this type is to avoid overflows when using big integers in
633/// JavaScript (which we consider as an important RPC API consumer).
634#[derive(Copy, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
635#[serde(untagged)]
636pub enum NumberOrHex {
637    /// The number represented directly.
638    Number(u64),
639    /// Hex representation of the number.
640    Hex(U256),
641}
642
643impl NumberOrHex {
644    /// Converts this number into an U256.
645    pub fn into_u256(self) -> U256 {
646        match self {
647            NumberOrHex::Number(n) => n.into(),
648            NumberOrHex::Hex(h) => h,
649        }
650    }
651}
652
653impl From<NumberOrHex> for U256 {
654    fn from(num_or_hex: NumberOrHex) -> U256 {
655        num_or_hex.into_u256()
656    }
657}
658
659macro_rules! into_number_or_hex {
660    ($($t: ty)+) => {
661        $(
662            impl From<$t> for NumberOrHex {
663                fn from(x: $t) -> Self {
664                    NumberOrHex::Number(x.into())
665                }
666            }
667        )+
668    }
669}
670into_number_or_hex!(u8 u16 u32 u64);
671
672impl From<u128> for NumberOrHex {
673    fn from(n: u128) -> Self {
674        NumberOrHex::Hex(n.into())
675    }
676}
677
678impl From<U256> for NumberOrHex {
679    fn from(n: U256) -> Self {
680        NumberOrHex::Hex(n)
681    }
682}
683
684/// A quick helper to encode some bytes to hex.
685fn to_hex(bytes: impl AsRef<[u8]>) -> String {
686    format!("0x{}", hex::encode(bytes.as_ref()))
687}
688
689/// Hex-serialized shim for `Vec<u8>`.
690#[derive(PartialEq, Eq, Clone, Serialize, Deserialize, Hash, PartialOrd, Ord, Debug)]
691pub struct Bytes(#[serde(with = "impl_serde::serialize")] pub Vec<u8>);
692impl std::ops::Deref for Bytes {
693    type Target = [u8];
694    fn deref(&self) -> &[u8] {
695        &self.0[..]
696    }
697}
698impl From<Vec<u8>> for Bytes {
699    fn from(s: Vec<u8>) -> Self {
700        Bytes(s)
701    }
702}