AlchemyMiddleware for Provider {
22 | // async fn alchemy_pending_transactions + Send + Sync + serde::Serialize>(
23 | // &self,
24 | // to: Option,
25 | // from: Option,
26 | // ) -> Result, Self::Error> {
27 | // let params = vec![
28 | // to.map(|t| serde_json::to_value(t).expect("Types never fail to serialize.")),
29 | // from.map(|t| serde_json::to_value(t).expect("Types never fail to serialize.")),
30 | // ]
31 | // .into_iter()
32 | // .flatten()
33 | // .collect();
34 | // self.request("alchemy_pendingTransactions", params).await
35 | // }
36 | // }
37 |
--------------------------------------------------------------------------------
/tests/manager.rs:
--------------------------------------------------------------------------------
1 | use std::str::FromStr;
2 |
3 | use ethers::types::Address;
4 |
5 | use alchemy_rs::{prelude::*, connectors::AlchemyConnectorType};
6 |
7 | #[actix_rt::test]
8 | async fn test_alchemy_subscription() {
9 | // Create the AlchemyManager
10 | let mut manager = AlchemyManager::new(
11 | "wss://eth-mainnet.g.alchemy.com/v2/MVNYMOb_58bAMzhXX2pS25NDiZ3Q9HeC",
12 | Some(AlchemyConnectorType::Raw),
13 | );
14 |
15 | // Connect to the websocket
16 | let _ = manager.connect().await.unwrap();
17 |
18 | // Listen to _pending_ transactions to the USDT address on mainnet
19 | // (there should be a lot of these!)
20 | let usdt_address = Address::from_str("dac17f958d2ee523a2206206994597c13d831ec7").unwrap();
21 |
22 | // Try to subscribe to pending transactions
23 | let sub_id = match manager.subscribe(Some(usdt_address), None).await {
24 | Ok(id) => id,
25 | Err(e) => {
26 | println!("Error subscribing to pending transactions: {:?}", e);
27 | return;
28 | }
29 | };
30 |
31 | // Now we can grab items from the stream
32 | let item = match manager.receive(sub_id).await {
33 | Ok(i) => i,
34 | Err(e) => {
35 | println!("Error receiving item: {:?}", e);
36 | return;
37 | }
38 | };
39 |
40 | // Print the next item
41 | println!("Received pending transaction from the stream: {:?}", item);
42 | }
43 |
--------------------------------------------------------------------------------
/tests/messages.rs:
--------------------------------------------------------------------------------
1 | use alchemy_rs::messages::{
2 | outbound::{AlchemySocketMessage, OutSocketMethod},
3 | prelude::AlchemySubscriptionMessageResult,
4 | };
5 |
6 | mod util;
7 |
8 | #[test]
9 | fn test_outbound_alchemy_socket_message_serialization() {
10 | // Craft an expected alchemy outbound eth_subscribe socket message json string
11 | let expected = r#"{
12 | "id": 1,
13 | "method": "eth_subscribe",
14 | "params": [
15 | "alchemy_pendingTransactions",
16 | {
17 | "toAddress": "dac17f958d2ee523a2206206994597c13d831ec7"
18 | }
19 | ]
20 | }"#;
21 |
22 | // Construct a raw outbound alchemy socket message
23 | let mut map = serde_json::Map::new();
24 | map.insert(
25 | "toAddress".to_string(),
26 | serde_json::Value::String("dac17f958d2ee523a2206206994597c13d831ec7".to_string()),
27 | );
28 | let constructed = AlchemySocketMessage {
29 | id: 1,
30 | method: OutSocketMethod::Subscribe,
31 | params: vec![
32 | serde_json::Value::String(String::from("alchemy_pendingTransactions")),
33 | serde_json::Value::Object(map),
34 | ],
35 | };
36 |
37 | // Make sure it can serialize to the expected string
38 | let serialized_string = match serde_json::to_string(&constructed) {
39 | Ok(s) => {
40 | util::assert_strings_roughly_equal(&s, expected);
41 | s
42 | }
43 | Err(e) => panic!("Failed to serialize outbound message: {}", e),
44 | };
45 |
46 | // Now take the resulting serialized string and deserialize it into an alchemy outbound socket message
47 | let deserialized = match serde_json::from_str::(&serialized_string) {
48 | Ok(d) => d,
49 | Err(e) => panic!("Failed to deserialize outbound message: {}", e),
50 | };
51 |
52 | // Make sure the deserialized message is the same as the constructed message
53 | assert_eq!(constructed, deserialized);
54 | }
55 |
56 | #[test]
57 | fn test_inbound_alchemy_subscription_message_result_serialization() {
58 | // Craft the expected json string
59 | let expected = r#"{
60 | "id": 1,
61 | "result": "0xa79a6df98fb2a42516b5aca3177fbb6c",
62 | "jsonrpc": "2.0"
63 | }"#;
64 |
65 | // Construct a concrete struct
66 | let constructed = AlchemySubscriptionMessageResult {
67 | id: 1,
68 | result: uuid::Uuid::parse_str("a79a6df98fb2a42516b5aca3177fbb6c").unwrap(),
69 | jsonrpc: "2.0".to_string(),
70 | };
71 |
72 | // Validate serialization
73 | let serialized_string = match serde_json::to_string(&constructed) {
74 | Ok(s) => {
75 | util::assert_strings_roughly_equal(&s, expected);
76 | s
77 | }
78 | Err(e) => panic!("Failed to serialize: {}", e),
79 | };
80 |
81 | // Now take the resulting serialized string and deserialize it
82 | let deserialized =
83 | match serde_json::from_str::(&serialized_string) {
84 | Ok(d) => d,
85 | Err(e) => panic!("Failed to deserialize: {}", e),
86 | };
87 |
88 | // Make sure the deserialized message is the same as the constructed message
89 | assert_eq!(constructed, deserialized);
90 | }
91 |
--------------------------------------------------------------------------------
/tests/sockets.rs:
--------------------------------------------------------------------------------
1 | use tokio_util::compat::TokioAsyncReadCompatExt;
2 |
3 | #[actix_rt::test]
4 | async fn test_connecting_to_alchemy() {
5 | // Create the socket connection
6 | let socket = match tokio::net::TcpStream::connect("eth-mainnet.g.alchemy.com:443").await {
7 | Ok(s) => s,
8 | Err(e) => panic!("Could not connect to Alchemy: {:?}", e),
9 | };
10 | println!("Create socket connection to Alchemy");
11 |
12 | // Create the client connection
13 | let compatible_socket = futures::io::BufReader::new(futures::io::BufWriter::new(socket.compat()));
14 | let mut client = soketto::handshake::Client::new(compatible_socket, "ws://eth-mainnet.g.alchemy.com", "/v2/MVNYMOb_58bAMzhXX2pS25NDiZ3Q9HeC");
15 | println!("Created client connection");
16 |
17 | // let api_key = "MVNYMOb_58bAMzhXX2pS25NDiZ3Q9HeC".as_bytes().to_vec();
18 | let gzip = "gzip".as_bytes().to_vec();
19 | let version = "2.0.3".as_bytes().to_vec();
20 | let auth_header = vec![
21 | // soketto::handshake::client::Header {
22 | // name: "ALCHEMY_API_KEY",
23 | // value: &api_key,
24 | // },
25 | soketto::handshake::client::Header {
26 | name: "Alchemy-Ethers-Sdk-Version",
27 | value: &version,
28 | },
29 | soketto::handshake::client::Header {
30 | name: "Accept-Encoding",
31 | value: &gzip,
32 | },
33 | ];
34 | client.set_headers(auth_header.as_slice());
35 |
36 | // Handshake the connection
37 | match client.handshake().await {
38 | Ok(sr) => {
39 | match sr {
40 | soketto::handshake::ServerResponse::Accepted { protocol } => {
41 | println!("Accepted protocol: {:?}", protocol);
42 | }
43 | soketto::handshake::ServerResponse::Redirect { status_code, location } => {
44 | println!("Redirected with status code: {}, location: {}", status_code, location);
45 | }
46 | soketto::handshake::ServerResponse::Rejected { status_code } => {
47 | println!("Rejected with status code: {}", status_code);
48 | panic!("Rejected with status code: {}", status_code);
49 | }
50 | }
51 | }
52 | Err(e) => panic!("Handshake error! {:?}", e),
53 | }
54 |
55 | let (_, _) = client.into_builder().finish();
56 | }
57 |
--------------------------------------------------------------------------------
/tests/tls.rs:
--------------------------------------------------------------------------------
1 | use async_tls::TlsConnector;
2 | use async_std::net::TcpStream;
3 |
4 | #[actix_rt::test]
5 | async fn test_connecting_to_alchemy() {
6 | // Create the socket connection
7 | let socket = match TcpStream::connect("eth-mainnet.g.alchemy.com:443").await {
8 | Ok(s) => s,
9 | Err(e) => panic!("Could not connect to Alchemy: {:?}", e),
10 | };
11 | println!("Create socket connection to Alchemy");
12 |
13 | // Create the async-tls connector
14 | let connector = TlsConnector::default();
15 |
16 | // Establish the connection
17 | let mut _tls_stream = match connector.connect("wss://eth-mainnet.g.alchemy.com/v2/MVNYMOb_58bAMzhXX2pS25NDiZ3Q9HeC", socket).await {
18 | Ok(s) => s,
19 | Err(e) => panic!("Could not connect to Alchemy: {:?}", e),
20 | };
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/tests/types.rs:
--------------------------------------------------------------------------------
1 | use ethers::providers::{Http, Middleware, Provider};
2 | use std::convert::TryFrom;
3 |
4 | use alchemy_rs::types::*;
5 |
6 | #[derive(Debug, Clone)]
7 | pub struct ProviderWrapper {
8 | /// The provider
9 | pub provider: Provider,
10 | }
11 |
12 | impl ExposedProvider for ProviderWrapper {
13 | fn provider(&self) -> &Provider {
14 | &self.provider
15 | }
16 | }
17 |
18 | #[actix_rt::test]
19 | async fn test_expose_provider() {
20 | // Instantiate the provider
21 | let provider =
22 | Provider::::try_from("https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27")
23 | .expect("could not instantiate HTTP Provider");
24 |
25 | // Create the wrapper containing the provider
26 | let wrapper = ProviderWrapper { provider };
27 |
28 | // Retrieve the provider from the wrapper
29 | let retrieved = wrapper.provider();
30 |
31 | // Verify that we can get a block from the provider
32 | let block = retrieved.get_block(100u64).await.unwrap();
33 | println!("Got block: {}", serde_json::to_string(&block).unwrap());
34 | }
35 |
--------------------------------------------------------------------------------
/tests/util.rs:
--------------------------------------------------------------------------------
1 | pub fn assert_strings_roughly_equal(a: impl Into, b: impl Into) {
2 | let undressed_a = (a.into() as String).as_str().replace(['\n', ' ', '\t'], "");
3 | let undressed_b = (b.into() as String).as_str().replace(['\n', ' ', '\t'], "");
4 | assert_eq!(undressed_a, undressed_b);
5 | }
6 |
--------------------------------------------------------------------------------