1extern crate alloc;
2
3pub mod ethereum_mainnet;
4pub mod rinkeby_testnet;
5pub mod traits;
6
7use alloc::boxed::Box;
8use alloc::string::{String, ToString};
9use alloc::vec;
10use alloc::vec::Vec;
11use futures::StreamExt;
12use secp256k1::rand::rngs::StdRng;
13use secp256k1::rand::Rng;
14use secp256k1::{
15 rand::{rngs, SeedableRng},
16 PublicKey, SecretKey,
17};
18use serde::{Deserialize, Serialize};
19use std::any::{Any, TypeId};
20use std::collections::HashMap;
21use std::convert::{From, TryFrom};
22use std::str::FromStr;
23use std::time::SystemTime;
24use web3::api::SubscriptionStream;
25use web3::contract::tokens::{Detokenize, Tokenize};
26use web3::contract::{Contract, Options};
27use web3::ethabi::ethereum_types::H256;
28use web3::ethabi::{Int, Uint};
29use web3::helpers as w3h;
30use web3::signing::keccak256;
31use web3::transports::{Http, WebSocket};
32use web3::types::{
33 Address, BlockNumber, Bytes, FilterBuilder, Log, SignedTransaction, TransactionId,
34 TransactionParameters, H160, U256, U64,
35};
36use web3::Web3;
37
38#[macro_export]
66macro_rules! switch {
67 ($v:expr; $($a:expr => $b:expr,)* _ => $e:expr $(,)?) => {
68 match $v {
69 $(v if v == $a => $b,)*
70 _ => $e,
71 }
72 };
73}
74
75#[cfg(test)]
76mod tests {
77 const A: u32 = 1 << 0;
78 const B: u32 = 1 << 1;
79 const C: u32 = 1 << 2;
80 const D: u32 = 1 << 3;
81
82 #[test]
83 fn it_works() {
84 assert!(switch! { 1; _ => true });
85
86 let v = switch! { A | B;
87 A => false,
88 B | C => false,
89 A | B => true,
90 C | D => {
91 unreachable!();
92 },
93 _ => false,
94 };
95 assert!(v);
96 }
97
98 #[test]
99 fn no_trailing_comma() {
100 let v = switch! { 1;
101 1 => true,
102 _ => false
103 };
104 assert!(v);
105 }
106}
107
108trait InstanceOf
110where
111 Self: Any,
112{
113 fn instance_of<U: ?Sized + Any>(&self) -> bool {
114 TypeId::of::<Self>() == TypeId::of::<U>()
115 }
116}
117
118impl<T: ?Sized + Any> InstanceOf for T {}
120
121#[derive(Clone, Debug, Serialize, Deserialize)]
122pub struct KeyPair {
123 pub secret_key: String,
124 pub public_key: String,
125}
126
127#[derive(Clone, Debug)]
128pub struct EVMNetwork {
129 pub http_url: String,
130 pub ws_url: String,
131 pub chain_id: Option<u64>,
132}
133
134pub enum Network {
135 EthereumMainnet = 1,
136 EthereumGoerli = 5,
137 EthereumSepolia = 11155111,
138 BSCMainnet = 56,
139 BSCTestnet = 97,
140 AvalancheMainnet = 99,
141 AvalancheTestnet = 100,
142}
143
144impl EVMNetwork {
145 pub fn new(network_id: Network) -> EVMNetwork {
146 let mut _http_url = "";
147 let mut _socket_url = "";
148
149 match network_id {
150 Network::EthereumMainnet => {
151 _http_url = "https://mainnet.infura.io/v3/d39a866f4f6d49b9916f9269bf880110";
152 _socket_url = "https://goerli.infura.io/v3/d39a866f4f6d49b9916f9269bf880110";
153 }
154 Network::EthereumGoerli => {
155 _http_url = "https://goerli.infura.io/v3/d39a866f4f6d49b9916f9269bf880110";
156 _socket_url = "wss://goerli.infura.io/ws/v3/d39a866f4f6d49b9916f9269bf880110";
157 }
158 Network::EthereumSepolia => {
159 _http_url = "https://sepolia.infura.io/v3/d39a866f4f6d49b9916f9269bf880110";
160 _socket_url = "wss://sepolia.infura.io/ws/v3/d39a866f4f6d49b9916f9269bf880110";
161 }
162 Network::BSCMainnet => {
163 _http_url = "https://bsc-mainnet.nodereal.io/v1/35714f2a92134c78b61e57d04a9e82b0";
164 _socket_url =
165 "wss://bsc-mainnet.nodereal.io/ws/v1/35714f2a92134c78b61e57d04a9e82b0";
166 }
167 Network::BSCTestnet => {
168 _http_url = "https://rpc.ankr.com/bsc_testnet_chapel/8bb975b26860eb14a52028cf0094617967e250459efe5360f1029369b445e6c0";
172 _socket_url =
173 "wss://rpc.ankr.com/bsc_testnet_chapel/ws/8bb975b26860eb14a52028cf0094617967e250459efe5360f1029369b445e6c0";
174 }
175 Network::AvalancheMainnet => {
176 _http_url = "https://speedy-nodes-nyc.moralis.io/84a2745d907034e6d388f8d6/avalanche/mainnet";
177 _socket_url = "wss://speedy-nodes-nyc.moralis.io/84a2745d907034e6d388f8d6/avalanche/mainnet/ws";
178 }
179 Network::AvalancheTestnet => {
180 _http_url = "https://speedy-nodes-nyc.moralis.io/84a2745d907034e6d388f8d6/avalanche/mainnet";
181 _socket_url = "wss://speedy-nodes-nyc.moralis.io/84a2745d907034e6d388f8d6/avalanche/mainnet/ws";
182 }
183 _ => {
184 _http_url = "https://speedy-nodes-nyc.moralis.io/84a2745d907034e6d388f8d6/avalanche/mainnet";
185 _socket_url = "wss://speedy-nodes-nyc.moralis.io/84a2745d907034e6d388f8d6/avalanche/mainnet/ws";
186 }
187 }
188
189 let u64chain_id: u64 = network_id as u64;
190 println!("chain id: {}", u64chain_id);
191 let chain_id: Option<u64> = Option::Some(u64::try_from(u64chain_id).unwrap());
192
193 EVMNetwork {
194 http_url: String::from(_http_url),
195 ws_url: String::from(_socket_url),
196 chain_id,
197 }
198 }
199}
200
201#[test]
202fn new_network() {
203 let network = EVMNetwork::new(Network::BSCMainnet);
204 println!("{:?}", network);
205}
206
207#[derive(Clone, Debug)]
209pub struct Router {
210 pub address: String,
211 pub factory: String,
212}
213
214impl Router {
215 pub async fn new(network_id: Network) {}
216}
217
218#[derive(Clone, Debug)]
219pub struct Web3Manager {
220 pub accounts: Vec<H160>,
222 pub web3http: Web3<Http>,
224 pub web3web_socket: Web3<WebSocket>,
226 accounts_map: HashMap<H160, String>,
228 current_nonce: U256,
229 chain_id: Option<u64>,
231}
232
233impl Web3Manager {
234 pub fn get_current_nonce(&self) -> U256 {
238 self.current_nonce
239 }
240
241 pub fn set_current_nonce(&mut self, new_nonce: U256) {
245 self.current_nonce = new_nonce;
246 }
247
248 pub async fn instance_contract(
273 &self,
274 plain_contract_address: &str,
275 abi_path: &[u8],
276 ) -> Result<Contract<Http>, Box<dyn std::error::Error>> {
277 Ok(Contract::from_json(
278 self.web3http.eth(),
279 Address::from_str(plain_contract_address)?,
280 abi_path,
281 )?)
282 }
283
284 pub fn generate_keypair() -> (SecretKey, PublicKey) {
285 let secp = secp256k1::Secp256k1::new();
286
287 let n2: u64 = 1;
288 println!("first random u64 is: {}", n2);
289 let mut rng: StdRng = rngs::StdRng::seed_from_u64(n2);
290 let random_number: u64 = rng.gen::<u64>();
291 println!(
292 "With seed {}, the first random u64 is: {}",
293 n2, random_number
294 );
295
296 secp.generate_keypair(&mut rng)
297 }
298
299 pub fn public_key_address(public_key: &PublicKey) -> Address {
300 let public_key = public_key.serialize_uncompressed();
301 debug_assert_eq!(public_key[0], 0x04);
302 let hash = keccak256(&public_key[1..]);
303 Address::from_slice(&hash[12..])
304 }
305
306 pub fn generate_keypairs(n: u8) -> Vec<(SecretKey, PublicKey)> {
307 let mut keypairs: Vec<(SecretKey, PublicKey)> = Vec::new();
308 for _ in 0..n {
309 keypairs.push(Web3Manager::generate_keypair());
310 }
311 keypairs
312 }
313
314 pub async fn get_token_balance(&self, token_address: &str, account: H160) -> U256 {
315 let token_abi = include_bytes!("../abi/TokenAbi.json");
316 let token_instance: Contract<Http> = self
317 .instance_contract(token_address, token_abi)
318 .await
319 .unwrap();
320
321 let token_decimals: U256 = self
322 .query_contract(&token_instance, "decimals", ())
323 .await
324 .unwrap();
325
326 let token_balance: U256 = self
327 .query_contract(&token_instance, "balanceOf", account)
328 .await
329 .unwrap();
330
331 println!("token_decimals: {:?}", token_decimals);
335 println!("token_balance: {:?}", token_balance);
336
337 token_balance
338 }
339
340 pub fn generate_deadline(&self) -> U256 {
341 U256::from(
342 SystemTime::now()
343 .duration_since(SystemTime::UNIX_EPOCH)
344 .unwrap()
345 .as_secs(),
346 ) + 1000usize
347 }
348
349 pub async fn swap_tokens_for_exact_tokens(
351 &mut self,
352 account: H160,
353 router_address: &str,
354 token_amount: U256,
355 pairs: &[&str],
356 slippage: usize,
357 ) -> Result<H256, web3::Error> {
358 let contract_function = "swapTokensForExactTokens";
359
360 let router_abi = include_bytes!("../abi/PancakeRouterAbi.json");
361 let router_instance: Contract<Http> = self
362 .instance_contract(router_address, router_abi)
363 .await
364 .expect("error creating the router instance");
365
366 let mut addresses = Vec::new();
367 for pair in pairs {
368 addresses.push(Address::from_str(pair).unwrap());
369 }
370
371 let parameter_out = (token_amount, addresses.clone());
372 let amount_out_min: Vec<Uint> = self
373 .query_contract(&router_instance, "getAmountsOut", parameter_out)
374 .await
375 .unwrap();
376
377 let min_amount = U256::from(amount_out_min[1].as_u128());
378 let min_amount_less_slippage = min_amount - ((min_amount * slippage) / 100usize);
379
380 let parameters2 = (
381 token_amount,
382 min_amount_less_slippage,
383 addresses,
384 self.first_loaded_account(),
385 self.generate_deadline(),
386 );
387
388 println!("amount_out: {:?}", token_amount);
389 println!("min_amount_less_slippage: {:?}", min_amount_less_slippage);
390
391 let send_tx_result = self
392 .sign_and_send_tx(
393 account,
394 &router_instance,
395 contract_function,
396 ¶meters2,
397 token_amount,
398 )
399 .await;
400
401 send_tx_result
402 }
403
404 pub async fn get_token_price(&mut self, router_address: &str, pairs: Vec<H160>) -> U256 {
405 let router_abi = include_bytes!("../abi/PancakeRouterAbi.json");
406 let router_instance: Contract<Http> = self
407 .instance_contract(router_address, router_abi)
408 .await
409 .expect("error creating the router instance");
410
411 let amount_out: U256 = U256::from_dec_str("1000000000000000000").unwrap();
412 let parameter_out = (amount_out, pairs.clone());
413 let amount_out_min: Vec<Uint> = self
414 .query_contract(&router_instance, "getAmountsOut", parameter_out)
415 .await
416 .unwrap();
417 let min_amount = U256::from(amount_out_min[1].as_u128());
418
419 min_amount
420 }
421
422 pub async fn swap_exact_tokens_for_tokens_supporting_fee_on_transfer_tokens(
423 &mut self,
424 account: H160,
425 router_address: &str,
426 token_amount: U256,
427 pairs: &[&str],
428 ) -> Result<H256, web3::Error> {
429 let contract_function: &str = "swapExactTokensForTokensSupportingFeeOnTransferTokens";
430
431 let router_abi = include_bytes!("../abi/PancakeRouterAbi.json");
432 let router_instance: Contract<Http> = self
433 .instance_contract(router_address, router_abi)
434 .await
435 .expect("error creating the router instance");
436
437 let mut addresses = Vec::new();
438 for pair in pairs {
439 addresses.push(Address::from_str(pair).unwrap());
440 }
441
442 let parameters = (
443 token_amount,
444 U256::from_dec_str("0").unwrap(),
445 addresses,
446 self.first_loaded_account(),
447 self.generate_deadline(),
448 );
449
450 let send_tx_result = self
451 .sign_and_send_tx(
452 account,
453 &router_instance,
454 contract_function,
455 ¶meters,
456 U256::from_dec_str("0").unwrap(),
457 )
458 .await;
459
460 send_tx_result
461 }
462 pub async fn swap_eth_for_exact_tokens(
463 &mut self,
464 account: H160,
465 router_address: &str,
466 token_address: &str,
467 eth_amount: U256,
468 slippage: usize,
469 ) -> Result<H256, web3::Error> {
470 let mut router_abi_path = "../abi/PancakeRouterAbi.json";
471 let mut contract_function: &str = "swapExactETHForTokens";
472 let mut wbnb_address = "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c";
473 let mut wbnb_address_testnet = "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd";
474
475 let mut path_address: Vec<&str> = vec![];
478
479 switch! { router_address;
480 "0x9Ac64Cc6e4415144C455BD8E4837Fea55603e5c3" => {
481
482 router_abi_path = "../abi/PancakeRouterAbi.json";
483 contract_function = "swapExactETHForTokens";
484
485 path_address.push(wbnb_address_testnet);
486 path_address.push(token_address);
487
488 },
489 "0x10ed43c718714eb63d5aa57b78b54704e256024e" => {
490
491 router_abi_path = "../abi/PancakeRouterAbi.json";
492 contract_function = "swapExactETHForTokens";
493
494 path_address.push(wbnb_address);
495 path_address.push(token_address);
496
497 },
498 _ => {
499
500 router_abi_path = "../abi/PancakeRouterAbi.json";
501 contract_function = "swapExactETHForTokens";
502
503 path_address.push(wbnb_address_testnet);
504 path_address.push(token_address);
505 },
506 }
507
508 let router_abi = include_bytes!("../abi/PancakeRouterAbi.json");
509 let router_instance: Contract<Http> = self
510 .instance_contract(router_address, router_abi)
511 .await
512 .unwrap();
513
514 let mut addresses = Vec::new();
515 for pair in path_address {
516 addresses.push(Address::from_str(pair).unwrap());
517 }
518
519 let parameter_out = (eth_amount, addresses.clone());
520 let amount_out_min: Vec<Uint> = self
521 .query_contract(&router_instance, "getAmountsOut", parameter_out)
522 .await
523 .unwrap();
524
525 let min_amount = U256::from(amount_out_min[1].as_u128());
526 let min_amount_less_slippage = min_amount - ((min_amount * slippage) / 100usize);
527
528 let parameters = (
529 min_amount_less_slippage,
530 addresses,
531 account,
532 self.generate_deadline(),
533 );
534
535 println!("slippage {}", slippage);
536 println!("eth_amount {}", eth_amount);
537 println!("amount_out_min[0] {}", amount_out_min[0]);
538 println!("amount_out_min[1] {}", amount_out_min[1]);
539 println!("min_amount_less_slippage {}", min_amount_less_slippage);
540
541 let send_tx_result = self
542 .sign_and_send_tx(
543 account,
544 &router_instance,
545 contract_function,
546 ¶meters,
547 eth_amount,
548 )
549 .await;
550
551 send_tx_result
552 }
553
554 pub async fn get_out_estimated_tokens_for_tokens(
555 &mut self,
556 contract_instance: &Contract<Http>,
557 pair_a: &str,
558 pair_b: &str,
559 amount: &str,
560 ) -> Result<U256, web3::contract::Error> {
561 self.query_contract(
562 contract_instance,
563 "getAmountsOut",
564 (
565 amount.to_string(),
566 vec![pair_a.to_string(), pair_b.to_string()],
567 ),
568 )
569 .await
570 }
571
572 pub async fn get_eth_balance(&mut self, account: H160) -> U256 {
573 let balance = self.web3http.eth().balance(account, None).await.unwrap();
574 return balance;
575 }
576
577 pub async fn last_nonce(&self, account: H160) -> U256 {
580 let block_number: Option<BlockNumber> = Option::Some(BlockNumber::Pending);
581
582 let nonce = self
583 .web3http
584 .eth()
585 .transaction_count(account, block_number)
586 .await
587 .unwrap();
588
589 return nonce;
590
591 }
598
599 pub async fn load_account(
600 &mut self,
601 plain_address: &str,
602 plain_private_key: &str,
603 ) -> &mut Web3Manager {
604 let wallet: H160 = H160::from_str(plain_address).unwrap();
607
608 self.accounts_map
610 .insert(wallet, plain_private_key.to_string());
611 self.accounts.push(wallet);
612
613 let nonce: U256 = self.last_nonce(wallet).await;
615
616 self.set_current_nonce(nonce);
617
618 self
619 }
620
621 pub async fn new_from_rpc_url(
622 http_url: &str,
623 websocket_url: &str,
624 u64chain_id: u64,
625 ) -> Web3Manager {
626 let web3http: Web3<Http> = web3::Web3::new(web3::transports::Http::new(http_url).unwrap());
628
629 let web3web_socket: Web3<WebSocket> = web3::Web3::new(
631 web3::transports::WebSocket::new(websocket_url)
632 .await
633 .unwrap(),
634 );
635
636 let accounts: Vec<Address> = vec![];
638 let accounts_map: HashMap<H160, String> = HashMap::new();
639 let current_nonce: U256 = U256::from_dec_str("0").unwrap();
640
641 let chain_id: Option<u64> = Option::Some(u64::try_from(u64chain_id).unwrap());
643
644 Web3Manager {
645 accounts,
646 web3http,
647 web3web_socket,
648 accounts_map,
649 current_nonce,
650 chain_id,
651 }
652 }
653
654 pub async fn new(network_id: Network) -> Web3Manager {
655 let network = EVMNetwork::new(network_id);
657
658 let web3http: Web3<Http> =
660 web3::Web3::new(web3::transports::Http::new(network.http_url.as_str()).unwrap());
661
662 let web3web_socket: Web3<WebSocket> = web3::Web3::new(
664 web3::transports::WebSocket::new(network.ws_url.as_str())
665 .await
666 .unwrap(),
667 );
668
669 let accounts: Vec<Address> = vec![];
671 let accounts_map: HashMap<H160, String> = HashMap::new();
672 let current_nonce: U256 = U256::from_dec_str("0").unwrap();
673 let chain_id: Option<u64> = Option::Some(u64::try_from(network.chain_id.unwrap()).unwrap());
674
675 Web3Manager {
676 accounts,
677 web3http,
678 web3web_socket,
679 accounts_map,
680 current_nonce,
681 chain_id,
682 }
683 }
684
685 pub async fn gas_price(&self) -> Result<U256, web3::Error> {
688 self.web3http.eth().gas_price().await
689 }
690
691 pub async fn get_block(&self) -> Result<U64, web3::Error> {
694 self.web3http.eth().block_number().await
695 }
696
697 pub async fn query_contract<P, T>(
698 &self,
699 contract_instance: &Contract<Http>,
700 func: &str,
701 params: P,
702 ) -> Result<T, web3::contract::Error>
703 where
704 P: Tokenize,
705 T: Detokenize,
706 {
707 contract_instance
709 .query(func, params, None, Default::default(), None)
710 .await
711 }
712
713 pub async fn sign_transaction(
716 &mut self,
717 account: H160,
718 transact_obj: TransactionParameters,
719 ) -> SignedTransaction {
720 let plain_pk = self.accounts_map.get(&account).unwrap();
721 let private_key = SecretKey::from_str(plain_pk).unwrap();
722
723 self.web3http
724 .accounts()
725 .sign_transaction(transact_obj, &private_key)
726 .await
727 .unwrap()
728 }
729
730 pub fn encode_tx_parameters(
731 &mut self,
732 nonce: U256,
733 to: Address,
734 value: U256,
735 gas: U256,
736 gas_price: U256,
737 data: Bytes,
738 ) -> TransactionParameters {
739 TransactionParameters {
740 nonce: Some(nonce),
741 to: Some(to),
742 value,
743 gas_price: Some(gas_price),
744 gas,
745 data,
746 chain_id: self.chain_id,
747 ..Default::default()
748 }
749 }
750
751 pub fn encode_tx_data<P>(&mut self, contract: &Contract<Http>, func: &str, params: P) -> Bytes
753 where
754 P: Tokenize,
755 {
756 contract
757 .abi()
758 .function(func)
759 .unwrap()
760 .encode_input(¶ms.into_tokens())
761 .unwrap()
762 .into()
763 }
764
765 pub async fn estimate_tx_gasV1<P>(
766 &mut self,
767 contract: &Contract<Http>,
768 func: &str,
769 params: P,
770 value: &str,
771 ) -> U256
772 where
773 P: Tokenize,
774 {
775 let mut gas_estimation = U256::from_dec_str("0").unwrap();
776 let gas_estimation_result = contract
777 .estimate_gas(
778 func,
779 params,
780 self.accounts[0],
781 Options {
782 value: Some(U256::from_dec_str(value).unwrap()),
783 ..Default::default()
784 },
785 )
786 .await;
787 if gas_estimation_result.is_ok() {
788 gas_estimation = gas_estimation_result.unwrap();
789 }
790 gas_estimation
791 }
792
793 pub fn first_loaded_account(&self) -> H160 {
794 self.accounts[0]
795 }
796
797 pub async fn approve_erc20_token(
798 &mut self,
799 account: H160,
800 token_address: &str,
801 spender: &str,
802 value: &str,
803 ) -> Result<H256, web3::Error> {
804 let token_abi = include_bytes!("../abi/TokenAbi.json");
805 let token_instance: Contract<Http> = self
806 .instance_contract(token_address, token_abi)
807 .await
808 .unwrap();
809
810 let spender_address: Address = Address::from_str(spender).unwrap();
811 let contract_function = "approve";
812 let contract_function_parameters = (spender_address, U256::from_dec_str(value).unwrap());
813
814 let send_tx_result = self
815 .sign_and_send_tx(
816 account,
817 &token_instance,
818 &contract_function.to_string(),
819 &contract_function_parameters,
820 U256::from_dec_str("0").unwrap(),
821 )
822 .await;
823
824 Ok(send_tx_result.unwrap())
825 }
826
827 pub async fn sign_and_send_tx<P: Clone>(
828 &mut self,
829 account: H160,
830 contract_instance: &Contract<Http>,
831 func: &str,
832 params: &P,
833 value: U256,
834 ) -> Result<H256, web3::Error>
835 where
836 P: Tokenize,
837 {
838 let mut gas_estimation_result = contract_instance
843 .estimate_gas(
844 func,
845 params.clone(),
846 account,
847 Options {
848 value: Some(value),
849 ..Default::default()
850 },
851 )
852 .await;
853
854 let estimated_tx_gas = gas_estimation_result.unwrap();
855
856 let tx_data: Bytes = self.encode_tx_data(contract_instance, func, params.clone());
868 let gas_price: U256 = self.web3http.eth().gas_price().await.unwrap();
869 let mut nonce: U256 = self.get_current_nonce();
870
871 let tx_parameters: TransactionParameters = self.encode_tx_parameters(
873 nonce,
874 contract_instance.address(),
875 value,
876 estimated_tx_gas,
877 gas_price,
878 tx_data,
879 );
880
881 let tx_result = self.sign_and_send_transaction(account, tx_parameters).await;
883
884 self.update_nonce();
885 nonce = self.get_current_nonce();
886 println!("current_nonce after: {:?}", nonce);
887
888 return tx_result;
889 }
890
891 async fn sign_and_send_transaction(
892 &mut self,
893 account: H160,
894 tx_parameters: TransactionParameters,
895 ) -> Result<H256, web3::Error> {
896 let signed_transaction: SignedTransaction =
897 self.sign_transaction(account, tx_parameters).await;
898
899 let tx_result = self
901 .web3http
902 .eth()
903 .send_raw_transaction(signed_transaction.raw_transaction)
904 .await;
905 tx_result
906 }
907
908 fn update_nonce(&mut self) {
909 self.set_current_nonce(self.get_current_nonce() + 1)
910 }
911
912 pub async fn sent_eth(&mut self, account: H160, to: H160, amount: &str) {
913 let amount_out: U256 = U256::from_dec_str(amount).unwrap();
914
915 let tx_object = TransactionParameters {
917 to: Some(to),
918 value: amount_out, ..Default::default()
920 };
921
922 let plain_pk = self.accounts_map.get(&account).unwrap();
923 let private_key = SecretKey::from_str(plain_pk).unwrap();
924
925 let signed = self
927 .web3http
928 .accounts()
929 .sign_transaction(tx_object, &private_key)
930 .await
931 .unwrap();
932
933 let result = self
935 .web3http
936 .eth()
937 .send_raw_transaction(signed.raw_transaction)
938 .await
939 .unwrap();
940
941 println!("Tx succeeded with hash: {}", result);
942 }
943
944 pub async fn sent_erc20_token(
945 &mut self,
946 account: H160,
947 contract_instance: Contract<Http>,
948 to: &str,
949 token_amount: &str,
950 ) -> H256 {
951 let contract_function = "transfer";
952
953 let recipient_address: Address = Address::from_str(to).unwrap();
954 let contract_function_parameters =
955 (recipient_address, U256::from_dec_str(token_amount).unwrap());
956
957 let send_tx_result = self
958 .sign_and_send_tx(
959 account,
960 &contract_instance,
961 contract_function,
962 &contract_function_parameters,
963 U256::from_dec_str("0").unwrap(),
964 )
965 .await;
966
967 send_tx_result.unwrap()
968 }
969
970 pub async fn get_latest_price(
975 &mut self,
976 network: impl crate::traits::GetAddress,
977 pair_address: &str,
978 ) -> Int {
979 let proxy_abi = include_bytes!("../abi/EACAggregatorProxy.json");
980 let proxy_instance: Contract<Http> = self
981 .instance_contract(&network.get_address(pair_address).unwrap(), proxy_abi)
982 .await
983 .unwrap();
984
985 let res: (Uint, Int, Uint, Uint, Uint) = self
986 .query_contract(&proxy_instance, "latestRoundData", ())
987 .await
988 .unwrap();
989 res.1
990 }
991
992 pub async fn listen_contract_events(&mut self, contract_address: &str) {
1009 let filter = FilterBuilder::default()
1025 .address(vec![Address::from_str(contract_address).unwrap()])
1026 .topics(None, None, None, None)
1027 .build();
1028
1029 let sub: SubscriptionStream<WebSocket, Log> = self
1030 .web3web_socket
1031 .eth_subscribe()
1032 .subscribe_logs(filter)
1033 .await
1034 .unwrap();
1035 sub.for_each(|log| async {
1036 let l: Log = log.unwrap();
1037 println!("Address: {:?}", l.transaction_hash.unwrap());
1038 println!("Data: {:?}", l.data);
1039 println!("Data0: {:?}", l.data.0);
1040 println!("{}", std::str::from_utf8(&l.data.0).unwrap());
1041 println!("topics: {:?}", l.topics);
1042 println!("log_type: {:?}", l.log_type);
1043
1044 let tx = self
1045 .web3http
1046 .eth()
1047 .transaction(TransactionId::Hash(l.transaction_hash.unwrap()))
1048 .await
1049 .unwrap()
1050 .unwrap();
1051
1052 let from_addr = tx.from.unwrap_or(H160::zero());
1053 let to_addr = tx.to.unwrap_or(H160::zero());
1054 let value = tx.value;
1055 let input = tx.input;
1056
1057 println!("from_addr: {:?}", from_addr);
1058 println!("to_addr: {:?}", to_addr);
1059 println!("value: {:?}", value);
1060 println!("input: {:?}", input);
1061 })
1062 .await;
1063 }
1064
1065 pub async fn build_contract_events(
1066 &mut self,
1067 contract_address: &str,
1068 ) -> SubscriptionStream<WebSocket, Log> {
1069 let filter = FilterBuilder::default()
1070 .address(vec![Address::from_str(contract_address).unwrap()])
1071 .topics(None, None, None, None)
1072 .build();
1073
1074 let sub: SubscriptionStream<WebSocket, Log> = self
1075 .web3web_socket
1076 .eth_subscribe()
1077 .subscribe_logs(filter)
1078 .await
1079 .unwrap();
1080 return sub;
1081 }
1082
1083 pub async fn init_pair(&self, lp_address: &str) -> Contract<Http> {
1084 let lp_pair_abi = include_bytes!("../abi/PancakeLPTokenAbi.json");
1085 let lp_pair_instance_address = lp_address;
1086 let lp_pair_instance: Contract<Http> = self
1087 .instance_contract(lp_pair_instance_address, lp_pair_abi)
1088 .await
1089 .expect("error creating the contract instance");
1090 lp_pair_instance
1091 }
1092
1093 pub async fn init_router_factory(&mut self, factory_address: &str) -> Contract<Http> {
1094 let factory_abi = include_bytes!("../abi/PancakeFactoryAbi.json");
1095 let factory_instance: Contract<Http> = self
1096 .instance_contract(factory_address, factory_abi)
1097 .await
1098 .expect("error creating the contract instance");
1099 factory_instance
1100 }
1101
1102 pub async fn init_router(&mut self, router_address: &str) -> Contract<Http> {
1103 let router_abi = include_bytes!("../abi/PancakeRouterAbi.json");
1105
1106 let router_instance: Contract<Http> = self
1107 .instance_contract(router_address, router_abi)
1108 .await
1109 .expect("error creating the contract instance");
1110 router_instance
1111 }
1112
1113 pub async fn token_has_liquidity(&self, lp_pair_factory_instance: Contract<Http>) -> bool {
1114 let lp_pair_reserves: (Uint, Uint, Uint) = self
1115 .query_contract(&lp_pair_factory_instance, "getReserves", ())
1116 .await
1117 .unwrap();
1118 lp_pair_reserves.0 > U256::from(0) && lp_pair_reserves.1 > U256::from(0)
1119 }
1120
1121 pub async fn find_lp_pair(&mut self, factory_address: &str, token_address: &str) -> String {
1122 let factory_instance = self.init_router_factory(factory_address).await;
1123
1124 let weth = "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd";
1125 let initial_lp_address = "0x0000000000000000000000000000000000000000";
1127 let lp_pair_address: H160 = self
1130 .query_contract(
1131 &factory_instance,
1132 "getPair",
1133 (
1134 H160::from_str(weth).unwrap(),
1135 H160::from_str(token_address).unwrap(),
1136 ),
1137 )
1138 .await
1139 .unwrap();
1140
1141 let mut lp_token_address = w3h::to_string(&lp_pair_address).replace("\"", "");
1142 if lp_token_address == initial_lp_address {
1143 let lp_pair_address: H160 = self
1144 .query_contract(
1145 &factory_instance,
1146 "getPair",
1147 (
1148 H160::from_str(weth).unwrap(),
1149 H160::from_str(token_address).unwrap(),
1150 ),
1151 )
1152 .await
1153 .unwrap();
1154 lp_token_address = w3h::to_string(&lp_pair_address).replace("\"", "")
1155 }
1156 lp_token_address
1157 }
1158
1159 pub async fn get_token_reserves(
1160 &mut self,
1161 lp_pair_factory_instance: Contract<Http>,
1162 ) -> (U256, U256, U256) {
1163 let lp_pair_reserves: (Uint, Uint, Uint) = self
1164 .query_contract(&lp_pair_factory_instance, "getReserves", ())
1165 .await
1166 .unwrap();
1167 println!("lp_pair_reserves: {:?}", lp_pair_reserves);
1168 lp_pair_reserves
1169 }
1170}